Only allow one instance of pinentry. Use a mutex to ensure it.
[pwmd.git] / src / commands.c
blobe4376fb9d6861e827df4614f9a1475899d48e089
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 *error)
225 z_stream z;
226 gint ret;
227 gpointer pout;
228 gz_header h;
229 gchar buf[17];
230 gpg_error_t rc;
231 gchar str[ASSUAN_LINELENGTH];
233 z.zalloc = z_alloc;
234 z.zfree = z_free;
235 z.next_in = in;
236 z.avail_in = insize;
237 z.avail_out = zlib_bufsize;
238 z.next_out = pout = g_malloc(zlib_bufsize);
240 if (!pout) {
241 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
242 *error = Z_MEM_ERROR;
243 return FALSE;
246 ret = inflateInit2(&z, 47);
248 if (ret != Z_OK) {
249 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
250 g_free(pout);
251 return FALSE;
254 memset(&h, 0, sizeof(gz_header));
255 h.comment = (guchar *)buf;
256 h.comm_max = sizeof(buf);
257 ret = inflateGetHeader(&z, &h);
259 if (ret != Z_OK) {
260 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
261 g_free(pout);
262 inflateEnd(&z);
263 return FALSE;
266 ret = inflate(&z, Z_BLOCK);
268 if (ret != Z_OK) {
269 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
270 g_free(pout);
271 inflateEnd(&z);
272 return FALSE;
275 if (h.comment)
276 insize = atoi((gchar *)h.comment);
278 do {
279 gpointer p;
281 ret = inflate(&z, Z_FINISH);
283 switch (ret) {
284 case Z_OK:
285 break;
286 case Z_BUF_ERROR:
287 if (!z.avail_out) {
288 p = g_realloc(pout, z.total_out + zlib_bufsize);
290 if (!p) {
291 ret = Z_MEM_ERROR;
292 goto fail;
295 pout = p;
296 z.next_out = pout + z.total_out;
297 z.avail_out = zlib_bufsize;
299 if (ctx) {
300 rc = assuan_write_status(ctx, "DECOMPRESS",
301 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
303 if (rc) {
304 ret = rc;
305 goto fail;
309 break;
310 case Z_STREAM_END:
311 break;
312 default:
313 goto fail;
314 break;
317 pth_yield(NULL);
318 } while (ret != Z_STREAM_END);
320 if (ctx) {
321 rc = assuan_write_status(ctx, "DECOMPRESS",
322 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
324 if (rc) {
325 ret = rc;
326 goto fail;
330 *out = pout;
331 *outsize = z.total_out;
332 inflateEnd(&z);
333 return TRUE;
335 fail:
336 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
337 *error = ret;
338 g_free(pout);
339 inflateEnd(&z);
340 return FALSE;
343 gpg_error_t read_file_header(const gchar *filename, file_header_t *fh)
345 gint fd;
346 gsize len;
348 fd = open(filename, O_RDONLY);
350 if (fd == -1)
351 return gpg_error_from_errno(errno);
353 len = pth_read(fd, fh, sizeof(file_header_t));
354 close(fd);
356 if (len != sizeof(file_header_t))
357 return gpg_error_from_errno(errno);
359 return 0;
362 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar shakey[],
363 gboolean cached)
365 struct client_s *client = assuan_get_pointer(ctx);
366 gpg_error_t error;
367 struct stat st;
368 gint fd;
369 gint timeout;
371 if ((fd = open_file(client->filename, &st)) == -1) {
372 /* New file. */
373 if (errno == ENOENT) {
374 if (shakey[0])
375 goto update_cache;
377 goto done;
380 error = errno;
381 log_write("%s: %s", client->filename, strerror(errno));
382 cleanup_client(client);
383 memset(shakey, 0, sizeof(shakey));
384 return send_syserror(ctx, error);
387 error = try_xml_decrypt(ctx, fd, st, shakey);
388 close(fd);
390 if (error) {
391 memset(shakey, 0, sizeof(shakey));
392 cleanup_client(client);
393 return send_error(ctx, error);
396 update_cache:
397 CACHE_LOCK(client->ctx);
399 if (cached == FALSE) {
400 if (cache_update_key(client->md5file, shakey) == FALSE) {
401 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
402 cleanup_client(client);
403 CACHE_UNLOCK;
404 return send_error(ctx, EPWMD_MAX_SLOTS);
407 timeout = get_key_file_integer(client->filename, "cache_timeout");
408 cache_reset_timeout(client->md5file, timeout);
410 else
411 cache_set_timeout(client->md5file, -2);
413 CACHE_UNLOCK;
415 done:
416 memset(shakey, 0, sizeof(shakey));
417 error = parse_xml(ctx);
419 if (client->xml) {
420 gcry_free(client->xml);
421 client->xml = NULL;
424 if (!error) {
425 if (client->new == FALSE)
426 send_cache_status_all();
428 client->state = STATE_OPEN;
431 return send_error(ctx, error);
434 static int open_command(assuan_context_t ctx, char *line)
436 struct stat st;
437 guchar shakey[gcrykeysize];
438 gboolean cached = FALSE;
439 gpg_error_t error;
440 struct client_s *client = assuan_get_pointer(ctx);
441 gchar **req;
442 gchar *filename = NULL;
443 file_header_t file_header;
445 memset(shakey, 0, sizeof(shakey));
447 if ((req = split_input_line(line, " ", 2)) != NULL)
448 filename = req[0];
450 if (!filename || !*filename) {
451 g_strfreev(req);
452 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
455 if (valid_filename(filename) == FALSE) {
456 g_strfreev(req);
457 return send_error(ctx, EPWMD_INVALID_FILENAME);
460 if (client->state == STATE_OPEN)
461 cleanup_client(client);
463 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
464 CACHE_LOCK(client->ctx);
466 if (cache_has_file(client->md5file) == FALSE) {
467 if (cache_add_file(client->md5file, NULL) == FALSE) {
468 g_strfreev(req);
469 CACHE_UNLOCK;
470 return send_error(ctx, EPWMD_MAX_SLOTS);
474 cache_incr_refcount(client->md5file);
475 CACHE_UNLOCK;
476 error = lock_file_mutex(client);
478 if (error) {
479 g_strfreev(req);
480 return send_error(ctx, error);
483 client->freed = FALSE;
485 if ((error = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
486 g_strfreev(req);
487 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
488 cleanup_client(client);
489 return send_error(ctx, error);
492 if (stat(filename, &st) == 0) {
493 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
494 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
495 g_strfreev(req);
496 cleanup_client(client);
497 return send_error(ctx, EPWMD_INVALID_FILENAME);
500 client->mtime = st.st_mtime;
503 client->filename = g_strdup(filename);
505 if (!client->filename) {
506 memset(shakey, 0, sizeof(shakey));
507 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
508 cleanup_client(client);
509 g_strfreev(req);
510 return send_syserror(ctx, ENOMEM);
513 #ifdef WITH_PINENTRY
514 client->pinentry->filename = g_strdup(client->filename);
516 if (!client->pinentry->filename) {
517 memset(shakey, 0, sizeof(shakey));
518 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
519 cleanup_client(client);
520 g_strfreev(req);
521 return send_syserror(ctx, ENOMEM);
523 #endif
526 * New files don't need a key.
528 if (access(filename, R_OK|W_OK) != 0) {
529 if (errno != ENOENT) {
530 error = errno;
531 log_write("%s: %s", filename, strerror(errno));
532 g_strfreev(req);
533 cleanup_client(client);
534 return send_syserror(ctx, error);
537 if ((client->xml = new_document()) == NULL) {
538 log_write("%s", strerror(ENOMEM));
539 g_strfreev(req);
540 cleanup_client(client);
541 return send_syserror(ctx, ENOMEM);
544 client->len = xmlStrlen(client->xml);
545 client->new = TRUE;
546 client->filename = g_strdup(filename);
548 if (!client->filename) {
549 g_strfreev(req);
550 cleanup_client(client);
551 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
552 return send_syserror(ctx, ENOMEM);
555 memset(shakey, 0, sizeof(shakey));
557 if (req[1] && *req[1])
558 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
560 g_strfreev(req);
561 return open_command_finalize(ctx, shakey, cached);
564 error = read_file_header(filename, &file_header);
566 if (error) {
567 g_strfreev(req);
568 cleanup_client(client);
569 return send_error(ctx, error);
572 if (file_header.iter == -1)
573 goto done;
575 CACHE_LOCK(client->ctx);
576 cached = cache_get_key(client->md5file, shakey);
577 CACHE_UNLOCK;
579 if (cached == FALSE) {
581 * No key specified and no matching filename found in the cache. Use
582 * pinentry to retrieve the key. Cannot return assuan_process_done()
583 * here otherwise the command will be interrupted. The event loop in
584 * client_thread() will poll the file descriptor waiting for it to
585 * become ready to read a pinentry_key_s which will contain the
586 * entered key or error. It will then call open_command_finalize() to
587 * to finish the command.
589 if (!req[1] || !*req[1]) {
590 #ifdef WITH_PINENTRY
591 if (get_key_file_boolean(filename, "enable_pinentry") == FALSE) {
592 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
593 goto done;
596 g_strfreev(req);
597 lock_pin_mutex(client);
598 client->pinentry->which = PINENTRY_OPEN;
599 error = pinentry_fork(ctx);
601 if (error) {
602 unlock_pin_mutex(client->pinentry);
603 cleanup_client(client);
604 return send_error(ctx, error);
607 client->pinentry->cb = open_command_finalize;
608 client->pinentry->status = PINENTRY_INIT;
609 return 0;
610 #else
611 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
612 goto done;
613 #endif
616 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
619 done:
620 g_strfreev(req);
621 return open_command_finalize(ctx, shakey, cached);
624 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
625 gint size, gpointer *out, glong *outsize, gint *error)
627 z_stream z;
628 gpointer pout, pin;
629 gint ret;
630 gz_header h;
631 gchar buf[17];
632 gint cmd = Z_NO_FLUSH;
633 gpg_error_t rc;
634 gchar str[ASSUAN_LINELENGTH];
636 z.zalloc = z_alloc;
637 z.zfree = z_free;
638 z.next_in = pin = data;
639 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
640 z.avail_out = zlib_bufsize;
641 z.next_out = pout = g_malloc(zlib_bufsize);
643 if (!pout) {
644 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
645 *error = Z_MEM_ERROR;
646 return FALSE;
649 ret = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
651 if (ret != Z_OK) {
652 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
653 *error = ret;
654 g_free(pout);
655 return FALSE;
658 memset(&h, 0, sizeof(gz_header));
659 snprintf(buf, sizeof(buf), "%i", size);
660 h.comment = (guchar *)buf;
661 ret = deflateSetHeader(&z, &h);
663 if (ret != Z_OK) {
664 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
665 *error = ret;
666 g_free(pout);
667 deflateEnd(&z);
668 return FALSE;
671 do {
672 gpointer p;
674 ret = deflate(&z, cmd);
676 switch (ret) {
677 case Z_OK:
678 break;
679 case Z_BUF_ERROR:
680 if (!z.avail_out) {
681 p = g_realloc(pout, z.total_out + zlib_bufsize);
683 if (!p) {
684 ret = Z_MEM_ERROR;
685 goto fail;
688 pout = p;
689 z.next_out = pout + z.total_out;
690 z.avail_out = zlib_bufsize;
693 if (!z.avail_in && z.total_in < size) {
694 if (z.total_in + zlib_bufsize > size)
695 z.avail_in = size - z.total_in;
696 else
697 z.avail_in = zlib_bufsize;
699 if (ctx) {
700 rc = assuan_write_status(ctx, "COMPRESS",
701 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
703 if (rc) {
704 ret = rc;
705 goto fail;
710 if (z.total_in >= size)
711 cmd = Z_FINISH;
713 break;
714 case Z_STREAM_END:
715 break;
716 default:
717 goto fail;
720 pth_yield(NULL);
721 } while (ret != Z_STREAM_END);
723 if (ctx) {
724 rc = assuan_write_status(ctx, "COMPRESS",
725 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
727 if (rc) {
728 ret = rc;
729 goto fail;
733 *out = pout;
734 *outsize = z.total_out;
735 deflateEnd(&z);
736 return TRUE;
738 fail:
739 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
740 *error = ret;
741 g_free(pout);
742 deflateEnd(&z);
743 return FALSE;
746 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
747 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
748 gint iter)
750 gsize len = insize;
751 gint fd;
752 gpointer inbuf;
753 guchar tkey[gcrykeysize];
754 gchar *p;
755 gint error;
756 gpg_error_t rc;
757 guint iter_progress = 0, n_iter = 0, xiter = 0;
758 gchar tmp[FILENAME_MAX];
759 file_header_t file_header;
760 gchar str[ASSUAN_LINELENGTH];
762 if (iter == -1) {
764 * cache_file_count() needs both .used == TRUE and a valid key in
765 * order for it to count as a used cache entry. Fixes CACHE status
766 * messages.
768 memset(shakey, '!', gcrykeysize);
769 inbuf = data;
770 file_header.iter = iter;
771 goto write_file;
774 if (insize / gcryblocksize) {
775 len = (insize / gcryblocksize) * gcryblocksize;
777 if (insize % gcryblocksize)
778 len += gcryblocksize;
782 * Resize the existing xml buffer to the block size required by gcrypt
783 * rather than duplicating it and wasting memory.
785 inbuf = gcry_realloc(data, len);
787 if (!inbuf)
788 return gpg_error_from_errno(ENOMEM);
790 insize = len;
791 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
792 memcpy(tkey, shakey, sizeof(tkey));
793 tkey[0] ^= 1;
795 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
796 gcry_free(inbuf);
797 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
798 return rc;
801 file_header.iter = iter;
803 if (client)
804 iter_progress = get_key_file_integer("global", "iteration_progress");
806 if (client && iter_progress && file_header.iter >= iter_progress) {
807 error = assuan_write_status(client->ctx, "ENCRYPT", "0");
809 if (error) {
810 gcry_free(inbuf);
811 return error;
815 while (xiter < file_header.iter) {
816 if (client && iter_progress > 0 && xiter >= iter_progress) {
817 if (!(xiter % iter_progress)) {
818 error = assuan_write_status(client->ctx, "ENCRYPT",
819 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
821 if (error) {
822 gcry_free(inbuf);
823 return error;
828 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
829 sizeof(file_header.iv)))) {
830 gcry_free(inbuf);
831 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
832 return rc;
835 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
836 == FALSE) {
837 gcry_free(inbuf);
838 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
839 return rc;
842 xiter++;
843 pth_yield(NULL);
846 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
847 sizeof(file_header.iv)))) {
848 gcry_free(inbuf);
849 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
850 return rc;
853 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
854 gcry_free(inbuf);
855 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
856 return rc;
859 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
860 gcry_free(inbuf);
861 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
862 return rc;
865 if (client && iter_progress && file_header.iter >= iter_progress) {
866 error = assuan_write_status(client->ctx, "ENCRYPT",
867 print_fmt(str, sizeof(str), "%i", file_header.iter));
869 if (error) {
870 gcry_free(inbuf);
871 return error;
875 write_file:
876 if (filename) {
877 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
879 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
880 error = errno;
881 gcry_free(inbuf);
882 p = strrchr(tmp, '/');
883 p++;
884 log_write("%s: %s", p, strerror(errno));
885 return gpg_error_from_errno(error);
888 else
890 * xml_import() from command line.
892 fd = STDOUT_FILENO;
894 len = pth_write(fd, &file_header, sizeof(file_header_t));
896 if (len != sizeof(file_header)) {
897 len = errno;
899 if (filename)
900 close(fd);
902 gcry_free(inbuf);
903 return gpg_error_from_errno(len);
906 len = pth_write(fd, inbuf, insize);
908 if (len != insize) {
909 len = errno;
911 if (filename)
912 close(fd);
914 gcry_free(inbuf);
915 return gpg_error_from_errno(len);
918 if (fsync(fd) == -1) {
919 len = errno;
920 close(fd);
921 gcry_free(inbuf);
922 return gpg_error_from_errno(len);
925 if (filename) {
926 struct stat st;
927 mode_t mode = 0;
929 close(fd);
931 if (stat(filename, &st) == 0)
932 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
934 if (rename(tmp, filename) == -1) {
935 len = errno;
936 gcry_free(inbuf);
937 return gpg_error_from_errno(len);
940 if (mode)
941 chmod(filename, mode);
944 gcry_free(inbuf);
945 return 0;
948 static gpg_error_t save_command_finalize(assuan_context_t ctx,
949 guchar shakey[], gboolean cached)
951 struct client_s *client = assuan_get_pointer(ctx);
952 gpointer xmlbuf;
953 xmlChar *p;
954 gint len;
955 gint iter;
956 gint timeout;
957 gpointer outbuf;
958 glong outsize = 0;
959 gint zerror;
960 gpg_error_t error;
961 struct stat st;
963 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
964 xmlbuf = p;
966 iter = get_key_file_integer(client->filename, "compression_level");
968 if (iter < 0)
969 iter = 0;
971 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zerror) == FALSE) {
972 memset(shakey, 0, sizeof(shakey));
973 xmlFree(xmlbuf);
975 if (zerror == Z_MEM_ERROR) {
976 return send_syserror(ctx, ENOMEM);
978 else
979 return send_error(ctx, GPG_ERR_COMPR_ALGO);
981 else {
982 gcry_free(xmlbuf);
983 xmlbuf = outbuf;
984 len = outsize;
987 iter = get_key_file_integer(client->filename, "iterations");
988 error = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
990 if (error) {
991 memset(shakey, 0, sizeof(shakey));
992 return send_error(ctx, error);
995 stat(client->filename, &st);
996 client->mtime = st.st_mtime;
997 timeout = get_key_file_integer(client->filename, "cache_timeout");
998 CACHE_LOCK(client->ctx);
1000 if (cached) {
1001 memset(shakey, 0, sizeof(shakey));
1002 cache_reset_timeout(client->md5file, timeout);
1003 CACHE_UNLOCK;
1005 if (client->new == TRUE)
1006 send_cache_status_all();
1008 client->new = FALSE;
1009 return send_error(ctx, 0);
1012 if (cache_update_key(client->md5file, shakey) == FALSE) {
1013 memset(shakey, 0, sizeof(shakey));
1014 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1015 CACHE_UNLOCK;
1016 return send_error(ctx, EPWMD_MAX_SLOTS);
1019 client->new = FALSE;
1020 memset(shakey, 0, sizeof(shakey));
1021 cache_reset_timeout(client->md5file, timeout);
1022 CACHE_UNLOCK;
1023 send_cache_status_all();
1024 return send_error(ctx, 0);
1027 static int save_command(assuan_context_t ctx, char *line)
1029 gboolean cached = FALSE;
1030 guchar shakey[gcrykeysize];
1031 struct stat st;
1032 struct client_s *client = assuan_get_pointer(ctx);
1033 gpg_error_t error;
1035 memset(shakey, 0, sizeof(shakey));
1036 error = file_modified(client);
1038 if (error) {
1039 log_write("%s: %s", client->filename ? client->filename : "",
1040 pwmd_strerror(error));
1041 return send_error(ctx, error);
1044 error = lock_file_mutex(client);
1046 if (error)
1047 return send_error(ctx, error);
1049 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1050 return send_syserror(ctx, errno);
1052 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1053 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1054 return send_error(ctx, EPWMD_INVALID_FILENAME);
1057 if (get_key_file_integer(client->filename, "iterations") == -1)
1058 goto done;
1060 if (!line || !*line) {
1061 guchar tmp[sizeof(shakey)];
1062 CACHE_LOCK(ctx);
1064 memset(tmp, '!', sizeof(tmp));
1066 if (cache_get_key(client->md5file, shakey) == FALSE ||
1067 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1068 CACHE_UNLOCK;
1069 #ifdef WITH_PINENTRY
1070 if (get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1071 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1072 goto done;
1075 lock_pin_mutex(client);
1076 client->pinentry->which = PINENTRY_SAVE;
1077 error = pinentry_fork(ctx);
1079 if (error) {
1080 unlock_pin_mutex(client->pinentry);
1081 return send_error(ctx, error);
1084 client->pinentry->cb = save_command_finalize;
1085 client->pinentry->status = PINENTRY_INIT;
1086 return 0;
1087 #else
1088 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1089 goto done;
1090 #endif
1092 else {
1093 CACHE_UNLOCK;
1094 cached = TRUE;
1097 else {
1098 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1099 memset(line, 0, strlen(line));
1102 done:
1103 return save_command_finalize(ctx, shakey, cached);
1106 static int delete_command(assuan_context_t ctx, char *line)
1108 struct client_s *client = assuan_get_pointer(ctx);
1109 gchar **req;
1110 gpg_error_t error;
1111 xmlNodePtr n;
1113 error = file_modified(client);
1115 if (error) {
1116 log_write("%s: %s", client->filename ? client->filename : "",
1117 pwmd_strerror(error));
1118 return send_error(ctx, error);
1121 if (strchr(line, '\t'))
1122 req = split_input_line(line, "\t", -1);
1123 else
1124 req = split_input_line(line, " ", -1);
1126 if (!req || !*req)
1127 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1129 n = find_account(client->doc, &req, &error, NULL, 0);
1131 if (!n) {
1132 g_strfreev(req);
1133 return send_error(ctx, error);
1137 * No sub-node defined. Remove the entire node (account).
1139 if (!req[1]) {
1140 if (n) {
1141 xmlUnlinkNode(n);
1142 xmlFreeNode(n);
1145 g_strfreev(req);
1146 return send_error(ctx, 0);
1149 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1150 g_strfreev(req);
1152 if (!n)
1153 return send_error(ctx, error);
1155 if (n) {
1156 xmlUnlinkNode(n);
1157 xmlFreeNode(n);
1160 return send_error(ctx, 0);
1164 * Don't return with assuan_process_done() here. This has been called from
1165 * assuan_process_next() and the command should be finished in
1166 * client_thread().
1168 static int store_command_finalize(gpointer data, gint rc, guchar *line,
1169 gsize len)
1171 assuan_context_t ctx = data;
1172 struct client_s *client = assuan_get_pointer(ctx);
1173 gchar **req;
1174 xmlNodePtr n;
1175 gpg_error_t error = file_modified(client);
1177 if (rc) {
1178 if (line)
1179 #ifndef MEM_DEBUG
1180 xfree(line);
1181 #else
1182 free(line);
1183 #endif
1184 return rc;
1187 req = split_input_line((gchar *)line, "\t", 0);
1188 #ifndef MEM_DEBUG
1189 xfree(line);
1190 #else
1191 free(line);
1192 #endif
1194 if (rc) {
1195 if (req)
1196 g_strfreev(req);
1198 return rc;
1201 if (!req || !*req)
1202 return EPWMD_COMMAND_SYNTAX;
1204 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1205 g_strfreev(req);
1206 return EPWMD_INVALID_ELEMENT;
1209 if (valid_element_path(req+1, TRUE) == FALSE) {
1210 g_strfreev(req);
1211 return EPWMD_INVALID_ELEMENT;
1214 again:
1215 n = find_account(client->doc, &req, &error, NULL, 0);
1217 if (error && error == EPWMD_ELEMENT_NOT_FOUND) {
1218 error = new_account(client->doc, *req);
1220 if (error) {
1221 g_strfreev(req);
1222 return error;
1225 goto again;
1228 if (!n) {
1229 g_strfreev(req);
1230 return error;
1233 if (req[1]) {
1234 if (!n->children)
1235 create_elements_cb(n, req+1, &error, NULL);
1236 else
1237 find_elements(client->doc, n->children, req+1, &error,
1238 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1241 g_strfreev(req);
1242 client->inquire_status = INQUIRE_DONE;
1243 return error;
1246 static int store_command(assuan_context_t ctx, char *line)
1248 struct client_s *client = assuan_get_pointer(ctx);
1249 gpg_error_t error = file_modified(client);
1251 if (error) {
1252 log_write("%s: %s", client->filename ? client->filename : "",
1253 pwmd_strerror(error));
1254 return send_error(ctx, error);
1257 error = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1259 if (error)
1260 return send_error(ctx, error);
1262 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1263 client->inquire_status = INQUIRE_BUSY;
1264 return 0;
1267 static int get_command(assuan_context_t ctx, char *line)
1269 struct client_s *client = assuan_get_pointer(ctx);
1270 gchar **req;
1271 gpg_error_t error;
1272 xmlNodePtr n;
1274 error = file_modified(client);
1276 if (error) {
1277 log_write("%s: %s", client->filename ? client->filename : "",
1278 pwmd_strerror(error));
1279 return send_error(ctx, error);
1282 req = split_input_line(line, "\t", -1);
1284 if (!req || !*req) {
1285 g_strfreev(req);
1286 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1289 n = find_account(client->doc, &req, &error, NULL, 0);
1291 if (!n) {
1292 g_strfreev(req);
1293 return send_error(ctx, error);
1296 if (req[1])
1297 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1299 g_strfreev(req);
1301 if (error)
1302 return send_error(ctx, error);
1304 if (!n || !n->children)
1305 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1307 n = find_text_node(n->children);
1309 if (!n || !n->content || !*n->content)
1310 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1312 error = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1313 return send_error(ctx, error);
1316 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1317 gpg_error_t *error, gchar **req_orig, void *data)
1319 gchar *path = *(gchar **)data;
1320 gchar *tmp = NULL, *result;
1322 if (path) {
1323 g_free(path);
1324 *(gchar **)data = NULL;
1327 path = g_strjoinv("\t", target);
1329 if (!path) {
1330 *error = gpg_error_from_errno(ENOMEM);
1331 return NULL;
1334 if (req_orig) {
1335 tmp = g_strjoinv("\t", req_orig);
1337 if (!tmp) {
1338 g_free(path);
1339 *error = gpg_error_from_errno(ENOMEM);
1340 return NULL;
1344 if (tmp && *tmp)
1345 result = g_strdup_printf("%s\t%s", path, tmp);
1346 else
1347 result = g_strdup(path);
1349 if (!result) {
1350 *error = gpg_error_from_errno(ENOMEM);
1351 g_free(path);
1352 g_free(tmp);
1353 return NULL;
1356 g_free(path);
1357 g_free(tmp);
1358 *(gchar **)data = result;
1359 return node;
1362 static int realpath_command(assuan_context_t ctx, char *line)
1364 gpg_error_t error;
1365 struct client_s *client = assuan_get_pointer(ctx);
1366 gchar **req;
1367 gchar *t;
1368 gint i;
1369 xmlNodePtr n;
1370 GString *string;
1371 gchar *rp = NULL;
1373 error = file_modified(client);
1375 if (error) {
1376 log_write("%s: %s", client->filename ? client->filename : "",
1377 pwmd_strerror(error));
1378 return send_error(ctx, error);
1381 if (strchr(line, '\t') != NULL) {
1382 if ((req = split_input_line(line, "\t", 0)) == NULL)
1383 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1385 else {
1386 if ((req = split_input_line(line, " ", 0)) == NULL)
1387 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1390 n = find_account(client->doc, &req, &error, NULL, 0);
1392 if (!n) {
1393 g_strfreev(req);
1394 return send_error(ctx, error);
1397 rp = g_strjoinv("\t", req);
1399 if (!rp) {
1400 g_strfreev(req);
1401 return send_syserror(ctx, ENOMEM);
1404 if (req[1]) {
1405 n = find_elements(client->doc, n->children, req+1, &error,
1406 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1408 if (!n) {
1409 g_free(rp);
1410 g_strfreev(req);
1411 return send_error(ctx, error);
1415 string = g_string_new(rp);
1416 g_free(rp);
1417 g_strfreev(req);
1419 if (!string)
1420 return send_syserror(ctx, ENOMEM);
1422 again:
1423 for (i = 0, t = string->str + i; *t; t++, i++) {
1424 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1425 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1426 goto again;
1430 error = assuan_send_data(ctx, string->str, string->len);
1431 g_string_free(string, TRUE);
1432 return send_error(ctx, error);
1435 static int list_command(assuan_context_t ctx, char *line)
1437 struct client_s *client = assuan_get_pointer(ctx);
1438 gpg_error_t rc;
1439 struct element_list_s *elements = NULL;
1440 gchar *tmp;
1442 if (disable_list_and_dump == TRUE)
1443 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1445 rc = file_modified(client);
1447 if (rc) {
1448 log_write("%s: %s", client->filename, pwmd_strerror(rc));
1449 return send_error(ctx, rc);
1452 if (!*line) {
1453 GString *str;
1455 rc = list_accounts(client->doc, &str);
1457 if (rc)
1458 return send_error(ctx, rc);
1460 rc = assuan_send_data(ctx, str->str, str->len);
1461 g_string_free(str, TRUE);
1462 return send_error(ctx, rc);
1465 elements = g_malloc0(sizeof(struct element_list_s));
1467 if (!elements) {
1468 rc = gpg_err_code_from_errno(ENOMEM);
1469 goto fail;
1472 rc = create_path_list(client->doc, elements, line);
1474 if (rc)
1475 goto fail;
1477 if (elements) {
1478 gint total = g_slist_length(elements->list);
1479 gint i;
1480 GString *str;
1482 if (!total) {
1483 rc = EPWMD_EMPTY_ELEMENT;
1484 goto fail;
1487 str = g_string_new(NULL);
1489 if (!str) {
1490 rc = gpg_err_code_from_errno(ENOMEM);
1491 goto fail;
1494 for (i = 0; i < total; i++) {
1495 tmp = g_slist_nth_data(elements->list, i);
1496 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1499 rc = assuan_send_data(ctx, str->str, str->len);
1500 g_string_free(str, TRUE);
1502 else
1503 rc = EPWMD_EMPTY_ELEMENT;
1505 fail:
1506 if (elements) {
1507 gint total = g_slist_length(elements->list);
1508 gint i;
1510 for (i = 0; i < total; i++) {
1511 tmp = g_slist_nth_data(elements->list, i);
1512 g_free(tmp);
1515 g_slist_free(elements->list);
1517 if (elements->prefix)
1518 g_free(elements->prefix);
1520 g_free(elements);
1523 return send_error(ctx, rc);
1526 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1527 const gchar *value)
1529 xmlAttrPtr a;
1531 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1532 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1534 if (!a)
1535 return EPWMD_LIBXML_ERROR;
1537 else
1538 xmlNodeSetContent(a->children, (xmlChar *)value);
1540 return 0;
1544 * req[0] - element path
1546 static int attribute_list(assuan_context_t ctx, gchar **req)
1548 struct client_s *client = assuan_get_pointer(ctx);
1549 gchar **attrlist = NULL;
1550 gint i = 0;
1551 gchar **path = NULL;
1552 xmlAttrPtr a;
1553 xmlNodePtr n, an;
1554 gchar *line;
1555 gpg_error_t error;
1557 if (!req || !req[0])
1558 return EPWMD_COMMAND_SYNTAX;
1560 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1562 * The first argument may be only an account.
1564 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1565 return EPWMD_COMMAND_SYNTAX;
1568 n = find_account(client->doc, &path, &error, NULL, 0);
1570 if (!n) {
1571 g_strfreev(path);
1572 return error;
1575 if (path[1]) {
1576 n = find_elements(client->doc, n->children, path+1, &error,
1577 NULL, NULL, NULL, FALSE, 0, NULL);
1579 if (!n) {
1580 g_strfreev(path);
1581 return error;
1585 g_strfreev(path);
1587 for (a = n->properties; a; a = a->next) {
1588 gchar **pa;
1590 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1591 if (attrlist)
1592 g_strfreev(attrlist);
1594 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1595 return gpg_error_from_errno(ENOMEM);
1598 attrlist = pa;
1599 an = a->children;
1600 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1602 if (!attrlist[i]) {
1603 g_strfreev(attrlist);
1604 return gpg_error_from_errno(ENOMEM);
1607 attrlist[++i] = NULL;
1610 if (!attrlist)
1611 return EPWMD_EMPTY_ELEMENT;
1613 line = g_strjoinv("\n", attrlist);
1615 if (!line) {
1616 g_strfreev(attrlist);
1617 return gpg_error_from_errno(ENOMEM);
1620 error = assuan_send_data(ctx, line, strlen(line));
1621 g_free(line);
1622 g_strfreev(attrlist);
1623 return error;
1627 * req[0] - attribute
1628 * req[1] - element path
1630 static int attribute_delete(struct client_s *client, gchar **req)
1632 xmlAttrPtr a;
1633 xmlNodePtr n;
1634 gchar **path = NULL;
1635 gpg_error_t error;
1637 if (!req || !req[0] || !req[1])
1638 return EPWMD_COMMAND_SYNTAX;
1640 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1642 * The first argument may be only an account.
1644 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1645 return EPWMD_COMMAND_SYNTAX;
1649 * Don't remove the "name" attribute for the account element. To remove an
1650 * account use DELETE <account>.
1652 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1653 error = EPWMD_ATTR_SYNTAX;
1654 goto fail;
1657 n = find_account(client->doc, &path, &error, NULL, 0);
1659 if (!n)
1660 goto fail;
1662 if (path[1]) {
1663 n = find_elements(client->doc, n->children, path+1, &error,
1664 NULL, NULL, NULL, FALSE, 0, NULL);
1666 if (!n)
1667 goto fail;
1670 g_strfreev(path);
1672 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1673 return EPWMD_ATTR_NOT_FOUND;
1675 if (xmlRemoveProp(a) == -1)
1676 return EPWMD_LIBXML_ERROR;
1678 return 0;
1680 fail:
1681 g_strfreev(path);
1682 return error;
1686 * Creates a "target" attribute. When other commands encounter an element with
1687 * this attribute, the element path is modified to the target value. If the
1688 * source element path doesn't exist when using 'ATTR SET target', it is
1689 * created, but the destination element path must exist.
1691 * req[0] - source element path
1692 * req[1] - destination element path
1694 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1696 gchar **src, **dst, *line = NULL;
1697 gpg_error_t error;
1698 xmlNodePtr n;
1699 gchar **src_orig = NULL;
1701 if (!req || !req[0] || !req[1])
1702 return EPWMD_COMMAND_SYNTAX;
1704 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1706 * The first argument may be only an account.
1708 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1709 return EPWMD_COMMAND_SYNTAX;
1712 if (valid_element_path(src, FALSE) == FALSE) {
1713 g_strfreev(src);
1714 return EPWMD_INVALID_ELEMENT;
1717 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1719 * The first argument may be only an account.
1721 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1722 error = EPWMD_COMMAND_SYNTAX;
1723 goto fail;
1727 n = find_account(client->doc, &dst, &error, NULL, 0);
1730 * Make sure the destination element path exists.
1732 if (!n)
1733 goto fail;
1735 if (dst[1]) {
1736 n = find_elements(client->doc, n->children, dst+1, &error,
1737 NULL, NULL, NULL, FALSE, 0, NULL);
1739 if (!n)
1740 goto fail;
1743 again:
1744 src_orig = g_strdupv(src);
1746 if (!src_orig) {
1747 error = gpg_error_from_errno(ENOMEM);
1748 goto fail;
1751 n = find_account(client->doc, &src, &error, NULL, 0);
1753 if (!n) {
1754 if (error == EPWMD_ELEMENT_NOT_FOUND) {
1755 error = new_account(client->doc, src[0]);
1757 if (error)
1758 goto fail;
1760 goto again;
1762 else
1763 goto fail;
1766 if (src[1]) {
1767 if (!n->children)
1768 n = create_target_elements_cb(n, src+1, &error, NULL);
1769 else
1770 n = find_elements(client->doc, n->children, src+1, &error,
1771 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1773 if (!n)
1774 goto fail;
1777 * Reset the position of the element tree now that the elements
1778 * have been created.
1780 g_strfreev(src);
1781 src = src_orig;
1782 src_orig = NULL;
1783 n = find_account(client->doc, &src, &error, NULL, 0);
1785 if (!n)
1786 goto fail;
1788 n = find_elements(client->doc, n->children, src+1, &error,
1789 NULL, NULL, NULL, FALSE, 0, NULL);
1791 if (!n)
1792 goto fail;
1795 line = g_strjoinv("\t", dst);
1797 if (!line) {
1798 error = gpg_error_from_errno(ENOMEM);
1799 goto fail;
1802 error = add_attribute(n, "target", line);
1804 fail:
1805 g_free(line);
1806 g_strfreev(src);
1807 g_strfreev(dst);
1808 g_strfreev(src_orig);
1809 return error;
1813 * req[0] - account name
1814 * req[1] - new name
1816 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
1818 gpg_error_t error;
1819 gchar **tmp;
1820 xmlNodePtr n;
1822 tmp = g_strdupv(req);
1824 if (!tmp)
1825 return gpg_error_from_errno(ENOMEM);
1827 n = find_account(client->doc, &tmp, &error, NULL, 0);
1828 g_strfreev(tmp);
1830 if (!n)
1831 return error;
1833 if (g_utf8_collate(req[0], req[1]) == 0)
1834 return 0;
1837 * Will not overwrite an existing account.
1839 tmp = g_strdupv(req+1);
1841 if (!tmp)
1842 return gpg_error_from_errno(ENOMEM);
1844 n = find_account(client->doc, &tmp, &error, NULL, 0);
1845 g_strfreev(tmp);
1847 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1848 return error;
1850 if (n)
1851 return EPWMD_ACCOUNT_EXISTS;
1854 * Whitespace not allowed in account names.
1856 if (contains_whitespace(req[1]) == TRUE)
1857 return EPWMD_ATTR_SYNTAX;
1859 tmp = g_strdupv(req);
1861 if (!tmp)
1862 return gpg_error_from_errno(ENOMEM);
1864 n = find_account(client->doc, &tmp, &error, NULL, 0);
1865 g_strfreev(tmp);
1867 if (!n)
1868 return EPWMD_ELEMENT_NOT_FOUND;
1870 return add_attribute(n, "name", req[1]);
1874 * req[0] - attribute
1875 * req[1] - element path
1877 static int attribute_get(assuan_context_t ctx, gchar **req)
1879 struct client_s *client = assuan_get_pointer(ctx);
1880 xmlNodePtr n;
1881 xmlChar *a;
1882 gchar **path= NULL;
1883 gpg_error_t error;
1885 if (!req || !req[0] || !req[1])
1886 return EPWMD_COMMAND_SYNTAX;
1888 if (strchr(req[1], '\t')) {
1889 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
1890 return EPWMD_COMMAND_SYNTAX;
1892 else {
1893 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1894 return EPWMD_COMMAND_SYNTAX;
1897 n = find_account(client->doc, &path, &error, NULL, 0);
1899 if (!n)
1900 goto fail;
1902 if (path[1]) {
1903 n = find_elements(client->doc, n->children, path+1, &error,
1904 NULL, NULL, NULL, FALSE, 0, NULL);
1906 if (!n)
1907 goto fail;
1910 g_strfreev(path);
1912 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
1913 return EPWMD_ATTR_NOT_FOUND;
1915 error = assuan_send_data(ctx, a, xmlStrlen(a));
1916 xmlFree(a);
1917 return error;
1919 fail:
1920 g_strfreev(path);
1921 return error;
1925 * req[0] - attribute
1926 * req[1] - element path
1927 * req[2] - value
1929 static int attribute_set(struct client_s *client, gchar **req)
1931 gchar **path = NULL;
1932 gpg_error_t error;
1933 xmlNodePtr n;
1935 if (!req || !req[0] || !req[1] || !req[2])
1936 return EPWMD_COMMAND_SYNTAX;
1939 * Reserved attribute names.
1941 if (g_utf8_collate(req[0], "name") == 0) {
1943 * Only reserved for the account element. Not the rest of the
1944 * document.
1946 if (strchr(req[1], '\t') == NULL)
1947 return name_attribute(client, req + 1);
1949 else if (g_utf8_collate(req[0], "target") == 0)
1950 return target_attribute(client, req + 1);
1952 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1954 * The first argument may be only an account.
1956 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1957 return EPWMD_COMMAND_SYNTAX;
1960 n = find_account(client->doc, &path, &error, NULL, 0);
1962 if (!n)
1963 goto fail;
1965 if (path[1]) {
1966 n = find_elements(client->doc, n->children, path+1, &error,
1967 NULL, NULL, NULL, FALSE, 0, NULL);
1969 if (!n)
1970 goto fail;
1973 g_strfreev(path);
1974 return add_attribute(n, req[0], req[2]);
1976 fail:
1977 g_strfreev(path);
1978 return error;
1982 * req[0] - command
1983 * req[1] - attribute name or element path if command is LIST
1984 * req[2] - element path
1985 * req[2] - element path or value
1987 static int attr_command(assuan_context_t ctx, char *line)
1989 struct client_s *client = assuan_get_pointer(ctx);
1990 gchar **req = split_input_line(line, " ", 4);
1991 gpg_error_t error = 0;
1993 error = file_modified(client);
1995 if (error) {
1996 log_write("%s: %s", client->filename ? client->filename : "",
1997 pwmd_strerror(error));
1998 g_strfreev(req);
1999 return send_error(ctx, error);
2002 if (!req || !req[0] || !req[1]) {
2003 g_strfreev(req);
2004 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2007 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2008 error = attribute_set(client, req+1);
2009 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2010 error = attribute_get(ctx, req+1);
2011 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2012 error = attribute_delete(client, req+1);
2013 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2014 error = attribute_list(ctx, req+1);
2015 else
2016 error = EPWMD_COMMAND_SYNTAX;
2018 g_strfreev(req);
2019 return send_error(ctx, error);
2022 static int iscached_command(assuan_context_t ctx, char *line)
2024 gchar **req = split_input_line(line, " ", 0);
2025 guchar md5file[16];
2027 if (!req || !*req) {
2028 g_strfreev(req);
2029 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2032 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2033 g_strfreev(req);
2034 CACHE_LOCK(ctx);
2036 if (cache_iscached(md5file) == FALSE) {
2037 CACHE_UNLOCK;
2038 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2041 CACHE_UNLOCK;
2042 return send_error(ctx, 0);
2045 gpg_error_t send_cache_status(assuan_context_t ctx)
2047 gchar *tmp;
2048 struct client_s *client = assuan_get_pointer(ctx);
2049 gchar buf[ASSUAN_LINELENGTH];
2051 CACHE_LOCK(client->ctx);
2052 tmp = print_fmt(buf, sizeof(buf), "%i %i",
2053 cache_file_count(),
2054 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2055 CACHE_UNLOCK;
2057 return assuan_write_status(ctx, "CACHE", buf);
2060 static int clearcache_command(assuan_context_t ctx, char *line)
2062 struct client_s *client = assuan_get_pointer(ctx);
2063 gchar **req = split_input_line(line, " ", 0);
2064 guchar md5file[16];
2066 CACHE_LOCK(ctx);
2068 if (!req || !*req) {
2069 g_strfreev(req);
2070 cache_clear(client->md5file, 2);
2071 CACHE_UNLOCK;
2072 return send_error(ctx, 0);
2075 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2076 g_strfreev(req);
2078 if (cache_clear(md5file, 1) == FALSE) {
2079 CACHE_UNLOCK;
2080 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2083 CACHE_UNLOCK;
2084 return send_error(ctx, 0);
2087 static int cachetimeout_command(assuan_context_t ctx, char *line)
2089 guchar md5file[16];
2090 glong timeout;
2091 gchar **req = split_input_line(line, " ", 0);
2092 gchar *p;
2093 struct client_s *client = assuan_get_pointer(ctx);
2095 if (!req || !*req || !req[1]) {
2096 g_strfreev(req);
2097 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2100 errno = 0;
2101 timeout = strtol(req[0], &p, 10);
2103 if (errno != 0 || *p != 0) {
2104 g_strfreev(req);
2105 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2108 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2109 g_strfreev(req);
2110 CACHE_LOCK(client->ctx);
2112 if (cache_set_timeout(md5file, timeout) == FALSE) {
2113 CACHE_UNLOCK;
2114 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2117 CACHE_UNLOCK;
2118 return send_error(ctx, 0);
2121 static int dump_command(assuan_context_t ctx, char *line)
2123 xmlChar *xml;
2124 gssize len;
2125 struct client_s *client = assuan_get_pointer(ctx);
2126 gpg_error_t error;
2128 if (disable_list_and_dump == TRUE)
2129 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2131 error = file_modified(client);
2133 if (error) {
2134 log_write("%s: %s", client->filename ? client->filename : "",
2135 pwmd_strerror(error));
2136 return send_error(ctx, error);
2139 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2141 if (!xml)
2142 return send_syserror(ctx, ENOMEM);
2144 error = assuan_send_data(ctx, xml, len);
2145 xmlFree(xml);
2146 return send_error(ctx, error);
2149 static int getconfig_command(assuan_context_t ctx, gchar *line)
2151 struct client_s *client = assuan_get_pointer(ctx);
2152 gpg_error_t error = 0;
2153 gchar *p, *tmp;
2155 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2156 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2158 p = get_key_file_string(client->filename ? client->filename : "global", line);
2160 if (!p)
2161 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2163 tmp = expand_homedir(p);
2165 if (!tmp) {
2166 g_free(p);
2167 return send_syserror(ctx, ENOMEM);
2170 g_free(p);
2171 p = tmp;
2172 error = assuan_send_data(ctx, p, strlen(p));
2173 g_free(p);
2174 return send_error(ctx, error);
2177 void cleanup_assuan(assuan_context_t ctx)
2179 struct client_s *cl = assuan_get_pointer(ctx);
2181 if (cl)
2182 cleanup_client(cl);
2185 static void reset_notify(assuan_context_t ctx)
2187 struct client_s *cl = assuan_get_pointer(ctx);
2189 if (cl)
2190 cleanup_client(cl);
2193 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2195 gchar name[32] = {0}, value[256] = {0};
2197 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2198 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2200 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2201 pth_attr_t attr = pth_attr_of(pth_self());
2203 log_write("OPTION CLIENT %s", line);
2204 pth_attr_set(attr, PTH_ATTR_NAME, value);
2205 pth_attr_destroy(attr);
2207 else
2208 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2210 return 0;
2213 static int option_handler(assuan_context_t ctx, const gchar *name,
2214 const gchar *value)
2216 #ifdef WITH_PINENTRY
2217 struct client_s *client = assuan_get_pointer(ctx);
2218 #endif
2220 if (!value || !*value)
2221 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2223 if (g_strcasecmp(name, (gchar *)"client") == 0)
2224 return parse_client_option(ctx, value);
2226 #ifdef WITH_PINENTRY
2227 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2228 g_free(client->pinentry->ttyname);
2229 client->pinentry->ttyname = g_strdup(value);
2231 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2232 g_free(client->pinentry->ttytype);
2233 client->pinentry->ttytype = g_strdup(value);
2235 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2236 g_free(client->pinentry->display);
2237 client->pinentry->display = g_strdup(value);
2239 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2240 g_free(client->pinentry->path);
2241 client->pinentry->path = g_strdup(value);
2243 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2244 g_free(client->pinentry->title);
2245 client->pinentry->title = g_strdup(value);
2247 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2248 g_free(client->pinentry->prompt);
2249 client->pinentry->prompt = g_strdup(value);
2251 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2252 g_free(client->pinentry->desc);
2253 client->pinentry->desc = g_strdup(value);
2255 #if 0
2256 /* Need to wait for pinentry to support a --timeout option so it can
2257 * terminate itself. Cannot do it here because assuan_pipe_connect() calls
2258 * execv() which replaces the pid of the fork()ed thread from
2259 * pinentry_fork(). So pinentry will become a real process after the
2260 * thread terminates and won't be able to be kill()ed from pwmd.
2262 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2263 gchar *p = NULL;
2264 gint n = strtol(value, &p, 10);
2266 if (*p || n < 0)
2267 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2269 client->pinentry->timeout = n;
2271 #endif
2272 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2273 gchar *p = NULL;
2274 gint n = strtol(value, &p, 10);
2276 if (*p || n < 0 || n > 1)
2277 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2279 g_key_file_set_boolean(keyfileh, client->filename ? client->filename : "global",
2280 "enable_pinentry", n == 0 ? FALSE : TRUE);
2282 else
2283 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2284 #else
2285 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
2286 #endif
2288 log_write("OPTION %s=%s", name, value);
2289 return 0;
2292 gpg_error_t register_commands(assuan_context_t ctx)
2294 static struct {
2295 const gchar *name;
2296 gint (*handler)(assuan_context_t, gchar *line);
2297 } table[] = {
2298 { "OPEN", open_command },
2299 { "SAVE", save_command },
2300 { "LIST", list_command },
2301 { "REALPATH", realpath_command },
2302 { "STORE", store_command },
2303 { "DELETE", delete_command },
2304 { "GET", get_command },
2305 { "ATTR", attr_command },
2306 { "ISCACHED", iscached_command },
2307 { "CLEARCACHE", clearcache_command },
2308 { "CACHETIMEOUT", cachetimeout_command },
2309 { "GETCONFIG", getconfig_command },
2310 { "DUMP", dump_command },
2311 { "INPUT", NULL },
2312 { "OUTPUT", NULL },
2313 { NULL, NULL }
2315 gint i, rc;
2317 for (i=0; table[i].name; i++) {
2318 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2320 if (rc)
2321 return rc;
2324 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2326 if (rc)
2327 return rc;
2329 rc = assuan_register_option_handler(ctx, option_handler);
2331 if (rc)
2332 return rc;
2334 return assuan_register_reset_notify(ctx, reset_notify);
2337 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2338 guchar *key)
2340 guchar *iv;
2341 void *inbuf;
2342 gsize insize, len;
2343 guchar tkey[gcrykeysize];
2344 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2345 gcry_cipher_hd_t gh;
2346 guint iter = 0, n_iter = 0;
2347 gint iter_progress;
2348 void *outbuf = NULL;
2349 gint zerror = 0;
2350 glong outsize = 0;
2351 gpg_error_t error;
2352 file_header_t file_header;
2353 gchar str[ASSUAN_LINELENGTH];
2355 if (!ctx) {
2356 error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2358 if (error)
2359 return error;
2361 else
2362 gh = client->gh;
2364 lseek(fd, 0, SEEK_SET);
2365 insize = st.st_size - sizeof(file_header_t);
2366 iv = gcry_malloc(gcryblocksize);
2368 if (!iv) {
2369 if (!ctx)
2370 gcry_cipher_close(gh);
2372 return gpg_error_from_errno(ENOMEM);
2375 len = pth_read(fd, &file_header, sizeof(file_header_t));
2377 if (len != sizeof(file_header_t)) {
2378 len = errno;
2380 if (!ctx)
2381 gcry_cipher_close(gh);
2383 gcry_free(iv);
2384 errno = len;
2385 return gpg_error_from_errno(errno);
2388 /* No encryption iterations. This is a plain (gzipped) file. */
2389 if (file_header.iter == -1) {
2391 * cache_file_count() needs both .used == TRUE and a valid key in
2392 * order for it to count as a used cache entry. Fixes CACHE status
2393 * messages.
2395 memset(key, '!', gcrykeysize);
2396 insize = st.st_size - sizeof(file_header_t);
2399 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2400 inbuf = gcry_malloc(insize);
2402 if (!inbuf) {
2403 if (!ctx)
2404 gcry_cipher_close(gh);
2406 gcry_free(iv);
2407 return gpg_error_from_errno(ENOMEM);
2410 len = pth_read(fd, inbuf, insize);
2412 if (len != insize) {
2413 len = errno;
2415 if (!ctx)
2416 gcry_cipher_close(gh);
2418 gcry_free(iv);
2419 errno = len;
2420 return gpg_error_from_errno(errno);
2423 if (file_header.iter == -1)
2424 goto decompress;
2426 memcpy(tkey, key, sizeof(tkey));
2427 tkey[0] ^= 1;
2429 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2430 if (!ctx) {
2431 gcry_cipher_close(gh);
2432 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2434 else
2435 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2437 gcry_free(inbuf);
2438 gcry_free(iv);
2439 return error;
2442 if ((error = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2443 if (!ctx) {
2444 gcry_cipher_close(gh);
2445 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2447 else
2448 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2450 gcry_free(inbuf);
2451 gcry_free(iv);
2453 if (!ctx)
2454 gcry_cipher_close(gh);
2456 return error;
2459 iter_progress = get_key_file_integer("global", "iteration_progress");
2461 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2462 error = assuan_write_status(client->ctx, "DECRYPT", "0");
2464 if (error) {
2465 gcry_free(inbuf);
2466 gcry_free(iv);
2467 return error;
2471 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2473 if (error) {
2474 gcry_free(inbuf);
2475 gcry_free(iv);
2476 return error;
2479 if ((error = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2480 if (!ctx) {
2481 gcry_cipher_close(gh);
2482 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2484 else
2485 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2487 gcry_free(inbuf);
2488 gcry_free(iv);
2489 return error;
2492 while (iter < file_header.iter) {
2493 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2494 if (!(iter % iter_progress)) {
2495 error = assuan_write_status(ctx, "DECRYPT",
2496 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
2498 if (error) {
2499 gcry_free(inbuf);
2500 gcry_free(iv);
2501 return error;
2506 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2507 if (!ctx) {
2508 gcry_cipher_close(gh);
2509 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2511 else
2512 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2514 gcry_free(inbuf);
2515 gcry_free(iv);
2516 return error;
2519 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2521 if (error) {
2522 if (!ctx) {
2523 gcry_cipher_close(gh);
2524 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2526 else
2527 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2529 gcry_free(inbuf);
2530 gcry_free(iv);
2531 return error;
2534 iter++;
2535 pth_yield(NULL);
2538 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2539 error = assuan_write_status(ctx, "DECRYPT",
2540 print_fmt(str, sizeof(str), "%i", file_header.iter));
2542 if (error) {
2543 gcry_free(inbuf);
2544 gcry_free(iv);
2545 return error;
2549 gcry_free(iv);
2551 decompress:
2552 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zerror) == FALSE) {
2554 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2556 if (zerror == Z_MEM_ERROR) {
2557 gcry_free(inbuf);
2558 return gpg_error_from_errno(ENOMEM);
2560 else if (zerror != Z_DATA_ERROR) {
2561 gcry_free(inbuf);
2563 if (!ctx)
2564 gcry_cipher_close(gh);
2566 return EPWMD_BADKEY;
2569 else {
2570 gcry_free(inbuf);
2571 inbuf = outbuf;
2572 insize = outsize;
2575 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2576 gcry_free(inbuf);
2578 if (!ctx)
2579 gcry_cipher_close(gh);
2581 return EPWMD_BADKEY;
2584 if (ctx) {
2585 client->xml = inbuf;
2586 client->len = insize;
2588 else {
2589 gcry_cipher_close(gh);
2590 gcry_free(inbuf);
2593 return 0;
2597 * This is called after every Assuan command.
2599 void command_finalize(assuan_context_t ctx, gint error)
2601 struct client_s *client = assuan_get_pointer(ctx);
2603 unlock_file_mutex(client);