If the client thread terminates while a pinentry is running, terminate
[pwmd.git] / src / commands.c
blob60d64fc3799a791d03357697e450077309ce8c75
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 #ifdef WITH_GNUTLS
48 #include "tls.h"
49 #endif
50 #include "commands.h"
51 #include "lock.h"
53 static void *z_alloc(void *data, unsigned items, unsigned size)
55 return gcry_calloc(items, size);
58 static void z_free(void *data, void *p)
60 gcry_free(p);
63 static gpg_error_t file_modified(struct client_s *client)
65 struct stat st;
66 gpg_error_t rc;
68 if (client->state != STATE_OPEN)
69 return EPWMD_NO_FILE;
71 rc = lock_file_mutex(client);
73 if (rc)
74 return rc;
76 if (lstat(client->filename, &st) == 0 && client->mtime) {
77 if (client->mtime != st.st_mtime)
78 return EPWMD_FILE_MODIFIED;
81 return 0;
84 static gpg_error_t parse_xml(assuan_context_t ctx)
86 struct client_s *client = assuan_get_pointer(ctx);
88 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
90 if (!client->doc)
91 return EPWMD_LIBXML_ERROR;
93 return 0;
96 void unlock_file_mutex(struct client_s *client)
98 struct file_mutex_s *m;
100 #ifdef WITH_PINENTRY
101 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
102 #else
103 if (client->has_lock == FALSE)
104 #endif
105 return;
107 CACHE_LOCK(client->ctx);
109 if (cache_get_mutex(client->md5file, &m) == FALSE) {
110 CACHE_UNLOCK;
111 return;
114 CACHE_UNLOCK;
115 MUTEX_UNLOCK(&m->mutex);
116 client->has_lock = client->is_lock_cmd = FALSE;
119 gpg_error_t lock_file_mutex(struct client_s *client)
121 struct file_mutex_s *m;
123 if (client->has_lock == TRUE)
124 return 0;
126 CACHE_LOCK(client->ctx);
128 if (cache_get_mutex(client->md5file, &m) == FALSE) {
129 CACHE_UNLOCK;
130 return 0;
133 CACHE_UNLOCK;
135 if (pthread_mutex_trylock(&m->mutex) == EBUSY) {
136 if (client->ctx) {
138 * If a client disconnects unexpectedly while waiting for a
139 * lock, this lets the thread terminate because send_status()
140 * will return an error.
142 while (pthread_mutex_trylock(&m->mutex) == EBUSY) {
143 gpg_error_t rc = send_status(client->ctx, STATUS_LOCKED, NULL);
145 if (rc)
146 return rc;
148 sleep(1);
151 else {
152 MUTEX_LOCK(&m->mutex);
155 else {
156 MUTEX_LOCK_DEBUG;
159 client->has_lock = TRUE;
160 return 0;
163 void free_client(struct client_s *client)
165 if (client->doc)
166 xmlFreeDoc(client->doc);
168 if (client->xml)
169 gcry_free(client->xml);
171 if (client->filename)
172 g_free(client->filename);
174 if (client->crypto)
175 cleanup_crypto(&client->crypto);
178 void cleanup_client(struct client_s *client)
180 assuan_context_t ctx = client->ctx;
181 struct client_thread_s *thd = client->thd;
182 gboolean has_lock = client->has_lock;
183 #ifdef WITH_PINENTRY
184 struct pinentry_s *pin = client->pinentry;
185 #endif
187 unlock_file_mutex(client);
188 CACHE_LOCK(client->ctx);
189 cache_decr_refcount(client->md5file);
192 * This may be a new file so don't use a cache slot. save_command() will
193 * set this to FALSE on success.
195 if (client->new == TRUE)
196 cache_clear(client->md5file, 1);
198 free_client(client);
199 memset(client, 0, sizeof(struct client_s));
200 client->state = STATE_CONNECTED;
201 client->ctx = ctx;
202 client->thd = thd;
203 client->freed = TRUE;
204 #ifdef WITH_PINENTRY
205 client->pinentry = pin;
206 #endif
207 client->has_lock = has_lock;
208 CACHE_UNLOCK;
211 gboolean do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
212 gpointer *out, gulong *outsize, gint *rc)
214 z_stream z;
215 gpointer pout;
216 gz_header h;
217 gchar buf[17];
219 z.zalloc = z_alloc;
220 z.zfree = z_free;
221 z.next_in = in;
222 z.avail_in = (uInt)insize;
223 z.avail_out = zlib_bufsize;
224 z.next_out = pout = gcry_malloc(zlib_bufsize);
226 if (!pout) {
227 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
228 *rc = Z_MEM_ERROR;
229 return FALSE;
232 *rc = inflateInit2(&z, 47);
234 if (*rc != Z_OK) {
235 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
236 gcry_free(pout);
237 return FALSE;
240 memset(&h, 0, sizeof(gz_header));
241 h.comment = (guchar *)buf;
242 h.comm_max = sizeof(buf);
243 *rc = inflateGetHeader(&z, &h);
245 if (*rc != Z_OK) {
246 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
247 gcry_free(pout);
248 inflateEnd(&z);
249 return FALSE;
252 *rc = inflate(&z, Z_BLOCK);
254 if (*rc != Z_OK) {
255 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
256 gcry_free(pout);
257 inflateEnd(&z);
258 return FALSE;
261 if (h.comment)
262 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
264 do {
265 gpointer p;
267 *rc = inflate(&z, Z_FINISH);
269 switch (*rc) {
270 case Z_OK:
271 break;
272 case Z_BUF_ERROR:
273 if (!z.avail_out) {
274 p = gcry_realloc(pout, z.total_out + zlib_bufsize);
276 if (!p) {
277 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
278 *rc = Z_MEM_ERROR;
279 goto fail;
282 pout = p;
283 z.next_out = pout + z.total_out;
284 z.avail_out = zlib_bufsize;
285 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
286 z.total_out, insize);
287 if (*rc)
288 goto fail;
290 break;
291 case Z_STREAM_END:
292 break;
293 default:
294 goto fail;
295 break;
297 } while (*rc != Z_STREAM_END);
299 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", z.total_out,
300 insize);
302 if (*rc)
303 goto fail;
305 *out = pout;
306 *outsize = z.total_out;
307 inflateEnd(&z);
308 *rc = 0;
309 return TRUE;
311 fail:
312 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
313 gcry_free(pout);
314 inflateEnd(&z);
315 return FALSE;
318 static void read_file_header_handler(void *arg)
320 close((int)arg);
323 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
324 gpg_error_t *rc)
326 gint fd;
327 gsize len;
328 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
329 gsize fh_size;
331 *rc = 0;
333 if (!fh) {
334 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
335 *rc = gpg_error_from_errno(ENOMEM);
336 return NULL;
339 fh_size = v1 ? sizeof(fh->fh1) : sizeof(fh->fh2);
341 if (lstat(filename, &fh->st) == -1) {
342 *rc = gpg_error_from_syserror();
343 g_free(fh);
344 return NULL;
347 if (!S_ISREG(fh->st.st_mode)) {
348 *rc = GPG_ERR_ENOANO;
349 g_free(fh);
350 return NULL;
353 fd = open(filename, O_RDONLY);
355 if (fd == -1) {
356 *rc = gpg_error_from_errno(errno);
357 g_free(fh);
358 return NULL;
361 if (v1)
362 len = read(fd, &fh->fh1, fh_size);
363 else
364 len = read(fd, &fh->fh2, fh_size);
366 if (len != fh_size) {
367 gint n = errno;
368 pthread_cleanup_push(read_file_header_handler, (void *)fd);
369 g_free(fh);
370 pthread_cleanup_pop(1);
371 *rc = gpg_error_from_errno(n);
372 return NULL;
375 fh->v1 = v1;
376 fh->fd = fd;
377 return fh;
380 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *key,
381 gboolean cached)
383 struct client_s *client = assuan_get_pointer(ctx);
384 gpg_error_t rc;
385 gint timeout;
387 /* New file. */
388 if (!client->crypto->fh) {
389 if (key[0])
390 goto update_cache;
392 goto done;
395 rc = try_xml_decrypt(ctx, key, client->crypto, NULL, NULL);
397 if (rc) {
398 cleanup_client(client);
399 return send_error(ctx, rc);
402 update_cache:
403 CACHE_LOCK(client->ctx);
405 if (cached == FALSE) {
406 if (cache_update_key(client->md5file, key) == FALSE) {
407 cleanup_client(client);
408 CACHE_UNLOCK;
409 return send_syserror(ctx, ENOMEM);
412 timeout = get_key_file_integer(client->filename, "cache_timeout");
413 cache_reset_timeout(client->md5file, timeout);
415 else
416 cache_set_timeout(client->md5file, -2);
418 CACHE_UNLOCK;
420 done:
421 if (client->crypto->key != key)
422 gcry_free(key); // This is invokation is a pinentry callback.
424 rc = parse_xml(ctx);
426 if (client->xml) {
427 gcry_free(client->xml);
428 client->xml = NULL;
431 if (!rc) {
432 if (client->new == FALSE)
433 send_status_all(STATUS_CACHE);
435 client->state = STATE_OPEN;
438 if (!rc && client->new == FALSE &&
439 client->crypto->fh->fh2.iter != (guint)get_key_file_integer(client->filename, "iterations")) {
440 g_key_file_set_integer(keyfileh, client->filename, "iterations",
441 client->crypto->fh->fh2.iter);
442 send_status_all(STATUS_CONFIG);
445 if (!rc)
446 log_write("OPEN '%s'", client->filename);
448 cleanup_crypto(&client->crypto);
449 return send_error(ctx, rc);
452 #ifdef WITH_GNUTLS
453 static gboolean validate_access(struct client_s *cl, const gchar *filename)
455 gchar *access = get_key_file_string(filename, "tcp_access");
456 gchar **list, **p;
458 if (!access)
459 return TRUE;
461 list = g_strsplit(access, ",", -1);
462 g_free(access);
464 if (!list) {
465 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
466 return FALSE;
469 for (p = list; *p; p++) {
470 gboolean not = FALSE;
471 gchar *fp = *p;
473 if (*fp == '!') {
474 not = TRUE;
475 fp++;
477 if (!*fp)
478 break;
481 if (strcasecmp(cl->thd->tls->fp, fp) == 0) {
482 if (not == TRUE)
483 continue;
485 g_strfreev(list);
486 return TRUE;
490 /* Not allowed. */
491 g_strfreev(list);
492 return FALSE;
494 #endif
496 static int open_command(assuan_context_t ctx, char *line)
498 gboolean cached = FALSE;
499 gpg_error_t rc;
500 struct client_s *client = assuan_get_pointer(ctx);
501 gchar **req;
502 gchar *filename = NULL;
504 if ((req = split_input_line(line, " ", 2)) != NULL)
505 filename = req[0];
507 if (!filename || !*filename) {
508 g_strfreev(req);
509 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
512 if (valid_filename(filename) == FALSE) {
513 g_strfreev(req);
514 return send_error(ctx, EPWMD_INVALID_FILENAME);
517 if (client->state == STATE_OPEN)
518 cleanup_client(client);
520 #ifdef WITH_GNUTLS
521 if (client->thd->remote == TRUE) {
522 if (validate_access(client, filename) == FALSE) {
523 log_write(N_("client validation failed for file '%s'"), filename);
524 g_strfreev(req);
525 return send_error(ctx, EPWMD_FILE_ACCESS);
528 #endif
530 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
531 CACHE_LOCK(client->ctx);
533 if (cache_has_file(client->md5file) == FALSE) {
534 if (cache_add_file(client->md5file, NULL) == FALSE) {
535 g_strfreev(req);
536 CACHE_UNLOCK;
537 return send_syserror(ctx, ENOMEM);
541 cache_incr_refcount(client->md5file);
542 CACHE_UNLOCK;
543 rc = lock_file_mutex(client);
545 if (rc) {
546 g_strfreev(req);
547 return send_error(ctx, rc);
550 client->freed = FALSE;
551 client->crypto = init_client_crypto();
553 if (!client->crypto) {
554 g_strfreev(req);
555 cleanup_client(client);
556 return send_syserror(ctx, ENOMEM);
559 client->crypto->key = gcry_malloc(gcrykeysize);
561 if (!client->crypto->key) {
562 g_strfreev(req);
563 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
564 gpg_error_from_errno(ENOMEM));
565 cleanup_client(client);
566 return send_syserror(ctx, ENOMEM);
569 memset(client->crypto->key, 0, gcrykeysize);
570 client->crypto->fh = read_file_header(filename, FALSE, &rc);
572 if (!client->crypto->fh) {
573 if (gpg_err_code_to_errno(rc) != ENOENT) {
574 log_write("%s: %s", filename, pwmd_strerror(rc));
575 g_strfreev(req);
576 cleanup_client(client);
577 return send_error(ctx, rc);
581 * New files don't need a key.
583 if ((client->xml = new_document()) == NULL) {
584 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
585 g_strfreev(req);
586 cleanup_client(client);
587 return send_syserror(ctx, ENOMEM);
590 client->len = xmlStrlen(client->xml);
591 client->new = TRUE;
592 client->filename = g_strdup(filename);
594 if (!client->filename) {
595 g_strfreev(req);
596 cleanup_client(client);
597 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
598 return send_syserror(ctx, ENOMEM);
601 if (req[1] && *req[1])
602 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
603 strlen(req[1]));
605 g_strfreev(req);
606 #ifdef WITH_PINENTRY
607 client->pinentry->filename = g_strdup(client->filename);
609 if (!client->pinentry->filename) {
610 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
611 cleanup_client(client);
612 return send_syserror(ctx, ENOMEM);
614 #endif
615 return open_command_finalize(ctx, client->crypto->key, cached);
617 else
618 client->mtime = client->crypto->fh->st.st_mtime;
620 client->filename = g_strdup(filename);
622 if (!client->filename) {
623 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
624 g_strfreev(req);
625 cleanup_client(client);
626 return send_syserror(ctx, ENOMEM);
629 #ifdef WITH_PINENTRY
630 client->pinentry->filename = g_strdup(client->filename);
632 if (!client->pinentry->filename) {
633 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
634 g_strfreev(req);
635 cleanup_client(client);
636 return send_syserror(ctx, ENOMEM);
638 #endif
640 if (client->crypto->fh->fh2.iter <= 0)
641 goto done;
643 #ifdef WITH_GNUTLS
644 if (client->thd->remote == FALSE ||
645 get_key_file_boolean(client->filename, "tcp_require_key") == FALSE)
647 #endif
648 CACHE_LOCK(client->ctx);
649 cached = cache_get_key(client->md5file, client->crypto->key);
650 CACHE_UNLOCK;
651 #ifdef WITH_GNUTLS
653 else
654 cached = FALSE;
655 #endif
657 if (cached == FALSE) {
658 gchar *tmp = get_key_file_string(filename, "key_file");
660 if (tmp) {
661 g_free(tmp);
662 cleanup_client(client);
663 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
667 * No key specified and no matching filename found in the cache. Use
668 * pinentry to retrieve the key. Cannot return assuan_process_done()
669 * here otherwise the command will be interrupted. The event loop in
670 * client_thread() will poll the file descriptor waiting for it to
671 * become ready to read a pinentry_key_s which will contain the
672 * entered key or rc. It will then call open_command_finalize() to
673 * to finish the command.
675 if (!req[1] || !*req[1]) {
676 #ifdef WITH_PINENTRY
677 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
679 /* From set_pinentry_defaults(). */
680 if (client->pinentry->enable == FALSE ||
681 (client->pinentry->enable == -1 && b == FALSE)) {
682 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
683 goto done;
686 g_strfreev(req);
687 rc = lock_pin_mutex(client);
689 if (rc) {
690 unlock_pin_mutex(client->pinentry);
691 cleanup_client(client);
692 return send_error(ctx, rc);
695 client->pinentry->which = PINENTRY_OPEN;
696 rc = pinentry_fork(ctx);
698 if (rc) {
699 unlock_pin_mutex(client->pinentry);
700 cleanup_client(client);
701 return send_error(ctx, rc);
704 client->pinentry->cb = open_command_finalize;
705 client->pinentry->status = PINENTRY_INIT;
706 return 0;
707 #else
708 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
709 goto done;
710 #endif
713 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
714 strlen(req[1]));
717 done:
718 g_strfreev(req);
719 return open_command_finalize(ctx, client->crypto->key, cached);
722 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
723 gulong size, gpointer *out, gulong *outsize, gint *rc)
725 z_stream z;
726 gpointer pout, pin;
727 gz_header h;
728 gchar buf[17];
729 gint cmd = Z_NO_FLUSH;
731 z.zalloc = z_alloc;
732 z.zfree = z_free;
733 z.next_in = pin = data;
734 z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
735 z.avail_out = (uInt)zlib_bufsize;
736 z.next_out = pout = gcry_malloc(zlib_bufsize);
738 if (!pout) {
739 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
740 *rc = Z_MEM_ERROR;
741 return FALSE;
744 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
746 if (*rc != Z_OK) {
747 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
748 gcry_free(pout);
749 return FALSE;
752 /* Rather than store the size of the uncompressed data in the file header,
753 * store it in the comment field of the gzip header. Don't give anyone too
754 * much information. Not sure why really, but it seems the right way. :)
756 memset(&h, 0, sizeof(gz_header));
757 g_snprintf(buf, sizeof(buf), "%li", size);
758 h.comment = (guchar *)buf;
759 *rc = deflateSetHeader(&z, &h);
761 if (*rc != Z_OK) {
762 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
763 gcry_free(pout);
764 deflateEnd(&z);
765 return FALSE;
768 do {
769 gpointer p;
771 *rc = deflate(&z, cmd);
773 switch (*rc) {
774 case Z_OK:
775 break;
776 case Z_BUF_ERROR:
777 if (!z.avail_out) {
778 p = gcry_realloc(pout, z.total_out + zlib_bufsize);
780 if (!p) {
781 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
782 *rc = Z_MEM_ERROR;
783 goto fail;
786 pout = p;
787 z.next_out = pout + z.total_out;
788 z.avail_out = zlib_bufsize;
791 if (!z.avail_in && z.total_in < size) {
792 if (z.total_in + zlib_bufsize > size)
793 z.avail_in = size - z.total_in;
794 else
795 z.avail_in = zlib_bufsize;
797 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li",
798 z.total_in, size);
800 if (*rc)
801 goto fail;
804 if (z.total_in >= size)
805 cmd = Z_FINISH;
807 break;
808 case Z_STREAM_END:
809 break;
810 default:
811 goto fail;
813 } while (*rc != Z_STREAM_END);
815 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li", z.total_in, size);
817 if (*rc)
818 goto fail;
820 *out = pout;
821 *outsize = z.total_out;
822 deflateEnd(&z);
823 *rc = 0;
824 return TRUE;
826 fail:
827 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
828 gcry_free(pout);
829 deflateEnd(&z);
830 return FALSE;
833 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
835 static gpg_error_t iterate_crypto_once(struct client_s *client,
836 struct client_crypto_s *crypto, status_msg_t which)
838 gpg_error_t rc = 0;
839 gsize len = CRYPTO_BLOCKSIZE;
840 gpointer p = gcry_malloc(len);
841 gsize total = 0;
842 gpointer inbuf;
844 if (!p)
845 return gpg_err_code_from_errno(ENOMEM);
847 pthread_cleanup_push(gcry_free, p);
849 if (crypto->insize < CRYPTO_BLOCKSIZE)
850 len = crypto->insize;
852 for (;;) {
853 inbuf = crypto->inbuf + total;
854 guchar *tmp;
856 if (len + total > crypto->insize)
857 len = gcryblocksize;
859 if (which == STATUS_ENCRYPT)
860 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
861 else
862 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
864 if (rc)
865 goto done;
867 tmp = crypto->inbuf+total;
868 memmove(tmp, p, len);
869 total += len;
871 if (total >= crypto->insize)
872 break;
874 pthread_testcancel();
877 done:
878 if (1) {}
879 pthread_cleanup_pop(1);
880 return rc;
883 /* The crypto struct must be setup for iterations and .key. */
884 gpg_error_t do_xml_encrypt(struct client_s *client,
885 struct client_crypto_s *crypto, const gchar *filename)
887 gsize len = crypto->insize;
888 gpointer inbuf;
889 gchar *p;
890 gpg_error_t rc;
891 guint iter_progress = 0, n_iter = 0, xiter = 0;
892 gchar tmp[FILENAME_MAX];
893 struct stat st;
894 mode_t mode = 0;
896 if (!crypto->fh->fh2.iter) {
898 * cache_file_count() needs both .used == TRUE and a valid key in
899 * order for it to count as a used cache entry. Fixes CACHE status
900 * messages.
902 memset(crypto->key, '!', gcrykeysize);
903 goto write_file;
907 * Resize the existing xml buffer to the block size required by gcrypt
908 * rather than duplicating it and wasting memory.
910 if (crypto->insize / gcryblocksize) {
911 len = (crypto->insize / gcryblocksize) * gcryblocksize;
913 if (crypto->insize % gcryblocksize)
914 len += gcryblocksize;
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->fh2.iv, sizeof(crypto->fh->fh2.iv));
927 crypto->tkey = gcry_malloc(gcrykeysize);
929 if (!crypto->tkey) {
930 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
931 return gpg_error_from_errno(ENOMEM);
934 memcpy(crypto->tkey, crypto->key, gcrykeysize);
935 guchar *tkey = crypto->tkey;
936 tkey[0] ^= 1;
938 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
939 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
940 return rc;
943 iter_progress = get_key_file_integer(client ? client->filename : "global",
944 "iteration_progress");
946 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
947 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
948 "%u %u", 0, crypto->fh->fh2.iter);
950 if (rc)
951 return rc;
954 while (xiter < crypto->fh->fh2.iter-1) {
955 if (iter_progress > 0 && xiter >= iter_progress) {
956 if (!(xiter % iter_progress)) {
957 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
958 "%u %u", ++n_iter * iter_progress, crypto->fh->fh2.iter);
960 if (rc)
961 return rc;
965 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
966 sizeof(crypto->fh->fh2.iv)))) {
967 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
968 return rc;
971 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
973 if (rc) {
974 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
975 return rc;
978 xiter++;
981 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
982 sizeof(crypto->fh->fh2.iv)))) {
983 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
984 return rc;
987 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, gcrykeysize))) {
988 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
989 return rc;
992 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
994 if (rc)
995 return rc;
997 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
998 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
999 "%u %u", crypto->fh->fh2.iter, crypto->fh->fh2.iter);
1001 if (rc)
1002 return rc;
1005 write_file:
1006 if (filename) {
1007 if (!client && !strcmp(filename, "-")) {
1008 crypto->fh->fd = STDOUT_FILENO;
1009 goto do_write_file;
1012 if (lstat(filename, &st) == 0) {
1013 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1016 * FIXME What if the file has an ACL?
1018 if (!(mode & S_IWUSR))
1019 return gpg_error_from_errno(EACCES);
1021 else {
1022 if (errno != ENOENT)
1023 return gpg_error_from_errno(errno);
1026 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1027 crypto->fh->fd = mkstemp(tmp);
1029 if (crypto->fh->fd == -1) {
1030 rc = errno;
1031 p = strrchr(tmp, '/');
1032 p++;
1033 log_write("%s: %s", p, strerror(rc));
1034 return gpg_error_from_errno(rc);
1037 else
1039 * xml_import() or convert_file() from command line.
1041 crypto->fh->fd = STDOUT_FILENO;
1043 do_write_file:
1044 crypto->fh->fh2.version = VERSION_HEX;
1045 len = write(crypto->fh->fd, &crypto->fh->fh2, sizeof(crypto->fh->fh2));
1047 if (len != sizeof(crypto->fh->fh2)) {
1048 len = errno;
1050 if (filename && strcmp(filename, "-"))
1051 unlink(tmp);
1053 return gpg_error_from_errno(len);
1056 len = write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1058 if (len != crypto->insize) {
1059 len = errno;
1061 if (filename && strcmp(filename, "-"))
1062 unlink(tmp);
1064 return gpg_error_from_errno(len);
1067 if (fsync(crypto->fh->fd) == -1) {
1068 len = errno;
1070 if (filename && strcmp(filename, "-"))
1071 unlink(tmp);
1073 return gpg_error_from_errno(len);
1076 if (filename && strcmp(filename, "-")) {
1077 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1078 gchar tmp2[FILENAME_MAX];
1080 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1082 if (rename(filename, tmp2) == -1) {
1083 unlink(tmp);
1084 len = errno;
1085 return gpg_error_from_errno(len);
1089 if (rename(tmp, filename) == -1) {
1090 len = errno;
1091 unlink(tmp);
1092 return gpg_error_from_errno(len);
1095 if (mode)
1096 chmod(filename, mode);
1099 if (client && lstat(filename, &st) == 0)
1100 client->mtime = st.st_mtime;
1102 return 0;
1105 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1106 gboolean cached)
1108 struct client_s *client = assuan_get_pointer(ctx);
1109 gpointer xmlbuf;
1110 gulong len, outsize = 0;
1111 guint iter;
1112 gint timeout;
1113 gpointer outbuf;
1114 gint zrc;
1115 gpg_error_t rc;
1117 if (client->crypto->key && client->crypto->key != key)
1118 gcry_free(client->crypto->key);
1120 client->crypto->key = key;
1121 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1122 iter = (guint)get_key_file_integer(client->filename, "compression_level");
1124 if (iter < 0)
1125 iter = 0;
1127 if (do_compress(ctx, (gint)iter, xmlbuf, len, &outbuf, &outsize, &zrc)
1128 == FALSE) {
1129 if (key != client->crypto->key)
1130 gcry_free(key);
1132 xmlFree(xmlbuf);
1133 cleanup_crypto(&client->crypto);
1135 if (zrc == Z_MEM_ERROR)
1136 return send_syserror(ctx, ENOMEM);
1137 else
1138 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1140 else {
1141 gcry_free(xmlbuf);
1142 xmlbuf = outbuf;
1143 len = outsize;
1146 client->crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1148 if (!client->crypto->fh) {
1149 cleanup_crypto(&client->crypto);
1150 gcry_free(outbuf);
1151 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1152 return send_syserror(ctx, ENOMEM);
1155 iter = get_key_file_integer(client->filename, "iterations");
1156 client->crypto->fh->fh2.iter = iter < 0 ? 0 : iter;
1157 client->crypto->inbuf = xmlbuf;
1158 client->crypto->insize = len;
1159 rc = do_xml_encrypt(client, client->crypto, client->filename);
1161 if (rc) {
1162 cleanup_crypto(&client->crypto);
1163 return send_error(ctx, rc);
1166 timeout = get_key_file_integer(client->filename, "cache_timeout");
1167 CACHE_LOCK(client->ctx);
1169 if (cached) {
1170 cache_reset_timeout(client->md5file, timeout);
1171 CACHE_UNLOCK;
1173 if (client->new == TRUE)
1174 send_status_all(STATUS_CACHE);
1176 client->new = FALSE;
1177 cleanup_crypto(&client->crypto);
1178 return send_error(ctx, 0);
1181 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1182 CACHE_UNLOCK;
1183 cleanup_crypto(&client->crypto);
1184 return send_syserror(ctx, ENOMEM);
1187 client->new = FALSE;
1188 cache_reset_timeout(client->md5file, timeout);
1189 CACHE_UNLOCK;
1190 send_status_all(STATUS_CACHE);
1191 cleanup_crypto(&client->crypto);
1192 return send_error(ctx, 0);
1195 static int save_command(assuan_context_t ctx, char *line)
1197 gboolean cached = FALSE;
1198 struct stat st;
1199 struct client_s *client = assuan_get_pointer(ctx);
1200 gpg_error_t rc;
1202 rc = lock_file_mutex(client);
1204 if (rc)
1205 return send_error(ctx, rc);
1207 rc = file_modified(client);
1209 if (rc)
1210 return send_error(ctx, rc);
1212 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1213 return send_syserror(ctx, errno);
1215 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1216 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1217 return send_error(ctx, GPG_ERR_ENOANO);
1220 CACHE_LOCK(ctx);
1221 cached = cache_iscached(client->md5file);
1222 CACHE_UNLOCK;
1225 * If a cache entry doesn't exist for this file and the file has a
1226 * "key_file" or "key" parameter, then it's an error. The reason is that
1227 * cache expiration would be useless.
1229 if (cached == FALSE) {
1230 gchar *tmp = get_key_file_string(client->filename, "key_file");
1232 if (tmp) {
1233 g_free(tmp);
1234 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1238 cached = FALSE;
1239 client->crypto = init_client_crypto();
1241 if (!client->crypto) {
1242 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1243 return send_syserror(ctx, ENOMEM);
1246 client->crypto->key = gcry_malloc(gcrykeysize);
1248 if (!client->crypto->key) {
1249 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1250 cleanup_crypto(&client->crypto);
1251 return send_syserror(ctx, ENOMEM);
1254 memset(client->crypto->key, '!', gcrykeysize);
1256 if (get_key_file_integer(client->filename, "iterations") <= 0)
1257 goto done;
1259 if (!line || !*line) {
1260 client->crypto->tkey = gcry_malloc(gcrykeysize);
1262 if (!client->crypto->tkey) {
1263 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1264 cleanup_crypto(&client->crypto);
1265 return send_syserror(ctx, ENOMEM);
1268 memset(client->crypto->tkey, '!', gcrykeysize);
1269 CACHE_LOCK(ctx);
1271 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1272 memcmp(client->crypto->key, client->crypto->tkey,
1273 gcrykeysize) == 0) {
1274 CACHE_UNLOCK;
1276 #ifdef WITH_PINENTRY
1277 if (client->pinentry->enable == FALSE ||
1278 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1279 /* Empty keys are allowed. */
1280 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1281 goto done;
1284 lock_pin_mutex(client);
1285 client->pinentry->which = PINENTRY_SAVE;
1286 rc = pinentry_fork(ctx);
1288 if (rc) {
1289 unlock_pin_mutex(client->pinentry);
1290 return send_error(ctx, rc);
1293 client->pinentry->cb = save_command_finalize;
1294 client->pinentry->status = PINENTRY_INIT;
1295 return 0;
1296 #else
1297 /* Empty keys are allowed. */
1298 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1299 goto done;
1300 #endif
1302 else {
1303 CACHE_UNLOCK;
1304 cached = TRUE;
1307 else {
1308 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1309 strlen(line));
1310 memset(line, 0, strlen(line));
1313 done:
1314 return save_command_finalize(ctx, client->crypto->key, cached);
1317 static int delete_command(assuan_context_t ctx, char *line)
1319 struct client_s *client = assuan_get_pointer(ctx);
1320 gchar **req;
1321 gpg_error_t rc;
1322 xmlNodePtr n;
1324 rc = file_modified(client);
1326 if (rc)
1327 return send_error(ctx, rc);
1329 if (strchr(line, '\t'))
1330 req = split_input_line(line, "\t", -1);
1331 else
1332 req = split_input_line(line, " ", -1);
1334 if (!req || !*req)
1335 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1337 n = find_account(client->doc, &req, &rc, NULL, 0);
1339 if (!n) {
1340 g_strfreev(req);
1341 return send_error(ctx, rc);
1345 * No sub-node defined. Remove the entire node (account).
1347 if (!req[1]) {
1348 if (n) {
1349 xmlUnlinkNode(n);
1350 xmlFreeNode(n);
1353 g_strfreev(req);
1354 return send_error(ctx, 0);
1357 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1358 g_strfreev(req);
1360 if (!n)
1361 return send_error(ctx, rc);
1363 if (n) {
1364 xmlUnlinkNode(n);
1365 xmlFreeNode(n);
1368 return send_error(ctx, 0);
1372 * Don't return with assuan_process_done() here. This has been called from
1373 * assuan_process_next() and the command should be finished in
1374 * client_thread().
1376 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1377 gsize len)
1379 assuan_context_t ctx = data;
1380 struct client_s *client = assuan_get_pointer(ctx);
1381 gchar **req;
1382 xmlNodePtr n;
1383 gpg_error_t rc = file_modified(client);
1385 if (assuan_rc || rc) {
1386 if (line)
1387 xfree(line);
1388 return assuan_rc ? assuan_rc : rc;
1391 req = split_input_line((gchar *)line, "\t", 0);
1392 xfree(line);
1394 if (!req || !*req)
1395 return EPWMD_COMMAND_SYNTAX;
1397 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1398 g_strfreev(req);
1399 return EPWMD_INVALID_ELEMENT;
1402 if (valid_element_path(req+1, TRUE) == FALSE) {
1403 g_strfreev(req);
1404 return EPWMD_INVALID_ELEMENT;
1407 again:
1408 n = find_account(client->doc, &req, &rc, NULL, 0);
1410 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1411 rc = new_account(client->doc, *req);
1413 if (rc) {
1414 g_strfreev(req);
1415 return rc;
1418 goto again;
1421 if (!n) {
1422 g_strfreev(req);
1423 return rc;
1426 if (req[1]) {
1427 if (!n->children)
1428 create_elements_cb(n, req+1, &rc, NULL);
1429 else
1430 find_elements(client->doc, n->children, req+1, &rc,
1431 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1434 g_strfreev(req);
1435 client->inquire_status = INQUIRE_DONE;
1436 return rc;
1439 static int store_command(assuan_context_t ctx, char *line)
1441 struct client_s *client = assuan_get_pointer(ctx);
1442 gpg_error_t rc = file_modified(client);
1444 if (rc)
1445 return send_error(ctx, rc);
1447 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1449 if (rc)
1450 return send_error(ctx, rc);
1452 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1453 client->inquire_status = INQUIRE_BUSY;
1454 return 0;
1457 static int get_command(assuan_context_t ctx, char *line)
1459 struct client_s *client = assuan_get_pointer(ctx);
1460 gchar **req;
1461 gpg_error_t rc;
1462 xmlNodePtr n;
1464 rc = file_modified(client);
1466 if (rc)
1467 return send_error(ctx, rc);
1469 req = split_input_line(line, "\t", -1);
1471 if (!req || !*req) {
1472 g_strfreev(req);
1473 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1476 n = find_account(client->doc, &req, &rc, NULL, 0);
1478 if (!n) {
1479 g_strfreev(req);
1480 return send_error(ctx, rc);
1483 if (req[1])
1484 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1486 g_strfreev(req);
1488 if (rc)
1489 return send_error(ctx, rc);
1491 if (!n || !n->children)
1492 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1494 n = find_text_node(n->children);
1496 if (!n || !n->content || !*n->content)
1497 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1499 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1500 return send_error(ctx, rc);
1503 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1504 gpg_error_t *rc, gchar **req_orig, void *data)
1506 gchar *path = *(gchar **)data;
1507 gchar *tmp = NULL, *result;
1509 if (path) {
1510 g_free(path);
1511 *(gchar **)data = NULL;
1514 path = g_strjoinv("\t", target);
1516 if (!path) {
1517 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1518 *rc = gpg_error_from_errno(ENOMEM);
1519 return NULL;
1522 if (req_orig) {
1523 tmp = g_strjoinv("\t", req_orig);
1525 if (!tmp) {
1526 g_free(path);
1527 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1528 *rc = gpg_error_from_errno(ENOMEM);
1529 return NULL;
1533 if (tmp && *tmp)
1534 result = g_strdup_printf("%s\t%s", path, tmp);
1535 else
1536 result = g_strdup(path);
1538 if (!result) {
1539 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1540 *rc = gpg_error_from_errno(ENOMEM);
1541 g_free(path);
1542 g_free(tmp);
1543 return NULL;
1546 g_free(path);
1547 g_free(tmp);
1548 *(gchar **)data = result;
1549 return node;
1552 static int realpath_command(assuan_context_t ctx, char *line)
1554 gpg_error_t rc;
1555 struct client_s *client = assuan_get_pointer(ctx);
1556 gchar **req;
1557 gchar *t;
1558 gint i;
1559 xmlNodePtr n;
1560 GString *string;
1561 gchar *rp = NULL;
1563 rc = file_modified(client);
1565 if (rc)
1566 return send_error(ctx, rc);
1568 if (strchr(line, '\t') != NULL) {
1569 if ((req = split_input_line(line, "\t", 0)) == NULL)
1570 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1572 else {
1573 if ((req = split_input_line(line, " ", 0)) == NULL)
1574 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1577 n = find_account(client->doc, &req, &rc, NULL, 0);
1579 if (!n) {
1580 g_strfreev(req);
1581 return send_error(ctx, rc);
1584 rp = g_strjoinv("\t", req);
1586 if (!rp) {
1587 g_strfreev(req);
1588 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1589 return send_syserror(ctx, ENOMEM);
1592 if (req[1]) {
1593 n = find_elements(client->doc, n->children, req+1, &rc,
1594 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1596 if (!n) {
1597 g_free(rp);
1598 g_strfreev(req);
1599 return send_error(ctx, rc);
1603 string = g_string_new(rp);
1604 g_free(rp);
1605 g_strfreev(req);
1607 if (!string) {
1608 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1609 return send_syserror(ctx, ENOMEM);
1612 again:
1613 for (i = 0, t = string->str + i; *t; t++, i++) {
1614 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1615 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1616 goto again;
1620 rc = assuan_send_data(ctx, string->str, string->len);
1621 g_string_free(string, TRUE);
1622 return send_error(ctx, rc);
1625 static int list_command(assuan_context_t ctx, char *line)
1627 struct client_s *client = assuan_get_pointer(ctx);
1628 gpg_error_t rc;
1629 struct element_list_s *elements = NULL;
1630 gchar *tmp;
1632 if (disable_list_and_dump == TRUE)
1633 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1635 rc = file_modified(client);
1637 if (rc)
1638 return send_error(ctx, rc);
1640 if (!*line) {
1641 GString *str;
1643 rc = list_accounts(client->doc, &str);
1645 if (rc)
1646 return send_error(ctx, rc);
1648 rc = assuan_send_data(ctx, str->str, str->len);
1649 g_string_free(str, TRUE);
1650 return send_error(ctx, rc);
1653 elements = g_malloc0(sizeof(struct element_list_s));
1655 if (!elements) {
1656 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1657 rc = gpg_err_code_from_errno(ENOMEM);
1658 goto fail;
1661 rc = create_path_list(client->doc, elements, line);
1663 if (rc)
1664 goto fail;
1666 if (elements) {
1667 gint total = g_slist_length(elements->list);
1668 gint i;
1669 GString *str;
1671 if (!total) {
1672 rc = EPWMD_EMPTY_ELEMENT;
1673 goto fail;
1676 str = g_string_new(NULL);
1678 if (!str) {
1679 rc = gpg_err_code_from_errno(ENOMEM);
1680 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1681 goto fail;
1684 for (i = 0; i < total; i++) {
1685 tmp = g_slist_nth_data(elements->list, i);
1686 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1689 rc = assuan_send_data(ctx, str->str, str->len);
1690 g_string_free(str, TRUE);
1692 else
1693 rc = EPWMD_EMPTY_ELEMENT;
1695 fail:
1696 if (elements) {
1697 gint total = g_slist_length(elements->list);
1698 gint i;
1700 for (i = 0; i < total; i++) {
1701 tmp = g_slist_nth_data(elements->list, i);
1702 g_free(tmp);
1705 g_slist_free(elements->list);
1707 if (elements->prefix)
1708 g_free(elements->prefix);
1710 g_free(elements);
1713 return send_error(ctx, rc);
1716 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1717 const gchar *value)
1719 xmlAttrPtr a;
1721 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1722 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1724 if (!a)
1725 return EPWMD_LIBXML_ERROR;
1727 else
1728 xmlNodeSetContent(a->children, (xmlChar *)value);
1730 return 0;
1734 * req[0] - element path
1736 static int attribute_list(assuan_context_t ctx, gchar **req)
1738 struct client_s *client = assuan_get_pointer(ctx);
1739 gchar **attrlist = NULL;
1740 gint i = 0;
1741 gchar **path = NULL;
1742 xmlAttrPtr a;
1743 xmlNodePtr n, an;
1744 gchar *line;
1745 gpg_error_t rc;
1747 if (!req || !req[0])
1748 return EPWMD_COMMAND_SYNTAX;
1750 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1752 * The first argument may be only an account.
1754 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1755 return EPWMD_COMMAND_SYNTAX;
1758 n = find_account(client->doc, &path, &rc, NULL, 0);
1760 if (!n) {
1761 g_strfreev(path);
1762 return rc;
1765 if (path[1]) {
1766 n = find_elements(client->doc, n->children, path+1, &rc,
1767 NULL, NULL, NULL, FALSE, 0, NULL);
1769 if (!n) {
1770 g_strfreev(path);
1771 return rc;
1775 g_strfreev(path);
1777 for (a = n->properties; a; a = a->next) {
1778 gchar **pa;
1780 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1781 if (attrlist)
1782 g_strfreev(attrlist);
1784 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1785 return gpg_error_from_errno(ENOMEM);
1788 attrlist = pa;
1789 an = a->children;
1790 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name, (gchar *)an->content);
1792 if (!attrlist[i]) {
1793 g_strfreev(attrlist);
1794 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1795 return gpg_error_from_errno(ENOMEM);
1798 attrlist[++i] = NULL;
1801 if (!attrlist)
1802 return EPWMD_EMPTY_ELEMENT;
1804 line = g_strjoinv("\n", attrlist);
1806 if (!line) {
1807 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1808 g_strfreev(attrlist);
1809 return gpg_error_from_errno(ENOMEM);
1812 rc = assuan_send_data(ctx, line, strlen(line));
1813 g_free(line);
1814 g_strfreev(attrlist);
1815 return rc;
1819 * req[0] - attribute
1820 * req[1] - element path
1822 static int attribute_delete(struct client_s *client, gchar **req)
1824 xmlAttrPtr a;
1825 xmlNodePtr n;
1826 gchar **path = NULL;
1827 gpg_error_t rc;
1829 if (!req || !req[0] || !req[1])
1830 return EPWMD_COMMAND_SYNTAX;
1832 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1834 * The first argument may be only an account.
1836 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1837 return EPWMD_COMMAND_SYNTAX;
1841 * Don't remove the "name" attribute for the account element. To remove an
1842 * account use DELETE <account>.
1844 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1845 rc = EPWMD_ATTR_SYNTAX;
1846 goto fail;
1849 n = find_account(client->doc, &path, &rc, NULL, 0);
1851 if (!n)
1852 goto fail;
1854 if (path[1]) {
1855 n = find_elements(client->doc, n->children, path+1, &rc,
1856 NULL, NULL, NULL, FALSE, 0, NULL);
1858 if (!n)
1859 goto fail;
1862 g_strfreev(path);
1864 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1865 return EPWMD_ATTR_NOT_FOUND;
1867 if (xmlRemoveProp(a) == -1)
1868 return EPWMD_LIBXML_ERROR;
1870 return 0;
1872 fail:
1873 g_strfreev(path);
1874 return rc;
1877 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1878 gpg_error_t *rc)
1880 gchar **src = *path;
1881 gchar **src_orig = g_strdupv(src);
1882 xmlNodePtr n = NULL;
1884 *rc = 0;
1886 if (!src_orig) {
1887 *rc = gpg_error_from_errno(ENOMEM);
1888 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1889 goto fail;
1892 again:
1893 n = find_account(client->doc, &src, rc, NULL, 0);
1895 if (!n) {
1896 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1897 *rc = new_account(client->doc, src[0]);
1899 if (*rc)
1900 goto fail;
1902 goto again;
1904 else
1905 goto fail;
1908 if (src[1]) {
1909 if (!n->children)
1910 n = create_target_elements_cb(n, src+1, rc, NULL);
1911 else
1912 n = find_elements(client->doc, n->children, src+1, rc,
1913 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1915 if (!n)
1916 goto fail;
1919 * Reset the position of the element tree now that the elements
1920 * have been created.
1922 g_strfreev(src);
1923 src = src_orig;
1924 src_orig = NULL;
1925 n = find_account(client->doc, &src, rc, NULL, 0);
1927 if (!n)
1928 goto fail;
1930 n = find_elements(client->doc, n->children, src+1, rc,
1931 NULL, NULL, NULL, FALSE, 0, NULL);
1933 if (!n)
1934 goto fail;
1937 fail:
1938 if (src_orig)
1939 g_strfreev(src_orig);
1941 *path = src;
1942 return n;
1946 * Creates a "target" attribute. When other commands encounter an element with
1947 * this attribute, the element path is modified to the target value. If the
1948 * source element path doesn't exist when using 'ATTR SET target', it is
1949 * created, but the destination element path must exist.
1951 * req[0] - source element path
1952 * req[1] - destination element path
1954 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1956 gchar **src, **dst, *line = NULL;
1957 gpg_error_t rc;
1958 xmlNodePtr n;
1960 if (!req || !req[0] || !req[1])
1961 return EPWMD_COMMAND_SYNTAX;
1963 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1965 * The first argument may be only an account.
1967 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1968 return EPWMD_COMMAND_SYNTAX;
1971 if (valid_element_path(src, FALSE) == FALSE) {
1972 g_strfreev(src);
1973 return EPWMD_INVALID_ELEMENT;
1976 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1978 * The first argument may be only an account.
1980 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1981 rc = EPWMD_COMMAND_SYNTAX;
1982 goto fail;
1986 n = find_account(client->doc, &dst, &rc, NULL, 0);
1989 * Make sure the destination element path exists.
1991 if (!n)
1992 goto fail;
1994 if (dst[1]) {
1995 n = find_elements(client->doc, n->children, dst+1, &rc,
1996 NULL, NULL, NULL, FALSE, 0, NULL);
1998 if (!n)
1999 goto fail;
2002 n = create_element_path(client, &src, &rc);
2004 if (rc)
2005 goto fail;
2007 line = g_strjoinv("\t", dst);
2009 if (!line) {
2010 rc = gpg_error_from_errno(ENOMEM);
2011 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2012 goto fail;
2015 rc = add_attribute(n, "target", line);
2017 fail:
2018 g_free(line);
2019 g_strfreev(src);
2020 g_strfreev(dst);
2021 return rc;
2025 * req[0] - account name
2026 * req[1] - new name
2028 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2030 gpg_error_t rc;
2031 gchar **tmp;
2032 xmlNodePtr n;
2034 tmp = g_strdupv(req);
2036 if (!tmp) {
2037 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2038 return gpg_error_from_errno(ENOMEM);
2041 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2042 g_strfreev(tmp);
2044 if (!n)
2045 return rc;
2047 if (g_utf8_collate(req[0], req[1]) == 0)
2048 return 0;
2051 * Will not overwrite an existing account.
2053 tmp = g_strdupv(req+1);
2055 if (!tmp) {
2056 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2057 return gpg_error_from_errno(ENOMEM);
2060 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2061 g_strfreev(tmp);
2063 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
2064 return rc;
2066 if (n)
2067 return EPWMD_ACCOUNT_EXISTS;
2070 * Whitespace not allowed in account names.
2072 if (contains_whitespace(req[1]) == TRUE)
2073 return EPWMD_ATTR_SYNTAX;
2075 tmp = g_strdupv(req);
2077 if (!tmp) {
2078 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2079 return gpg_error_from_errno(ENOMEM);
2082 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2083 g_strfreev(tmp);
2085 if (!n)
2086 return EPWMD_ELEMENT_NOT_FOUND;
2088 return add_attribute(n, "name", req[1]);
2092 * req[0] - attribute
2093 * req[1] - element path
2095 static int attribute_get(assuan_context_t ctx, gchar **req)
2097 struct client_s *client = assuan_get_pointer(ctx);
2098 xmlNodePtr n;
2099 xmlChar *a;
2100 gchar **path= NULL;
2101 gpg_error_t rc;
2103 if (!req || !req[0] || !req[1])
2104 return EPWMD_COMMAND_SYNTAX;
2106 if (strchr(req[1], '\t')) {
2107 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2108 return EPWMD_COMMAND_SYNTAX;
2110 else {
2111 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2112 return EPWMD_COMMAND_SYNTAX;
2115 n = find_account(client->doc, &path, &rc, NULL, 0);
2117 if (!n)
2118 goto fail;
2120 if (path[1]) {
2121 n = find_elements(client->doc, n->children, path+1, &rc,
2122 NULL, NULL, NULL, FALSE, 0, NULL);
2124 if (!n)
2125 goto fail;
2128 g_strfreev(path);
2130 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2131 return EPWMD_ATTR_NOT_FOUND;
2133 rc = assuan_send_data(ctx, a, xmlStrlen(a));
2134 xmlFree(a);
2135 return rc;
2137 fail:
2138 g_strfreev(path);
2139 return rc;
2143 * req[0] - attribute
2144 * req[1] - element path
2145 * req[2] - value
2147 static int attribute_set(struct client_s *client, gchar **req)
2149 gchar **path = NULL;
2150 gpg_error_t rc;
2151 xmlNodePtr n;
2153 if (!req || !req[0] || !req[1] || !req[2])
2154 return EPWMD_COMMAND_SYNTAX;
2157 * Reserved attribute names.
2159 if (g_utf8_collate(req[0], "name") == 0) {
2161 * Only reserved for the account element. Not the rest of the
2162 * document.
2164 if (strchr(req[1], '\t') == NULL)
2165 return name_attribute(client, req + 1);
2167 else if (g_utf8_collate(req[0], "target") == 0)
2168 return target_attribute(client, req + 1);
2170 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2172 * The first argument may be only an account.
2174 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2175 return EPWMD_COMMAND_SYNTAX;
2178 n = find_account(client->doc, &path, &rc, NULL, 0);
2180 if (!n)
2181 goto fail;
2183 if (path[1]) {
2184 n = find_elements(client->doc, n->children, path+1, &rc,
2185 NULL, NULL, NULL, FALSE, 0, NULL);
2187 if (!n)
2188 goto fail;
2191 g_strfreev(path);
2192 return add_attribute(n, req[0], req[2]);
2194 fail:
2195 g_strfreev(path);
2196 return rc;
2200 * req[0] - command
2201 * req[1] - attribute name or element path if command is LIST
2202 * req[2] - element path
2203 * req[2] - element path or value
2205 static int attr_command(assuan_context_t ctx, char *line)
2207 struct client_s *client = assuan_get_pointer(ctx);
2208 gchar **req;
2209 gpg_error_t rc = 0;
2211 rc = file_modified(client);
2213 if (rc)
2214 return send_error(ctx, rc);
2216 req = split_input_line(line, " ", 4);
2218 if (!req || !req[0] || !req[1]) {
2219 g_strfreev(req);
2220 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2223 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2224 rc = attribute_set(client, req+1);
2225 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2226 rc = attribute_get(ctx, req+1);
2227 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2228 rc = attribute_delete(client, req+1);
2229 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2230 rc = attribute_list(ctx, req+1);
2231 else
2232 rc = EPWMD_COMMAND_SYNTAX;
2234 g_strfreev(req);
2235 return send_error(ctx, rc);
2238 static int iscached_command(assuan_context_t ctx, char *line)
2240 gchar **req = split_input_line(line, " ", 0);
2241 guchar md5file[16];
2243 if (!req || !*req) {
2244 g_strfreev(req);
2245 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2248 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2249 g_strfreev(req);
2250 CACHE_LOCK(ctx);
2252 if (cache_iscached(md5file) == FALSE) {
2253 CACHE_UNLOCK;
2254 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2257 CACHE_UNLOCK;
2258 return send_error(ctx, 0);
2261 static int clearcache_command(assuan_context_t ctx, char *line)
2263 struct client_s *client = assuan_get_pointer(ctx);
2264 gchar **req = split_input_line(line, " ", 0);
2265 guchar md5file[16];
2267 CACHE_LOCK(ctx);
2269 if (!req || !*req) {
2270 g_strfreev(req);
2271 cache_clear(client->md5file, 2);
2272 CACHE_UNLOCK;
2273 return send_error(ctx, 0);
2276 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2277 g_strfreev(req);
2279 if (cache_clear(md5file, 1) == FALSE) {
2280 CACHE_UNLOCK;
2281 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2284 CACHE_UNLOCK;
2285 return send_error(ctx, 0);
2288 static int cachetimeout_command(assuan_context_t ctx, char *line)
2290 guchar md5file[16];
2291 glong timeout;
2292 gchar **req = split_input_line(line, " ", 0);
2293 gchar *p;
2294 struct client_s *client = assuan_get_pointer(ctx);
2296 if (!req || !*req || !req[1]) {
2297 g_strfreev(req);
2298 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2301 errno = 0;
2302 timeout = strtol(req[0], &p, 10);
2304 if (errno != 0 || *p != 0) {
2305 g_strfreev(req);
2306 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2309 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2310 g_strfreev(req);
2311 CACHE_LOCK(client->ctx);
2313 if (cache_set_timeout(md5file, timeout) == FALSE) {
2314 CACHE_UNLOCK;
2315 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2318 CACHE_UNLOCK;
2319 return send_error(ctx, 0);
2322 static int dump_command(assuan_context_t ctx, char *line)
2324 xmlChar *xml;
2325 gssize len;
2326 struct client_s *client = assuan_get_pointer(ctx);
2327 gpg_error_t rc;
2329 if (disable_list_and_dump == TRUE)
2330 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2332 rc = file_modified(client);
2334 if (rc)
2335 return send_error(ctx, rc);
2337 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2339 if (!xml) {
2340 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2341 return send_syserror(ctx, ENOMEM);
2344 rc = assuan_send_data(ctx, xml, len);
2345 xmlFree(xml);
2346 return send_error(ctx, rc);
2349 static int getconfig_command(assuan_context_t ctx, gchar *line)
2351 struct client_s *client = assuan_get_pointer(ctx);
2352 gpg_error_t rc = 0;
2353 gchar filename[255]={0}, param[747]={0};
2354 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2356 if (strchr(line, ' ')) {
2357 sscanf(line, " %254[^ ] %746c", filename, param);
2358 fp = filename;
2359 paramp = param;
2362 if (fp && !valid_filename(fp))
2363 return send_error(ctx, EPWMD_INVALID_FILENAME);
2365 paramp = g_ascii_strdown(paramp, -1);
2367 if (!paramp) {
2368 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2369 return send_syserror(ctx, ENOMEM);
2372 p = get_key_file_string(fp ? fp : "global", paramp);
2373 g_free(paramp);
2375 if (!p)
2376 return send_error(ctx, GPG_ERR_NO_VALUE);
2378 tmp = expand_homedir(p);
2379 g_free(p);
2381 if (!tmp) {
2382 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2383 return send_syserror(ctx, ENOMEM);
2386 p = tmp;
2387 rc = assuan_send_data(ctx, p, strlen(p));
2388 g_free(p);
2389 return send_error(ctx, rc);
2392 static int xpath_command(assuan_context_t ctx, gchar *line)
2394 struct client_s *client = assuan_get_pointer(ctx);
2395 gpg_error_t rc;
2396 xmlXPathContextPtr xp;
2397 xmlXPathObjectPtr result;
2398 xmlBufferPtr buf = NULL;
2399 gchar **req = NULL;
2401 if (disable_list_and_dump == TRUE)
2402 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2404 rc = file_modified(client);
2406 if (rc)
2407 return send_error(ctx, rc);
2409 if (!line || !*line)
2410 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2412 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2413 if (strv_printf(&req, "%s", line) == FALSE)
2414 return send_syserror(ctx, ENOMEM);
2417 xp = xmlXPathNewContext(client->doc);
2419 if (!xp)
2420 return send_error(ctx, EPWMD_LIBXML_ERROR);
2422 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2424 if (!result) {
2425 xmlXPathFreeContext(xp);
2426 return send_error(ctx, EPWMD_LIBXML_ERROR);
2429 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2430 rc = EPWMD_EMPTY_ELEMENT;
2431 goto fail;
2434 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2435 (xmlChar *)req[1], &buf);
2437 if (rc)
2438 goto fail;
2439 else if (!req[1] && !xmlBufferLength(buf)) {
2440 rc = EPWMD_EMPTY_ELEMENT;
2441 goto fail;
2443 else if (req[1])
2444 goto fail;
2446 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2448 fail:
2449 g_strfreev(req);
2451 if (buf)
2452 xmlBufferFree(buf);
2454 if (result)
2455 xmlXPathFreeObject(result);
2457 if (xp)
2458 xmlXPathFreeContext(xp);
2460 return send_error(ctx, rc);
2463 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2464 gsize len)
2466 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2467 gpg_error_t rc = file_modified(client);
2468 gchar **req, **path = NULL, **path_orig = NULL, *content;
2469 xmlDocPtr doc;
2470 xmlNodePtr n, root, copy;
2472 if (assuan_rc || rc) {
2473 if (line)
2474 xfree(line);
2475 return assuan_rc ? assuan_rc : rc;
2478 req = split_input_line((gchar *)line, " ", 2);
2479 xfree(line);
2481 if (!req || !*req)
2482 return EPWMD_COMMAND_SYNTAX;
2484 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2485 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2486 return EPWMD_COMMAND_SYNTAX;
2489 content = req[1];
2491 if (!content || !*content) {
2492 rc = EPWMD_COMMAND_SYNTAX;
2493 goto fail;
2496 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2497 rc = EPWMD_INVALID_ELEMENT;
2498 goto fail;
2501 if (valid_element_path(path+1, FALSE) == FALSE) {
2502 rc = EPWMD_INVALID_ELEMENT;
2503 goto fail;
2506 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2508 if (!doc) {
2509 rc = EPWMD_LIBXML_ERROR;
2510 goto fail;
2513 root = xmlDocGetRootElement(doc);
2514 path_orig = g_strdupv(path);
2516 if (!path_orig) {
2517 xmlFreeDoc(doc);
2518 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2519 rc = gpg_error_from_errno(ENOMEM);
2520 goto fail;
2523 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2524 g_strfreev(path_orig);
2525 xmlFreeDoc(doc);
2526 rc = gpg_error_from_errno(ENOMEM);
2527 goto fail;
2530 n = find_account(client->doc, &path, &rc, NULL, 0);
2532 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2533 g_strfreev(path_orig);
2534 xmlFreeDoc(doc);
2535 goto fail;
2537 else if (!rc) {
2538 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2540 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2541 g_strfreev(path_orig);
2542 xmlFreeDoc(doc);
2543 goto fail;
2545 else if (!rc) {
2546 xmlNodePtr parent = n->parent;
2548 xmlUnlinkNode(n);
2549 xmlFreeNode(n);
2550 n = parent;
2554 g_strfreev(path);
2555 path = path_orig;
2557 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2558 n = create_element_path(client, &path, &rc);
2560 if (rc) {
2561 xmlFreeDoc(doc);
2562 goto fail;
2566 copy = xmlCopyNode(root, 1);
2567 n = xmlAddChild(n, copy);
2568 xmlFreeDoc(doc);
2570 if (!n)
2571 rc = EPWMD_LIBXML_ERROR;
2573 fail:
2574 g_strfreev(path);
2575 g_strfreev(req);
2576 client->inquire_status = INQUIRE_DONE;
2577 return rc;
2580 static int import_command(assuan_context_t ctx, gchar *line)
2582 gpg_error_t rc;
2583 struct client_s *client = assuan_get_pointer(ctx);
2585 rc = file_modified(client);
2587 if (rc)
2588 return send_error(ctx, rc);
2590 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2592 if (rc)
2593 return send_error(ctx, rc);
2595 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2596 client->inquire_status = INQUIRE_BUSY;
2597 return 0;
2600 static int lock_command(assuan_context_t ctx, gchar *line)
2602 gpg_error_t rc;
2603 struct client_s *client = assuan_get_pointer(ctx);
2605 rc = file_modified(client);
2607 if (rc)
2608 return send_error(ctx, rc);
2610 rc = lock_file_mutex(client);
2612 if (!rc)
2613 client->is_lock_cmd = TRUE;
2615 return send_error(ctx, rc);
2618 static int unlock_command(assuan_context_t ctx, gchar *line)
2620 struct client_s *client = assuan_get_pointer(ctx);
2621 gpg_error_t rc = file_modified(client);
2623 if (rc)
2624 return send_error(ctx, rc);
2626 unlock_file_mutex(client);
2627 return send_error(ctx, 0);
2630 static int getpid_command(assuan_context_t ctx, gchar *line)
2632 gpg_error_t rc;
2633 gchar buf[32];
2634 pid_t pid = getpid();
2636 print_fmt(buf, sizeof(buf), "%i", pid);
2637 rc = assuan_send_data(ctx, buf, strlen(buf));
2638 return send_error(ctx, rc);
2641 static int version_command(assuan_context_t ctx, gchar *line)
2643 gpg_error_t rc;
2644 gchar buf[32];
2646 print_fmt(buf, sizeof(buf), "%s", PACKAGE_VERSION);
2647 rc = assuan_send_data(ctx, buf, strlen(buf));
2648 return send_error(ctx, rc);
2651 static void bye_notify(assuan_context_t ctx)
2653 struct client_s *cl = assuan_get_pointer(ctx);
2654 #ifdef WITH_GNUTLS
2655 gint rc;
2657 if (!cl->thd->remote)
2658 return;
2660 do {
2661 rc = gnutls_bye(cl->thd->tls->ses, GNUTLS_SHUT_RDWR);
2662 } while (rc == GNUTLS_E_AGAIN);
2663 #endif
2665 /* This will let assuan_process_next() return. */
2666 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
2669 static void reset_notify(assuan_context_t ctx)
2671 struct client_s *cl = assuan_get_pointer(ctx);
2673 if (cl)
2674 cleanup_client(cl);
2677 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2679 gchar name[32] = {0}, value[256] = {0};
2681 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2682 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2684 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2685 struct client_s *cl = assuan_get_pointer(ctx);
2687 if (cl->thd->name)
2688 g_free(cl->thd->name);
2690 cl->thd->name = g_strdup(value);
2691 log_write("OPTION CLIENT %s", line);
2693 else
2694 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2696 return 0;
2699 static int option_handler(assuan_context_t ctx, const gchar *name,
2700 const gchar *value)
2702 struct client_s *client = assuan_get_pointer(ctx);
2704 if (!value || !*value)
2705 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2707 if (g_strcasecmp(name, (gchar *)"client") == 0)
2708 return parse_client_option(ctx, value);
2710 if (g_strcasecmp(name, (gchar *)"iterations") == 0) {
2711 long n;
2712 gchar *p = NULL;
2714 errno = 0;
2715 n = strtol(value, &p, 10);
2717 if (errno || (p && *p) || n < 0)
2718 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2720 g_key_file_set_integer(keyfileh, client->filename ? client->filename : "global", "iterations", (guint)n);
2721 send_status_all(STATUS_CONFIG);
2723 #ifdef WITH_PINENTRY
2724 else if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2725 g_free(client->pinentry->ttyname);
2726 client->pinentry->ttyname = g_strdup(value);
2728 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2729 g_free(client->pinentry->ttytype);
2730 client->pinentry->ttytype = g_strdup(value);
2732 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2733 g_free(client->pinentry->display);
2734 client->pinentry->display = g_strdup(value);
2736 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2737 g_free(client->pinentry->path);
2738 client->pinentry->path = g_strdup(value);
2740 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2741 g_free(client->pinentry->title);
2742 client->pinentry->title = g_strdup(value);
2744 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2745 g_free(client->pinentry->prompt);
2746 client->pinentry->prompt = g_strdup(value);
2748 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2749 g_free(client->pinentry->desc);
2750 client->pinentry->desc = g_strdup(value);
2753 * Look at client_thread() to see how this works.
2755 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2756 gchar *p = NULL;
2757 gint n = strtol(value, &p, 10);
2759 if (*p || n < 0)
2760 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2762 client->pinentry->timeout = n;
2764 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2765 gchar *p = NULL;
2766 gint n = strtol(value, &p, 10);
2768 if (*p || n < 0 || n > 1)
2769 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2771 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2773 #endif
2774 else
2775 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2777 log_write("OPTION %s=%s", name, value);
2778 return 0;
2781 gpg_error_t register_commands(assuan_context_t ctx)
2783 static struct {
2784 const gchar *name;
2785 gint (*handler)(assuan_context_t, gchar *line);
2786 } table[] = {
2787 { "OPEN", open_command },
2788 { "SAVE", save_command },
2789 { "LIST", list_command },
2790 { "REALPATH", realpath_command },
2791 { "STORE", store_command },
2792 { "DELETE", delete_command },
2793 { "GET", get_command },
2794 { "ATTR", attr_command },
2795 { "ISCACHED", iscached_command },
2796 { "CLEARCACHE", clearcache_command },
2797 { "CACHETIMEOUT", cachetimeout_command },
2798 { "GETCONFIG", getconfig_command },
2799 { "DUMP", dump_command },
2800 { "XPATH", xpath_command },
2801 { "IMPORT", import_command },
2802 { "LOCK", lock_command },
2803 { "UNLOCK", unlock_command },
2804 { "GETPID", getpid_command },
2805 { "VERSION", version_command },
2806 { "INPUT", NULL },
2807 { "OUTPUT", NULL },
2808 { NULL, NULL }
2810 gint i, rc;
2812 for (i=0; table[i].name; i++) {
2813 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2815 if (rc)
2816 return rc;
2819 rc = assuan_register_bye_notify(ctx, bye_notify);
2821 if (rc)
2822 return rc;
2824 rc = assuan_register_option_handler(ctx, option_handler);
2826 if (rc)
2827 return rc;
2829 rc = assuan_register_reset_notify(ctx, reset_notify);
2831 if (rc)
2832 return rc;
2834 return assuan_register_post_cmd_notify(ctx, command_finalize);
2837 gpg_error_t try_xml_decrypt(assuan_context_t ctx, guchar *key,
2838 struct client_crypto_s *crypto, gpointer *dst, gsize *dst_len)
2840 gsize insize, len;
2841 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2842 guint iter = 0, n_iter = 0, iter_progress = 0;
2843 gint zrc = 0;
2844 gulong outsize = 0;
2845 gpg_error_t rc;
2846 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->fh1) : sizeof(crypto->fh->fh2);
2847 glong fh_iter = crypto->fh->v1 ? crypto->fh->fh1.iter : crypto->fh->fh2.iter;
2849 lseek(crypto->fh->fd, fh_size, SEEK_SET);
2850 insize = crypto->fh->st.st_size - fh_size;
2851 crypto->iv = gcry_malloc(gcryblocksize);
2853 if (!crypto->iv) {
2854 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2855 return gpg_error_from_errno(ENOMEM);
2858 /* No encryption iterations. This is a plain (gzipped) file. */
2859 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0)) {
2861 * cache_file_count() needs both .used == TRUE and a valid key in
2862 * order for it to count as a used cache entry. Fixes CACHE status
2863 * messages.
2865 memset(key, '!', gcrykeysize);
2868 if (crypto->fh->v1)
2869 memcpy(crypto->iv, crypto->fh->fh1.iv, gcryblocksize);
2870 else
2871 memcpy(crypto->iv, crypto->fh->fh2.iv, gcryblocksize);
2873 crypto->inbuf = gcry_malloc(insize);
2875 if (!crypto->inbuf) {
2876 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2877 return gpg_error_from_errno(ENOMEM);
2880 crypto->insize = insize;
2881 len = read(crypto->fh->fd, crypto->inbuf, crypto->insize);
2883 if (len != crypto->insize)
2884 return GPG_ERR_INV_LENGTH;
2886 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0))
2887 goto decompress;
2889 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
2890 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2891 return rc;
2894 if ((rc = gcry_cipher_setkey(crypto->gh, key, gcrykeysize))) {
2895 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2896 return rc;
2899 iter_progress = (guint)get_key_file_integer(client && client->filename ?
2900 client->filename : "global", "iteration_progress");
2902 if (iter_progress > 0 && fh_iter >= iter_progress) {
2903 rc = send_status(ctx, STATUS_DECRYPT, "%u %u", 0, fh_iter);
2905 if (rc)
2906 return rc;
2909 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
2911 if (rc)
2912 return rc;
2914 crypto->tkey = gcry_malloc(gcrykeysize);
2916 if (!crypto->tkey) {
2917 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
2918 return gpg_error_from_errno(ENOMEM);
2921 memcpy(crypto->tkey, key, gcrykeysize);
2922 guchar *tkey = crypto->tkey;
2923 tkey[0] ^= 1;
2925 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
2926 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2927 return rc;
2930 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
2931 if (iter_progress > 0 && iter >= iter_progress) {
2932 if (!(iter % iter_progress)) {
2933 rc = send_status(ctx, STATUS_DECRYPT, "%u %u",
2934 ++n_iter * iter_progress, fh_iter);
2936 if (rc)
2937 return rc;
2941 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
2942 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2943 return rc;
2946 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
2948 if (rc) {
2949 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2950 return rc;
2953 iter++;
2956 if (iter_progress && fh_iter >= iter_progress) {
2957 rc = send_status(ctx, STATUS_DECRYPT, "%u %u", fh_iter, fh_iter);
2959 if (rc)
2960 return rc;
2963 decompress:
2964 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
2965 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
2966 if (zrc == Z_MEM_ERROR)
2967 return gpg_error_from_errno(ENOMEM);
2968 else
2969 return EPWMD_BADKEY; // Not a valid gzip header. Must be a bad key.
2972 if (g_strncasecmp(crypto->outbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2973 gcry_free(crypto->outbuf);
2974 crypto->outbuf = NULL;
2975 return EPWMD_BADKEY;
2978 if (ctx) {
2979 client->xml = crypto->outbuf;
2980 client->len = outsize;
2981 crypto->outbuf = NULL;
2983 else if (dst) {
2984 *dst = crypto->outbuf;
2985 *dst_len = outsize;
2986 crypto->outbuf = NULL;
2989 /* The calling function should free the crypto struct. */
2990 return 0;
2994 * This is called after every Assuan command.
2996 void command_finalize(assuan_context_t ctx, gint rc)
2998 struct client_s *client = assuan_get_pointer(ctx);
3000 if (!client->is_lock_cmd)
3001 unlock_file_mutex(client);