Zero out the contents of the temporary key with the OPEN and SAVE
[pwmd.git] / src / commands.c
blobf410083c17f1e7386bc5c5098211fca619a9a42b
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) {
170 * If a client disconnects unexpectedly while waiting for a
171 * lock, this lets the thread terminate because send_status()
172 * will return an error. We can't use an PTH_EVENT_FUNC here
173 * because the thread that would call the callback uses it's
174 * own stack space which messes up access to the client data
175 * (if I understand it correctly).
177 while (pth_mutex_acquire(m, TRUE, NULL) == FALSE) {
178 gpg_error_t rc = send_status(client->ctx, STATUS_LOCKED);
180 if (rc)
181 return rc;
183 pth_usleep(100000);
186 else
187 pth_mutex_acquire(m, FALSE, NULL);
189 else {
190 gint e = errno;
191 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(errno));
192 return gpg_error_from_errno(e);
196 client->has_lock = TRUE;
197 return 0;
200 void free_client(struct client_s *client)
202 if (client->doc)
203 xmlFreeDoc(client->doc);
205 if (client->xml)
206 gcry_free(client->xml);
208 if (client->filename)
209 g_free(client->filename);
211 if (client->gh)
212 gcry_cipher_close(client->gh);
215 void cleanup_client(struct client_s *client)
217 assuan_context_t ctx = client->ctx;
218 #ifdef WITH_PINENTRY
219 struct pinentry_s *pin = client->pinentry;
220 #endif
222 unlock_file_mutex(client);
223 CACHE_LOCK(client->ctx);
224 cache_decr_refcount(client->md5file);
227 * This may be a new file so don't use a cache slot. save_command() will
228 * set this to FALSE on success.
230 if (client->new == TRUE)
231 cache_clear(client->md5file, 1);
233 free_client(client);
234 memset(client, 0, sizeof(struct client_s));
235 client->state = STATE_CONNECTED;
236 client->ctx = ctx;
237 client->freed = TRUE;
238 #ifdef WITH_PINENTRY
239 client->pinentry = pin;
240 #endif
241 CACHE_UNLOCK;
244 gboolean do_decompress(assuan_context_t ctx, gpointer in, gint insize,
245 gpointer *out, glong *outsize, gint *rc)
247 z_stream z;
248 gpointer pout;
249 gz_header h;
250 gchar buf[17];
251 gchar str[ASSUAN_LINELENGTH];
253 z.zalloc = z_alloc;
254 z.zfree = z_free;
255 z.next_in = in;
256 z.avail_in = insize;
257 z.avail_out = zlib_bufsize;
258 z.next_out = pout = g_malloc(zlib_bufsize);
260 if (!pout) {
261 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
262 *rc = Z_MEM_ERROR;
263 return FALSE;
266 *rc = inflateInit2(&z, 47);
268 if (*rc != Z_OK) {
269 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
270 g_free(pout);
271 return FALSE;
274 memset(&h, 0, sizeof(gz_header));
275 h.comment = (guchar *)buf;
276 h.comm_max = sizeof(buf);
277 *rc = inflateGetHeader(&z, &h);
279 if (*rc != Z_OK) {
280 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
281 g_free(pout);
282 inflateEnd(&z);
283 return FALSE;
286 *rc = inflate(&z, Z_BLOCK);
288 if (*rc != Z_OK) {
289 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
290 g_free(pout);
291 inflateEnd(&z);
292 return FALSE;
295 if (h.comment)
296 insize = atoi((gchar *)h.comment);
298 do {
299 gpointer p;
301 *rc = inflate(&z, Z_FINISH);
303 switch (*rc) {
304 case Z_OK:
305 break;
306 case Z_BUF_ERROR:
307 if (!z.avail_out) {
308 p = g_realloc(pout, z.total_out + zlib_bufsize);
310 if (!p) {
311 *rc = Z_MEM_ERROR;
312 goto fail;
315 pout = p;
316 z.next_out = pout + z.total_out;
317 z.avail_out = zlib_bufsize;
319 if (ctx) {
320 *rc = assuan_write_status(ctx, "DECOMPRESS",
321 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
323 if (*rc)
324 goto fail;
327 break;
328 case Z_STREAM_END:
329 break;
330 default:
331 goto fail;
332 break;
335 pth_yield(NULL);
336 } while (*rc != Z_STREAM_END);
338 if (ctx) {
339 *rc = assuan_write_status(ctx, "DECOMPRESS",
340 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
342 if (*rc)
343 goto fail;
346 *out = pout;
347 *outsize = z.total_out;
348 inflateEnd(&z);
349 *rc = 0;
350 return TRUE;
352 fail:
353 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
354 g_free(pout);
355 inflateEnd(&z);
356 return FALSE;
359 gpg_error_t read_file_header(const gchar *filename, file_header_t *fh)
361 gint fd;
362 gsize len;
364 fd = open(filename, O_RDONLY);
366 if (fd == -1)
367 return gpg_error_from_errno(errno);
369 len = pth_read(fd, fh, sizeof(file_header_t));
370 close(fd);
372 if (len != sizeof(file_header_t))
373 return gpg_error_from_errno(errno);
375 return 0;
378 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar shakey[],
379 gboolean cached)
381 struct client_s *client = assuan_get_pointer(ctx);
382 gpg_error_t rc;
383 struct stat st;
384 gint fd;
385 gint timeout;
387 if ((fd = open_file(client->filename, &st)) == -1) {
388 /* New file. */
389 if (errno == ENOENT) {
390 if (shakey[0])
391 goto update_cache;
393 goto done;
396 rc = errno;
397 log_write("%s: %s", client->filename, strerror(errno));
398 cleanup_client(client);
399 memset(shakey, 0, sizeof(shakey));
400 return send_syserror(ctx, rc);
403 rc = try_xml_decrypt(ctx, fd, st, shakey);
404 close(fd);
406 if (rc) {
407 memset(shakey, 0, sizeof(shakey));
408 cleanup_client(client);
409 return send_error(ctx, rc);
412 update_cache:
413 CACHE_LOCK(client->ctx);
415 if (cached == FALSE) {
416 if (cache_update_key(client->md5file, shakey) == FALSE) {
417 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
418 cleanup_client(client);
419 CACHE_UNLOCK;
420 return send_error(ctx, EPWMD_MAX_SLOTS);
423 timeout = get_key_file_integer(client->filename, "cache_timeout");
424 cache_reset_timeout(client->md5file, timeout);
426 else
427 cache_set_timeout(client->md5file, -2);
429 CACHE_UNLOCK;
431 done:
432 memset(shakey, 0, sizeof(shakey));
433 rc = parse_xml(ctx);
435 if (client->xml) {
436 gcry_free(client->xml);
437 client->xml = NULL;
440 if (!rc) {
441 if (client->new == FALSE)
442 send_status_all(STATUS_CACHE);
444 client->state = STATE_OPEN;
447 return send_error(ctx, rc);
450 static int open_command(assuan_context_t ctx, char *line)
452 struct stat st;
453 guchar shakey[gcrykeysize];
454 gboolean cached = FALSE;
455 gpg_error_t rc;
456 struct client_s *client = assuan_get_pointer(ctx);
457 gchar **req;
458 gchar *filename = NULL;
459 file_header_t file_header;
461 memset(shakey, 0, sizeof(shakey));
463 if ((req = split_input_line(line, " ", 2)) != NULL)
464 filename = req[0];
466 if (!filename || !*filename) {
467 g_strfreev(req);
468 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
471 if (valid_filename(filename) == FALSE) {
472 g_strfreev(req);
473 return send_error(ctx, EPWMD_INVALID_FILENAME);
476 if (client->state == STATE_OPEN)
477 cleanup_client(client);
479 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
480 CACHE_LOCK(client->ctx);
482 if (cache_has_file(client->md5file) == FALSE) {
483 if (cache_add_file(client->md5file, NULL) == FALSE) {
484 g_strfreev(req);
485 CACHE_UNLOCK;
486 return send_error(ctx, EPWMD_MAX_SLOTS);
490 cache_incr_refcount(client->md5file);
491 CACHE_UNLOCK;
492 rc = lock_file_mutex(client);
494 if (rc) {
495 g_strfreev(req);
496 return send_error(ctx, rc);
499 client->freed = FALSE;
501 if ((rc = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
502 g_strfreev(req);
503 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
504 cleanup_client(client);
505 return send_error(ctx, rc);
508 if (stat(filename, &st) == 0) {
509 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
510 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
511 g_strfreev(req);
512 cleanup_client(client);
513 return send_error(ctx, EPWMD_INVALID_FILENAME);
516 client->mtime = st.st_mtime;
519 client->filename = g_strdup(filename);
521 if (!client->filename) {
522 memset(shakey, 0, sizeof(shakey));
523 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
524 cleanup_client(client);
525 g_strfreev(req);
526 return send_syserror(ctx, ENOMEM);
529 #ifdef WITH_PINENTRY
530 client->pinentry->filename = g_strdup(client->filename);
532 if (!client->pinentry->filename) {
533 memset(shakey, 0, sizeof(shakey));
534 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
535 cleanup_client(client);
536 g_strfreev(req);
537 return send_syserror(ctx, ENOMEM);
539 #endif
542 * New files don't need a key.
544 if (access(filename, R_OK) != 0) {
545 if (errno != ENOENT) {
546 rc = errno;
547 log_write("%s: %s", filename, strerror(errno));
548 g_strfreev(req);
549 cleanup_client(client);
550 return send_syserror(ctx, rc);
553 if ((client->xml = new_document()) == NULL) {
554 log_write("%s", strerror(ENOMEM));
555 g_strfreev(req);
556 cleanup_client(client);
557 return send_syserror(ctx, ENOMEM);
560 client->len = xmlStrlen(client->xml);
561 client->new = TRUE;
562 client->filename = g_strdup(filename);
564 if (!client->filename) {
565 g_strfreev(req);
566 cleanup_client(client);
567 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
568 return send_syserror(ctx, ENOMEM);
571 memset(shakey, 0, sizeof(shakey));
573 if (req[1] && *req[1])
574 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
576 g_strfreev(req);
577 return open_command_finalize(ctx, shakey, cached);
580 rc = read_file_header(filename, &file_header);
582 if (rc) {
583 g_strfreev(req);
584 cleanup_client(client);
585 return send_error(ctx, rc);
588 if (file_header.iter == -1)
589 goto done;
591 CACHE_LOCK(client->ctx);
592 cached = cache_get_key(client->md5file, shakey);
593 CACHE_UNLOCK;
595 if (cached == FALSE) {
597 * No key specified and no matching filename found in the cache. Use
598 * pinentry to retrieve the key. Cannot return assuan_process_done()
599 * here otherwise the command will be interrupted. The event loop in
600 * client_thread() will poll the file descriptor waiting for it to
601 * become ready to read a pinentry_key_s which will contain the
602 * entered key or rc. It will then call open_command_finalize() to
603 * to finish the command.
605 if (!req[1] || !*req[1]) {
606 #ifdef WITH_PINENTRY
607 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
609 /* From set_pinentry_defaults(). */
610 if (client->pinentry->enable == FALSE ||
611 (client->pinentry->enable == -1 && b == FALSE)) {
612 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
613 goto done;
616 g_strfreev(req);
617 lock_pin_mutex(client);
618 client->pinentry->which = PINENTRY_OPEN;
619 rc = pinentry_fork(ctx);
621 if (rc) {
622 unlock_pin_mutex(client->pinentry);
623 cleanup_client(client);
624 return send_error(ctx, rc);
627 client->pinentry->cb = open_command_finalize;
628 client->pinentry->status = PINENTRY_INIT;
629 return 0;
630 #else
631 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
632 goto done;
633 #endif
636 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
639 done:
640 g_strfreev(req);
641 return open_command_finalize(ctx, shakey, cached);
644 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
645 gint size, gpointer *out, glong *outsize, gint *rc)
647 z_stream z;
648 gpointer pout, pin;
649 gz_header h;
650 gchar buf[17];
651 gint cmd = Z_NO_FLUSH;
652 gchar str[ASSUAN_LINELENGTH];
654 z.zalloc = z_alloc;
655 z.zfree = z_free;
656 z.next_in = pin = data;
657 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
658 z.avail_out = zlib_bufsize;
659 z.next_out = pout = g_malloc(zlib_bufsize);
661 if (!pout) {
662 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
663 *rc = Z_MEM_ERROR;
664 return FALSE;
667 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
669 if (*rc != Z_OK) {
670 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
671 g_free(pout);
672 return FALSE;
675 memset(&h, 0, sizeof(gz_header));
676 g_snprintf(buf, sizeof(buf), "%i", size);
677 h.comment = (guchar *)buf;
678 *rc = deflateSetHeader(&z, &h);
680 if (*rc != Z_OK) {
681 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
682 g_free(pout);
683 deflateEnd(&z);
684 return FALSE;
687 do {
688 gpointer p;
690 *rc = deflate(&z, cmd);
692 switch (*rc) {
693 case Z_OK:
694 break;
695 case Z_BUF_ERROR:
696 if (!z.avail_out) {
697 p = g_realloc(pout, z.total_out + zlib_bufsize);
699 if (!p) {
700 *rc = Z_MEM_ERROR;
701 goto fail;
704 pout = p;
705 z.next_out = pout + z.total_out;
706 z.avail_out = zlib_bufsize;
709 if (!z.avail_in && z.total_in < size) {
710 if (z.total_in + zlib_bufsize > size)
711 z.avail_in = size - z.total_in;
712 else
713 z.avail_in = zlib_bufsize;
715 if (ctx) {
716 *rc = assuan_write_status(ctx, "COMPRESS",
717 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
719 if (*rc)
720 goto fail;
724 if (z.total_in >= size)
725 cmd = Z_FINISH;
727 break;
728 case Z_STREAM_END:
729 break;
730 default:
731 goto fail;
734 pth_yield(NULL);
735 } while (*rc != Z_STREAM_END);
737 if (ctx) {
738 *rc = assuan_write_status(ctx, "COMPRESS",
739 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
741 if (*rc)
742 goto fail;
745 *out = pout;
746 *outsize = z.total_out;
747 deflateEnd(&z);
748 *rc = 0;
749 return TRUE;
751 fail:
752 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
753 g_free(pout);
754 deflateEnd(&z);
755 return FALSE;
758 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
759 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
760 gint iter)
762 gsize len = insize;
763 gint fd;
764 gpointer inbuf;
765 guchar tkey[gcrykeysize];
766 gchar *p;
767 gpg_error_t rc;
768 guint iter_progress = 0, n_iter = 0, xiter = 0;
769 gchar tmp[FILENAME_MAX];
770 struct stat st;
771 mode_t mode = 0;
772 file_header_t file_header;
773 gchar str[ASSUAN_LINELENGTH];
775 if (iter == -1) {
777 * cache_file_count() needs both .used == TRUE and a valid key in
778 * order for it to count as a used cache entry. Fixes CACHE status
779 * messages.
781 memset(shakey, '!', gcrykeysize);
782 inbuf = data;
783 file_header.iter = iter;
784 goto write_file;
787 if (insize / gcryblocksize) {
788 len = (insize / gcryblocksize) * gcryblocksize;
790 if (insize % gcryblocksize)
791 len += gcryblocksize;
795 * Resize the existing xml buffer to the block size required by gcrypt
796 * rather than duplicating it and wasting memory.
798 inbuf = gcry_realloc(data, len);
800 if (!inbuf)
801 return gpg_error_from_errno(ENOMEM);
803 insize = len;
804 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
805 memcpy(tkey, shakey, sizeof(tkey));
806 tkey[0] ^= 1;
808 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
809 memset(tkey, 0, sizeof(tkey));
810 gcry_free(inbuf);
811 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
812 return rc;
815 memset(tkey, 0, sizeof(tkey));
816 file_header.iter = iter;
818 if (client)
819 iter_progress = get_key_file_integer(client->filename, "iteration_progress");
821 if (client && iter_progress && file_header.iter >= iter_progress) {
822 rc = assuan_write_status(client->ctx, "ENCRYPT", "0");
824 if (rc) {
825 gcry_free(inbuf);
826 return rc;
830 while (xiter < file_header.iter) {
831 if (client && iter_progress > 0 && xiter >= iter_progress) {
832 if (!(xiter % iter_progress)) {
833 rc = assuan_write_status(client->ctx, "ENCRYPT",
834 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
836 if (rc) {
837 gcry_free(inbuf);
838 return rc;
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 (encrypt_xml(gh, inbuf, insize, NULL, 0)
851 == FALSE) {
852 gcry_free(inbuf);
853 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
854 return rc;
857 xiter++;
858 pth_yield(NULL);
861 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
862 sizeof(file_header.iv)))) {
863 gcry_free(inbuf);
864 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
865 return rc;
868 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
869 gcry_free(inbuf);
870 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
871 return rc;
874 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
875 gcry_free(inbuf);
876 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
877 return rc;
880 if (client && iter_progress && file_header.iter >= iter_progress) {
881 rc = assuan_write_status(client->ctx, "ENCRYPT",
882 print_fmt(str, sizeof(str), "%i", file_header.iter));
884 if (rc) {
885 gcry_free(inbuf);
886 return rc;
890 write_file:
891 if (filename) {
892 if (stat(filename, &st) == 0) {
893 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
896 * FIXME What if the file has an ACL?
898 if (!(mode & S_IWUSR)) {
899 gcry_free(inbuf);
900 return gpg_error_from_errno(EACCES);
903 else {
904 if (errno != ENOENT) {
905 rc = errno;
906 gcry_free(inbuf);
907 return gpg_error_from_errno(rc);
911 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
913 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
914 rc = errno;
915 gcry_free(inbuf);
916 p = strrchr(tmp, '/');
917 p++;
918 log_write("%s: %s", p, strerror(rc));
919 return gpg_error_from_errno(rc);
922 else
924 * xml_import() from command line.
926 fd = STDOUT_FILENO;
928 len = pth_write(fd, &file_header, sizeof(file_header_t));
930 if (len != sizeof(file_header)) {
931 len = errno;
933 if (filename) {
934 close(fd);
935 unlink(tmp);
938 gcry_free(inbuf);
939 return gpg_error_from_errno(len);
942 len = pth_write(fd, inbuf, insize);
944 if (len != insize) {
945 len = errno;
947 if (filename) {
948 close(fd);
949 unlink(tmp);
952 gcry_free(inbuf);
953 return gpg_error_from_errno(len);
956 if (fsync(fd) == -1) {
957 len = errno;
959 if (filename) {
960 close(fd);
961 unlink(tmp);
964 gcry_free(inbuf);
965 return gpg_error_from_errno(len);
968 if (filename) {
969 close(fd);
971 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
972 gchar tmp2[FILENAME_MAX];
974 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
976 if (rename(filename, tmp2) == -1) {
977 unlink(tmp);
978 len = errno;
979 gcry_free(inbuf);
980 return gpg_error_from_errno(len);
984 if (rename(tmp, filename) == -1) {
985 len = errno;
986 unlink(tmp);
987 gcry_free(inbuf);
988 return gpg_error_from_errno(len);
991 if (mode)
992 chmod(filename, mode);
995 gcry_free(inbuf);
996 return 0;
999 static gpg_error_t save_command_finalize(assuan_context_t ctx,
1000 guchar shakey[], gboolean cached)
1002 struct client_s *client = assuan_get_pointer(ctx);
1003 gpointer xmlbuf;
1004 xmlChar *p;
1005 gint len;
1006 gint iter;
1007 gint timeout;
1008 gpointer outbuf;
1009 glong outsize = 0;
1010 gint zrc;
1011 gpg_error_t rc;
1012 struct stat st;
1014 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
1015 xmlbuf = p;
1017 iter = get_key_file_integer(client->filename, "compression_level");
1019 if (iter < 0)
1020 iter = 0;
1022 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
1023 memset(shakey, 0, sizeof(shakey));
1024 xmlFree(xmlbuf);
1026 if (zrc == Z_MEM_ERROR) {
1027 return send_syserror(ctx, ENOMEM);
1029 else
1030 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1032 else {
1033 gcry_free(xmlbuf);
1034 xmlbuf = outbuf;
1035 len = outsize;
1038 iter = get_key_file_integer(client->filename, "iterations");
1039 rc = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1041 if (rc) {
1042 memset(shakey, 0, sizeof(shakey));
1043 return send_error(ctx, rc);
1046 stat(client->filename, &st);
1047 client->mtime = st.st_mtime;
1048 timeout = get_key_file_integer(client->filename, "cache_timeout");
1049 CACHE_LOCK(client->ctx);
1051 if (cached) {
1052 memset(shakey, 0, sizeof(shakey));
1053 cache_reset_timeout(client->md5file, timeout);
1054 CACHE_UNLOCK;
1056 if (client->new == TRUE)
1057 send_status_all(STATUS_CACHE);
1059 client->new = FALSE;
1060 return send_error(ctx, 0);
1063 if (cache_update_key(client->md5file, shakey) == FALSE) {
1064 memset(shakey, 0, sizeof(shakey));
1065 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1066 CACHE_UNLOCK;
1067 return send_error(ctx, EPWMD_MAX_SLOTS);
1070 client->new = FALSE;
1071 memset(shakey, 0, sizeof(shakey));
1072 cache_reset_timeout(client->md5file, timeout);
1073 CACHE_UNLOCK;
1074 send_status_all(STATUS_CACHE);
1075 return send_error(ctx, 0);
1078 static int save_command(assuan_context_t ctx, char *line)
1080 gboolean cached = FALSE;
1081 guchar shakey[gcrykeysize];
1082 struct stat st;
1083 struct client_s *client = assuan_get_pointer(ctx);
1084 gpg_error_t rc;
1086 memset(shakey, 0, sizeof(shakey));
1087 rc = file_modified(client);
1089 if (rc) {
1090 log_write("%s: %s", client->filename ? client->filename : "",
1091 pwmd_strerror(rc));
1092 return send_error(ctx, rc);
1095 rc = lock_file_mutex(client);
1097 if (rc)
1098 return send_error(ctx, rc);
1100 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1101 return send_syserror(ctx, errno);
1103 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1104 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1105 return send_error(ctx, EPWMD_INVALID_FILENAME);
1108 if (get_key_file_integer(client->filename, "iterations") == -1)
1109 goto done;
1111 if (!line || !*line) {
1112 guchar tmp[sizeof(shakey)];
1113 CACHE_LOCK(ctx);
1115 memset(tmp, '!', sizeof(tmp));
1117 if (cache_get_key(client->md5file, shakey) == FALSE ||
1118 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1119 CACHE_UNLOCK;
1120 #ifdef WITH_PINENTRY
1121 if (get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1122 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1123 goto done;
1126 lock_pin_mutex(client);
1127 client->pinentry->which = PINENTRY_SAVE;
1128 rc = pinentry_fork(ctx);
1130 if (rc) {
1131 unlock_pin_mutex(client->pinentry);
1132 return send_error(ctx, rc);
1135 client->pinentry->cb = save_command_finalize;
1136 client->pinentry->status = PINENTRY_INIT;
1137 return 0;
1138 #else
1139 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1140 goto done;
1141 #endif
1143 else {
1144 CACHE_UNLOCK;
1145 cached = TRUE;
1148 else {
1149 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1150 memset(line, 0, strlen(line));
1153 done:
1154 return save_command_finalize(ctx, shakey, cached);
1157 static int delete_command(assuan_context_t ctx, char *line)
1159 struct client_s *client = assuan_get_pointer(ctx);
1160 gchar **req;
1161 gpg_error_t rc;
1162 xmlNodePtr n;
1164 rc = file_modified(client);
1166 if (rc) {
1167 log_write("%s: %s", client->filename ? client->filename : "",
1168 pwmd_strerror(rc));
1169 return send_error(ctx, rc);
1172 if (strchr(line, '\t'))
1173 req = split_input_line(line, "\t", -1);
1174 else
1175 req = split_input_line(line, " ", -1);
1177 if (!req || !*req)
1178 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1180 n = find_account(client->doc, &req, &rc, NULL, 0);
1182 if (!n) {
1183 g_strfreev(req);
1184 return send_error(ctx, rc);
1188 * No sub-node defined. Remove the entire node (account).
1190 if (!req[1]) {
1191 if (n) {
1192 xmlUnlinkNode(n);
1193 xmlFreeNode(n);
1196 g_strfreev(req);
1197 return send_error(ctx, 0);
1200 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1201 g_strfreev(req);
1203 if (!n)
1204 return send_error(ctx, rc);
1206 if (n) {
1207 xmlUnlinkNode(n);
1208 xmlFreeNode(n);
1211 return send_error(ctx, 0);
1215 * Don't return with assuan_process_done() here. This has been called from
1216 * assuan_process_next() and the command should be finished in
1217 * client_thread().
1219 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1220 gsize len)
1222 assuan_context_t ctx = data;
1223 struct client_s *client = assuan_get_pointer(ctx);
1224 gchar **req;
1225 xmlNodePtr n;
1226 gpg_error_t rc = file_modified(client);
1228 if (assuan_rc || rc) {
1229 if (line)
1230 #ifndef MEM_DEBUG
1231 xfree(line);
1232 #else
1233 free(line);
1234 #endif
1235 return assuan_rc ? assuan_rc : rc;
1238 req = split_input_line((gchar *)line, "\t", 0);
1239 #ifndef MEM_DEBUG
1240 xfree(line);
1241 #else
1242 free(line);
1243 #endif
1245 if (!req || !*req)
1246 return EPWMD_COMMAND_SYNTAX;
1248 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1249 g_strfreev(req);
1250 return EPWMD_INVALID_ELEMENT;
1253 if (valid_element_path(req+1, TRUE) == FALSE) {
1254 g_strfreev(req);
1255 return EPWMD_INVALID_ELEMENT;
1258 again:
1259 n = find_account(client->doc, &req, &rc, NULL, 0);
1261 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1262 rc = new_account(client->doc, *req);
1264 if (rc) {
1265 g_strfreev(req);
1266 return rc;
1269 goto again;
1272 if (!n) {
1273 g_strfreev(req);
1274 return rc;
1277 if (req[1]) {
1278 if (!n->children)
1279 create_elements_cb(n, req+1, &rc, NULL);
1280 else
1281 find_elements(client->doc, n->children, req+1, &rc,
1282 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1285 g_strfreev(req);
1286 client->inquire_status = INQUIRE_DONE;
1287 return rc;
1290 static int store_command(assuan_context_t ctx, char *line)
1292 struct client_s *client = assuan_get_pointer(ctx);
1293 gpg_error_t rc = file_modified(client);
1295 if (rc) {
1296 log_write("%s: %s", client->filename ? client->filename : "",
1297 pwmd_strerror(rc));
1298 return send_error(ctx, rc);
1301 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1303 if (rc)
1304 return send_error(ctx, rc);
1306 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1307 client->inquire_status = INQUIRE_BUSY;
1308 return 0;
1311 static int get_command(assuan_context_t ctx, char *line)
1313 struct client_s *client = assuan_get_pointer(ctx);
1314 gchar **req;
1315 gpg_error_t rc;
1316 xmlNodePtr n;
1318 rc = file_modified(client);
1320 if (rc) {
1321 log_write("%s: %s", client->filename ? client->filename : "",
1322 pwmd_strerror(rc));
1323 return send_error(ctx, rc);
1326 req = split_input_line(line, "\t", -1);
1328 if (!req || !*req) {
1329 g_strfreev(req);
1330 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1333 n = find_account(client->doc, &req, &rc, NULL, 0);
1335 if (!n) {
1336 g_strfreev(req);
1337 return send_error(ctx, rc);
1340 if (req[1])
1341 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1343 g_strfreev(req);
1345 if (rc)
1346 return send_error(ctx, rc);
1348 if (!n || !n->children)
1349 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1351 n = find_text_node(n->children);
1353 if (!n || !n->content || !*n->content)
1354 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1356 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1357 return send_error(ctx, rc);
1360 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1361 gpg_error_t *rc, gchar **req_orig, void *data)
1363 gchar *path = *(gchar **)data;
1364 gchar *tmp = NULL, *result;
1366 if (path) {
1367 g_free(path);
1368 *(gchar **)data = NULL;
1371 path = g_strjoinv("\t", target);
1373 if (!path) {
1374 *rc = gpg_error_from_errno(ENOMEM);
1375 return NULL;
1378 if (req_orig) {
1379 tmp = g_strjoinv("\t", req_orig);
1381 if (!tmp) {
1382 g_free(path);
1383 *rc = gpg_error_from_errno(ENOMEM);
1384 return NULL;
1388 if (tmp && *tmp)
1389 result = g_strdup_printf("%s\t%s", path, tmp);
1390 else
1391 result = g_strdup(path);
1393 if (!result) {
1394 *rc = gpg_error_from_errno(ENOMEM);
1395 g_free(path);
1396 g_free(tmp);
1397 return NULL;
1400 g_free(path);
1401 g_free(tmp);
1402 *(gchar **)data = result;
1403 return node;
1406 static int realpath_command(assuan_context_t ctx, char *line)
1408 gpg_error_t rc;
1409 struct client_s *client = assuan_get_pointer(ctx);
1410 gchar **req;
1411 gchar *t;
1412 gint i;
1413 xmlNodePtr n;
1414 GString *string;
1415 gchar *rp = NULL;
1417 rc = file_modified(client);
1419 if (rc) {
1420 log_write("%s: %s", client->filename ? client->filename : "",
1421 pwmd_strerror(rc));
1422 return send_error(ctx, rc);
1425 if (strchr(line, '\t') != NULL) {
1426 if ((req = split_input_line(line, "\t", 0)) == NULL)
1427 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1429 else {
1430 if ((req = split_input_line(line, " ", 0)) == NULL)
1431 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1434 n = find_account(client->doc, &req, &rc, NULL, 0);
1436 if (!n) {
1437 g_strfreev(req);
1438 return send_error(ctx, rc);
1441 rp = g_strjoinv("\t", req);
1443 if (!rp) {
1444 g_strfreev(req);
1445 return send_syserror(ctx, ENOMEM);
1448 if (req[1]) {
1449 n = find_elements(client->doc, n->children, req+1, &rc,
1450 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1452 if (!n) {
1453 g_free(rp);
1454 g_strfreev(req);
1455 return send_error(ctx, rc);
1459 string = g_string_new(rp);
1460 g_free(rp);
1461 g_strfreev(req);
1463 if (!string)
1464 return send_syserror(ctx, ENOMEM);
1466 again:
1467 for (i = 0, t = string->str + i; *t; t++, i++) {
1468 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1469 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1470 goto again;
1474 rc = assuan_send_data(ctx, string->str, string->len);
1475 g_string_free(string, TRUE);
1476 return send_error(ctx, rc);
1479 static int list_command(assuan_context_t ctx, char *line)
1481 struct client_s *client = assuan_get_pointer(ctx);
1482 gpg_error_t rc;
1483 struct element_list_s *elements = NULL;
1484 gchar *tmp;
1486 if (disable_list_and_dump == TRUE)
1487 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1489 rc = file_modified(client);
1491 if (rc) {
1492 log_write("%s: %s", client->filename, pwmd_strerror(rc));
1493 return send_error(ctx, rc);
1496 if (!*line) {
1497 GString *str;
1499 rc = list_accounts(client->doc, &str);
1501 if (rc)
1502 return send_error(ctx, rc);
1504 rc = assuan_send_data(ctx, str->str, str->len);
1505 g_string_free(str, TRUE);
1506 return send_error(ctx, rc);
1509 elements = g_malloc0(sizeof(struct element_list_s));
1511 if (!elements) {
1512 rc = gpg_err_code_from_errno(ENOMEM);
1513 goto fail;
1516 rc = create_path_list(client->doc, elements, line);
1518 if (rc)
1519 goto fail;
1521 if (elements) {
1522 gint total = g_slist_length(elements->list);
1523 gint i;
1524 GString *str;
1526 if (!total) {
1527 rc = EPWMD_EMPTY_ELEMENT;
1528 goto fail;
1531 str = g_string_new(NULL);
1533 if (!str) {
1534 rc = gpg_err_code_from_errno(ENOMEM);
1535 goto fail;
1538 for (i = 0; i < total; i++) {
1539 tmp = g_slist_nth_data(elements->list, i);
1540 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1543 rc = assuan_send_data(ctx, str->str, str->len);
1544 g_string_free(str, TRUE);
1546 else
1547 rc = EPWMD_EMPTY_ELEMENT;
1549 fail:
1550 if (elements) {
1551 gint total = g_slist_length(elements->list);
1552 gint i;
1554 for (i = 0; i < total; i++) {
1555 tmp = g_slist_nth_data(elements->list, i);
1556 g_free(tmp);
1559 g_slist_free(elements->list);
1561 if (elements->prefix)
1562 g_free(elements->prefix);
1564 g_free(elements);
1567 return send_error(ctx, rc);
1570 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1571 const gchar *value)
1573 xmlAttrPtr a;
1575 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1576 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1578 if (!a)
1579 return EPWMD_LIBXML_ERROR;
1581 else
1582 xmlNodeSetContent(a->children, (xmlChar *)value);
1584 return 0;
1588 * req[0] - element path
1590 static int attribute_list(assuan_context_t ctx, gchar **req)
1592 struct client_s *client = assuan_get_pointer(ctx);
1593 gchar **attrlist = NULL;
1594 gint i = 0;
1595 gchar **path = NULL;
1596 xmlAttrPtr a;
1597 xmlNodePtr n, an;
1598 gchar *line;
1599 gpg_error_t rc;
1601 if (!req || !req[0])
1602 return EPWMD_COMMAND_SYNTAX;
1604 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1606 * The first argument may be only an account.
1608 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1609 return EPWMD_COMMAND_SYNTAX;
1612 n = find_account(client->doc, &path, &rc, NULL, 0);
1614 if (!n) {
1615 g_strfreev(path);
1616 return rc;
1619 if (path[1]) {
1620 n = find_elements(client->doc, n->children, path+1, &rc,
1621 NULL, NULL, NULL, FALSE, 0, NULL);
1623 if (!n) {
1624 g_strfreev(path);
1625 return rc;
1629 g_strfreev(path);
1631 for (a = n->properties; a; a = a->next) {
1632 gchar **pa;
1634 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1635 if (attrlist)
1636 g_strfreev(attrlist);
1638 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1639 return gpg_error_from_errno(ENOMEM);
1642 attrlist = pa;
1643 an = a->children;
1644 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1646 if (!attrlist[i]) {
1647 g_strfreev(attrlist);
1648 return gpg_error_from_errno(ENOMEM);
1651 attrlist[++i] = NULL;
1654 if (!attrlist)
1655 return EPWMD_EMPTY_ELEMENT;
1657 line = g_strjoinv("\n", attrlist);
1659 if (!line) {
1660 g_strfreev(attrlist);
1661 return gpg_error_from_errno(ENOMEM);
1664 rc = assuan_send_data(ctx, line, strlen(line));
1665 g_free(line);
1666 g_strfreev(attrlist);
1667 return rc;
1671 * req[0] - attribute
1672 * req[1] - element path
1674 static int attribute_delete(struct client_s *client, gchar **req)
1676 xmlAttrPtr a;
1677 xmlNodePtr n;
1678 gchar **path = NULL;
1679 gpg_error_t rc;
1681 if (!req || !req[0] || !req[1])
1682 return EPWMD_COMMAND_SYNTAX;
1684 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1686 * The first argument may be only an account.
1688 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1689 return EPWMD_COMMAND_SYNTAX;
1693 * Don't remove the "name" attribute for the account element. To remove an
1694 * account use DELETE <account>.
1696 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1697 rc = EPWMD_ATTR_SYNTAX;
1698 goto fail;
1701 n = find_account(client->doc, &path, &rc, NULL, 0);
1703 if (!n)
1704 goto fail;
1706 if (path[1]) {
1707 n = find_elements(client->doc, n->children, path+1, &rc,
1708 NULL, NULL, NULL, FALSE, 0, NULL);
1710 if (!n)
1711 goto fail;
1714 g_strfreev(path);
1716 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1717 return EPWMD_ATTR_NOT_FOUND;
1719 if (xmlRemoveProp(a) == -1)
1720 return EPWMD_LIBXML_ERROR;
1722 return 0;
1724 fail:
1725 g_strfreev(path);
1726 return rc;
1729 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1730 gpg_error_t *rc)
1732 gchar **src = *path;
1733 gchar **src_orig = g_strdupv(src);
1734 xmlNodePtr n = NULL;
1736 *rc = 0;
1738 if (!src_orig) {
1739 *rc = gpg_error_from_errno(ENOMEM);
1740 goto fail;
1743 again:
1744 n = find_account(client->doc, &src, rc, NULL, 0);
1746 if (!n) {
1747 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1748 *rc = new_account(client->doc, src[0]);
1750 if (*rc)
1751 goto fail;
1753 goto again;
1755 else
1756 goto fail;
1759 if (src[1]) {
1760 if (!n->children)
1761 n = create_target_elements_cb(n, src+1, rc, NULL);
1762 else
1763 n = find_elements(client->doc, n->children, src+1, rc,
1764 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1766 if (!n)
1767 goto fail;
1770 * Reset the position of the element tree now that the elements
1771 * have been created.
1773 g_strfreev(src);
1774 src = src_orig;
1775 src_orig = NULL;
1776 n = find_account(client->doc, &src, rc, NULL, 0);
1778 if (!n)
1779 goto fail;
1781 n = find_elements(client->doc, n->children, src+1, rc,
1782 NULL, NULL, NULL, FALSE, 0, NULL);
1784 if (!n)
1785 goto fail;
1788 fail:
1789 if (src_orig)
1790 g_strfreev(src_orig);
1792 *path = src;
1793 return n;
1797 * Creates a "target" attribute. When other commands encounter an element with
1798 * this attribute, the element path is modified to the target value. If the
1799 * source element path doesn't exist when using 'ATTR SET target', it is
1800 * created, but the destination element path must exist.
1802 * req[0] - source element path
1803 * req[1] - destination element path
1805 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1807 gchar **src, **dst, *line = NULL;
1808 gpg_error_t rc;
1809 xmlNodePtr n;
1811 if (!req || !req[0] || !req[1])
1812 return EPWMD_COMMAND_SYNTAX;
1814 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1816 * The first argument may be only an account.
1818 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1819 return EPWMD_COMMAND_SYNTAX;
1822 if (valid_element_path(src, FALSE) == FALSE) {
1823 g_strfreev(src);
1824 return EPWMD_INVALID_ELEMENT;
1827 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1829 * The first argument may be only an account.
1831 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1832 rc = EPWMD_COMMAND_SYNTAX;
1833 goto fail;
1837 n = find_account(client->doc, &dst, &rc, NULL, 0);
1840 * Make sure the destination element path exists.
1842 if (!n)
1843 goto fail;
1845 if (dst[1]) {
1846 n = find_elements(client->doc, n->children, dst+1, &rc,
1847 NULL, NULL, NULL, FALSE, 0, NULL);
1849 if (!n)
1850 goto fail;
1853 n = create_element_path(client, &src, &rc);
1855 if (rc)
1856 goto fail;
1858 line = g_strjoinv("\t", dst);
1860 if (!line) {
1861 rc = gpg_error_from_errno(ENOMEM);
1862 goto fail;
1865 rc = add_attribute(n, "target", line);
1867 fail:
1868 g_free(line);
1869 g_strfreev(src);
1870 g_strfreev(dst);
1871 return rc;
1875 * req[0] - account name
1876 * req[1] - new name
1878 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
1880 gpg_error_t rc;
1881 gchar **tmp;
1882 xmlNodePtr n;
1884 tmp = g_strdupv(req);
1886 if (!tmp)
1887 return gpg_error_from_errno(ENOMEM);
1889 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1890 g_strfreev(tmp);
1892 if (!n)
1893 return rc;
1895 if (g_utf8_collate(req[0], req[1]) == 0)
1896 return 0;
1899 * Will not overwrite an existing account.
1901 tmp = g_strdupv(req+1);
1903 if (!tmp)
1904 return gpg_error_from_errno(ENOMEM);
1906 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1907 g_strfreev(tmp);
1909 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
1910 return rc;
1912 if (n)
1913 return EPWMD_ACCOUNT_EXISTS;
1916 * Whitespace not allowed in account names.
1918 if (contains_whitespace(req[1]) == TRUE)
1919 return EPWMD_ATTR_SYNTAX;
1921 tmp = g_strdupv(req);
1923 if (!tmp)
1924 return gpg_error_from_errno(ENOMEM);
1926 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1927 g_strfreev(tmp);
1929 if (!n)
1930 return EPWMD_ELEMENT_NOT_FOUND;
1932 return add_attribute(n, "name", req[1]);
1936 * req[0] - attribute
1937 * req[1] - element path
1939 static int attribute_get(assuan_context_t ctx, gchar **req)
1941 struct client_s *client = assuan_get_pointer(ctx);
1942 xmlNodePtr n;
1943 xmlChar *a;
1944 gchar **path= NULL;
1945 gpg_error_t rc;
1947 if (!req || !req[0] || !req[1])
1948 return EPWMD_COMMAND_SYNTAX;
1950 if (strchr(req[1], '\t')) {
1951 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
1952 return EPWMD_COMMAND_SYNTAX;
1954 else {
1955 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1956 return EPWMD_COMMAND_SYNTAX;
1959 n = find_account(client->doc, &path, &rc, NULL, 0);
1961 if (!n)
1962 goto fail;
1964 if (path[1]) {
1965 n = find_elements(client->doc, n->children, path+1, &rc,
1966 NULL, NULL, NULL, FALSE, 0, NULL);
1968 if (!n)
1969 goto fail;
1972 g_strfreev(path);
1974 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
1975 return EPWMD_ATTR_NOT_FOUND;
1977 rc = assuan_send_data(ctx, a, xmlStrlen(a));
1978 xmlFree(a);
1979 return rc;
1981 fail:
1982 g_strfreev(path);
1983 return rc;
1987 * req[0] - attribute
1988 * req[1] - element path
1989 * req[2] - value
1991 static int attribute_set(struct client_s *client, gchar **req)
1993 gchar **path = NULL;
1994 gpg_error_t rc;
1995 xmlNodePtr n;
1997 if (!req || !req[0] || !req[1] || !req[2])
1998 return EPWMD_COMMAND_SYNTAX;
2001 * Reserved attribute names.
2003 if (g_utf8_collate(req[0], "name") == 0) {
2005 * Only reserved for the account element. Not the rest of the
2006 * document.
2008 if (strchr(req[1], '\t') == NULL)
2009 return name_attribute(client, req + 1);
2011 else if (g_utf8_collate(req[0], "target") == 0)
2012 return target_attribute(client, req + 1);
2014 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2016 * The first argument may be only an account.
2018 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2019 return EPWMD_COMMAND_SYNTAX;
2022 n = find_account(client->doc, &path, &rc, NULL, 0);
2024 if (!n)
2025 goto fail;
2027 if (path[1]) {
2028 n = find_elements(client->doc, n->children, path+1, &rc,
2029 NULL, NULL, NULL, FALSE, 0, NULL);
2031 if (!n)
2032 goto fail;
2035 g_strfreev(path);
2036 return add_attribute(n, req[0], req[2]);
2038 fail:
2039 g_strfreev(path);
2040 return rc;
2044 * req[0] - command
2045 * req[1] - attribute name or element path if command is LIST
2046 * req[2] - element path
2047 * req[2] - element path or value
2049 static int attr_command(assuan_context_t ctx, char *line)
2051 struct client_s *client = assuan_get_pointer(ctx);
2052 gchar **req;
2053 gpg_error_t rc = 0;
2055 rc = file_modified(client);
2057 if (rc) {
2058 log_write("%s: %s", client->filename ? client->filename : "",
2059 pwmd_strerror(rc));
2060 return send_error(ctx, rc);
2063 req = split_input_line(line, " ", 4);
2065 if (!req || !req[0] || !req[1]) {
2066 g_strfreev(req);
2067 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2070 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2071 rc = attribute_set(client, req+1);
2072 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2073 rc = attribute_get(ctx, req+1);
2074 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2075 rc = attribute_delete(client, req+1);
2076 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2077 rc = attribute_list(ctx, req+1);
2078 else
2079 rc = EPWMD_COMMAND_SYNTAX;
2081 g_strfreev(req);
2082 return send_error(ctx, rc);
2085 static int iscached_command(assuan_context_t ctx, char *line)
2087 gchar **req = split_input_line(line, " ", 0);
2088 guchar md5file[16];
2090 if (!req || !*req) {
2091 g_strfreev(req);
2092 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2095 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2096 g_strfreev(req);
2097 CACHE_LOCK(ctx);
2099 if (cache_iscached(md5file) == FALSE) {
2100 CACHE_UNLOCK;
2101 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2104 CACHE_UNLOCK;
2105 return send_error(ctx, 0);
2108 static int clearcache_command(assuan_context_t ctx, char *line)
2110 struct client_s *client = assuan_get_pointer(ctx);
2111 gchar **req = split_input_line(line, " ", 0);
2112 guchar md5file[16];
2114 CACHE_LOCK(ctx);
2116 if (!req || !*req) {
2117 g_strfreev(req);
2118 cache_clear(client->md5file, 2);
2119 CACHE_UNLOCK;
2120 return send_error(ctx, 0);
2123 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2124 g_strfreev(req);
2126 if (cache_clear(md5file, 1) == FALSE) {
2127 CACHE_UNLOCK;
2128 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2131 CACHE_UNLOCK;
2132 return send_error(ctx, 0);
2135 static int cachetimeout_command(assuan_context_t ctx, char *line)
2137 guchar md5file[16];
2138 glong timeout;
2139 gchar **req = split_input_line(line, " ", 0);
2140 gchar *p;
2141 struct client_s *client = assuan_get_pointer(ctx);
2143 if (!req || !*req || !req[1]) {
2144 g_strfreev(req);
2145 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2148 errno = 0;
2149 timeout = strtol(req[0], &p, 10);
2151 if (errno != 0 || *p != 0) {
2152 g_strfreev(req);
2153 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2156 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2157 g_strfreev(req);
2158 CACHE_LOCK(client->ctx);
2160 if (cache_set_timeout(md5file, timeout) == FALSE) {
2161 CACHE_UNLOCK;
2162 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2165 CACHE_UNLOCK;
2166 return send_error(ctx, 0);
2169 static int dump_command(assuan_context_t ctx, char *line)
2171 xmlChar *xml;
2172 gssize len;
2173 struct client_s *client = assuan_get_pointer(ctx);
2174 gpg_error_t rc;
2176 if (disable_list_and_dump == TRUE)
2177 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2179 rc = file_modified(client);
2181 if (rc) {
2182 log_write("%s: %s", client->filename ? client->filename : "",
2183 pwmd_strerror(rc));
2184 return send_error(ctx, rc);
2187 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2189 if (!xml)
2190 return send_syserror(ctx, ENOMEM);
2192 rc = assuan_send_data(ctx, xml, len);
2193 xmlFree(xml);
2194 return send_error(ctx, rc);
2197 static int getconfig_command(assuan_context_t ctx, gchar *line)
2199 struct client_s *client = assuan_get_pointer(ctx);
2200 gpg_error_t rc = 0;
2201 gchar filename[255]={0}, param[747]={0};
2202 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2204 if (strchr(line, ' ')) {
2205 sscanf(line, " %254[a-zA-Z] %746c", filename, param);
2206 fp = filename;
2207 paramp = param;
2210 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2211 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2213 p = get_key_file_string(fp ? fp : "global", paramp);
2215 if (!p)
2216 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2218 tmp = expand_homedir(p);
2220 if (!tmp) {
2221 g_free(p);
2222 return send_syserror(ctx, ENOMEM);
2225 g_free(p);
2226 p = tmp;
2227 rc = assuan_send_data(ctx, p, strlen(p));
2228 g_free(p);
2229 return send_error(ctx, rc);
2232 static int xpath_command(assuan_context_t ctx, gchar *line)
2234 struct client_s *client = assuan_get_pointer(ctx);
2235 gpg_error_t rc;
2236 xmlXPathContextPtr xp;
2237 xmlXPathObjectPtr result;
2238 xmlBufferPtr buf = NULL;
2239 gchar **req = NULL;
2241 rc = file_modified(client);
2243 if (rc) {
2244 log_write("%s: %s", client->filename ? client->filename : "",
2245 pwmd_strerror(rc));
2246 return send_error(ctx, rc);
2249 if (!line || !*line)
2250 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2252 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2253 if (strv_printf(&req, "%s", line) == FALSE)
2254 return send_syserror(ctx, ENOMEM);
2257 xp = xmlXPathNewContext(client->doc);
2259 if (!xp)
2260 return send_error(ctx, EPWMD_LIBXML_ERROR);
2262 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2264 if (!result) {
2265 xmlXPathFreeContext(xp);
2266 return send_error(ctx, EPWMD_LIBXML_ERROR);
2269 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2270 rc = EPWMD_EMPTY_ELEMENT;
2271 goto fail;
2274 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2275 (xmlChar *)req[1], &buf);
2277 if (rc)
2278 goto fail;
2279 else if (!req[1] && !xmlBufferLength(buf)) {
2280 rc = EPWMD_EMPTY_ELEMENT;
2281 goto fail;
2283 else if (req[1])
2284 goto fail;
2286 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2288 fail:
2289 g_strfreev(req);
2291 if (buf)
2292 xmlBufferFree(buf);
2294 if (result)
2295 xmlXPathFreeObject(result);
2297 if (xp)
2298 xmlXPathFreeContext(xp);
2300 return send_error(ctx, rc);
2303 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2304 gsize len)
2306 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2307 gpg_error_t rc = file_modified(client);
2308 gchar **req, **path = NULL, **path_orig = NULL, *content;
2309 xmlDocPtr doc;
2310 xmlNodePtr n, root, copy;
2312 if (assuan_rc || rc) {
2313 if (line)
2314 #ifndef MEM_DEBUG
2315 xfree(line);
2316 #else
2317 free(line);
2318 #endif
2319 return assuan_rc ? assuan_rc : rc;
2322 req = split_input_line((gchar *)line, " ", 2);
2323 #ifndef MEM_DEBUG
2324 xfree(line);
2325 #else
2326 free(line);
2327 #endif
2329 if (!req || !*req)
2330 return EPWMD_COMMAND_SYNTAX;
2332 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2333 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2334 return EPWMD_COMMAND_SYNTAX;
2337 content = req[1];
2339 if (!content || !*content) {
2340 rc = EPWMD_COMMAND_SYNTAX;
2341 goto fail;
2344 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2345 rc = EPWMD_INVALID_ELEMENT;
2346 goto fail;
2349 if (valid_element_path(path+1, FALSE) == FALSE) {
2350 rc = EPWMD_INVALID_ELEMENT;
2351 goto fail;
2354 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2356 if (!doc) {
2357 rc = EPWMD_LIBXML_ERROR;
2358 goto fail;
2361 root = xmlDocGetRootElement(doc);
2362 path_orig = g_strdupv(path);
2364 if (!path_orig) {
2365 xmlFreeDoc(doc);
2366 rc = gpg_error_from_errno(ENOMEM);
2367 goto fail;
2370 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2371 g_strfreev(path_orig);
2372 xmlFreeDoc(doc);
2373 rc = gpg_error_from_errno(ENOMEM);
2374 goto fail;
2377 n = find_account(client->doc, &path, &rc, NULL, 0);
2379 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2380 g_strfreev(path_orig);
2381 xmlFreeDoc(doc);
2382 goto fail;
2384 else if (!rc) {
2385 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2387 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2388 g_strfreev(path_orig);
2389 xmlFreeDoc(doc);
2390 goto fail;
2392 else if (!rc) {
2393 xmlNodePtr parent = n->parent;
2395 xmlUnlinkNode(n);
2396 xmlFreeNode(n);
2397 n = parent;
2401 g_strfreev(path);
2402 path = path_orig;
2404 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2405 n = create_element_path(client, &path, &rc);
2407 if (rc) {
2408 xmlFreeDoc(doc);
2409 goto fail;
2413 copy = xmlCopyNode(root, 1);
2414 n = xmlAddChild(n, copy);
2415 xmlFreeDoc(doc);
2417 if (!n)
2418 rc = EPWMD_LIBXML_ERROR;
2420 fail:
2421 g_strfreev(path);
2422 g_strfreev(req);
2423 client->inquire_status = INQUIRE_DONE;
2424 return rc;
2427 static int import_command(assuan_context_t ctx, gchar *line)
2429 gpg_error_t rc;
2430 struct client_s *client = assuan_get_pointer(ctx);
2432 rc = file_modified(client);
2434 if (rc) {
2435 log_write("%s: %s", client->filename ? client->filename : "",
2436 pwmd_strerror(rc));
2437 return send_error(ctx, rc);
2440 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2442 if (rc)
2443 return send_error(ctx, rc);
2445 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2446 client->inquire_status = INQUIRE_BUSY;
2447 return 0;
2450 static int lock_command(assuan_context_t ctx, gchar *line)
2452 gpg_error_t rc;
2453 struct client_s *client = assuan_get_pointer(ctx);
2455 rc = file_modified(client);
2457 if (rc) {
2458 log_write("%s: %s", client->filename ? client->filename : "",
2459 pwmd_strerror(rc));
2460 return send_error(ctx, rc);
2463 rc = lock_file_mutex(client);
2465 if (!rc)
2466 client->is_lock_cmd = TRUE;
2468 return send_error(ctx, rc);
2471 static int unlock_command(assuan_context_t ctx, gchar *line)
2473 gpg_error_t rc;
2474 struct client_s *client = assuan_get_pointer(ctx);
2476 rc = file_modified(client);
2478 if (rc) {
2479 log_write("%s: %s", client->filename ? client->filename : "",
2480 pwmd_strerror(rc));
2481 return send_error(ctx, rc);
2484 unlock_file_mutex(client);
2485 return send_error(ctx, 0);
2488 static int getpid_command(assuan_context_t ctx, gchar *line)
2490 gpg_error_t rc;
2491 gchar buf[32];
2492 pid_t pid = getpid();
2494 print_fmt(buf, sizeof(buf), "%i", pid);
2495 rc = assuan_send_data(ctx, buf, strlen(buf));
2496 return send_error(ctx, rc);
2499 void cleanup_assuan(assuan_context_t ctx)
2501 struct client_s *cl = assuan_get_pointer(ctx);
2503 if (cl)
2504 cleanup_client(cl);
2507 static void reset_notify(assuan_context_t ctx)
2509 struct client_s *cl = assuan_get_pointer(ctx);
2511 if (cl)
2512 cleanup_client(cl);
2515 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2517 gchar name[32] = {0}, value[256] = {0};
2519 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2520 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2522 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2523 pth_attr_t attr = pth_attr_of(pth_self());
2525 log_write("OPTION CLIENT %s", line);
2526 pth_attr_set(attr, PTH_ATTR_NAME, value);
2527 pth_attr_destroy(attr);
2529 else
2530 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2532 return 0;
2535 static int option_handler(assuan_context_t ctx, const gchar *name,
2536 const gchar *value)
2538 #ifdef WITH_PINENTRY
2539 struct client_s *client = assuan_get_pointer(ctx);
2540 #endif
2542 if (!value || !*value)
2543 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2545 if (g_strcasecmp(name, (gchar *)"client") == 0)
2546 return parse_client_option(ctx, value);
2548 if (g_strcasecmp(name, (gchar *)"iterations") == 0) {
2549 long n;
2550 gchar *p = NULL;
2552 errno = 0;
2553 n = strtol(value, &p, 10);
2555 if (errno || (p && *p))
2556 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2558 g_key_file_set_integer(keyfileh, client->filename ? client->filename : "global", "iterations", n);
2559 send_status_all(STATUS_CONFIG);
2561 #ifdef WITH_PINENTRY
2562 else if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2563 g_free(client->pinentry->ttyname);
2564 client->pinentry->ttyname = g_strdup(value);
2566 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2567 g_free(client->pinentry->ttytype);
2568 client->pinentry->ttytype = g_strdup(value);
2570 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2571 g_free(client->pinentry->display);
2572 client->pinentry->display = g_strdup(value);
2574 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2575 g_free(client->pinentry->path);
2576 client->pinentry->path = g_strdup(value);
2578 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2579 g_free(client->pinentry->title);
2580 client->pinentry->title = g_strdup(value);
2582 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2583 g_free(client->pinentry->prompt);
2584 client->pinentry->prompt = g_strdup(value);
2586 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2587 g_free(client->pinentry->desc);
2588 client->pinentry->desc = g_strdup(value);
2590 #if 0
2591 /* Need to wait for pinentry to support a --timeout option so it can
2592 * terminate itself. Cannot do it here because assuan_pipe_connect() calls
2593 * execv() which replaces the pid of the fork()ed thread from
2594 * pinentry_fork(). So pinentry will become a real process after the
2595 * thread terminates and won't be able to be kill()ed from pwmd.
2597 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2598 gchar *p = NULL;
2599 gint n = strtol(value, &p, 10);
2601 if (*p || n < 0)
2602 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2604 client->pinentry->timeout = n;
2606 #endif
2607 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2608 gchar *p = NULL;
2609 gint n = strtol(value, &p, 10);
2611 if (*p || n < 0 || n > 1)
2612 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2614 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2616 #else
2617 else
2618 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2619 #endif
2621 log_write("OPTION %s=%s", name, value);
2622 return 0;
2625 gpg_error_t register_commands(assuan_context_t ctx)
2627 static struct {
2628 const gchar *name;
2629 gint (*handler)(assuan_context_t, gchar *line);
2630 } table[] = {
2631 { "OPEN", open_command },
2632 { "SAVE", save_command },
2633 { "LIST", list_command },
2634 { "REALPATH", realpath_command },
2635 { "STORE", store_command },
2636 { "DELETE", delete_command },
2637 { "GET", get_command },
2638 { "ATTR", attr_command },
2639 { "ISCACHED", iscached_command },
2640 { "CLEARCACHE", clearcache_command },
2641 { "CACHETIMEOUT", cachetimeout_command },
2642 { "GETCONFIG", getconfig_command },
2643 { "DUMP", dump_command },
2644 { "XPATH", xpath_command },
2645 { "IMPORT", import_command },
2646 { "LOCK", lock_command },
2647 { "UNLOCK", unlock_command },
2648 { "GETPID", getpid_command },
2649 { "INPUT", NULL },
2650 { "OUTPUT", NULL },
2651 { NULL, NULL }
2653 gint i, rc;
2655 for (i=0; table[i].name; i++) {
2656 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2658 if (rc)
2659 return rc;
2662 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2664 if (rc)
2665 return rc;
2667 rc = assuan_register_option_handler(ctx, option_handler);
2669 if (rc)
2670 return rc;
2672 return assuan_register_reset_notify(ctx, reset_notify);
2675 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2676 guchar *key)
2678 guchar *iv;
2679 void *inbuf;
2680 gsize insize, len;
2681 guchar tkey[gcrykeysize];
2682 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2683 gcry_cipher_hd_t gh;
2684 guint iter = 0, n_iter = 0;
2685 gint iter_progress;
2686 void *outbuf = NULL;
2687 gint zrc = 0;
2688 glong outsize = 0;
2689 gpg_error_t rc;
2690 file_header_t file_header;
2691 gchar str[ASSUAN_LINELENGTH];
2693 if (!ctx) {
2694 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2696 if (rc)
2697 return rc;
2699 else
2700 gh = client->gh;
2702 lseek(fd, 0, SEEK_SET);
2703 insize = st.st_size - sizeof(file_header_t);
2704 iv = gcry_malloc(gcryblocksize);
2706 if (!iv) {
2707 if (!ctx)
2708 gcry_cipher_close(gh);
2710 return gpg_error_from_errno(ENOMEM);
2713 len = pth_read(fd, &file_header, sizeof(file_header_t));
2715 if (len != sizeof(file_header_t)) {
2716 len = errno;
2718 if (!ctx)
2719 gcry_cipher_close(gh);
2721 gcry_free(iv);
2722 errno = len;
2723 return gpg_error_from_errno(errno);
2726 /* No encryption iterations. This is a plain (gzipped) file. */
2727 if (file_header.iter == -1) {
2729 * cache_file_count() needs both .used == TRUE and a valid key in
2730 * order for it to count as a used cache entry. Fixes CACHE status
2731 * messages.
2733 memset(key, '!', gcrykeysize);
2734 insize = st.st_size - sizeof(file_header_t);
2737 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2738 inbuf = gcry_malloc(insize);
2740 if (!inbuf) {
2741 if (!ctx)
2742 gcry_cipher_close(gh);
2744 gcry_free(iv);
2745 return gpg_error_from_errno(ENOMEM);
2748 len = pth_read(fd, inbuf, insize);
2750 if (len != insize) {
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 if (file_header.iter == -1)
2762 goto decompress;
2764 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2765 if (!ctx) {
2766 gcry_cipher_close(gh);
2767 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2769 else
2770 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2772 gcry_free(inbuf);
2773 gcry_free(iv);
2774 return rc;
2777 if ((rc = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2778 if (!ctx) {
2779 gcry_cipher_close(gh);
2780 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2782 else
2783 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2785 gcry_free(inbuf);
2786 gcry_free(iv);
2788 if (!ctx)
2789 gcry_cipher_close(gh);
2791 return rc;
2794 iter_progress = get_key_file_integer(client->filename, "iteration_progress");
2796 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2797 rc = assuan_write_status(client->ctx, "DECRYPT", "0");
2799 if (rc) {
2800 gcry_free(inbuf);
2801 gcry_free(iv);
2802 return rc;
2806 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2808 if (rc) {
2809 gcry_free(inbuf);
2810 gcry_free(iv);
2811 return rc;
2814 memcpy(tkey, key, sizeof(tkey));
2815 tkey[0] ^= 1;
2817 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2818 if (!ctx) {
2819 gcry_cipher_close(gh);
2820 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2822 else
2823 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2825 memset(tkey, 0, sizeof(tkey));
2826 gcry_free(inbuf);
2827 gcry_free(iv);
2828 return rc;
2831 memset(tkey, 0, sizeof(tkey));
2833 while (iter < file_header.iter) {
2834 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2835 if (!(iter % iter_progress)) {
2836 rc = assuan_write_status(ctx, "DECRYPT",
2837 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
2839 if (rc) {
2840 gcry_free(inbuf);
2841 gcry_free(iv);
2842 return rc;
2847 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2848 if (!ctx) {
2849 gcry_cipher_close(gh);
2850 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2852 else
2853 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2855 gcry_free(inbuf);
2856 gcry_free(iv);
2857 return rc;
2860 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2862 if (rc) {
2863 if (!ctx) {
2864 gcry_cipher_close(gh);
2865 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2867 else
2868 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2870 gcry_free(inbuf);
2871 gcry_free(iv);
2872 return rc;
2875 iter++;
2876 pth_yield(NULL);
2879 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2880 rc = assuan_write_status(ctx, "DECRYPT",
2881 print_fmt(str, sizeof(str), "%i", file_header.iter));
2883 if (rc) {
2884 gcry_free(inbuf);
2885 gcry_free(iv);
2886 return rc;
2890 gcry_free(iv);
2892 decompress:
2893 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zrc) == FALSE) {
2895 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2897 if (zrc == Z_MEM_ERROR) {
2898 gcry_free(inbuf);
2899 return gpg_error_from_errno(ENOMEM);
2901 else if (zrc != Z_DATA_ERROR) {
2902 gcry_free(inbuf);
2904 if (!ctx)
2905 gcry_cipher_close(gh);
2907 return EPWMD_BADKEY;
2910 else {
2911 gcry_free(inbuf);
2912 inbuf = outbuf;
2913 insize = outsize;
2916 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2917 gcry_free(inbuf);
2919 if (!ctx)
2920 gcry_cipher_close(gh);
2922 return EPWMD_BADKEY;
2925 if (ctx) {
2926 client->xml = inbuf;
2927 client->len = insize;
2929 else {
2930 gcry_cipher_close(gh);
2931 gcry_free(inbuf);
2934 return 0;
2938 * This is called after every Assuan command.
2940 void command_finalize(assuan_context_t ctx, gint rc)
2942 struct client_s *client = assuan_get_pointer(ctx);
2944 if (!client->is_lock_cmd)
2945 unlock_file_mutex(client);