Fixed "xfer_progress=0".
[pwmd.git] / src / commands.c
blob6d3a7074849d66be7dc86c12ad02293b730624ad
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 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>
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #include "mem.h"
37 #include "xml.h"
38 #include "common.h"
40 #ifdef WITH_PINENTRY
41 #include "pinentry.h"
42 #endif
44 #include "pwmd_error.h"
45 #include "cache.h"
46 #include "misc.h"
47 #include "commands.h"
48 #include "lock.h"
50 struct gz_s {
51 z_stream z;
52 gpointer out;
53 gboolean done;
54 status_msg_t which;
57 static void *z_alloc(void *data, unsigned items, unsigned size)
59 return gcry_calloc(items, size);
62 static void z_free(void *data, void *p)
64 gcry_free(p);
67 static gpg_error_t file_modified(struct client_s *client)
69 struct stat st;
70 gpg_error_t rc;
72 if (client->state != STATE_OPEN)
73 return EPWMD_NO_FILE;
75 rc = lock_file_mutex(client);
77 if (rc)
78 return rc;
80 if (lstat(client->filename, &st) == 0 && client->mtime) {
81 if (client->mtime != st.st_mtime)
82 return EPWMD_FILE_MODIFIED;
85 pth_cancel_point();
86 return 0;
89 static gpg_error_t parse_xml(assuan_context_t ctx)
91 struct client_s *client = assuan_get_pointer(ctx);
93 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
95 if (!client->doc)
96 return EPWMD_LIBXML_ERROR;
98 return 0;
101 void unlock_file_mutex(struct client_s *client)
103 pth_mutex_t *m;
105 #ifdef WITH_PINENTRY
106 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
107 #else
108 if (client->has_lock == FALSE)
109 #endif
110 return;
112 CACHE_LOCK(client->ctx);
114 if (cache_get_mutex(client->md5file, &m) == FALSE) {
115 CACHE_UNLOCK;
116 return;
119 CACHE_UNLOCK;
120 MUTEX_UNLOCK(m);
121 client->has_lock = client->is_lock_cmd = FALSE;
124 gpg_error_t lock_file_mutex(struct client_s *client)
126 pth_mutex_t *m;
127 gpg_error_t rc = 0;
129 if (client->has_lock == TRUE)
130 return 0;
132 CACHE_LOCK(client->ctx);
134 if (cache_get_mutex(client->md5file, &m) == FALSE) {
135 CACHE_UNLOCK;
136 return 0;
139 CACHE_UNLOCK;
140 MUTEX_TRYLOCK(client->ctx, m, rc);
142 if (!rc)
143 client->has_lock = TRUE;
145 return rc;
148 void free_client(struct client_s *client)
150 if (client->doc)
151 xmlFreeDoc(client->doc);
153 if (client->xml)
154 gcry_free(client->xml);
156 if (client->filename)
157 g_free(client->filename);
159 if (client->crypto)
160 cleanup_crypto(&client->crypto);
162 if (client->xml_error)
163 xmlResetError(client->xml_error);
166 void cleanup_client(struct client_s *client)
168 assuan_context_t ctx = client->ctx;
169 struct client_thread_s *thd = client->thd;
170 gboolean has_lock = client->has_lock;
171 #ifdef WITH_PINENTRY
172 struct pinentry_s *pin = client->pinentry;
173 #endif
175 unlock_file_mutex(client);
176 CACHE_LOCK(client->ctx);
177 cache_decr_refcount(client->md5file);
180 * This may be a new file so don't use a cache slot. save_command() will
181 * set this to FALSE on success.
183 if (client->new == TRUE)
184 cache_clear(client->md5file, 1);
186 CACHE_UNLOCK;
187 free_client(client);
188 memset(client, 0, sizeof(struct client_s));
189 client->state = STATE_CONNECTED;
190 client->ctx = ctx;
191 client->thd = thd;
192 client->freed = TRUE;
193 #ifdef WITH_PINENTRY
194 client->pinentry = pin;
195 #endif
196 client->has_lock = has_lock;
199 static void gz_cleanup(void *arg)
201 struct gz_s **gz = (struct gz_s **)arg;
203 if (!gz)
204 return;
206 if (!(*gz)->done && (*gz)->out)
207 gcry_free((*gz)->out);
210 if ((*gz)->which == STATUS_COMPRESS) {
211 if ((*gz)->z.zalloc)
212 deflateEnd(&(*gz)->z);
214 else {
215 if ((*gz)->z.zalloc)
216 inflateEnd(&(*gz)->z);
219 g_free(*gz);
220 *gz = NULL;
223 gboolean do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
224 gpointer *out, gulong *outsize, gint *rc)
226 struct gz_s *gz;
227 gz_header h;
228 gchar buf[17];
230 gz = g_malloc0(sizeof(struct gz_s));
232 if (!gz) {
233 *rc = gpg_error_from_errno(ENOMEM);
234 return FALSE;
237 gz->which = STATUS_DECOMPRESS;
238 gz->z.zalloc = z_alloc;
239 gz->z.zfree = z_free;
240 gz->z.next_in = in;
241 gz->z.avail_in = (uInt)insize;
242 gz->z.avail_out = zlib_bufsize;
243 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
245 if (!gz->out) {
246 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
247 *rc = Z_MEM_ERROR;
248 gz_cleanup(&gz);
249 return FALSE;
252 *rc = inflateInit2(&gz->z, 47);
254 if (*rc != Z_OK) {
255 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
256 gz_cleanup(&gz);
257 return FALSE;
260 memset(&h, 0, sizeof(gz_header));
261 h.comment = (guchar *)buf;
262 h.comm_max = sizeof(buf);
263 *rc = inflateGetHeader(&gz->z, &h);
265 if (*rc != Z_OK) {
266 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
267 gz_cleanup(&gz);
268 return FALSE;
271 *rc = inflate(&gz->z, Z_BLOCK);
273 if (*rc != Z_OK) {
274 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
275 gz_cleanup(&gz);
276 return FALSE;
279 if (h.comment)
280 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
282 do {
283 gpointer p;
285 *rc = inflate(&gz->z, Z_FINISH);
287 switch (*rc) {
288 case Z_OK:
289 break;
290 case Z_BUF_ERROR:
291 if (!gz->z.avail_out) {
292 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
294 if (!p) {
295 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
296 *rc = Z_MEM_ERROR;
297 goto fail;
300 gz->out = p;
301 gz->z.next_out = gz->out + gz->z.total_out;
302 gz->z.avail_out = zlib_bufsize;
303 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
304 gz->z.total_out, insize);
306 if (*rc)
307 goto fail;
309 break;
310 case Z_STREAM_END:
311 break;
312 default:
313 goto fail;
314 break;
316 } while (*rc != Z_STREAM_END);
318 pth_cancel_point();
319 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
320 insize);
321 pth_cancel_point();
323 if (*rc)
324 goto fail;
326 *out = gz->out;
327 *outsize = gz->z.total_out;
328 gz->done = TRUE;
329 gz_cleanup(&gz);
330 *rc = 0;
331 return TRUE;
333 fail:
334 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
335 gz_cleanup(&gz);
336 return FALSE;
339 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
340 gpg_error_t *rc)
342 gint fd;
343 gsize len;
344 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
345 gsize fh_size;
347 *rc = 0;
349 if (!fh) {
350 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
351 *rc = gpg_error_from_errno(ENOMEM);
352 return NULL;
355 fh_size = v1 ? sizeof(fh->fh1) : sizeof(fh->fh2);
357 if (lstat(filename, &fh->st) == -1) {
358 *rc = gpg_error_from_syserror();
359 g_free(fh);
360 return NULL;
363 if (!S_ISREG(fh->st.st_mode)) {
364 *rc = GPG_ERR_ENOANO;
365 g_free(fh);
366 return NULL;
369 fd = open(filename, O_RDONLY);
371 if (fd == -1) {
372 *rc = gpg_error_from_errno(errno);
373 g_free(fh);
374 return NULL;
377 if (v1)
378 len = pth_read(fd, &fh->fh1, fh_size);
379 else
380 len = pth_read(fd, &fh->fh2, fh_size);
382 if (len != fh_size) {
383 gint n = errno;
384 close(fd);
385 g_free(fh);
386 *rc = gpg_error_from_errno(n);
387 return NULL;
390 fh->v1 = v1;
391 fh->fd = fd;
392 return fh;
395 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *key,
396 gboolean cached)
398 struct client_s *client = assuan_get_pointer(ctx);
399 gpg_error_t rc;
400 gint timeout;
402 /* New file. */
403 if (!client->crypto->fh) {
404 if (key[0])
405 goto update_cache;
407 goto done;
410 rc = try_xml_decrypt(ctx, key, client->crypto, NULL, NULL);
412 if (rc) {
413 cleanup_client(client);
414 return send_error(ctx, rc);
417 update_cache:
418 CACHE_LOCK(client->ctx);
420 if (cached == FALSE) {
421 if (cache_update_key(client->md5file, key) == FALSE) {
422 cleanup_client(client);
423 CACHE_UNLOCK;
424 return send_syserror(ctx, ENOMEM);
427 timeout = get_key_file_integer(client->filename, "cache_timeout");
428 cache_reset_timeout(client->md5file, timeout);
430 else
431 cache_set_timeout(client->md5file, -2);
433 CACHE_UNLOCK;
435 done:
436 rc = parse_xml(ctx);
438 if (client->xml) {
439 gcry_free(client->xml);
440 client->xml = NULL;
443 if (!rc) {
444 if (client->new == FALSE)
445 send_status_all(STATUS_CACHE);
447 client->state = STATE_OPEN;
450 if (!rc && client->new == FALSE &&
451 client->crypto->fh->fh2.iter != (guint64)get_key_file_integer(client->filename, "iterations")) {
452 MUTEX_LOCK(&rcfile_mutex);
453 g_key_file_set_integer(keyfileh, client->filename, "iterations",
454 client->crypto->fh->fh2.iter);
455 MUTEX_UNLOCK(&rcfile_mutex);
456 send_status_all(STATUS_CONFIG);
459 if (!rc)
460 log_write("OPEN '%s'", client->filename);
462 cleanup_crypto(&client->crypto);
463 return send_error(ctx, rc);
466 static void req_cleanup(void *arg)
468 if (!arg)
469 return;
471 g_strfreev((gchar **)arg);
474 static int open_command(assuan_context_t ctx, char *line)
476 gboolean cached = FALSE;
477 gpg_error_t rc;
478 struct client_s *client = assuan_get_pointer(ctx);
479 gchar **req;
480 gchar *filename = NULL;
482 if ((req = split_input_line(line, " ", 2)) != NULL)
483 filename = req[0];
485 if (!filename || !*filename) {
486 g_strfreev(req);
487 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
490 if (valid_filename(filename) == FALSE) {
491 g_strfreev(req);
492 return send_error(ctx, EPWMD_INVALID_FILENAME);
495 if (client->state == STATE_OPEN)
496 cleanup_client(client);
498 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
499 CACHE_LOCK(client->ctx);
501 if (cache_has_file(client->md5file) == FALSE) {
502 if (cache_add_file(client->md5file, NULL) == FALSE) {
503 g_strfreev(req);
504 CACHE_UNLOCK;
505 return send_syserror(ctx, ENOMEM);
509 cache_incr_refcount(client->md5file);
510 CACHE_UNLOCK;
511 rc = lock_file_mutex(client);
513 if (rc) {
514 g_strfreev(req);
515 return send_error(ctx, rc);
518 client->freed = FALSE;
519 client->crypto = init_client_crypto();
521 if (!client->crypto) {
522 g_strfreev(req);
523 cleanup_client(client);
524 return send_syserror(ctx, ENOMEM);
527 client->crypto->key = gcry_malloc(gcrykeysize);
529 if (!client->crypto->key) {
530 g_strfreev(req);
531 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
532 gpg_error_from_errno(ENOMEM));
533 cleanup_client(client);
534 return send_syserror(ctx, ENOMEM);
537 memset(client->crypto->key, 0, gcrykeysize);
538 client->crypto->fh = read_file_header(filename, FALSE, &rc);
539 pth_cancel_point();
541 if (!client->crypto->fh) {
542 if (gpg_err_code_to_errno(rc) != ENOENT) {
543 log_write("%s: %s", filename, pwmd_strerror(rc));
544 g_strfreev(req);
545 cleanup_client(client);
546 return send_error(ctx, rc);
550 * New files don't need a key.
552 if ((client->xml = new_document()) == NULL) {
553 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
554 g_strfreev(req);
555 cleanup_client(client);
556 return send_syserror(ctx, ENOMEM);
559 client->len = xmlStrlen(client->xml);
560 client->new = TRUE;
561 client->filename = g_strdup(filename);
563 if (!client->filename) {
564 g_strfreev(req);
565 cleanup_client(client);
566 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
567 return send_syserror(ctx, ENOMEM);
570 if (req[1] && *req[1])
571 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
572 strlen(req[1]));
574 g_strfreev(req);
575 #ifdef WITH_PINENTRY
576 client->pinentry->filename = g_strdup(client->filename);
578 if (!client->pinentry->filename) {
579 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
580 cleanup_client(client);
581 return send_syserror(ctx, ENOMEM);
583 #endif
584 return open_command_finalize(ctx, client->crypto->key, cached);
586 else
587 client->mtime = client->crypto->fh->st.st_mtime;
589 client->filename = g_strdup(filename);
591 if (!client->filename) {
592 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
593 g_strfreev(req);
594 cleanup_client(client);
595 return send_syserror(ctx, ENOMEM);
598 #ifdef WITH_PINENTRY
599 client->pinentry->filename = g_strdup(client->filename);
601 if (!client->pinentry->filename) {
602 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
603 g_strfreev(req);
604 cleanup_client(client);
605 return send_syserror(ctx, ENOMEM);
607 #endif
609 if (client->crypto->fh->fh2.iter <= 0)
610 goto done;
612 CACHE_LOCK(client->ctx);
613 cached = cache_get_key(client->md5file, client->crypto->key);
614 CACHE_UNLOCK;
616 if (cached == FALSE) {
617 gchar *tmp = get_key_file_string(filename, "key_file");
619 if (tmp) {
620 g_free(tmp);
621 cleanup_client(client);
622 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
626 * No key specified and no matching filename found in the cache. Use
627 * pinentry to retrieve the key. Cannot return assuan_process_done()
628 * here otherwise the command will be interrupted. The event loop in
629 * client_thread() will poll the file descriptor waiting for it to
630 * become ready to read a pinentry_key_s which will contain the
631 * entered key or an error code. It will then call
632 * open_command_finalize() to to finish the command.
634 if (!req[1] || !*req[1]) {
635 #ifdef WITH_PINENTRY
636 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
638 /* From set_pinentry_defaults(). */
639 if (client->pinentry->enable == FALSE ||
640 (client->pinentry->enable == -1 && b == FALSE)) {
641 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
642 goto done;
645 g_strfreev(req);
646 rc = lock_pin_mutex(client);
648 if (rc) {
649 unlock_pin_mutex(client->pinentry);
650 cleanup_client(client);
651 return send_error(ctx, rc);
654 client->pinentry->which = PINENTRY_OPEN;
655 rc = pinentry_fork(ctx);
657 if (rc) {
658 unlock_pin_mutex(client->pinentry);
659 cleanup_client(client);
660 return send_error(ctx, rc);
663 // Called from pinentry iterate.
664 client->pinentry->cb = open_command_finalize;
665 client->pinentry->status = PINENTRY_INIT;
666 return 0;
667 #else
668 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
669 goto done;
670 #endif
673 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
674 strlen(req[1]));
677 done:
678 req_cleanup(req);
679 return open_command_finalize(ctx, client->crypto->key, cached);
682 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
683 gulong size, gpointer *out, gulong *outsize, gint *rc)
685 struct gz_s *gz;
686 gz_header h;
687 gchar buf[17];
688 gint cmd = Z_NO_FLUSH;
690 gz = g_malloc0(sizeof(struct gz_s));
692 if (!gz) {
693 *rc = gpg_error_from_errno(ENOMEM);
694 return FALSE;
697 gz->which = STATUS_COMPRESS;
698 gz->z.zalloc = z_alloc;
699 gz->z.zfree = z_free;
700 gz->z.next_in = data;
701 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
702 gz->z.avail_out = (uInt)zlib_bufsize;
703 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
705 if (!gz->out) {
706 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
707 *rc = Z_MEM_ERROR;
708 gz_cleanup(&gz);
709 return FALSE;
712 *rc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
714 if (*rc != Z_OK) {
715 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
716 gz_cleanup(&gz);
717 return FALSE;
720 /* Rather than store the size of the uncompressed data in the file header,
721 * store it in the comment field of the gzip header. Don't give anyone too
722 * much information. Not sure why really, but it seems the right way. :)
724 memset(&h, 0, sizeof(gz_header));
725 g_snprintf(buf, sizeof(buf), "%li", size);
726 h.comment = (guchar *)buf;
727 *rc = deflateSetHeader(&gz->z, &h);
729 if (*rc != Z_OK) {
730 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
731 gz_cleanup(&gz);
732 return FALSE;
735 do {
736 gpointer p;
738 *rc = deflate(&gz->z, cmd);
740 switch (*rc) {
741 case Z_OK:
742 break;
743 case Z_BUF_ERROR:
744 if (!gz->z.avail_out) {
745 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
747 if (!p) {
748 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
749 *rc = Z_MEM_ERROR;
750 goto fail;
753 gz->out = p;
754 gz->z.next_out = gz->out + gz->z.total_out;
755 gz->z.avail_out = zlib_bufsize;
758 if (!gz->z.avail_in && gz->z.total_in < size) {
759 if (gz->z.total_in + zlib_bufsize > size)
760 gz->z.avail_in = size - gz->z.total_in;
761 else
762 gz->z.avail_in = zlib_bufsize;
764 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li",
765 gz->z.total_in, size);
767 if (*rc)
768 goto fail;
771 if (gz->z.total_in >= size)
772 cmd = Z_FINISH;
774 break;
775 case Z_STREAM_END:
776 break;
777 default:
778 goto fail;
780 } while (*rc != Z_STREAM_END);
782 pth_cancel_point();
783 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li", gz->z.total_in, size);
784 pth_cancel_point();
786 if (*rc)
787 goto fail;
789 *out = gz->out;
790 *outsize = gz->z.total_out;
791 *rc = 0;
792 gz->done = TRUE;
793 gz_cleanup(&gz);
794 return TRUE;
796 fail:
797 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
798 gz_cleanup(&gz);
799 return FALSE;
802 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
804 static gpg_error_t iterate_crypto_once(struct client_s *client,
805 struct client_crypto_s *crypto, status_msg_t which)
807 gpg_error_t rc = 0;
808 goffset len = CRYPTO_BLOCKSIZE;
809 gpointer p = gcry_malloc(len);
810 goffset total = 0;
811 gpointer inbuf;
813 if (!p)
814 return gpg_err_code_from_errno(ENOMEM);
816 if (crypto->insize < CRYPTO_BLOCKSIZE)
817 len = crypto->insize;
819 for (;;) {
820 inbuf = crypto->inbuf + total;
821 guchar *tmp;
823 if (len + total > crypto->insize)
824 len = gcryblocksize;
826 if (which == STATUS_ENCRYPT)
827 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
828 else
829 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
831 if (rc)
832 goto done;
834 tmp = crypto->inbuf+total;
835 memmove(tmp, p, len);
836 total += len;
838 if (total >= crypto->insize)
839 break;
841 pth_cancel_point();
844 done:
845 gcry_free(p);
846 return rc;
849 /* The crypto struct must be setup for iterations and .key. */
850 gpg_error_t do_xml_encrypt(struct client_s *client,
851 struct client_crypto_s *crypto, const gchar *filename)
853 goffset len = crypto->insize;
854 gpointer inbuf;
855 gchar *p;
856 gpg_error_t rc;
857 guint64 iter_progress = 0, n_iter = 0, xiter = 0;
858 gchar tmp[FILENAME_MAX];
859 struct stat st;
860 mode_t mode = 0;
862 if (!crypto->fh->fh2.iter) {
864 * cache_file_count() needs both .used == TRUE and a valid key in
865 * order for it to count as a used cache entry. Fixes CACHE status
866 * messages.
868 memset(crypto->key, '!', gcrykeysize);
869 goto write_file;
873 * Resize the existing xml buffer to the block size required by gcrypt
874 * rather than duplicating it and wasting memory.
876 if (crypto->insize / gcryblocksize) {
877 len = (crypto->insize / gcryblocksize) * gcryblocksize;
879 if (crypto->insize % gcryblocksize)
880 len += gcryblocksize;
883 inbuf = gcry_realloc(crypto->inbuf, len);
885 if (!inbuf) {
886 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
887 return gpg_error_from_errno(ENOMEM);
890 crypto->inbuf = inbuf;
891 crypto->insize = len;
892 gcry_create_nonce(crypto->fh->fh2.iv, sizeof(crypto->fh->fh2.iv));
893 crypto->tkey = gcry_malloc(gcrykeysize);
895 if (!crypto->tkey) {
896 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
897 return gpg_error_from_errno(ENOMEM);
900 memcpy(crypto->tkey, crypto->key, gcrykeysize);
901 guchar *tkey = crypto->tkey;
902 tkey[0] ^= 1;
904 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
905 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
906 return rc;
909 iter_progress = (guint64)get_key_file_integer(
910 client ? client->filename : "global", "iteration_progress");
912 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
913 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
914 "0 %llu", crypto->fh->fh2.iter);
915 pth_cancel_point();
917 if (rc)
918 return rc;
921 while (xiter < crypto->fh->fh2.iter-1) {
922 if (iter_progress > 0 && xiter >= iter_progress) {
923 if (!(xiter % iter_progress)) {
924 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
925 "%llu %llu", ++n_iter * iter_progress,
926 crypto->fh->fh2.iter);
927 pth_cancel_point();
929 if (rc)
930 return rc;
934 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
935 sizeof(crypto->fh->fh2.iv)))) {
936 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
937 return rc;
940 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
942 if (rc) {
943 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
944 return rc;
947 xiter++;
950 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
951 sizeof(crypto->fh->fh2.iv)))) {
952 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
953 return rc;
956 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, gcrykeysize))) {
957 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
958 return rc;
961 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
963 if (rc)
964 return rc;
966 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
967 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
968 "%llu %llu", crypto->fh->fh2.iter, crypto->fh->fh2.iter);
969 pth_cancel_point();
971 if (rc)
972 return rc;
975 write_file:
976 if (filename) {
977 if (!client && !strcmp(filename, "-")) {
978 crypto->fh->fd = STDOUT_FILENO;
979 goto do_write_file;
982 if (lstat(filename, &st) == 0) {
983 pth_cancel_point();
984 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
987 * FIXME What if the file has an ACL?
989 if (!(mode & S_IWUSR))
990 return gpg_error_from_errno(EACCES);
992 else {
993 pth_cancel_point();
994 if (errno != ENOENT)
995 return gpg_error_from_errno(errno);
998 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
999 crypto->fh->fd = mkstemp(tmp);
1001 if (crypto->fh->fd == -1) {
1002 rc = errno;
1003 p = strrchr(tmp, '/');
1004 p++;
1005 log_write("%s: %s", p, strerror(rc));
1006 return gpg_error_from_errno(rc);
1009 else
1011 * xml_import() or convert_file() from command line.
1013 crypto->fh->fd = STDOUT_FILENO;
1015 do_write_file:
1016 crypto->fh->fh2.version = VERSION_HEX;
1017 len = pth_write(crypto->fh->fd, &crypto->fh->fh2, sizeof(crypto->fh->fh2));
1018 pth_cancel_point();
1020 if (len != sizeof(crypto->fh->fh2)) {
1021 len = errno;
1023 if (filename && strcmp(filename, "-"))
1024 unlink(tmp);
1026 return gpg_error_from_errno(len);
1029 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1030 pth_cancel_point();
1032 if (len != crypto->insize) {
1033 pth_cancel_point();
1034 len = errno;
1036 if (filename && strcmp(filename, "-")) {
1037 unlink(tmp);
1038 pth_cancel_point();
1041 return gpg_error_from_errno(len);
1044 if (fsync(crypto->fh->fd) == -1) {
1045 pth_cancel_point();
1046 len = errno;
1048 if (filename && strcmp(filename, "-"))
1049 unlink(tmp);
1051 return gpg_error_from_errno(len);
1054 if (filename && strcmp(filename, "-")) {
1055 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1056 gchar tmp2[FILENAME_MAX];
1058 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1060 if (rename(filename, tmp2) == -1) {
1061 pth_cancel_point();
1062 unlink(tmp);
1063 len = errno;
1064 return gpg_error_from_errno(len);
1068 if (rename(tmp, filename) == -1) {
1069 pth_cancel_point();
1070 len = errno;
1071 unlink(tmp);
1072 return gpg_error_from_errno(len);
1075 if (mode) {
1076 chmod(filename, mode);
1077 pth_cancel_point();
1081 if (client && lstat(filename, &st) == 0)
1082 client->mtime = st.st_mtime;
1084 pth_cancel_point();
1085 return 0;
1088 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1089 gboolean cached)
1091 struct client_s *client = assuan_get_pointer(ctx);
1092 gpointer xmlbuf;
1093 gulong len, outsize = 0;
1094 guint iter;
1095 gint timeout;
1096 gpointer outbuf;
1097 gint zrc;
1098 gpg_error_t rc;
1100 if (client->crypto->key && client->crypto->key != key)
1101 gcry_free(client->crypto->key);
1103 client->crypto->key = key;
1104 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1105 iter = (guint)get_key_file_integer(client->filename, "compression_level");
1107 if (iter < 0)
1108 iter = 0;
1110 if (do_compress(ctx, (gint)iter, xmlbuf, len, &outbuf, &outsize, &zrc)
1111 == FALSE) {
1112 xmlFree(xmlbuf);
1113 cleanup_crypto(&client->crypto);
1115 if (zrc == Z_MEM_ERROR)
1116 return send_syserror(ctx, ENOMEM);
1117 else
1118 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1120 else {
1121 gcry_free(xmlbuf);
1122 xmlbuf = outbuf;
1123 len = outsize;
1126 client->crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1128 if (!client->crypto->fh) {
1129 cleanup_crypto(&client->crypto);
1130 gcry_free(outbuf);
1131 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1132 return send_syserror(ctx, ENOMEM);
1135 iter = get_key_file_integer(client->filename, "iterations");
1136 client->crypto->fh->fh2.iter = iter < 0 ? 0 : iter;
1137 client->crypto->inbuf = xmlbuf;
1138 client->crypto->insize = len;
1139 rc = do_xml_encrypt(client, client->crypto, client->filename);
1141 if (rc) {
1142 cleanup_crypto(&client->crypto);
1143 return send_error(ctx, rc);
1146 timeout = get_key_file_integer(client->filename, "cache_timeout");
1147 CACHE_LOCK(client->ctx);
1149 if (cached) {
1150 cache_reset_timeout(client->md5file, timeout);
1151 CACHE_UNLOCK;
1153 if (client->new == TRUE)
1154 send_status_all(STATUS_CACHE);
1156 client->new = FALSE;
1157 cleanup_crypto(&client->crypto);
1158 return send_error(ctx, 0);
1161 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1162 CACHE_UNLOCK;
1163 cleanup_crypto(&client->crypto);
1164 return send_syserror(ctx, ENOMEM);
1167 client->new = FALSE;
1168 cache_reset_timeout(client->md5file, timeout);
1169 CACHE_UNLOCK;
1170 send_status_all(STATUS_CACHE);
1171 cleanup_crypto(&client->crypto);
1172 return send_error(ctx, 0);
1175 static int save_command(assuan_context_t ctx, char *line)
1177 gboolean cached = FALSE;
1178 struct stat st;
1179 struct client_s *client = assuan_get_pointer(ctx);
1180 gpg_error_t rc;
1182 rc = lock_file_mutex(client);
1184 if (rc)
1185 return send_error(ctx, rc);
1187 rc = file_modified(client);
1189 if (rc)
1190 return send_error(ctx, rc);
1192 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1193 return send_syserror(ctx, errno);
1195 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1196 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1197 return send_error(ctx, GPG_ERR_ENOANO);
1200 CACHE_LOCK(ctx);
1201 cached = cache_iscached(client->md5file);
1202 CACHE_UNLOCK;
1205 * If a cache entry doesn't exist for this file and the file has a
1206 * "key_file" or "key" parameter, then it's an error. The reason is that
1207 * cache expiration would be useless.
1209 if (cached == FALSE) {
1210 gchar *tmp = get_key_file_string(client->filename, "key_file");
1212 if (tmp) {
1213 g_free(tmp);
1214 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1218 cached = FALSE;
1219 client->crypto = init_client_crypto();
1221 if (!client->crypto) {
1222 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1223 return send_syserror(ctx, ENOMEM);
1226 client->crypto->key = gcry_malloc(gcrykeysize);
1228 if (!client->crypto->key) {
1229 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1230 cleanup_crypto(&client->crypto);
1231 return send_syserror(ctx, ENOMEM);
1234 memset(client->crypto->key, '!', gcrykeysize);
1236 if (get_key_file_integer(client->filename, "iterations") <= 0)
1237 goto done;
1239 if (!line || !*line) {
1240 client->crypto->tkey = gcry_malloc(gcrykeysize);
1242 if (!client->crypto->tkey) {
1243 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1244 cleanup_crypto(&client->crypto);
1245 return send_syserror(ctx, ENOMEM);
1248 memset(client->crypto->tkey, '!', gcrykeysize);
1249 CACHE_LOCK(ctx);
1251 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1252 memcmp(client->crypto->key, client->crypto->tkey,
1253 gcrykeysize) == 0) {
1254 CACHE_UNLOCK;
1256 #ifdef WITH_PINENTRY
1257 if (client->pinentry->enable == FALSE ||
1258 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1259 /* Empty keys are allowed. */
1260 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1261 goto done;
1264 lock_pin_mutex(client);
1265 client->pinentry->which = PINENTRY_SAVE;
1266 rc = pinentry_fork(ctx);
1268 if (rc) {
1269 unlock_pin_mutex(client->pinentry);
1270 return send_error(ctx, rc);
1273 client->pinentry->cb = save_command_finalize;
1274 client->pinentry->status = PINENTRY_INIT;
1275 return 0;
1276 #else
1277 /* Empty keys are allowed. */
1278 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1279 goto done;
1280 #endif
1282 else {
1283 CACHE_UNLOCK;
1284 cached = TRUE;
1287 else {
1288 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1289 strlen(line));
1290 memset(line, 0, strlen(line));
1293 done:
1294 return save_command_finalize(ctx, client->crypto->key, cached);
1297 static int delete_command(assuan_context_t ctx, char *line)
1299 struct client_s *client = assuan_get_pointer(ctx);
1300 gchar **req;
1301 gpg_error_t rc;
1302 xmlNodePtr n;
1304 rc = file_modified(client);
1306 if (rc)
1307 return send_error(ctx, rc);
1309 if (strchr(line, '\t'))
1310 req = split_input_line(line, "\t", -1);
1311 else
1312 req = split_input_line(line, " ", -1);
1314 if (!req || !*req)
1315 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1317 n = find_account(client->doc, &req, &rc, NULL, 0);
1319 if (!n) {
1320 g_strfreev(req);
1321 return send_error(ctx, rc);
1325 * No sub-node defined. Remove the entire node (account).
1327 if (!req[1]) {
1328 if (n) {
1329 xmlUnlinkNode(n);
1330 xmlFreeNode(n);
1333 g_strfreev(req);
1334 return send_error(ctx, 0);
1337 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1338 g_strfreev(req);
1340 if (!n)
1341 return send_error(ctx, rc);
1343 if (n) {
1344 xmlUnlinkNode(n);
1345 xmlFreeNode(n);
1348 return send_error(ctx, 0);
1352 * Don't return with assuan_process_done() here. This has been called from
1353 * assuan_process_next() and the command should be finished in
1354 * client_thread().
1356 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1357 gsize len)
1359 assuan_context_t ctx = data;
1360 struct client_s *client = assuan_get_pointer(ctx);
1361 gchar **req;
1362 xmlNodePtr n;
1363 gpg_error_t rc = file_modified(client);
1365 if (assuan_rc || rc) {
1366 if (line)
1367 xfree(line);
1368 return assuan_rc ? assuan_rc : rc;
1371 req = split_input_line((gchar *)line, "\t", 0);
1372 xfree(line);
1374 if (!req || !*req)
1375 return EPWMD_COMMAND_SYNTAX;
1377 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1378 g_strfreev(req);
1379 return EPWMD_INVALID_ELEMENT;
1382 if (valid_element_path(req+1, TRUE) == FALSE) {
1383 g_strfreev(req);
1384 return EPWMD_INVALID_ELEMENT;
1387 again:
1388 n = find_account(client->doc, &req, &rc, NULL, 0);
1390 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1391 rc = new_account(client->doc, *req);
1393 if (rc) {
1394 g_strfreev(req);
1395 return rc;
1398 goto again;
1401 if (!n) {
1402 g_strfreev(req);
1403 return rc;
1406 if (req[1]) {
1407 if (!n->children)
1408 create_elements_cb(n, req+1, &rc, NULL);
1409 else
1410 find_elements(client->doc, n->children, req+1, &rc,
1411 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1414 g_strfreev(req);
1415 client->inquire_status = INQUIRE_DONE;
1416 return rc;
1419 static int store_command(assuan_context_t ctx, char *line)
1421 struct client_s *client = assuan_get_pointer(ctx);
1422 gpg_error_t rc = file_modified(client);
1424 if (rc)
1425 return send_error(ctx, rc);
1427 pth_cancel_point();
1428 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1429 pth_cancel_point();
1431 if (rc)
1432 return send_error(ctx, rc);
1434 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1435 client->inquire_status = INQUIRE_BUSY;
1436 return 0;
1439 static void *send_data_cb(void *arg)
1441 struct assuan_cmd_s *data = arg;
1442 gpg_error_t rc = assuan_send_data(data->ctx, data->line, data->line_len);
1443 pth_exit((void *)rc);
1444 return NULL;
1447 /* For every assuan command that needs to be sent to the client, a timeout is
1448 * needed to determine if the client lost the connection. The timeout is the
1449 * same as the "keepalive" configuration parameter or a default if unset.
1451 gpg_error_t do_assuan_command(assuan_context_t ctx,
1452 void *(*cb)(void *data), void *data)
1454 pth_attr_t attr = pth_attr_new();
1455 pth_t tid;
1456 gint n;
1457 gint to = get_key_file_integer("global", "keepalive");
1458 pth_event_t ev, tev;
1459 pth_status_t st;
1460 gpg_error_t rc;
1462 pth_attr_init(attr);
1463 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1464 tid = pth_spawn(attr, cb, data);
1465 n = errno;
1466 pth_attr_destroy(attr);
1468 if (!tid) {
1469 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1470 _gpg_strerror(gpg_error_from_errno(n)));
1471 return gpg_error_from_errno(n);
1474 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1475 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1476 tev = pth_event(PTH_EVENT_TIME, pth_timeout(to, 0));
1477 ev = pth_event_concat(ev, tev, NULL);
1478 pth_yield(tid);
1479 pth_wait(ev);
1480 st = pth_event_status(ev);
1482 if (st == PTH_STATUS_FAILED) {
1483 pth_cancel(tid);
1484 rc = GPG_ERR_ASS_WRITE_ERROR;
1486 else if (st == PTH_STATUS_OCCURRED) {
1487 pth_join(tid, (void **)&rc);
1489 else {
1490 st = pth_event_status(tev);
1492 if (st == PTH_STATUS_OCCURRED) {
1493 pth_cancel(tid);
1494 rc = GPG_ERR_ASS_WRITE_ERROR;
1498 return rc;
1501 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1502 gint total)
1504 int to_send;
1505 int sent = 0;
1506 gpg_error_t rc;
1507 struct assuan_cmd_s data;
1508 int progress = get_key_file_integer("global", "xfer_progress");
1510 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1512 if (total < ASSUAN_LINELENGTH)
1513 to_send = total;
1514 else
1515 to_send = ASSUAN_LINELENGTH;
1517 data.ctx = ctx;
1518 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1520 if (rc)
1521 return rc;
1523 do {
1524 if (sent + to_send > total)
1525 to_send = total - sent;
1527 data.line = (gchar *)line+sent;
1528 data.line_len = to_send;
1529 rc = do_assuan_command(ctx, send_data_cb, &data);
1531 if (!rc) {
1532 sent += to_send;
1534 if ((progress && !(sent % progress)) || sent == total)
1535 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1538 } while (!rc && sent < total);
1540 return rc;
1543 static int get_command(assuan_context_t ctx, char *line)
1545 struct client_s *client = assuan_get_pointer(ctx);
1546 gchar **req;
1547 gpg_error_t rc;
1548 xmlNodePtr n;
1550 rc = file_modified(client);
1552 if (rc)
1553 return send_error(ctx, rc);
1555 req = split_input_line(line, "\t", -1);
1557 if (!req || !*req) {
1558 g_strfreev(req);
1559 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1562 n = find_account(client->doc, &req, &rc, NULL, 0);
1564 if (!n) {
1565 g_strfreev(req);
1566 return send_error(ctx, rc);
1569 if (req[1])
1570 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1572 g_strfreev(req);
1574 if (rc)
1575 return send_error(ctx, rc);
1577 if (!n || !n->children)
1578 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1580 n = find_text_node(n->children);
1582 if (!n || !n->content || !*n->content)
1583 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1585 pth_cancel_point();
1586 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
1587 return send_error(ctx, rc);
1590 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1591 gpg_error_t *rc, gchar **req_orig, void *data)
1593 gchar *path = *(gchar **)data;
1594 gchar *tmp = NULL, *result;
1596 if (path) {
1597 g_free(path);
1598 *(gchar **)data = NULL;
1601 path = g_strjoinv("\t", target);
1603 if (!path) {
1604 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1605 *rc = gpg_error_from_errno(ENOMEM);
1606 return NULL;
1609 if (req_orig) {
1610 tmp = g_strjoinv("\t", req_orig);
1612 if (!tmp) {
1613 g_free(path);
1614 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1615 *rc = gpg_error_from_errno(ENOMEM);
1616 return NULL;
1620 if (tmp && *tmp)
1621 result = g_strdup_printf("%s\t%s", path, tmp);
1622 else
1623 result = g_strdup(path);
1625 if (!result) {
1626 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1627 *rc = gpg_error_from_errno(ENOMEM);
1628 g_free(path);
1629 g_free(tmp);
1630 return NULL;
1633 g_free(path);
1634 g_free(tmp);
1635 *(gchar **)data = result;
1636 return node;
1639 static void list_command_cleanup1(void *arg);
1640 static int realpath_command(assuan_context_t ctx, char *line)
1642 gpg_error_t rc;
1643 struct client_s *client = assuan_get_pointer(ctx);
1644 gchar **req;
1645 gchar *t;
1646 gint i;
1647 xmlNodePtr n;
1648 GString *string;
1649 gchar *rp = NULL;
1651 rc = file_modified(client);
1653 if (rc)
1654 return send_error(ctx, rc);
1656 if (strchr(line, '\t') != NULL) {
1657 if ((req = split_input_line(line, "\t", 0)) == NULL)
1658 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1660 else {
1661 if ((req = split_input_line(line, " ", 0)) == NULL)
1662 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1665 n = find_account(client->doc, &req, &rc, NULL, 0);
1667 if (!n) {
1668 g_strfreev(req);
1669 return send_error(ctx, rc);
1672 rp = g_strjoinv("\t", req);
1674 if (!rp) {
1675 g_strfreev(req);
1676 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1677 return send_syserror(ctx, ENOMEM);
1680 if (req[1]) {
1681 n = find_elements(client->doc, n->children, req+1, &rc,
1682 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1684 if (!n) {
1685 g_free(rp);
1686 g_strfreev(req);
1687 return send_error(ctx, rc);
1691 string = g_string_new(rp);
1692 g_free(rp);
1693 g_strfreev(req);
1695 if (!string) {
1696 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1697 return send_syserror(ctx, ENOMEM);
1700 again:
1701 for (i = 0, t = string->str + i; *t; t++, i++) {
1702 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1703 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1704 goto again;
1708 rc = xfer_data(ctx, string->str, string->len);
1709 list_command_cleanup1(string);
1710 return send_error(ctx, rc);
1713 static void list_command_cleanup1(void *arg)
1715 g_string_free((GString *)arg, TRUE);
1718 static void list_command_cleanup2(void *arg)
1720 struct element_list_s *elements = arg;
1722 if (elements) {
1723 gint total = g_slist_length(elements->list);
1724 gint i;
1726 for (i = 0; i < total; i++) {
1727 gchar *tmp = g_slist_nth_data(elements->list, i);
1728 g_free(tmp);
1731 g_slist_free(elements->list);
1733 if (elements->prefix)
1734 g_free(elements->prefix);
1736 g_free(elements);
1740 static int list_command(assuan_context_t ctx, char *line)
1742 struct client_s *client = assuan_get_pointer(ctx);
1743 gpg_error_t rc;
1744 struct element_list_s *elements = NULL;
1745 gchar *tmp;
1747 if (disable_list_and_dump == TRUE)
1748 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1750 rc = file_modified(client);
1752 if (rc)
1753 return send_error(ctx, rc);
1755 if (!*line) {
1756 GString *str;
1758 rc = list_accounts(client->doc, &str);
1760 if (rc)
1761 return send_error(ctx, rc);
1763 rc = xfer_data(ctx, str->str, str->len);
1764 list_command_cleanup1(str);
1765 return send_error(ctx, rc);
1768 elements = g_malloc0(sizeof(struct element_list_s));
1770 if (!elements) {
1771 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1772 rc = gpg_err_code_from_errno(ENOMEM);
1773 goto fail;
1776 rc = create_path_list(client->doc, elements, line);
1778 if (rc)
1779 goto fail;
1781 if (elements) {
1782 gint total = g_slist_length(elements->list);
1783 gint i;
1784 GString *str;
1786 if (!total) {
1787 rc = EPWMD_EMPTY_ELEMENT;
1788 goto fail;
1791 str = g_string_new(NULL);
1793 if (!str) {
1794 rc = gpg_err_code_from_errno(ENOMEM);
1795 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1796 goto fail;
1799 for (i = 0; i < total; i++) {
1800 tmp = g_slist_nth_data(elements->list, i);
1801 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1804 rc = xfer_data(ctx, str->str, str->len);
1805 list_command_cleanup1(str);
1807 else
1808 rc = EPWMD_EMPTY_ELEMENT;
1810 fail:
1811 list_command_cleanup2(elements);
1812 return send_error(ctx, rc);
1815 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1816 const gchar *value)
1818 xmlAttrPtr a;
1820 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1821 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1823 if (!a)
1824 return EPWMD_LIBXML_ERROR;
1826 else
1827 xmlNodeSetContent(a->children, (xmlChar *)value);
1829 return 0;
1833 * req[0] - element path
1835 static int attribute_list(assuan_context_t ctx, gchar **req)
1837 struct client_s *client = assuan_get_pointer(ctx);
1838 gchar **attrlist = NULL;
1839 gint i = 0;
1840 gchar **path = NULL;
1841 xmlAttrPtr a;
1842 xmlNodePtr n, an;
1843 gchar *line;
1844 gpg_error_t rc;
1846 if (!req || !req[0])
1847 return EPWMD_COMMAND_SYNTAX;
1849 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1851 * The first argument may be only an account.
1853 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1854 return EPWMD_COMMAND_SYNTAX;
1857 n = find_account(client->doc, &path, &rc, NULL, 0);
1859 if (!n) {
1860 g_strfreev(path);
1861 return rc;
1864 if (path[1]) {
1865 n = find_elements(client->doc, n->children, path+1, &rc,
1866 NULL, NULL, NULL, FALSE, 0, NULL);
1868 if (!n) {
1869 g_strfreev(path);
1870 return rc;
1874 g_strfreev(path);
1876 for (a = n->properties; a; a = a->next) {
1877 gchar **pa;
1879 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1880 if (attrlist)
1881 g_strfreev(attrlist);
1883 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1884 return gpg_error_from_errno(ENOMEM);
1887 attrlist = pa;
1888 an = a->children;
1889 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name, (gchar *)an->content);
1891 if (!attrlist[i]) {
1892 g_strfreev(attrlist);
1893 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1894 return gpg_error_from_errno(ENOMEM);
1897 attrlist[++i] = NULL;
1900 if (!attrlist)
1901 return EPWMD_EMPTY_ELEMENT;
1903 line = g_strjoinv("\n", attrlist);
1905 if (!line) {
1906 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1907 g_strfreev(attrlist);
1908 return gpg_error_from_errno(ENOMEM);
1911 rc = xfer_data(ctx, line, strlen(line));
1912 g_free(line);
1913 req_cleanup(attrlist);
1914 return rc;
1918 * req[0] - attribute
1919 * req[1] - element path
1921 static int attribute_delete(struct client_s *client, gchar **req)
1923 xmlAttrPtr a;
1924 xmlNodePtr n;
1925 gchar **path = NULL;
1926 gpg_error_t rc;
1928 if (!req || !req[0] || !req[1])
1929 return EPWMD_COMMAND_SYNTAX;
1931 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1933 * The first argument may be only an account.
1935 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1936 return EPWMD_COMMAND_SYNTAX;
1940 * Don't remove the "name" attribute for the account element. To remove an
1941 * account use DELETE <account>.
1943 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1944 rc = EPWMD_ATTR_SYNTAX;
1945 goto fail;
1948 n = find_account(client->doc, &path, &rc, NULL, 0);
1950 if (!n)
1951 goto fail;
1953 if (path[1]) {
1954 n = find_elements(client->doc, n->children, path+1, &rc,
1955 NULL, NULL, NULL, FALSE, 0, NULL);
1957 if (!n)
1958 goto fail;
1961 g_strfreev(path);
1963 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1964 return EPWMD_ATTR_NOT_FOUND;
1966 if (xmlRemoveProp(a) == -1)
1967 return EPWMD_LIBXML_ERROR;
1969 return 0;
1971 fail:
1972 g_strfreev(path);
1973 return rc;
1976 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1977 gpg_error_t *rc)
1979 gchar **src = *path;
1980 gchar **src_orig = g_strdupv(src);
1981 xmlNodePtr n = NULL;
1983 *rc = 0;
1985 if (!src_orig) {
1986 *rc = gpg_error_from_errno(ENOMEM);
1987 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1988 goto fail;
1991 again:
1992 n = find_account(client->doc, &src, rc, NULL, 0);
1994 if (!n) {
1995 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1996 *rc = new_account(client->doc, src[0]);
1998 if (*rc)
1999 goto fail;
2001 goto again;
2003 else
2004 goto fail;
2007 if (src[1]) {
2008 if (!n->children)
2009 n = create_target_elements_cb(n, src+1, rc, NULL);
2010 else
2011 n = find_elements(client->doc, n->children, src+1, rc,
2012 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
2014 if (!n)
2015 goto fail;
2018 * Reset the position of the element tree now that the elements
2019 * have been created.
2021 g_strfreev(src);
2022 src = src_orig;
2023 src_orig = NULL;
2024 n = find_account(client->doc, &src, rc, NULL, 0);
2026 if (!n)
2027 goto fail;
2029 n = find_elements(client->doc, n->children, src+1, rc,
2030 NULL, NULL, NULL, FALSE, 0, NULL);
2032 if (!n)
2033 goto fail;
2036 fail:
2037 if (src_orig)
2038 g_strfreev(src_orig);
2040 *path = src;
2041 return n;
2045 * Creates a "target" attribute. When other commands encounter an element with
2046 * this attribute, the element path is modified to the target value. If the
2047 * source element path doesn't exist when using 'ATTR SET target', it is
2048 * created, but the destination element path must exist.
2050 * req[0] - source element path
2051 * req[1] - destination element path
2053 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2055 gchar **src, **dst, *line = NULL;
2056 gpg_error_t rc;
2057 xmlNodePtr n;
2059 if (!req || !req[0] || !req[1])
2060 return EPWMD_COMMAND_SYNTAX;
2062 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2064 * The first argument may be only an account.
2066 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2067 return EPWMD_COMMAND_SYNTAX;
2070 if (valid_element_path(src, FALSE) == FALSE) {
2071 g_strfreev(src);
2072 return EPWMD_INVALID_ELEMENT;
2075 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2077 * The first argument may be only an account.
2079 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2080 rc = EPWMD_COMMAND_SYNTAX;
2081 goto fail;
2085 n = find_account(client->doc, &dst, &rc, NULL, 0);
2088 * Make sure the destination element path exists.
2090 if (!n)
2091 goto fail;
2093 if (dst[1]) {
2094 n = find_elements(client->doc, n->children, dst+1, &rc,
2095 NULL, NULL, NULL, FALSE, 0, NULL);
2097 if (!n)
2098 goto fail;
2101 n = create_element_path(client, &src, &rc);
2103 if (rc)
2104 goto fail;
2106 line = g_strjoinv("\t", dst);
2108 if (!line) {
2109 rc = gpg_error_from_errno(ENOMEM);
2110 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2111 goto fail;
2114 rc = add_attribute(n, "target", line);
2116 fail:
2117 g_free(line);
2118 g_strfreev(src);
2119 g_strfreev(dst);
2120 return rc;
2124 * req[0] - account name
2125 * req[1] - new name
2127 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2129 gpg_error_t rc;
2130 gchar **tmp;
2131 xmlNodePtr n;
2133 tmp = g_strdupv(req);
2135 if (!tmp) {
2136 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2137 return gpg_error_from_errno(ENOMEM);
2140 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2141 g_strfreev(tmp);
2143 if (!n)
2144 return rc;
2146 if (g_utf8_collate(req[0], req[1]) == 0)
2147 return 0;
2150 * Will not overwrite an existing account.
2152 tmp = g_strdupv(req+1);
2154 if (!tmp) {
2155 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2156 return gpg_error_from_errno(ENOMEM);
2159 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2160 g_strfreev(tmp);
2162 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
2163 return rc;
2165 if (n)
2166 return EPWMD_ACCOUNT_EXISTS;
2169 * Whitespace not allowed in account names.
2171 if (contains_whitespace(req[1]) == TRUE)
2172 return EPWMD_ATTR_SYNTAX;
2174 tmp = g_strdupv(req);
2176 if (!tmp) {
2177 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2178 return gpg_error_from_errno(ENOMEM);
2181 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2182 g_strfreev(tmp);
2184 if (!n)
2185 return EPWMD_ELEMENT_NOT_FOUND;
2187 return add_attribute(n, "name", req[1]);
2191 * req[0] - attribute
2192 * req[1] - element path
2194 static int attribute_get(assuan_context_t ctx, gchar **req)
2196 struct client_s *client = assuan_get_pointer(ctx);
2197 xmlNodePtr n;
2198 xmlChar *a;
2199 gchar **path= NULL;
2200 gpg_error_t rc;
2202 if (!req || !req[0] || !req[1])
2203 return EPWMD_COMMAND_SYNTAX;
2205 if (strchr(req[1], '\t')) {
2206 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2207 return EPWMD_COMMAND_SYNTAX;
2209 else {
2210 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2211 return EPWMD_COMMAND_SYNTAX;
2214 n = find_account(client->doc, &path, &rc, NULL, 0);
2216 if (!n)
2217 goto fail;
2219 if (path[1]) {
2220 n = find_elements(client->doc, n->children, path+1, &rc,
2221 NULL, NULL, NULL, FALSE, 0, NULL);
2223 if (!n)
2224 goto fail;
2227 g_strfreev(path);
2229 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2230 return EPWMD_ATTR_NOT_FOUND;
2232 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2233 xmlFree(a);
2234 return rc;
2236 fail:
2237 g_strfreev(path);
2238 return rc;
2242 * req[0] - attribute
2243 * req[1] - element path
2244 * req[2] - value
2246 static int attribute_set(struct client_s *client, gchar **req)
2248 gchar **path = NULL;
2249 gpg_error_t rc;
2250 xmlNodePtr n;
2252 if (!req || !req[0] || !req[1] || !req[2])
2253 return EPWMD_COMMAND_SYNTAX;
2256 * Reserved attribute names.
2258 if (g_utf8_collate(req[0], "name") == 0) {
2260 * Only reserved for the account element. Not the rest of the
2261 * document.
2263 if (strchr(req[1], '\t') == NULL)
2264 return name_attribute(client, req + 1);
2266 else if (g_utf8_collate(req[0], "target") == 0)
2267 return target_attribute(client, req + 1);
2269 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2271 * The first argument may be only an account.
2273 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2274 return EPWMD_COMMAND_SYNTAX;
2277 n = find_account(client->doc, &path, &rc, NULL, 0);
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);
2286 if (!n)
2287 goto fail;
2290 g_strfreev(path);
2291 return add_attribute(n, req[0], req[2]);
2293 fail:
2294 g_strfreev(path);
2295 return rc;
2299 * req[0] - command
2300 * req[1] - attribute name or element path if command is LIST
2301 * req[2] - element path
2302 * req[2] - element path or value
2304 static int attr_command(assuan_context_t ctx, char *line)
2306 struct client_s *client = assuan_get_pointer(ctx);
2307 gchar **req;
2308 gpg_error_t rc = 0;
2310 rc = file_modified(client);
2312 if (rc)
2313 return send_error(ctx, rc);
2315 req = split_input_line(line, " ", 4);
2317 if (!req || !req[0] || !req[1]) {
2318 g_strfreev(req);
2319 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2322 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2323 rc = attribute_set(client, req+1);
2324 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2325 rc = attribute_get(ctx, req+1);
2326 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2327 rc = attribute_delete(client, req+1);
2328 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2329 rc = attribute_list(ctx, req+1);
2330 else
2331 rc = EPWMD_COMMAND_SYNTAX;
2333 req_cleanup(req);
2334 return send_error(ctx, rc);
2337 static int iscached_command(assuan_context_t ctx, char *line)
2339 gchar **req = split_input_line(line, " ", 0);
2340 guchar md5file[16];
2341 gchar *path, *tmp;
2343 if (!req || !*req) {
2344 g_strfreev(req);
2345 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2348 if (!valid_filename(req[0])) {
2349 g_strfreev(req);
2350 return EPWMD_INVALID_FILENAME;
2353 tmp = get_key_file_string("global", "data_directory");
2355 if (!tmp) {
2356 g_strfreev(req);
2357 return gpg_error_from_errno(ENOMEM);
2360 path = expand_homedir(tmp);
2362 if (!path) {
2363 g_strfreev(req);
2364 g_free(tmp);
2365 return gpg_error_from_errno(ENOMEM);
2368 g_free(tmp);
2369 tmp = path;
2370 path = g_strdup_printf("%s/%s", tmp, req[0]);
2371 g_free(tmp);
2373 if (!path) {
2374 g_strfreev(req);
2375 return gpg_error_from_errno(ENOMEM);
2378 if (access(path, R_OK) == -1) {
2379 gpg_error_t rc = gpg_error_from_syserror();
2381 g_free(path);
2382 g_strfreev(req);
2383 return send_error(ctx, rc);
2386 g_free(path);
2387 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2388 g_strfreev(req);
2389 CACHE_LOCK(ctx);
2391 if (cache_iscached(md5file) == FALSE) {
2392 CACHE_UNLOCK;
2393 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2396 CACHE_UNLOCK;
2397 return send_error(ctx, 0);
2400 static int clearcache_command(assuan_context_t ctx, char *line)
2402 struct client_s *client = assuan_get_pointer(ctx);
2403 gchar **req = split_input_line(line, " ", 0);
2404 guchar md5file[16];
2406 CACHE_LOCK(ctx);
2408 if (!req || !*req) {
2409 g_strfreev(req);
2410 cache_clear(client->md5file, 2);
2411 CACHE_UNLOCK;
2412 return send_error(ctx, 0);
2415 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2416 g_strfreev(req);
2418 if (cache_clear(md5file, 1) == FALSE) {
2419 CACHE_UNLOCK;
2420 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2423 CACHE_UNLOCK;
2424 return send_error(ctx, 0);
2427 static int cachetimeout_command(assuan_context_t ctx, char *line)
2429 guchar md5file[16];
2430 glong timeout;
2431 gchar **req = split_input_line(line, " ", 0);
2432 gchar *p;
2434 if (!req || !*req || !req[1]) {
2435 g_strfreev(req);
2436 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2439 errno = 0;
2440 timeout = strtol(req[0], &p, 10);
2442 if (errno != 0 || *p != 0) {
2443 g_strfreev(req);
2444 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2447 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2448 CACHE_LOCK(client->ctx);
2450 if (cache_set_timeout(md5file, timeout) == FALSE) {
2451 CACHE_UNLOCK;
2452 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2455 CACHE_UNLOCK;
2456 return send_error(ctx, 0);
2459 static int dump_command(assuan_context_t ctx, char *line)
2461 xmlChar *xml;
2462 gssize len;
2463 struct client_s *client = assuan_get_pointer(ctx);
2464 gpg_error_t rc;
2466 if (disable_list_and_dump == TRUE)
2467 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2469 rc = file_modified(client);
2471 if (rc)
2472 return send_error(ctx, rc);
2474 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2476 if (!xml) {
2477 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2478 return send_syserror(ctx, ENOMEM);
2481 rc = xfer_data(ctx, (gchar *)xml, len);
2482 xmlFree(xml);
2483 return send_error(ctx, rc);
2486 static int getconfig_command(assuan_context_t ctx, gchar *line)
2488 struct client_s *client = assuan_get_pointer(ctx);
2489 gpg_error_t rc = 0;
2490 gchar filename[255]={0}, param[747]={0};
2491 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2493 if (strchr(line, ' ')) {
2494 sscanf(line, " %254[^ ] %746c", filename, param);
2495 fp = filename;
2496 paramp = param;
2499 if (fp && !valid_filename(fp))
2500 return send_error(ctx, EPWMD_INVALID_FILENAME);
2502 paramp = g_ascii_strdown(paramp, -1);
2504 if (!paramp) {
2505 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2506 return send_syserror(ctx, ENOMEM);
2509 p = get_key_file_string(fp ? fp : "global", paramp);
2510 g_free(paramp);
2512 if (!p)
2513 return send_error(ctx, GPG_ERR_NO_VALUE);
2515 tmp = expand_homedir(p);
2516 g_free(p);
2518 if (!tmp) {
2519 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2520 return send_syserror(ctx, ENOMEM);
2523 p = tmp;
2524 rc = xfer_data(ctx, p, strlen(p));
2525 g_free(p);
2526 return send_error(ctx, rc);
2529 struct xpath_s {
2530 xmlXPathContextPtr xp;
2531 xmlXPathObjectPtr result;
2532 xmlBufferPtr buf;
2533 gchar **req;
2536 static void xpath_command_cleanup(void *arg)
2538 struct xpath_s *xpath = arg;
2540 req_cleanup(xpath->req);
2542 if (xpath->buf)
2543 xmlBufferFree(xpath->buf);
2545 if (xpath->result)
2546 xmlXPathFreeObject(xpath->result);
2548 if (xpath->xp)
2549 xmlXPathFreeContext(xpath->xp);
2552 static int xpath_command(assuan_context_t ctx, gchar *line)
2554 struct client_s *client = assuan_get_pointer(ctx);
2555 gpg_error_t rc;
2556 struct xpath_s xpath;
2558 if (disable_list_and_dump == TRUE)
2559 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2561 rc = file_modified(client);
2563 if (rc)
2564 return send_error(ctx, rc);
2566 if (!line || !*line)
2567 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2569 memset(&xpath, 0, sizeof(struct xpath_s));
2571 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
2572 if (strv_printf(&xpath.req, "%s", line) == FALSE)
2573 return send_syserror(ctx, ENOMEM);
2576 xpath.xp = xmlXPathNewContext(client->doc);
2578 if (!xpath.xp) {
2579 xpath_command_cleanup(&xpath);
2580 return send_error(ctx, EPWMD_LIBXML_ERROR);
2583 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2585 if (!xpath.result) {
2586 xpath_command_cleanup(&xpath);
2587 return send_error(ctx, EPWMD_LIBXML_ERROR);
2590 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2591 rc = EPWMD_EMPTY_ELEMENT;
2592 goto fail;
2595 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2596 (xmlChar *)xpath.req[1], &xpath.buf);
2598 if (rc)
2599 goto fail;
2600 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
2601 rc = EPWMD_EMPTY_ELEMENT;
2602 goto fail;
2604 else if (xpath.req[1])
2605 goto fail;
2607 pth_cancel_point();
2608 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
2609 xmlBufferLength(xpath.buf));
2611 fail:
2612 xpath_command_cleanup(&xpath);
2613 return send_error(ctx, rc);
2616 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2617 gsize len)
2619 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2620 gpg_error_t rc = file_modified(client);
2621 gchar **req, **path = NULL, **path_orig = NULL, *content;
2622 xmlDocPtr doc;
2623 xmlNodePtr n, root, copy;
2625 if (assuan_rc || rc) {
2626 if (line)
2627 xfree(line);
2628 return assuan_rc ? assuan_rc : rc;
2631 req = split_input_line((gchar *)line, " ", 2);
2632 xfree(line);
2634 if (!req || !*req)
2635 return EPWMD_COMMAND_SYNTAX;
2637 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2638 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2639 return EPWMD_COMMAND_SYNTAX;
2642 content = req[1];
2644 if (!content || !*content) {
2645 rc = EPWMD_COMMAND_SYNTAX;
2646 goto fail;
2649 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2650 rc = EPWMD_INVALID_ELEMENT;
2651 goto fail;
2654 if (valid_element_path(path+1, FALSE) == FALSE) {
2655 rc = EPWMD_INVALID_ELEMENT;
2656 goto fail;
2659 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2661 if (!doc) {
2662 rc = EPWMD_LIBXML_ERROR;
2663 goto fail;
2666 root = xmlDocGetRootElement(doc);
2667 path_orig = g_strdupv(path);
2669 if (!path_orig) {
2670 xmlFreeDoc(doc);
2671 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2672 rc = gpg_error_from_errno(ENOMEM);
2673 goto fail;
2676 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2677 g_strfreev(path_orig);
2678 xmlFreeDoc(doc);
2679 rc = gpg_error_from_errno(ENOMEM);
2680 goto fail;
2683 n = find_account(client->doc, &path, &rc, NULL, 0);
2685 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2686 g_strfreev(path_orig);
2687 xmlFreeDoc(doc);
2688 goto fail;
2690 else if (!rc) {
2691 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2693 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2694 g_strfreev(path_orig);
2695 xmlFreeDoc(doc);
2696 goto fail;
2698 else if (!rc) {
2699 xmlNodePtr parent = n->parent;
2701 xmlUnlinkNode(n);
2702 xmlFreeNode(n);
2703 n = parent;
2707 g_strfreev(path);
2708 path = path_orig;
2710 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2711 n = create_element_path(client, &path, &rc);
2713 if (rc) {
2714 xmlFreeDoc(doc);
2715 goto fail;
2719 copy = xmlCopyNode(root, 1);
2720 n = xmlAddChild(n, copy);
2721 xmlFreeDoc(doc);
2723 if (!n)
2724 rc = EPWMD_LIBXML_ERROR;
2726 fail:
2727 g_strfreev(path);
2728 g_strfreev(req);
2729 client->inquire_status = INQUIRE_DONE;
2730 return rc;
2733 static int import_command(assuan_context_t ctx, gchar *line)
2735 gpg_error_t rc;
2736 struct client_s *client = assuan_get_pointer(ctx);
2738 rc = file_modified(client);
2740 if (rc)
2741 return send_error(ctx, rc);
2743 pth_cancel_point();
2744 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2745 pth_cancel_point();
2747 if (rc)
2748 return send_error(ctx, rc);
2750 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2751 client->inquire_status = INQUIRE_BUSY;
2752 return 0;
2755 static int lock_command(assuan_context_t ctx, gchar *line)
2757 gpg_error_t rc;
2758 struct client_s *client = assuan_get_pointer(ctx);
2760 rc = file_modified(client);
2762 if (rc)
2763 return send_error(ctx, rc);
2765 rc = lock_file_mutex(client);
2767 if (!rc)
2768 client->is_lock_cmd = TRUE;
2770 return send_error(ctx, rc);
2773 static int unlock_command(assuan_context_t ctx, gchar *line)
2775 struct client_s *client = assuan_get_pointer(ctx);
2776 gpg_error_t rc = file_modified(client);
2778 if (rc)
2779 return send_error(ctx, rc);
2781 unlock_file_mutex(client);
2782 return send_error(ctx, 0);
2785 static int getpid_command(assuan_context_t ctx, gchar *line)
2787 gpg_error_t rc;
2788 gchar buf[32];
2789 pid_t pid = getpid();
2791 print_fmt(buf, sizeof(buf), "%i", pid);
2792 pth_cancel_point();
2793 rc = xfer_data(ctx, buf, strlen(buf));
2794 pth_cancel_point();
2795 return send_error(ctx, rc);
2798 static int version_command(assuan_context_t ctx, gchar *line)
2800 gpg_error_t rc;
2801 gchar buf[32];
2803 print_fmt(buf, sizeof(buf), "%s", PACKAGE_VERSION);
2804 pth_cancel_point();
2805 rc = xfer_data(ctx, buf, strlen(buf));
2806 pth_cancel_point();
2807 return send_error(ctx, rc);
2810 static void bye_notify(assuan_context_t ctx)
2812 struct client_s *cl = assuan_get_pointer(ctx);
2814 /* This will let assuan_process_next() return. */
2815 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
2818 static void reset_notify(assuan_context_t ctx)
2820 struct client_s *cl = assuan_get_pointer(ctx);
2822 if (cl)
2823 cleanup_client(cl);
2826 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2828 gchar name[32] = {0}, value[256] = {0};
2829 struct client_s *cl = assuan_get_pointer(ctx);
2831 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2832 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2834 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2835 pth_attr_t attr = pth_attr_of(pth_self());
2836 gchar buf[41];
2838 if (!strcmp(value, "NULL")) {
2839 pth_attr_set(attr, PTH_ATTR_NAME, NULL);
2840 pth_attr_destroy(attr);
2841 return 0;
2844 print_fmt(buf, sizeof(buf), "%s", value);
2845 pth_attr_set(attr, PTH_ATTR_NAME, buf);
2846 pth_attr_destroy(attr);
2847 #ifdef WITH_PINENTRY
2848 if (cl->pinentry->name)
2849 g_free(cl->pinentry->name);
2851 cl->pinentry->name = g_strdup(buf);
2852 #endif
2853 log_write("OPTION CLIENT %s=%s", name, buf);
2855 else
2856 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2858 return 0;
2861 static void set_option_value(gchar **opt, const gchar *val)
2863 if (opt)
2864 g_free(*opt);
2866 *opt = NULL;
2868 if (val && strcmp(val, "NULL"))
2869 *opt = g_strdup(val);
2872 static int option_handler(assuan_context_t ctx, const gchar *name,
2873 const gchar *value)
2875 struct client_s *client = assuan_get_pointer(ctx);
2877 if (!value || !*value)
2878 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2880 if (g_strcasecmp(name, (gchar *)"client") == 0)
2881 return parse_client_option(ctx, value);
2883 if (g_strcasecmp(name, (gchar *)"iterations") == 0) {
2884 long n;
2885 gchar *p = NULL;
2887 errno = 0;
2888 n = strtol(value, &p, 10);
2890 if (errno || (p && *p) || n < 0)
2891 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2893 MUTEX_LOCK(&rcfile_mutex);
2894 g_key_file_set_integer(keyfileh, client->filename ? client->filename : "global", "iterations", (guint)n);
2895 MUTEX_UNLOCK(&rcfile_mutex);
2896 send_status_all(STATUS_CONFIG);
2898 #ifdef WITH_PINENTRY
2899 else if (g_strcasecmp(name, (gchar *)"lc_messages") == 0)
2900 set_option_value(&client->pinentry->lcmessages, value);
2901 else if (g_strcasecmp(name, (gchar *)"lc_ctype") == 0)
2902 set_option_value(&client->pinentry->lcctype, value);
2903 else if (g_strcasecmp(name, (gchar *)"ttyname") == 0)
2904 set_option_value(&client->pinentry->ttyname, value);
2905 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0)
2906 set_option_value(&client->pinentry->ttytype, value);
2907 else if (g_strcasecmp(name, (gchar *)"display") == 0)
2908 set_option_value(&client->pinentry->display, value);
2909 else if (g_strcasecmp(name, (gchar *)"path") == 0)
2910 set_option_value(&client->pinentry->path, value);
2911 else if (g_strcasecmp(name, (gchar *)"title") == 0)
2912 set_option_value(&client->pinentry->title, value);
2913 else if (g_strcasecmp(name, (gchar *)"prompt") == 0)
2914 set_option_value(&client->pinentry->prompt, value);
2915 else if (g_strcasecmp(name, (gchar *)"desc") == 0)
2916 set_option_value(&client->pinentry->desc, value);
2918 * Look at client_thread() to see how this works.
2920 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2921 gchar *p = NULL;
2922 gint n = strtol(value, &p, 10);
2924 if (*p || n < 0)
2925 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2927 client->pinentry->timeout = n;
2929 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2930 gchar *p = NULL;
2931 gint n = strtol(value, &p, 10);
2933 if (*p || n < 0 || n > 1)
2934 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2936 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2938 #endif
2939 else
2940 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2942 log_write("OPTION %s=%s", name, value);
2943 return 0;
2946 gpg_error_t register_commands(assuan_context_t ctx)
2948 static struct {
2949 const gchar *name;
2950 gint (*handler)(assuan_context_t, gchar *line);
2951 } table[] = {
2952 { "OPEN", open_command },
2953 { "SAVE", save_command },
2954 { "LIST", list_command },
2955 { "REALPATH", realpath_command },
2956 { "STORE", store_command },
2957 { "DELETE", delete_command },
2958 { "GET", get_command },
2959 { "ATTR", attr_command },
2960 { "ISCACHED", iscached_command },
2961 { "CLEARCACHE", clearcache_command },
2962 { "CACHETIMEOUT", cachetimeout_command },
2963 { "GETCONFIG", getconfig_command },
2964 { "DUMP", dump_command },
2965 { "XPATH", xpath_command },
2966 { "IMPORT", import_command },
2967 { "LOCK", lock_command },
2968 { "UNLOCK", unlock_command },
2969 { "GETPID", getpid_command },
2970 { "VERSION", version_command },
2971 { "INPUT", NULL },
2972 { "OUTPUT", NULL },
2973 { NULL, NULL }
2975 gint i, rc;
2977 for (i=0; table[i].name; i++) {
2978 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2980 if (rc)
2981 return rc;
2984 rc = assuan_register_bye_notify(ctx, bye_notify);
2986 if (rc)
2987 return rc;
2989 rc = assuan_register_option_handler(ctx, option_handler);
2991 if (rc)
2992 return rc;
2994 rc = assuan_register_reset_notify(ctx, reset_notify);
2996 if (rc)
2997 return rc;
2999 return assuan_register_post_cmd_notify(ctx, command_finalize);
3002 gpg_error_t try_xml_decrypt(assuan_context_t ctx, guchar *key,
3003 struct client_crypto_s *crypto, gpointer *dst, goffset *dst_len)
3005 goffset insize, len;
3006 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
3007 guint64 iter = 0, n_iter = 0, iter_progress = 0;
3008 gint zrc = 0;
3009 gulong outsize = 0;
3010 gpg_error_t rc;
3011 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->fh1) : sizeof(crypto->fh->fh2);
3012 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->fh1.iter : crypto->fh->fh2.iter;
3014 lseek(crypto->fh->fd, fh_size, SEEK_SET);
3015 insize = crypto->fh->st.st_size - fh_size;
3016 crypto->iv = gcry_malloc(gcryblocksize);
3018 if (!crypto->iv) {
3019 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3020 return gpg_error_from_errno(ENOMEM);
3023 /* No encryption iterations. This is a plain (gzipped) file. */
3024 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0)) {
3026 * cache_file_count() needs both .used == TRUE and a valid key in
3027 * order for it to count as a used cache entry. Fixes CACHE status
3028 * messages.
3030 memset(key, '!', gcrykeysize);
3033 if (crypto->fh->v1)
3034 memcpy(crypto->iv, crypto->fh->fh1.iv, gcryblocksize);
3035 else
3036 memcpy(crypto->iv, crypto->fh->fh2.iv, gcryblocksize);
3038 crypto->inbuf = gcry_malloc(insize);
3040 if (!crypto->inbuf) {
3041 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3042 return gpg_error_from_errno(ENOMEM);
3045 crypto->insize = insize;
3046 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
3047 pth_cancel_point();
3049 if (len != crypto->insize)
3050 return GPG_ERR_INV_LENGTH;
3052 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0))
3053 goto decompress;
3055 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
3056 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3057 return rc;
3060 if ((rc = gcry_cipher_setkey(crypto->gh, key, gcrykeysize))) {
3061 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3062 return rc;
3065 iter_progress = (guint64)get_key_file_integer(client && client->filename ?
3066 client->filename : "global", "iteration_progress");
3068 if (iter_progress > 0 && fh_iter >= iter_progress) {
3069 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
3070 pth_cancel_point();
3072 if (rc)
3073 return rc;
3076 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3078 if (rc)
3079 return rc;
3081 crypto->tkey = gcry_malloc(gcrykeysize);
3083 if (!crypto->tkey) {
3084 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
3085 return gpg_error_from_errno(ENOMEM);
3088 memcpy(crypto->tkey, key, gcrykeysize);
3089 guchar *tkey = crypto->tkey;
3090 tkey[0] ^= 1;
3092 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
3093 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3094 return rc;
3097 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
3098 if (iter_progress > 0 && iter >= iter_progress) {
3099 if (!(iter % iter_progress)) {
3100 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
3101 ++n_iter * iter_progress, fh_iter);
3102 pth_cancel_point();
3104 if (rc)
3105 return rc;
3109 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
3110 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3111 return rc;
3114 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3116 if (rc) {
3117 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3118 return rc;
3121 iter++;
3124 if (iter_progress && fh_iter >= iter_progress) {
3125 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
3126 pth_cancel_point();
3128 if (rc)
3129 return rc;
3132 decompress:
3133 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
3134 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
3135 if (zrc == Z_MEM_ERROR)
3136 return gpg_error_from_errno(ENOMEM);
3137 else
3138 return EPWMD_BADKEY; // Not a valid gzip header. Must be a bad key.
3141 if (g_strncasecmp(crypto->outbuf, "<?xml version=", 14) != 0) {
3142 gcry_free(crypto->outbuf);
3143 crypto->outbuf = NULL;
3144 return EPWMD_BADKEY;
3147 if (ctx) {
3148 client->xml = crypto->outbuf;
3149 client->len = outsize;
3150 crypto->outbuf = NULL;
3152 else if (dst) {
3153 *dst = crypto->outbuf;
3154 *dst_len = outsize;
3155 crypto->outbuf = NULL;
3158 /* The calling function should free the crypto struct. */
3159 return 0;
3163 * This is called after every Assuan command.
3165 void command_finalize(assuan_context_t ctx, gint rc)
3167 struct client_s *client = assuan_get_pointer(ctx);
3169 if (!client->is_lock_cmd)
3170 unlock_file_mutex(client);