Fixed a segfault in the COPY command.
[pwmd.git] / src / commands.c
blobeae7a9ae37b0da6a4816574cf0167a0285c7b5e8
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 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <ctype.h>
28 #include <glib.h>
29 #include <gcrypt.h>
30 #include <zlib.h>
31 #include <dirent.h>
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
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 "lock.h"
55 struct gz_s {
56 z_stream z;
57 gpointer out;
58 gboolean done;
59 status_msg_t which;
62 static gpg_error_t do_lock_command(struct client_s *client);
64 static void *z_alloc(void *data, unsigned items, unsigned size)
66 return gcry_calloc(items, size);
69 static void z_free(void *data, void *p)
71 gcry_free(p);
74 static gpg_error_t file_modified(struct client_s *client)
76 struct stat st;
77 gpg_error_t rc;
79 if (client->state != STATE_OPEN)
80 return EPWMD_NO_FILE;
82 rc = lock_file_mutex(client);
84 if (rc)
85 return rc;
87 if (lstat(client->filename, &st) == 0 && client->mtime) {
88 if (client->mtime != st.st_mtime)
89 return EPWMD_FILE_MODIFIED;
92 pth_cancel_point();
93 return 0;
96 static gpg_error_t parse_xml(assuan_context_t ctx)
98 struct client_s *client = assuan_get_pointer(ctx);
100 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
102 if (!client->doc)
103 return EPWMD_LIBXML_ERROR;
105 return 0;
108 void unlock_file_mutex(struct client_s *client)
110 pth_mutex_t *m;
112 #ifdef WITH_PINENTRY
113 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
114 #else
115 if (client->has_lock == FALSE)
116 #endif
117 return;
119 CACHE_LOCK(client->ctx);
121 if (cache_get_mutex(client->md5file, &m) == FALSE) {
122 CACHE_UNLOCK;
123 return;
126 CACHE_UNLOCK;
127 MUTEX_UNLOCK(m);
128 client->has_lock = client->is_lock_cmd = FALSE;
131 gpg_error_t lock_file_mutex(struct client_s *client)
133 pth_mutex_t *m;
134 gpg_error_t rc = 0;
136 if (client->has_lock == TRUE)
137 return 0;
139 CACHE_LOCK(client->ctx);
141 if (cache_get_mutex(client->md5file, &m) == FALSE) {
142 CACHE_UNLOCK;
143 return 0;
146 CACHE_UNLOCK;
147 MUTEX_TRYLOCK(client->ctx, m, rc);
149 if (!rc)
150 client->has_lock = TRUE;
152 return rc;
155 void free_client(struct client_s *client)
157 if (client->doc)
158 xmlFreeDoc(client->doc);
160 if (client->xml)
161 gcry_free(client->xml);
163 if (client->filename)
164 g_free(client->filename);
166 if (client->crypto)
167 cleanup_crypto(&client->crypto);
169 if (client->xml_error)
170 xmlResetError(client->xml_error);
173 void cleanup_client(struct client_s *client)
175 assuan_context_t ctx = client->ctx;
176 struct client_thread_s *thd = client->thd;
177 gboolean has_lock = client->has_lock;
178 #ifdef WITH_PINENTRY
179 struct pinentry_s *pin = client->pinentry;
180 #endif
182 unlock_file_mutex(client);
183 CACHE_LOCK(client->ctx);
184 cache_decr_refcount(client->md5file);
187 * This may be a new file so don't use a cache slot. save_command() will
188 * set this to FALSE on success.
190 if (client->new == TRUE)
191 cache_clear(client->md5file, 1);
193 CACHE_UNLOCK;
194 free_client(client);
195 memset(client, 0, sizeof(struct client_s));
196 client->state = STATE_CONNECTED;
197 client->ctx = ctx;
198 client->thd = thd;
199 client->freed = TRUE;
200 #ifdef WITH_PINENTRY
201 client->pinentry = pin;
202 #endif
203 client->has_lock = has_lock;
206 static void gz_cleanup(void *arg)
208 struct gz_s **gz = (struct gz_s **)arg;
210 if (!gz)
211 return;
213 if (!(*gz)->done && (*gz)->out)
214 gcry_free((*gz)->out);
216 if ((*gz)->which == STATUS_COMPRESS) {
217 if ((*gz)->z.zalloc)
218 deflateEnd(&(*gz)->z);
220 else {
221 if ((*gz)->z.zalloc)
222 inflateEnd(&(*gz)->z);
225 g_free(*gz);
226 *gz = NULL;
229 gboolean do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
230 gpointer *out, gulong *outsize, gint *rc)
232 struct gz_s *gz;
233 gz_header h;
234 gchar buf[17];
236 gz = g_malloc0(sizeof(struct gz_s));
238 if (!gz) {
239 *rc = gpg_error_from_errno(ENOMEM);
240 return FALSE;
243 pth_cleanup_push(gz_cleanup, &gz);
244 gz->which = STATUS_DECOMPRESS;
245 gz->z.zalloc = z_alloc;
246 gz->z.zfree = z_free;
247 gz->z.next_in = in;
248 gz->z.avail_in = (uInt)insize;
249 gz->z.avail_out = zlib_bufsize;
250 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
252 if (!gz->out) {
253 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
254 *rc = Z_MEM_ERROR;
255 pth_cleanup_pop(1);
256 return FALSE;
259 *rc = inflateInit2(&gz->z, 47);
261 if (*rc != Z_OK) {
262 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
263 pth_cleanup_pop(1);
264 return FALSE;
267 memset(&h, 0, sizeof(gz_header));
268 h.comment = (guchar *)buf;
269 h.comm_max = sizeof(buf);
270 *rc = inflateGetHeader(&gz->z, &h);
272 if (*rc != Z_OK) {
273 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
274 pth_cleanup_pop(1);
275 return FALSE;
278 *rc = inflate(&gz->z, Z_BLOCK);
280 if (*rc != Z_OK) {
281 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
282 pth_cleanup_pop(1);
283 return FALSE;
286 if (h.comment)
287 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
289 do {
290 gpointer p;
292 *rc = inflate(&gz->z, Z_FINISH);
294 switch (*rc) {
295 case Z_OK:
296 break;
297 case Z_BUF_ERROR:
298 if (!gz->z.avail_out) {
299 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
301 if (!p) {
302 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
303 *rc = Z_MEM_ERROR;
304 goto fail;
307 gz->out = p;
308 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
309 gz->z.avail_out = zlib_bufsize;
310 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
311 gz->z.total_out, insize);
313 if (*rc)
314 goto fail;
316 break;
317 case Z_STREAM_END:
318 break;
319 default:
320 goto fail;
321 break;
323 } while (*rc != Z_STREAM_END);
325 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
326 insize);
328 if (*rc)
329 goto fail;
331 *out = gz->out;
332 *outsize = gz->z.total_out;
333 gz->done = TRUE;
334 pth_cleanup_pop(1);
335 *rc = 0;
336 return TRUE;
338 fail:
339 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
340 pth_cleanup_pop(1);
341 return FALSE;
344 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
345 gpg_error_t *rc)
347 gint fd;
348 gsize len;
349 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
350 gsize fh_size;
351 gpointer p;
353 *rc = 0;
355 if (!fh) {
356 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
357 *rc = gpg_error_from_errno(ENOMEM);
358 return NULL;
361 pth_cleanup_push(g_free, fh);
362 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2);
364 if (lstat(filename, &fh->st) == -1) {
365 *rc = gpg_error_from_syserror();
366 pth_cleanup_pop(1);
367 return NULL;
370 if (!S_ISREG(fh->st.st_mode)) {
371 *rc = GPG_ERR_ENOANO;
372 pth_cleanup_pop(1);
373 return NULL;
376 fd = open(filename, O_RDONLY);
378 if (fd == -1) {
379 *rc = gpg_error_from_errno(errno);
380 pth_cleanup_pop(1);
381 return NULL;
384 pth_cleanup_push(cleanup_fd_cb, &fd);
385 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
386 len = pth_read(fd, p, fh_size);
388 if (len != fh_size) {
389 gint n = errno;
390 pth_cleanup_pop(1);
391 pth_cleanup_pop(1);
392 *rc = gpg_error_from_errno(n);
393 return NULL;
396 fh->v1 = v1;
397 fh->fd = fd;
398 pth_cleanup_pop(0);
399 pth_cleanup_pop(0);
400 return fh;
403 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *unused,
404 gboolean cached)
406 struct client_s *client = assuan_get_pointer(ctx);
407 gpg_error_t rc;
408 gint timeout;
409 guchar *key = client->crypto->key;
411 /* New file. */
412 if (!client->crypto->fh) {
413 if (key[0])
414 goto update_cache;
416 goto done;
419 rc = init_client_crypto2(client->filename, client->crypto);
421 if (rc) {
422 cleanup_client(client);
423 return send_error(ctx, rc);
426 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
428 if (rc) {
429 cleanup_client(client);
430 return send_error(ctx, rc);
433 update_cache:
434 CACHE_LOCK(client->ctx);
436 if (cached == FALSE) {
437 if (cache_update_key(client->md5file, key) == FALSE) {
438 cleanup_client(client);
439 CACHE_UNLOCK;
440 return send_syserror(ctx, ENOMEM);
443 timeout = get_key_file_integer(client->filename, "cache_timeout");
444 cache_reset_timeout(client->md5file, timeout);
446 else
447 cache_set_timeout(client->md5file, -2);
449 CACHE_UNLOCK;
451 done:
452 rc = parse_xml(ctx);
454 if (client->xml) {
455 gcry_free(client->xml);
456 client->xml = NULL;
459 if (!rc) {
460 if (client->new == FALSE)
461 send_status_all(STATUS_CACHE);
463 client->state = STATE_OPEN;
466 if (!rc && client->new == FALSE &&
467 client->crypto->fh->ver.fh2.iter != (guint64)get_key_file_double(client->filename, "iterations")) {
468 MUTEX_LOCK(&rcfile_mutex);
469 g_key_file_set_double(keyfileh, client->filename, "iterations",
470 client->crypto->fh->ver.fh2.iter);
471 MUTEX_UNLOCK(&rcfile_mutex);
472 send_status_all(STATUS_CONFIG);
475 cleanup_crypto(&client->crypto);
477 if (client->lockonopen)
478 return do_lock_command(client);
480 return send_error(ctx, rc);
483 static void req_cleanup(void *arg)
485 if (!arg)
486 return;
488 g_strfreev((gchar **)arg);
491 static gint open_command(assuan_context_t ctx, gchar *line)
493 gboolean cached = FALSE;
494 gpg_error_t rc;
495 struct client_s *client = assuan_get_pointer(ctx);
496 gchar **req;
497 gchar *filename = NULL;
498 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
500 if ((req = split_input_line(line, " ", 2)) != NULL)
501 filename = req[0];
503 pth_cleanup_push(req_cleanup, req);
505 if (!filename || !*filename) {
506 pth_cleanup_pop(1);
507 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
510 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
512 if (valid_filename(filename) == FALSE) {
513 pth_cleanup_pop(1);
514 return send_error(ctx, EPWMD_INVALID_FILENAME);
517 if (client->state == STATE_OPEN)
518 cleanup_client(client);
520 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
521 CACHE_LOCK(client->ctx);
523 if (cache_has_file(client->md5file) == FALSE) {
524 if (cache_add_file(client->md5file, NULL) == FALSE) {
525 pth_cleanup_pop(1);
526 CACHE_UNLOCK;
527 return send_syserror(ctx, ENOMEM);
531 cache_incr_refcount(client->md5file);
532 CACHE_UNLOCK;
533 rc = lock_file_mutex(client);
535 if (rc) {
536 pth_cleanup_pop(1);
537 return send_error(ctx, rc);
540 client->freed = FALSE;
541 client->crypto = init_client_crypto();
543 if (!client->crypto) {
544 pth_cleanup_pop(1);
545 cleanup_client(client);
546 return send_syserror(ctx, ENOMEM);
549 client->crypto->key = gcry_malloc(hashlen);
551 if (!client->crypto->key) {
552 pth_cleanup_pop(1);
553 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
554 gpg_error_from_errno(ENOMEM));
555 cleanup_client(client);
556 return send_syserror(ctx, ENOMEM);
559 memset(client->crypto->key, 0, hashlen);
560 client->crypto->fh = read_file_header(filename, FALSE, &rc);
562 if (!client->crypto->fh) {
563 if (gpg_err_code_to_errno(rc) != ENOENT) {
564 log_write("%s: %s", filename, pwmd_strerror(rc));
565 pth_cleanup_pop(1);
566 cleanup_client(client);
567 return send_error(ctx, rc);
571 * New files don't need a key.
573 if ((client->xml = new_document()) == NULL) {
574 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
575 pth_cleanup_pop(1);
576 cleanup_client(client);
577 return send_syserror(ctx, ENOMEM);
580 client->len = xmlStrlen(client->xml);
581 client->new = TRUE;
582 client->filename = g_strdup(filename);
584 if (!client->filename) {
585 pth_cleanup_pop(1);
586 cleanup_client(client);
587 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
588 return send_syserror(ctx, ENOMEM);
591 if (req[1] && *req[1])
592 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
593 strlen(req[1]));
595 pth_cleanup_pop(1);
596 #ifdef WITH_PINENTRY
597 client->pinentry->filename = g_strdup(client->filename);
599 if (!client->pinentry->filename) {
600 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
601 cleanup_client(client);
602 return send_syserror(ctx, ENOMEM);
604 #endif
605 return open_command_finalize(ctx, NULL, cached);
607 else
608 client->mtime = client->crypto->fh->st.st_mtime;
610 client->filename = g_strdup(filename);
612 if (!client->filename) {
613 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
614 pth_cleanup_pop(1);
615 cleanup_client(client);
616 return send_syserror(ctx, ENOMEM);
619 #ifdef WITH_PINENTRY
620 if (client->pinentry->filename)
621 g_free(client->pinentry->filename);
623 client->pinentry->filename = g_strdup(client->filename);
625 if (!client->pinentry->filename) {
626 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
627 pth_cleanup_pop(1);
628 cleanup_client(client);
629 return send_syserror(ctx, ENOMEM);
631 #endif
633 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
634 goto done;
636 CACHE_LOCK(client->ctx);
637 cached = cache_get_key(client->md5file, client->crypto->key);
638 CACHE_UNLOCK;
640 if (cached == FALSE) {
641 gchar *tmp = get_key_file_string(filename, "key_file");
643 if (tmp) {
644 g_free(tmp);
645 pth_cleanup_pop(1);
646 cleanup_client(client);
647 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
651 * No key specified and no matching filename found in the cache. Use
652 * pinentry to retrieve the key. Cannot return assuan_process_done()
653 * here otherwise the command will be interrupted. The event loop in
654 * client_thread() will poll the file descriptor waiting for it to
655 * become ready to read a pinentry_key_s which will contain the
656 * entered key or an error code. It will then call
657 * open_command_finalize() to to finish the command.
659 if (!req[1] || !*req[1]) {
660 #ifdef WITH_PINENTRY
661 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
663 /* From set_pinentry_defaults(). */
664 if (client->pinentry->enable == FALSE ||
665 (client->pinentry->enable == -1 && b == FALSE)) {
666 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
667 goto done;
670 pth_cleanup_pop(1);
671 rc = lock_pin_mutex(client);
673 if (rc) {
674 unlock_pin_mutex(client->pinentry);
675 cleanup_client(client);
676 return send_error(ctx, rc);
679 client->pinentry->which = PINENTRY_OPEN;
680 rc = pinentry_fork(ctx);
682 if (rc) {
683 unlock_pin_mutex(client->pinentry);
684 cleanup_client(client);
685 return send_error(ctx, rc);
688 // Called from pinentry iterate.
689 client->pinentry->cb = open_command_finalize;
690 client->pinentry->status = PINENTRY_INIT;
691 return 0;
692 #else
693 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
694 goto done;
695 #endif
698 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
699 strlen(req[1]));
701 else if (req && req[1] && *req[1]) {
702 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
703 strlen(req[1]) ? strlen(req[1]) : 1);
706 done:
707 pth_cleanup_pop(1);
708 return open_command_finalize(ctx, NULL, cached);
711 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
712 guint size, gpointer *out, gulong *outsize, gint *rc)
714 struct gz_s *gz;
715 gz_header h;
716 gchar buf[17];
717 gint cmd = Z_NO_FLUSH;
719 gz = g_malloc0(sizeof(struct gz_s));
721 if (!gz) {
722 *rc = gpg_error_from_errno(ENOMEM);
723 return FALSE;
726 pth_cleanup_push(gz_cleanup, &gz);
727 gz->which = STATUS_COMPRESS;
728 gz->z.zalloc = z_alloc;
729 gz->z.zfree = z_free;
730 gz->z.next_in = data;
731 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
732 gz->z.avail_out = (uInt)zlib_bufsize;
733 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
735 if (!gz->out) {
736 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
737 *rc = Z_MEM_ERROR;
738 pth_cleanup_pop(1);
739 return FALSE;
742 *rc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
744 if (*rc != Z_OK) {
745 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
746 pth_cleanup_pop(1);
747 return FALSE;
750 /* Rather than store the size of the uncompressed data in the file header,
751 * store it in the comment field of the gzip header. Don't give anyone too
752 * much information. Not sure why really, but it seems the right way. :)
754 memset(&h, 0, sizeof(gz_header));
755 g_snprintf(buf, sizeof(buf), "%u", size);
756 h.comment = (guchar *)buf;
757 *rc = deflateSetHeader(&gz->z, &h);
759 if (*rc != Z_OK) {
760 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
761 pth_cleanup_pop(1);
762 return FALSE;
765 do {
766 gpointer p;
768 *rc = deflate(&gz->z, cmd);
770 switch (*rc) {
771 case Z_OK:
772 break;
773 case Z_BUF_ERROR:
774 if (!gz->z.avail_out) {
775 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
777 if (!p) {
778 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
779 *rc = Z_MEM_ERROR;
780 goto fail;
783 gz->out = p;
784 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
785 gz->z.avail_out = zlib_bufsize;
788 if (!gz->z.avail_in && gz->z.total_in < size) {
789 if (gz->z.total_in + zlib_bufsize > size)
790 gz->z.avail_in = size - gz->z.total_in;
791 else
792 gz->z.avail_in = zlib_bufsize;
794 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
795 gz->z.total_in, size);
797 if (*rc)
798 goto fail;
801 if (gz->z.total_in >= size)
802 cmd = Z_FINISH;
804 break;
805 case Z_STREAM_END:
806 break;
807 default:
808 goto fail;
810 } while (*rc != Z_STREAM_END);
812 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
814 if (*rc)
815 goto fail;
817 *out = gz->out;
818 *outsize = gz->z.total_out;
819 *rc = 0;
820 gz->done = TRUE;
821 pth_cleanup_pop(1);
822 return TRUE;
824 fail:
825 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
826 pth_cleanup_pop(1);
827 return FALSE;
830 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
833 * Useful for a large amount of data. Rather than doing all of the data in one
834 * iteration do it in chunks. This lets the command be cancelable rather than
835 * waiting for it to complete.
837 static gpg_error_t iterate_crypto_once(struct client_s *client,
838 struct client_crypto_s *crypto, status_msg_t which)
840 gpg_error_t rc = 0;
841 goffset len = CRYPTO_BLOCKSIZE(crypto);
842 gpointer p = gcry_malloc(len);
843 goffset total = 0;
844 gpointer inbuf;
846 if (!p)
847 return gpg_err_code_from_errno(ENOMEM);
849 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
850 len = crypto->insize;
852 pth_cleanup_push(gcry_free, p);
854 for (;;) {
855 inbuf = (guchar *)crypto->inbuf + total;
856 guchar *tmp;
858 if (len + total > crypto->insize)
859 len = crypto->blocksize;
861 if (which == STATUS_ENCRYPT)
862 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
863 else
864 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
866 if (rc)
867 goto done;
869 tmp = (guchar *)crypto->inbuf + total;
870 memmove(tmp, p, len);
871 total += len;
873 if (total >= crypto->insize)
874 break;
876 pth_cancel_point();
879 done:
880 pth_cleanup_pop(1);
881 return rc;
884 /* The crypto struct must be setup for iterations and .key. */
885 gpg_error_t do_xml_encrypt(struct client_s *client,
886 struct client_crypto_s *crypto, const gchar *filename)
888 goffset len = crypto->insize;
889 gpointer inbuf;
890 gchar *p;
891 gpg_error_t rc;
892 guint64 iter_progress = 0ULL, n_iter = 0ULL, xiter = 0ULL;
893 gchar tmp[FILENAME_MAX];
894 struct stat st;
895 mode_t mode = 0;
896 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
898 if (!crypto->fh->ver.fh2.iter) {
900 * cache_file_count() needs both .used == TRUE and a valid key in
901 * order for it to count as a used cache entry. Fixes CACHE status
902 * messages.
904 memset(crypto->key, '!', hashlen);
905 goto write_file;
909 * Resize the existing xml buffer to the block size required by gcrypt
910 * rather than duplicating it and wasting memory.
912 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
914 if (crypto->insize % crypto->blocksize)
915 len += crypto->blocksize;
917 inbuf = gcry_realloc(crypto->inbuf, len);
919 if (!inbuf) {
920 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
921 return gpg_error_from_errno(ENOMEM);
924 crypto->inbuf = inbuf;
925 crypto->insize = len;
926 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
928 if (crypto->tkey)
929 gcry_free(crypto->tkey);
931 crypto->tkey = gcry_malloc(hashlen);
933 if (!crypto->tkey) {
934 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
935 return gpg_error_from_errno(ENOMEM);
938 memcpy(crypto->tkey, crypto->key, hashlen);
939 guchar *tkey = crypto->tkey;
940 tkey[0] ^= 1;
942 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
943 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
944 return rc;
947 iter_progress = (guint64)get_key_file_double(
948 client ? client->filename : "global", "iteration_progress");
950 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
951 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
952 "0 %llu", crypto->fh->ver.fh2.iter);
954 if (rc)
955 return rc;
958 while (xiter < crypto->fh->ver.fh2.iter-1) {
959 if (iter_progress > 0ULL && xiter >= iter_progress) {
960 if (!(xiter % iter_progress)) {
961 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
962 "%llu %llu", ++n_iter * iter_progress,
963 crypto->fh->ver.fh2.iter);
965 if (rc)
966 return rc;
970 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
971 crypto->blocksize))) {
972 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
973 return rc;
976 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
978 if (rc) {
979 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
980 return rc;
983 xiter++;
986 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
987 crypto->blocksize))) {
988 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
989 return rc;
992 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
993 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
994 return rc;
997 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
999 if (rc)
1000 return rc;
1002 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1003 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1004 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1006 if (rc)
1007 return rc;
1010 write_file:
1011 tmp[0] = 0;
1013 if (filename) {
1014 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1015 crypto->fh->fd = STDOUT_FILENO;
1016 goto do_write_file;
1019 if (lstat(filename, &st) == 0) {
1020 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1022 if (!(mode & S_IWUSR))
1023 return gpg_error_from_errno(EACCES);
1025 else if (errno != ENOENT)
1026 return gpg_error_from_errno(errno);
1028 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1029 crypto->fh->fd = mkstemp(tmp);
1031 if (crypto->fh->fd == -1) {
1032 rc = errno;
1033 p = strrchr(tmp, '/');
1034 p++;
1035 log_write("%s: %s", p, strerror(rc));
1036 return gpg_error_from_errno(rc);
1039 pth_cleanup_push(cleanup_unlink_cb, tmp);
1041 else
1043 * xml_import() or convert_file() from command line.
1045 crypto->fh->fd = STDOUT_FILENO;
1047 do_write_file:
1048 crypto->fh->ver.fh2.magic[0] = '\177';
1049 crypto->fh->ver.fh2.magic[1] = 'P';
1050 crypto->fh->ver.fh2.magic[2] = 'W';
1051 crypto->fh->ver.fh2.magic[3] = 'M';
1052 crypto->fh->ver.fh2.magic[4] = 'D';
1053 crypto->fh->ver.fh2.version = VERSION_HEX;
1054 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1056 if (len != sizeof(crypto->fh->ver.fh2)) {
1057 len = errno;
1059 if (tmp[0])
1060 pth_cleanup_pop(1);
1062 return gpg_error_from_errno(len);
1065 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1067 if (len != crypto->insize) {
1068 len = errno;
1070 if (tmp[0])
1071 pth_cleanup_pop(1);
1073 return gpg_error_from_errno(len);
1076 if (fsync(crypto->fh->fd) == -1) {
1077 len = errno;
1079 if (tmp[0])
1080 pth_cleanup_pop(1);
1082 return gpg_error_from_errno(len);
1085 if (tmp[0]) {
1086 #ifdef WITH_LIBACL
1087 acl_t acl;
1088 #endif
1089 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1090 gchar tmp2[FILENAME_MAX];
1092 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1093 #ifdef WITH_LIBACL
1094 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1096 if (!acl)
1097 log_write("ACL: %s: %s", filename, strerror(errno));
1098 #endif
1100 if (rename(filename, tmp2) == -1) {
1101 len = errno;
1102 pth_cleanup_pop(1);
1103 #ifdef WITH_LIBACL
1104 if (acl)
1105 acl_free(acl);
1106 #endif
1107 return gpg_error_from_errno(len);
1110 #ifdef WITH_LIBACL
1111 else {
1112 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1114 if (!acl)
1115 log_write("ACL: %s: %s", filename, strerror(errno));
1117 #endif
1119 if (rename(tmp, filename) == -1) {
1120 len = errno;
1121 pth_cleanup_pop(1);
1122 #ifdef WITH_LIBACL
1123 if (acl)
1124 acl_free(acl);
1125 #endif
1126 return gpg_error_from_errno(len);
1129 pth_cleanup_pop(0);
1131 if (mode)
1132 chmod(filename, mode);
1134 #ifdef WITH_LIBACL
1135 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1136 log_write("ACL: %s: %s", filename, strerror(errno));
1138 if (acl)
1139 acl_free(acl);
1140 #endif
1143 if (client && lstat(filename, &st) == 0)
1144 client->mtime = st.st_mtime;
1146 return 0;
1149 gpg_error_t update_save_flags(const gchar *filename,
1150 struct client_crypto_s *crypto)
1152 gpg_error_t rc;
1153 guint64 iter;
1155 /* New file? */
1156 if (!crypto->fh) {
1157 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1159 if (!crypto->fh)
1160 return GPG_ERR_ENOMEM;
1163 rc = init_client_crypto2(filename, crypto);
1165 if (rc)
1166 return rc;
1168 if (filename && !crypto->fh->v1) {
1169 iter = (guint64)get_key_file_double(filename, "iterations");
1170 crypto->fh->ver.fh2.iter = iter < 0L ? 0UL : iter;
1173 return 0;
1176 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1177 gboolean cached)
1179 struct client_s *client = assuan_get_pointer(ctx);
1180 gpointer xmlbuf;
1181 gulong outsize = 0;
1182 guint len;
1183 gint clevel;
1184 gint timeout;
1185 gpointer outbuf;
1186 gint zrc;
1187 gpg_error_t rc;
1189 if (client->crypto->key && client->crypto->key != key)
1190 gcry_free(client->crypto->key);
1192 client->crypto->key = key;
1193 rc = update_timestamp(client->doc);
1195 if (rc)
1196 return send_error(ctx, rc);
1198 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1199 pth_cleanup_push(xmlFree, xmlbuf);
1200 clevel = get_key_file_integer(client->filename, "compression_level");
1202 if (clevel < 0)
1203 clevel = 0;
1205 if (do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
1206 pth_cleanup_pop(1);
1207 cleanup_crypto(&client->crypto);
1209 if (zrc == Z_MEM_ERROR)
1210 return send_syserror(ctx, ENOMEM);
1211 else
1212 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1214 else {
1215 pth_cleanup_pop(1);
1216 xmlbuf = outbuf;
1217 len = outsize;
1220 client->crypto->inbuf = xmlbuf;
1221 client->crypto->insize = len;
1222 rc = update_save_flags(client->filename, client->crypto);
1224 if (rc) {
1225 cleanup_crypto(&client->crypto);
1226 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1227 return send_error(ctx, rc);
1230 rc = do_xml_encrypt(client, client->crypto, client->filename);
1232 if (rc) {
1233 cleanup_crypto(&client->crypto);
1234 return send_error(ctx, rc);
1237 timeout = get_key_file_integer(client->filename, "cache_timeout");
1238 CACHE_LOCK(client->ctx);
1240 if (cached) {
1241 cache_reset_timeout(client->md5file, timeout);
1242 CACHE_UNLOCK;
1244 if (client->new == TRUE)
1245 send_status_all(STATUS_CACHE);
1247 client->new = FALSE;
1248 cleanup_crypto(&client->crypto);
1249 return send_error(ctx, 0);
1252 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1253 CACHE_UNLOCK;
1254 cleanup_crypto(&client->crypto);
1255 return send_syserror(ctx, ENOMEM);
1258 client->new = FALSE;
1259 cache_reset_timeout(client->md5file, timeout);
1260 CACHE_UNLOCK;
1261 send_status_all(STATUS_CACHE);
1262 cleanup_crypto(&client->crypto);
1263 return send_error(ctx, 0);
1266 static gint save_command(assuan_context_t ctx, gchar *line)
1268 gboolean cached = FALSE;
1269 struct stat st;
1270 struct client_s *client = assuan_get_pointer(ctx);
1271 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1273 if (line && *line)
1274 log_write2("ARGS=%s", "<passphrase>");
1276 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1277 return send_syserror(ctx, errno);
1279 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1280 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1281 return send_error(ctx, GPG_ERR_ENOANO);
1284 CACHE_LOCK(ctx);
1285 cached = cache_iscached(client->md5file);
1286 CACHE_UNLOCK;
1289 * If a cache entry doesn't exist for this file and the file has a
1290 * "key_file" or "key" parameter, then it's an error. The reason is that
1291 * cache expiration would be useless.
1293 if (cached == FALSE) {
1294 gchar *tmp = get_key_file_string(client->filename, "key_file");
1296 if (tmp) {
1297 g_free(tmp);
1298 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1302 cached = FALSE;
1304 /* New file? */
1305 if (!client->crypto) {
1306 client->crypto = init_client_crypto();
1308 if (!client->crypto) {
1309 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1310 return send_syserror(ctx, ENOMEM);
1314 client->crypto->key = gcry_malloc(hashlen);
1316 if (!client->crypto->key) {
1317 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1318 cleanup_crypto(&client->crypto);
1319 return send_syserror(ctx, ENOMEM);
1322 memset(client->crypto->key, '!', hashlen);
1324 if (get_key_file_double(client->filename, "iterations") <= 0L)
1325 goto done;
1327 if (!line || !*line) {
1328 client->crypto->tkey = gcry_malloc(hashlen);
1330 if (!client->crypto->tkey) {
1331 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1332 cleanup_crypto(&client->crypto);
1333 return send_syserror(ctx, ENOMEM);
1336 memset(client->crypto->tkey, '!', hashlen);
1337 CACHE_LOCK(ctx);
1339 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1340 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1341 CACHE_UNLOCK;
1343 #ifdef WITH_PINENTRY
1344 gpg_error_t rc;
1346 if (client->pinentry->enable == FALSE ||
1347 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1348 /* Empty keys are allowed. */
1349 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1350 goto done;
1353 lock_pin_mutex(client);
1354 client->pinentry->which = PINENTRY_SAVE;
1355 rc = pinentry_fork(ctx);
1357 if (rc) {
1358 unlock_pin_mutex(client->pinentry);
1359 cleanup_crypto(&client->crypto);
1360 return send_error(ctx, rc);
1363 client->pinentry->cb = save_command_finalize;
1364 client->pinentry->status = PINENTRY_INIT;
1365 return 0;
1366 #else
1367 /* Empty keys are allowed. */
1368 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1369 goto done;
1370 #endif
1372 else {
1373 CACHE_UNLOCK;
1374 cached = TRUE;
1377 else
1378 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1379 strlen(line));
1381 done:
1382 return save_command_finalize(ctx, client->crypto->key, cached);
1385 static gint delete_command(assuan_context_t ctx, gchar *line)
1387 struct client_s *client = assuan_get_pointer(ctx);
1388 gchar **req;
1389 gpg_error_t rc;
1390 xmlNodePtr n;
1392 log_write2("ARGS=\"%s\"", line);
1394 if (strchr(line, '\t'))
1395 req = split_input_line(line, "\t", -1);
1396 else
1397 req = split_input_line(line, " ", -1);
1399 if (!req || !*req)
1400 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1402 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1404 if (!n) {
1405 g_strfreev(req);
1406 return send_error(ctx, rc);
1410 * No sub-node defined. Remove the entire node (root element).
1412 if (!req[1]) {
1413 if (n) {
1414 xmlUnlinkNode(n);
1415 xmlFreeNode(n);
1418 g_strfreev(req);
1419 return send_error(ctx, 0);
1422 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1423 g_strfreev(req);
1425 if (!n)
1426 return send_error(ctx, rc);
1428 if (n) {
1429 xmlUnlinkNode(n);
1430 xmlFreeNode(n);
1433 return send_error(ctx, 0);
1437 * Don't return with assuan_process_done() here. This has been called from
1438 * assuan_process_next() and the command should be finished in
1439 * client_thread().
1441 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1442 gsize len)
1444 assuan_context_t ctx = data;
1445 struct client_s *client = assuan_get_pointer(ctx);
1446 gchar **req;
1447 xmlNodePtr n;
1448 gpg_error_t rc = file_modified(client);
1450 if (assuan_rc || rc) {
1451 if (line)
1452 xfree(line);
1453 return assuan_rc ? assuan_rc : rc;
1456 req = split_input_line((gchar *)line, "\t", 0);
1457 xfree(line);
1459 if (!req || !*req)
1460 return EPWMD_COMMAND_SYNTAX;
1462 again:
1463 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1465 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1466 rc = new_root_element(client->doc, *req);
1468 if (rc) {
1469 g_strfreev(req);
1470 return rc;
1473 goto again;
1476 if (!n) {
1477 g_strfreev(req);
1478 return rc;
1481 if (req[1]) {
1482 if (!n->children)
1483 create_elements_cb(n, req+1, &rc, NULL);
1484 else
1485 find_elements(client->doc, n->children, req+1, &rc,
1486 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1489 g_strfreev(req);
1490 client->inquire_status = INQUIRE_DONE;
1491 return rc;
1494 static gint store_command(assuan_context_t ctx, gchar *line)
1496 struct client_s *client = assuan_get_pointer(ctx);
1497 gpg_error_t rc;
1499 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1501 if (rc)
1502 return send_error(ctx, rc);
1504 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1505 client->inquire_status = INQUIRE_BUSY;
1506 return 0;
1509 static void *send_data_cb(void *arg)
1511 struct assuan_cmd_s *data = arg;
1512 gint old;
1513 gpg_error_t *rc;
1515 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1516 rc = g_malloc(sizeof(gpg_error_t));
1517 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1518 pth_cancel_state(old, NULL);
1519 pth_exit(rc);
1520 return NULL;
1523 /* For every assuan command that needs to be sent to the client, a timeout is
1524 * needed to determine if the client lost the connection. The timeout is the
1525 * same as the "keepalive" configuration parameter or a default if unset.
1527 gpg_error_t do_assuan_command(assuan_context_t ctx,
1528 void *(*cb)(void *data), void *data)
1530 pth_attr_t attr = pth_attr_new();
1531 pth_t tid;
1532 gint n;
1533 gint to = get_key_file_integer("global", "keepalive");
1534 pth_event_t ev, tev;
1535 pth_status_t st;
1536 gpg_error_t rc = 0;
1537 void *p;
1539 pth_attr_init(attr);
1540 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1541 tid = pth_spawn(attr, cb, data);
1542 n = errno;
1543 pth_attr_destroy(attr);
1545 if (!tid) {
1546 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1547 _gpg_strerror(gpg_error_from_errno(n)));
1548 return gpg_error_from_errno(n);
1551 pth_cleanup_push(cleanup_cancel_cb, tid);
1552 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1553 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1554 tev = pth_event(PTH_EVENT_TIME, pth_timeout(to, 0));
1555 ev = pth_event_concat(ev, tev, NULL);
1556 pth_cleanup_push(cleanup_ev_cb, ev);
1557 pth_yield(tid);
1558 pth_wait(ev);
1559 st = pth_event_status(ev);
1561 if (st == PTH_STATUS_FAILED) {
1562 pth_cancel(tid);
1563 pth_join(tid, &p);
1564 g_free(p);
1565 rc = GPG_ERR_ASS_WRITE_ERROR;
1567 else if (st == PTH_STATUS_OCCURRED) {
1568 pth_join(tid, &p);
1569 rc = *(gpg_error_t *)p;
1570 g_free(p);
1572 else {
1573 st = pth_event_status(tev);
1575 if (st == PTH_STATUS_OCCURRED) {
1576 pth_cancel(tid);
1577 pth_join(tid, &p);
1578 g_free(p);
1579 rc = GPG_ERR_ASS_WRITE_ERROR;
1583 pth_cleanup_pop(1);
1584 pth_cleanup_pop(0);
1585 return rc;
1588 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1589 gint total)
1591 gint to_send;
1592 gint sent = 0;
1593 gpg_error_t rc;
1594 struct assuan_cmd_s data;
1595 gint progress = get_key_file_integer("global", "xfer_progress");
1596 gint flush = 0;
1598 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1599 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1600 data.ctx = ctx;
1601 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1603 if (rc)
1604 return rc;
1606 again:
1607 do {
1608 if (sent + to_send > total)
1609 to_send = total - sent;
1611 data.line = flush ? NULL : (gchar *)line+sent;
1612 data.line_len = flush ? 0 : to_send;
1613 rc = do_assuan_command(ctx, send_data_cb, &data);
1615 if (!rc) {
1616 sent += flush ? 0 : to_send;
1618 if ((progress && !(sent % progress) && sent != total) ||
1619 (sent == total && flush))
1620 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1622 if (!flush && !rc && sent == total) {
1623 flush = 1;
1624 goto again;
1627 } while (!rc && sent < total);
1629 return rc;
1632 static gint get_command(assuan_context_t ctx, gchar *line)
1634 struct client_s *client = assuan_get_pointer(ctx);
1635 gchar **req;
1636 gpg_error_t rc;
1637 xmlNodePtr n;
1639 log_write2("ARGS=\"%s\"", line);
1640 req = split_input_line(line, "\t", -1);
1642 if (!req || !*req) {
1643 g_strfreev(req);
1644 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1647 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1649 if (!n) {
1650 g_strfreev(req);
1651 return send_error(ctx, rc);
1654 if (req[1])
1655 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1657 g_strfreev(req);
1659 if (rc)
1660 return send_error(ctx, rc);
1662 if (!n || !n->children)
1663 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1665 n = find_text_node(n->children);
1667 if (!n || !n->content || !*n->content)
1668 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1670 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
1671 return send_error(ctx, rc);
1674 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1675 gpg_error_t *rc, gchar **req_orig, void *data)
1677 gchar *path = *(gchar **)data;
1678 gchar *tmp = NULL, *result;
1680 if (path) {
1681 g_free(path);
1682 *(gchar **)data = NULL;
1685 path = g_strjoinv("\t", target);
1687 if (!path) {
1688 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1689 *rc = gpg_error_from_errno(ENOMEM);
1690 return NULL;
1693 if (req_orig) {
1694 tmp = g_strjoinv("\t", req_orig);
1696 if (!tmp) {
1697 g_free(path);
1698 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1699 *rc = gpg_error_from_errno(ENOMEM);
1700 return NULL;
1704 if (tmp && *tmp)
1705 result = g_strdup_printf("%s\t%s", path, tmp);
1706 else
1707 result = g_strdup(path);
1709 if (!result) {
1710 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1711 *rc = gpg_error_from_errno(ENOMEM);
1712 g_free(path);
1713 g_free(tmp);
1714 return NULL;
1717 g_free(path);
1718 g_free(tmp);
1719 *(gchar **)data = result;
1720 return node;
1723 static void list_command_cleanup1(void *arg);
1724 static gint realpath_command(assuan_context_t ctx, gchar *line)
1726 gpg_error_t rc;
1727 struct client_s *client = assuan_get_pointer(ctx);
1728 gchar **req;
1729 gchar *t;
1730 gint i;
1731 xmlNodePtr n;
1732 GString *string;
1733 gchar *rp = NULL;
1735 log_write2("ARGS=\"%s\"", line);
1737 if (strchr(line, '\t') != NULL) {
1738 if ((req = split_input_line(line, "\t", 0)) == NULL)
1739 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1741 else {
1742 if ((req = split_input_line(line, " ", 0)) == NULL)
1743 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1746 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1748 if (!n) {
1749 g_strfreev(req);
1750 return send_error(ctx, rc);
1753 rp = g_strjoinv("\t", req);
1755 if (!rp) {
1756 g_strfreev(req);
1757 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1758 return send_syserror(ctx, ENOMEM);
1761 if (req[1]) {
1762 n = find_elements(client->doc, n->children, req+1, &rc,
1763 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
1765 if (!n) {
1766 g_free(rp);
1767 g_strfreev(req);
1768 return send_error(ctx, rc);
1772 string = g_string_new(rp);
1773 g_free(rp);
1774 g_strfreev(req);
1776 if (!string) {
1777 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1778 return send_syserror(ctx, ENOMEM);
1781 again:
1782 for (i = 0, t = string->str + i; *t; t++, i++) {
1783 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1784 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1785 goto again;
1789 pth_cleanup_push(list_command_cleanup1, string);
1790 rc = xfer_data(ctx, string->str, string->len);
1791 pth_cleanup_pop(1);
1792 return send_error(ctx, rc);
1795 static void list_command_cleanup1(void *arg)
1797 g_string_free((GString *)arg, TRUE);
1800 static void list_command_cleanup2(void *arg)
1802 struct element_list_s *elements = arg;
1804 if (elements) {
1805 gint total = g_slist_length(elements->list);
1806 gint i;
1808 for (i = 0; i < total; i++) {
1809 gchar *tmp = g_slist_nth_data(elements->list, i);
1810 g_free(tmp);
1813 g_slist_free(elements->list);
1815 if (elements->prefix)
1816 g_free(elements->prefix);
1818 g_free(elements);
1822 static gint list_command(assuan_context_t ctx, gchar *line)
1824 struct client_s *client = assuan_get_pointer(ctx);
1825 gpg_error_t rc;
1826 struct element_list_s *elements = NULL;
1827 gchar *tmp;
1829 if (disable_list_and_dump == TRUE)
1830 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1832 log_write2("ARGS=\"%s\"", line);
1834 if (!*line) {
1835 GString *str;
1837 rc = list_root_elements(client->doc, &str);
1839 if (rc)
1840 return send_error(ctx, rc);
1842 pth_cleanup_push(list_command_cleanup1, str);
1843 rc = xfer_data(ctx, str->str, str->len);
1844 pth_cleanup_pop(1);
1845 return send_error(ctx, rc);
1848 elements = g_malloc0(sizeof(struct element_list_s));
1850 if (!elements) {
1851 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1852 rc = gpg_err_code_from_errno(ENOMEM);
1853 goto fail;
1856 pth_cleanup_push(list_command_cleanup2, elements);
1857 rc = create_path_list(client->doc, elements, line);
1859 if (rc)
1860 goto fail;
1862 if (elements) {
1863 gint total = g_slist_length(elements->list);
1864 gint i;
1865 GString *str;
1867 if (!total) {
1868 rc = EPWMD_EMPTY_ELEMENT;
1869 goto fail;
1872 str = g_string_new(NULL);
1874 if (!str) {
1875 rc = gpg_err_code_from_errno(ENOMEM);
1876 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1877 goto fail;
1880 for (i = 0; i < total; i++) {
1881 tmp = g_slist_nth_data(elements->list, i);
1882 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1885 pth_cleanup_push(list_command_cleanup1, str);
1886 rc = xfer_data(ctx, str->str, str->len);
1887 pth_cleanup_pop(1);
1889 else
1890 rc = EPWMD_EMPTY_ELEMENT;
1892 fail:
1893 pth_cleanup_pop(1);
1894 return send_error(ctx, rc);
1898 * req[0] - element path
1900 static gint attribute_list(assuan_context_t ctx, gchar **req)
1902 struct client_s *client = assuan_get_pointer(ctx);
1903 gchar **attrlist = NULL;
1904 gint i = 0;
1905 gchar **path = NULL;
1906 xmlAttrPtr a;
1907 xmlNodePtr n, an;
1908 gchar *line;
1909 gpg_error_t rc;
1911 if (!req || !req[0])
1912 return EPWMD_COMMAND_SYNTAX;
1914 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1916 * The first argument may be only a root element.
1918 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1919 return EPWMD_COMMAND_SYNTAX;
1922 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
1924 if (!n) {
1925 g_strfreev(path);
1926 return rc;
1929 if (path[1]) {
1930 n = find_elements(client->doc, n->children, path+1, &rc,
1931 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1933 if (!n) {
1934 g_strfreev(path);
1935 return rc;
1939 g_strfreev(path);
1941 for (a = n->properties; a; a = a->next) {
1942 gchar **pa;
1944 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1945 if (attrlist)
1946 g_strfreev(attrlist);
1948 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1949 return gpg_error_from_errno(ENOMEM);
1952 attrlist = pa;
1953 an = a->children;
1954 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
1955 an && an->content ? (gchar *)an->content : "");
1957 if (!attrlist[i]) {
1958 g_strfreev(attrlist);
1959 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1960 return gpg_error_from_errno(ENOMEM);
1963 attrlist[++i] = NULL;
1966 if (!attrlist)
1967 return EPWMD_EMPTY_ELEMENT;
1969 line = g_strjoinv("\n", attrlist);
1971 if (!line) {
1972 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1973 g_strfreev(attrlist);
1974 return gpg_error_from_errno(ENOMEM);
1977 pth_cleanup_push(g_free, line);
1978 pth_cleanup_push(req_cleanup, attrlist);
1979 rc = xfer_data(ctx, line, strlen(line));
1980 pth_cleanup_pop(1);
1981 pth_cleanup_pop(1);
1982 return rc;
1986 * req[0] - attribute
1987 * req[1] - element path
1989 static gint attribute_delete(struct client_s *client, gchar **req)
1991 xmlNodePtr n;
1992 gchar **path = NULL;
1993 gpg_error_t rc;
1995 if (!req || !req[0] || !req[1])
1996 return EPWMD_COMMAND_SYNTAX;
1998 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2000 * The first argument may be only a root element.
2002 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2003 return EPWMD_COMMAND_SYNTAX;
2007 * Don't remove the "name" attribute for the root element. To remove an
2008 * root element use DELETE <name>.
2010 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
2011 rc = EPWMD_ATTR_SYNTAX;
2012 goto fail;
2015 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2017 if (!n)
2018 goto fail;
2020 if (path[1]) {
2021 n = find_elements(client->doc, n->children, path+1, &rc,
2022 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2024 if (!n)
2025 goto fail;
2028 g_strfreev(path);
2029 return delete_attribute(n, (xmlChar *)req[0]);
2031 fail:
2032 g_strfreev(path);
2033 return rc;
2036 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2037 gpg_error_t *rc)
2039 gchar **src = *path;
2040 gchar **src_orig = g_strdupv(src);
2041 xmlNodePtr n = NULL;
2043 *rc = 0;
2045 if (!src_orig) {
2046 *rc = gpg_error_from_errno(ENOMEM);
2047 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2048 goto fail;
2051 again:
2052 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2054 if (!n) {
2055 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
2056 *rc = new_root_element(client->doc, src[0]);
2058 if (*rc)
2059 goto fail;
2061 goto again;
2063 else
2064 goto fail;
2067 if (src[1]) {
2068 if (!n->children)
2069 n = create_target_elements_cb(n, src+1, rc, NULL);
2070 else
2071 n = find_elements(client->doc, n->children, src+1, rc,
2072 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2074 if (!n)
2075 goto fail;
2078 * Reset the position of the element tree now that the elements
2079 * have been created.
2081 g_strfreev(src);
2082 src = src_orig;
2083 src_orig = NULL;
2084 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2086 if (!n)
2087 goto fail;
2089 n = find_elements(client->doc, n->children, src+1, rc,
2090 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2092 if (!n)
2093 goto fail;
2096 fail:
2097 if (src_orig)
2098 g_strfreev(src_orig);
2100 *path = src;
2101 return n;
2105 * Creates a "target" attribute. When other commands encounter an element with
2106 * this attribute, the element path is modified to the target value. If the
2107 * source element path doesn't exist when using 'ATTR SET target', it is
2108 * created, but the destination element path must exist.
2110 * req[0] - source element path
2111 * req[1] - destination element path
2113 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2115 gchar **src, **dst, *line = NULL, **odst = NULL;
2116 gpg_error_t rc;
2117 xmlNodePtr n;
2119 if (!req || !req[0] || !req[1])
2120 return EPWMD_COMMAND_SYNTAX;
2122 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2124 * The first argument may be only a root element.
2126 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2127 return EPWMD_COMMAND_SYNTAX;
2130 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2132 * The first argument may be only a root element.
2134 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2135 rc = EPWMD_COMMAND_SYNTAX;
2136 goto fail;
2140 odst = g_strdupv(dst);
2142 if (!odst) {
2143 rc = gpg_error_from_errno(ENOMEM);
2144 goto fail;
2147 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2150 * Make sure the destination element path exists.
2152 if (!n)
2153 goto fail;
2155 if (dst[1]) {
2156 n = find_elements(client->doc, n->children, dst+1, &rc,
2157 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2159 if (!n)
2160 goto fail;
2163 n = create_element_path(client, &src, &rc);
2165 if (rc)
2166 goto fail;
2168 line = g_strjoinv("\t", odst);
2170 if (!line) {
2171 rc = gpg_error_from_errno(ENOMEM);
2172 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2173 goto fail;
2176 rc = add_attribute(n, "target", line);
2178 fail:
2179 g_free(line);
2180 g_strfreev(src);
2181 g_strfreev(dst);
2182 g_strfreev(odst);
2183 return rc;
2187 * req[0] - name
2188 * req[1] - new name
2190 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2192 gpg_error_t rc;
2193 gchar **tmp;
2194 xmlNodePtr n;
2196 tmp = g_strdupv(req);
2198 if (!tmp) {
2199 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2200 return gpg_error_from_errno(ENOMEM);
2203 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2204 g_strfreev(tmp);
2206 if (!n)
2207 return rc;
2209 if (g_utf8_collate(req[0], req[1]) == 0)
2210 return 0;
2213 * Will not overwrite an existing root.
2215 tmp = g_strdupv(req+1);
2217 if (!tmp) {
2218 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2219 return gpg_error_from_errno(ENOMEM);
2222 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2223 g_strfreev(tmp);
2225 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
2226 return rc;
2228 if (n)
2229 return GPG_ERR_AMBIGUOUS_NAME;
2232 * Whitespace not allowed in root names.
2234 if (contains_whitespace(req[1]) == TRUE)
2235 return EPWMD_ATTR_SYNTAX;
2237 tmp = g_strdupv(req);
2239 if (!tmp) {
2240 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2241 return gpg_error_from_errno(ENOMEM);
2244 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2245 g_strfreev(tmp);
2247 if (!n)
2248 return EPWMD_ELEMENT_NOT_FOUND;
2250 return add_attribute(n, "name", req[1]);
2254 * req[0] - attribute
2255 * req[1] - element path
2257 static gint attribute_get(assuan_context_t ctx, gchar **req)
2259 struct client_s *client = assuan_get_pointer(ctx);
2260 xmlNodePtr n;
2261 xmlChar *a;
2262 gchar **path= NULL;
2263 gpg_error_t rc;
2265 if (!req || !req[0] || !req[1])
2266 return EPWMD_COMMAND_SYNTAX;
2268 if (strchr(req[1], '\t')) {
2269 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2270 return EPWMD_COMMAND_SYNTAX;
2272 else {
2273 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2274 return EPWMD_COMMAND_SYNTAX;
2277 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2279 if (!n)
2280 goto fail;
2282 if (path[1]) {
2283 n = find_elements(client->doc, n->children, path+1, &rc,
2284 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2286 if (!n)
2287 goto fail;
2290 g_strfreev(path);
2292 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2293 return EPWMD_ATTR_NOT_FOUND;
2295 pth_cleanup_push(xmlFree, a);
2297 if (*a)
2298 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2299 else
2300 rc = GPG_ERR_NO_VALUE;
2302 pth_cleanup_pop(1);
2303 return rc;
2305 fail:
2306 g_strfreev(path);
2307 return rc;
2311 * req[0] - attribute
2312 * req[1] - element path
2313 * req[2] - value
2315 static gint attribute_set(struct client_s *client, gchar **req)
2317 gchar **path = NULL;
2318 gpg_error_t rc;
2319 xmlNodePtr n;
2321 if (!req || !req[0] || !req[1])
2322 return EPWMD_COMMAND_SYNTAX;
2325 * Reserved attribute names.
2327 if (!strcmp(req[0], "name")) {
2329 * Only reserved for the root element. Not the rest of the
2330 * document.
2332 if (strchr(req[1], '\t') == NULL)
2333 return name_attribute(client, req + 1);
2335 else if (!strcmp(req[0], "target"))
2336 return target_attribute(client, req + 1);
2338 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2340 * The first argument may be only a root element.
2342 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2343 return EPWMD_COMMAND_SYNTAX;
2346 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2348 if (!n)
2349 goto fail;
2351 if (path[1]) {
2352 n = find_elements(client->doc, n->children, path+1, &rc,
2353 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2355 if (!n)
2356 goto fail;
2359 g_strfreev(path);
2360 return add_attribute(n, req[0], req[2]);
2362 fail:
2363 g_strfreev(path);
2364 return rc;
2368 * req[0] - command
2369 * req[1] - attribute name or element path if command is LIST
2370 * req[2] - element path
2371 * req[2] - element path or value
2373 static gint attr_command(assuan_context_t ctx, gchar *line)
2375 struct client_s *client = assuan_get_pointer(ctx);
2376 gchar **req;
2377 gpg_error_t rc = 0;
2379 log_write2("ARGS=\"%s\"", line);
2380 req = split_input_line(line, " ", 4);
2382 if (!req || !req[0] || !req[1]) {
2383 g_strfreev(req);
2384 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2387 pth_cleanup_push(req_cleanup, req);
2389 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2390 rc = attribute_set(client, req+1);
2391 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2392 rc = attribute_get(ctx, req+1);
2393 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2394 rc = attribute_delete(client, req+1);
2395 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2396 rc = attribute_list(ctx, req+1);
2397 else
2398 rc = EPWMD_COMMAND_SYNTAX;
2400 pth_cleanup_pop(1);
2401 return send_error(ctx, rc);
2404 static gint iscached_command(assuan_context_t ctx, gchar *line)
2406 gchar **req = split_input_line(line, " ", 0);
2407 guchar md5file[16];
2408 gchar *path, *tmp;
2410 if (!req || !*req) {
2411 g_strfreev(req);
2412 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2415 log_write2("ARGS=\"%s\"", line);
2417 if (!valid_filename(req[0])) {
2418 g_strfreev(req);
2419 return EPWMD_INVALID_FILENAME;
2422 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2423 CACHE_LOCK(ctx);
2425 if (cache_iscached(md5file)) {
2426 g_strfreev(req);
2427 CACHE_UNLOCK;
2428 return send_error(ctx, 0);
2431 CACHE_UNLOCK;
2432 tmp = get_key_file_string("global", "data_directory");
2434 if (!tmp) {
2435 g_strfreev(req);
2436 return gpg_error_from_errno(ENOMEM);
2439 path = expand_homedir(tmp);
2441 if (!path) {
2442 g_strfreev(req);
2443 g_free(tmp);
2444 return gpg_error_from_errno(ENOMEM);
2447 g_free(tmp);
2448 tmp = path;
2449 path = g_strdup_printf("%s/%s", tmp, req[0]);
2450 g_free(tmp);
2452 if (!path) {
2453 g_strfreev(req);
2454 return gpg_error_from_errno(ENOMEM);
2457 if (access(path, R_OK) == -1) {
2458 gpg_error_t rc = gpg_error_from_syserror();
2460 g_free(path);
2461 g_strfreev(req);
2462 return send_error(ctx, rc);
2465 g_free(path);
2466 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2469 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2471 struct client_s *client = assuan_get_pointer(ctx);
2472 gchar **req = split_input_line(line, " ", 0);
2473 guchar md5file[16];
2475 log_write2("ARGS=\"%s\"", line);
2476 CACHE_LOCK(ctx);
2478 if (!req || !*req) {
2479 g_strfreev(req);
2480 cache_clear(client->md5file, 2);
2481 CACHE_UNLOCK;
2482 return send_error(ctx, 0);
2485 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2486 g_strfreev(req);
2488 if (cache_clear(md5file, 1) == FALSE) {
2489 CACHE_UNLOCK;
2490 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2493 CACHE_UNLOCK;
2494 return send_error(ctx, 0);
2497 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2499 guchar md5file[16];
2500 glong timeout;
2501 gchar **req = split_input_line(line, " ", 0);
2502 gchar *p;
2504 if (!req || !*req || !req[1]) {
2505 g_strfreev(req);
2506 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2509 errno = 0;
2510 timeout = strtol(req[1], &p, 10);
2512 if (errno != 0 || *p != 0 || timeout < -1) {
2513 g_strfreev(req);
2514 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2517 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2518 CACHE_LOCK(client->ctx);
2520 if (cache_set_timeout(md5file, timeout) == FALSE) {
2521 CACHE_UNLOCK;
2522 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2525 CACHE_UNLOCK;
2526 return send_error(ctx, 0);
2529 static gint dump_command(assuan_context_t ctx, gchar *line)
2531 xmlChar *xml;
2532 gint len;
2533 struct client_s *client = assuan_get_pointer(ctx);
2534 gpg_error_t rc;
2536 if (disable_list_and_dump == TRUE)
2537 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2539 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2541 if (!xml) {
2542 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2543 return send_syserror(ctx, ENOMEM);
2546 pth_cleanup_push(xmlFree, xml);
2547 rc = xfer_data(ctx, (gchar *)xml, len);
2548 pth_cleanup_pop(1);
2549 return send_error(ctx, rc);
2552 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2554 struct client_s *client = assuan_get_pointer(ctx);
2555 gpg_error_t rc = 0;
2556 gchar filename[255]={0}, param[747]={0};
2557 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2559 log_write2("ARGS=\"%s\"", line);
2561 if (strchr(line, ' ')) {
2562 sscanf(line, " %254[^ ] %746c", filename, param);
2563 paramp = param;
2564 fp = filename;
2567 if (fp && !valid_filename(fp))
2568 return send_error(ctx, EPWMD_INVALID_FILENAME);
2570 paramp = g_ascii_strdown(paramp, -1);
2572 if (!paramp) {
2573 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2574 return send_syserror(ctx, ENOMEM);
2577 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2578 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2579 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2581 if (!fh && rc != GPG_ERR_ENOENT)
2582 return send_error(ctx, rc);
2584 if (!rc) {
2585 g_free(paramp);
2586 p = g_strdup_printf("%lu", (unsigned long)fh->ver.fh2.iter);
2587 close_file_header(fh);
2589 if (!p) {
2590 log_write("%s(%i): %s", __FILE__, __LINE__,
2591 strerror(ENOMEM));
2592 return send_syserror(ctx, ENOMEM);
2595 goto done;
2599 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2600 #ifdef WITH_PINENTRY
2601 gboolean n;
2603 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2604 n = client->pinentry->enable;
2605 else
2606 n = get_key_file_boolean(fp, "enable_pinentry");
2608 p = g_strdup_printf("%s", n ? "true" : "false");
2610 if (!p) {
2611 log_write("%s(%i): %s", __FILE__, __LINE__,
2612 strerror(ENOMEM));
2613 return send_syserror(ctx, ENOMEM);
2616 goto done;
2617 #else
2618 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2619 #endif
2621 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
2622 #ifdef WITH_PINENTRY
2623 if (fp == client->filename && (client->opts & OPT_PINENTRY_TO))
2624 p = g_strdup_printf("%i", client->pinentry->timeout);
2625 else
2626 p = g_strdup_printf("%i",
2627 get_key_file_integer(fp, "pinentry_timeout"));
2629 if (!p) {
2630 log_write("%s(%i): %s", __FILE__, __LINE__,
2631 strerror(ENOMEM));
2632 return send_syserror(ctx, ENOMEM);
2635 goto done;
2636 #else
2637 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2638 #endif
2641 p = get_key_file_string(fp ? fp : "global", paramp);
2642 g_free(paramp);
2644 if (!p)
2645 return send_error(ctx, GPG_ERR_NO_VALUE);
2647 tmp = expand_homedir(p);
2648 g_free(p);
2650 if (!tmp) {
2651 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2652 return send_syserror(ctx, ENOMEM);
2655 p = tmp;
2656 done:
2657 pth_cleanup_push(g_free, p);
2658 rc = xfer_data(ctx, p, strlen(p));
2659 pth_cleanup_pop(1);
2660 return send_error(ctx, rc);
2663 struct xpath_s {
2664 xmlXPathContextPtr xp;
2665 xmlXPathObjectPtr result;
2666 xmlBufferPtr buf;
2667 gchar **req;
2670 static void xpath_command_cleanup(void *arg)
2672 struct xpath_s *xpath = arg;
2674 req_cleanup(xpath->req);
2676 if (xpath->buf)
2677 xmlBufferFree(xpath->buf);
2679 if (xpath->result)
2680 xmlXPathFreeObject(xpath->result);
2682 if (xpath->xp)
2683 xmlXPathFreeContext(xpath->xp);
2686 static gint xpath_command(assuan_context_t ctx, gchar *line)
2688 struct client_s *client = assuan_get_pointer(ctx);
2689 gpg_error_t rc;
2690 struct xpath_s xpath;
2692 log_write2("ARGS=\"%s\"", line);
2694 if (disable_list_and_dump == TRUE)
2695 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2697 if (!line || !*line)
2698 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2700 memset(&xpath, 0, sizeof(struct xpath_s));
2702 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
2703 if (strv_printf(&xpath.req, "%s", line) == FALSE)
2704 return send_syserror(ctx, ENOMEM);
2707 xpath.xp = xmlXPathNewContext(client->doc);
2709 if (!xpath.xp) {
2710 xpath_command_cleanup(&xpath);
2711 return send_error(ctx, EPWMD_LIBXML_ERROR);
2714 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2716 if (!xpath.result) {
2717 xpath_command_cleanup(&xpath);
2718 return send_error(ctx, EPWMD_LIBXML_ERROR);
2721 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2722 rc = EPWMD_ELEMENT_NOT_FOUND;
2723 goto fail;
2726 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2727 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
2729 if (rc)
2730 goto fail;
2731 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
2732 rc = EPWMD_EMPTY_ELEMENT;
2733 goto fail;
2735 else if (xpath.req[1])
2736 goto fail;
2738 pth_cleanup_push(xpath_command_cleanup, &xpath);
2739 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
2740 xmlBufferLength(xpath.buf));
2741 pth_cleanup_pop(0);
2743 fail:
2744 xpath_command_cleanup(&xpath);
2745 return send_error(ctx, rc);
2748 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
2749 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
2751 struct client_s *client = assuan_get_pointer(ctx);
2752 gpg_error_t rc;
2753 struct xpath_s xpath;
2754 gchar **req = NULL;
2755 gboolean cmd = FALSE; //SET
2757 log_write2("ARGS=\"%s\"", line);
2759 if (disable_list_and_dump == TRUE)
2760 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2762 if (!line || !*line)
2763 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2765 memset(&xpath, 0, sizeof(struct xpath_s));
2767 if ((req = split_input_line(line, " ", 3)) == NULL)
2768 return send_syserror(ctx, ENOMEM);
2770 if (!req[0]) {
2771 rc = GPG_ERR_SYNTAX;
2772 goto fail;
2775 if (!g_ascii_strcasecmp(req[0], "SET"))
2776 cmd = FALSE;
2777 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
2778 cmd = TRUE;
2779 else {
2780 rc = GPG_ERR_SYNTAX;
2781 goto fail;
2784 if (!req[1] || !req[2]) {
2785 rc = GPG_ERR_SYNTAX;
2786 goto fail;
2789 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
2790 rc = gpg_err_code_from_errno(ENOMEM);
2791 goto fail;
2794 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
2795 rc = GPG_ERR_SYNTAX;
2796 goto fail;
2799 xpath.xp = xmlXPathNewContext(client->doc);
2801 if (!xpath.xp) {
2802 rc = EPWMD_LIBXML_ERROR;
2803 goto fail;
2806 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2808 if (!xpath.result) {
2809 rc = EPWMD_LIBXML_ERROR;
2810 goto fail;
2813 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2814 rc = EPWMD_ELEMENT_NOT_FOUND;
2815 goto fail;
2818 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2819 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
2821 fail:
2822 g_strfreev(req);
2823 xpath_command_cleanup(&xpath);
2824 return send_error(ctx, rc);
2827 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2828 gsize len)
2830 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2831 gpg_error_t rc = file_modified(client);
2832 gchar **req, **path = NULL, **path_orig = NULL, *content;
2833 xmlDocPtr doc = NULL;
2834 xmlNodePtr n, root, copy;
2836 if (assuan_rc || rc) {
2837 if (line)
2838 xfree(line);
2839 return assuan_rc ? assuan_rc : rc;
2842 req = split_input_line((gchar *)line, "\t", 2);
2843 xfree(line);
2845 if (!req || !*req)
2846 return EPWMD_COMMAND_SYNTAX;
2848 content = req[0];
2849 path = split_input_line(req[1], "\t", 0);
2851 if (!content || !*content) {
2852 rc = EPWMD_COMMAND_SYNTAX;
2853 goto fail;
2856 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2858 if (!doc) {
2859 rc = EPWMD_LIBXML_ERROR;
2860 goto fail;
2863 root = xmlDocGetRootElement(doc);
2865 if (path) {
2866 path_orig = g_strdupv(path);
2868 if (!path_orig) {
2869 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2870 rc = gpg_error_from_errno(ENOMEM);
2871 goto fail;
2874 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2875 g_strfreev(path_orig);
2876 rc = gpg_error_from_errno(ENOMEM);
2877 goto fail;
2880 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2882 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2883 g_strfreev(path_orig);
2884 goto fail;
2887 if (!rc) {
2888 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
2890 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2891 g_strfreev(path_orig);
2892 goto fail;
2894 else if (!rc) {
2895 xmlNodePtr parent = n->parent;
2897 xmlUnlinkNode(n);
2898 xmlFreeNode(n);
2899 n = parent;
2903 g_strfreev(path);
2904 path = path_orig;
2906 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2907 n = create_element_path(client, &path, &rc);
2909 if (rc)
2910 goto fail;
2913 copy = xmlCopyNode(root, 1);
2914 n = xmlAddChild(n, copy);
2916 if (!n)
2917 rc = EPWMD_LIBXML_ERROR;
2919 else {
2920 /* Check if the content root element can create a DTD root element. */
2921 if (xmlStrcmp((xmlChar *)"root", root->name)) {
2922 rc = EPWMD_COMMAND_SYNTAX;
2923 goto fail;
2926 xmlChar *a;
2928 if ((a = xmlGetProp(root, (xmlChar *)"name")) == NULL) {
2929 rc = EPWMD_COMMAND_SYNTAX;
2930 goto fail;
2933 gchar *tmp = g_strdup((gchar *)a);
2934 xmlFree(a);
2935 gboolean literal = is_literal_element(&tmp);
2937 if (!valid_xml_element((xmlChar *)tmp) || literal) {
2938 g_free(tmp);
2939 rc = EPWMD_INVALID_ELEMENT;
2940 goto fail;
2943 if (strv_printf(&path, "%s", tmp) == FALSE) {
2944 g_free(tmp);
2945 rc = gpg_error_from_errno(ENOMEM);
2946 goto fail;
2949 g_free(tmp);
2950 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
2952 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2953 rc = EPWMD_LIBXML_ERROR;
2954 goto fail;
2957 /* Overwriting the existing tree. */
2958 if (!rc) {
2959 xmlUnlinkNode(n);
2960 xmlFreeNodeList(n);
2963 rc = 0;
2964 xmlSetProp(root, (xmlChar *)"name", (xmlChar *)path[0]);
2965 n = xmlCopyNode(root, 1);
2966 n = xmlAddChild(xmlDocGetRootElement(client->doc), n);
2969 fail:
2970 if (doc)
2971 xmlFreeDoc(doc);
2973 if (path)
2974 g_strfreev(path);
2976 g_strfreev(req);
2977 client->inquire_status = INQUIRE_DONE;
2978 return rc;
2981 static gint import_command(assuan_context_t ctx, gchar *line)
2983 gpg_error_t rc;
2984 struct client_s *client = assuan_get_pointer(ctx);
2986 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2988 if (rc)
2989 return send_error(ctx, rc);
2991 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2992 client->inquire_status = INQUIRE_BUSY;
2993 return 0;
2996 static gpg_error_t do_lock_command(struct client_s *client)
2998 gpg_error_t rc = lock_file_mutex(client);
3000 if (!rc)
3001 client->is_lock_cmd = TRUE;
3003 return send_error(client->ctx, rc);
3006 static gint lock_command(assuan_context_t ctx, gchar *line)
3008 struct client_s *client = assuan_get_pointer(ctx);
3010 return do_lock_command(client);
3013 static gint unlock_command(assuan_context_t ctx, gchar *line)
3015 struct client_s *client = assuan_get_pointer(ctx);
3017 unlock_file_mutex(client);
3018 return send_error(ctx, 0);
3021 static gint getpid_command(assuan_context_t ctx, gchar *line)
3023 gpg_error_t rc;
3024 gchar buf[32];
3025 pid_t pid = getpid();
3027 print_fmt(buf, sizeof(buf), "%i", pid);
3028 rc = xfer_data(ctx, buf, strlen(buf));
3029 return send_error(ctx, rc);
3032 static gint version_command(assuan_context_t ctx, gchar *line)
3034 gpg_error_t rc;
3035 gchar buf[32];
3037 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
3038 rc = xfer_data(ctx, buf, strlen(buf));
3039 return send_error(ctx, rc);
3042 #ifdef WITH_PINENTRY
3043 static void set_option_value(gchar **opt, const gchar *value)
3045 if (opt)
3046 g_free(*opt);
3048 *opt = NULL;
3050 if (value)
3051 *opt = g_strdup(value);
3053 #endif
3055 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3056 const gchar *value)
3058 struct client_s *client = assuan_get_pointer(ctx);
3060 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3061 glong l = 0;
3063 if (value) {
3064 l = strtol(value, NULL, 10);
3066 if (l < 0 || l > 2)
3067 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3070 log_write1("log_level=%li", l);
3071 MUTEX_LOCK(&rcfile_mutex);
3072 g_key_file_set_integer(keyfileh, "global", "log_level", (gint)l);
3073 MUTEX_UNLOCK(&rcfile_mutex);
3074 goto done;
3076 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3077 glong l = 0;
3079 if (value) {
3080 l = strtol(value, NULL, 10);
3082 if (l < 0 || l > 1)
3083 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3086 log_write1("lock_on_open=%li", l);
3087 client->lockonopen = l ? TRUE : FALSE;
3088 goto done;
3090 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3091 guint64 flags;
3092 const gchar *p = value;
3094 if (!client->filename)
3095 return EPWMD_NO_FILE;
3097 if (value) {
3098 flags = pwmd_cipher_str_to_cipher(value);
3100 if (!flags)
3101 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3103 else if (!value)
3104 p = get_key_file_string("global", "cipher");
3106 MUTEX_LOCK(&rcfile_mutex);
3107 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
3108 MUTEX_UNLOCK(&rcfile_mutex);
3109 log_write1("cipher=%s", p);
3111 if (!value)
3112 g_free((gchar *)p);
3114 goto done;
3116 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3117 guint64 n;
3118 gchar *p = NULL;
3120 if (!client->filename)
3121 return EPWMD_NO_FILE;
3123 if (!value) {
3124 MUTEX_LOCK(&rcfile_mutex);
3125 g_key_file_set_double(keyfileh, client->filename, "iterations",
3126 get_key_file_double("global", "iterations"));
3127 MUTEX_UNLOCK(&rcfile_mutex);
3128 log_write1("iterations=%lu",
3129 (guint64)get_key_file_double(client->filename, "iterations"));
3130 goto done;
3133 errno = 0;
3134 n = strtoul(value, &p, 10);
3136 if (errno || (p && *p) || n == G_MAXULONG)
3137 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3139 MUTEX_LOCK(&rcfile_mutex);
3140 g_key_file_set_double(keyfileh,
3141 client->filename ? client->filename : "global", "iterations", n);
3142 MUTEX_UNLOCK(&rcfile_mutex);
3144 if (client->filename)
3145 client->opts |= OPT_ITERATIONS;
3147 log_write1("iterations=%lu", n);
3148 goto done;
3150 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3151 pth_attr_t attr = pth_attr_of(pth_self());
3152 gchar buf[41];
3154 if (!value) {
3155 pth_attr_destroy(attr);
3156 goto done;
3159 print_fmt(buf, sizeof(buf), "%s", value);
3160 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3161 pth_attr_destroy(attr);
3162 log_write1("name=%s", buf);
3163 #ifdef WITH_PINENTRY
3164 if (client->pinentry->name)
3165 g_free(client->pinentry->name);
3167 client->pinentry->name = g_strdup(buf);
3169 if (!client->pinentry->name)
3170 return gpg_error_from_errno(ENOMEM);
3171 #endif
3173 goto done;
3175 #ifdef WITH_PINENTRY
3176 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3177 set_option_value(&client->pinentry->lcmessages, value);
3178 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3179 set_option_value(&client->pinentry->lcctype, value);
3180 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3181 set_option_value(&client->pinentry->ttyname, value);
3182 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3183 set_option_value(&client->pinentry->ttytype, value);
3184 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3185 set_option_value(&client->pinentry->display, value);
3186 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3187 set_option_value(&client->pinentry->path, value);
3188 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3189 set_option_value(&client->pinentry->title, value);
3190 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3191 set_option_value(&client->pinentry->prompt, value);
3192 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3193 set_option_value(&client->pinentry->desc, value);
3194 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3195 gchar *p = NULL;
3196 gint n;
3198 if (!value) {
3199 client->pinentry->timeout =
3200 get_key_file_integer(client->filename, "pinentry_timeout");
3201 client->opts &= ~(OPT_PINENTRY_TO);
3202 log_write1("pinentry_timeout=%i",
3203 get_key_file_integer(client->filename, "pinentry_timeout"));
3204 goto done;
3207 n = strtol(value, &p, 10);
3209 if (*p || n < 0)
3210 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3212 client->pinentry->timeout = n;
3213 client->opts |= OPT_PINENTRY_TO;
3214 log_write1("pinentry_timeout=%i", n);
3215 goto done;
3217 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3218 gchar *p = NULL;
3219 gint n;
3221 if (!value) {
3222 client->pinentry->enable = -1;
3223 client->opts &= ~(OPT_PINENTRY);
3224 goto done;
3227 n = strtol(value, &p, 10);
3229 if (*p || n < 0 || n > 1)
3230 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3232 client->pinentry->enable = n == 0 ? FALSE : TRUE;
3233 client->opts |= OPT_PINENTRY;
3234 log_write1("enable_pinentry=%i", n);
3235 goto done;
3237 #endif
3238 else
3239 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3241 log_write1("%s=%s", name, value ? value : "");
3243 done:
3244 return 0;
3247 static gint unset_command(assuan_context_t ctx, gchar *line)
3249 log_write2("ARGS=\"%s\"", line);
3250 return send_error(ctx, set_unset_common(ctx, line, NULL));
3253 static gint set_command(assuan_context_t ctx, gchar *line)
3255 gchar name[64] = {0}, value[256] = {0};
3257 log_write2("ARGS=\"%s\"", line);
3259 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3260 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3262 return send_error(ctx, set_unset_common(ctx, name, value));
3265 static gint rename_command(assuan_context_t ctx, gchar *line)
3267 struct client_s *client = assuan_get_pointer(ctx);
3268 gpg_error_t rc;
3269 gchar **req, **src, *dst;
3270 xmlNodePtr n, ndst;
3272 log_write2("ARGS=\"%s\"", line);
3273 req = split_input_line(line, " ", -1);
3275 if (!req || !req[0] || !req[1]) {
3276 g_strfreev(req);
3277 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
3280 dst = req[1];
3281 is_literal_element(&dst);
3283 if (!valid_xml_element((xmlChar *)dst)) {
3284 g_strfreev(req);
3285 return EPWMD_INVALID_ELEMENT;
3288 if (strchr(req[0], '\t'))
3289 src = split_input_line(req[0], "\t", -1);
3290 else
3291 src = split_input_line(req[0], " ", -1);
3293 if (!src || !*src) {
3294 rc = EPWMD_COMMAND_SYNTAX;
3295 goto fail;
3298 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3300 if (src[1] && n)
3301 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3302 NULL, FALSE, 0, NULL, FALSE);
3304 if (!n)
3305 goto fail;
3307 /* To prevent unwanted effects:
3309 * <root name="a"><b/></root>
3311 * RENAME a<TAB>b b
3313 if (xmlStrEqual(n->name, (xmlChar *)dst)) {
3314 rc = GPG_ERR_AMBIGUOUS_NAME;
3315 goto fail;
3318 gchar **tmp = NULL;
3320 if (src[1]) {
3321 gchar **p;
3323 for (p = src; *p; p++) {
3324 if (!*(p+1))
3325 break;
3327 strv_printf(&tmp, "%s", *p);
3331 strv_printf(&tmp, "!%s", dst);
3332 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3334 if (!ndst && rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
3335 g_strfreev(tmp);
3336 goto fail;
3339 if (tmp[1] && ndst)
3340 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3341 NULL, NULL, FALSE, 0, NULL, FALSE);
3343 g_strfreev(tmp);
3345 if (!ndst && rc && rc != EPWMD_ELEMENT_NOT_FOUND)
3346 goto fail;
3348 rc = 0;
3350 /* Target may exist:
3352 * <root name="a"/>
3353 * <root name="b" target="a"/>
3355 * RENAME b a
3357 * Would need to do:
3358 * RENAME !b a
3360 if (ndst == n) {
3361 rc = GPG_ERR_AMBIGUOUS_NAME;
3362 goto fail;
3365 if (ndst) {
3366 xmlUnlinkNode(ndst);
3367 xmlFreeNodeList(ndst);
3370 if (src[1])
3371 xmlNodeSetName(n, (xmlChar *)dst);
3372 else
3373 rc = add_attribute(n, "name", dst);
3375 fail:
3376 g_strfreev(req);
3377 g_strfreev(src);
3378 return send_error(ctx, rc);
3381 static gint copy_command(assuan_context_t ctx, gchar *line)
3383 struct client_s *client = assuan_get_pointer(ctx);
3384 gpg_error_t rc;
3385 gchar **req, **src = NULL, **dst = NULL;
3386 xmlNodePtr nsrc, ndst, new;
3388 log_write2("ARGS=\"%s\"", line);
3389 req = split_input_line(line, " ", -1);
3391 if (!req || !req[0] || !req[1]) {
3392 g_strfreev(req);
3393 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
3396 if (strchr(req[0], '\t'))
3397 src = split_input_line(req[0], "\t", -1);
3398 else
3399 src = split_input_line(req[0], " ", -1);
3401 if (!src || !*src) {
3402 rc = EPWMD_COMMAND_SYNTAX;
3403 goto fail;
3406 if (strchr(req[1], '\t'))
3407 dst = split_input_line(req[1], "\t", -1);
3408 else
3409 dst = split_input_line(req[1], " ", -1);
3411 if (!dst || !*dst) {
3412 rc = EPWMD_COMMAND_SYNTAX;
3413 goto fail;
3416 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3418 if (nsrc && src[1])
3419 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3420 NULL, NULL, FALSE, 0, NULL, FALSE);
3422 if (!nsrc)
3423 goto fail;
3425 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3427 if (ndst && dst[1])
3428 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3429 NULL, NULL, FALSE, 0, NULL, FALSE);
3431 if (!ndst && rc != EPWMD_ELEMENT_NOT_FOUND)
3432 goto fail;
3434 new = xmlCopyNodeList(nsrc);
3436 if (!new) {
3437 rc = GPG_ERR_ENOMEM;
3438 goto fail;
3441 if (!ndst)
3442 ndst = create_element_path(client, &dst, &rc);
3444 if (!ndst) {
3445 xmlUnlinkNode(new);
3446 xmlFreeNodeList(new);
3447 goto fail;
3450 /* Merge any attributes from the src node to the initial dst node. */
3451 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3452 if ((!src[1] || !dst[1]) && xmlStrEqual(attr->name, (xmlChar *)"name"))
3453 continue;
3455 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3457 if (a)
3458 xmlRemoveProp(a);
3460 xmlNewProp(ndst, attr->name, attr->children->content);
3463 xmlNodePtr n = ndst->children;
3464 xmlUnlinkNode(ndst->children);
3465 xmlFreeNodeList(n);
3466 n = xmlCopyNodeList(new->children);
3467 xmlFreeNodeList(new);
3468 ndst->children = NULL;
3469 xmlAddChild(ndst, n);
3471 fail:
3472 if (req)
3473 g_strfreev(req);
3475 if (src)
3476 g_strfreev(src);
3478 if (dst)
3479 g_strfreev(dst);
3481 return send_error(ctx, rc);
3484 static int ls_command(assuan_context_t ctx, gchar *line)
3486 log_write2("ARGS=\"%s\"", line);
3487 gpg_error_t rc;
3488 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
3489 gchar *dir = expand_homedir(tmp);
3490 DIR *d = opendir(dir);
3491 gint n = errno;
3493 g_free(tmp);
3495 if (!d) {
3496 g_free(dir);
3497 return send_syserror(ctx, n);
3500 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
3501 struct dirent *p = g_malloc(len), *cur = NULL;
3502 gchar *list = NULL;
3504 g_free(dir);
3505 rc = 0;
3507 while (!readdir_r(d, p, &cur) && cur) {
3508 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
3509 continue;
3510 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
3511 continue;
3513 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
3515 if (!tmp) {
3516 if (list)
3517 g_free(list);
3519 rc = GPG_ERR_ENOMEM;
3520 break;
3523 g_free(list);
3524 list = tmp;
3527 closedir(d);
3528 g_free(p);
3530 if (rc)
3531 return send_error(ctx, rc);
3533 if (!list)
3534 return send_error(ctx, GPG_ERR_NO_VALUE);
3536 list[strlen(list)-1] = 0;
3537 rc = xfer_data(ctx, list, strlen(list));
3538 g_free(list);
3539 return send_error(ctx, rc);
3542 static void bye_notify(assuan_context_t ctx)
3544 struct client_s *cl = assuan_get_pointer(ctx);
3546 /* This will let assuan_process_next() return. */
3547 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
3550 static void reset_notify(assuan_context_t ctx)
3552 struct client_s *cl = assuan_get_pointer(ctx);
3554 if (cl)
3555 cleanup_client(cl);
3559 * This is called before every Assuan command.
3561 gint command_startup(assuan_context_t ctx, const gchar *name)
3563 struct client_s *cl = assuan_get_pointer(ctx);
3564 gpg_error_t rc;
3566 log_write1("%s", name);
3568 if (!g_ascii_strcasecmp(name, "ISCACHED") ||
3569 !g_ascii_strcasecmp(name, "CLEARCACHE") ||
3570 !g_ascii_strcasecmp(name, "CACHETIMEOUT") ||
3571 !g_ascii_strcasecmp(name, "GETCONFIG") ||
3572 !g_ascii_strcasecmp(name, "GETPID") ||
3573 !g_ascii_strcasecmp(name, "VERSION") ||
3574 !g_ascii_strcasecmp(name, "SET") ||
3575 !g_ascii_strcasecmp(name, "BYE") ||
3576 !g_ascii_strcasecmp(name, "NOP") ||
3577 !g_ascii_strcasecmp(name, "CANCEL") ||
3578 !g_ascii_strcasecmp(name, "RESET") ||
3579 !g_ascii_strcasecmp(name, "END") ||
3580 !g_ascii_strcasecmp(name, "HELP") ||
3581 !g_ascii_strcasecmp(name, "OPTION") ||
3582 !g_ascii_strcasecmp(name, "INPUT") ||
3583 !g_ascii_strcasecmp(name, "OUTPUT") ||
3584 !g_ascii_strcasecmp(name, "LS") ||
3585 !g_ascii_strcasecmp(name, "UNSET"))
3586 return 0;
3588 cl->last_rc = rc = file_modified(cl);
3590 if (rc) {
3591 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
3592 !g_ascii_strcasecmp(name, "OPEN"))
3593 rc = 0;
3596 return rc;
3600 * This is called after every Assuan command.
3602 void command_finalize(assuan_context_t ctx, gint rc)
3604 struct client_s *client = assuan_get_pointer(ctx);
3606 if (!client->is_lock_cmd)
3607 unlock_file_mutex(client);
3609 log_write1(N_("command completed (rc=%u)"), client->last_rc);
3612 gpg_error_t register_commands(assuan_context_t ctx)
3614 static struct {
3615 const gchar *name;
3616 gint (*handler)(assuan_context_t, gchar *line);
3617 } table[] = {
3618 { "OPEN", open_command },
3619 { "SAVE", save_command },
3620 { "LIST", list_command },
3621 { "REALPATH", realpath_command },
3622 { "STORE", store_command },
3623 { "DELETE", delete_command },
3624 { "GET", get_command },
3625 { "ATTR", attr_command },
3626 { "ISCACHED", iscached_command },
3627 { "CLEARCACHE", clearcache_command },
3628 { "CACHETIMEOUT", cachetimeout_command },
3629 { "GETCONFIG", getconfig_command },
3630 { "DUMP", dump_command },
3631 { "XPATH", xpath_command },
3632 { "XPATHATTR", xpathattr_command },
3633 { "IMPORT", import_command },
3634 { "LOCK", lock_command },
3635 { "UNLOCK", unlock_command },
3636 { "GETPID", getpid_command },
3637 { "VERSION", version_command },
3638 { "SET", set_command },
3639 { "UNSET", unset_command },
3640 { "RENAME", rename_command },
3641 { "COPY", copy_command },
3642 { "LS", ls_command },
3643 { "INPUT", NULL },
3644 { "OUTPUT", NULL },
3645 { NULL, NULL }
3647 gint i, rc;
3649 for (i=0; table[i].name; i++) {
3650 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
3652 if (rc)
3653 return rc;
3656 rc = assuan_register_bye_notify(ctx, bye_notify);
3658 if (rc)
3659 return rc;
3661 rc = assuan_register_reset_notify(ctx, reset_notify);
3663 if (rc)
3664 return rc;
3666 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
3668 if (rc)
3669 return rc;
3671 return assuan_register_post_cmd_notify(ctx, command_finalize);
3674 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
3675 struct client_crypto_s *crypto, gpointer *dst, goffset *dst_len)
3677 goffset insize, len;
3678 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
3679 guint64 iter = 0ULL, n_iter = 0ULL, iter_progress = 0ULL;
3680 gint zrc = 0;
3681 gulong outsize = 0;
3682 gpg_error_t rc;
3683 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
3684 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
3685 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
3687 lseek(crypto->fh->fd, fh_size, SEEK_SET);
3688 insize = crypto->fh->st.st_size - fh_size;
3689 crypto->iv = gcry_malloc(crypto->blocksize);
3691 if (!crypto->iv) {
3692 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3693 return gpg_error_from_errno(ENOMEM);
3696 if (crypto->fh->v1)
3697 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
3698 else
3699 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
3701 crypto->inbuf = gcry_malloc(insize);
3703 if (!crypto->inbuf) {
3704 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3705 return gpg_error_from_errno(ENOMEM);
3708 crypto->insize = insize;
3709 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
3711 if (len != crypto->insize)
3712 return GPG_ERR_INV_LENGTH;
3714 /* No encryption iterations. This is a plain (gzipped) file. */
3715 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
3716 (!crypto->fh->v1 && fh_iter <= 0L)) {
3718 * cache_file_count() needs both .used == TRUE and a valid key in
3719 * order for it to count as a used cache entry. Fixes CACHE status
3720 * messages.
3722 memset(crypto->key, '!', hashlen);
3723 goto decompress;
3726 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
3727 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3728 return rc;
3731 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
3732 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3733 return rc;
3736 iter_progress = (guint64)get_key_file_double(client && client->filename ?
3737 client->filename : "global", "iteration_progress");
3739 if (iter_progress > 0ULL && fh_iter >= iter_progress) {
3740 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
3742 if (rc)
3743 return rc;
3746 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3748 if (rc)
3749 return rc;
3751 crypto->tkey = gcry_malloc(hashlen);
3753 if (!crypto->tkey) {
3754 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
3755 return gpg_error_from_errno(ENOMEM);
3758 memcpy(crypto->tkey, crypto->key, hashlen);
3759 guchar *tkey = crypto->tkey;
3760 tkey[0] ^= 1;
3762 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
3763 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3764 return rc;
3767 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
3768 if (iter_progress > 0ULL && iter >= iter_progress) {
3769 if (!(iter % iter_progress)) {
3770 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
3771 ++n_iter * iter_progress, fh_iter);
3773 if (rc)
3774 return rc;
3778 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
3779 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3780 return rc;
3783 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3785 if (rc) {
3786 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3787 return rc;
3790 iter++;
3793 if (iter_progress && fh_iter >= iter_progress) {
3794 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
3796 if (rc)
3797 return rc;
3800 decompress:
3801 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
3802 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
3803 if (zrc == Z_MEM_ERROR)
3804 return gpg_error_from_errno(ENOMEM);
3805 else
3806 return EPWMD_BADKEY; // Not a valid gzip header. Must be a bad key.
3809 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
3810 gcry_free(crypto->outbuf);
3811 crypto->outbuf = NULL;
3812 return EPWMD_BADKEY;
3815 if (ctx) {
3816 client->xml = crypto->outbuf;
3817 client->len = outsize;
3818 crypto->outbuf = NULL;
3820 else if (dst) {
3821 *dst = crypto->outbuf;
3822 *dst_len = outsize;
3823 crypto->outbuf = NULL;
3826 /* The calling function should free the crypto struct. */
3827 return 0;