Out of memory check in import_command_finalize().
[pwmd.git] / src / commands.c
blobf67c43abe8164f46e7e43443b514109cb3137e55
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2008 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 02111-1307 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 #ifndef MEM_DEBUG
37 #include "mem.h"
38 #endif
40 #include "xml.h"
41 #include "common.h"
43 #ifdef WITH_PINENTRY
44 #include "pinentry.h"
45 #endif
47 #include "pwmd_error.h"
48 #include "cache.h"
49 #include "misc.h"
50 #include "commands.h"
52 static void *z_alloc(void *data, unsigned items, unsigned size)
54 #ifndef MEM_DEBUG
55 return gcry_calloc(items, size);
56 #else
57 return calloc(items, size);
58 #endif
61 static void z_free(void *data, void *p)
63 #ifndef MEM_DEBUG
64 gcry_free(p);
65 #else
66 free(p);
67 #endif
70 static gpg_error_t file_modified(struct client_s *client)
72 struct stat st;
74 if (client->state != STATE_OPEN)
75 return EPWMD_NO_FILE;
77 if (stat(client->filename, &st) == 0 && client->mtime) {
78 if (client->mtime != st.st_mtime)
79 return EPWMD_FILE_MODIFIED;
82 return 0;
85 static gboolean encrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
86 void *inbuf, gsize insize)
88 gpg_error_t rc;
90 if ((rc = gcry_cipher_encrypt(gh, outbuf, outsize, inbuf, insize))) {
91 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
92 return FALSE;
95 return TRUE;
98 static gpg_error_t decrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
99 void *inbuf, gsize insize)
101 gpg_error_t rc;
103 if ((rc = gcry_cipher_decrypt(gh, outbuf, outsize, inbuf, insize)))
104 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
106 return rc;
109 static gpg_error_t parse_xml(assuan_context_t ctx)
111 struct client_s *client = assuan_get_pointer(ctx);
113 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
115 if (!client->doc)
116 return EPWMD_LIBXML_ERROR;
118 return 0;
121 void unlock_file_mutex(struct client_s *client)
123 pth_mutex_t *m;
125 #ifdef WITH_PINENTRY
126 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
127 #else
128 if (client->has_lock == FALSE)
129 #endif
130 return;
132 CACHE_LOCK(client->ctx);
134 if (cache_get_mutex(client->md5file, &m) == FALSE) {
135 CACHE_UNLOCK;
136 return;
139 CACHE_UNLOCK;
140 pth_mutex_release(m);
141 client->has_lock = FALSE;
144 gpg_error_t lock_file_mutex(struct client_s *client)
146 pth_mutex_t *m;
148 if (client->has_lock == TRUE)
149 return 0;
151 CACHE_LOCK(client->ctx);
153 if (cache_get_mutex(client->md5file, &m) == FALSE) {
154 CACHE_UNLOCK;
155 return 0;
158 CACHE_UNLOCK;
160 if (pth_mutex_acquire(m, TRUE, NULL) == FALSE) {
161 if (errno == EBUSY) {
162 if (client->ctx)
163 assuan_write_status(client->ctx, "LOCKED", N_("Waiting for lock"));
165 pth_mutex_acquire(m, FALSE, NULL);
167 else {
168 gint e = errno;
169 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(errno));
170 return gpg_error_from_errno(e);
174 client->has_lock = TRUE;
175 return 0;
178 void free_client(struct client_s *client)
180 if (client->doc)
181 xmlFreeDoc(client->doc);
183 if (client->xml)
184 gcry_free(client->xml);
186 if (client->filename)
187 g_free(client->filename);
189 if (client->gh)
190 gcry_cipher_close(client->gh);
193 void cleanup_client(struct client_s *client)
195 assuan_context_t ctx = client->ctx;
196 #ifdef WITH_PINENTRY
197 struct pinentry_s *pin = client->pinentry;
198 #endif
200 unlock_file_mutex(client);
201 CACHE_LOCK(client->ctx);
202 cache_decr_refcount(client->md5file);
205 * This may be a new file so don't use a cache slot. save_command() will
206 * set this to FALSE on success.
208 if (client->new == TRUE)
209 cache_clear(client->md5file, 1);
211 free_client(client);
212 memset(client, 0, sizeof(struct client_s));
213 client->state = STATE_CONNECTED;
214 client->ctx = ctx;
215 client->freed = TRUE;
216 #ifdef WITH_PINENTRY
217 client->pinentry = pin;
218 #endif
219 CACHE_UNLOCK;
222 gboolean do_decompress(assuan_context_t ctx, gpointer in, gint insize,
223 gpointer *out, glong *outsize, gint *rc)
225 z_stream z;
226 gpointer pout;
227 gz_header h;
228 gchar buf[17];
229 gchar str[ASSUAN_LINELENGTH];
231 z.zalloc = z_alloc;
232 z.zfree = z_free;
233 z.next_in = in;
234 z.avail_in = insize;
235 z.avail_out = zlib_bufsize;
236 z.next_out = pout = g_malloc(zlib_bufsize);
238 if (!pout) {
239 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
240 *rc = Z_MEM_ERROR;
241 return FALSE;
244 *rc = inflateInit2(&z, 47);
246 if (*rc != Z_OK) {
247 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
248 g_free(pout);
249 return FALSE;
252 memset(&h, 0, sizeof(gz_header));
253 h.comment = (guchar *)buf;
254 h.comm_max = sizeof(buf);
255 *rc = inflateGetHeader(&z, &h);
257 if (*rc != Z_OK) {
258 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
259 g_free(pout);
260 inflateEnd(&z);
261 return FALSE;
264 *rc = inflate(&z, Z_BLOCK);
266 if (*rc != Z_OK) {
267 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
268 g_free(pout);
269 inflateEnd(&z);
270 return FALSE;
273 if (h.comment)
274 insize = atoi((gchar *)h.comment);
276 do {
277 gpointer p;
279 *rc = inflate(&z, Z_FINISH);
281 switch (*rc) {
282 case Z_OK:
283 break;
284 case Z_BUF_ERROR:
285 if (!z.avail_out) {
286 p = g_realloc(pout, z.total_out + zlib_bufsize);
288 if (!p) {
289 *rc = Z_MEM_ERROR;
290 goto fail;
293 pout = p;
294 z.next_out = pout + z.total_out;
295 z.avail_out = zlib_bufsize;
297 if (ctx) {
298 *rc = assuan_write_status(ctx, "DECOMPRESS",
299 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
301 if (*rc)
302 goto fail;
305 break;
306 case Z_STREAM_END:
307 break;
308 default:
309 goto fail;
310 break;
313 pth_yield(NULL);
314 } while (*rc != Z_STREAM_END);
316 if (ctx) {
317 *rc = assuan_write_status(ctx, "DECOMPRESS",
318 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
320 if (*rc)
321 goto fail;
324 *out = pout;
325 *outsize = z.total_out;
326 inflateEnd(&z);
327 *rc = 0;
328 return TRUE;
330 fail:
331 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
332 g_free(pout);
333 inflateEnd(&z);
334 return FALSE;
337 gpg_error_t read_file_header(const gchar *filename, file_header_t *fh)
339 gint fd;
340 gsize len;
342 fd = open(filename, O_RDONLY);
344 if (fd == -1)
345 return gpg_error_from_errno(errno);
347 len = pth_read(fd, fh, sizeof(file_header_t));
348 close(fd);
350 if (len != sizeof(file_header_t))
351 return gpg_error_from_errno(errno);
353 return 0;
356 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar shakey[],
357 gboolean cached)
359 struct client_s *client = assuan_get_pointer(ctx);
360 gpg_error_t rc;
361 struct stat st;
362 gint fd;
363 gint timeout;
365 if ((fd = open_file(client->filename, &st)) == -1) {
366 /* New file. */
367 if (errno == ENOENT) {
368 if (shakey[0])
369 goto update_cache;
371 goto done;
374 rc = errno;
375 log_write("%s: %s", client->filename, strerror(errno));
376 cleanup_client(client);
377 memset(shakey, 0, sizeof(shakey));
378 return send_syserror(ctx, rc);
381 rc = try_xml_decrypt(ctx, fd, st, shakey);
382 close(fd);
384 if (rc) {
385 memset(shakey, 0, sizeof(shakey));
386 cleanup_client(client);
387 return send_error(ctx, rc);
390 update_cache:
391 CACHE_LOCK(client->ctx);
393 if (cached == FALSE) {
394 if (cache_update_key(client->md5file, shakey) == FALSE) {
395 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
396 cleanup_client(client);
397 CACHE_UNLOCK;
398 return send_error(ctx, EPWMD_MAX_SLOTS);
401 timeout = get_key_file_integer(client->filename, "cache_timeout");
402 cache_reset_timeout(client->md5file, timeout);
404 else
405 cache_set_timeout(client->md5file, -2);
407 CACHE_UNLOCK;
409 done:
410 memset(shakey, 0, sizeof(shakey));
411 rc = parse_xml(ctx);
413 if (client->xml) {
414 gcry_free(client->xml);
415 client->xml = NULL;
418 if (!rc) {
419 if (client->new == FALSE)
420 send_cache_status_all();
422 client->state = STATE_OPEN;
425 return send_error(ctx, rc);
428 static int open_command(assuan_context_t ctx, char *line)
430 struct stat st;
431 guchar shakey[gcrykeysize];
432 gboolean cached = FALSE;
433 gpg_error_t rc;
434 struct client_s *client = assuan_get_pointer(ctx);
435 gchar **req;
436 gchar *filename = NULL;
437 file_header_t file_header;
439 memset(shakey, 0, sizeof(shakey));
441 if ((req = split_input_line(line, " ", 2)) != NULL)
442 filename = req[0];
444 if (!filename || !*filename) {
445 g_strfreev(req);
446 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
449 if (valid_filename(filename) == FALSE) {
450 g_strfreev(req);
451 return send_error(ctx, EPWMD_INVALID_FILENAME);
454 if (client->state == STATE_OPEN)
455 cleanup_client(client);
457 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
458 CACHE_LOCK(client->ctx);
460 if (cache_has_file(client->md5file) == FALSE) {
461 if (cache_add_file(client->md5file, NULL) == FALSE) {
462 g_strfreev(req);
463 CACHE_UNLOCK;
464 return send_error(ctx, EPWMD_MAX_SLOTS);
468 cache_incr_refcount(client->md5file);
469 CACHE_UNLOCK;
470 rc = lock_file_mutex(client);
472 if (rc) {
473 g_strfreev(req);
474 return send_error(ctx, rc);
477 client->freed = FALSE;
479 if ((rc = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
480 g_strfreev(req);
481 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
482 cleanup_client(client);
483 return send_error(ctx, rc);
486 if (stat(filename, &st) == 0) {
487 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
488 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
489 g_strfreev(req);
490 cleanup_client(client);
491 return send_error(ctx, EPWMD_INVALID_FILENAME);
494 client->mtime = st.st_mtime;
497 client->filename = g_strdup(filename);
499 if (!client->filename) {
500 memset(shakey, 0, sizeof(shakey));
501 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
502 cleanup_client(client);
503 g_strfreev(req);
504 return send_syserror(ctx, ENOMEM);
507 #ifdef WITH_PINENTRY
508 client->pinentry->filename = g_strdup(client->filename);
510 if (!client->pinentry->filename) {
511 memset(shakey, 0, sizeof(shakey));
512 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
513 cleanup_client(client);
514 g_strfreev(req);
515 return send_syserror(ctx, ENOMEM);
517 #endif
520 * New files don't need a key.
522 if (access(filename, R_OK) != 0) {
523 if (errno != ENOENT) {
524 rc = errno;
525 log_write("%s: %s", filename, strerror(errno));
526 g_strfreev(req);
527 cleanup_client(client);
528 return send_syserror(ctx, rc);
531 if ((client->xml = new_document()) == NULL) {
532 log_write("%s", strerror(ENOMEM));
533 g_strfreev(req);
534 cleanup_client(client);
535 return send_syserror(ctx, ENOMEM);
538 client->len = xmlStrlen(client->xml);
539 client->new = TRUE;
540 client->filename = g_strdup(filename);
542 if (!client->filename) {
543 g_strfreev(req);
544 cleanup_client(client);
545 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
546 return send_syserror(ctx, ENOMEM);
549 memset(shakey, 0, sizeof(shakey));
551 if (req[1] && *req[1])
552 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
554 g_strfreev(req);
555 return open_command_finalize(ctx, shakey, cached);
558 rc = read_file_header(filename, &file_header);
560 if (rc) {
561 g_strfreev(req);
562 cleanup_client(client);
563 return send_error(ctx, rc);
566 if (file_header.iter == -1)
567 goto done;
569 CACHE_LOCK(client->ctx);
570 cached = cache_get_key(client->md5file, shakey);
571 CACHE_UNLOCK;
573 if (cached == FALSE) {
575 * No key specified and no matching filename found in the cache. Use
576 * pinentry to retrieve the key. Cannot return assuan_process_done()
577 * here otherwise the command will be interrupted. The event loop in
578 * client_thread() will poll the file descriptor waiting for it to
579 * become ready to read a pinentry_key_s which will contain the
580 * entered key or rc. It will then call open_command_finalize() to
581 * to finish the command.
583 if (!req[1] || !*req[1]) {
584 #ifdef WITH_PINENTRY
585 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
587 /* From set_pinentry_defaults(). */
588 if (client->pinentry->enable == FALSE ||
589 (client->pinentry->enable == -1 && b == FALSE)) {
590 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
591 goto done;
594 g_strfreev(req);
595 lock_pin_mutex(client);
596 client->pinentry->which = PINENTRY_OPEN;
597 rc = pinentry_fork(ctx);
599 if (rc) {
600 unlock_pin_mutex(client->pinentry);
601 cleanup_client(client);
602 return send_error(ctx, rc);
605 client->pinentry->cb = open_command_finalize;
606 client->pinentry->status = PINENTRY_INIT;
607 return 0;
608 #else
609 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
610 goto done;
611 #endif
614 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
617 done:
618 g_strfreev(req);
619 return open_command_finalize(ctx, shakey, cached);
622 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
623 gint size, gpointer *out, glong *outsize, gint *rc)
625 z_stream z;
626 gpointer pout, pin;
627 gz_header h;
628 gchar buf[17];
629 gint cmd = Z_NO_FLUSH;
630 gchar str[ASSUAN_LINELENGTH];
632 z.zalloc = z_alloc;
633 z.zfree = z_free;
634 z.next_in = pin = data;
635 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
636 z.avail_out = zlib_bufsize;
637 z.next_out = pout = g_malloc(zlib_bufsize);
639 if (!pout) {
640 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
641 *rc = Z_MEM_ERROR;
642 return FALSE;
645 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
647 if (*rc != Z_OK) {
648 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
649 g_free(pout);
650 return FALSE;
653 memset(&h, 0, sizeof(gz_header));
654 g_snprintf(buf, sizeof(buf), "%i", size);
655 h.comment = (guchar *)buf;
656 *rc = deflateSetHeader(&z, &h);
658 if (*rc != Z_OK) {
659 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
660 g_free(pout);
661 deflateEnd(&z);
662 return FALSE;
665 do {
666 gpointer p;
668 *rc = deflate(&z, cmd);
670 switch (*rc) {
671 case Z_OK:
672 break;
673 case Z_BUF_ERROR:
674 if (!z.avail_out) {
675 p = g_realloc(pout, z.total_out + zlib_bufsize);
677 if (!p) {
678 *rc = Z_MEM_ERROR;
679 goto fail;
682 pout = p;
683 z.next_out = pout + z.total_out;
684 z.avail_out = zlib_bufsize;
687 if (!z.avail_in && z.total_in < size) {
688 if (z.total_in + zlib_bufsize > size)
689 z.avail_in = size - z.total_in;
690 else
691 z.avail_in = zlib_bufsize;
693 if (ctx) {
694 *rc = assuan_write_status(ctx, "COMPRESS",
695 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
697 if (*rc)
698 goto fail;
702 if (z.total_in >= size)
703 cmd = Z_FINISH;
705 break;
706 case Z_STREAM_END:
707 break;
708 default:
709 goto fail;
712 pth_yield(NULL);
713 } while (*rc != Z_STREAM_END);
715 if (ctx) {
716 *rc = assuan_write_status(ctx, "COMPRESS",
717 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
719 if (*rc)
720 goto fail;
723 *out = pout;
724 *outsize = z.total_out;
725 deflateEnd(&z);
726 *rc = 0;
727 return TRUE;
729 fail:
730 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
731 g_free(pout);
732 deflateEnd(&z);
733 return FALSE;
736 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
737 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
738 gint iter)
740 gsize len = insize;
741 gint fd;
742 gpointer inbuf;
743 guchar tkey[gcrykeysize];
744 gchar *p;
745 gpg_error_t rc;
746 guint iter_progress = 0, n_iter = 0, xiter = 0;
747 gchar tmp[FILENAME_MAX];
748 struct stat st;
749 mode_t mode = 0;
750 file_header_t file_header;
751 gchar str[ASSUAN_LINELENGTH];
753 if (iter == -1) {
755 * cache_file_count() needs both .used == TRUE and a valid key in
756 * order for it to count as a used cache entry. Fixes CACHE status
757 * messages.
759 memset(shakey, '!', gcrykeysize);
760 inbuf = data;
761 file_header.iter = iter;
762 goto write_file;
765 if (insize / gcryblocksize) {
766 len = (insize / gcryblocksize) * gcryblocksize;
768 if (insize % gcryblocksize)
769 len += gcryblocksize;
773 * Resize the existing xml buffer to the block size required by gcrypt
774 * rather than duplicating it and wasting memory.
776 inbuf = gcry_realloc(data, len);
778 if (!inbuf)
779 return gpg_error_from_errno(ENOMEM);
781 insize = len;
782 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
783 memcpy(tkey, shakey, sizeof(tkey));
784 tkey[0] ^= 1;
786 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
787 gcry_free(inbuf);
788 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
789 return rc;
792 file_header.iter = iter;
794 if (client)
795 iter_progress = get_key_file_integer("global", "iteration_progress");
797 if (client && iter_progress && file_header.iter >= iter_progress) {
798 rc = assuan_write_status(client->ctx, "ENCRYPT", "0");
800 if (rc) {
801 gcry_free(inbuf);
802 return rc;
806 while (xiter < file_header.iter) {
807 if (client && iter_progress > 0 && xiter >= iter_progress) {
808 if (!(xiter % iter_progress)) {
809 rc = assuan_write_status(client->ctx, "ENCRYPT",
810 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
812 if (rc) {
813 gcry_free(inbuf);
814 return rc;
819 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
820 sizeof(file_header.iv)))) {
821 gcry_free(inbuf);
822 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
823 return rc;
826 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
827 == FALSE) {
828 gcry_free(inbuf);
829 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
830 return rc;
833 xiter++;
834 pth_yield(NULL);
837 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
838 sizeof(file_header.iv)))) {
839 gcry_free(inbuf);
840 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
841 return rc;
844 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
845 gcry_free(inbuf);
846 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
847 return rc;
850 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
851 gcry_free(inbuf);
852 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
853 return rc;
856 if (client && iter_progress && file_header.iter >= iter_progress) {
857 rc = assuan_write_status(client->ctx, "ENCRYPT",
858 print_fmt(str, sizeof(str), "%i", file_header.iter));
860 if (rc) {
861 gcry_free(inbuf);
862 return rc;
866 write_file:
867 if (filename) {
868 if (stat(filename, &st) == 0) {
869 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
872 * FIXME What if the file has an ACL?
874 if (!(mode & S_IWUSR)) {
875 gcry_free(inbuf);
876 return gpg_error_from_errno(EACCES);
879 else {
880 if (errno != ENOENT) {
881 rc = errno;
882 gcry_free(inbuf);
883 return gpg_error_from_errno(rc);
887 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
889 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
890 rc = errno;
891 gcry_free(inbuf);
892 p = strrchr(tmp, '/');
893 p++;
894 log_write("%s: %s", p, strerror(rc));
895 return gpg_error_from_errno(rc);
898 else
900 * xml_import() from command line.
902 fd = STDOUT_FILENO;
904 len = pth_write(fd, &file_header, sizeof(file_header_t));
906 if (len != sizeof(file_header)) {
907 len = errno;
909 if (filename) {
910 close(fd);
911 unlink(tmp);
914 gcry_free(inbuf);
915 return gpg_error_from_errno(len);
918 len = pth_write(fd, inbuf, insize);
920 if (len != insize) {
921 len = errno;
923 if (filename) {
924 close(fd);
925 unlink(tmp);
928 gcry_free(inbuf);
929 return gpg_error_from_errno(len);
932 if (fsync(fd) == -1) {
933 len = errno;
935 if (filename) {
936 close(fd);
937 unlink(tmp);
940 gcry_free(inbuf);
941 return gpg_error_from_errno(len);
944 if (filename) {
945 close(fd);
947 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
948 gchar tmp2[FILENAME_MAX];
950 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
952 if (rename(filename, tmp2) == -1) {
953 unlink(tmp);
954 len = errno;
955 gcry_free(inbuf);
956 return gpg_error_from_errno(len);
960 if (rename(tmp, filename) == -1) {
961 len = errno;
962 unlink(tmp);
963 gcry_free(inbuf);
964 return gpg_error_from_errno(len);
967 if (mode)
968 chmod(filename, mode);
971 gcry_free(inbuf);
972 return 0;
975 static gpg_error_t save_command_finalize(assuan_context_t ctx,
976 guchar shakey[], gboolean cached)
978 struct client_s *client = assuan_get_pointer(ctx);
979 gpointer xmlbuf;
980 xmlChar *p;
981 gint len;
982 gint iter;
983 gint timeout;
984 gpointer outbuf;
985 glong outsize = 0;
986 gint zrc;
987 gpg_error_t rc;
988 struct stat st;
990 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
991 xmlbuf = p;
993 iter = get_key_file_integer(client->filename, "compression_level");
995 if (iter < 0)
996 iter = 0;
998 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
999 memset(shakey, 0, sizeof(shakey));
1000 xmlFree(xmlbuf);
1002 if (zrc == Z_MEM_ERROR) {
1003 return send_syserror(ctx, ENOMEM);
1005 else
1006 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1008 else {
1009 gcry_free(xmlbuf);
1010 xmlbuf = outbuf;
1011 len = outsize;
1014 iter = get_key_file_integer(client->filename, "iterations");
1015 rc = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1017 if (rc) {
1018 memset(shakey, 0, sizeof(shakey));
1019 return send_error(ctx, rc);
1022 stat(client->filename, &st);
1023 client->mtime = st.st_mtime;
1024 timeout = get_key_file_integer(client->filename, "cache_timeout");
1025 CACHE_LOCK(client->ctx);
1027 if (cached) {
1028 memset(shakey, 0, sizeof(shakey));
1029 cache_reset_timeout(client->md5file, timeout);
1030 CACHE_UNLOCK;
1032 if (client->new == TRUE)
1033 send_cache_status_all();
1035 client->new = FALSE;
1036 return send_error(ctx, 0);
1039 if (cache_update_key(client->md5file, shakey) == FALSE) {
1040 memset(shakey, 0, sizeof(shakey));
1041 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1042 CACHE_UNLOCK;
1043 return send_error(ctx, EPWMD_MAX_SLOTS);
1046 client->new = FALSE;
1047 memset(shakey, 0, sizeof(shakey));
1048 cache_reset_timeout(client->md5file, timeout);
1049 CACHE_UNLOCK;
1050 send_cache_status_all();
1051 return send_error(ctx, 0);
1054 static int save_command(assuan_context_t ctx, char *line)
1056 gboolean cached = FALSE;
1057 guchar shakey[gcrykeysize];
1058 struct stat st;
1059 struct client_s *client = assuan_get_pointer(ctx);
1060 gpg_error_t rc;
1062 memset(shakey, 0, sizeof(shakey));
1063 rc = file_modified(client);
1065 if (rc) {
1066 log_write("%s: %s", client->filename ? client->filename : "",
1067 pwmd_strerror(rc));
1068 return send_error(ctx, rc);
1071 rc = lock_file_mutex(client);
1073 if (rc)
1074 return send_error(ctx, rc);
1076 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1077 return send_syserror(ctx, errno);
1079 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1080 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1081 return send_error(ctx, EPWMD_INVALID_FILENAME);
1084 if (get_key_file_integer(client->filename, "iterations") == -1)
1085 goto done;
1087 if (!line || !*line) {
1088 guchar tmp[sizeof(shakey)];
1089 CACHE_LOCK(ctx);
1091 memset(tmp, '!', sizeof(tmp));
1093 if (cache_get_key(client->md5file, shakey) == FALSE ||
1094 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1095 CACHE_UNLOCK;
1096 #ifdef WITH_PINENTRY
1097 if (get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1098 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1099 goto done;
1102 lock_pin_mutex(client);
1103 client->pinentry->which = PINENTRY_SAVE;
1104 rc = pinentry_fork(ctx);
1106 if (rc) {
1107 unlock_pin_mutex(client->pinentry);
1108 return send_error(ctx, rc);
1111 client->pinentry->cb = save_command_finalize;
1112 client->pinentry->status = PINENTRY_INIT;
1113 return 0;
1114 #else
1115 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1116 goto done;
1117 #endif
1119 else {
1120 CACHE_UNLOCK;
1121 cached = TRUE;
1124 else {
1125 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1126 memset(line, 0, strlen(line));
1129 done:
1130 return save_command_finalize(ctx, shakey, cached);
1133 static int delete_command(assuan_context_t ctx, char *line)
1135 struct client_s *client = assuan_get_pointer(ctx);
1136 gchar **req;
1137 gpg_error_t rc;
1138 xmlNodePtr n;
1140 rc = file_modified(client);
1142 if (rc) {
1143 log_write("%s: %s", client->filename ? client->filename : "",
1144 pwmd_strerror(rc));
1145 return send_error(ctx, rc);
1148 if (strchr(line, '\t'))
1149 req = split_input_line(line, "\t", -1);
1150 else
1151 req = split_input_line(line, " ", -1);
1153 if (!req || !*req)
1154 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1156 n = find_account(client->doc, &req, &rc, NULL, 0);
1158 if (!n) {
1159 g_strfreev(req);
1160 return send_error(ctx, rc);
1164 * No sub-node defined. Remove the entire node (account).
1166 if (!req[1]) {
1167 if (n) {
1168 xmlUnlinkNode(n);
1169 xmlFreeNode(n);
1172 g_strfreev(req);
1173 return send_error(ctx, 0);
1176 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1177 g_strfreev(req);
1179 if (!n)
1180 return send_error(ctx, rc);
1182 if (n) {
1183 xmlUnlinkNode(n);
1184 xmlFreeNode(n);
1187 return send_error(ctx, 0);
1191 * Don't return with assuan_process_done() here. This has been called from
1192 * assuan_process_next() and the command should be finished in
1193 * client_thread().
1195 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1196 gsize len)
1198 assuan_context_t ctx = data;
1199 struct client_s *client = assuan_get_pointer(ctx);
1200 gchar **req;
1201 xmlNodePtr n;
1202 gpg_error_t rc = file_modified(client);
1204 if (assuan_rc || rc) {
1205 if (line)
1206 #ifndef MEM_DEBUG
1207 xfree(line);
1208 #else
1209 free(line);
1210 #endif
1211 return assuan_rc ? assuan_rc : rc;
1214 req = split_input_line((gchar *)line, "\t", 0);
1215 #ifndef MEM_DEBUG
1216 xfree(line);
1217 #else
1218 free(line);
1219 #endif
1221 if (!req || !*req)
1222 return EPWMD_COMMAND_SYNTAX;
1224 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1225 g_strfreev(req);
1226 return EPWMD_INVALID_ELEMENT;
1229 if (valid_element_path(req+1, TRUE) == FALSE) {
1230 g_strfreev(req);
1231 return EPWMD_INVALID_ELEMENT;
1234 again:
1235 n = find_account(client->doc, &req, &rc, NULL, 0);
1237 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1238 rc = new_account(client->doc, *req);
1240 if (rc) {
1241 g_strfreev(req);
1242 return rc;
1245 goto again;
1248 if (!n) {
1249 g_strfreev(req);
1250 return rc;
1253 if (req[1]) {
1254 if (!n->children)
1255 create_elements_cb(n, req+1, &rc, NULL);
1256 else
1257 find_elements(client->doc, n->children, req+1, &rc,
1258 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1261 g_strfreev(req);
1262 client->inquire_status = INQUIRE_DONE;
1263 return rc;
1266 static int store_command(assuan_context_t ctx, char *line)
1268 struct client_s *client = assuan_get_pointer(ctx);
1269 gpg_error_t rc = file_modified(client);
1271 if (rc) {
1272 log_write("%s: %s", client->filename ? client->filename : "",
1273 pwmd_strerror(rc));
1274 return send_error(ctx, rc);
1277 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1279 if (rc)
1280 return send_error(ctx, rc);
1282 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1283 client->inquire_status = INQUIRE_BUSY;
1284 return 0;
1287 static int get_command(assuan_context_t ctx, char *line)
1289 struct client_s *client = assuan_get_pointer(ctx);
1290 gchar **req;
1291 gpg_error_t rc;
1292 xmlNodePtr n;
1294 rc = file_modified(client);
1296 if (rc) {
1297 log_write("%s: %s", client->filename ? client->filename : "",
1298 pwmd_strerror(rc));
1299 return send_error(ctx, rc);
1302 req = split_input_line(line, "\t", -1);
1304 if (!req || !*req) {
1305 g_strfreev(req);
1306 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1309 n = find_account(client->doc, &req, &rc, NULL, 0);
1311 if (!n) {
1312 g_strfreev(req);
1313 return send_error(ctx, rc);
1316 if (req[1])
1317 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1319 g_strfreev(req);
1321 if (rc)
1322 return send_error(ctx, rc);
1324 if (!n || !n->children)
1325 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1327 n = find_text_node(n->children);
1329 if (!n || !n->content || !*n->content)
1330 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1332 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1333 return send_error(ctx, rc);
1336 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1337 gpg_error_t *rc, gchar **req_orig, void *data)
1339 gchar *path = *(gchar **)data;
1340 gchar *tmp = NULL, *result;
1342 if (path) {
1343 g_free(path);
1344 *(gchar **)data = NULL;
1347 path = g_strjoinv("\t", target);
1349 if (!path) {
1350 *rc = gpg_error_from_errno(ENOMEM);
1351 return NULL;
1354 if (req_orig) {
1355 tmp = g_strjoinv("\t", req_orig);
1357 if (!tmp) {
1358 g_free(path);
1359 *rc = gpg_error_from_errno(ENOMEM);
1360 return NULL;
1364 if (tmp && *tmp)
1365 result = g_strdup_printf("%s\t%s", path, tmp);
1366 else
1367 result = g_strdup(path);
1369 if (!result) {
1370 *rc = gpg_error_from_errno(ENOMEM);
1371 g_free(path);
1372 g_free(tmp);
1373 return NULL;
1376 g_free(path);
1377 g_free(tmp);
1378 *(gchar **)data = result;
1379 return node;
1382 static int realpath_command(assuan_context_t ctx, char *line)
1384 gpg_error_t rc;
1385 struct client_s *client = assuan_get_pointer(ctx);
1386 gchar **req;
1387 gchar *t;
1388 gint i;
1389 xmlNodePtr n;
1390 GString *string;
1391 gchar *rp = NULL;
1393 rc = file_modified(client);
1395 if (rc) {
1396 log_write("%s: %s", client->filename ? client->filename : "",
1397 pwmd_strerror(rc));
1398 return send_error(ctx, rc);
1401 if (strchr(line, '\t') != NULL) {
1402 if ((req = split_input_line(line, "\t", 0)) == NULL)
1403 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1405 else {
1406 if ((req = split_input_line(line, " ", 0)) == NULL)
1407 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1410 n = find_account(client->doc, &req, &rc, NULL, 0);
1412 if (!n) {
1413 g_strfreev(req);
1414 return send_error(ctx, rc);
1417 rp = g_strjoinv("\t", req);
1419 if (!rp) {
1420 g_strfreev(req);
1421 return send_syserror(ctx, ENOMEM);
1424 if (req[1]) {
1425 n = find_elements(client->doc, n->children, req+1, &rc,
1426 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1428 if (!n) {
1429 g_free(rp);
1430 g_strfreev(req);
1431 return send_error(ctx, rc);
1435 string = g_string_new(rp);
1436 g_free(rp);
1437 g_strfreev(req);
1439 if (!string)
1440 return send_syserror(ctx, ENOMEM);
1442 again:
1443 for (i = 0, t = string->str + i; *t; t++, i++) {
1444 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1445 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1446 goto again;
1450 rc = assuan_send_data(ctx, string->str, string->len);
1451 g_string_free(string, TRUE);
1452 return send_error(ctx, rc);
1455 static int list_command(assuan_context_t ctx, char *line)
1457 struct client_s *client = assuan_get_pointer(ctx);
1458 gpg_error_t rc;
1459 struct element_list_s *elements = NULL;
1460 gchar *tmp;
1462 if (disable_list_and_dump == TRUE)
1463 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1465 rc = file_modified(client);
1467 if (rc) {
1468 log_write("%s: %s", client->filename, pwmd_strerror(rc));
1469 return send_error(ctx, rc);
1472 if (!*line) {
1473 GString *str;
1475 rc = list_accounts(client->doc, &str);
1477 if (rc)
1478 return send_error(ctx, rc);
1480 rc = assuan_send_data(ctx, str->str, str->len);
1481 g_string_free(str, TRUE);
1482 return send_error(ctx, rc);
1485 elements = g_malloc0(sizeof(struct element_list_s));
1487 if (!elements) {
1488 rc = gpg_err_code_from_errno(ENOMEM);
1489 goto fail;
1492 rc = create_path_list(client->doc, elements, line);
1494 if (rc)
1495 goto fail;
1497 if (elements) {
1498 gint total = g_slist_length(elements->list);
1499 gint i;
1500 GString *str;
1502 if (!total) {
1503 rc = EPWMD_EMPTY_ELEMENT;
1504 goto fail;
1507 str = g_string_new(NULL);
1509 if (!str) {
1510 rc = gpg_err_code_from_errno(ENOMEM);
1511 goto fail;
1514 for (i = 0; i < total; i++) {
1515 tmp = g_slist_nth_data(elements->list, i);
1516 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1519 rc = assuan_send_data(ctx, str->str, str->len);
1520 g_string_free(str, TRUE);
1522 else
1523 rc = EPWMD_EMPTY_ELEMENT;
1525 fail:
1526 if (elements) {
1527 gint total = g_slist_length(elements->list);
1528 gint i;
1530 for (i = 0; i < total; i++) {
1531 tmp = g_slist_nth_data(elements->list, i);
1532 g_free(tmp);
1535 g_slist_free(elements->list);
1537 if (elements->prefix)
1538 g_free(elements->prefix);
1540 g_free(elements);
1543 return send_error(ctx, rc);
1546 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1547 const gchar *value)
1549 xmlAttrPtr a;
1551 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1552 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1554 if (!a)
1555 return EPWMD_LIBXML_ERROR;
1557 else
1558 xmlNodeSetContent(a->children, (xmlChar *)value);
1560 return 0;
1564 * req[0] - element path
1566 static int attribute_list(assuan_context_t ctx, gchar **req)
1568 struct client_s *client = assuan_get_pointer(ctx);
1569 gchar **attrlist = NULL;
1570 gint i = 0;
1571 gchar **path = NULL;
1572 xmlAttrPtr a;
1573 xmlNodePtr n, an;
1574 gchar *line;
1575 gpg_error_t rc;
1577 if (!req || !req[0])
1578 return EPWMD_COMMAND_SYNTAX;
1580 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1582 * The first argument may be only an account.
1584 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1585 return EPWMD_COMMAND_SYNTAX;
1588 n = find_account(client->doc, &path, &rc, NULL, 0);
1590 if (!n) {
1591 g_strfreev(path);
1592 return rc;
1595 if (path[1]) {
1596 n = find_elements(client->doc, n->children, path+1, &rc,
1597 NULL, NULL, NULL, FALSE, 0, NULL);
1599 if (!n) {
1600 g_strfreev(path);
1601 return rc;
1605 g_strfreev(path);
1607 for (a = n->properties; a; a = a->next) {
1608 gchar **pa;
1610 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1611 if (attrlist)
1612 g_strfreev(attrlist);
1614 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1615 return gpg_error_from_errno(ENOMEM);
1618 attrlist = pa;
1619 an = a->children;
1620 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1622 if (!attrlist[i]) {
1623 g_strfreev(attrlist);
1624 return gpg_error_from_errno(ENOMEM);
1627 attrlist[++i] = NULL;
1630 if (!attrlist)
1631 return EPWMD_EMPTY_ELEMENT;
1633 line = g_strjoinv("\n", attrlist);
1635 if (!line) {
1636 g_strfreev(attrlist);
1637 return gpg_error_from_errno(ENOMEM);
1640 rc = assuan_send_data(ctx, line, strlen(line));
1641 g_free(line);
1642 g_strfreev(attrlist);
1643 return rc;
1647 * req[0] - attribute
1648 * req[1] - element path
1650 static int attribute_delete(struct client_s *client, gchar **req)
1652 xmlAttrPtr a;
1653 xmlNodePtr n;
1654 gchar **path = NULL;
1655 gpg_error_t rc;
1657 if (!req || !req[0] || !req[1])
1658 return EPWMD_COMMAND_SYNTAX;
1660 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1662 * The first argument may be only an account.
1664 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1665 return EPWMD_COMMAND_SYNTAX;
1669 * Don't remove the "name" attribute for the account element. To remove an
1670 * account use DELETE <account>.
1672 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1673 rc = EPWMD_ATTR_SYNTAX;
1674 goto fail;
1677 n = find_account(client->doc, &path, &rc, NULL, 0);
1679 if (!n)
1680 goto fail;
1682 if (path[1]) {
1683 n = find_elements(client->doc, n->children, path+1, &rc,
1684 NULL, NULL, NULL, FALSE, 0, NULL);
1686 if (!n)
1687 goto fail;
1690 g_strfreev(path);
1692 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1693 return EPWMD_ATTR_NOT_FOUND;
1695 if (xmlRemoveProp(a) == -1)
1696 return EPWMD_LIBXML_ERROR;
1698 return 0;
1700 fail:
1701 g_strfreev(path);
1702 return rc;
1705 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1706 gpg_error_t *rc)
1708 gchar **src = *path;
1709 gchar **src_orig = g_strdupv(src);
1710 xmlNodePtr n = NULL;
1712 *rc = 0;
1714 if (!src_orig) {
1715 *rc = gpg_error_from_errno(ENOMEM);
1716 goto fail;
1719 again:
1720 n = find_account(client->doc, &src, rc, NULL, 0);
1722 if (!n) {
1723 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1724 *rc = new_account(client->doc, src[0]);
1726 if (*rc)
1727 goto fail;
1729 goto again;
1731 else
1732 goto fail;
1735 if (src[1]) {
1736 if (!n->children)
1737 n = create_target_elements_cb(n, src+1, rc, NULL);
1738 else
1739 n = find_elements(client->doc, n->children, src+1, rc,
1740 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1742 if (!n)
1743 goto fail;
1746 * Reset the position of the element tree now that the elements
1747 * have been created.
1749 g_strfreev(src);
1750 src = src_orig;
1751 src_orig = NULL;
1752 n = find_account(client->doc, &src, rc, NULL, 0);
1754 if (!n)
1755 goto fail;
1757 n = find_elements(client->doc, n->children, src+1, rc,
1758 NULL, NULL, NULL, FALSE, 0, NULL);
1760 if (!n)
1761 goto fail;
1764 fail:
1765 if (src_orig)
1766 g_strfreev(src_orig);
1768 *path = src;
1769 return n;
1773 * Creates a "target" attribute. When other commands encounter an element with
1774 * this attribute, the element path is modified to the target value. If the
1775 * source element path doesn't exist when using 'ATTR SET target', it is
1776 * created, but the destination element path must exist.
1778 * req[0] - source element path
1779 * req[1] - destination element path
1781 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1783 gchar **src, **dst, *line = NULL;
1784 gpg_error_t rc;
1785 xmlNodePtr n;
1787 if (!req || !req[0] || !req[1])
1788 return EPWMD_COMMAND_SYNTAX;
1790 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1792 * The first argument may be only an account.
1794 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1795 return EPWMD_COMMAND_SYNTAX;
1798 if (valid_element_path(src, FALSE) == FALSE) {
1799 g_strfreev(src);
1800 return EPWMD_INVALID_ELEMENT;
1803 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1805 * The first argument may be only an account.
1807 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1808 rc = EPWMD_COMMAND_SYNTAX;
1809 goto fail;
1813 n = find_account(client->doc, &dst, &rc, NULL, 0);
1816 * Make sure the destination element path exists.
1818 if (!n)
1819 goto fail;
1821 if (dst[1]) {
1822 n = find_elements(client->doc, n->children, dst+1, &rc,
1823 NULL, NULL, NULL, FALSE, 0, NULL);
1825 if (!n)
1826 goto fail;
1829 n = create_element_path(client, &src, &rc);
1831 if (rc)
1832 goto fail;
1834 line = g_strjoinv("\t", dst);
1836 if (!line) {
1837 rc = gpg_error_from_errno(ENOMEM);
1838 goto fail;
1841 rc = add_attribute(n, "target", line);
1843 fail:
1844 g_free(line);
1845 g_strfreev(src);
1846 g_strfreev(dst);
1847 return rc;
1851 * req[0] - account name
1852 * req[1] - new name
1854 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
1856 gpg_error_t rc;
1857 gchar **tmp;
1858 xmlNodePtr n;
1860 tmp = g_strdupv(req);
1862 if (!tmp)
1863 return gpg_error_from_errno(ENOMEM);
1865 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1866 g_strfreev(tmp);
1868 if (!n)
1869 return rc;
1871 if (g_utf8_collate(req[0], req[1]) == 0)
1872 return 0;
1875 * Will not overwrite an existing account.
1877 tmp = g_strdupv(req+1);
1879 if (!tmp)
1880 return gpg_error_from_errno(ENOMEM);
1882 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1883 g_strfreev(tmp);
1885 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
1886 return rc;
1888 if (n)
1889 return EPWMD_ACCOUNT_EXISTS;
1892 * Whitespace not allowed in account names.
1894 if (contains_whitespace(req[1]) == TRUE)
1895 return EPWMD_ATTR_SYNTAX;
1897 tmp = g_strdupv(req);
1899 if (!tmp)
1900 return gpg_error_from_errno(ENOMEM);
1902 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1903 g_strfreev(tmp);
1905 if (!n)
1906 return EPWMD_ELEMENT_NOT_FOUND;
1908 return add_attribute(n, "name", req[1]);
1912 * req[0] - attribute
1913 * req[1] - element path
1915 static int attribute_get(assuan_context_t ctx, gchar **req)
1917 struct client_s *client = assuan_get_pointer(ctx);
1918 xmlNodePtr n;
1919 xmlChar *a;
1920 gchar **path= NULL;
1921 gpg_error_t rc;
1923 if (!req || !req[0] || !req[1])
1924 return EPWMD_COMMAND_SYNTAX;
1926 if (strchr(req[1], '\t')) {
1927 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
1928 return EPWMD_COMMAND_SYNTAX;
1930 else {
1931 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1932 return EPWMD_COMMAND_SYNTAX;
1935 n = find_account(client->doc, &path, &rc, NULL, 0);
1937 if (!n)
1938 goto fail;
1940 if (path[1]) {
1941 n = find_elements(client->doc, n->children, path+1, &rc,
1942 NULL, NULL, NULL, FALSE, 0, NULL);
1944 if (!n)
1945 goto fail;
1948 g_strfreev(path);
1950 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
1951 return EPWMD_ATTR_NOT_FOUND;
1953 rc = assuan_send_data(ctx, a, xmlStrlen(a));
1954 xmlFree(a);
1955 return rc;
1957 fail:
1958 g_strfreev(path);
1959 return rc;
1963 * req[0] - attribute
1964 * req[1] - element path
1965 * req[2] - value
1967 static int attribute_set(struct client_s *client, gchar **req)
1969 gchar **path = NULL;
1970 gpg_error_t rc;
1971 xmlNodePtr n;
1973 if (!req || !req[0] || !req[1] || !req[2])
1974 return EPWMD_COMMAND_SYNTAX;
1977 * Reserved attribute names.
1979 if (g_utf8_collate(req[0], "name") == 0) {
1981 * Only reserved for the account element. Not the rest of the
1982 * document.
1984 if (strchr(req[1], '\t') == NULL)
1985 return name_attribute(client, req + 1);
1987 else if (g_utf8_collate(req[0], "target") == 0)
1988 return target_attribute(client, req + 1);
1990 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1992 * The first argument may be only an account.
1994 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1995 return EPWMD_COMMAND_SYNTAX;
1998 n = find_account(client->doc, &path, &rc, NULL, 0);
2000 if (!n)
2001 goto fail;
2003 if (path[1]) {
2004 n = find_elements(client->doc, n->children, path+1, &rc,
2005 NULL, NULL, NULL, FALSE, 0, NULL);
2007 if (!n)
2008 goto fail;
2011 g_strfreev(path);
2012 return add_attribute(n, req[0], req[2]);
2014 fail:
2015 g_strfreev(path);
2016 return rc;
2020 * req[0] - command
2021 * req[1] - attribute name or element path if command is LIST
2022 * req[2] - element path
2023 * req[2] - element path or value
2025 static int attr_command(assuan_context_t ctx, char *line)
2027 struct client_s *client = assuan_get_pointer(ctx);
2028 gchar **req = split_input_line(line, " ", 4);
2029 gpg_error_t rc = 0;
2031 rc = file_modified(client);
2033 if (rc) {
2034 log_write("%s: %s", client->filename ? client->filename : "",
2035 pwmd_strerror(rc));
2036 g_strfreev(req);
2037 return send_error(ctx, rc);
2040 if (!req || !req[0] || !req[1]) {
2041 g_strfreev(req);
2042 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2045 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2046 rc = attribute_set(client, req+1);
2047 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2048 rc = attribute_get(ctx, req+1);
2049 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2050 rc = attribute_delete(client, req+1);
2051 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2052 rc = attribute_list(ctx, req+1);
2053 else
2054 rc = EPWMD_COMMAND_SYNTAX;
2056 g_strfreev(req);
2057 return send_error(ctx, rc);
2060 static int iscached_command(assuan_context_t ctx, char *line)
2062 gchar **req = split_input_line(line, " ", 0);
2063 guchar md5file[16];
2065 if (!req || !*req) {
2066 g_strfreev(req);
2067 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2070 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2071 g_strfreev(req);
2072 CACHE_LOCK(ctx);
2074 if (cache_iscached(md5file) == FALSE) {
2075 CACHE_UNLOCK;
2076 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2079 CACHE_UNLOCK;
2080 return send_error(ctx, 0);
2083 gpg_error_t send_cache_status(assuan_context_t ctx)
2085 gchar *tmp;
2086 struct client_s *client = assuan_get_pointer(ctx);
2087 gchar buf[ASSUAN_LINELENGTH];
2089 CACHE_LOCK(client->ctx);
2090 tmp = print_fmt(buf, sizeof(buf), "%i %i",
2091 cache_file_count(),
2092 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2093 CACHE_UNLOCK;
2095 return assuan_write_status(ctx, "CACHE", buf);
2098 static int clearcache_command(assuan_context_t ctx, char *line)
2100 struct client_s *client = assuan_get_pointer(ctx);
2101 gchar **req = split_input_line(line, " ", 0);
2102 guchar md5file[16];
2104 CACHE_LOCK(ctx);
2106 if (!req || !*req) {
2107 g_strfreev(req);
2108 cache_clear(client->md5file, 2);
2109 CACHE_UNLOCK;
2110 return send_error(ctx, 0);
2113 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2114 g_strfreev(req);
2116 if (cache_clear(md5file, 1) == FALSE) {
2117 CACHE_UNLOCK;
2118 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2121 CACHE_UNLOCK;
2122 return send_error(ctx, 0);
2125 static int cachetimeout_command(assuan_context_t ctx, char *line)
2127 guchar md5file[16];
2128 glong timeout;
2129 gchar **req = split_input_line(line, " ", 0);
2130 gchar *p;
2131 struct client_s *client = assuan_get_pointer(ctx);
2133 if (!req || !*req || !req[1]) {
2134 g_strfreev(req);
2135 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2138 errno = 0;
2139 timeout = strtol(req[0], &p, 10);
2141 if (errno != 0 || *p != 0) {
2142 g_strfreev(req);
2143 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2146 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2147 g_strfreev(req);
2148 CACHE_LOCK(client->ctx);
2150 if (cache_set_timeout(md5file, timeout) == FALSE) {
2151 CACHE_UNLOCK;
2152 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2155 CACHE_UNLOCK;
2156 return send_error(ctx, 0);
2159 static int dump_command(assuan_context_t ctx, char *line)
2161 xmlChar *xml;
2162 gssize len;
2163 struct client_s *client = assuan_get_pointer(ctx);
2164 gpg_error_t rc;
2166 if (disable_list_and_dump == TRUE)
2167 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2169 rc = file_modified(client);
2171 if (rc) {
2172 log_write("%s: %s", client->filename ? client->filename : "",
2173 pwmd_strerror(rc));
2174 return send_error(ctx, rc);
2177 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2179 if (!xml)
2180 return send_syserror(ctx, ENOMEM);
2182 rc = assuan_send_data(ctx, xml, len);
2183 xmlFree(xml);
2184 return send_error(ctx, rc);
2187 static int getconfig_command(assuan_context_t ctx, gchar *line)
2189 struct client_s *client = assuan_get_pointer(ctx);
2190 gpg_error_t rc = 0;
2191 gchar *p, *tmp;
2193 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2194 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2196 p = get_key_file_string(client->filename ? client->filename : "global", line);
2198 if (!p)
2199 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2201 tmp = expand_homedir(p);
2203 if (!tmp) {
2204 g_free(p);
2205 return send_syserror(ctx, ENOMEM);
2208 g_free(p);
2209 p = tmp;
2210 rc = assuan_send_data(ctx, p, strlen(p));
2211 g_free(p);
2212 return send_error(ctx, rc);
2215 static int xpath_command(assuan_context_t ctx, gchar *line)
2217 struct client_s *client = assuan_get_pointer(ctx);
2218 gpg_error_t rc;
2219 xmlXPathContextPtr xp;
2220 xmlXPathObjectPtr result;
2221 xmlBufferPtr buf = NULL;
2222 gchar **req = NULL;
2224 rc = file_modified(client);
2226 if (rc) {
2227 log_write("%s: %s", client->filename ? client->filename : "",
2228 pwmd_strerror(rc));
2229 return send_error(ctx, rc);
2232 if (!line || !*line)
2233 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2235 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2236 if (strv_printf(&req, "%s", line) == FALSE)
2237 return send_syserror(ctx, ENOMEM);
2240 xp = xmlXPathNewContext(client->doc);
2242 if (!xp)
2243 return send_error(ctx, EPWMD_LIBXML_ERROR);
2245 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2247 if (!result) {
2248 xmlXPathFreeContext(xp);
2249 return send_error(ctx, EPWMD_LIBXML_ERROR);
2252 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2253 rc = EPWMD_EMPTY_ELEMENT;
2254 goto fail;
2257 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2258 (xmlChar *)req[1], &buf);
2260 if (rc)
2261 goto fail;
2262 else if (!req[1] && !xmlBufferLength(buf)) {
2263 rc = EPWMD_EMPTY_ELEMENT;
2264 goto fail;
2266 else if (req[1])
2267 goto fail;
2269 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2271 fail:
2272 g_strfreev(req);
2274 if (buf)
2275 xmlBufferFree(buf);
2277 if (result)
2278 xmlXPathFreeObject(result);
2280 if (xp)
2281 xmlXPathFreeContext(xp);
2283 return send_error(ctx, rc);
2286 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2287 gsize len)
2289 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2290 gpg_error_t rc = file_modified(client);
2291 gchar **req, **path = NULL, **path_orig = NULL, *content;
2292 xmlDocPtr doc;
2293 xmlNodePtr n, root, copy;
2295 if (assuan_rc || rc) {
2296 if (line)
2297 #ifndef MEM_DEBUG
2298 xfree(line);
2299 #else
2300 free(line);
2301 #endif
2302 return assuan_rc ? assuan_rc : rc;
2305 req = split_input_line((gchar *)line, " ", 2);
2306 #ifndef MEM_DEBUG
2307 xfree(line);
2308 #else
2309 free(line);
2310 #endif
2312 if (!req || !*req)
2313 return EPWMD_COMMAND_SYNTAX;
2315 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2316 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2317 return EPWMD_COMMAND_SYNTAX;
2320 content = req[1];
2322 if (!content || !*content) {
2323 rc = EPWMD_COMMAND_SYNTAX;
2324 goto fail;
2327 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2328 rc = EPWMD_INVALID_ELEMENT;
2329 goto fail;
2332 if (valid_element_path(path+1, FALSE) == FALSE) {
2333 rc = EPWMD_INVALID_ELEMENT;
2334 goto fail;
2337 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2339 if (!doc) {
2340 rc = EPWMD_LIBXML_ERROR;
2341 goto fail;
2344 root = xmlDocGetRootElement(doc);
2345 path_orig = g_strdupv(path);
2347 if (!path_orig) {
2348 xmlFreeDoc(doc);
2349 rc = gpg_error_from_errno(ENOMEM);
2350 goto fail;
2353 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2354 g_strfreev(path_orig);
2355 xmlFreeDoc(doc);
2356 rc = gpg_error_from_errno(ENOMEM);
2357 goto fail;
2360 n = find_account(client->doc, &path, &rc, NULL, 0);
2362 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2363 g_strfreev(path_orig);
2364 xmlFreeDoc(doc);
2365 goto fail;
2367 else if (!rc) {
2368 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2370 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2371 g_strfreev(path_orig);
2372 xmlFreeDoc(doc);
2373 goto fail;
2375 else if (!rc) {
2376 xmlNodePtr parent = n->parent;
2378 xmlUnlinkNode(n);
2379 xmlFreeNode(n);
2380 n = parent;
2384 g_strfreev(path);
2385 path = path_orig;
2387 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2388 n = create_element_path(client, &path, &rc);
2390 if (rc) {
2391 xmlFreeDoc(doc);
2392 goto fail;
2396 copy = xmlCopyNode(root, 1);
2397 n = xmlAddChild(n, copy);
2398 xmlFreeDoc(doc);
2400 if (!n)
2401 rc = EPWMD_LIBXML_ERROR;
2403 fail:
2404 g_strfreev(path);
2405 g_strfreev(req);
2406 client->inquire_status = INQUIRE_DONE;
2407 return rc;
2410 static int import_command(assuan_context_t ctx, gchar *line)
2412 gpg_error_t rc;
2413 struct client_s *client = assuan_get_pointer(ctx);
2415 rc = file_modified(client);
2417 if (rc) {
2418 log_write("%s: %s", client->filename ? client->filename : "",
2419 pwmd_strerror(rc));
2420 return send_error(ctx, rc);
2423 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2425 if (rc)
2426 return send_error(ctx, rc);
2428 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2429 client->inquire_status = INQUIRE_BUSY;
2430 return 0;
2433 void cleanup_assuan(assuan_context_t ctx)
2435 struct client_s *cl = assuan_get_pointer(ctx);
2437 if (cl)
2438 cleanup_client(cl);
2441 static void reset_notify(assuan_context_t ctx)
2443 struct client_s *cl = assuan_get_pointer(ctx);
2445 if (cl)
2446 cleanup_client(cl);
2449 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2451 gchar name[32] = {0}, value[256] = {0};
2453 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2454 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2456 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2457 pth_attr_t attr = pth_attr_of(pth_self());
2459 log_write("OPTION CLIENT %s", line);
2460 pth_attr_set(attr, PTH_ATTR_NAME, value);
2461 pth_attr_destroy(attr);
2463 else
2464 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2466 return 0;
2469 static int option_handler(assuan_context_t ctx, const gchar *name,
2470 const gchar *value)
2472 #ifdef WITH_PINENTRY
2473 struct client_s *client = assuan_get_pointer(ctx);
2474 #endif
2476 if (!value || !*value)
2477 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2479 if (g_strcasecmp(name, (gchar *)"client") == 0)
2480 return parse_client_option(ctx, value);
2482 #ifdef WITH_PINENTRY
2483 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2484 g_free(client->pinentry->ttyname);
2485 client->pinentry->ttyname = g_strdup(value);
2487 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2488 g_free(client->pinentry->ttytype);
2489 client->pinentry->ttytype = g_strdup(value);
2491 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2492 g_free(client->pinentry->display);
2493 client->pinentry->display = g_strdup(value);
2495 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2496 g_free(client->pinentry->path);
2497 client->pinentry->path = g_strdup(value);
2499 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2500 g_free(client->pinentry->title);
2501 client->pinentry->title = g_strdup(value);
2503 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2504 g_free(client->pinentry->prompt);
2505 client->pinentry->prompt = g_strdup(value);
2507 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2508 g_free(client->pinentry->desc);
2509 client->pinentry->desc = g_strdup(value);
2511 #if 0
2512 /* Need to wait for pinentry to support a --timeout option so it can
2513 * terminate itself. Cannot do it here because assuan_pipe_connect() calls
2514 * execv() which replaces the pid of the fork()ed thread from
2515 * pinentry_fork(). So pinentry will become a real process after the
2516 * thread terminates and won't be able to be kill()ed from pwmd.
2518 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2519 gchar *p = NULL;
2520 gint n = strtol(value, &p, 10);
2522 if (*p || n < 0)
2523 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2525 client->pinentry->timeout = n;
2527 #endif
2528 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2529 gchar *p = NULL;
2530 gint n = strtol(value, &p, 10);
2532 if (*p || n < 0 || n > 1)
2533 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2535 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2537 else
2538 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2539 #else
2540 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
2541 #endif
2543 log_write("OPTION %s=%s", name, value);
2544 return 0;
2547 gpg_error_t register_commands(assuan_context_t ctx)
2549 static struct {
2550 const gchar *name;
2551 gint (*handler)(assuan_context_t, gchar *line);
2552 } table[] = {
2553 { "OPEN", open_command },
2554 { "SAVE", save_command },
2555 { "LIST", list_command },
2556 { "REALPATH", realpath_command },
2557 { "STORE", store_command },
2558 { "DELETE", delete_command },
2559 { "GET", get_command },
2560 { "ATTR", attr_command },
2561 { "ISCACHED", iscached_command },
2562 { "CLEARCACHE", clearcache_command },
2563 { "CACHETIMEOUT", cachetimeout_command },
2564 { "GETCONFIG", getconfig_command },
2565 { "DUMP", dump_command },
2566 { "XPATH", xpath_command },
2567 { "IMPORT", import_command },
2568 { "INPUT", NULL },
2569 { "OUTPUT", NULL },
2570 { NULL, NULL }
2572 gint i, rc;
2574 for (i=0; table[i].name; i++) {
2575 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2577 if (rc)
2578 return rc;
2581 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2583 if (rc)
2584 return rc;
2586 rc = assuan_register_option_handler(ctx, option_handler);
2588 if (rc)
2589 return rc;
2591 return assuan_register_reset_notify(ctx, reset_notify);
2594 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2595 guchar *key)
2597 guchar *iv;
2598 void *inbuf;
2599 gsize insize, len;
2600 guchar tkey[gcrykeysize];
2601 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2602 gcry_cipher_hd_t gh;
2603 guint iter = 0, n_iter = 0;
2604 gint iter_progress;
2605 void *outbuf = NULL;
2606 gint zrc = 0;
2607 glong outsize = 0;
2608 gpg_error_t rc;
2609 file_header_t file_header;
2610 gchar str[ASSUAN_LINELENGTH];
2612 if (!ctx) {
2613 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2615 if (rc)
2616 return rc;
2618 else
2619 gh = client->gh;
2621 lseek(fd, 0, SEEK_SET);
2622 insize = st.st_size - sizeof(file_header_t);
2623 iv = gcry_malloc(gcryblocksize);
2625 if (!iv) {
2626 if (!ctx)
2627 gcry_cipher_close(gh);
2629 return gpg_error_from_errno(ENOMEM);
2632 len = pth_read(fd, &file_header, sizeof(file_header_t));
2634 if (len != sizeof(file_header_t)) {
2635 len = errno;
2637 if (!ctx)
2638 gcry_cipher_close(gh);
2640 gcry_free(iv);
2641 errno = len;
2642 return gpg_error_from_errno(errno);
2645 /* No encryption iterations. This is a plain (gzipped) file. */
2646 if (file_header.iter == -1) {
2648 * cache_file_count() needs both .used == TRUE and a valid key in
2649 * order for it to count as a used cache entry. Fixes CACHE status
2650 * messages.
2652 memset(key, '!', gcrykeysize);
2653 insize = st.st_size - sizeof(file_header_t);
2656 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2657 inbuf = gcry_malloc(insize);
2659 if (!inbuf) {
2660 if (!ctx)
2661 gcry_cipher_close(gh);
2663 gcry_free(iv);
2664 return gpg_error_from_errno(ENOMEM);
2667 len = pth_read(fd, inbuf, insize);
2669 if (len != insize) {
2670 len = errno;
2672 if (!ctx)
2673 gcry_cipher_close(gh);
2675 gcry_free(iv);
2676 errno = len;
2677 return gpg_error_from_errno(errno);
2680 if (file_header.iter == -1)
2681 goto decompress;
2683 memcpy(tkey, key, sizeof(tkey));
2684 tkey[0] ^= 1;
2686 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2687 if (!ctx) {
2688 gcry_cipher_close(gh);
2689 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2691 else
2692 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2694 gcry_free(inbuf);
2695 gcry_free(iv);
2696 return rc;
2699 if ((rc = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2700 if (!ctx) {
2701 gcry_cipher_close(gh);
2702 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2704 else
2705 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2707 gcry_free(inbuf);
2708 gcry_free(iv);
2710 if (!ctx)
2711 gcry_cipher_close(gh);
2713 return rc;
2716 iter_progress = get_key_file_integer("global", "iteration_progress");
2718 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2719 rc = assuan_write_status(client->ctx, "DECRYPT", "0");
2721 if (rc) {
2722 gcry_free(inbuf);
2723 gcry_free(iv);
2724 return rc;
2728 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2730 if (rc) {
2731 gcry_free(inbuf);
2732 gcry_free(iv);
2733 return rc;
2736 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2737 if (!ctx) {
2738 gcry_cipher_close(gh);
2739 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2741 else
2742 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2744 gcry_free(inbuf);
2745 gcry_free(iv);
2746 return rc;
2749 while (iter < file_header.iter) {
2750 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2751 if (!(iter % iter_progress)) {
2752 rc = assuan_write_status(ctx, "DECRYPT",
2753 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
2755 if (rc) {
2756 gcry_free(inbuf);
2757 gcry_free(iv);
2758 return rc;
2763 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2764 if (!ctx) {
2765 gcry_cipher_close(gh);
2766 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2768 else
2769 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2771 gcry_free(inbuf);
2772 gcry_free(iv);
2773 return rc;
2776 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2778 if (rc) {
2779 if (!ctx) {
2780 gcry_cipher_close(gh);
2781 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2783 else
2784 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2786 gcry_free(inbuf);
2787 gcry_free(iv);
2788 return rc;
2791 iter++;
2792 pth_yield(NULL);
2795 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2796 rc = assuan_write_status(ctx, "DECRYPT",
2797 print_fmt(str, sizeof(str), "%i", file_header.iter));
2799 if (rc) {
2800 gcry_free(inbuf);
2801 gcry_free(iv);
2802 return rc;
2806 gcry_free(iv);
2808 decompress:
2809 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zrc) == FALSE) {
2811 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2813 if (zrc == Z_MEM_ERROR) {
2814 gcry_free(inbuf);
2815 return gpg_error_from_errno(ENOMEM);
2817 else if (zrc != Z_DATA_ERROR) {
2818 gcry_free(inbuf);
2820 if (!ctx)
2821 gcry_cipher_close(gh);
2823 return EPWMD_BADKEY;
2826 else {
2827 gcry_free(inbuf);
2828 inbuf = outbuf;
2829 insize = outsize;
2832 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2833 gcry_free(inbuf);
2835 if (!ctx)
2836 gcry_cipher_close(gh);
2838 return EPWMD_BADKEY;
2841 if (ctx) {
2842 client->xml = inbuf;
2843 client->len = insize;
2845 else {
2846 gcry_cipher_close(gh);
2847 gcry_free(inbuf);
2850 return 0;
2854 * This is called after every Assuan command.
2856 void command_finalize(assuan_context_t ctx, gint rc)
2858 struct client_s *client = assuan_get_pointer(ctx);
2860 unlock_file_mutex(client);