Some --disable-pinentry compile time fixes.
[pwmd.git] / src / commands.c
blobe0002e87171bd34facf47fe006461f01d93b6180
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2007 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 <glib/gprintf.h>
30 #include <gcrypt.h>
31 #include <zlib.h>
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
37 #ifndef MEM_DEBUG
38 #include "mem.h"
39 #endif
41 #include "xml.h"
42 #include "common.h"
44 #ifdef WITH_PINENTRY
45 #include "pinentry.h"
46 #endif
48 #include "pwmd_error.h"
49 #include "cache.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 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 gboolean valid_filename(const gchar *filename)
123 const gchar *p;
125 if (!filename || !*filename)
126 return FALSE;
128 for (p = filename; *p; p++) {
129 if (g_ascii_isalnum(*p) == FALSE && *p != '-' && *p != '_' && *p != '.')
130 return FALSE;
133 return TRUE;
136 gint open_file(const gchar *filename, struct stat *st)
138 gint fd;
140 if ((fd = open(filename, O_RDONLY)) == -1)
141 return -1;
143 if (stat(filename, st) == -1) {
144 close(fd);
145 return -1;
148 return fd;
151 void unlock_file_mutex(struct client_s *client)
153 pth_mutex_t *m;
155 #ifdef WITH_PINENTRY
156 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
157 #else
158 if (client->has_lock == FALSE)
159 #endif
160 return;
162 CACHE_LOCK(client->ctx);
164 if (cache_get_mutex(client->md5file, &m) == FALSE) {
165 CACHE_UNLOCK;
166 return;
169 CACHE_UNLOCK;
170 pth_mutex_release(m);
171 client->has_lock = FALSE;
174 gpg_error_t lock_file_mutex(struct client_s *client)
176 pth_mutex_t *m;
178 if (client->has_lock == TRUE)
179 return 0;
181 CACHE_LOCK(client->ctx);
183 if (cache_get_mutex(client->md5file, &m) == FALSE) {
184 CACHE_UNLOCK;
185 return 0;
188 CACHE_UNLOCK;
190 if (pth_mutex_acquire(m, TRUE, NULL) == FALSE) {
191 if (errno == EBUSY) {
192 if (client->ctx)
193 assuan_write_status(client->ctx, "LOCKED", N_("Waiting for lock"));
195 pth_mutex_acquire(m, FALSE, NULL);
197 else {
198 gint e = errno;
199 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(errno));
200 return gpg_error_from_errno(e);
204 client->has_lock = TRUE;
205 return 0;
208 void free_client(struct client_s *client)
210 if (client->doc)
211 xmlFreeDoc(client->doc);
213 if (client->xml)
214 gcry_free(client->xml);
216 if (client->filename)
217 g_free(client->filename);
219 if (client->gh)
220 gcry_cipher_close(client->gh);
223 static void cleanup_client(struct client_s *client)
225 assuan_context_t ctx = client->ctx;
226 #ifdef WITH_PINENTRY
227 struct pinentry_s *pin = client->pinentry;
228 #endif
230 unlock_file_mutex(client);
231 CACHE_LOCK(client->ctx);
232 cache_decr_refcount(client->md5file);
235 * This may be a new file so don't use a cache slot. save_command() will
236 * set this to FALSE on success.
238 if (client->new == TRUE)
239 cache_clear(client->md5file, 1);
241 free_client(client);
242 memset(client, 0, sizeof(struct client_s));
243 client->state = STATE_CONNECTED;
244 client->ctx = ctx;
245 client->freed = TRUE;
246 #ifdef WITH_PINENTRY
247 client->pinentry = pin;
248 #endif
249 CACHE_UNLOCK;
252 static gchar *print_fmt(const char *fmt, ...)
254 va_list ap;
255 static gchar buf[ASSUAN_LINELENGTH] = {0};
257 va_start(ap, fmt);
258 vsnprintf(buf, sizeof(buf), fmt, ap);
259 va_end(ap);
260 return buf;
263 gboolean do_decompress(assuan_context_t ctx, gpointer in, gint insize,
264 gpointer *out, glong *outsize, gint *error)
266 z_stream z;
267 gint ret;
268 gpointer pout;
269 gz_header h;
270 gchar buf[17];
271 gpg_error_t rc;
273 z.zalloc = z_alloc;
274 z.zfree = z_free;
275 z.next_in = in;
276 z.avail_in = insize;
277 z.avail_out = zlib_bufsize;
278 z.next_out = pout = g_malloc(zlib_bufsize);
280 if (!pout) {
281 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
282 *error = Z_MEM_ERROR;
283 return FALSE;
286 ret = inflateInit2(&z, 47);
288 if (ret != Z_OK) {
289 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
290 g_free(pout);
291 return FALSE;
294 memset(&h, 0, sizeof(gz_header));
295 h.comment = (guchar *)buf;
296 h.comm_max = sizeof(buf);
297 ret = inflateGetHeader(&z, &h);
299 if (ret != Z_OK) {
300 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
301 g_free(pout);
302 inflateEnd(&z);
303 return FALSE;
306 ret = inflate(&z, Z_BLOCK);
308 if (ret != Z_OK) {
309 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
310 g_free(pout);
311 inflateEnd(&z);
312 return FALSE;
315 if (h.comment)
316 insize = atoi((gchar *)h.comment);
318 do {
319 gpointer p;
321 ret = inflate(&z, Z_FINISH);
323 switch (ret) {
324 case Z_OK:
325 break;
326 case Z_BUF_ERROR:
327 if (!z.avail_out) {
328 p = g_realloc(pout, z.total_out + zlib_bufsize);
330 if (!p) {
331 ret = Z_MEM_ERROR;
332 goto fail;
335 pout = p;
336 z.next_out = pout + z.total_out;
337 z.avail_out = zlib_bufsize;
339 if (ctx) {
340 rc = assuan_write_status(ctx, "DECOMPRESS",
341 print_fmt("%i %i", z.total_out, insize));
343 if (rc) {
344 ret = rc;
345 goto fail;
349 break;
350 case Z_STREAM_END:
351 break;
352 default:
353 goto fail;
354 break;
357 pth_yield(NULL);
358 } while (ret != Z_STREAM_END);
360 if (ctx) {
361 rc = assuan_write_status(ctx, "DECOMPRESS",
362 print_fmt("%i %i", z.total_out, insize));
364 if (rc) {
365 ret = rc;
366 goto fail;
370 *out = pout;
371 *outsize = z.total_out;
372 inflateEnd(&z);
373 return TRUE;
375 fail:
376 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
377 *error = ret;
378 g_free(pout);
379 inflateEnd(&z);
380 return FALSE;
383 gpg_error_t read_file_header(const gchar *filename, file_header_t *fh)
385 gint fd;
386 gsize len;
388 fd = open(filename, O_RDONLY);
390 if (fd == -1)
391 return gpg_error_from_errno(errno);
393 len = pth_read(fd, fh, sizeof(file_header_t));
394 close(fd);
396 if (len != sizeof(file_header_t))
397 return gpg_error_from_errno(errno);
399 return 0;
402 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar shakey[],
403 gboolean cached)
405 struct client_s *client = assuan_get_pointer(ctx);
406 gpg_error_t error;
407 struct stat st;
408 gint fd;
409 gint timeout;
411 if ((fd = open_file(client->filename, &st)) == -1) {
412 /* New file. */
413 if (errno == ENOENT) {
414 if (shakey[0])
415 goto update_cache;
417 goto done;
420 error = errno;
421 log_write("%s: %s", client->filename, strerror(errno));
422 cleanup_client(client);
423 memset(shakey, 0, sizeof(shakey));
424 return send_syserror(ctx, error);
427 error = try_xml_decrypt(ctx, fd, st, shakey);
428 close(fd);
430 if (error) {
431 memset(shakey, 0, sizeof(shakey));
432 cleanup_client(client);
433 return send_error(ctx, error);
436 update_cache:
437 CACHE_LOCK(client->ctx);
439 if (cached == FALSE) {
440 if (cache_update_key(client->md5file, shakey) == FALSE) {
441 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
442 cleanup_client(client);
443 CACHE_UNLOCK;
444 return send_error(ctx, EPWMD_MAX_SLOTS);
447 timeout = get_key_file_integer(client->filename, "cache_timeout");
448 cache_reset_timeout(client->md5file, timeout);
450 else
451 cache_set_timeout(client->md5file, -2);
453 CACHE_UNLOCK;
455 done:
456 memset(shakey, 0, sizeof(shakey));
457 error = parse_xml(ctx);
459 if (client->xml) {
460 gcry_free(client->xml);
461 client->xml = NULL;
464 if (!error) {
465 if (client->new == FALSE)
466 send_cache_status_all();
468 client->state = STATE_OPEN;
471 return send_error(ctx, error);
474 static int open_command(assuan_context_t ctx, char *line)
476 struct stat st;
477 guchar shakey[gcrykeysize];
478 gboolean cached = FALSE;
479 gpg_error_t error;
480 struct client_s *client = assuan_get_pointer(ctx);
481 gchar **req;
482 gchar *filename = NULL;
483 file_header_t file_header;
485 memset(shakey, 0, sizeof(shakey));
487 if ((req = split_input_line(line, " ", 2)) != NULL)
488 filename = req[0];
490 if (!filename || !*filename) {
491 g_strfreev(req);
492 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
495 if (valid_filename(filename) == FALSE) {
496 g_strfreev(req);
497 return send_error(ctx, EPWMD_INVALID_FILENAME);
500 if (client->state == STATE_OPEN)
501 cleanup_client(client);
503 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
504 CACHE_LOCK(client->ctx);
506 if (cache_has_file(client->md5file) == FALSE) {
507 if (cache_add_file(client->md5file, NULL) == FALSE) {
508 g_strfreev(req);
509 CACHE_UNLOCK;
510 return send_error(ctx, EPWMD_MAX_SLOTS);
514 cache_incr_refcount(client->md5file);
515 CACHE_UNLOCK;
516 error = lock_file_mutex(client);
518 if (error) {
519 g_strfreev(req);
520 return send_error(ctx, error);
523 client->freed = FALSE;
525 if ((error = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
526 g_strfreev(req);
527 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
528 cleanup_client(client);
529 return send_error(ctx, error);
532 if (stat(filename, &st) == 0) {
533 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
534 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
535 g_strfreev(req);
536 cleanup_client(client);
537 return send_error(ctx, EPWMD_INVALID_FILENAME);
540 client->mtime = st.st_mtime;
543 client->filename = g_strdup(filename);
544 #ifdef WITH_PINENTRY
545 client->pinentry->filename = client->filename;
546 #endif
548 if (!client->filename) {
549 memset(shakey, 0, sizeof(shakey));
550 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
551 cleanup_client(client);
552 g_strfreev(req);
553 return send_syserror(ctx, ENOMEM);
557 * New files don't need a key.
559 if (access(filename, R_OK|W_OK) != 0) {
560 if (errno != ENOENT) {
561 error = errno;
562 log_write("%s: %s", filename, strerror(errno));
563 g_strfreev(req);
564 cleanup_client(client);
565 return send_syserror(ctx, error);
568 if ((client->xml = new_document()) == NULL) {
569 log_write("%s", strerror(ENOMEM));
570 g_strfreev(req);
571 cleanup_client(client);
572 return send_syserror(ctx, ENOMEM);
575 client->len = xmlStrlen(client->xml);
576 client->new = TRUE;
577 client->filename = g_strdup(filename);
579 if (!client->filename) {
580 g_strfreev(req);
581 cleanup_client(client);
582 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
583 return send_syserror(ctx, ENOMEM);
586 memset(shakey, 0, sizeof(shakey));
588 if (req[1] && *req[1])
589 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
591 g_strfreev(req);
592 return open_command_finalize(ctx, shakey, cached);
595 error = read_file_header(filename, &file_header);
597 if (error) {
598 g_strfreev(req);
599 cleanup_client(client);
600 return send_error(ctx, error);
603 if (file_header.iter == -1)
604 goto done;
606 CACHE_LOCK(client->ctx);
607 cached = cache_get_key(client->md5file, shakey);
608 CACHE_UNLOCK;
610 if (cached == FALSE) {
612 * No key specified and no matching filename found in the cache. Use
613 * pinentry to retrieve the key. Cannot return assuan_process_done()
614 * here otherwise the command will be interrupted. The event loop in
615 * client_thread() will poll the file descriptor waiting for it to
616 * become ready to read a pinentry_key_s which will contain the
617 * entered key or error. It will then call open_command_finalize() to
618 * to finish the command.
620 if (!req[1] || !*req[1]) {
621 #ifdef WITH_PINENTRY
622 if (client->pinentry->use == FALSE) {
623 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
624 goto done;
627 g_strfreev(req);
628 client->pinentry->which = PINENTRY_OPEN;
629 error = pinentry_fork(ctx);
631 if (error) {
632 cleanup_client(client);
633 return send_error(ctx, error);
636 client->pinentry->cb = open_command_finalize;
637 client->pinentry->status = PINENTRY_INIT;
638 return 0;
639 #else
640 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
641 goto done;
642 #endif
645 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
648 done:
649 g_strfreev(req);
650 return open_command_finalize(ctx, shakey, cached);
653 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
654 gint size, gpointer *out, glong *outsize, gint *error)
656 z_stream z;
657 gpointer pout, pin;
658 gint ret;
659 gz_header h;
660 gchar buf[17];
661 gint cmd = Z_NO_FLUSH;
662 gpg_error_t rc;
664 z.zalloc = z_alloc;
665 z.zfree = z_free;
666 z.next_in = pin = data;
667 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
668 z.avail_out = zlib_bufsize;
669 z.next_out = pout = g_malloc(zlib_bufsize);
671 if (!pout) {
672 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
673 *error = Z_MEM_ERROR;
674 return FALSE;
677 ret = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
679 if (ret != Z_OK) {
680 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
681 *error = ret;
682 g_free(pout);
683 return FALSE;
686 memset(&h, 0, sizeof(gz_header));
687 snprintf(buf, sizeof(buf), "%i", size);
688 h.comment = (guchar *)buf;
689 ret = deflateSetHeader(&z, &h);
691 if (ret != Z_OK) {
692 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
693 *error = ret;
694 g_free(pout);
695 deflateEnd(&z);
696 return FALSE;
699 do {
700 gpointer p;
702 ret = deflate(&z, cmd);
704 switch (ret) {
705 case Z_OK:
706 break;
707 case Z_BUF_ERROR:
708 if (!z.avail_out) {
709 p = g_realloc(pout, z.total_out + zlib_bufsize);
711 if (!p) {
712 ret = Z_MEM_ERROR;
713 goto fail;
716 pout = p;
717 z.next_out = pout + z.total_out;
718 z.avail_out = zlib_bufsize;
721 if (!z.avail_in && z.total_in < size) {
722 if (z.total_in + zlib_bufsize > size)
723 z.avail_in = size - z.total_in;
724 else
725 z.avail_in = zlib_bufsize;
727 if (ctx) {
728 rc = assuan_write_status(ctx, "COMPRESS",
729 print_fmt("%i %i", z.total_in, size));
731 if (rc) {
732 ret = rc;
733 goto fail;
738 if (z.total_in >= size)
739 cmd = Z_FINISH;
741 break;
742 case Z_STREAM_END:
743 break;
744 default:
745 goto fail;
748 pth_yield(NULL);
749 } while (ret != Z_STREAM_END);
751 if (ctx) {
752 rc = assuan_write_status(ctx, "COMPRESS",
753 print_fmt("%i %i", z.total_in, size));
755 if (rc) {
756 ret = rc;
757 goto fail;
761 *out = pout;
762 *outsize = z.total_out;
763 deflateEnd(&z);
764 return TRUE;
766 fail:
767 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
768 *error = ret;
769 g_free(pout);
770 deflateEnd(&z);
771 return FALSE;
774 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
775 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
776 gint iter)
778 gsize len = insize;
779 gint fd;
780 gpointer inbuf;
781 guchar tkey[gcrykeysize];
782 gchar *p;
783 gint error;
784 gpg_error_t rc;
785 guint iter_progress = 0, n_iter = 0, xiter = 0;
786 gchar tmp[FILENAME_MAX];
787 file_header_t file_header;
789 if (iter == -1) {
791 * cache_file_count() needs both .used == TRUE and a valid key in
792 * order for it to count as a used cache entry. Fixes CACHE status
793 * messages.
795 memset(shakey, '!', gcrykeysize);
796 inbuf = data;
797 file_header.iter = iter;
798 goto write_file;
801 if (insize / gcryblocksize) {
802 len = (insize / gcryblocksize) * gcryblocksize;
804 if (insize % gcryblocksize)
805 len += gcryblocksize;
809 * Resize the existing xml buffer to the block size required by gcrypt
810 * rather than duplicating it and wasting memory.
812 inbuf = gcry_realloc(data, len);
814 if (!inbuf)
815 return gpg_error_from_errno(ENOMEM);
817 insize = len;
818 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
819 memcpy(tkey, shakey, sizeof(tkey));
820 tkey[0] ^= 1;
822 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
823 gcry_free(inbuf);
824 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
825 return rc;
828 file_header.iter = iter;
830 if (client)
831 iter_progress = get_key_file_integer("default", "iteration_progress");
833 if (client && iter_progress && file_header.iter >= iter_progress) {
834 error = assuan_write_status(client->ctx, "ENCRYPT", "0");
836 if (error) {
837 gcry_free(inbuf);
838 return error;
842 while (xiter < file_header.iter) {
843 if (client && iter_progress > 0 && xiter >= iter_progress) {
844 if (!(xiter % iter_progress)) {
845 error = assuan_write_status(client->ctx, "ENCRYPT", print_fmt("%i",
846 ++n_iter * iter_progress));
848 if (error) {
849 gcry_free(inbuf);
850 return error;
855 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
856 sizeof(file_header.iv)))) {
857 gcry_free(inbuf);
858 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
859 return rc;
862 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
863 == FALSE) {
864 gcry_free(inbuf);
865 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
866 return rc;
869 xiter++;
870 pth_yield(NULL);
873 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
874 sizeof(file_header.iv)))) {
875 gcry_free(inbuf);
876 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
877 return rc;
880 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
881 gcry_free(inbuf);
882 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
883 return rc;
886 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
887 gcry_free(inbuf);
888 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
889 return rc;
892 if (client && iter_progress && file_header.iter >= iter_progress) {
893 error = assuan_write_status(client->ctx, "ENCRYPT",
894 print_fmt("%i", file_header.iter));
896 if (error) {
897 gcry_free(inbuf);
898 return error;
902 write_file:
903 if (filename) {
904 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
906 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
907 error = errno;
908 gcry_free(inbuf);
909 p = strrchr(tmp, '/');
910 p++;
911 log_write("%s: %s", p, strerror(errno));
912 return gpg_error_from_errno(error);
915 else
917 * xml_import() from command line.
919 fd = STDOUT_FILENO;
921 len = pth_write(fd, &file_header, sizeof(file_header_t));
923 if (len != sizeof(file_header)) {
924 len = errno;
926 if (filename)
927 close(fd);
929 gcry_free(inbuf);
930 return gpg_error_from_errno(len);
933 len = pth_write(fd, inbuf, insize);
935 if (len != insize) {
936 len = errno;
938 if (filename)
939 close(fd);
941 gcry_free(inbuf);
942 return gpg_error_from_errno(len);
945 if (fsync(fd) == -1) {
946 len = errno;
947 close(fd);
948 gcry_free(inbuf);
949 return gpg_error_from_errno(len);
952 if (filename) {
953 struct stat st;
954 mode_t mode = 0;
956 close(fd);
958 if (stat(filename, &st) == 0)
959 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
961 if (rename(tmp, filename) == -1) {
962 len = errno;
963 gcry_free(inbuf);
964 return gpg_error_from_errno(len);
967 if (mode)
968 chmod(filename, mode);
971 gcry_free(inbuf);
972 return 0;
975 static gpg_error_t save_command_finalize(assuan_context_t ctx,
976 guchar shakey[], gboolean cached)
978 struct client_s *client = assuan_get_pointer(ctx);
979 gpointer xmlbuf;
980 xmlChar *p;
981 gint len;
982 gint iter;
983 gint timeout;
984 gpointer outbuf;
985 glong outsize = 0;
986 gint zerror;
987 gpg_error_t error;
988 struct stat st;
990 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
991 xmlbuf = p;
993 iter = get_key_file_integer(client->filename, "compression_level");
995 if (iter < 0)
996 iter = 0;
998 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zerror) == FALSE) {
999 memset(shakey, 0, sizeof(shakey));
1000 xmlFree(xmlbuf);
1002 if (zerror == Z_MEM_ERROR) {
1003 return send_syserror(ctx, ENOMEM);
1005 else
1006 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1008 else {
1009 gcry_free(xmlbuf);
1010 xmlbuf = outbuf;
1011 len = outsize;
1014 iter = get_key_file_integer(client->filename, "iterations");
1015 error = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1017 if (error) {
1018 memset(shakey, 0, sizeof(shakey));
1019 return send_error(ctx, error);
1022 stat(client->filename, &st);
1023 client->mtime = st.st_mtime;
1024 timeout = get_key_file_integer(client->filename, "cache_timeout");
1025 CACHE_LOCK(client->ctx);
1027 if (cached) {
1028 memset(shakey, 0, sizeof(shakey));
1029 cache_reset_timeout(client->md5file, timeout);
1030 CACHE_UNLOCK;
1032 if (client->new == TRUE)
1033 send_cache_status_all();
1035 client->new = FALSE;
1036 return send_error(ctx, 0);
1039 if (cache_update_key(client->md5file, shakey) == FALSE) {
1040 memset(shakey, 0, sizeof(shakey));
1041 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1042 CACHE_UNLOCK;
1043 return send_error(ctx, EPWMD_MAX_SLOTS);
1046 client->new = FALSE;
1047 memset(shakey, 0, sizeof(shakey));
1048 cache_reset_timeout(client->md5file, timeout);
1049 CACHE_UNLOCK;
1050 send_cache_status_all();
1051 return send_error(ctx, 0);
1054 static int save_command(assuan_context_t ctx, char *line)
1056 gboolean cached = FALSE;
1057 guchar shakey[gcrykeysize];
1058 struct stat st;
1059 struct client_s *client = assuan_get_pointer(ctx);
1060 gpg_error_t error;
1062 memset(shakey, 0, sizeof(shakey));
1063 error = file_modified(client);
1065 if (error) {
1066 log_write("%s: %s", client->filename ? client->filename : "",
1067 pwmd_strerror(error));
1068 return send_error(ctx, error);
1071 error = lock_file_mutex(client);
1073 if (error)
1074 return send_error(ctx, error);
1076 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1077 return send_syserror(ctx, errno);
1079 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1080 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1081 return send_error(ctx, EPWMD_INVALID_FILENAME);
1084 if (get_key_file_integer(client->filename, "iterations") == -1)
1085 goto done;
1087 if (!line || !*line) {
1088 guchar tmp[sizeof(shakey)];
1089 CACHE_LOCK(ctx);
1091 memset(tmp, '!', sizeof(tmp));
1093 if (cache_get_key(client->md5file, shakey) == FALSE ||
1094 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1095 CACHE_UNLOCK;
1096 #ifdef WITH_PINENTRY
1097 if (client->pinentry->use == FALSE) {
1098 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1099 goto done;
1102 client->pinentry->which = PINENTRY_SAVE;
1103 error = pinentry_fork(ctx);
1105 if (error)
1106 return send_error(ctx, error);
1108 client->pinentry->cb = save_command_finalize;
1109 client->pinentry->status = PINENTRY_INIT;
1110 return 0;
1111 #else
1112 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1113 goto done;
1114 #endif
1116 else {
1117 CACHE_UNLOCK;
1118 cached = TRUE;
1121 else {
1122 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1123 memset(line, 0, strlen(line));
1126 done:
1127 return save_command_finalize(ctx, shakey, cached);
1130 static gboolean contains_whitespace(const gchar *str)
1132 const gchar *p = str;
1133 gunichar c;
1134 glong len;
1136 len = g_utf8_strlen(p++, -1) -1;
1138 while (len--) {
1139 c = g_utf8_get_char(p++);
1141 if (g_unichar_isspace(c))
1142 return TRUE;
1145 return FALSE;
1148 static int delete_command(assuan_context_t ctx, char *line)
1150 struct client_s *client = assuan_get_pointer(ctx);
1151 gchar **req;
1152 gpg_error_t error;
1153 xmlNodePtr n;
1155 error = file_modified(client);
1157 if (error) {
1158 log_write("%s: %s", client->filename ? client->filename : "",
1159 pwmd_strerror(error));
1160 return send_error(ctx, error);
1163 if (strchr(line, '\t'))
1164 req = split_input_line(line, "\t", -1);
1165 else
1166 req = split_input_line(line, " ", -1);
1168 if (!req || !*req)
1169 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1171 n = find_account(client->doc, &req, &error, NULL, 0);
1173 if (!n) {
1174 g_strfreev(req);
1175 return send_error(ctx, error);
1179 * No sub-node defined. Remove the entire node (account).
1181 if (!req[1]) {
1182 if (n) {
1183 xmlUnlinkNode(n);
1184 xmlFreeNode(n);
1187 g_strfreev(req);
1188 return send_error(ctx, 0);
1191 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1192 g_strfreev(req);
1194 if (!n)
1195 return send_error(ctx, error);
1197 if (n) {
1198 xmlUnlinkNode(n);
1199 xmlFreeNode(n);
1202 return send_error(ctx, 0);
1206 * Don't return with assuan_process_done() here. This has been called from
1207 * assuan_process_next() and the command should be finished in
1208 * client_thread().
1210 static int store_command_finalize(gpointer data, gint rc, guchar *line,
1211 gsize len)
1213 assuan_context_t ctx = data;
1214 struct client_s *client = assuan_get_pointer(ctx);
1215 gchar **req;
1216 guchar *result = line;
1217 xmlNodePtr n;
1218 gpg_error_t error = file_modified(client);
1220 if (rc) {
1221 if (line)
1222 #ifndef MEM_DEBUG
1223 xfree(line);
1224 #else
1225 free(line);
1226 #endif
1227 return rc;
1230 req = split_input_line((gchar *)result, "\t", 0);
1231 #ifndef MEM_DEBUG
1232 xfree(line);
1233 #else
1234 free(line);
1235 #endif
1237 if (rc) {
1238 if (req)
1239 g_strfreev(req);
1241 return rc;
1244 if (!req || !*req)
1245 return EPWMD_COMMAND_SYNTAX;
1247 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1248 g_strfreev(req);
1249 return EPWMD_INVALID_ELEMENT;
1252 if (valid_element_path(req+1, TRUE) == FALSE) {
1253 g_strfreev(req);
1254 return EPWMD_INVALID_ELEMENT;
1257 again:
1258 n = find_account(client->doc, &req, &error, NULL, 0);
1260 if (error && error == EPWMD_ELEMENT_NOT_FOUND) {
1261 error = new_account(client->doc, *req);
1263 if (error) {
1264 g_strfreev(req);
1265 return error;
1268 goto again;
1271 if (!n) {
1272 g_strfreev(req);
1273 return error;
1276 if (req[1]) {
1277 if (!n->children)
1278 create_elements_cb(n, req+1, &error, NULL);
1279 else
1280 find_elements(client->doc, n->children, req+1, &error,
1281 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1284 g_strfreev(req);
1285 client->inquire_status = INQUIRE_DONE;
1286 return error;
1289 static int store_command(assuan_context_t ctx, char *line)
1291 struct client_s *client = assuan_get_pointer(ctx);
1292 gpg_error_t error = file_modified(client);
1294 if (error) {
1295 log_write("%s: %s", client->filename ? client->filename : "",
1296 pwmd_strerror(error));
1297 return send_error(ctx, error);
1300 error = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1302 if (error)
1303 return send_error(ctx, error);
1305 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1306 client->inquire_status = INQUIRE_BUSY;
1307 return 0;
1310 static int get_command(assuan_context_t ctx, char *line)
1312 struct client_s *client = assuan_get_pointer(ctx);
1313 gchar **req;
1314 gpg_error_t error;
1315 xmlNodePtr n;
1317 error = file_modified(client);
1319 if (error) {
1320 log_write("%s: %s", client->filename ? client->filename : "",
1321 pwmd_strerror(error));
1322 return send_error(ctx, error);
1325 req = split_input_line(line, "\t", -1);
1327 if (!req || !*req) {
1328 g_strfreev(req);
1329 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1332 n = find_account(client->doc, &req, &error, NULL, 0);
1334 if (!n) {
1335 g_strfreev(req);
1336 return send_error(ctx, error);
1339 if (req[1])
1340 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1342 g_strfreev(req);
1344 if (error)
1345 return send_error(ctx, error);
1347 if (!n || !n->children)
1348 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1350 n = n->children;
1352 if (!n || !n->content || !*n->content)
1353 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1355 error = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1356 return send_error(ctx, error);
1359 static gchar *element_path_to_req(const gchar *account, xmlChar *path)
1361 xmlChar *p = path;
1362 gint n;
1363 gchar *buf;
1365 if (!p)
1366 return NULL;
1368 for (n = 0; *p && n < 3; p++) {
1369 if (*p == '/')
1370 n++;
1373 if (strstr((gchar *)p, "text()") != NULL)
1374 p[xmlStrlen(p) - 7] = 0;
1376 for (n = 0; p[n]; n++) {
1377 if (p[n] == '/')
1378 p[n] = '\t';
1381 buf = g_strdup_printf("%s\t%s", account, p);
1382 p = (xmlChar *)buf + strlen(buf) - 1;
1384 while (isspace(*p))
1385 *p-- = 0;
1387 return buf;
1390 gboolean strv_printf(gchar ***array, const gchar *fmt, ...)
1392 gchar **a;
1393 va_list ap;
1394 gchar *buf;
1395 gint len = *array ? g_strv_length(*array) : 0;
1396 gint ret;
1398 if (!fmt)
1399 return FALSE;
1401 if ((a = g_realloc(*array, (len + 2) * sizeof(gchar *))) == NULL)
1402 return FALSE;
1404 va_start(ap, fmt);
1405 ret = g_vasprintf(&buf, fmt, ap);
1406 va_end(ap);
1408 if (ret == -1)
1409 return FALSE;
1411 a[len++] = buf;
1412 a[len] = NULL;
1413 *array = a;
1414 return TRUE;
1417 struct realpath_s {
1418 gchar *account;
1421 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **req,
1422 gpg_error_t *error, void *data)
1424 struct realpath_s *rp = data;
1426 if (rp->account)
1427 g_free(rp->account);
1429 rp->account = g_strdup(req[0]);
1431 if (!rp->account) {
1432 *error = gpg_error_from_errno(ENOMEM);
1433 return NULL;
1436 return node;
1439 static int realpath_command(assuan_context_t ctx, char *line)
1441 gpg_error_t error;
1442 struct client_s *client = assuan_get_pointer(ctx);
1443 xmlChar *p;
1444 gchar **req;
1445 gchar *result, *t;
1446 gint i;
1447 xmlNodePtr n;
1448 struct realpath_s *rp;
1449 GString *string;
1451 error = file_modified(client);
1453 if (error) {
1454 log_write("%s: %s", client->filename ? client->filename : "",
1455 pwmd_strerror(error));
1456 return send_error(ctx, error);
1459 if (strchr(line, '\t') != NULL) {
1460 if ((req = split_input_line(line, "\t", 0)) == NULL)
1461 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1463 else {
1464 if ((req = split_input_line(line, " ", 0)) == NULL)
1465 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1468 n = find_account(client->doc, &req, &error, NULL, 0);
1470 if (!n) {
1471 g_strfreev(req);
1472 return send_error(ctx, error);
1475 rp = g_malloc(sizeof(struct realpath_s));
1477 if (!rp) {
1478 g_strfreev(req);
1479 return send_syserror(ctx, ENOMEM);
1482 rp->account = g_strdup(req[0]);
1484 if (!rp->account) {
1485 g_strfreev(req);
1486 return send_syserror(ctx, ENOMEM);
1489 if (req[1]) {
1490 n = find_elements(client->doc, n->children, req+1, &error,
1491 NULL, realpath_elements_cb, NULL, FALSE, 0, rp);
1493 if (!n) {
1494 g_free(rp->account);
1495 g_free(rp);
1496 g_strfreev(req);
1497 return send_error(ctx, error);
1501 p = xmlGetNodePath(n);
1502 result = element_path_to_req(rp->account, p);
1504 if (!result) {
1505 g_free(result);
1506 g_free(rp->account);
1507 g_free(rp);
1508 g_strfreev(req);
1509 xmlFree(p);
1510 return send_syserror(ctx, ENOMEM);
1513 string = g_string_new(result);
1514 g_free(result);
1515 g_free(rp->account);
1516 g_free(rp);
1517 g_strfreev(req);
1518 xmlFree(p);
1519 i = 0;
1521 again:
1522 for (t = string->str + i; *t; t++, i++) {
1523 if ((!i && *t != '!') || *t == '\t') {
1524 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1525 goto again;
1529 error = assuan_send_data(ctx, string->str, string->len);
1530 g_string_free(string, TRUE);
1531 return send_error(ctx, error);
1534 struct list_element_s {
1535 GSList *list;
1536 gchar **elements;
1539 static gboolean append_to_element_list(struct list_element_s *elements)
1541 gchar *tmp;
1542 gint i, total;
1543 gchar *a;
1544 GSList *list;
1546 if (!elements || !elements->elements)
1547 return TRUE;
1549 tmp = g_strjoinv("\t", elements->elements);
1551 if (!tmp)
1552 return FALSE;
1554 g_strfreev(elements->elements);
1555 elements->elements = NULL;
1556 total = g_slist_length(elements->list);
1557 a = g_utf8_collate_key(tmp, -1);
1559 if (!a) {
1560 g_free(tmp);
1561 return FALSE;
1565 * Removes duplicate element paths from the list. This is needed when
1566 * appending an element tree from list_command(). The glib docs recommend
1567 * using g_utf8_collate_key() for a large number of strings.
1569 for (i = 0; i < total; i++) {
1570 gchar *p = g_slist_nth_data(elements->list, i);
1571 gchar *b = g_utf8_collate_key(p, -1);
1573 if (!b) {
1574 g_free(a);
1575 g_free(tmp);
1576 return FALSE;
1579 if (strcmp(a, b) == 0) {
1580 g_free(a);
1581 g_free(b);
1582 g_free(tmp);
1583 return TRUE;
1586 g_free(b);
1589 g_free(a);
1590 list = g_slist_append(elements->list, tmp);
1592 if (!list)
1593 return FALSE;
1595 elements->list = list;
1596 return TRUE;
1599 static gpg_error_t do_list_recurse(xmlDocPtr doc, xmlNodePtr node,
1600 struct list_element_s *elements, gchar *prefix)
1602 xmlNodePtr n;
1603 gpg_error_t error;
1605 if (append_to_element_list(elements) == FALSE)
1606 return gpg_error_from_errno(ENOMEM);
1608 for (n = node; n; n = n->next) {
1609 if (n->type == XML_ELEMENT_NODE) {
1610 xmlChar *content = node_has_attribute(n, (xmlChar *)"target");
1611 gchar *tmp;
1613 if (content) {
1614 if (strv_printf(&elements->elements, "%s\t%s", prefix, n->name) == FALSE)
1615 return gpg_error_from_errno(ENOMEM);
1617 if (append_to_element_list(elements) == FALSE)
1618 return gpg_error_from_errno(ENOMEM);
1621 tmp = g_strdup_printf("%s\t!%s", prefix, n->name);
1623 if (!tmp)
1624 return gpg_error_from_errno(ENOMEM);
1626 if (strv_printf(&elements->elements, "%s", tmp) == FALSE) {
1627 g_free(tmp);
1628 return gpg_error_from_errno(ENOMEM);
1631 if (n->children) {
1632 error = do_list_recurse(doc, n->children, elements, tmp);
1633 g_free(tmp);
1635 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1636 return error;
1638 else
1639 g_free(tmp);
1641 if (append_to_element_list(elements) == FALSE)
1642 return gpg_error_from_errno(ENOMEM);
1646 return 0;
1649 static gpg_error_t do_list_command(assuan_context_t ctx, xmlDocPtr doc,
1650 struct list_element_s *elements, char *line)
1652 gchar *prefix = NULL, *account;
1653 gchar **req = NULL, **oreq = NULL, *tmp;
1654 xmlNodePtr n;
1655 gboolean account_is_literal, account_has_target = FALSE;
1656 gint which = 0;
1657 gchar **p;
1658 gpg_error_t error;
1660 if ((req = split_input_line(line, "\t", 0)) == NULL) {
1661 if ((req = split_input_line(line, " ", 0)) == NULL)
1662 return EPWMD_COMMAND_SYNTAX;
1665 prefix = g_strdup(*req);
1667 if (!prefix) {
1668 g_strfreev(req);
1669 return gpg_error_from_errno(ENOMEM);
1672 account = g_strdup(*req);
1674 if (!account) {
1675 g_free(prefix);
1676 g_strfreev(req);
1677 return gpg_error_from_errno(ENOMEM);
1680 oreq = g_strdupv(req);
1682 if (!oreq) {
1683 g_free(prefix);
1684 g_free(account);
1685 g_strfreev(req);
1686 return gpg_error_from_errno(ENOMEM);
1689 p = req;
1690 again:
1691 account_has_target = FALSE;
1692 account_is_literal = is_literal_element_str(prefix);
1693 n = find_account(doc, &p, &error, &account_has_target, 0);
1695 if (which)
1696 oreq = p;
1697 else
1698 req = p;
1700 if (!n)
1701 goto fail;
1703 if (!which && account_is_literal == FALSE && account_has_target == FALSE) {
1704 tmp = g_strdup_printf("!%s", prefix);
1706 if (!tmp) {
1707 error = gpg_error_from_errno(ENOMEM);
1708 goto fail;
1711 g_free(prefix);
1712 prefix = tmp;
1715 if (*(p+1)) {
1716 gchar *t;
1718 n = find_elements(doc, n->children, p+1, &error, NULL, NULL, NULL,
1719 TRUE, 0, NULL);
1721 if (error)
1722 goto fail;
1724 tmp = g_strjoinv("\t", p+1);
1725 if (!tmp) {
1726 error = gpg_error_from_errno(ENOMEM);
1727 goto fail;
1730 t = g_strdup_printf("%s\t%s", prefix, tmp);
1731 if (!t) {
1732 error = gpg_error_from_errno(ENOMEM);
1733 goto fail;
1736 g_free(prefix);
1737 prefix = t;
1738 g_free(tmp);
1741 if (strv_printf(&elements->elements, "%s", prefix) == FALSE) {
1742 error = gpg_error_from_errno(ENOMEM);
1743 goto fail;
1746 if (node_has_child_element(n->children) == FALSE) {
1747 if (append_to_element_list(elements) == FALSE) {
1748 error = gpg_error_from_errno(ENOMEM);
1749 goto fail;
1752 else
1753 error = do_list_recurse(doc, n->children, elements, prefix);
1755 if (error)
1756 goto fail;
1758 if (!which++ && !*(p+1) && account_is_literal == FALSE && account_has_target == TRUE) {
1759 g_free(*oreq);
1760 *oreq = g_strdup_printf("!%s", account);
1762 if (!*oreq) {
1763 error = gpg_error_from_errno(ENOMEM);
1764 goto fail;
1767 p = oreq;
1768 g_free(prefix);
1769 prefix = g_strdup(*oreq);
1771 if (!prefix) {
1772 error = gpg_error_from_errno(ENOMEM);
1773 goto fail;
1776 goto again;
1779 fail:
1780 g_free(prefix);
1781 g_free(account);
1782 g_strfreev(req);
1784 if (oreq)
1785 g_strfreev(oreq);
1787 return error;
1791 * This could be faster especially when finding "target" attributes.
1793 static int list_command(assuan_context_t ctx, char *line)
1795 struct client_s *client = assuan_get_pointer(ctx);
1796 gpg_error_t error;
1797 struct list_element_s *elements = NULL;
1798 GString *string;
1799 gchar *tmp;
1800 gint i, total;
1802 if (disable_list_and_dump == TRUE)
1803 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1805 error = file_modified(client);
1807 if (error) {
1808 log_write("%s: %s", client->filename, pwmd_strerror(error));
1809 return send_error(ctx, error);
1812 if (!*line) {
1813 GString *str;
1815 error = list_accounts(client->doc, &str);
1817 if (error)
1818 return send_error(ctx, error);
1820 error = assuan_send_data(ctx, str->str, str->len);
1821 g_string_free(str, TRUE);
1822 return send_error(ctx, error);
1825 elements = g_malloc0(sizeof(struct list_element_s));
1827 if (!elements) {
1828 error = gpg_error_from_errno(ENOMEM);
1829 goto fail;
1832 error = do_list_command(ctx, client->doc, elements, line);
1834 if (error)
1835 goto fail;
1837 if (!error) {
1838 total = g_slist_length(elements->list);
1840 if (!total) {
1841 error = EPWMD_EMPTY_ELEMENT;
1842 goto fail;
1846 * Find element paths with a target and append those element trees to
1847 * the list.
1849 for (i = 0; i < total; i++) {
1850 gchar **req;
1852 tmp = g_slist_nth_data(elements->list, i);
1853 req = split_input_line(tmp, "\t", 0);
1855 if (!req) {
1856 if (g_str_has_prefix(tmp, "!") == TRUE) {
1857 g_strfreev(req);
1858 continue;
1861 else {
1862 gchar **p;
1864 for (p = req; *p; p++) {
1865 if (g_str_has_prefix(*p, "!") == FALSE)
1866 break;
1869 if (!*p) {
1870 g_strfreev(req);
1871 continue;
1875 g_strfreev(req);
1876 error = do_list_command(ctx, client->doc, elements, tmp);
1878 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1879 goto fail;
1881 total = g_slist_length(elements->list);
1885 string = g_string_new(NULL);
1887 for (i = 0; i < total; i++) {
1888 tmp = g_slist_nth_data(elements->list, i);
1889 g_string_append_printf(string, "%s\n", tmp);
1890 g_free(tmp);
1893 string = g_string_truncate(string, string->len - 1);
1894 error = assuan_send_data(ctx, string->str, string->len);
1895 g_string_free(string, TRUE);
1897 fail:
1898 if (elements) {
1899 if (elements->list)
1900 g_slist_free(elements->list);
1902 if (elements->elements)
1903 g_strfreev(elements->elements);
1905 g_free(elements);
1908 return send_error(ctx, error);
1911 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1912 const gchar *value)
1914 xmlAttrPtr a;
1916 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1917 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1919 if (!a)
1920 return EPWMD_LIBXML_ERROR;
1922 else
1923 xmlNodeSetContent(a->children, (xmlChar *)value);
1925 return 0;
1929 * req[0] - element path
1931 static int attribute_list(assuan_context_t ctx, gchar **req)
1933 struct client_s *client = assuan_get_pointer(ctx);
1934 gchar **attrlist = NULL;
1935 gint i = 0;
1936 gchar **path = NULL;
1937 xmlAttrPtr a;
1938 xmlNodePtr n, an;
1939 gchar *line;
1940 gpg_error_t error;
1942 if (!req || !req[0])
1943 return EPWMD_COMMAND_SYNTAX;
1945 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1947 * The first argument may be only an account.
1949 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1950 return EPWMD_COMMAND_SYNTAX;
1953 n = find_account(client->doc, &path, &error, NULL, 0);
1955 if (!n) {
1956 g_strfreev(path);
1957 return error;
1960 if (path[1]) {
1961 n = find_elements(client->doc, n->children, path+1, &error,
1962 NULL, NULL, NULL, FALSE, 0, NULL);
1964 if (!n) {
1965 g_strfreev(path);
1966 return error;
1970 g_strfreev(path);
1972 for (a = n->properties; a; a = a->next) {
1973 gchar **pa;
1975 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1976 if (attrlist)
1977 g_strfreev(attrlist);
1979 error = errno;
1980 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(errno));
1981 return gpg_error_from_errno(error);
1984 attrlist = pa;
1985 an = a->children;
1986 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1988 if (!attrlist[i]) {
1989 g_strfreev(attrlist);
1990 return gpg_error_from_errno(ENOMEM);
1993 attrlist[++i] = NULL;
1996 if (!attrlist)
1997 return EPWMD_EMPTY_ELEMENT;
1999 line = g_strjoinv("\n", attrlist);
2001 if (!line) {
2002 g_strfreev(attrlist);
2003 return gpg_error_from_errno(ENOMEM);
2006 error = assuan_send_data(ctx, line, strlen(line));
2007 g_free(line);
2008 g_strfreev(attrlist);
2009 return error;
2013 * req[0] - attribute
2014 * req[1] - element path
2016 static int attribute_delete(struct client_s *client, gchar **req)
2018 xmlAttrPtr a;
2019 xmlNodePtr n;
2020 gchar **path = NULL;
2021 gpg_error_t error;
2023 if (!req || !req[0] || !req[1])
2024 return EPWMD_COMMAND_SYNTAX;
2026 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2028 * The first argument may be only an account.
2030 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2031 return EPWMD_COMMAND_SYNTAX;
2035 * Don't remove the "name" attribute for the account element. To remove an
2036 * account use DELETE <account>.
2038 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
2039 error = EPWMD_ATTR_SYNTAX;
2040 goto fail;
2043 n = find_account(client->doc, &path, &error, NULL, 0);
2045 if (!n)
2046 goto fail;
2048 if (path[1]) {
2049 n = find_elements(client->doc, n->children, path+1, &error,
2050 NULL, NULL, NULL, FALSE, 0, NULL);
2052 if (!n)
2053 goto fail;
2056 g_strfreev(path);
2058 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
2059 return EPWMD_ATTR_NOT_FOUND;
2061 if (xmlRemoveProp(a) == -1)
2062 return EPWMD_LIBXML_ERROR;
2064 return 0;
2066 fail:
2067 g_strfreev(path);
2068 return error;
2072 * Creates a "target" attribute. When other commands encounter an element with
2073 * this attribute, the element path is modified to the target value. If the
2074 * source element path doesn't exist when using 'ATTR SET target', it is
2075 * created, but the destination element path must exist.
2077 * req[0] - source element path
2078 * req[1] - destination element path
2080 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2082 gchar **src, **dst, *line = NULL;
2083 gpg_error_t error;
2084 xmlNodePtr n;
2086 if (!req || !req[0] || !req[1])
2087 return EPWMD_COMMAND_SYNTAX;
2089 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2091 * The first argument may be only an account.
2093 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2094 return EPWMD_COMMAND_SYNTAX;
2097 if (valid_element_path(src, FALSE) == FALSE) {
2098 g_strfreev(src);
2099 return EPWMD_INVALID_ELEMENT;
2102 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2104 * The first argument may be only an account.
2106 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2107 error = EPWMD_COMMAND_SYNTAX;
2108 goto fail;
2112 n = find_account(client->doc, &dst, &error, NULL, 0);
2115 * Make sure the destination element path exists.
2117 if (!n)
2118 goto fail;
2120 if (dst[1]) {
2121 n = find_elements(client->doc, n->children, dst+1, &error,
2122 NULL, NULL, NULL, FALSE, 0, NULL);
2124 if (!n)
2125 goto fail;
2128 again:
2129 n = find_account(client->doc, &src, &error, NULL, 0);
2131 if (!n) {
2132 if (error == EPWMD_ELEMENT_NOT_FOUND) {
2133 error = new_account(client->doc, src[0]);
2135 if (error)
2136 goto fail;
2138 goto again;
2140 else
2141 goto fail;
2144 if (src[1]) {
2145 if (!n->children)
2146 n = create_target_elements_cb(n, src+1, &error, NULL);
2147 else
2148 n = find_elements(client->doc, n->children, src+1, &error,
2149 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
2151 if (!n)
2152 goto fail;
2155 * Reset the position of the element tree now that the elements
2156 * have been created.
2158 n = find_account(client->doc, &src, &error, NULL, 0);
2160 if (!n)
2161 goto fail;
2163 n = find_elements(client->doc, n->children, src+1, &error,
2164 NULL, NULL, NULL, FALSE, 0, NULL);
2166 if (!n)
2167 goto fail;
2170 line = g_strjoinv("\t", dst);
2171 error = add_attribute(n, "target", line);
2173 fail:
2174 g_free(line);
2175 g_strfreev(src);
2176 g_strfreev(dst);
2177 return error;
2181 * req[0] - account name
2182 * req[1] - new name
2184 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2186 gpg_error_t error;
2187 gchar **tmp;
2188 xmlNodePtr n;
2190 tmp = g_strdupv(req);
2192 if (!tmp)
2193 return gpg_error_from_errno(ENOMEM);
2195 n = find_account(client->doc, &tmp, &error, NULL, 0);
2196 g_strfreev(tmp);
2198 if (!n)
2199 return error;
2201 if (g_utf8_collate(req[0], req[1]) == 0)
2202 return 0;
2205 * Will not overwrite an existing account.
2207 tmp = g_strdupv(req+1);
2209 if (!tmp)
2210 return gpg_error_from_errno(ENOMEM);
2212 n = find_account(client->doc, &tmp, &error, NULL, 0);
2213 g_strfreev(tmp);
2215 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
2216 return error;
2218 if (n)
2219 return EPWMD_ACCOUNT_EXISTS;
2222 * Whitespace not allowed in account names.
2224 if (contains_whitespace(req[1]) == TRUE)
2225 return EPWMD_ATTR_SYNTAX;
2227 tmp = g_strdupv(req);
2229 if (!tmp)
2230 return gpg_error_from_errno(ENOMEM);
2232 n = find_account(client->doc, &tmp, &error, NULL, 0);
2233 g_strfreev(tmp);
2235 if (!n)
2236 return EPWMD_ELEMENT_NOT_FOUND;
2238 return add_attribute(n, "name", req[1]);
2242 * req[0] - attribute
2243 * req[1] - element path
2245 static int attribute_get(assuan_context_t ctx, gchar **req)
2247 struct client_s *client = assuan_get_pointer(ctx);
2248 xmlNodePtr n;
2249 xmlChar *a;
2250 gchar **path= NULL;
2251 gpg_error_t error;
2253 if (!req || !req[0] || !req[1])
2254 return EPWMD_COMMAND_SYNTAX;
2256 if (strchr(req[1], '\t')) {
2257 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2258 return EPWMD_COMMAND_SYNTAX;
2260 else {
2261 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2262 return EPWMD_COMMAND_SYNTAX;
2265 n = find_account(client->doc, &path, &error, NULL, 0);
2267 if (!n)
2268 goto fail;
2270 if (path[1]) {
2271 n = find_elements(client->doc, n->children, path+1, &error,
2272 NULL, NULL, NULL, FALSE, 0, NULL);
2274 if (!n)
2275 goto fail;
2278 g_strfreev(path);
2280 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2281 return EPWMD_ATTR_NOT_FOUND;
2283 error = assuan_send_data(ctx, a, xmlStrlen(a));
2284 xmlFree(a);
2285 return error;
2287 fail:
2288 g_strfreev(path);
2289 return error;
2293 * req[0] - attribute
2294 * req[1] - element path
2295 * req[2] - value
2297 static int attribute_set(struct client_s *client, gchar **req)
2299 gchar **path = NULL;
2300 gpg_error_t error;
2301 xmlNodePtr n;
2303 if (!req || !req[0] || !req[1] || !req[2])
2304 return EPWMD_COMMAND_SYNTAX;
2307 * Reserved attribute names.
2309 if (g_utf8_collate(req[0], "name") == 0) {
2311 * Only reserved for the account element. Not the rest of the
2312 * document.
2314 if (strchr(req[1], '\t') == NULL)
2315 return name_attribute(client, req + 1);
2317 else if (g_utf8_collate(req[0], "target") == 0)
2318 return target_attribute(client, req + 1);
2320 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2322 * The first argument may be only an account.
2324 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2325 return EPWMD_COMMAND_SYNTAX;
2328 n = find_account(client->doc, &path, &error, NULL, 0);
2330 if (!n)
2331 goto fail;
2333 if (path[1]) {
2334 n = find_elements(client->doc, n->children, path+1, &error,
2335 NULL, NULL, NULL, FALSE, 0, NULL);
2337 if (!n)
2338 goto fail;
2341 g_strfreev(path);
2342 return add_attribute(n, req[0], req[2]);
2344 fail:
2345 g_strfreev(path);
2346 return error;
2350 * req[0] - command
2351 * req[1] - attribute name or element path if command is LIST
2352 * req[2] - element path
2353 * req[2] - element path or value
2355 static int attr_command(assuan_context_t ctx, char *line)
2357 struct client_s *client = assuan_get_pointer(ctx);
2358 gchar **req = split_input_line(line, " ", 4);
2359 gpg_error_t error = 0;
2361 error = file_modified(client);
2363 if (error) {
2364 log_write("%s: %s", client->filename ? client->filename : "",
2365 pwmd_strerror(error));
2366 g_strfreev(req);
2367 return send_error(ctx, error);
2370 if (!req || !req[0] || !req[1]) {
2371 g_strfreev(req);
2372 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2375 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2376 error = attribute_set(client, req+1);
2377 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2378 error = attribute_get(ctx, req+1);
2379 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2380 error = attribute_delete(client, req+1);
2381 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2382 error = attribute_list(ctx, req+1);
2383 else
2384 error = EPWMD_COMMAND_SYNTAX;
2386 g_strfreev(req);
2387 return send_error(ctx, error);
2390 static int iscached_command(assuan_context_t ctx, char *line)
2392 gchar **req = split_input_line(line, " ", 0);
2393 guchar md5file[16];
2395 if (!req || !*req) {
2396 g_strfreev(req);
2397 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2400 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2401 g_strfreev(req);
2402 CACHE_LOCK(ctx);
2404 if (cache_iscached(md5file) == FALSE) {
2405 CACHE_UNLOCK;
2406 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2409 CACHE_UNLOCK;
2410 return send_error(ctx, 0);
2413 gpg_error_t send_cache_status(assuan_context_t ctx)
2415 gchar *tmp;
2416 struct client_s *client = assuan_get_pointer(ctx);
2418 CACHE_LOCK(client->ctx);
2419 tmp = print_fmt("%i %i",
2420 cache_file_count(),
2421 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2422 CACHE_UNLOCK;
2424 return assuan_write_status(ctx, "CACHE", tmp);
2427 static int clearcache_command(assuan_context_t ctx, char *line)
2429 struct client_s *client = assuan_get_pointer(ctx);
2430 gchar **req = split_input_line(line, " ", 0);
2431 guchar md5file[16];
2433 CACHE_LOCK(ctx);
2435 if (!req || !*req) {
2436 g_strfreev(req);
2437 cache_clear(client->md5file, 2);
2438 CACHE_UNLOCK;
2439 return send_error(ctx, 0);
2442 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2443 g_strfreev(req);
2445 if (cache_clear(md5file, 1) == FALSE) {
2446 CACHE_UNLOCK;
2447 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2450 CACHE_UNLOCK;
2451 return send_error(ctx, 0);
2454 static int cachetimeout_command(assuan_context_t ctx, char *line)
2456 guchar md5file[16];
2457 glong timeout;
2458 gchar **req = split_input_line(line, " ", 0);
2459 gchar *p;
2460 struct client_s *client = assuan_get_pointer(ctx);
2462 if (!req || !*req || !req[1]) {
2463 g_strfreev(req);
2464 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2467 errno = 0;
2468 timeout = strtol(req[0], &p, 10);
2470 if (errno != 0 || *p != 0) {
2471 g_strfreev(req);
2472 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2475 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2476 g_strfreev(req);
2477 CACHE_LOCK(client->ctx);
2479 if (cache_set_timeout(md5file, timeout) == FALSE) {
2480 CACHE_UNLOCK;
2481 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2484 CACHE_UNLOCK;
2485 send_cache_status_all();
2486 return send_error(ctx, 0);
2489 static int dump_command(assuan_context_t ctx, char *line)
2491 xmlChar *xml;
2492 gssize len;
2493 struct client_s *client = assuan_get_pointer(ctx);
2494 gpg_error_t error;
2496 if (disable_list_and_dump == TRUE)
2497 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2499 error = file_modified(client);
2501 if (error) {
2502 log_write("%s: %s", client->filename ? client->filename : "",
2503 pwmd_strerror(error));
2504 return send_error(ctx, error);
2507 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2508 error = assuan_send_data(ctx, xml, len);
2509 xmlFree(xml);
2510 return send_error(ctx, error);
2513 static int getconfig_command(assuan_context_t ctx, gchar *line)
2515 struct client_s *client = assuan_get_pointer(ctx);
2516 gpg_error_t error = 0;
2517 gchar *p, *tmp;
2519 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2520 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2522 p = get_key_file_string(client->filename ? client->filename : "default", line);
2524 if (!p)
2525 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2527 tmp = expand_homedir(p);
2528 g_free(p);
2529 p = tmp;
2530 error = assuan_send_data(ctx, p, strlen(p));
2531 g_free(p);
2532 return send_error(ctx, error);
2535 void cleanup_assuan(assuan_context_t ctx)
2537 struct client_s *cl = assuan_get_pointer(ctx);
2539 cleanup_client(cl);
2542 static void reset_notify(assuan_context_t ctx)
2544 struct client_s *cl = assuan_get_pointer(ctx);
2546 cleanup_client(cl);
2549 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2551 gchar name[32] = {0}, value[256] = {0};
2552 pth_attr_t attr = pth_attr_of(pth_self());
2554 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2555 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_SYNTAX);
2557 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2558 log_write("OPTION CLIENT %s", line);
2559 pth_attr_set(attr, PTH_ATTR_NAME, value);
2561 else
2562 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_UNKNOWN_OPTION);
2564 return 0;
2567 static int option_handler(assuan_context_t ctx, const gchar *name,
2568 const gchar *value)
2570 #ifdef WITH_PINENTRY
2571 struct client_s *client = assuan_get_pointer(ctx);
2572 #endif
2574 if (!value || !*value)
2575 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2577 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2578 #ifdef WITH_PINENTRY
2579 g_free(client->pinentry->ttyname);
2580 client->pinentry->ttyname = g_strdup(value);
2581 #else
2582 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_NOT_IMPLEMENTED);
2583 #endif
2585 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2586 #ifdef WITH_PINENTRY
2587 g_free(client->pinentry->ttytype);
2588 client->pinentry->ttytype = g_strdup(value);
2589 #else
2590 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_NOT_IMPLEMENTED);
2591 #endif
2593 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2594 #ifdef WITH_PINENTRY
2595 g_free(client->pinentry->display);
2596 client->pinentry->display = g_strdup(value);
2597 #else
2598 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_NOT_IMPLEMENTED);
2599 #endif
2601 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2602 #ifdef WITH_PINENTRY
2603 g_free(client->pinentry->path);
2604 client->pinentry->path = g_strdup(value);
2605 #else
2606 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_NOT_IMPLEMENTED);
2607 #endif
2609 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2610 #ifdef WITH_PINENTRY
2611 g_free(client->pinentry->title);
2612 client->pinentry->title = g_strdup(value);
2613 #else
2614 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_NOT_IMPLEMENTED);
2615 #endif
2617 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2618 #ifdef WITH_PINENTRY
2619 g_free(client->pinentry->prompt);
2620 client->pinentry->prompt = g_strdup(value);
2621 #else
2622 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_NOT_IMPLEMENTED);
2623 #endif
2625 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2626 #ifdef WITH_PINENTRY
2627 g_free(client->pinentry->desc);
2628 client->pinentry->desc = g_strdup(value);
2629 #else
2630 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_NOT_IMPLEMENTED);
2631 #endif
2633 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2634 #ifndef WITH_PINENTRY
2635 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_NOT_IMPLEMENTED);
2636 #else
2637 gchar *p = NULL;
2638 gint n = strtol(value, &p, 10);
2640 if (*p || n < 0)
2641 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2643 client->pinentry->timeout = n;
2644 #endif
2646 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2647 #ifndef WITH_PINENTRY
2648 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_NOT_IMPLEMENTED);
2649 #else
2650 gchar *p = NULL;
2651 gint n = strtol(value, &p, 10);
2653 if (*p || n < 0 || n > 1)
2654 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2656 client->pinentry->use = n == 0 ? FALSE : TRUE;
2657 #endif
2659 else if (g_strcasecmp(name, (gchar *)"client") == 0)
2660 return parse_client_option(ctx, value);
2661 else
2662 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_UNKNOWN_OPTION);
2664 log_write("OPTION %s=%s", name, value);
2665 return 0;
2668 gpg_error_t register_commands(assuan_context_t ctx)
2670 static struct {
2671 const char *name;
2672 int (*handler)(assuan_context_t, char *line);
2673 } table[] = {
2674 { "OPEN", open_command },
2675 { "SAVE", save_command },
2676 { "LIST", list_command },
2677 { "REALPATH", realpath_command },
2678 { "STORE", store_command },
2679 { "DELETE", delete_command },
2680 { "GET", get_command },
2681 { "ATTR", attr_command },
2682 { "ISCACHED", iscached_command },
2683 { "CLEARCACHE", clearcache_command },
2684 { "CACHETIMEOUT", cachetimeout_command },
2685 { "GETCONFIG", getconfig_command },
2686 { "DUMP", dump_command },
2687 { "INPUT", NULL },
2688 { "OUTPUT", NULL },
2689 { NULL, NULL }
2691 int i, rc;
2693 for (i=0; table[i].name; i++) {
2694 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2696 if (rc)
2697 return rc;
2700 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2701 if (rc)
2702 return rc;
2704 rc = assuan_register_option_handler(ctx, option_handler);
2705 if (rc)
2706 return rc;
2708 return assuan_register_reset_notify(ctx, reset_notify);
2711 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2712 guchar *key)
2714 guchar *iv;
2715 void *inbuf;
2716 gsize insize, len;
2717 guchar tkey[gcrykeysize];
2718 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2719 gcry_cipher_hd_t gh;
2720 guint iter = 0, n_iter = 0;
2721 gint iter_progress;
2722 void *outbuf = NULL;
2723 gint zerror = 0;
2724 glong outsize = 0;
2725 gpg_error_t error;
2726 file_header_t file_header;
2728 if (!ctx) {
2729 error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2731 if (error)
2732 return error;
2734 else
2735 gh = client->gh;
2737 lseek(fd, 0, SEEK_SET);
2738 insize = st.st_size - sizeof(file_header_t);
2739 iv = gcry_malloc(gcryblocksize);
2741 if (!iv) {
2742 if (!ctx)
2743 gcry_cipher_close(gh);
2745 return gpg_error_from_errno(ENOMEM);
2748 len = pth_read(fd, &file_header, sizeof(file_header_t));
2750 if (len != sizeof(file_header_t)) {
2751 len = errno;
2753 if (!ctx)
2754 gcry_cipher_close(gh);
2756 gcry_free(iv);
2757 errno = len;
2758 return gpg_error_from_errno(errno);
2761 /* No encryption iterations. This is a plain (gzipped) file. */
2762 if (file_header.iter == -1) {
2764 * cache_file_count() needs both .used == TRUE and a valid key in
2765 * order for it to count as a used cache entry. Fixes CACHE status
2766 * messages.
2768 memset(key, '!', gcrykeysize);
2769 insize = st.st_size - sizeof(file_header_t);
2772 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2773 inbuf = gcry_malloc(insize);
2775 if (!inbuf) {
2776 if (!ctx)
2777 gcry_cipher_close(gh);
2779 gcry_free(iv);
2780 return gpg_error_from_errno(ENOMEM);
2783 len = pth_read(fd, inbuf, insize);
2785 if (len != insize) {
2786 len = errno;
2788 if (!ctx)
2789 gcry_cipher_close(gh);
2791 gcry_free(iv);
2792 errno = len;
2793 return gpg_error_from_errno(errno);
2796 if (file_header.iter == -1)
2797 goto decompress;
2799 memcpy(tkey, key, sizeof(tkey));
2800 tkey[0] ^= 1;
2802 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2803 if (!ctx) {
2804 gcry_cipher_close(gh);
2805 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2807 else
2808 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2810 gcry_free(inbuf);
2811 gcry_free(iv);
2812 return error;
2815 if ((error = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2816 if (!ctx) {
2817 gcry_cipher_close(gh);
2818 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2820 else
2821 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2823 gcry_free(inbuf);
2824 gcry_free(iv);
2826 if (!ctx)
2827 gcry_cipher_close(gh);
2829 return error;
2832 iter_progress = get_key_file_integer("default", "iteration_progress");
2834 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2835 error = assuan_write_status(client->ctx, "DECRYPT", "0");
2837 if (error) {
2838 gcry_free(inbuf);
2839 gcry_free(iv);
2840 return error;
2844 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2846 if (error) {
2847 gcry_free(inbuf);
2848 gcry_free(iv);
2849 return error;
2852 if ((error = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2853 if (!ctx) {
2854 gcry_cipher_close(gh);
2855 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2857 else
2858 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2860 gcry_free(inbuf);
2861 gcry_free(iv);
2862 return error;
2865 while (iter < file_header.iter) {
2866 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2867 if (!(iter % iter_progress)) {
2868 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i",
2869 ++n_iter * iter_progress));
2871 if (error) {
2872 gcry_free(inbuf);
2873 gcry_free(iv);
2874 return error;
2879 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2880 if (!ctx) {
2881 gcry_cipher_close(gh);
2882 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2884 else
2885 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2887 gcry_free(inbuf);
2888 gcry_free(iv);
2889 return error;
2892 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2894 if (error) {
2895 if (!ctx) {
2896 gcry_cipher_close(gh);
2897 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2899 else
2900 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2902 gcry_free(inbuf);
2903 gcry_free(iv);
2904 return error;
2907 iter++;
2908 pth_yield(NULL);
2911 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2912 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i", file_header.iter));
2914 if (error) {
2915 gcry_free(inbuf);
2916 gcry_free(iv);
2917 return error;
2921 gcry_free(iv);
2923 decompress:
2924 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zerror) == FALSE) {
2926 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2928 if (zerror == Z_MEM_ERROR) {
2929 gcry_free(inbuf);
2930 return gpg_error_from_errno(ENOMEM);
2932 else if (zerror != Z_DATA_ERROR) {
2933 gcry_free(inbuf);
2935 if (!ctx)
2936 gcry_cipher_close(gh);
2938 return EPWMD_BADKEY;
2941 else {
2942 gcry_free(inbuf);
2943 inbuf = outbuf;
2944 insize = outsize;
2947 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2948 gcry_free(inbuf);
2950 if (!ctx)
2951 gcry_cipher_close(gh);
2953 return EPWMD_BADKEY;
2956 if (ctx) {
2957 client->xml = inbuf;
2958 client->len = insize;
2960 else {
2961 gcry_cipher_close(gh);
2962 gcry_free(inbuf);
2965 return 0;
2969 * This is called after every Assuan command.
2971 void command_finalize(assuan_context_t ctx, gint error)
2973 struct client_s *client = assuan_get_pointer(ctx);
2975 unlock_file_mutex(client);