Added the LOCK and UNLOCK commands. LOCK will lock the file mutex and
[pwmd.git] / src / commands.c
blobceded9dbf0a0ebc93a21b3a83cce29e082a415db
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;
73 gpg_error_t rc;
75 if (client->state != STATE_OPEN)
76 return EPWMD_NO_FILE;
78 rc = lock_file_mutex(client);
80 if (rc)
81 return rc;
83 if (stat(client->filename, &st) == 0 && client->mtime) {
84 if (client->mtime != st.st_mtime)
85 return EPWMD_FILE_MODIFIED;
88 return 0;
91 static gboolean encrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
92 void *inbuf, gsize insize)
94 gpg_error_t rc;
96 if ((rc = gcry_cipher_encrypt(gh, outbuf, outsize, inbuf, insize))) {
97 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
98 return FALSE;
101 return TRUE;
104 static gpg_error_t decrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
105 void *inbuf, gsize insize)
107 gpg_error_t rc;
109 if ((rc = gcry_cipher_decrypt(gh, outbuf, outsize, inbuf, insize)))
110 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
112 return rc;
115 static gpg_error_t parse_xml(assuan_context_t ctx)
117 struct client_s *client = assuan_get_pointer(ctx);
119 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
121 if (!client->doc)
122 return EPWMD_LIBXML_ERROR;
124 return 0;
127 void unlock_file_mutex(struct client_s *client)
129 pth_mutex_t *m;
131 #ifdef WITH_PINENTRY
132 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
133 #else
134 if (client->has_lock == FALSE)
135 #endif
136 return;
138 CACHE_LOCK(client->ctx);
140 if (cache_get_mutex(client->md5file, &m) == FALSE) {
141 CACHE_UNLOCK;
142 return;
145 CACHE_UNLOCK;
146 pth_mutex_release(m);
147 client->has_lock = client->is_lock_cmd = FALSE;
150 gpg_error_t lock_file_mutex(struct client_s *client)
152 pth_mutex_t *m;
154 if (client->has_lock == TRUE)
155 return 0;
157 CACHE_LOCK(client->ctx);
159 if (cache_get_mutex(client->md5file, &m) == FALSE) {
160 CACHE_UNLOCK;
161 return 0;
164 CACHE_UNLOCK;
166 if (pth_mutex_acquire(m, TRUE, NULL) == FALSE) {
167 if (errno == EBUSY) {
168 if (client->ctx)
169 assuan_write_status(client->ctx, "LOCKED", N_("Waiting for lock"));
171 pth_mutex_acquire(m, FALSE, NULL);
173 else {
174 gint e = errno;
175 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(errno));
176 return gpg_error_from_errno(e);
180 client->has_lock = TRUE;
181 return 0;
184 void free_client(struct client_s *client)
186 if (client->doc)
187 xmlFreeDoc(client->doc);
189 if (client->xml)
190 gcry_free(client->xml);
192 if (client->filename)
193 g_free(client->filename);
195 if (client->gh)
196 gcry_cipher_close(client->gh);
199 void cleanup_client(struct client_s *client)
201 assuan_context_t ctx = client->ctx;
202 #ifdef WITH_PINENTRY
203 struct pinentry_s *pin = client->pinentry;
204 #endif
206 unlock_file_mutex(client);
207 CACHE_LOCK(client->ctx);
208 cache_decr_refcount(client->md5file);
211 * This may be a new file so don't use a cache slot. save_command() will
212 * set this to FALSE on success.
214 if (client->new == TRUE)
215 cache_clear(client->md5file, 1);
217 free_client(client);
218 memset(client, 0, sizeof(struct client_s));
219 client->state = STATE_CONNECTED;
220 client->ctx = ctx;
221 client->freed = TRUE;
222 #ifdef WITH_PINENTRY
223 client->pinentry = pin;
224 #endif
225 CACHE_UNLOCK;
228 gboolean do_decompress(assuan_context_t ctx, gpointer in, gint insize,
229 gpointer *out, glong *outsize, gint *rc)
231 z_stream z;
232 gpointer pout;
233 gz_header h;
234 gchar buf[17];
235 gchar str[ASSUAN_LINELENGTH];
237 z.zalloc = z_alloc;
238 z.zfree = z_free;
239 z.next_in = in;
240 z.avail_in = insize;
241 z.avail_out = zlib_bufsize;
242 z.next_out = pout = g_malloc(zlib_bufsize);
244 if (!pout) {
245 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
246 *rc = Z_MEM_ERROR;
247 return FALSE;
250 *rc = inflateInit2(&z, 47);
252 if (*rc != Z_OK) {
253 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
254 g_free(pout);
255 return FALSE;
258 memset(&h, 0, sizeof(gz_header));
259 h.comment = (guchar *)buf;
260 h.comm_max = sizeof(buf);
261 *rc = inflateGetHeader(&z, &h);
263 if (*rc != Z_OK) {
264 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
265 g_free(pout);
266 inflateEnd(&z);
267 return FALSE;
270 *rc = inflate(&z, Z_BLOCK);
272 if (*rc != Z_OK) {
273 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
274 g_free(pout);
275 inflateEnd(&z);
276 return FALSE;
279 if (h.comment)
280 insize = atoi((gchar *)h.comment);
282 do {
283 gpointer p;
285 *rc = inflate(&z, Z_FINISH);
287 switch (*rc) {
288 case Z_OK:
289 break;
290 case Z_BUF_ERROR:
291 if (!z.avail_out) {
292 p = g_realloc(pout, z.total_out + zlib_bufsize);
294 if (!p) {
295 *rc = Z_MEM_ERROR;
296 goto fail;
299 pout = p;
300 z.next_out = pout + z.total_out;
301 z.avail_out = zlib_bufsize;
303 if (ctx) {
304 *rc = assuan_write_status(ctx, "DECOMPRESS",
305 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
307 if (*rc)
308 goto fail;
311 break;
312 case Z_STREAM_END:
313 break;
314 default:
315 goto fail;
316 break;
319 pth_yield(NULL);
320 } while (*rc != Z_STREAM_END);
322 if (ctx) {
323 *rc = assuan_write_status(ctx, "DECOMPRESS",
324 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
326 if (*rc)
327 goto fail;
330 *out = pout;
331 *outsize = z.total_out;
332 inflateEnd(&z);
333 *rc = 0;
334 return TRUE;
336 fail:
337 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
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 rc;
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 rc = 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, rc);
387 rc = try_xml_decrypt(ctx, fd, st, shakey);
388 close(fd);
390 if (rc) {
391 memset(shakey, 0, sizeof(shakey));
392 cleanup_client(client);
393 return send_error(ctx, rc);
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 rc = parse_xml(ctx);
419 if (client->xml) {
420 gcry_free(client->xml);
421 client->xml = NULL;
424 if (!rc) {
425 if (client->new == FALSE)
426 send_cache_status_all();
428 client->state = STATE_OPEN;
431 return send_error(ctx, rc);
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 rc;
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 rc = lock_file_mutex(client);
478 if (rc) {
479 g_strfreev(req);
480 return send_error(ctx, rc);
483 client->freed = FALSE;
485 if ((rc = 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(rc));
488 cleanup_client(client);
489 return send_error(ctx, rc);
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) != 0) {
529 if (errno != ENOENT) {
530 rc = errno;
531 log_write("%s: %s", filename, strerror(errno));
532 g_strfreev(req);
533 cleanup_client(client);
534 return send_syserror(ctx, rc);
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 rc = read_file_header(filename, &file_header);
566 if (rc) {
567 g_strfreev(req);
568 cleanup_client(client);
569 return send_error(ctx, rc);
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 rc. It will then call open_command_finalize() to
587 * to finish the command.
589 if (!req[1] || !*req[1]) {
590 #ifdef WITH_PINENTRY
591 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
593 /* From set_pinentry_defaults(). */
594 if (client->pinentry->enable == FALSE ||
595 (client->pinentry->enable == -1 && b == FALSE)) {
596 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
597 goto done;
600 g_strfreev(req);
601 lock_pin_mutex(client);
602 client->pinentry->which = PINENTRY_OPEN;
603 rc = pinentry_fork(ctx);
605 if (rc) {
606 unlock_pin_mutex(client->pinentry);
607 cleanup_client(client);
608 return send_error(ctx, rc);
611 client->pinentry->cb = open_command_finalize;
612 client->pinentry->status = PINENTRY_INIT;
613 return 0;
614 #else
615 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
616 goto done;
617 #endif
620 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
623 done:
624 g_strfreev(req);
625 return open_command_finalize(ctx, shakey, cached);
628 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
629 gint size, gpointer *out, glong *outsize, gint *rc)
631 z_stream z;
632 gpointer pout, pin;
633 gz_header h;
634 gchar buf[17];
635 gint cmd = Z_NO_FLUSH;
636 gchar str[ASSUAN_LINELENGTH];
638 z.zalloc = z_alloc;
639 z.zfree = z_free;
640 z.next_in = pin = data;
641 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
642 z.avail_out = zlib_bufsize;
643 z.next_out = pout = g_malloc(zlib_bufsize);
645 if (!pout) {
646 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
647 *rc = Z_MEM_ERROR;
648 return FALSE;
651 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
653 if (*rc != Z_OK) {
654 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
655 g_free(pout);
656 return FALSE;
659 memset(&h, 0, sizeof(gz_header));
660 g_snprintf(buf, sizeof(buf), "%i", size);
661 h.comment = (guchar *)buf;
662 *rc = deflateSetHeader(&z, &h);
664 if (*rc != Z_OK) {
665 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
666 g_free(pout);
667 deflateEnd(&z);
668 return FALSE;
671 do {
672 gpointer p;
674 *rc = deflate(&z, cmd);
676 switch (*rc) {
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 *rc = 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 goto fail;
708 if (z.total_in >= size)
709 cmd = Z_FINISH;
711 break;
712 case Z_STREAM_END:
713 break;
714 default:
715 goto fail;
718 pth_yield(NULL);
719 } while (*rc != Z_STREAM_END);
721 if (ctx) {
722 *rc = assuan_write_status(ctx, "COMPRESS",
723 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
725 if (*rc)
726 goto fail;
729 *out = pout;
730 *outsize = z.total_out;
731 deflateEnd(&z);
732 *rc = 0;
733 return TRUE;
735 fail:
736 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
737 g_free(pout);
738 deflateEnd(&z);
739 return FALSE;
742 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
743 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
744 gint iter)
746 gsize len = insize;
747 gint fd;
748 gpointer inbuf;
749 guchar tkey[gcrykeysize];
750 gchar *p;
751 gpg_error_t rc;
752 guint iter_progress = 0, n_iter = 0, xiter = 0;
753 gchar tmp[FILENAME_MAX];
754 struct stat st;
755 mode_t mode = 0;
756 file_header_t file_header;
757 gchar str[ASSUAN_LINELENGTH];
759 if (iter == -1) {
761 * cache_file_count() needs both .used == TRUE and a valid key in
762 * order for it to count as a used cache entry. Fixes CACHE status
763 * messages.
765 memset(shakey, '!', gcrykeysize);
766 inbuf = data;
767 file_header.iter = iter;
768 goto write_file;
771 if (insize / gcryblocksize) {
772 len = (insize / gcryblocksize) * gcryblocksize;
774 if (insize % gcryblocksize)
775 len += gcryblocksize;
779 * Resize the existing xml buffer to the block size required by gcrypt
780 * rather than duplicating it and wasting memory.
782 inbuf = gcry_realloc(data, len);
784 if (!inbuf)
785 return gpg_error_from_errno(ENOMEM);
787 insize = len;
788 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
789 memcpy(tkey, shakey, sizeof(tkey));
790 tkey[0] ^= 1;
792 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
793 gcry_free(inbuf);
794 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
795 return rc;
798 file_header.iter = iter;
800 if (client)
801 iter_progress = get_key_file_integer("global", "iteration_progress");
803 if (client && iter_progress && file_header.iter >= iter_progress) {
804 rc = assuan_write_status(client->ctx, "ENCRYPT", "0");
806 if (rc) {
807 gcry_free(inbuf);
808 return rc;
812 while (xiter < file_header.iter) {
813 if (client && iter_progress > 0 && xiter >= iter_progress) {
814 if (!(xiter % iter_progress)) {
815 rc = assuan_write_status(client->ctx, "ENCRYPT",
816 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
818 if (rc) {
819 gcry_free(inbuf);
820 return rc;
825 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
826 sizeof(file_header.iv)))) {
827 gcry_free(inbuf);
828 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
829 return rc;
832 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
833 == FALSE) {
834 gcry_free(inbuf);
835 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
836 return rc;
839 xiter++;
840 pth_yield(NULL);
843 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
844 sizeof(file_header.iv)))) {
845 gcry_free(inbuf);
846 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
847 return rc;
850 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
851 gcry_free(inbuf);
852 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
853 return rc;
856 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
857 gcry_free(inbuf);
858 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
859 return rc;
862 if (client && iter_progress && file_header.iter >= iter_progress) {
863 rc = assuan_write_status(client->ctx, "ENCRYPT",
864 print_fmt(str, sizeof(str), "%i", file_header.iter));
866 if (rc) {
867 gcry_free(inbuf);
868 return rc;
872 write_file:
873 if (filename) {
874 if (stat(filename, &st) == 0) {
875 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
878 * FIXME What if the file has an ACL?
880 if (!(mode & S_IWUSR)) {
881 gcry_free(inbuf);
882 return gpg_error_from_errno(EACCES);
885 else {
886 if (errno != ENOENT) {
887 rc = errno;
888 gcry_free(inbuf);
889 return gpg_error_from_errno(rc);
893 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
895 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
896 rc = errno;
897 gcry_free(inbuf);
898 p = strrchr(tmp, '/');
899 p++;
900 log_write("%s: %s", p, strerror(rc));
901 return gpg_error_from_errno(rc);
904 else
906 * xml_import() from command line.
908 fd = STDOUT_FILENO;
910 len = pth_write(fd, &file_header, sizeof(file_header_t));
912 if (len != sizeof(file_header)) {
913 len = errno;
915 if (filename) {
916 close(fd);
917 unlink(tmp);
920 gcry_free(inbuf);
921 return gpg_error_from_errno(len);
924 len = pth_write(fd, inbuf, insize);
926 if (len != insize) {
927 len = errno;
929 if (filename) {
930 close(fd);
931 unlink(tmp);
934 gcry_free(inbuf);
935 return gpg_error_from_errno(len);
938 if (fsync(fd) == -1) {
939 len = errno;
941 if (filename) {
942 close(fd);
943 unlink(tmp);
946 gcry_free(inbuf);
947 return gpg_error_from_errno(len);
950 if (filename) {
951 close(fd);
953 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
954 gchar tmp2[FILENAME_MAX];
956 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
958 if (rename(filename, tmp2) == -1) {
959 unlink(tmp);
960 len = errno;
961 gcry_free(inbuf);
962 return gpg_error_from_errno(len);
966 if (rename(tmp, filename) == -1) {
967 len = errno;
968 unlink(tmp);
969 gcry_free(inbuf);
970 return gpg_error_from_errno(len);
973 if (mode)
974 chmod(filename, mode);
977 gcry_free(inbuf);
978 return 0;
981 static gpg_error_t save_command_finalize(assuan_context_t ctx,
982 guchar shakey[], gboolean cached)
984 struct client_s *client = assuan_get_pointer(ctx);
985 gpointer xmlbuf;
986 xmlChar *p;
987 gint len;
988 gint iter;
989 gint timeout;
990 gpointer outbuf;
991 glong outsize = 0;
992 gint zrc;
993 gpg_error_t rc;
994 struct stat st;
996 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
997 xmlbuf = p;
999 iter = get_key_file_integer(client->filename, "compression_level");
1001 if (iter < 0)
1002 iter = 0;
1004 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
1005 memset(shakey, 0, sizeof(shakey));
1006 xmlFree(xmlbuf);
1008 if (zrc == Z_MEM_ERROR) {
1009 return send_syserror(ctx, ENOMEM);
1011 else
1012 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1014 else {
1015 gcry_free(xmlbuf);
1016 xmlbuf = outbuf;
1017 len = outsize;
1020 iter = get_key_file_integer(client->filename, "iterations");
1021 rc = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1023 if (rc) {
1024 memset(shakey, 0, sizeof(shakey));
1025 return send_error(ctx, rc);
1028 stat(client->filename, &st);
1029 client->mtime = st.st_mtime;
1030 timeout = get_key_file_integer(client->filename, "cache_timeout");
1031 CACHE_LOCK(client->ctx);
1033 if (cached) {
1034 memset(shakey, 0, sizeof(shakey));
1035 cache_reset_timeout(client->md5file, timeout);
1036 CACHE_UNLOCK;
1038 if (client->new == TRUE)
1039 send_cache_status_all();
1041 client->new = FALSE;
1042 return send_error(ctx, 0);
1045 if (cache_update_key(client->md5file, shakey) == FALSE) {
1046 memset(shakey, 0, sizeof(shakey));
1047 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1048 CACHE_UNLOCK;
1049 return send_error(ctx, EPWMD_MAX_SLOTS);
1052 client->new = FALSE;
1053 memset(shakey, 0, sizeof(shakey));
1054 cache_reset_timeout(client->md5file, timeout);
1055 CACHE_UNLOCK;
1056 send_cache_status_all();
1057 return send_error(ctx, 0);
1060 static int save_command(assuan_context_t ctx, char *line)
1062 gboolean cached = FALSE;
1063 guchar shakey[gcrykeysize];
1064 struct stat st;
1065 struct client_s *client = assuan_get_pointer(ctx);
1066 gpg_error_t rc;
1068 memset(shakey, 0, sizeof(shakey));
1069 rc = file_modified(client);
1071 if (rc) {
1072 log_write("%s: %s", client->filename ? client->filename : "",
1073 pwmd_strerror(rc));
1074 return send_error(ctx, rc);
1077 rc = lock_file_mutex(client);
1079 if (rc)
1080 return send_error(ctx, rc);
1082 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1083 return send_syserror(ctx, errno);
1085 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1086 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1087 return send_error(ctx, EPWMD_INVALID_FILENAME);
1090 if (get_key_file_integer(client->filename, "iterations") == -1)
1091 goto done;
1093 if (!line || !*line) {
1094 guchar tmp[sizeof(shakey)];
1095 CACHE_LOCK(ctx);
1097 memset(tmp, '!', sizeof(tmp));
1099 if (cache_get_key(client->md5file, shakey) == FALSE ||
1100 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1101 CACHE_UNLOCK;
1102 #ifdef WITH_PINENTRY
1103 if (get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1104 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1105 goto done;
1108 lock_pin_mutex(client);
1109 client->pinentry->which = PINENTRY_SAVE;
1110 rc = pinentry_fork(ctx);
1112 if (rc) {
1113 unlock_pin_mutex(client->pinentry);
1114 return send_error(ctx, rc);
1117 client->pinentry->cb = save_command_finalize;
1118 client->pinentry->status = PINENTRY_INIT;
1119 return 0;
1120 #else
1121 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1122 goto done;
1123 #endif
1125 else {
1126 CACHE_UNLOCK;
1127 cached = TRUE;
1130 else {
1131 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1132 memset(line, 0, strlen(line));
1135 done:
1136 return save_command_finalize(ctx, shakey, cached);
1139 static int delete_command(assuan_context_t ctx, char *line)
1141 struct client_s *client = assuan_get_pointer(ctx);
1142 gchar **req;
1143 gpg_error_t rc;
1144 xmlNodePtr n;
1146 rc = file_modified(client);
1148 if (rc) {
1149 log_write("%s: %s", client->filename ? client->filename : "",
1150 pwmd_strerror(rc));
1151 return send_error(ctx, rc);
1154 if (strchr(line, '\t'))
1155 req = split_input_line(line, "\t", -1);
1156 else
1157 req = split_input_line(line, " ", -1);
1159 if (!req || !*req)
1160 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1162 n = find_account(client->doc, &req, &rc, NULL, 0);
1164 if (!n) {
1165 g_strfreev(req);
1166 return send_error(ctx, rc);
1170 * No sub-node defined. Remove the entire node (account).
1172 if (!req[1]) {
1173 if (n) {
1174 xmlUnlinkNode(n);
1175 xmlFreeNode(n);
1178 g_strfreev(req);
1179 return send_error(ctx, 0);
1182 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1183 g_strfreev(req);
1185 if (!n)
1186 return send_error(ctx, rc);
1188 if (n) {
1189 xmlUnlinkNode(n);
1190 xmlFreeNode(n);
1193 return send_error(ctx, 0);
1197 * Don't return with assuan_process_done() here. This has been called from
1198 * assuan_process_next() and the command should be finished in
1199 * client_thread().
1201 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1202 gsize len)
1204 assuan_context_t ctx = data;
1205 struct client_s *client = assuan_get_pointer(ctx);
1206 gchar **req;
1207 xmlNodePtr n;
1208 gpg_error_t rc = file_modified(client);
1210 if (assuan_rc || rc) {
1211 if (line)
1212 #ifndef MEM_DEBUG
1213 xfree(line);
1214 #else
1215 free(line);
1216 #endif
1217 return assuan_rc ? assuan_rc : rc;
1220 req = split_input_line((gchar *)line, "\t", 0);
1221 #ifndef MEM_DEBUG
1222 xfree(line);
1223 #else
1224 free(line);
1225 #endif
1227 if (!req || !*req)
1228 return EPWMD_COMMAND_SYNTAX;
1230 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1231 g_strfreev(req);
1232 return EPWMD_INVALID_ELEMENT;
1235 if (valid_element_path(req+1, TRUE) == FALSE) {
1236 g_strfreev(req);
1237 return EPWMD_INVALID_ELEMENT;
1240 again:
1241 n = find_account(client->doc, &req, &rc, NULL, 0);
1243 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1244 rc = new_account(client->doc, *req);
1246 if (rc) {
1247 g_strfreev(req);
1248 return rc;
1251 goto again;
1254 if (!n) {
1255 g_strfreev(req);
1256 return rc;
1259 if (req[1]) {
1260 if (!n->children)
1261 create_elements_cb(n, req+1, &rc, NULL);
1262 else
1263 find_elements(client->doc, n->children, req+1, &rc,
1264 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1267 g_strfreev(req);
1268 client->inquire_status = INQUIRE_DONE;
1269 return rc;
1272 static int store_command(assuan_context_t ctx, char *line)
1274 struct client_s *client = assuan_get_pointer(ctx);
1275 gpg_error_t rc = file_modified(client);
1277 if (rc) {
1278 log_write("%s: %s", client->filename ? client->filename : "",
1279 pwmd_strerror(rc));
1280 return send_error(ctx, rc);
1283 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1285 if (rc)
1286 return send_error(ctx, rc);
1288 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1289 client->inquire_status = INQUIRE_BUSY;
1290 return 0;
1293 static int get_command(assuan_context_t ctx, char *line)
1295 struct client_s *client = assuan_get_pointer(ctx);
1296 gchar **req;
1297 gpg_error_t rc;
1298 xmlNodePtr n;
1300 rc = file_modified(client);
1302 if (rc) {
1303 log_write("%s: %s", client->filename ? client->filename : "",
1304 pwmd_strerror(rc));
1305 return send_error(ctx, rc);
1308 req = split_input_line(line, "\t", -1);
1310 if (!req || !*req) {
1311 g_strfreev(req);
1312 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1315 n = find_account(client->doc, &req, &rc, NULL, 0);
1317 if (!n) {
1318 g_strfreev(req);
1319 return send_error(ctx, rc);
1322 if (req[1])
1323 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1325 g_strfreev(req);
1327 if (rc)
1328 return send_error(ctx, rc);
1330 if (!n || !n->children)
1331 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1333 n = find_text_node(n->children);
1335 if (!n || !n->content || !*n->content)
1336 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1338 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1339 return send_error(ctx, rc);
1342 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1343 gpg_error_t *rc, gchar **req_orig, void *data)
1345 gchar *path = *(gchar **)data;
1346 gchar *tmp = NULL, *result;
1348 if (path) {
1349 g_free(path);
1350 *(gchar **)data = NULL;
1353 path = g_strjoinv("\t", target);
1355 if (!path) {
1356 *rc = gpg_error_from_errno(ENOMEM);
1357 return NULL;
1360 if (req_orig) {
1361 tmp = g_strjoinv("\t", req_orig);
1363 if (!tmp) {
1364 g_free(path);
1365 *rc = gpg_error_from_errno(ENOMEM);
1366 return NULL;
1370 if (tmp && *tmp)
1371 result = g_strdup_printf("%s\t%s", path, tmp);
1372 else
1373 result = g_strdup(path);
1375 if (!result) {
1376 *rc = gpg_error_from_errno(ENOMEM);
1377 g_free(path);
1378 g_free(tmp);
1379 return NULL;
1382 g_free(path);
1383 g_free(tmp);
1384 *(gchar **)data = result;
1385 return node;
1388 static int realpath_command(assuan_context_t ctx, char *line)
1390 gpg_error_t rc;
1391 struct client_s *client = assuan_get_pointer(ctx);
1392 gchar **req;
1393 gchar *t;
1394 gint i;
1395 xmlNodePtr n;
1396 GString *string;
1397 gchar *rp = NULL;
1399 rc = file_modified(client);
1401 if (rc) {
1402 log_write("%s: %s", client->filename ? client->filename : "",
1403 pwmd_strerror(rc));
1404 return send_error(ctx, rc);
1407 if (strchr(line, '\t') != NULL) {
1408 if ((req = split_input_line(line, "\t", 0)) == NULL)
1409 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1411 else {
1412 if ((req = split_input_line(line, " ", 0)) == NULL)
1413 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1416 n = find_account(client->doc, &req, &rc, NULL, 0);
1418 if (!n) {
1419 g_strfreev(req);
1420 return send_error(ctx, rc);
1423 rp = g_strjoinv("\t", req);
1425 if (!rp) {
1426 g_strfreev(req);
1427 return send_syserror(ctx, ENOMEM);
1430 if (req[1]) {
1431 n = find_elements(client->doc, n->children, req+1, &rc,
1432 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1434 if (!n) {
1435 g_free(rp);
1436 g_strfreev(req);
1437 return send_error(ctx, rc);
1441 string = g_string_new(rp);
1442 g_free(rp);
1443 g_strfreev(req);
1445 if (!string)
1446 return send_syserror(ctx, ENOMEM);
1448 again:
1449 for (i = 0, t = string->str + i; *t; t++, i++) {
1450 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1451 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1452 goto again;
1456 rc = assuan_send_data(ctx, string->str, string->len);
1457 g_string_free(string, TRUE);
1458 return send_error(ctx, rc);
1461 static int list_command(assuan_context_t ctx, char *line)
1463 struct client_s *client = assuan_get_pointer(ctx);
1464 gpg_error_t rc;
1465 struct element_list_s *elements = NULL;
1466 gchar *tmp;
1468 if (disable_list_and_dump == TRUE)
1469 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1471 rc = file_modified(client);
1473 if (rc) {
1474 log_write("%s: %s", client->filename, pwmd_strerror(rc));
1475 return send_error(ctx, rc);
1478 if (!*line) {
1479 GString *str;
1481 rc = list_accounts(client->doc, &str);
1483 if (rc)
1484 return send_error(ctx, rc);
1486 rc = assuan_send_data(ctx, str->str, str->len);
1487 g_string_free(str, TRUE);
1488 return send_error(ctx, rc);
1491 elements = g_malloc0(sizeof(struct element_list_s));
1493 if (!elements) {
1494 rc = gpg_err_code_from_errno(ENOMEM);
1495 goto fail;
1498 rc = create_path_list(client->doc, elements, line);
1500 if (rc)
1501 goto fail;
1503 if (elements) {
1504 gint total = g_slist_length(elements->list);
1505 gint i;
1506 GString *str;
1508 if (!total) {
1509 rc = EPWMD_EMPTY_ELEMENT;
1510 goto fail;
1513 str = g_string_new(NULL);
1515 if (!str) {
1516 rc = gpg_err_code_from_errno(ENOMEM);
1517 goto fail;
1520 for (i = 0; i < total; i++) {
1521 tmp = g_slist_nth_data(elements->list, i);
1522 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1525 rc = assuan_send_data(ctx, str->str, str->len);
1526 g_string_free(str, TRUE);
1528 else
1529 rc = EPWMD_EMPTY_ELEMENT;
1531 fail:
1532 if (elements) {
1533 gint total = g_slist_length(elements->list);
1534 gint i;
1536 for (i = 0; i < total; i++) {
1537 tmp = g_slist_nth_data(elements->list, i);
1538 g_free(tmp);
1541 g_slist_free(elements->list);
1543 if (elements->prefix)
1544 g_free(elements->prefix);
1546 g_free(elements);
1549 return send_error(ctx, rc);
1552 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1553 const gchar *value)
1555 xmlAttrPtr a;
1557 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1558 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1560 if (!a)
1561 return EPWMD_LIBXML_ERROR;
1563 else
1564 xmlNodeSetContent(a->children, (xmlChar *)value);
1566 return 0;
1570 * req[0] - element path
1572 static int attribute_list(assuan_context_t ctx, gchar **req)
1574 struct client_s *client = assuan_get_pointer(ctx);
1575 gchar **attrlist = NULL;
1576 gint i = 0;
1577 gchar **path = NULL;
1578 xmlAttrPtr a;
1579 xmlNodePtr n, an;
1580 gchar *line;
1581 gpg_error_t rc;
1583 if (!req || !req[0])
1584 return EPWMD_COMMAND_SYNTAX;
1586 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1588 * The first argument may be only an account.
1590 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1591 return EPWMD_COMMAND_SYNTAX;
1594 n = find_account(client->doc, &path, &rc, NULL, 0);
1596 if (!n) {
1597 g_strfreev(path);
1598 return rc;
1601 if (path[1]) {
1602 n = find_elements(client->doc, n->children, path+1, &rc,
1603 NULL, NULL, NULL, FALSE, 0, NULL);
1605 if (!n) {
1606 g_strfreev(path);
1607 return rc;
1611 g_strfreev(path);
1613 for (a = n->properties; a; a = a->next) {
1614 gchar **pa;
1616 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1617 if (attrlist)
1618 g_strfreev(attrlist);
1620 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1621 return gpg_error_from_errno(ENOMEM);
1624 attrlist = pa;
1625 an = a->children;
1626 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1628 if (!attrlist[i]) {
1629 g_strfreev(attrlist);
1630 return gpg_error_from_errno(ENOMEM);
1633 attrlist[++i] = NULL;
1636 if (!attrlist)
1637 return EPWMD_EMPTY_ELEMENT;
1639 line = g_strjoinv("\n", attrlist);
1641 if (!line) {
1642 g_strfreev(attrlist);
1643 return gpg_error_from_errno(ENOMEM);
1646 rc = assuan_send_data(ctx, line, strlen(line));
1647 g_free(line);
1648 g_strfreev(attrlist);
1649 return rc;
1653 * req[0] - attribute
1654 * req[1] - element path
1656 static int attribute_delete(struct client_s *client, gchar **req)
1658 xmlAttrPtr a;
1659 xmlNodePtr n;
1660 gchar **path = NULL;
1661 gpg_error_t rc;
1663 if (!req || !req[0] || !req[1])
1664 return EPWMD_COMMAND_SYNTAX;
1666 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1668 * The first argument may be only an account.
1670 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1671 return EPWMD_COMMAND_SYNTAX;
1675 * Don't remove the "name" attribute for the account element. To remove an
1676 * account use DELETE <account>.
1678 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1679 rc = EPWMD_ATTR_SYNTAX;
1680 goto fail;
1683 n = find_account(client->doc, &path, &rc, NULL, 0);
1685 if (!n)
1686 goto fail;
1688 if (path[1]) {
1689 n = find_elements(client->doc, n->children, path+1, &rc,
1690 NULL, NULL, NULL, FALSE, 0, NULL);
1692 if (!n)
1693 goto fail;
1696 g_strfreev(path);
1698 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1699 return EPWMD_ATTR_NOT_FOUND;
1701 if (xmlRemoveProp(a) == -1)
1702 return EPWMD_LIBXML_ERROR;
1704 return 0;
1706 fail:
1707 g_strfreev(path);
1708 return rc;
1711 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1712 gpg_error_t *rc)
1714 gchar **src = *path;
1715 gchar **src_orig = g_strdupv(src);
1716 xmlNodePtr n = NULL;
1718 *rc = 0;
1720 if (!src_orig) {
1721 *rc = gpg_error_from_errno(ENOMEM);
1722 goto fail;
1725 again:
1726 n = find_account(client->doc, &src, rc, NULL, 0);
1728 if (!n) {
1729 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1730 *rc = new_account(client->doc, src[0]);
1732 if (*rc)
1733 goto fail;
1735 goto again;
1737 else
1738 goto fail;
1741 if (src[1]) {
1742 if (!n->children)
1743 n = create_target_elements_cb(n, src+1, rc, NULL);
1744 else
1745 n = find_elements(client->doc, n->children, src+1, rc,
1746 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1748 if (!n)
1749 goto fail;
1752 * Reset the position of the element tree now that the elements
1753 * have been created.
1755 g_strfreev(src);
1756 src = src_orig;
1757 src_orig = NULL;
1758 n = find_account(client->doc, &src, rc, NULL, 0);
1760 if (!n)
1761 goto fail;
1763 n = find_elements(client->doc, n->children, src+1, rc,
1764 NULL, NULL, NULL, FALSE, 0, NULL);
1766 if (!n)
1767 goto fail;
1770 fail:
1771 if (src_orig)
1772 g_strfreev(src_orig);
1774 *path = src;
1775 return n;
1779 * Creates a "target" attribute. When other commands encounter an element with
1780 * this attribute, the element path is modified to the target value. If the
1781 * source element path doesn't exist when using 'ATTR SET target', it is
1782 * created, but the destination element path must exist.
1784 * req[0] - source element path
1785 * req[1] - destination element path
1787 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1789 gchar **src, **dst, *line = NULL;
1790 gpg_error_t rc;
1791 xmlNodePtr n;
1793 if (!req || !req[0] || !req[1])
1794 return EPWMD_COMMAND_SYNTAX;
1796 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1798 * The first argument may be only an account.
1800 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1801 return EPWMD_COMMAND_SYNTAX;
1804 if (valid_element_path(src, FALSE) == FALSE) {
1805 g_strfreev(src);
1806 return EPWMD_INVALID_ELEMENT;
1809 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1811 * The first argument may be only an account.
1813 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1814 rc = EPWMD_COMMAND_SYNTAX;
1815 goto fail;
1819 n = find_account(client->doc, &dst, &rc, NULL, 0);
1822 * Make sure the destination element path exists.
1824 if (!n)
1825 goto fail;
1827 if (dst[1]) {
1828 n = find_elements(client->doc, n->children, dst+1, &rc,
1829 NULL, NULL, NULL, FALSE, 0, NULL);
1831 if (!n)
1832 goto fail;
1835 n = create_element_path(client, &src, &rc);
1837 if (rc)
1838 goto fail;
1840 line = g_strjoinv("\t", dst);
1842 if (!line) {
1843 rc = gpg_error_from_errno(ENOMEM);
1844 goto fail;
1847 rc = add_attribute(n, "target", line);
1849 fail:
1850 g_free(line);
1851 g_strfreev(src);
1852 g_strfreev(dst);
1853 return rc;
1857 * req[0] - account name
1858 * req[1] - new name
1860 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
1862 gpg_error_t rc;
1863 gchar **tmp;
1864 xmlNodePtr n;
1866 tmp = g_strdupv(req);
1868 if (!tmp)
1869 return gpg_error_from_errno(ENOMEM);
1871 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1872 g_strfreev(tmp);
1874 if (!n)
1875 return rc;
1877 if (g_utf8_collate(req[0], req[1]) == 0)
1878 return 0;
1881 * Will not overwrite an existing account.
1883 tmp = g_strdupv(req+1);
1885 if (!tmp)
1886 return gpg_error_from_errno(ENOMEM);
1888 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1889 g_strfreev(tmp);
1891 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
1892 return rc;
1894 if (n)
1895 return EPWMD_ACCOUNT_EXISTS;
1898 * Whitespace not allowed in account names.
1900 if (contains_whitespace(req[1]) == TRUE)
1901 return EPWMD_ATTR_SYNTAX;
1903 tmp = g_strdupv(req);
1905 if (!tmp)
1906 return gpg_error_from_errno(ENOMEM);
1908 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1909 g_strfreev(tmp);
1911 if (!n)
1912 return EPWMD_ELEMENT_NOT_FOUND;
1914 return add_attribute(n, "name", req[1]);
1918 * req[0] - attribute
1919 * req[1] - element path
1921 static int attribute_get(assuan_context_t ctx, gchar **req)
1923 struct client_s *client = assuan_get_pointer(ctx);
1924 xmlNodePtr n;
1925 xmlChar *a;
1926 gchar **path= NULL;
1927 gpg_error_t rc;
1929 if (!req || !req[0] || !req[1])
1930 return EPWMD_COMMAND_SYNTAX;
1932 if (strchr(req[1], '\t')) {
1933 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
1934 return EPWMD_COMMAND_SYNTAX;
1936 else {
1937 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1938 return EPWMD_COMMAND_SYNTAX;
1941 n = find_account(client->doc, &path, &rc, NULL, 0);
1943 if (!n)
1944 goto fail;
1946 if (path[1]) {
1947 n = find_elements(client->doc, n->children, path+1, &rc,
1948 NULL, NULL, NULL, FALSE, 0, NULL);
1950 if (!n)
1951 goto fail;
1954 g_strfreev(path);
1956 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
1957 return EPWMD_ATTR_NOT_FOUND;
1959 rc = assuan_send_data(ctx, a, xmlStrlen(a));
1960 xmlFree(a);
1961 return rc;
1963 fail:
1964 g_strfreev(path);
1965 return rc;
1969 * req[0] - attribute
1970 * req[1] - element path
1971 * req[2] - value
1973 static int attribute_set(struct client_s *client, gchar **req)
1975 gchar **path = NULL;
1976 gpg_error_t rc;
1977 xmlNodePtr n;
1979 if (!req || !req[0] || !req[1] || !req[2])
1980 return EPWMD_COMMAND_SYNTAX;
1983 * Reserved attribute names.
1985 if (g_utf8_collate(req[0], "name") == 0) {
1987 * Only reserved for the account element. Not the rest of the
1988 * document.
1990 if (strchr(req[1], '\t') == NULL)
1991 return name_attribute(client, req + 1);
1993 else if (g_utf8_collate(req[0], "target") == 0)
1994 return target_attribute(client, req + 1);
1996 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1998 * The first argument may be only an account.
2000 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2001 return EPWMD_COMMAND_SYNTAX;
2004 n = find_account(client->doc, &path, &rc, NULL, 0);
2006 if (!n)
2007 goto fail;
2009 if (path[1]) {
2010 n = find_elements(client->doc, n->children, path+1, &rc,
2011 NULL, NULL, NULL, FALSE, 0, NULL);
2013 if (!n)
2014 goto fail;
2017 g_strfreev(path);
2018 return add_attribute(n, req[0], req[2]);
2020 fail:
2021 g_strfreev(path);
2022 return rc;
2026 * req[0] - command
2027 * req[1] - attribute name or element path if command is LIST
2028 * req[2] - element path
2029 * req[2] - element path or value
2031 static int attr_command(assuan_context_t ctx, char *line)
2033 struct client_s *client = assuan_get_pointer(ctx);
2034 gchar **req;
2035 gpg_error_t rc = 0;
2037 rc = file_modified(client);
2039 if (rc) {
2040 log_write("%s: %s", client->filename ? client->filename : "",
2041 pwmd_strerror(rc));
2042 return send_error(ctx, rc);
2045 req = split_input_line(line, " ", 4);
2047 if (!req || !req[0] || !req[1]) {
2048 g_strfreev(req);
2049 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2052 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2053 rc = attribute_set(client, req+1);
2054 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2055 rc = attribute_get(ctx, req+1);
2056 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2057 rc = attribute_delete(client, req+1);
2058 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2059 rc = attribute_list(ctx, req+1);
2060 else
2061 rc = EPWMD_COMMAND_SYNTAX;
2063 g_strfreev(req);
2064 return send_error(ctx, rc);
2067 static int iscached_command(assuan_context_t ctx, char *line)
2069 gchar **req = split_input_line(line, " ", 0);
2070 guchar md5file[16];
2072 if (!req || !*req) {
2073 g_strfreev(req);
2074 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2077 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2078 g_strfreev(req);
2079 CACHE_LOCK(ctx);
2081 if (cache_iscached(md5file) == FALSE) {
2082 CACHE_UNLOCK;
2083 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2086 CACHE_UNLOCK;
2087 return send_error(ctx, 0);
2090 gpg_error_t send_cache_status(assuan_context_t ctx)
2092 gchar *tmp;
2093 struct client_s *client = assuan_get_pointer(ctx);
2094 gchar buf[ASSUAN_LINELENGTH];
2096 CACHE_LOCK(client->ctx);
2097 tmp = print_fmt(buf, sizeof(buf), "%i %i",
2098 cache_file_count(),
2099 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2100 CACHE_UNLOCK;
2102 return assuan_write_status(ctx, "CACHE", buf);
2105 static int clearcache_command(assuan_context_t ctx, char *line)
2107 struct client_s *client = assuan_get_pointer(ctx);
2108 gchar **req = split_input_line(line, " ", 0);
2109 guchar md5file[16];
2111 CACHE_LOCK(ctx);
2113 if (!req || !*req) {
2114 g_strfreev(req);
2115 cache_clear(client->md5file, 2);
2116 CACHE_UNLOCK;
2117 return send_error(ctx, 0);
2120 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2121 g_strfreev(req);
2123 if (cache_clear(md5file, 1) == FALSE) {
2124 CACHE_UNLOCK;
2125 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2128 CACHE_UNLOCK;
2129 return send_error(ctx, 0);
2132 static int cachetimeout_command(assuan_context_t ctx, char *line)
2134 guchar md5file[16];
2135 glong timeout;
2136 gchar **req = split_input_line(line, " ", 0);
2137 gchar *p;
2138 struct client_s *client = assuan_get_pointer(ctx);
2140 if (!req || !*req || !req[1]) {
2141 g_strfreev(req);
2142 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2145 errno = 0;
2146 timeout = strtol(req[0], &p, 10);
2148 if (errno != 0 || *p != 0) {
2149 g_strfreev(req);
2150 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2153 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2154 g_strfreev(req);
2155 CACHE_LOCK(client->ctx);
2157 if (cache_set_timeout(md5file, timeout) == FALSE) {
2158 CACHE_UNLOCK;
2159 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2162 CACHE_UNLOCK;
2163 return send_error(ctx, 0);
2166 static int dump_command(assuan_context_t ctx, char *line)
2168 xmlChar *xml;
2169 gssize len;
2170 struct client_s *client = assuan_get_pointer(ctx);
2171 gpg_error_t rc;
2173 if (disable_list_and_dump == TRUE)
2174 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2176 rc = file_modified(client);
2178 if (rc) {
2179 log_write("%s: %s", client->filename ? client->filename : "",
2180 pwmd_strerror(rc));
2181 return send_error(ctx, rc);
2184 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2186 if (!xml)
2187 return send_syserror(ctx, ENOMEM);
2189 rc = assuan_send_data(ctx, xml, len);
2190 xmlFree(xml);
2191 return send_error(ctx, rc);
2194 static int getconfig_command(assuan_context_t ctx, gchar *line)
2196 struct client_s *client = assuan_get_pointer(ctx);
2197 gpg_error_t rc = 0;
2198 gchar *p, *tmp;
2200 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2201 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2203 p = get_key_file_string(client->filename ? client->filename : "global", line);
2205 if (!p)
2206 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2208 tmp = expand_homedir(p);
2210 if (!tmp) {
2211 g_free(p);
2212 return send_syserror(ctx, ENOMEM);
2215 g_free(p);
2216 p = tmp;
2217 rc = assuan_send_data(ctx, p, strlen(p));
2218 g_free(p);
2219 return send_error(ctx, rc);
2222 static int xpath_command(assuan_context_t ctx, gchar *line)
2224 struct client_s *client = assuan_get_pointer(ctx);
2225 gpg_error_t rc;
2226 xmlXPathContextPtr xp;
2227 xmlXPathObjectPtr result;
2228 xmlBufferPtr buf = NULL;
2229 gchar **req = NULL;
2231 rc = file_modified(client);
2233 if (rc) {
2234 log_write("%s: %s", client->filename ? client->filename : "",
2235 pwmd_strerror(rc));
2236 return send_error(ctx, rc);
2239 if (!line || !*line)
2240 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2242 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2243 if (strv_printf(&req, "%s", line) == FALSE)
2244 return send_syserror(ctx, ENOMEM);
2247 xp = xmlXPathNewContext(client->doc);
2249 if (!xp)
2250 return send_error(ctx, EPWMD_LIBXML_ERROR);
2252 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2254 if (!result) {
2255 xmlXPathFreeContext(xp);
2256 return send_error(ctx, EPWMD_LIBXML_ERROR);
2259 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2260 rc = EPWMD_EMPTY_ELEMENT;
2261 goto fail;
2264 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2265 (xmlChar *)req[1], &buf);
2267 if (rc)
2268 goto fail;
2269 else if (!req[1] && !xmlBufferLength(buf)) {
2270 rc = EPWMD_EMPTY_ELEMENT;
2271 goto fail;
2273 else if (req[1])
2274 goto fail;
2276 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2278 fail:
2279 g_strfreev(req);
2281 if (buf)
2282 xmlBufferFree(buf);
2284 if (result)
2285 xmlXPathFreeObject(result);
2287 if (xp)
2288 xmlXPathFreeContext(xp);
2290 return send_error(ctx, rc);
2293 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2294 gsize len)
2296 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2297 gpg_error_t rc = file_modified(client);
2298 gchar **req, **path = NULL, **path_orig = NULL, *content;
2299 xmlDocPtr doc;
2300 xmlNodePtr n, root, copy;
2302 if (assuan_rc || rc) {
2303 if (line)
2304 #ifndef MEM_DEBUG
2305 xfree(line);
2306 #else
2307 free(line);
2308 #endif
2309 return assuan_rc ? assuan_rc : rc;
2312 req = split_input_line((gchar *)line, " ", 2);
2313 #ifndef MEM_DEBUG
2314 xfree(line);
2315 #else
2316 free(line);
2317 #endif
2319 if (!req || !*req)
2320 return EPWMD_COMMAND_SYNTAX;
2322 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2323 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2324 return EPWMD_COMMAND_SYNTAX;
2327 content = req[1];
2329 if (!content || !*content) {
2330 rc = EPWMD_COMMAND_SYNTAX;
2331 goto fail;
2334 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2335 rc = EPWMD_INVALID_ELEMENT;
2336 goto fail;
2339 if (valid_element_path(path+1, FALSE) == FALSE) {
2340 rc = EPWMD_INVALID_ELEMENT;
2341 goto fail;
2344 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2346 if (!doc) {
2347 rc = EPWMD_LIBXML_ERROR;
2348 goto fail;
2351 root = xmlDocGetRootElement(doc);
2352 path_orig = g_strdupv(path);
2354 if (!path_orig) {
2355 xmlFreeDoc(doc);
2356 rc = gpg_error_from_errno(ENOMEM);
2357 goto fail;
2360 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2361 g_strfreev(path_orig);
2362 xmlFreeDoc(doc);
2363 rc = gpg_error_from_errno(ENOMEM);
2364 goto fail;
2367 n = find_account(client->doc, &path, &rc, NULL, 0);
2369 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2370 g_strfreev(path_orig);
2371 xmlFreeDoc(doc);
2372 goto fail;
2374 else if (!rc) {
2375 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2377 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2378 g_strfreev(path_orig);
2379 xmlFreeDoc(doc);
2380 goto fail;
2382 else if (!rc) {
2383 xmlNodePtr parent = n->parent;
2385 xmlUnlinkNode(n);
2386 xmlFreeNode(n);
2387 n = parent;
2391 g_strfreev(path);
2392 path = path_orig;
2394 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2395 n = create_element_path(client, &path, &rc);
2397 if (rc) {
2398 xmlFreeDoc(doc);
2399 goto fail;
2403 copy = xmlCopyNode(root, 1);
2404 n = xmlAddChild(n, copy);
2405 xmlFreeDoc(doc);
2407 if (!n)
2408 rc = EPWMD_LIBXML_ERROR;
2410 fail:
2411 g_strfreev(path);
2412 g_strfreev(req);
2413 client->inquire_status = INQUIRE_DONE;
2414 return rc;
2417 static int import_command(assuan_context_t ctx, gchar *line)
2419 gpg_error_t rc;
2420 struct client_s *client = assuan_get_pointer(ctx);
2422 rc = file_modified(client);
2424 if (rc) {
2425 log_write("%s: %s", client->filename ? client->filename : "",
2426 pwmd_strerror(rc));
2427 return send_error(ctx, rc);
2430 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2432 if (rc)
2433 return send_error(ctx, rc);
2435 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2436 client->inquire_status = INQUIRE_BUSY;
2437 return 0;
2440 static int lock_command(assuan_context_t ctx, gchar *line)
2442 gpg_error_t rc;
2443 struct client_s *client = assuan_get_pointer(ctx);
2445 rc = file_modified(client);
2447 if (rc) {
2448 log_write("%s: %s", client->filename ? client->filename : "",
2449 pwmd_strerror(rc));
2450 return send_error(ctx, rc);
2453 rc = lock_file_mutex(client);
2455 if (!rc)
2456 client->is_lock_cmd = TRUE;
2458 return send_error(ctx, rc);
2461 static int unlock_command(assuan_context_t ctx, gchar *line)
2463 gpg_error_t rc;
2464 struct client_s *client = assuan_get_pointer(ctx);
2466 rc = file_modified(client);
2468 if (rc) {
2469 log_write("%s: %s", client->filename ? client->filename : "",
2470 pwmd_strerror(rc));
2471 return send_error(ctx, rc);
2474 unlock_file_mutex(client);
2475 return send_error(ctx, 0);
2478 void cleanup_assuan(assuan_context_t ctx)
2480 struct client_s *cl = assuan_get_pointer(ctx);
2482 if (cl)
2483 cleanup_client(cl);
2486 static void reset_notify(assuan_context_t ctx)
2488 struct client_s *cl = assuan_get_pointer(ctx);
2490 if (cl)
2491 cleanup_client(cl);
2494 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2496 gchar name[32] = {0}, value[256] = {0};
2498 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2499 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2501 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2502 pth_attr_t attr = pth_attr_of(pth_self());
2504 log_write("OPTION CLIENT %s", line);
2505 pth_attr_set(attr, PTH_ATTR_NAME, value);
2506 pth_attr_destroy(attr);
2508 else
2509 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2511 return 0;
2514 static int option_handler(assuan_context_t ctx, const gchar *name,
2515 const gchar *value)
2517 #ifdef WITH_PINENTRY
2518 struct client_s *client = assuan_get_pointer(ctx);
2519 #endif
2521 if (!value || !*value)
2522 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2524 if (g_strcasecmp(name, (gchar *)"client") == 0)
2525 return parse_client_option(ctx, value);
2527 #ifdef WITH_PINENTRY
2528 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2529 g_free(client->pinentry->ttyname);
2530 client->pinentry->ttyname = g_strdup(value);
2532 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2533 g_free(client->pinentry->ttytype);
2534 client->pinentry->ttytype = g_strdup(value);
2536 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2537 g_free(client->pinentry->display);
2538 client->pinentry->display = g_strdup(value);
2540 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2541 g_free(client->pinentry->path);
2542 client->pinentry->path = g_strdup(value);
2544 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2545 g_free(client->pinentry->title);
2546 client->pinentry->title = g_strdup(value);
2548 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2549 g_free(client->pinentry->prompt);
2550 client->pinentry->prompt = g_strdup(value);
2552 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2553 g_free(client->pinentry->desc);
2554 client->pinentry->desc = g_strdup(value);
2556 #if 0
2557 /* Need to wait for pinentry to support a --timeout option so it can
2558 * terminate itself. Cannot do it here because assuan_pipe_connect() calls
2559 * execv() which replaces the pid of the fork()ed thread from
2560 * pinentry_fork(). So pinentry will become a real process after the
2561 * thread terminates and won't be able to be kill()ed from pwmd.
2563 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2564 gchar *p = NULL;
2565 gint n = strtol(value, &p, 10);
2567 if (*p || n < 0)
2568 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2570 client->pinentry->timeout = n;
2572 #endif
2573 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2574 gchar *p = NULL;
2575 gint n = strtol(value, &p, 10);
2577 if (*p || n < 0 || n > 1)
2578 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2580 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2582 else
2583 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2584 #else
2585 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
2586 #endif
2588 log_write("OPTION %s=%s", name, value);
2589 return 0;
2592 gpg_error_t register_commands(assuan_context_t ctx)
2594 static struct {
2595 const gchar *name;
2596 gint (*handler)(assuan_context_t, gchar *line);
2597 } table[] = {
2598 { "OPEN", open_command },
2599 { "SAVE", save_command },
2600 { "LIST", list_command },
2601 { "REALPATH", realpath_command },
2602 { "STORE", store_command },
2603 { "DELETE", delete_command },
2604 { "GET", get_command },
2605 { "ATTR", attr_command },
2606 { "ISCACHED", iscached_command },
2607 { "CLEARCACHE", clearcache_command },
2608 { "CACHETIMEOUT", cachetimeout_command },
2609 { "GETCONFIG", getconfig_command },
2610 { "DUMP", dump_command },
2611 { "XPATH", xpath_command },
2612 { "IMPORT", import_command },
2613 { "LOCK", lock_command },
2614 { "UNLOCK", unlock_command },
2615 { "INPUT", NULL },
2616 { "OUTPUT", NULL },
2617 { NULL, NULL }
2619 gint i, rc;
2621 for (i=0; table[i].name; i++) {
2622 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2624 if (rc)
2625 return rc;
2628 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2630 if (rc)
2631 return rc;
2633 rc = assuan_register_option_handler(ctx, option_handler);
2635 if (rc)
2636 return rc;
2638 return assuan_register_reset_notify(ctx, reset_notify);
2641 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2642 guchar *key)
2644 guchar *iv;
2645 void *inbuf;
2646 gsize insize, len;
2647 guchar tkey[gcrykeysize];
2648 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2649 gcry_cipher_hd_t gh;
2650 guint iter = 0, n_iter = 0;
2651 gint iter_progress;
2652 void *outbuf = NULL;
2653 gint zrc = 0;
2654 glong outsize = 0;
2655 gpg_error_t rc;
2656 file_header_t file_header;
2657 gchar str[ASSUAN_LINELENGTH];
2659 if (!ctx) {
2660 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2662 if (rc)
2663 return rc;
2665 else
2666 gh = client->gh;
2668 lseek(fd, 0, SEEK_SET);
2669 insize = st.st_size - sizeof(file_header_t);
2670 iv = gcry_malloc(gcryblocksize);
2672 if (!iv) {
2673 if (!ctx)
2674 gcry_cipher_close(gh);
2676 return gpg_error_from_errno(ENOMEM);
2679 len = pth_read(fd, &file_header, sizeof(file_header_t));
2681 if (len != sizeof(file_header_t)) {
2682 len = errno;
2684 if (!ctx)
2685 gcry_cipher_close(gh);
2687 gcry_free(iv);
2688 errno = len;
2689 return gpg_error_from_errno(errno);
2692 /* No encryption iterations. This is a plain (gzipped) file. */
2693 if (file_header.iter == -1) {
2695 * cache_file_count() needs both .used == TRUE and a valid key in
2696 * order for it to count as a used cache entry. Fixes CACHE status
2697 * messages.
2699 memset(key, '!', gcrykeysize);
2700 insize = st.st_size - sizeof(file_header_t);
2703 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2704 inbuf = gcry_malloc(insize);
2706 if (!inbuf) {
2707 if (!ctx)
2708 gcry_cipher_close(gh);
2710 gcry_free(iv);
2711 return gpg_error_from_errno(ENOMEM);
2714 len = pth_read(fd, inbuf, insize);
2716 if (len != insize) {
2717 len = errno;
2719 if (!ctx)
2720 gcry_cipher_close(gh);
2722 gcry_free(iv);
2723 errno = len;
2724 return gpg_error_from_errno(errno);
2727 if (file_header.iter == -1)
2728 goto decompress;
2730 memcpy(tkey, key, sizeof(tkey));
2731 tkey[0] ^= 1;
2733 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2734 if (!ctx) {
2735 gcry_cipher_close(gh);
2736 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2738 else
2739 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2741 gcry_free(inbuf);
2742 gcry_free(iv);
2743 return rc;
2746 if ((rc = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2747 if (!ctx) {
2748 gcry_cipher_close(gh);
2749 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2751 else
2752 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2754 gcry_free(inbuf);
2755 gcry_free(iv);
2757 if (!ctx)
2758 gcry_cipher_close(gh);
2760 return rc;
2763 iter_progress = get_key_file_integer("global", "iteration_progress");
2765 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2766 rc = assuan_write_status(client->ctx, "DECRYPT", "0");
2768 if (rc) {
2769 gcry_free(inbuf);
2770 gcry_free(iv);
2771 return rc;
2775 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2777 if (rc) {
2778 gcry_free(inbuf);
2779 gcry_free(iv);
2780 return rc;
2783 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2784 if (!ctx) {
2785 gcry_cipher_close(gh);
2786 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2788 else
2789 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2791 gcry_free(inbuf);
2792 gcry_free(iv);
2793 return rc;
2796 while (iter < file_header.iter) {
2797 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2798 if (!(iter % iter_progress)) {
2799 rc = assuan_write_status(ctx, "DECRYPT",
2800 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
2802 if (rc) {
2803 gcry_free(inbuf);
2804 gcry_free(iv);
2805 return rc;
2810 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2811 if (!ctx) {
2812 gcry_cipher_close(gh);
2813 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2815 else
2816 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2818 gcry_free(inbuf);
2819 gcry_free(iv);
2820 return rc;
2823 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2825 if (rc) {
2826 if (!ctx) {
2827 gcry_cipher_close(gh);
2828 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2830 else
2831 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2833 gcry_free(inbuf);
2834 gcry_free(iv);
2835 return rc;
2838 iter++;
2839 pth_yield(NULL);
2842 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2843 rc = assuan_write_status(ctx, "DECRYPT",
2844 print_fmt(str, sizeof(str), "%i", file_header.iter));
2846 if (rc) {
2847 gcry_free(inbuf);
2848 gcry_free(iv);
2849 return rc;
2853 gcry_free(iv);
2855 decompress:
2856 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zrc) == FALSE) {
2858 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2860 if (zrc == Z_MEM_ERROR) {
2861 gcry_free(inbuf);
2862 return gpg_error_from_errno(ENOMEM);
2864 else if (zrc != Z_DATA_ERROR) {
2865 gcry_free(inbuf);
2867 if (!ctx)
2868 gcry_cipher_close(gh);
2870 return EPWMD_BADKEY;
2873 else {
2874 gcry_free(inbuf);
2875 inbuf = outbuf;
2876 insize = outsize;
2879 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2880 gcry_free(inbuf);
2882 if (!ctx)
2883 gcry_cipher_close(gh);
2885 return EPWMD_BADKEY;
2888 if (ctx) {
2889 client->xml = inbuf;
2890 client->len = insize;
2892 else {
2893 gcry_cipher_close(gh);
2894 gcry_free(inbuf);
2897 return 0;
2901 * This is called after every Assuan command.
2903 void command_finalize(assuan_context_t ctx, gint rc)
2905 struct client_s *client = assuan_get_pointer(ctx);
2907 if (!client->is_lock_cmd)
2908 unlock_file_mutex(client);