When encrypting/decrypting, don't do the whole thing in one go. Break up
[pwmd.git] / src / commands.c
blob3e12bc814ac931e529383e865b48c437f254f69d
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 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
319 gpg_error_t *rc)
321 gint fd;
322 gsize len;
323 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
324 gsize fh_size;
326 *rc = 0;
328 if (!fh) {
329 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
330 *rc = gpg_error_from_errno(ENOMEM);
331 return NULL;
334 fh_size = v1 ? sizeof(fh->fh1) : sizeof(fh->fh2);
336 if (lstat(filename, &fh->st) == -1) {
337 *rc = gpg_error_from_syserror();
338 g_free(fh);
339 return NULL;
342 if (!S_ISREG(fh->st.st_mode)) {
343 *rc = GPG_ERR_ENOANO;
344 g_free(fh);
345 return NULL;
348 fd = open(filename, O_RDONLY);
350 if (fd == -1) {
351 *rc = gpg_error_from_errno(errno);
352 g_free(fh);
353 return NULL;
356 if (v1)
357 len = read(fd, &fh->fh1, fh_size);
358 else
359 len = read(fd, &fh->fh2, fh_size);
361 if (len != fh_size) {
362 close(fd);
363 *rc = GPG_ERR_INV_LENGTH;
364 g_free(fh);
365 return NULL;
368 fh->v1 = v1;
369 fh->fd = fd;
370 return fh;
373 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *key,
374 gboolean cached)
376 struct client_s *client = assuan_get_pointer(ctx);
377 gpg_error_t rc;
378 gint timeout;
380 /* New file. */
381 if (!client->crypto->fh) {
382 if (key[0])
383 goto update_cache;
385 goto done;
388 rc = try_xml_decrypt(ctx, key, client->crypto, NULL, NULL);
390 if (rc) {
391 cleanup_client(client);
392 return send_error(ctx, rc);
395 update_cache:
396 CACHE_LOCK(client->ctx);
398 if (cached == FALSE) {
399 if (cache_update_key(client->md5file, key) == FALSE) {
400 cleanup_client(client);
401 CACHE_UNLOCK;
402 return send_syserror(ctx, ENOMEM);
405 timeout = get_key_file_integer(client->filename, "cache_timeout");
406 cache_reset_timeout(client->md5file, timeout);
408 else
409 cache_set_timeout(client->md5file, -2);
411 CACHE_UNLOCK;
413 done:
414 if (client->crypto->key != key)
415 gcry_free(key); // This is invokation is a pinentry callback.
417 rc = parse_xml(ctx);
419 if (client->xml) {
420 gcry_free(client->xml);
421 client->xml = NULL;
424 if (!rc) {
425 if (client->new == FALSE)
426 send_status_all(STATUS_CACHE);
428 client->state = STATE_OPEN;
431 if (!rc && client->new == FALSE &&
432 client->crypto->fh->fh2.iter != (guint)get_key_file_integer(client->filename, "iterations")) {
433 g_key_file_set_integer(keyfileh, client->filename, "iterations",
434 client->crypto->fh->fh2.iter);
435 send_status_all(STATUS_CONFIG);
438 if (!rc)
439 log_write("OPEN '%s'", client->filename);
441 cleanup_crypto(&client->crypto);
442 return send_error(ctx, rc);
445 #ifdef WITH_GNUTLS
446 static gboolean validate_access(struct client_s *cl, const gchar *filename)
448 gchar *access = get_key_file_string(filename, "tcp_access");
449 gchar **list, **p;
451 if (!access)
452 return TRUE;
454 list = g_strsplit(access, ",", -1);
455 g_free(access);
457 if (!list) {
458 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
459 return FALSE;
462 for (p = list; *p; p++) {
463 gboolean not = FALSE;
464 gchar *fp = *p;
466 if (*fp == '!') {
467 not = TRUE;
468 fp++;
470 if (!*fp)
471 break;
474 if (strcasecmp(cl->thd->tls->fp, fp) == 0) {
475 if (not == TRUE)
476 continue;
478 g_strfreev(list);
479 return TRUE;
483 /* Not allowed. */
484 g_strfreev(list);
485 return FALSE;
487 #endif
489 static int open_command(assuan_context_t ctx, char *line)
491 gboolean cached = FALSE;
492 gpg_error_t rc;
493 struct client_s *client = assuan_get_pointer(ctx);
494 gchar **req;
495 gchar *filename = NULL;
497 if ((req = split_input_line(line, " ", 2)) != NULL)
498 filename = req[0];
500 if (!filename || !*filename) {
501 g_strfreev(req);
502 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
505 if (valid_filename(filename) == FALSE) {
506 g_strfreev(req);
507 return send_error(ctx, EPWMD_INVALID_FILENAME);
510 if (client->state == STATE_OPEN)
511 cleanup_client(client);
513 #ifdef WITH_GNUTLS
514 if (client->thd->remote == TRUE) {
515 if (validate_access(client, filename) == FALSE) {
516 log_write(N_("client validation failed for file '%s'"), filename);
517 g_strfreev(req);
518 return send_error(ctx, EPWMD_FILE_ACCESS);
521 #endif
523 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
524 CACHE_LOCK(client->ctx);
526 if (cache_has_file(client->md5file) == FALSE) {
527 if (cache_add_file(client->md5file, NULL) == FALSE) {
528 g_strfreev(req);
529 CACHE_UNLOCK;
530 return send_syserror(ctx, ENOMEM);
534 cache_incr_refcount(client->md5file);
535 CACHE_UNLOCK;
536 rc = lock_file_mutex(client);
538 if (rc) {
539 g_strfreev(req);
540 return send_error(ctx, rc);
543 client->freed = FALSE;
544 client->crypto = init_client_crypto();
546 if (!client->crypto) {
547 g_strfreev(req);
548 cleanup_client(client);
549 return send_syserror(ctx, ENOMEM);
552 client->crypto->key = gcry_malloc(gcrykeysize);
554 if (!client->crypto->key) {
555 g_strfreev(req);
556 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
557 gpg_error_from_errno(ENOMEM));
558 cleanup_client(client);
559 return send_syserror(ctx, ENOMEM);
562 memset(client->crypto->key, 0, gcrykeysize);
563 client->crypto->fh = read_file_header(filename, FALSE, &rc);
565 if (!client->crypto->fh) {
566 if (gpg_err_code_to_errno(rc) != ENOENT) {
567 log_write("%s: %s", filename, pwmd_strerror(rc));
568 g_strfreev(req);
569 cleanup_client(client);
570 return send_error(ctx, rc);
574 * New files don't need a key.
576 if ((client->xml = new_document()) == NULL) {
577 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
578 g_strfreev(req);
579 cleanup_client(client);
580 return send_syserror(ctx, ENOMEM);
583 client->len = xmlStrlen(client->xml);
584 client->new = TRUE;
585 client->filename = g_strdup(filename);
587 if (!client->filename) {
588 g_strfreev(req);
589 cleanup_client(client);
590 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
591 return send_syserror(ctx, ENOMEM);
594 if (req[1] && *req[1])
595 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
596 strlen(req[1]));
598 g_strfreev(req);
599 #ifdef WITH_PINENTRY
600 client->pinentry->filename = g_strdup(client->filename);
602 if (!client->pinentry->filename) {
603 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
604 cleanup_client(client);
605 return send_syserror(ctx, ENOMEM);
607 #endif
608 return open_command_finalize(ctx, client->crypto->key, cached);
610 else
611 client->mtime = client->crypto->fh->st.st_mtime;
613 client->filename = g_strdup(filename);
615 if (!client->filename) {
616 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
617 g_strfreev(req);
618 cleanup_client(client);
619 return send_syserror(ctx, ENOMEM);
622 #ifdef WITH_PINENTRY
623 client->pinentry->filename = g_strdup(client->filename);
625 if (!client->pinentry->filename) {
626 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
627 g_strfreev(req);
628 cleanup_client(client);
629 return send_syserror(ctx, ENOMEM);
631 #endif
633 if (client->crypto->fh->fh2.iter <= 0)
634 goto done;
636 #ifdef WITH_GNUTLS
637 if (client->thd->remote == FALSE ||
638 get_key_file_boolean(client->filename, "tcp_require_key") == FALSE)
640 #endif
641 CACHE_LOCK(client->ctx);
642 cached = cache_get_key(client->md5file, client->crypto->key);
643 CACHE_UNLOCK;
644 #ifdef WITH_GNUTLS
646 else
647 cached = FALSE;
648 #endif
650 if (cached == FALSE) {
651 gchar *tmp = get_key_file_string(filename, "key_file");
653 if (tmp) {
654 g_free(tmp);
655 cleanup_client(client);
656 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
660 * No key specified and no matching filename found in the cache. Use
661 * pinentry to retrieve the key. Cannot return assuan_process_done()
662 * here otherwise the command will be interrupted. The event loop in
663 * client_thread() will poll the file descriptor waiting for it to
664 * become ready to read a pinentry_key_s which will contain the
665 * entered key or rc. It will then call open_command_finalize() to
666 * to finish the command.
668 if (!req[1] || !*req[1]) {
669 #ifdef WITH_PINENTRY
670 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
672 /* From set_pinentry_defaults(). */
673 if (client->pinentry->enable == FALSE ||
674 (client->pinentry->enable == -1 && b == FALSE)) {
675 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
676 goto done;
679 g_strfreev(req);
680 rc = lock_pin_mutex(client);
682 if (rc) {
683 unlock_pin_mutex(client->pinentry);
684 cleanup_client(client);
685 return send_error(ctx, rc);
688 client->pinentry->which = PINENTRY_OPEN;
689 rc = pinentry_fork(ctx);
691 if (rc) {
692 unlock_pin_mutex(client->pinentry);
693 cleanup_client(client);
694 return send_error(ctx, rc);
697 client->pinentry->cb = open_command_finalize;
698 client->pinentry->status = PINENTRY_INIT;
699 return 0;
700 #else
701 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
702 goto done;
703 #endif
706 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
707 strlen(req[1]));
710 done:
711 g_strfreev(req);
712 return open_command_finalize(ctx, client->crypto->key, cached);
715 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
716 gulong size, gpointer *out, gulong *outsize, gint *rc)
718 z_stream z;
719 gpointer pout, pin;
720 gz_header h;
721 gchar buf[17];
722 gint cmd = Z_NO_FLUSH;
724 z.zalloc = z_alloc;
725 z.zfree = z_free;
726 z.next_in = pin = data;
727 z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
728 z.avail_out = (uInt)zlib_bufsize;
729 z.next_out = pout = gcry_malloc(zlib_bufsize);
731 if (!pout) {
732 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
733 *rc = Z_MEM_ERROR;
734 return FALSE;
737 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
739 if (*rc != Z_OK) {
740 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
741 gcry_free(pout);
742 return FALSE;
745 /* Rather than store the size of the uncompressed data in the file header,
746 * store it in the comment field of the gzip header. Don't give anyone too
747 * much information. Not sure why really, but it seems the right way. :)
749 memset(&h, 0, sizeof(gz_header));
750 g_snprintf(buf, sizeof(buf), "%li", size);
751 h.comment = (guchar *)buf;
752 *rc = deflateSetHeader(&z, &h);
754 if (*rc != Z_OK) {
755 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
756 gcry_free(pout);
757 deflateEnd(&z);
758 return FALSE;
761 do {
762 gpointer p;
764 *rc = deflate(&z, cmd);
766 switch (*rc) {
767 case Z_OK:
768 break;
769 case Z_BUF_ERROR:
770 if (!z.avail_out) {
771 p = gcry_realloc(pout, z.total_out + zlib_bufsize);
773 if (!p) {
774 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
775 *rc = Z_MEM_ERROR;
776 goto fail;
779 pout = p;
780 z.next_out = pout + z.total_out;
781 z.avail_out = zlib_bufsize;
784 if (!z.avail_in && z.total_in < size) {
785 if (z.total_in + zlib_bufsize > size)
786 z.avail_in = size - z.total_in;
787 else
788 z.avail_in = zlib_bufsize;
790 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li",
791 z.total_in, size);
793 if (*rc)
794 goto fail;
797 if (z.total_in >= size)
798 cmd = Z_FINISH;
800 break;
801 case Z_STREAM_END:
802 break;
803 default:
804 goto fail;
806 } while (*rc != Z_STREAM_END);
808 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li", z.total_in, size);
810 if (*rc)
811 goto fail;
813 *out = pout;
814 *outsize = z.total_out;
815 deflateEnd(&z);
816 *rc = 0;
817 return TRUE;
819 fail:
820 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
821 gcry_free(pout);
822 deflateEnd(&z);
823 return FALSE;
826 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
828 static gpg_error_t iterate_crypto_once(struct client_s *client,
829 struct client_crypto_s *crypto, status_msg_t which)
831 gpg_error_t rc = 0;
832 gsize len = CRYPTO_BLOCKSIZE;
833 gpointer p = gcry_malloc(len);
834 gsize total = 0;
835 gpointer inbuf;
837 if (!p)
838 return gpg_err_code_from_errno(ENOMEM);
840 if (crypto->insize < CRYPTO_BLOCKSIZE)
841 len = crypto->insize;
843 for (;;) {
844 inbuf = crypto->inbuf + total;
845 guchar *tmp;
847 if (len + total > crypto->insize)
848 len = gcryblocksize;
850 if (which == STATUS_ENCRYPT)
851 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
852 else
853 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
855 if (rc)
856 goto done;
858 tmp = crypto->inbuf+total;
859 memmove(tmp, p, len);
860 total += len;
862 if (total >= crypto->insize)
863 break;
865 pthread_testcancel();
868 done:
869 gcry_free(p);
870 return rc;
873 /* The crypto struct must be setup for iterations and .key. */
874 gpg_error_t do_xml_encrypt(struct client_s *client,
875 struct client_crypto_s *crypto, const gchar *filename)
877 gsize len = crypto->insize;
878 gpointer inbuf;
879 gchar *p;
880 gpg_error_t rc;
881 guint iter_progress = 0, n_iter = 0, xiter = 0;
882 gchar tmp[FILENAME_MAX];
883 struct stat st;
884 mode_t mode = 0;
886 if (!crypto->fh->fh2.iter) {
888 * cache_file_count() needs both .used == TRUE and a valid key in
889 * order for it to count as a used cache entry. Fixes CACHE status
890 * messages.
892 memset(crypto->key, '!', gcrykeysize);
893 goto write_file;
897 * Resize the existing xml buffer to the block size required by gcrypt
898 * rather than duplicating it and wasting memory.
900 if (crypto->insize / gcryblocksize) {
901 len = (crypto->insize / gcryblocksize) * gcryblocksize;
903 if (crypto->insize % gcryblocksize)
904 len += gcryblocksize;
907 inbuf = gcry_realloc(crypto->inbuf, len);
909 if (!inbuf) {
910 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
911 return gpg_error_from_errno(ENOMEM);
914 crypto->inbuf = inbuf;
915 crypto->insize = len;
916 gcry_create_nonce(crypto->fh->fh2.iv, sizeof(crypto->fh->fh2.iv));
917 crypto->tkey = gcry_malloc(gcrykeysize);
919 if (!crypto->tkey) {
920 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
921 return gpg_error_from_errno(ENOMEM);
924 memcpy(crypto->tkey, crypto->key, gcrykeysize);
925 guchar *tkey = crypto->tkey;
926 tkey[0] ^= 1;
928 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
929 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
930 return rc;
933 iter_progress = get_key_file_integer(client ? client->filename : "global",
934 "iteration_progress");
936 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
937 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
938 "%u %u", 0, crypto->fh->fh2.iter);
940 if (rc)
941 return rc;
944 while (xiter < crypto->fh->fh2.iter-1) {
945 if (iter_progress > 0 && xiter >= iter_progress) {
946 if (!(xiter % iter_progress)) {
947 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
948 "%u %u", ++n_iter * iter_progress, crypto->fh->fh2.iter);
950 if (rc)
951 return rc;
955 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
956 sizeof(crypto->fh->fh2.iv)))) {
957 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
958 return rc;
961 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
963 if (rc) {
964 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
965 return rc;
968 xiter++;
971 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
972 sizeof(crypto->fh->fh2.iv)))) {
973 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
974 return rc;
977 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, gcrykeysize))) {
978 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
979 return rc;
982 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
984 if (rc)
985 return rc;
987 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
988 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
989 "%u %u", crypto->fh->fh2.iter, crypto->fh->fh2.iter);
991 if (rc)
992 return rc;
995 write_file:
996 if (filename) {
997 if (!client && !strcmp(filename, "-")) {
998 crypto->fh->fd = STDOUT_FILENO;
999 goto do_write_file;
1002 if (lstat(filename, &st) == 0) {
1003 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1006 * FIXME What if the file has an ACL?
1008 if (!(mode & S_IWUSR))
1009 return gpg_error_from_errno(EACCES);
1011 else {
1012 if (errno != ENOENT)
1013 return gpg_error_from_errno(errno);
1016 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1017 crypto->fh->fd = mkstemp(tmp);
1019 if (crypto->fh->fd == -1) {
1020 rc = errno;
1021 p = strrchr(tmp, '/');
1022 p++;
1023 log_write("%s: %s", p, strerror(rc));
1024 return gpg_error_from_errno(rc);
1027 else
1029 * xml_import() or convert_file() from command line.
1031 crypto->fh->fd = STDOUT_FILENO;
1033 do_write_file:
1034 crypto->fh->fh2.version = VERSION_HEX;
1035 len = write(crypto->fh->fd, &crypto->fh->fh2, sizeof(crypto->fh->fh2));
1037 if (len != sizeof(crypto->fh->fh2)) {
1038 len = errno;
1040 if (filename && strcmp(filename, "-"))
1041 unlink(tmp);
1043 return gpg_error_from_errno(len);
1046 len = write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1048 if (len != crypto->insize) {
1049 len = errno;
1051 if (filename && strcmp(filename, "-"))
1052 unlink(tmp);
1054 return gpg_error_from_errno(len);
1057 if (fsync(crypto->fh->fd) == -1) {
1058 len = errno;
1060 if (filename && strcmp(filename, "-"))
1061 unlink(tmp);
1063 return gpg_error_from_errno(len);
1066 if (filename && strcmp(filename, "-")) {
1067 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1068 gchar tmp2[FILENAME_MAX];
1070 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1072 if (rename(filename, tmp2) == -1) {
1073 unlink(tmp);
1074 len = errno;
1075 return gpg_error_from_errno(len);
1079 if (rename(tmp, filename) == -1) {
1080 len = errno;
1081 unlink(tmp);
1082 return gpg_error_from_errno(len);
1085 if (mode)
1086 chmod(filename, mode);
1089 if (client && lstat(filename, &st) == 0)
1090 client->mtime = st.st_mtime;
1092 return 0;
1095 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1096 gboolean cached)
1098 struct client_s *client = assuan_get_pointer(ctx);
1099 gpointer xmlbuf;
1100 gulong len, outsize = 0;
1101 guint iter;
1102 gint timeout;
1103 gpointer outbuf;
1104 gint zrc;
1105 gpg_error_t rc;
1107 if (client->crypto->key && client->crypto->key != key)
1108 gcry_free(client->crypto->key);
1110 client->crypto->key = key;
1111 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1112 iter = (guint)get_key_file_integer(client->filename, "compression_level");
1114 if (iter < 0)
1115 iter = 0;
1117 if (do_compress(ctx, (gint)iter, xmlbuf, len, &outbuf, &outsize, &zrc)
1118 == FALSE) {
1119 if (key != client->crypto->key)
1120 gcry_free(key);
1122 xmlFree(xmlbuf);
1123 cleanup_crypto(&client->crypto);
1125 if (zrc == Z_MEM_ERROR)
1126 return send_syserror(ctx, ENOMEM);
1127 else
1128 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1130 else {
1131 gcry_free(xmlbuf);
1132 xmlbuf = outbuf;
1133 len = outsize;
1136 client->crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1138 if (!client->crypto->fh) {
1139 cleanup_crypto(&client->crypto);
1140 gcry_free(outbuf);
1141 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1142 return send_syserror(ctx, ENOMEM);
1145 iter = get_key_file_integer(client->filename, "iterations");
1146 client->crypto->fh->fh2.iter = iter < 0 ? 0 : iter;
1147 client->crypto->inbuf = xmlbuf;
1148 client->crypto->insize = len;
1149 rc = do_xml_encrypt(client, client->crypto, client->filename);
1151 if (rc) {
1152 cleanup_crypto(&client->crypto);
1153 return send_error(ctx, rc);
1156 timeout = get_key_file_integer(client->filename, "cache_timeout");
1157 CACHE_LOCK(client->ctx);
1159 if (cached) {
1160 cache_reset_timeout(client->md5file, timeout);
1161 CACHE_UNLOCK;
1163 if (client->new == TRUE)
1164 send_status_all(STATUS_CACHE);
1166 client->new = FALSE;
1167 cleanup_crypto(&client->crypto);
1168 return send_error(ctx, 0);
1171 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1172 CACHE_UNLOCK;
1173 cleanup_crypto(&client->crypto);
1174 return send_syserror(ctx, ENOMEM);
1177 client->new = FALSE;
1178 cache_reset_timeout(client->md5file, timeout);
1179 CACHE_UNLOCK;
1180 send_status_all(STATUS_CACHE);
1181 cleanup_crypto(&client->crypto);
1182 return send_error(ctx, 0);
1185 static int save_command(assuan_context_t ctx, char *line)
1187 gboolean cached = FALSE;
1188 struct stat st;
1189 struct client_s *client = assuan_get_pointer(ctx);
1190 gpg_error_t rc;
1192 rc = lock_file_mutex(client);
1194 if (rc)
1195 return send_error(ctx, rc);
1197 rc = file_modified(client);
1199 if (rc)
1200 return send_error(ctx, rc);
1202 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1203 return send_syserror(ctx, errno);
1205 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1206 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1207 return send_error(ctx, GPG_ERR_ENOANO);
1210 CACHE_LOCK(ctx);
1211 cached = cache_iscached(client->md5file);
1212 CACHE_UNLOCK;
1215 * If a cache entry doesn't exist for this file and the file has a
1216 * "key_file" or "key" parameter, then it's an error. The reason is that
1217 * cache expiration would be useless.
1219 if (cached == FALSE) {
1220 gchar *tmp = get_key_file_string(client->filename, "key_file");
1222 if (tmp) {
1223 g_free(tmp);
1224 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1228 cached = FALSE;
1229 client->crypto = init_client_crypto();
1231 if (!client->crypto) {
1232 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1233 return send_syserror(ctx, ENOMEM);
1236 client->crypto->key = gcry_malloc(gcrykeysize);
1238 if (!client->crypto->key) {
1239 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1240 cleanup_crypto(&client->crypto);
1241 return send_syserror(ctx, ENOMEM);
1244 memset(client->crypto->key, '!', gcrykeysize);
1246 if (get_key_file_integer(client->filename, "iterations") <= 0)
1247 goto done;
1249 if (!line || !*line) {
1250 client->crypto->tkey = gcry_malloc(gcrykeysize);
1252 if (!client->crypto->tkey) {
1253 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1254 cleanup_crypto(&client->crypto);
1255 return send_syserror(ctx, ENOMEM);
1258 memset(client->crypto->tkey, '!', gcrykeysize);
1259 CACHE_LOCK(ctx);
1261 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1262 memcmp(client->crypto->key, client->crypto->tkey,
1263 gcrykeysize) == 0) {
1264 CACHE_UNLOCK;
1266 #ifdef WITH_PINENTRY
1267 if (client->pinentry->enable == FALSE ||
1268 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1269 /* Empty keys are allowed. */
1270 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1271 goto done;
1274 lock_pin_mutex(client);
1275 client->pinentry->which = PINENTRY_SAVE;
1276 rc = pinentry_fork(ctx);
1278 if (rc) {
1279 unlock_pin_mutex(client->pinentry);
1280 return send_error(ctx, rc);
1283 client->pinentry->cb = save_command_finalize;
1284 client->pinentry->status = PINENTRY_INIT;
1285 return 0;
1286 #else
1287 /* Empty keys are allowed. */
1288 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1289 goto done;
1290 #endif
1292 else {
1293 CACHE_UNLOCK;
1294 cached = TRUE;
1297 else {
1298 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1299 strlen(line));
1300 memset(line, 0, strlen(line));
1303 done:
1304 return save_command_finalize(ctx, client->crypto->key, cached);
1307 static int delete_command(assuan_context_t ctx, char *line)
1309 struct client_s *client = assuan_get_pointer(ctx);
1310 gchar **req;
1311 gpg_error_t rc;
1312 xmlNodePtr n;
1314 rc = file_modified(client);
1316 if (rc)
1317 return send_error(ctx, rc);
1319 if (strchr(line, '\t'))
1320 req = split_input_line(line, "\t", -1);
1321 else
1322 req = split_input_line(line, " ", -1);
1324 if (!req || !*req)
1325 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1327 n = find_account(client->doc, &req, &rc, NULL, 0);
1329 if (!n) {
1330 g_strfreev(req);
1331 return send_error(ctx, rc);
1335 * No sub-node defined. Remove the entire node (account).
1337 if (!req[1]) {
1338 if (n) {
1339 xmlUnlinkNode(n);
1340 xmlFreeNode(n);
1343 g_strfreev(req);
1344 return send_error(ctx, 0);
1347 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1348 g_strfreev(req);
1350 if (!n)
1351 return send_error(ctx, rc);
1353 if (n) {
1354 xmlUnlinkNode(n);
1355 xmlFreeNode(n);
1358 return send_error(ctx, 0);
1362 * Don't return with assuan_process_done() here. This has been called from
1363 * assuan_process_next() and the command should be finished in
1364 * client_thread().
1366 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1367 gsize len)
1369 assuan_context_t ctx = data;
1370 struct client_s *client = assuan_get_pointer(ctx);
1371 gchar **req;
1372 xmlNodePtr n;
1373 gpg_error_t rc = file_modified(client);
1375 if (assuan_rc || rc) {
1376 if (line)
1377 xfree(line);
1378 return assuan_rc ? assuan_rc : rc;
1381 req = split_input_line((gchar *)line, "\t", 0);
1382 xfree(line);
1384 if (!req || !*req)
1385 return EPWMD_COMMAND_SYNTAX;
1387 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1388 g_strfreev(req);
1389 return EPWMD_INVALID_ELEMENT;
1392 if (valid_element_path(req+1, TRUE) == FALSE) {
1393 g_strfreev(req);
1394 return EPWMD_INVALID_ELEMENT;
1397 again:
1398 n = find_account(client->doc, &req, &rc, NULL, 0);
1400 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1401 rc = new_account(client->doc, *req);
1403 if (rc) {
1404 g_strfreev(req);
1405 return rc;
1408 goto again;
1411 if (!n) {
1412 g_strfreev(req);
1413 return rc;
1416 if (req[1]) {
1417 if (!n->children)
1418 create_elements_cb(n, req+1, &rc, NULL);
1419 else
1420 find_elements(client->doc, n->children, req+1, &rc,
1421 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1424 g_strfreev(req);
1425 client->inquire_status = INQUIRE_DONE;
1426 return rc;
1429 static int store_command(assuan_context_t ctx, char *line)
1431 struct client_s *client = assuan_get_pointer(ctx);
1432 gpg_error_t rc = file_modified(client);
1434 if (rc)
1435 return send_error(ctx, rc);
1437 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1439 if (rc)
1440 return send_error(ctx, rc);
1442 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1443 client->inquire_status = INQUIRE_BUSY;
1444 return 0;
1447 static int get_command(assuan_context_t ctx, char *line)
1449 struct client_s *client = assuan_get_pointer(ctx);
1450 gchar **req;
1451 gpg_error_t rc;
1452 xmlNodePtr n;
1454 rc = file_modified(client);
1456 if (rc)
1457 return send_error(ctx, rc);
1459 req = split_input_line(line, "\t", -1);
1461 if (!req || !*req) {
1462 g_strfreev(req);
1463 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1466 n = find_account(client->doc, &req, &rc, NULL, 0);
1468 if (!n) {
1469 g_strfreev(req);
1470 return send_error(ctx, rc);
1473 if (req[1])
1474 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1476 g_strfreev(req);
1478 if (rc)
1479 return send_error(ctx, rc);
1481 if (!n || !n->children)
1482 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1484 n = find_text_node(n->children);
1486 if (!n || !n->content || !*n->content)
1487 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1489 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1490 return send_error(ctx, rc);
1493 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1494 gpg_error_t *rc, gchar **req_orig, void *data)
1496 gchar *path = *(gchar **)data;
1497 gchar *tmp = NULL, *result;
1499 if (path) {
1500 g_free(path);
1501 *(gchar **)data = NULL;
1504 path = g_strjoinv("\t", target);
1506 if (!path) {
1507 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1508 *rc = gpg_error_from_errno(ENOMEM);
1509 return NULL;
1512 if (req_orig) {
1513 tmp = g_strjoinv("\t", req_orig);
1515 if (!tmp) {
1516 g_free(path);
1517 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1518 *rc = gpg_error_from_errno(ENOMEM);
1519 return NULL;
1523 if (tmp && *tmp)
1524 result = g_strdup_printf("%s\t%s", path, tmp);
1525 else
1526 result = g_strdup(path);
1528 if (!result) {
1529 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1530 *rc = gpg_error_from_errno(ENOMEM);
1531 g_free(path);
1532 g_free(tmp);
1533 return NULL;
1536 g_free(path);
1537 g_free(tmp);
1538 *(gchar **)data = result;
1539 return node;
1542 static int realpath_command(assuan_context_t ctx, char *line)
1544 gpg_error_t rc;
1545 struct client_s *client = assuan_get_pointer(ctx);
1546 gchar **req;
1547 gchar *t;
1548 gint i;
1549 xmlNodePtr n;
1550 GString *string;
1551 gchar *rp = NULL;
1553 rc = file_modified(client);
1555 if (rc)
1556 return send_error(ctx, rc);
1558 if (strchr(line, '\t') != NULL) {
1559 if ((req = split_input_line(line, "\t", 0)) == NULL)
1560 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1562 else {
1563 if ((req = split_input_line(line, " ", 0)) == NULL)
1564 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1567 n = find_account(client->doc, &req, &rc, NULL, 0);
1569 if (!n) {
1570 g_strfreev(req);
1571 return send_error(ctx, rc);
1574 rp = g_strjoinv("\t", req);
1576 if (!rp) {
1577 g_strfreev(req);
1578 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1579 return send_syserror(ctx, ENOMEM);
1582 if (req[1]) {
1583 n = find_elements(client->doc, n->children, req+1, &rc,
1584 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1586 if (!n) {
1587 g_free(rp);
1588 g_strfreev(req);
1589 return send_error(ctx, rc);
1593 string = g_string_new(rp);
1594 g_free(rp);
1595 g_strfreev(req);
1597 if (!string) {
1598 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1599 return send_syserror(ctx, ENOMEM);
1602 again:
1603 for (i = 0, t = string->str + i; *t; t++, i++) {
1604 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1605 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1606 goto again;
1610 rc = assuan_send_data(ctx, string->str, string->len);
1611 g_string_free(string, TRUE);
1612 return send_error(ctx, rc);
1615 static int list_command(assuan_context_t ctx, char *line)
1617 struct client_s *client = assuan_get_pointer(ctx);
1618 gpg_error_t rc;
1619 struct element_list_s *elements = NULL;
1620 gchar *tmp;
1622 if (disable_list_and_dump == TRUE)
1623 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1625 rc = file_modified(client);
1627 if (rc)
1628 return send_error(ctx, rc);
1630 if (!*line) {
1631 GString *str;
1633 rc = list_accounts(client->doc, &str);
1635 if (rc)
1636 return send_error(ctx, rc);
1638 rc = assuan_send_data(ctx, str->str, str->len);
1639 g_string_free(str, TRUE);
1640 return send_error(ctx, rc);
1643 elements = g_malloc0(sizeof(struct element_list_s));
1645 if (!elements) {
1646 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1647 rc = gpg_err_code_from_errno(ENOMEM);
1648 goto fail;
1651 rc = create_path_list(client->doc, elements, line);
1653 if (rc)
1654 goto fail;
1656 if (elements) {
1657 gint total = g_slist_length(elements->list);
1658 gint i;
1659 GString *str;
1661 if (!total) {
1662 rc = EPWMD_EMPTY_ELEMENT;
1663 goto fail;
1666 str = g_string_new(NULL);
1668 if (!str) {
1669 rc = gpg_err_code_from_errno(ENOMEM);
1670 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1671 goto fail;
1674 for (i = 0; i < total; i++) {
1675 tmp = g_slist_nth_data(elements->list, i);
1676 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1679 rc = assuan_send_data(ctx, str->str, str->len);
1680 g_string_free(str, TRUE);
1682 else
1683 rc = EPWMD_EMPTY_ELEMENT;
1685 fail:
1686 if (elements) {
1687 gint total = g_slist_length(elements->list);
1688 gint i;
1690 for (i = 0; i < total; i++) {
1691 tmp = g_slist_nth_data(elements->list, i);
1692 g_free(tmp);
1695 g_slist_free(elements->list);
1697 if (elements->prefix)
1698 g_free(elements->prefix);
1700 g_free(elements);
1703 return send_error(ctx, rc);
1706 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1707 const gchar *value)
1709 xmlAttrPtr a;
1711 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1712 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1714 if (!a)
1715 return EPWMD_LIBXML_ERROR;
1717 else
1718 xmlNodeSetContent(a->children, (xmlChar *)value);
1720 return 0;
1724 * req[0] - element path
1726 static int attribute_list(assuan_context_t ctx, gchar **req)
1728 struct client_s *client = assuan_get_pointer(ctx);
1729 gchar **attrlist = NULL;
1730 gint i = 0;
1731 gchar **path = NULL;
1732 xmlAttrPtr a;
1733 xmlNodePtr n, an;
1734 gchar *line;
1735 gpg_error_t rc;
1737 if (!req || !req[0])
1738 return EPWMD_COMMAND_SYNTAX;
1740 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1742 * The first argument may be only an account.
1744 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1745 return EPWMD_COMMAND_SYNTAX;
1748 n = find_account(client->doc, &path, &rc, NULL, 0);
1750 if (!n) {
1751 g_strfreev(path);
1752 return rc;
1755 if (path[1]) {
1756 n = find_elements(client->doc, n->children, path+1, &rc,
1757 NULL, NULL, NULL, FALSE, 0, NULL);
1759 if (!n) {
1760 g_strfreev(path);
1761 return rc;
1765 g_strfreev(path);
1767 for (a = n->properties; a; a = a->next) {
1768 gchar **pa;
1770 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1771 if (attrlist)
1772 g_strfreev(attrlist);
1774 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1775 return gpg_error_from_errno(ENOMEM);
1778 attrlist = pa;
1779 an = a->children;
1780 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name, (gchar *)an->content);
1782 if (!attrlist[i]) {
1783 g_strfreev(attrlist);
1784 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1785 return gpg_error_from_errno(ENOMEM);
1788 attrlist[++i] = NULL;
1791 if (!attrlist)
1792 return EPWMD_EMPTY_ELEMENT;
1794 line = g_strjoinv("\n", attrlist);
1796 if (!line) {
1797 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1798 g_strfreev(attrlist);
1799 return gpg_error_from_errno(ENOMEM);
1802 rc = assuan_send_data(ctx, line, strlen(line));
1803 g_free(line);
1804 g_strfreev(attrlist);
1805 return rc;
1809 * req[0] - attribute
1810 * req[1] - element path
1812 static int attribute_delete(struct client_s *client, gchar **req)
1814 xmlAttrPtr a;
1815 xmlNodePtr n;
1816 gchar **path = NULL;
1817 gpg_error_t rc;
1819 if (!req || !req[0] || !req[1])
1820 return EPWMD_COMMAND_SYNTAX;
1822 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1824 * The first argument may be only an account.
1826 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1827 return EPWMD_COMMAND_SYNTAX;
1831 * Don't remove the "name" attribute for the account element. To remove an
1832 * account use DELETE <account>.
1834 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1835 rc = EPWMD_ATTR_SYNTAX;
1836 goto fail;
1839 n = find_account(client->doc, &path, &rc, NULL, 0);
1841 if (!n)
1842 goto fail;
1844 if (path[1]) {
1845 n = find_elements(client->doc, n->children, path+1, &rc,
1846 NULL, NULL, NULL, FALSE, 0, NULL);
1848 if (!n)
1849 goto fail;
1852 g_strfreev(path);
1854 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1855 return EPWMD_ATTR_NOT_FOUND;
1857 if (xmlRemoveProp(a) == -1)
1858 return EPWMD_LIBXML_ERROR;
1860 return 0;
1862 fail:
1863 g_strfreev(path);
1864 return rc;
1867 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1868 gpg_error_t *rc)
1870 gchar **src = *path;
1871 gchar **src_orig = g_strdupv(src);
1872 xmlNodePtr n = NULL;
1874 *rc = 0;
1876 if (!src_orig) {
1877 *rc = gpg_error_from_errno(ENOMEM);
1878 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1879 goto fail;
1882 again:
1883 n = find_account(client->doc, &src, rc, NULL, 0);
1885 if (!n) {
1886 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1887 *rc = new_account(client->doc, src[0]);
1889 if (*rc)
1890 goto fail;
1892 goto again;
1894 else
1895 goto fail;
1898 if (src[1]) {
1899 if (!n->children)
1900 n = create_target_elements_cb(n, src+1, rc, NULL);
1901 else
1902 n = find_elements(client->doc, n->children, src+1, rc,
1903 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1905 if (!n)
1906 goto fail;
1909 * Reset the position of the element tree now that the elements
1910 * have been created.
1912 g_strfreev(src);
1913 src = src_orig;
1914 src_orig = NULL;
1915 n = find_account(client->doc, &src, rc, NULL, 0);
1917 if (!n)
1918 goto fail;
1920 n = find_elements(client->doc, n->children, src+1, rc,
1921 NULL, NULL, NULL, FALSE, 0, NULL);
1923 if (!n)
1924 goto fail;
1927 fail:
1928 if (src_orig)
1929 g_strfreev(src_orig);
1931 *path = src;
1932 return n;
1936 * Creates a "target" attribute. When other commands encounter an element with
1937 * this attribute, the element path is modified to the target value. If the
1938 * source element path doesn't exist when using 'ATTR SET target', it is
1939 * created, but the destination element path must exist.
1941 * req[0] - source element path
1942 * req[1] - destination element path
1944 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1946 gchar **src, **dst, *line = NULL;
1947 gpg_error_t rc;
1948 xmlNodePtr n;
1950 if (!req || !req[0] || !req[1])
1951 return EPWMD_COMMAND_SYNTAX;
1953 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1955 * The first argument may be only an account.
1957 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1958 return EPWMD_COMMAND_SYNTAX;
1961 if (valid_element_path(src, FALSE) == FALSE) {
1962 g_strfreev(src);
1963 return EPWMD_INVALID_ELEMENT;
1966 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1968 * The first argument may be only an account.
1970 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1971 rc = EPWMD_COMMAND_SYNTAX;
1972 goto fail;
1976 n = find_account(client->doc, &dst, &rc, NULL, 0);
1979 * Make sure the destination element path exists.
1981 if (!n)
1982 goto fail;
1984 if (dst[1]) {
1985 n = find_elements(client->doc, n->children, dst+1, &rc,
1986 NULL, NULL, NULL, FALSE, 0, NULL);
1988 if (!n)
1989 goto fail;
1992 n = create_element_path(client, &src, &rc);
1994 if (rc)
1995 goto fail;
1997 line = g_strjoinv("\t", dst);
1999 if (!line) {
2000 rc = gpg_error_from_errno(ENOMEM);
2001 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2002 goto fail;
2005 rc = add_attribute(n, "target", line);
2007 fail:
2008 g_free(line);
2009 g_strfreev(src);
2010 g_strfreev(dst);
2011 return rc;
2015 * req[0] - account name
2016 * req[1] - new name
2018 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2020 gpg_error_t rc;
2021 gchar **tmp;
2022 xmlNodePtr n;
2024 tmp = g_strdupv(req);
2026 if (!tmp) {
2027 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2028 return gpg_error_from_errno(ENOMEM);
2031 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2032 g_strfreev(tmp);
2034 if (!n)
2035 return rc;
2037 if (g_utf8_collate(req[0], req[1]) == 0)
2038 return 0;
2041 * Will not overwrite an existing account.
2043 tmp = g_strdupv(req+1);
2045 if (!tmp) {
2046 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2047 return gpg_error_from_errno(ENOMEM);
2050 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2051 g_strfreev(tmp);
2053 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
2054 return rc;
2056 if (n)
2057 return EPWMD_ACCOUNT_EXISTS;
2060 * Whitespace not allowed in account names.
2062 if (contains_whitespace(req[1]) == TRUE)
2063 return EPWMD_ATTR_SYNTAX;
2065 tmp = g_strdupv(req);
2067 if (!tmp) {
2068 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2069 return gpg_error_from_errno(ENOMEM);
2072 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2073 g_strfreev(tmp);
2075 if (!n)
2076 return EPWMD_ELEMENT_NOT_FOUND;
2078 return add_attribute(n, "name", req[1]);
2082 * req[0] - attribute
2083 * req[1] - element path
2085 static int attribute_get(assuan_context_t ctx, gchar **req)
2087 struct client_s *client = assuan_get_pointer(ctx);
2088 xmlNodePtr n;
2089 xmlChar *a;
2090 gchar **path= NULL;
2091 gpg_error_t rc;
2093 if (!req || !req[0] || !req[1])
2094 return EPWMD_COMMAND_SYNTAX;
2096 if (strchr(req[1], '\t')) {
2097 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2098 return EPWMD_COMMAND_SYNTAX;
2100 else {
2101 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2102 return EPWMD_COMMAND_SYNTAX;
2105 n = find_account(client->doc, &path, &rc, NULL, 0);
2107 if (!n)
2108 goto fail;
2110 if (path[1]) {
2111 n = find_elements(client->doc, n->children, path+1, &rc,
2112 NULL, NULL, NULL, FALSE, 0, NULL);
2114 if (!n)
2115 goto fail;
2118 g_strfreev(path);
2120 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2121 return EPWMD_ATTR_NOT_FOUND;
2123 rc = assuan_send_data(ctx, a, xmlStrlen(a));
2124 xmlFree(a);
2125 return rc;
2127 fail:
2128 g_strfreev(path);
2129 return rc;
2133 * req[0] - attribute
2134 * req[1] - element path
2135 * req[2] - value
2137 static int attribute_set(struct client_s *client, gchar **req)
2139 gchar **path = NULL;
2140 gpg_error_t rc;
2141 xmlNodePtr n;
2143 if (!req || !req[0] || !req[1] || !req[2])
2144 return EPWMD_COMMAND_SYNTAX;
2147 * Reserved attribute names.
2149 if (g_utf8_collate(req[0], "name") == 0) {
2151 * Only reserved for the account element. Not the rest of the
2152 * document.
2154 if (strchr(req[1], '\t') == NULL)
2155 return name_attribute(client, req + 1);
2157 else if (g_utf8_collate(req[0], "target") == 0)
2158 return target_attribute(client, req + 1);
2160 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2162 * The first argument may be only an account.
2164 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2165 return EPWMD_COMMAND_SYNTAX;
2168 n = find_account(client->doc, &path, &rc, NULL, 0);
2170 if (!n)
2171 goto fail;
2173 if (path[1]) {
2174 n = find_elements(client->doc, n->children, path+1, &rc,
2175 NULL, NULL, NULL, FALSE, 0, NULL);
2177 if (!n)
2178 goto fail;
2181 g_strfreev(path);
2182 return add_attribute(n, req[0], req[2]);
2184 fail:
2185 g_strfreev(path);
2186 return rc;
2190 * req[0] - command
2191 * req[1] - attribute name or element path if command is LIST
2192 * req[2] - element path
2193 * req[2] - element path or value
2195 static int attr_command(assuan_context_t ctx, char *line)
2197 struct client_s *client = assuan_get_pointer(ctx);
2198 gchar **req;
2199 gpg_error_t rc = 0;
2201 rc = file_modified(client);
2203 if (rc)
2204 return send_error(ctx, rc);
2206 req = split_input_line(line, " ", 4);
2208 if (!req || !req[0] || !req[1]) {
2209 g_strfreev(req);
2210 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2213 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2214 rc = attribute_set(client, req+1);
2215 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2216 rc = attribute_get(ctx, req+1);
2217 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2218 rc = attribute_delete(client, req+1);
2219 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2220 rc = attribute_list(ctx, req+1);
2221 else
2222 rc = EPWMD_COMMAND_SYNTAX;
2224 g_strfreev(req);
2225 return send_error(ctx, rc);
2228 static int iscached_command(assuan_context_t ctx, char *line)
2230 gchar **req = split_input_line(line, " ", 0);
2231 guchar md5file[16];
2233 if (!req || !*req) {
2234 g_strfreev(req);
2235 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2238 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2239 g_strfreev(req);
2240 CACHE_LOCK(ctx);
2242 if (cache_iscached(md5file) == FALSE) {
2243 CACHE_UNLOCK;
2244 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2247 CACHE_UNLOCK;
2248 return send_error(ctx, 0);
2251 static int clearcache_command(assuan_context_t ctx, char *line)
2253 struct client_s *client = assuan_get_pointer(ctx);
2254 gchar **req = split_input_line(line, " ", 0);
2255 guchar md5file[16];
2257 CACHE_LOCK(ctx);
2259 if (!req || !*req) {
2260 g_strfreev(req);
2261 cache_clear(client->md5file, 2);
2262 CACHE_UNLOCK;
2263 return send_error(ctx, 0);
2266 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2267 g_strfreev(req);
2269 if (cache_clear(md5file, 1) == FALSE) {
2270 CACHE_UNLOCK;
2271 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2274 CACHE_UNLOCK;
2275 return send_error(ctx, 0);
2278 static int cachetimeout_command(assuan_context_t ctx, char *line)
2280 guchar md5file[16];
2281 glong timeout;
2282 gchar **req = split_input_line(line, " ", 0);
2283 gchar *p;
2284 struct client_s *client = assuan_get_pointer(ctx);
2286 if (!req || !*req || !req[1]) {
2287 g_strfreev(req);
2288 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2291 errno = 0;
2292 timeout = strtol(req[0], &p, 10);
2294 if (errno != 0 || *p != 0) {
2295 g_strfreev(req);
2296 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2299 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2300 g_strfreev(req);
2301 CACHE_LOCK(client->ctx);
2303 if (cache_set_timeout(md5file, timeout) == FALSE) {
2304 CACHE_UNLOCK;
2305 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2308 CACHE_UNLOCK;
2309 return send_error(ctx, 0);
2312 static int dump_command(assuan_context_t ctx, char *line)
2314 xmlChar *xml;
2315 gssize len;
2316 struct client_s *client = assuan_get_pointer(ctx);
2317 gpg_error_t rc;
2319 if (disable_list_and_dump == TRUE)
2320 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2322 rc = file_modified(client);
2324 if (rc)
2325 return send_error(ctx, rc);
2327 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2329 if (!xml) {
2330 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2331 return send_syserror(ctx, ENOMEM);
2334 rc = assuan_send_data(ctx, xml, len);
2335 xmlFree(xml);
2336 return send_error(ctx, rc);
2339 static int getconfig_command(assuan_context_t ctx, gchar *line)
2341 struct client_s *client = assuan_get_pointer(ctx);
2342 gpg_error_t rc = 0;
2343 gchar filename[255]={0}, param[747]={0};
2344 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2346 if (strchr(line, ' ')) {
2347 sscanf(line, " %254[^ ] %746c", filename, param);
2348 fp = filename;
2349 paramp = param;
2352 if (fp && !valid_filename(fp))
2353 return send_error(ctx, EPWMD_INVALID_FILENAME);
2355 paramp = g_ascii_strdown(paramp, -1);
2357 if (!paramp) {
2358 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2359 return send_syserror(ctx, ENOMEM);
2362 p = get_key_file_string(fp ? fp : "global", paramp);
2363 g_free(paramp);
2365 if (!p)
2366 return send_error(ctx, GPG_ERR_NO_VALUE);
2368 tmp = expand_homedir(p);
2369 g_free(p);
2371 if (!tmp) {
2372 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2373 return send_syserror(ctx, ENOMEM);
2376 p = tmp;
2377 rc = assuan_send_data(ctx, p, strlen(p));
2378 g_free(p);
2379 return send_error(ctx, rc);
2382 static int xpath_command(assuan_context_t ctx, gchar *line)
2384 struct client_s *client = assuan_get_pointer(ctx);
2385 gpg_error_t rc;
2386 xmlXPathContextPtr xp;
2387 xmlXPathObjectPtr result;
2388 xmlBufferPtr buf = NULL;
2389 gchar **req = NULL;
2391 if (disable_list_and_dump == TRUE)
2392 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2394 rc = file_modified(client);
2396 if (rc)
2397 return send_error(ctx, rc);
2399 if (!line || !*line)
2400 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2402 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2403 if (strv_printf(&req, "%s", line) == FALSE)
2404 return send_syserror(ctx, ENOMEM);
2407 xp = xmlXPathNewContext(client->doc);
2409 if (!xp)
2410 return send_error(ctx, EPWMD_LIBXML_ERROR);
2412 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2414 if (!result) {
2415 xmlXPathFreeContext(xp);
2416 return send_error(ctx, EPWMD_LIBXML_ERROR);
2419 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2420 rc = EPWMD_EMPTY_ELEMENT;
2421 goto fail;
2424 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2425 (xmlChar *)req[1], &buf);
2427 if (rc)
2428 goto fail;
2429 else if (!req[1] && !xmlBufferLength(buf)) {
2430 rc = EPWMD_EMPTY_ELEMENT;
2431 goto fail;
2433 else if (req[1])
2434 goto fail;
2436 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2438 fail:
2439 g_strfreev(req);
2441 if (buf)
2442 xmlBufferFree(buf);
2444 if (result)
2445 xmlXPathFreeObject(result);
2447 if (xp)
2448 xmlXPathFreeContext(xp);
2450 return send_error(ctx, rc);
2453 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2454 gsize len)
2456 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2457 gpg_error_t rc = file_modified(client);
2458 gchar **req, **path = NULL, **path_orig = NULL, *content;
2459 xmlDocPtr doc;
2460 xmlNodePtr n, root, copy;
2462 if (assuan_rc || rc) {
2463 if (line)
2464 xfree(line);
2465 return assuan_rc ? assuan_rc : rc;
2468 req = split_input_line((gchar *)line, " ", 2);
2469 xfree(line);
2471 if (!req || !*req)
2472 return EPWMD_COMMAND_SYNTAX;
2474 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2475 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2476 return EPWMD_COMMAND_SYNTAX;
2479 content = req[1];
2481 if (!content || !*content) {
2482 rc = EPWMD_COMMAND_SYNTAX;
2483 goto fail;
2486 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2487 rc = EPWMD_INVALID_ELEMENT;
2488 goto fail;
2491 if (valid_element_path(path+1, FALSE) == FALSE) {
2492 rc = EPWMD_INVALID_ELEMENT;
2493 goto fail;
2496 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2498 if (!doc) {
2499 rc = EPWMD_LIBXML_ERROR;
2500 goto fail;
2503 root = xmlDocGetRootElement(doc);
2504 path_orig = g_strdupv(path);
2506 if (!path_orig) {
2507 xmlFreeDoc(doc);
2508 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2509 rc = gpg_error_from_errno(ENOMEM);
2510 goto fail;
2513 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2514 g_strfreev(path_orig);
2515 xmlFreeDoc(doc);
2516 rc = gpg_error_from_errno(ENOMEM);
2517 goto fail;
2520 n = find_account(client->doc, &path, &rc, NULL, 0);
2522 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2523 g_strfreev(path_orig);
2524 xmlFreeDoc(doc);
2525 goto fail;
2527 else if (!rc) {
2528 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2530 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2531 g_strfreev(path_orig);
2532 xmlFreeDoc(doc);
2533 goto fail;
2535 else if (!rc) {
2536 xmlNodePtr parent = n->parent;
2538 xmlUnlinkNode(n);
2539 xmlFreeNode(n);
2540 n = parent;
2544 g_strfreev(path);
2545 path = path_orig;
2547 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2548 n = create_element_path(client, &path, &rc);
2550 if (rc) {
2551 xmlFreeDoc(doc);
2552 goto fail;
2556 copy = xmlCopyNode(root, 1);
2557 n = xmlAddChild(n, copy);
2558 xmlFreeDoc(doc);
2560 if (!n)
2561 rc = EPWMD_LIBXML_ERROR;
2563 fail:
2564 g_strfreev(path);
2565 g_strfreev(req);
2566 client->inquire_status = INQUIRE_DONE;
2567 return rc;
2570 static int import_command(assuan_context_t ctx, gchar *line)
2572 gpg_error_t rc;
2573 struct client_s *client = assuan_get_pointer(ctx);
2575 rc = file_modified(client);
2577 if (rc)
2578 return send_error(ctx, rc);
2580 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2582 if (rc)
2583 return send_error(ctx, rc);
2585 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2586 client->inquire_status = INQUIRE_BUSY;
2587 return 0;
2590 static int lock_command(assuan_context_t ctx, gchar *line)
2592 gpg_error_t rc;
2593 struct client_s *client = assuan_get_pointer(ctx);
2595 rc = file_modified(client);
2597 if (rc)
2598 return send_error(ctx, rc);
2600 rc = lock_file_mutex(client);
2602 if (!rc)
2603 client->is_lock_cmd = TRUE;
2605 return send_error(ctx, rc);
2608 static int unlock_command(assuan_context_t ctx, gchar *line)
2610 struct client_s *client = assuan_get_pointer(ctx);
2611 gpg_error_t rc = file_modified(client);
2613 if (rc)
2614 return send_error(ctx, rc);
2616 unlock_file_mutex(client);
2617 return send_error(ctx, 0);
2620 static int getpid_command(assuan_context_t ctx, gchar *line)
2622 gpg_error_t rc;
2623 gchar buf[32];
2624 pid_t pid = getpid();
2626 print_fmt(buf, sizeof(buf), "%i", pid);
2627 rc = assuan_send_data(ctx, buf, strlen(buf));
2628 return send_error(ctx, rc);
2631 static int version_command(assuan_context_t ctx, gchar *line)
2633 gpg_error_t rc;
2634 gchar buf[32];
2636 print_fmt(buf, sizeof(buf), "%s", PACKAGE_VERSION);
2637 rc = assuan_send_data(ctx, buf, strlen(buf));
2638 return send_error(ctx, rc);
2641 static void bye_notify(assuan_context_t ctx)
2643 struct client_s *cl = assuan_get_pointer(ctx);
2644 #ifdef WITH_GNUTLS
2645 gint rc;
2647 if (!cl->thd->remote)
2648 return;
2650 do {
2651 rc = gnutls_bye(cl->thd->tls->ses, GNUTLS_SHUT_RDWR);
2652 } while (rc == GNUTLS_E_AGAIN);
2653 #endif
2655 /* This will let assuan_process_next() return. */
2656 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
2659 static void reset_notify(assuan_context_t ctx)
2661 struct client_s *cl = assuan_get_pointer(ctx);
2663 if (cl)
2664 cleanup_client(cl);
2667 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2669 gchar name[32] = {0}, value[256] = {0};
2671 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2672 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2674 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2675 struct client_s *cl = assuan_get_pointer(ctx);
2677 if (cl->thd->name)
2678 g_free(cl->thd->name);
2680 cl->thd->name = g_strdup(value);
2681 log_write("OPTION CLIENT %s", line);
2683 else
2684 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2686 return 0;
2689 static int option_handler(assuan_context_t ctx, const gchar *name,
2690 const gchar *value)
2692 struct client_s *client = assuan_get_pointer(ctx);
2694 if (!value || !*value)
2695 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2697 if (g_strcasecmp(name, (gchar *)"client") == 0)
2698 return parse_client_option(ctx, value);
2700 if (g_strcasecmp(name, (gchar *)"iterations") == 0) {
2701 long n;
2702 gchar *p = NULL;
2704 errno = 0;
2705 n = strtol(value, &p, 10);
2707 if (errno || (p && *p) || n < 0)
2708 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2710 g_key_file_set_integer(keyfileh, client->filename ? client->filename : "global", "iterations", (guint)n);
2711 send_status_all(STATUS_CONFIG);
2713 #ifdef WITH_PINENTRY
2714 else if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2715 g_free(client->pinentry->ttyname);
2716 client->pinentry->ttyname = g_strdup(value);
2718 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2719 g_free(client->pinentry->ttytype);
2720 client->pinentry->ttytype = g_strdup(value);
2722 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2723 g_free(client->pinentry->display);
2724 client->pinentry->display = g_strdup(value);
2726 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2727 g_free(client->pinentry->path);
2728 client->pinentry->path = g_strdup(value);
2730 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2731 g_free(client->pinentry->title);
2732 client->pinentry->title = g_strdup(value);
2734 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2735 g_free(client->pinentry->prompt);
2736 client->pinentry->prompt = g_strdup(value);
2738 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2739 g_free(client->pinentry->desc);
2740 client->pinentry->desc = g_strdup(value);
2743 * Look at client_thread() to see how this works.
2745 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2746 gchar *p = NULL;
2747 gint n = strtol(value, &p, 10);
2749 if (*p || n < 0)
2750 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2752 client->pinentry->timeout = n;
2754 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2755 gchar *p = NULL;
2756 gint n = strtol(value, &p, 10);
2758 if (*p || n < 0 || n > 1)
2759 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2761 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2763 #endif
2764 else
2765 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2767 log_write("OPTION %s=%s", name, value);
2768 return 0;
2771 gpg_error_t register_commands(assuan_context_t ctx)
2773 static struct {
2774 const gchar *name;
2775 gint (*handler)(assuan_context_t, gchar *line);
2776 } table[] = {
2777 { "OPEN", open_command },
2778 { "SAVE", save_command },
2779 { "LIST", list_command },
2780 { "REALPATH", realpath_command },
2781 { "STORE", store_command },
2782 { "DELETE", delete_command },
2783 { "GET", get_command },
2784 { "ATTR", attr_command },
2785 { "ISCACHED", iscached_command },
2786 { "CLEARCACHE", clearcache_command },
2787 { "CACHETIMEOUT", cachetimeout_command },
2788 { "GETCONFIG", getconfig_command },
2789 { "DUMP", dump_command },
2790 { "XPATH", xpath_command },
2791 { "IMPORT", import_command },
2792 { "LOCK", lock_command },
2793 { "UNLOCK", unlock_command },
2794 { "GETPID", getpid_command },
2795 { "VERSION", version_command },
2796 { "INPUT", NULL },
2797 { "OUTPUT", NULL },
2798 { NULL, NULL }
2800 gint i, rc;
2802 for (i=0; table[i].name; i++) {
2803 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2805 if (rc)
2806 return rc;
2809 rc = assuan_register_bye_notify(ctx, bye_notify);
2811 if (rc)
2812 return rc;
2814 rc = assuan_register_option_handler(ctx, option_handler);
2816 if (rc)
2817 return rc;
2819 rc = assuan_register_reset_notify(ctx, reset_notify);
2821 if (rc)
2822 return rc;
2824 return assuan_register_post_cmd_notify(ctx, command_finalize);
2827 gpg_error_t try_xml_decrypt(assuan_context_t ctx, guchar *key,
2828 struct client_crypto_s *crypto, gpointer *dst, gsize *dst_len)
2830 gsize insize, len;
2831 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2832 guint iter = 0, n_iter = 0, iter_progress = 0;
2833 gint zrc = 0;
2834 gulong outsize = 0;
2835 gpg_error_t rc;
2836 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->fh1) : sizeof(crypto->fh->fh2);
2837 glong fh_iter = crypto->fh->v1 ? crypto->fh->fh1.iter : crypto->fh->fh2.iter;
2839 lseek(crypto->fh->fd, fh_size, SEEK_SET);
2840 insize = crypto->fh->st.st_size - fh_size;
2841 crypto->iv = gcry_malloc(gcryblocksize);
2843 if (!crypto->iv) {
2844 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2845 return gpg_error_from_errno(ENOMEM);
2848 /* No encryption iterations. This is a plain (gzipped) file. */
2849 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0)) {
2851 * cache_file_count() needs both .used == TRUE and a valid key in
2852 * order for it to count as a used cache entry. Fixes CACHE status
2853 * messages.
2855 memset(key, '!', gcrykeysize);
2858 if (crypto->fh->v1)
2859 memcpy(crypto->iv, crypto->fh->fh1.iv, gcryblocksize);
2860 else
2861 memcpy(crypto->iv, crypto->fh->fh2.iv, gcryblocksize);
2863 crypto->inbuf = gcry_malloc(insize);
2865 if (!crypto->inbuf) {
2866 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2867 return gpg_error_from_errno(ENOMEM);
2870 crypto->insize = insize;
2871 len = read(crypto->fh->fd, crypto->inbuf, crypto->insize);
2873 if (len != crypto->insize)
2874 return GPG_ERR_INV_LENGTH;
2876 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0))
2877 goto decompress;
2879 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
2880 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2881 return rc;
2884 if ((rc = gcry_cipher_setkey(crypto->gh, key, gcrykeysize))) {
2885 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2886 return rc;
2889 iter_progress = (guint)get_key_file_integer(client && client->filename ?
2890 client->filename : "global", "iteration_progress");
2892 if (iter_progress > 0 && fh_iter >= iter_progress) {
2893 rc = send_status(ctx, STATUS_DECRYPT, "%u %u", 0, fh_iter);
2895 if (rc)
2896 return rc;
2899 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
2901 if (rc)
2902 return rc;
2904 crypto->tkey = gcry_malloc(gcrykeysize);
2906 if (!crypto->tkey) {
2907 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
2908 return gpg_error_from_errno(ENOMEM);
2911 memcpy(crypto->tkey, key, gcrykeysize);
2912 guchar *tkey = crypto->tkey;
2913 tkey[0] ^= 1;
2915 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
2916 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2917 return rc;
2920 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
2921 if (iter_progress > 0 && iter >= iter_progress) {
2922 if (!(iter % iter_progress)) {
2923 rc = send_status(ctx, STATUS_DECRYPT, "%u %u",
2924 ++n_iter * iter_progress, fh_iter);
2926 if (rc)
2927 return rc;
2931 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
2932 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2933 return rc;
2936 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
2938 if (rc) {
2939 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2940 return rc;
2943 iter++;
2946 if (iter_progress && fh_iter >= iter_progress) {
2947 rc = send_status(ctx, STATUS_DECRYPT, "%u %u", fh_iter, fh_iter);
2949 if (rc)
2950 return rc;
2953 decompress:
2954 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
2955 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
2956 if (zrc == Z_MEM_ERROR)
2957 return gpg_error_from_errno(ENOMEM);
2958 else
2959 return EPWMD_BADKEY; // Not a valid gzip header. Must be a bad key.
2962 if (g_strncasecmp(crypto->outbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2963 gcry_free(crypto->outbuf);
2964 crypto->outbuf = NULL;
2965 return EPWMD_BADKEY;
2968 if (ctx) {
2969 client->xml = crypto->outbuf;
2970 client->len = outsize;
2971 crypto->outbuf = NULL;
2973 else if (dst) {
2974 *dst = crypto->outbuf;
2975 *dst_len = outsize;
2976 crypto->outbuf = NULL;
2979 /* The calling function should free the crypto struct. */
2980 return 0;
2984 * This is called after every Assuan command.
2986 void command_finalize(assuan_context_t ctx, gint rc)
2988 struct client_s *client = assuan_get_pointer(ctx);
2990 if (!client->is_lock_cmd)
2991 unlock_file_mutex(client);