Added the "backup" configuration parameter. When "true", the default,
[pwmd.git] / src / commands.c
blobe595c8650f08f9b37d55bd88fcec06497899b6df
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 (get_key_file_boolean(filename, "backup") == TRUE) {
935 gchar tmp2[FILENAME_MAX];
937 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
939 if (rename(filename, tmp2) == -1) {
940 len = errno;
941 gcry_free(inbuf);
942 return gpg_error_from_errno(len);
947 if (rename(tmp, filename) == -1) {
948 len = errno;
949 gcry_free(inbuf);
950 return gpg_error_from_errno(len);
953 if (mode)
954 chmod(filename, mode);
957 gcry_free(inbuf);
958 return 0;
961 static gpg_error_t save_command_finalize(assuan_context_t ctx,
962 guchar shakey[], gboolean cached)
964 struct client_s *client = assuan_get_pointer(ctx);
965 gpointer xmlbuf;
966 xmlChar *p;
967 gint len;
968 gint iter;
969 gint timeout;
970 gpointer outbuf;
971 glong outsize = 0;
972 gint zerror;
973 gpg_error_t error;
974 struct stat st;
976 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
977 xmlbuf = p;
979 iter = get_key_file_integer(client->filename, "compression_level");
981 if (iter < 0)
982 iter = 0;
984 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zerror) == FALSE) {
985 memset(shakey, 0, sizeof(shakey));
986 xmlFree(xmlbuf);
988 if (zerror == Z_MEM_ERROR) {
989 return send_syserror(ctx, ENOMEM);
991 else
992 return send_error(ctx, GPG_ERR_COMPR_ALGO);
994 else {
995 gcry_free(xmlbuf);
996 xmlbuf = outbuf;
997 len = outsize;
1000 iter = get_key_file_integer(client->filename, "iterations");
1001 error = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1003 if (error) {
1004 memset(shakey, 0, sizeof(shakey));
1005 return send_error(ctx, error);
1008 stat(client->filename, &st);
1009 client->mtime = st.st_mtime;
1010 timeout = get_key_file_integer(client->filename, "cache_timeout");
1011 CACHE_LOCK(client->ctx);
1013 if (cached) {
1014 memset(shakey, 0, sizeof(shakey));
1015 cache_reset_timeout(client->md5file, timeout);
1016 CACHE_UNLOCK;
1018 if (client->new == TRUE)
1019 send_cache_status_all();
1021 client->new = FALSE;
1022 return send_error(ctx, 0);
1025 if (cache_update_key(client->md5file, shakey) == FALSE) {
1026 memset(shakey, 0, sizeof(shakey));
1027 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1028 CACHE_UNLOCK;
1029 return send_error(ctx, EPWMD_MAX_SLOTS);
1032 client->new = FALSE;
1033 memset(shakey, 0, sizeof(shakey));
1034 cache_reset_timeout(client->md5file, timeout);
1035 CACHE_UNLOCK;
1036 send_cache_status_all();
1037 return send_error(ctx, 0);
1040 static int save_command(assuan_context_t ctx, char *line)
1042 gboolean cached = FALSE;
1043 guchar shakey[gcrykeysize];
1044 struct stat st;
1045 struct client_s *client = assuan_get_pointer(ctx);
1046 gpg_error_t error;
1048 memset(shakey, 0, sizeof(shakey));
1049 error = file_modified(client);
1051 if (error) {
1052 log_write("%s: %s", client->filename ? client->filename : "",
1053 pwmd_strerror(error));
1054 return send_error(ctx, error);
1057 error = lock_file_mutex(client);
1059 if (error)
1060 return send_error(ctx, error);
1062 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1063 return send_syserror(ctx, errno);
1065 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1066 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1067 return send_error(ctx, EPWMD_INVALID_FILENAME);
1070 if (get_key_file_integer(client->filename, "iterations") == -1)
1071 goto done;
1073 if (!line || !*line) {
1074 guchar tmp[sizeof(shakey)];
1075 CACHE_LOCK(ctx);
1077 memset(tmp, '!', sizeof(tmp));
1079 if (cache_get_key(client->md5file, shakey) == FALSE ||
1080 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1081 CACHE_UNLOCK;
1082 #ifdef WITH_PINENTRY
1083 if (get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1084 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1085 goto done;
1088 lock_pin_mutex(client);
1089 client->pinentry->which = PINENTRY_SAVE;
1090 error = pinentry_fork(ctx);
1092 if (error) {
1093 unlock_pin_mutex(client->pinentry);
1094 return send_error(ctx, error);
1097 client->pinentry->cb = save_command_finalize;
1098 client->pinentry->status = PINENTRY_INIT;
1099 return 0;
1100 #else
1101 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1102 goto done;
1103 #endif
1105 else {
1106 CACHE_UNLOCK;
1107 cached = TRUE;
1110 else {
1111 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1112 memset(line, 0, strlen(line));
1115 done:
1116 return save_command_finalize(ctx, shakey, cached);
1119 static int delete_command(assuan_context_t ctx, char *line)
1121 struct client_s *client = assuan_get_pointer(ctx);
1122 gchar **req;
1123 gpg_error_t error;
1124 xmlNodePtr n;
1126 error = file_modified(client);
1128 if (error) {
1129 log_write("%s: %s", client->filename ? client->filename : "",
1130 pwmd_strerror(error));
1131 return send_error(ctx, error);
1134 if (strchr(line, '\t'))
1135 req = split_input_line(line, "\t", -1);
1136 else
1137 req = split_input_line(line, " ", -1);
1139 if (!req || !*req)
1140 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1142 n = find_account(client->doc, &req, &error, NULL, 0);
1144 if (!n) {
1145 g_strfreev(req);
1146 return send_error(ctx, error);
1150 * No sub-node defined. Remove the entire node (account).
1152 if (!req[1]) {
1153 if (n) {
1154 xmlUnlinkNode(n);
1155 xmlFreeNode(n);
1158 g_strfreev(req);
1159 return send_error(ctx, 0);
1162 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1163 g_strfreev(req);
1165 if (!n)
1166 return send_error(ctx, error);
1168 if (n) {
1169 xmlUnlinkNode(n);
1170 xmlFreeNode(n);
1173 return send_error(ctx, 0);
1177 * Don't return with assuan_process_done() here. This has been called from
1178 * assuan_process_next() and the command should be finished in
1179 * client_thread().
1181 static int store_command_finalize(gpointer data, gint rc, guchar *line,
1182 gsize len)
1184 assuan_context_t ctx = data;
1185 struct client_s *client = assuan_get_pointer(ctx);
1186 gchar **req;
1187 xmlNodePtr n;
1188 gpg_error_t error = file_modified(client);
1190 if (rc) {
1191 if (line)
1192 #ifndef MEM_DEBUG
1193 xfree(line);
1194 #else
1195 free(line);
1196 #endif
1197 return rc;
1200 req = split_input_line((gchar *)line, "\t", 0);
1201 #ifndef MEM_DEBUG
1202 xfree(line);
1203 #else
1204 free(line);
1205 #endif
1207 if (rc) {
1208 if (req)
1209 g_strfreev(req);
1211 return rc;
1214 if (!req || !*req)
1215 return EPWMD_COMMAND_SYNTAX;
1217 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1218 g_strfreev(req);
1219 return EPWMD_INVALID_ELEMENT;
1222 if (valid_element_path(req+1, TRUE) == FALSE) {
1223 g_strfreev(req);
1224 return EPWMD_INVALID_ELEMENT;
1227 again:
1228 n = find_account(client->doc, &req, &error, NULL, 0);
1230 if (error && error == EPWMD_ELEMENT_NOT_FOUND) {
1231 error = new_account(client->doc, *req);
1233 if (error) {
1234 g_strfreev(req);
1235 return error;
1238 goto again;
1241 if (!n) {
1242 g_strfreev(req);
1243 return error;
1246 if (req[1]) {
1247 if (!n->children)
1248 create_elements_cb(n, req+1, &error, NULL);
1249 else
1250 find_elements(client->doc, n->children, req+1, &error,
1251 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1254 g_strfreev(req);
1255 client->inquire_status = INQUIRE_DONE;
1256 return error;
1259 static int store_command(assuan_context_t ctx, char *line)
1261 struct client_s *client = assuan_get_pointer(ctx);
1262 gpg_error_t error = file_modified(client);
1264 if (error) {
1265 log_write("%s: %s", client->filename ? client->filename : "",
1266 pwmd_strerror(error));
1267 return send_error(ctx, error);
1270 error = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1272 if (error)
1273 return send_error(ctx, error);
1275 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1276 client->inquire_status = INQUIRE_BUSY;
1277 return 0;
1280 static int get_command(assuan_context_t ctx, char *line)
1282 struct client_s *client = assuan_get_pointer(ctx);
1283 gchar **req;
1284 gpg_error_t error;
1285 xmlNodePtr n;
1287 error = file_modified(client);
1289 if (error) {
1290 log_write("%s: %s", client->filename ? client->filename : "",
1291 pwmd_strerror(error));
1292 return send_error(ctx, error);
1295 req = split_input_line(line, "\t", -1);
1297 if (!req || !*req) {
1298 g_strfreev(req);
1299 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1302 n = find_account(client->doc, &req, &error, NULL, 0);
1304 if (!n) {
1305 g_strfreev(req);
1306 return send_error(ctx, error);
1309 if (req[1])
1310 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1312 g_strfreev(req);
1314 if (error)
1315 return send_error(ctx, error);
1317 if (!n || !n->children)
1318 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1320 n = find_text_node(n->children);
1322 if (!n || !n->content || !*n->content)
1323 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1325 error = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1326 return send_error(ctx, error);
1329 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1330 gpg_error_t *error, gchar **req_orig, void *data)
1332 gchar *path = *(gchar **)data;
1333 gchar *tmp = NULL, *result;
1335 if (path) {
1336 g_free(path);
1337 *(gchar **)data = NULL;
1340 path = g_strjoinv("\t", target);
1342 if (!path) {
1343 *error = gpg_error_from_errno(ENOMEM);
1344 return NULL;
1347 if (req_orig) {
1348 tmp = g_strjoinv("\t", req_orig);
1350 if (!tmp) {
1351 g_free(path);
1352 *error = gpg_error_from_errno(ENOMEM);
1353 return NULL;
1357 if (tmp && *tmp)
1358 result = g_strdup_printf("%s\t%s", path, tmp);
1359 else
1360 result = g_strdup(path);
1362 if (!result) {
1363 *error = gpg_error_from_errno(ENOMEM);
1364 g_free(path);
1365 g_free(tmp);
1366 return NULL;
1369 g_free(path);
1370 g_free(tmp);
1371 *(gchar **)data = result;
1372 return node;
1375 static int realpath_command(assuan_context_t ctx, char *line)
1377 gpg_error_t error;
1378 struct client_s *client = assuan_get_pointer(ctx);
1379 gchar **req;
1380 gchar *t;
1381 gint i;
1382 xmlNodePtr n;
1383 GString *string;
1384 gchar *rp = NULL;
1386 error = file_modified(client);
1388 if (error) {
1389 log_write("%s: %s", client->filename ? client->filename : "",
1390 pwmd_strerror(error));
1391 return send_error(ctx, error);
1394 if (strchr(line, '\t') != NULL) {
1395 if ((req = split_input_line(line, "\t", 0)) == NULL)
1396 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1398 else {
1399 if ((req = split_input_line(line, " ", 0)) == NULL)
1400 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1403 n = find_account(client->doc, &req, &error, NULL, 0);
1405 if (!n) {
1406 g_strfreev(req);
1407 return send_error(ctx, error);
1410 rp = g_strjoinv("\t", req);
1412 if (!rp) {
1413 g_strfreev(req);
1414 return send_syserror(ctx, ENOMEM);
1417 if (req[1]) {
1418 n = find_elements(client->doc, n->children, req+1, &error,
1419 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1421 if (!n) {
1422 g_free(rp);
1423 g_strfreev(req);
1424 return send_error(ctx, error);
1428 string = g_string_new(rp);
1429 g_free(rp);
1430 g_strfreev(req);
1432 if (!string)
1433 return send_syserror(ctx, ENOMEM);
1435 again:
1436 for (i = 0, t = string->str + i; *t; t++, i++) {
1437 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1438 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1439 goto again;
1443 error = assuan_send_data(ctx, string->str, string->len);
1444 g_string_free(string, TRUE);
1445 return send_error(ctx, error);
1448 static int list_command(assuan_context_t ctx, char *line)
1450 struct client_s *client = assuan_get_pointer(ctx);
1451 gpg_error_t rc;
1452 struct element_list_s *elements = NULL;
1453 gchar *tmp;
1455 if (disable_list_and_dump == TRUE)
1456 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1458 rc = file_modified(client);
1460 if (rc) {
1461 log_write("%s: %s", client->filename, pwmd_strerror(rc));
1462 return send_error(ctx, rc);
1465 if (!*line) {
1466 GString *str;
1468 rc = list_accounts(client->doc, &str);
1470 if (rc)
1471 return send_error(ctx, rc);
1473 rc = assuan_send_data(ctx, str->str, str->len);
1474 g_string_free(str, TRUE);
1475 return send_error(ctx, rc);
1478 elements = g_malloc0(sizeof(struct element_list_s));
1480 if (!elements) {
1481 rc = gpg_err_code_from_errno(ENOMEM);
1482 goto fail;
1485 rc = create_path_list(client->doc, elements, line);
1487 if (rc)
1488 goto fail;
1490 if (elements) {
1491 gint total = g_slist_length(elements->list);
1492 gint i;
1493 GString *str;
1495 if (!total) {
1496 rc = EPWMD_EMPTY_ELEMENT;
1497 goto fail;
1500 str = g_string_new(NULL);
1502 if (!str) {
1503 rc = gpg_err_code_from_errno(ENOMEM);
1504 goto fail;
1507 for (i = 0; i < total; i++) {
1508 tmp = g_slist_nth_data(elements->list, i);
1509 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1512 rc = assuan_send_data(ctx, str->str, str->len);
1513 g_string_free(str, TRUE);
1515 else
1516 rc = EPWMD_EMPTY_ELEMENT;
1518 fail:
1519 if (elements) {
1520 gint total = g_slist_length(elements->list);
1521 gint i;
1523 for (i = 0; i < total; i++) {
1524 tmp = g_slist_nth_data(elements->list, i);
1525 g_free(tmp);
1528 g_slist_free(elements->list);
1530 if (elements->prefix)
1531 g_free(elements->prefix);
1533 g_free(elements);
1536 return send_error(ctx, rc);
1539 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1540 const gchar *value)
1542 xmlAttrPtr a;
1544 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1545 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1547 if (!a)
1548 return EPWMD_LIBXML_ERROR;
1550 else
1551 xmlNodeSetContent(a->children, (xmlChar *)value);
1553 return 0;
1557 * req[0] - element path
1559 static int attribute_list(assuan_context_t ctx, gchar **req)
1561 struct client_s *client = assuan_get_pointer(ctx);
1562 gchar **attrlist = NULL;
1563 gint i = 0;
1564 gchar **path = NULL;
1565 xmlAttrPtr a;
1566 xmlNodePtr n, an;
1567 gchar *line;
1568 gpg_error_t error;
1570 if (!req || !req[0])
1571 return EPWMD_COMMAND_SYNTAX;
1573 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1575 * The first argument may be only an account.
1577 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1578 return EPWMD_COMMAND_SYNTAX;
1581 n = find_account(client->doc, &path, &error, NULL, 0);
1583 if (!n) {
1584 g_strfreev(path);
1585 return error;
1588 if (path[1]) {
1589 n = find_elements(client->doc, n->children, path+1, &error,
1590 NULL, NULL, NULL, FALSE, 0, NULL);
1592 if (!n) {
1593 g_strfreev(path);
1594 return error;
1598 g_strfreev(path);
1600 for (a = n->properties; a; a = a->next) {
1601 gchar **pa;
1603 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1604 if (attrlist)
1605 g_strfreev(attrlist);
1607 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1608 return gpg_error_from_errno(ENOMEM);
1611 attrlist = pa;
1612 an = a->children;
1613 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1615 if (!attrlist[i]) {
1616 g_strfreev(attrlist);
1617 return gpg_error_from_errno(ENOMEM);
1620 attrlist[++i] = NULL;
1623 if (!attrlist)
1624 return EPWMD_EMPTY_ELEMENT;
1626 line = g_strjoinv("\n", attrlist);
1628 if (!line) {
1629 g_strfreev(attrlist);
1630 return gpg_error_from_errno(ENOMEM);
1633 error = assuan_send_data(ctx, line, strlen(line));
1634 g_free(line);
1635 g_strfreev(attrlist);
1636 return error;
1640 * req[0] - attribute
1641 * req[1] - element path
1643 static int attribute_delete(struct client_s *client, gchar **req)
1645 xmlAttrPtr a;
1646 xmlNodePtr n;
1647 gchar **path = NULL;
1648 gpg_error_t error;
1650 if (!req || !req[0] || !req[1])
1651 return EPWMD_COMMAND_SYNTAX;
1653 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1655 * The first argument may be only an account.
1657 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1658 return EPWMD_COMMAND_SYNTAX;
1662 * Don't remove the "name" attribute for the account element. To remove an
1663 * account use DELETE <account>.
1665 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1666 error = EPWMD_ATTR_SYNTAX;
1667 goto fail;
1670 n = find_account(client->doc, &path, &error, NULL, 0);
1672 if (!n)
1673 goto fail;
1675 if (path[1]) {
1676 n = find_elements(client->doc, n->children, path+1, &error,
1677 NULL, NULL, NULL, FALSE, 0, NULL);
1679 if (!n)
1680 goto fail;
1683 g_strfreev(path);
1685 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1686 return EPWMD_ATTR_NOT_FOUND;
1688 if (xmlRemoveProp(a) == -1)
1689 return EPWMD_LIBXML_ERROR;
1691 return 0;
1693 fail:
1694 g_strfreev(path);
1695 return error;
1699 * Creates a "target" attribute. When other commands encounter an element with
1700 * this attribute, the element path is modified to the target value. If the
1701 * source element path doesn't exist when using 'ATTR SET target', it is
1702 * created, but the destination element path must exist.
1704 * req[0] - source element path
1705 * req[1] - destination element path
1707 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1709 gchar **src, **dst, *line = NULL;
1710 gpg_error_t error;
1711 xmlNodePtr n;
1712 gchar **src_orig = NULL;
1714 if (!req || !req[0] || !req[1])
1715 return EPWMD_COMMAND_SYNTAX;
1717 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1719 * The first argument may be only an account.
1721 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1722 return EPWMD_COMMAND_SYNTAX;
1725 if (valid_element_path(src, FALSE) == FALSE) {
1726 g_strfreev(src);
1727 return EPWMD_INVALID_ELEMENT;
1730 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1732 * The first argument may be only an account.
1734 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1735 error = EPWMD_COMMAND_SYNTAX;
1736 goto fail;
1740 n = find_account(client->doc, &dst, &error, NULL, 0);
1743 * Make sure the destination element path exists.
1745 if (!n)
1746 goto fail;
1748 if (dst[1]) {
1749 n = find_elements(client->doc, n->children, dst+1, &error,
1750 NULL, NULL, NULL, FALSE, 0, NULL);
1752 if (!n)
1753 goto fail;
1756 again:
1757 src_orig = g_strdupv(src);
1759 if (!src_orig) {
1760 error = gpg_error_from_errno(ENOMEM);
1761 goto fail;
1764 n = find_account(client->doc, &src, &error, NULL, 0);
1766 if (!n) {
1767 if (error == EPWMD_ELEMENT_NOT_FOUND) {
1768 error = new_account(client->doc, src[0]);
1770 if (error)
1771 goto fail;
1773 goto again;
1775 else
1776 goto fail;
1779 if (src[1]) {
1780 if (!n->children)
1781 n = create_target_elements_cb(n, src+1, &error, NULL);
1782 else
1783 n = find_elements(client->doc, n->children, src+1, &error,
1784 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1786 if (!n)
1787 goto fail;
1790 * Reset the position of the element tree now that the elements
1791 * have been created.
1793 g_strfreev(src);
1794 src = src_orig;
1795 src_orig = NULL;
1796 n = find_account(client->doc, &src, &error, NULL, 0);
1798 if (!n)
1799 goto fail;
1801 n = find_elements(client->doc, n->children, src+1, &error,
1802 NULL, NULL, NULL, FALSE, 0, NULL);
1804 if (!n)
1805 goto fail;
1808 line = g_strjoinv("\t", dst);
1810 if (!line) {
1811 error = gpg_error_from_errno(ENOMEM);
1812 goto fail;
1815 error = add_attribute(n, "target", line);
1817 fail:
1818 g_free(line);
1819 g_strfreev(src);
1820 g_strfreev(dst);
1821 g_strfreev(src_orig);
1822 return error;
1826 * req[0] - account name
1827 * req[1] - new name
1829 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
1831 gpg_error_t error;
1832 gchar **tmp;
1833 xmlNodePtr n;
1835 tmp = g_strdupv(req);
1837 if (!tmp)
1838 return gpg_error_from_errno(ENOMEM);
1840 n = find_account(client->doc, &tmp, &error, NULL, 0);
1841 g_strfreev(tmp);
1843 if (!n)
1844 return error;
1846 if (g_utf8_collate(req[0], req[1]) == 0)
1847 return 0;
1850 * Will not overwrite an existing account.
1852 tmp = g_strdupv(req+1);
1854 if (!tmp)
1855 return gpg_error_from_errno(ENOMEM);
1857 n = find_account(client->doc, &tmp, &error, NULL, 0);
1858 g_strfreev(tmp);
1860 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1861 return error;
1863 if (n)
1864 return EPWMD_ACCOUNT_EXISTS;
1867 * Whitespace not allowed in account names.
1869 if (contains_whitespace(req[1]) == TRUE)
1870 return EPWMD_ATTR_SYNTAX;
1872 tmp = g_strdupv(req);
1874 if (!tmp)
1875 return gpg_error_from_errno(ENOMEM);
1877 n = find_account(client->doc, &tmp, &error, NULL, 0);
1878 g_strfreev(tmp);
1880 if (!n)
1881 return EPWMD_ELEMENT_NOT_FOUND;
1883 return add_attribute(n, "name", req[1]);
1887 * req[0] - attribute
1888 * req[1] - element path
1890 static int attribute_get(assuan_context_t ctx, gchar **req)
1892 struct client_s *client = assuan_get_pointer(ctx);
1893 xmlNodePtr n;
1894 xmlChar *a;
1895 gchar **path= NULL;
1896 gpg_error_t error;
1898 if (!req || !req[0] || !req[1])
1899 return EPWMD_COMMAND_SYNTAX;
1901 if (strchr(req[1], '\t')) {
1902 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
1903 return EPWMD_COMMAND_SYNTAX;
1905 else {
1906 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1907 return EPWMD_COMMAND_SYNTAX;
1910 n = find_account(client->doc, &path, &error, NULL, 0);
1912 if (!n)
1913 goto fail;
1915 if (path[1]) {
1916 n = find_elements(client->doc, n->children, path+1, &error,
1917 NULL, NULL, NULL, FALSE, 0, NULL);
1919 if (!n)
1920 goto fail;
1923 g_strfreev(path);
1925 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
1926 return EPWMD_ATTR_NOT_FOUND;
1928 error = assuan_send_data(ctx, a, xmlStrlen(a));
1929 xmlFree(a);
1930 return error;
1932 fail:
1933 g_strfreev(path);
1934 return error;
1938 * req[0] - attribute
1939 * req[1] - element path
1940 * req[2] - value
1942 static int attribute_set(struct client_s *client, gchar **req)
1944 gchar **path = NULL;
1945 gpg_error_t error;
1946 xmlNodePtr n;
1948 if (!req || !req[0] || !req[1] || !req[2])
1949 return EPWMD_COMMAND_SYNTAX;
1952 * Reserved attribute names.
1954 if (g_utf8_collate(req[0], "name") == 0) {
1956 * Only reserved for the account element. Not the rest of the
1957 * document.
1959 if (strchr(req[1], '\t') == NULL)
1960 return name_attribute(client, req + 1);
1962 else if (g_utf8_collate(req[0], "target") == 0)
1963 return target_attribute(client, req + 1);
1965 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1967 * The first argument may be only an account.
1969 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1970 return EPWMD_COMMAND_SYNTAX;
1973 n = find_account(client->doc, &path, &error, NULL, 0);
1975 if (!n)
1976 goto fail;
1978 if (path[1]) {
1979 n = find_elements(client->doc, n->children, path+1, &error,
1980 NULL, NULL, NULL, FALSE, 0, NULL);
1982 if (!n)
1983 goto fail;
1986 g_strfreev(path);
1987 return add_attribute(n, req[0], req[2]);
1989 fail:
1990 g_strfreev(path);
1991 return error;
1995 * req[0] - command
1996 * req[1] - attribute name or element path if command is LIST
1997 * req[2] - element path
1998 * req[2] - element path or value
2000 static int attr_command(assuan_context_t ctx, char *line)
2002 struct client_s *client = assuan_get_pointer(ctx);
2003 gchar **req = split_input_line(line, " ", 4);
2004 gpg_error_t error = 0;
2006 error = file_modified(client);
2008 if (error) {
2009 log_write("%s: %s", client->filename ? client->filename : "",
2010 pwmd_strerror(error));
2011 g_strfreev(req);
2012 return send_error(ctx, error);
2015 if (!req || !req[0] || !req[1]) {
2016 g_strfreev(req);
2017 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2020 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2021 error = attribute_set(client, req+1);
2022 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2023 error = attribute_get(ctx, req+1);
2024 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2025 error = attribute_delete(client, req+1);
2026 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2027 error = attribute_list(ctx, req+1);
2028 else
2029 error = EPWMD_COMMAND_SYNTAX;
2031 g_strfreev(req);
2032 return send_error(ctx, error);
2035 static int iscached_command(assuan_context_t ctx, char *line)
2037 gchar **req = split_input_line(line, " ", 0);
2038 guchar md5file[16];
2040 if (!req || !*req) {
2041 g_strfreev(req);
2042 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2045 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2046 g_strfreev(req);
2047 CACHE_LOCK(ctx);
2049 if (cache_iscached(md5file) == FALSE) {
2050 CACHE_UNLOCK;
2051 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2054 CACHE_UNLOCK;
2055 return send_error(ctx, 0);
2058 gpg_error_t send_cache_status(assuan_context_t ctx)
2060 gchar *tmp;
2061 struct client_s *client = assuan_get_pointer(ctx);
2062 gchar buf[ASSUAN_LINELENGTH];
2064 CACHE_LOCK(client->ctx);
2065 tmp = print_fmt(buf, sizeof(buf), "%i %i",
2066 cache_file_count(),
2067 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2068 CACHE_UNLOCK;
2070 return assuan_write_status(ctx, "CACHE", buf);
2073 static int clearcache_command(assuan_context_t ctx, char *line)
2075 struct client_s *client = assuan_get_pointer(ctx);
2076 gchar **req = split_input_line(line, " ", 0);
2077 guchar md5file[16];
2079 CACHE_LOCK(ctx);
2081 if (!req || !*req) {
2082 g_strfreev(req);
2083 cache_clear(client->md5file, 2);
2084 CACHE_UNLOCK;
2085 return send_error(ctx, 0);
2088 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2089 g_strfreev(req);
2091 if (cache_clear(md5file, 1) == FALSE) {
2092 CACHE_UNLOCK;
2093 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2096 CACHE_UNLOCK;
2097 return send_error(ctx, 0);
2100 static int cachetimeout_command(assuan_context_t ctx, char *line)
2102 guchar md5file[16];
2103 glong timeout;
2104 gchar **req = split_input_line(line, " ", 0);
2105 gchar *p;
2106 struct client_s *client = assuan_get_pointer(ctx);
2108 if (!req || !*req || !req[1]) {
2109 g_strfreev(req);
2110 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2113 errno = 0;
2114 timeout = strtol(req[0], &p, 10);
2116 if (errno != 0 || *p != 0) {
2117 g_strfreev(req);
2118 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2121 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2122 g_strfreev(req);
2123 CACHE_LOCK(client->ctx);
2125 if (cache_set_timeout(md5file, timeout) == FALSE) {
2126 CACHE_UNLOCK;
2127 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2130 CACHE_UNLOCK;
2131 return send_error(ctx, 0);
2134 static int dump_command(assuan_context_t ctx, char *line)
2136 xmlChar *xml;
2137 gssize len;
2138 struct client_s *client = assuan_get_pointer(ctx);
2139 gpg_error_t error;
2141 if (disable_list_and_dump == TRUE)
2142 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2144 error = file_modified(client);
2146 if (error) {
2147 log_write("%s: %s", client->filename ? client->filename : "",
2148 pwmd_strerror(error));
2149 return send_error(ctx, error);
2152 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2154 if (!xml)
2155 return send_syserror(ctx, ENOMEM);
2157 error = assuan_send_data(ctx, xml, len);
2158 xmlFree(xml);
2159 return send_error(ctx, error);
2162 static int getconfig_command(assuan_context_t ctx, gchar *line)
2164 struct client_s *client = assuan_get_pointer(ctx);
2165 gpg_error_t error = 0;
2166 gchar *p, *tmp;
2168 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2169 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2171 p = get_key_file_string(client->filename ? client->filename : "global", line);
2173 if (!p)
2174 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2176 tmp = expand_homedir(p);
2178 if (!tmp) {
2179 g_free(p);
2180 return send_syserror(ctx, ENOMEM);
2183 g_free(p);
2184 p = tmp;
2185 error = assuan_send_data(ctx, p, strlen(p));
2186 g_free(p);
2187 return send_error(ctx, error);
2190 void cleanup_assuan(assuan_context_t ctx)
2192 struct client_s *cl = assuan_get_pointer(ctx);
2194 if (cl)
2195 cleanup_client(cl);
2198 static void reset_notify(assuan_context_t ctx)
2200 struct client_s *cl = assuan_get_pointer(ctx);
2202 if (cl)
2203 cleanup_client(cl);
2206 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2208 gchar name[32] = {0}, value[256] = {0};
2210 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2211 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2213 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2214 pth_attr_t attr = pth_attr_of(pth_self());
2216 log_write("OPTION CLIENT %s", line);
2217 pth_attr_set(attr, PTH_ATTR_NAME, value);
2218 pth_attr_destroy(attr);
2220 else
2221 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2223 return 0;
2226 static int option_handler(assuan_context_t ctx, const gchar *name,
2227 const gchar *value)
2229 #ifdef WITH_PINENTRY
2230 struct client_s *client = assuan_get_pointer(ctx);
2231 #endif
2233 if (!value || !*value)
2234 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2236 if (g_strcasecmp(name, (gchar *)"client") == 0)
2237 return parse_client_option(ctx, value);
2239 #ifdef WITH_PINENTRY
2240 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2241 g_free(client->pinentry->ttyname);
2242 client->pinentry->ttyname = g_strdup(value);
2244 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2245 g_free(client->pinentry->ttytype);
2246 client->pinentry->ttytype = g_strdup(value);
2248 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2249 g_free(client->pinentry->display);
2250 client->pinentry->display = g_strdup(value);
2252 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2253 g_free(client->pinentry->path);
2254 client->pinentry->path = g_strdup(value);
2256 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2257 g_free(client->pinentry->title);
2258 client->pinentry->title = g_strdup(value);
2260 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2261 g_free(client->pinentry->prompt);
2262 client->pinentry->prompt = g_strdup(value);
2264 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2265 g_free(client->pinentry->desc);
2266 client->pinentry->desc = g_strdup(value);
2268 #if 0
2269 /* Need to wait for pinentry to support a --timeout option so it can
2270 * terminate itself. Cannot do it here because assuan_pipe_connect() calls
2271 * execv() which replaces the pid of the fork()ed thread from
2272 * pinentry_fork(). So pinentry will become a real process after the
2273 * thread terminates and won't be able to be kill()ed from pwmd.
2275 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2276 gchar *p = NULL;
2277 gint n = strtol(value, &p, 10);
2279 if (*p || n < 0)
2280 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2282 client->pinentry->timeout = n;
2284 #endif
2285 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2286 gchar *p = NULL;
2287 gint n = strtol(value, &p, 10);
2289 if (*p || n < 0 || n > 1)
2290 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2292 g_key_file_set_boolean(keyfileh, client->filename ? client->filename : "global",
2293 "enable_pinentry", n == 0 ? FALSE : TRUE);
2295 else
2296 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2297 #else
2298 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
2299 #endif
2301 log_write("OPTION %s=%s", name, value);
2302 return 0;
2305 gpg_error_t register_commands(assuan_context_t ctx)
2307 static struct {
2308 const gchar *name;
2309 gint (*handler)(assuan_context_t, gchar *line);
2310 } table[] = {
2311 { "OPEN", open_command },
2312 { "SAVE", save_command },
2313 { "LIST", list_command },
2314 { "REALPATH", realpath_command },
2315 { "STORE", store_command },
2316 { "DELETE", delete_command },
2317 { "GET", get_command },
2318 { "ATTR", attr_command },
2319 { "ISCACHED", iscached_command },
2320 { "CLEARCACHE", clearcache_command },
2321 { "CACHETIMEOUT", cachetimeout_command },
2322 { "GETCONFIG", getconfig_command },
2323 { "DUMP", dump_command },
2324 { "INPUT", NULL },
2325 { "OUTPUT", NULL },
2326 { NULL, NULL }
2328 gint i, rc;
2330 for (i=0; table[i].name; i++) {
2331 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2333 if (rc)
2334 return rc;
2337 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2339 if (rc)
2340 return rc;
2342 rc = assuan_register_option_handler(ctx, option_handler);
2344 if (rc)
2345 return rc;
2347 return assuan_register_reset_notify(ctx, reset_notify);
2350 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2351 guchar *key)
2353 guchar *iv;
2354 void *inbuf;
2355 gsize insize, len;
2356 guchar tkey[gcrykeysize];
2357 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2358 gcry_cipher_hd_t gh;
2359 guint iter = 0, n_iter = 0;
2360 gint iter_progress;
2361 void *outbuf = NULL;
2362 gint zerror = 0;
2363 glong outsize = 0;
2364 gpg_error_t error;
2365 file_header_t file_header;
2366 gchar str[ASSUAN_LINELENGTH];
2368 if (!ctx) {
2369 error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2371 if (error)
2372 return error;
2374 else
2375 gh = client->gh;
2377 lseek(fd, 0, SEEK_SET);
2378 insize = st.st_size - sizeof(file_header_t);
2379 iv = gcry_malloc(gcryblocksize);
2381 if (!iv) {
2382 if (!ctx)
2383 gcry_cipher_close(gh);
2385 return gpg_error_from_errno(ENOMEM);
2388 len = pth_read(fd, &file_header, sizeof(file_header_t));
2390 if (len != sizeof(file_header_t)) {
2391 len = errno;
2393 if (!ctx)
2394 gcry_cipher_close(gh);
2396 gcry_free(iv);
2397 errno = len;
2398 return gpg_error_from_errno(errno);
2401 /* No encryption iterations. This is a plain (gzipped) file. */
2402 if (file_header.iter == -1) {
2404 * cache_file_count() needs both .used == TRUE and a valid key in
2405 * order for it to count as a used cache entry. Fixes CACHE status
2406 * messages.
2408 memset(key, '!', gcrykeysize);
2409 insize = st.st_size - sizeof(file_header_t);
2412 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2413 inbuf = gcry_malloc(insize);
2415 if (!inbuf) {
2416 if (!ctx)
2417 gcry_cipher_close(gh);
2419 gcry_free(iv);
2420 return gpg_error_from_errno(ENOMEM);
2423 len = pth_read(fd, inbuf, insize);
2425 if (len != insize) {
2426 len = errno;
2428 if (!ctx)
2429 gcry_cipher_close(gh);
2431 gcry_free(iv);
2432 errno = len;
2433 return gpg_error_from_errno(errno);
2436 if (file_header.iter == -1)
2437 goto decompress;
2439 memcpy(tkey, key, sizeof(tkey));
2440 tkey[0] ^= 1;
2442 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
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);
2452 return error;
2455 if ((error = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2456 if (!ctx) {
2457 gcry_cipher_close(gh);
2458 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2460 else
2461 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2463 gcry_free(inbuf);
2464 gcry_free(iv);
2466 if (!ctx)
2467 gcry_cipher_close(gh);
2469 return error;
2472 iter_progress = get_key_file_integer("global", "iteration_progress");
2474 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2475 error = assuan_write_status(client->ctx, "DECRYPT", "0");
2477 if (error) {
2478 gcry_free(inbuf);
2479 gcry_free(iv);
2480 return error;
2484 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2486 if (error) {
2487 gcry_free(inbuf);
2488 gcry_free(iv);
2489 return error;
2492 if ((error = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2493 if (!ctx) {
2494 gcry_cipher_close(gh);
2495 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2497 else
2498 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2500 gcry_free(inbuf);
2501 gcry_free(iv);
2502 return error;
2505 while (iter < file_header.iter) {
2506 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2507 if (!(iter % iter_progress)) {
2508 error = assuan_write_status(ctx, "DECRYPT",
2509 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
2511 if (error) {
2512 gcry_free(inbuf);
2513 gcry_free(iv);
2514 return error;
2519 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2520 if (!ctx) {
2521 gcry_cipher_close(gh);
2522 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2524 else
2525 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2527 gcry_free(inbuf);
2528 gcry_free(iv);
2529 return error;
2532 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2534 if (error) {
2535 if (!ctx) {
2536 gcry_cipher_close(gh);
2537 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2539 else
2540 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2542 gcry_free(inbuf);
2543 gcry_free(iv);
2544 return error;
2547 iter++;
2548 pth_yield(NULL);
2551 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2552 error = assuan_write_status(ctx, "DECRYPT",
2553 print_fmt(str, sizeof(str), "%i", file_header.iter));
2555 if (error) {
2556 gcry_free(inbuf);
2557 gcry_free(iv);
2558 return error;
2562 gcry_free(iv);
2564 decompress:
2565 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zerror) == FALSE) {
2567 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2569 if (zerror == Z_MEM_ERROR) {
2570 gcry_free(inbuf);
2571 return gpg_error_from_errno(ENOMEM);
2573 else if (zerror != Z_DATA_ERROR) {
2574 gcry_free(inbuf);
2576 if (!ctx)
2577 gcry_cipher_close(gh);
2579 return EPWMD_BADKEY;
2582 else {
2583 gcry_free(inbuf);
2584 inbuf = outbuf;
2585 insize = outsize;
2588 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2589 gcry_free(inbuf);
2591 if (!ctx)
2592 gcry_cipher_close(gh);
2594 return EPWMD_BADKEY;
2597 if (ctx) {
2598 client->xml = inbuf;
2599 client->len = insize;
2601 else {
2602 gcry_cipher_close(gh);
2603 gcry_free(inbuf);
2606 return 0;
2610 * This is called after every Assuan command.
2612 void command_finalize(assuan_context_t ctx, gint error)
2614 struct client_s *client = assuan_get_pointer(ctx);
2616 unlock_file_mutex(client);