--disable-pinentry build fix.
[pwmd.git] / src / commands.c
blob4029353fff81f8488cfcc406d2bce23ec3a4f19d
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 02110-1301 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_sleep(1);
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 struct client_thread_s *thd = client->thd;
219 #ifdef WITH_PINENTRY
220 struct pinentry_s *pin = client->pinentry;
221 #endif
223 unlock_file_mutex(client);
224 CACHE_LOCK(client->ctx);
225 cache_decr_refcount(client->md5file);
228 * This may be a new file so don't use a cache slot. save_command() will
229 * set this to FALSE on success.
231 if (client->new == TRUE)
232 cache_clear(client->md5file, 1);
234 free_client(client);
235 memset(client, 0, sizeof(struct client_s));
236 client->state = STATE_CONNECTED;
237 client->ctx = ctx;
238 client->thd = thd;
239 client->freed = TRUE;
240 #ifdef WITH_PINENTRY
241 client->pinentry = pin;
242 #endif
243 CACHE_UNLOCK;
246 gboolean do_decompress(assuan_context_t ctx, gpointer in, gint insize,
247 gpointer *out, glong *outsize, gint *rc)
249 z_stream z;
250 gpointer pout;
251 gz_header h;
252 gchar buf[17];
253 gchar str[ASSUAN_LINELENGTH];
255 z.zalloc = z_alloc;
256 z.zfree = z_free;
257 z.next_in = in;
258 z.avail_in = insize;
259 z.avail_out = zlib_bufsize;
260 z.next_out = pout = g_malloc(zlib_bufsize);
262 if (!pout) {
263 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
264 *rc = Z_MEM_ERROR;
265 return FALSE;
268 *rc = inflateInit2(&z, 47);
270 if (*rc != Z_OK) {
271 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
272 g_free(pout);
273 return FALSE;
276 memset(&h, 0, sizeof(gz_header));
277 h.comment = (guchar *)buf;
278 h.comm_max = sizeof(buf);
279 *rc = inflateGetHeader(&z, &h);
281 if (*rc != Z_OK) {
282 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
283 g_free(pout);
284 inflateEnd(&z);
285 return FALSE;
288 *rc = inflate(&z, Z_BLOCK);
290 if (*rc != Z_OK) {
291 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
292 g_free(pout);
293 inflateEnd(&z);
294 return FALSE;
297 if (h.comment)
298 insize = atoi((gchar *)h.comment);
300 do {
301 gpointer p;
303 *rc = inflate(&z, Z_FINISH);
305 switch (*rc) {
306 case Z_OK:
307 break;
308 case Z_BUF_ERROR:
309 if (!z.avail_out) {
310 p = g_realloc(pout, z.total_out + zlib_bufsize);
312 if (!p) {
313 *rc = Z_MEM_ERROR;
314 goto fail;
317 pout = p;
318 z.next_out = pout + z.total_out;
319 z.avail_out = zlib_bufsize;
321 if (ctx) {
322 *rc = assuan_write_status(ctx, "DECOMPRESS",
323 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
325 if (*rc)
326 goto fail;
329 break;
330 case Z_STREAM_END:
331 break;
332 default:
333 goto fail;
334 break;
337 pth_yield(NULL);
338 } while (*rc != Z_STREAM_END);
340 if (ctx) {
341 *rc = assuan_write_status(ctx, "DECOMPRESS",
342 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
344 if (*rc)
345 goto fail;
348 *out = pout;
349 *outsize = z.total_out;
350 inflateEnd(&z);
351 *rc = 0;
352 return TRUE;
354 fail:
355 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
356 g_free(pout);
357 inflateEnd(&z);
358 return FALSE;
361 gpg_error_t read_file_header(const gchar *filename, file_header_t *fh)
363 gint fd;
364 gsize len;
366 fd = open(filename, O_RDONLY);
368 if (fd == -1)
369 return gpg_error_from_errno(errno);
371 len = pth_read(fd, fh, sizeof(file_header_t));
372 close(fd);
374 if (len != sizeof(file_header_t))
375 return gpg_error_from_errno(errno);
377 return 0;
380 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar shakey[],
381 gboolean cached)
383 struct client_s *client = assuan_get_pointer(ctx);
384 gpg_error_t rc;
385 struct stat st;
386 gint fd;
387 gint timeout;
388 gint iter;
390 if ((fd = open_file(client->filename, &st)) == -1) {
391 /* New file. */
392 if (errno == ENOENT) {
393 if (shakey[0])
394 goto update_cache;
396 goto done;
399 rc = errno;
400 log_write("%s: %s", client->filename, strerror(errno));
401 cleanup_client(client);
402 memset(shakey, 0, sizeof(shakey));
403 return send_syserror(ctx, rc);
406 rc = try_xml_decrypt(ctx, fd, st, shakey, &iter);
407 close(fd);
409 if (rc) {
410 memset(shakey, 0, sizeof(shakey));
411 cleanup_client(client);
412 return send_error(ctx, rc);
415 update_cache:
416 CACHE_LOCK(client->ctx);
418 if (cached == FALSE) {
419 if (cache_update_key(client->md5file, shakey) == FALSE) {
420 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
421 cleanup_client(client);
422 CACHE_UNLOCK;
423 return send_error(ctx, EPWMD_MAX_SLOTS);
426 timeout = get_key_file_integer(client->filename, "cache_timeout");
427 cache_reset_timeout(client->md5file, timeout);
429 else
430 cache_set_timeout(client->md5file, -2);
432 CACHE_UNLOCK;
434 done:
435 memset(shakey, 0, sizeof(shakey));
436 rc = parse_xml(ctx);
438 if (client->xml) {
439 gcry_free(client->xml);
440 client->xml = NULL;
443 if (!rc) {
444 if (client->new == FALSE)
445 send_status_all(STATUS_CACHE);
447 client->state = STATE_OPEN;
450 if (!rc && client->new == FALSE &&
451 iter != get_key_file_integer(client->filename, "iterations")) {
452 g_key_file_set_integer(keyfileh, client->filename, "iterations", iter);
453 send_status_all(STATUS_CONFIG);
456 return send_error(ctx, rc);
459 static int open_command(assuan_context_t ctx, char *line)
461 struct stat st;
462 guchar shakey[gcrykeysize];
463 gboolean cached = FALSE;
464 gpg_error_t rc;
465 struct client_s *client = assuan_get_pointer(ctx);
466 gchar **req;
467 gchar *filename = NULL;
468 file_header_t file_header;
470 memset(shakey, 0, sizeof(shakey));
472 if ((req = split_input_line(line, " ", 2)) != NULL)
473 filename = req[0];
475 if (!filename || !*filename) {
476 g_strfreev(req);
477 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
480 if (valid_filename(filename) == FALSE) {
481 g_strfreev(req);
482 return send_error(ctx, EPWMD_INVALID_FILENAME);
485 if (client->state == STATE_OPEN)
486 cleanup_client(client);
488 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
489 CACHE_LOCK(client->ctx);
491 if (cache_has_file(client->md5file) == FALSE) {
492 if (cache_add_file(client->md5file, NULL) == FALSE) {
493 g_strfreev(req);
494 CACHE_UNLOCK;
495 return send_error(ctx, EPWMD_MAX_SLOTS);
499 cache_incr_refcount(client->md5file);
500 CACHE_UNLOCK;
501 rc = lock_file_mutex(client);
503 if (rc) {
504 g_strfreev(req);
505 return send_error(ctx, rc);
508 client->freed = FALSE;
510 if ((rc = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
511 g_strfreev(req);
512 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
513 cleanup_client(client);
514 return send_error(ctx, rc);
517 if (stat(filename, &st) == 0) {
518 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
519 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
520 g_strfreev(req);
521 cleanup_client(client);
522 return send_error(ctx, EPWMD_INVALID_FILENAME);
525 client->mtime = st.st_mtime;
528 client->filename = g_strdup(filename);
530 if (!client->filename) {
531 memset(shakey, 0, sizeof(shakey));
532 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
533 cleanup_client(client);
534 g_strfreev(req);
535 return send_syserror(ctx, ENOMEM);
538 #ifdef WITH_PINENTRY
539 client->pinentry->filename = g_strdup(client->filename);
541 if (!client->pinentry->filename) {
542 memset(shakey, 0, sizeof(shakey));
543 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
544 cleanup_client(client);
545 g_strfreev(req);
546 return send_syserror(ctx, ENOMEM);
548 #endif
551 * New files don't need a key.
553 if (access(filename, R_OK) != 0) {
554 if (errno != ENOENT) {
555 rc = errno;
556 log_write("%s: %s", filename, strerror(errno));
557 g_strfreev(req);
558 cleanup_client(client);
559 return send_syserror(ctx, rc);
562 if ((client->xml = new_document()) == NULL) {
563 log_write("%s", strerror(ENOMEM));
564 g_strfreev(req);
565 cleanup_client(client);
566 return send_syserror(ctx, ENOMEM);
569 client->len = xmlStrlen(client->xml);
570 client->new = TRUE;
571 client->filename = g_strdup(filename);
573 if (!client->filename) {
574 g_strfreev(req);
575 cleanup_client(client);
576 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
577 return send_syserror(ctx, ENOMEM);
580 memset(shakey, 0, sizeof(shakey));
582 if (req[1] && *req[1])
583 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
585 g_strfreev(req);
586 return open_command_finalize(ctx, shakey, cached);
589 rc = read_file_header(filename, &file_header);
591 if (rc) {
592 g_strfreev(req);
593 cleanup_client(client);
594 return send_error(ctx, rc);
597 if (file_header.iter == -1)
598 goto done;
600 CACHE_LOCK(client->ctx);
601 cached = cache_get_key(client->md5file, shakey);
602 CACHE_UNLOCK;
604 if (cached == FALSE) {
606 * No key specified and no matching filename found in the cache. Use
607 * pinentry to retrieve the key. Cannot return assuan_process_done()
608 * here otherwise the command will be interrupted. The event loop in
609 * client_thread() will poll the file descriptor waiting for it to
610 * become ready to read a pinentry_key_s which will contain the
611 * entered key or rc. It will then call open_command_finalize() to
612 * to finish the command.
614 if (!req[1] || !*req[1]) {
615 #ifdef WITH_PINENTRY
616 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
618 /* From set_pinentry_defaults(). */
619 if (client->pinentry->enable == FALSE ||
620 (client->pinentry->enable == -1 && b == FALSE)) {
621 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
622 goto done;
625 g_strfreev(req);
626 rc = lock_pin_mutex(client);
628 if (rc) {
629 unlock_pin_mutex(client->pinentry);
630 cleanup_client(client);
631 return send_error(ctx, rc);
634 client->pinentry->which = PINENTRY_OPEN;
635 rc = pinentry_fork(ctx);
637 if (rc) {
638 unlock_pin_mutex(client->pinentry);
639 cleanup_client(client);
640 return send_error(ctx, rc);
643 client->pinentry->cb = open_command_finalize;
644 client->pinentry->status = PINENTRY_INIT;
645 return 0;
646 #else
647 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
648 goto done;
649 #endif
652 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
655 done:
656 g_strfreev(req);
657 return open_command_finalize(ctx, shakey, cached);
660 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
661 gint size, gpointer *out, glong *outsize, gint *rc)
663 z_stream z;
664 gpointer pout, pin;
665 gz_header h;
666 gchar buf[17];
667 gint cmd = Z_NO_FLUSH;
668 gchar str[ASSUAN_LINELENGTH];
670 z.zalloc = z_alloc;
671 z.zfree = z_free;
672 z.next_in = pin = data;
673 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
674 z.avail_out = zlib_bufsize;
675 z.next_out = pout = g_malloc(zlib_bufsize);
677 if (!pout) {
678 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
679 *rc = Z_MEM_ERROR;
680 return FALSE;
683 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
685 if (*rc != Z_OK) {
686 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
687 g_free(pout);
688 return FALSE;
691 memset(&h, 0, sizeof(gz_header));
692 g_snprintf(buf, sizeof(buf), "%i", size);
693 h.comment = (guchar *)buf;
694 *rc = deflateSetHeader(&z, &h);
696 if (*rc != Z_OK) {
697 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
698 g_free(pout);
699 deflateEnd(&z);
700 return FALSE;
703 do {
704 gpointer p;
706 *rc = deflate(&z, cmd);
708 switch (*rc) {
709 case Z_OK:
710 break;
711 case Z_BUF_ERROR:
712 if (!z.avail_out) {
713 p = g_realloc(pout, z.total_out + zlib_bufsize);
715 if (!p) {
716 *rc = Z_MEM_ERROR;
717 goto fail;
720 pout = p;
721 z.next_out = pout + z.total_out;
722 z.avail_out = zlib_bufsize;
725 if (!z.avail_in && z.total_in < size) {
726 if (z.total_in + zlib_bufsize > size)
727 z.avail_in = size - z.total_in;
728 else
729 z.avail_in = zlib_bufsize;
731 if (ctx) {
732 *rc = assuan_write_status(ctx, "COMPRESS",
733 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
735 if (*rc)
736 goto fail;
740 if (z.total_in >= size)
741 cmd = Z_FINISH;
743 break;
744 case Z_STREAM_END:
745 break;
746 default:
747 goto fail;
750 pth_yield(NULL);
751 } while (*rc != Z_STREAM_END);
753 if (ctx) {
754 *rc = assuan_write_status(ctx, "COMPRESS",
755 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
757 if (*rc)
758 goto fail;
761 *out = pout;
762 *outsize = z.total_out;
763 deflateEnd(&z);
764 *rc = 0;
765 return TRUE;
767 fail:
768 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
769 g_free(pout);
770 deflateEnd(&z);
771 return FALSE;
774 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
775 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
776 gint iter)
778 gsize len = insize;
779 gint fd;
780 gpointer inbuf;
781 guchar tkey[gcrykeysize];
782 gchar *p;
783 gpg_error_t rc;
784 guint iter_progress = 0, n_iter = 0, xiter = 0;
785 gchar tmp[FILENAME_MAX];
786 struct stat st;
787 mode_t mode = 0;
788 file_header_t file_header;
789 gchar str[ASSUAN_LINELENGTH];
791 if (iter == -1) {
793 * cache_file_count() needs both .used == TRUE and a valid key in
794 * order for it to count as a used cache entry. Fixes CACHE status
795 * messages.
797 memset(shakey, '!', gcrykeysize);
798 inbuf = data;
799 file_header.iter = iter;
800 goto write_file;
803 if (insize / gcryblocksize) {
804 len = (insize / gcryblocksize) * gcryblocksize;
806 if (insize % gcryblocksize)
807 len += gcryblocksize;
811 * Resize the existing xml buffer to the block size required by gcrypt
812 * rather than duplicating it and wasting memory.
814 inbuf = gcry_realloc(data, len);
816 if (!inbuf)
817 return gpg_error_from_errno(ENOMEM);
819 insize = len;
820 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
821 memcpy(tkey, shakey, sizeof(tkey));
822 tkey[0] ^= 1;
824 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
825 memset(tkey, 0, sizeof(tkey));
826 gcry_free(inbuf);
827 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
828 return rc;
831 memset(tkey, 0, sizeof(tkey));
832 file_header.iter = iter;
834 if (client)
835 iter_progress = get_key_file_integer(client->filename, "iteration_progress");
837 if (client && iter_progress && file_header.iter >= iter_progress) {
838 rc = assuan_write_status(client->ctx, "ENCRYPT",
839 print_fmt(str, sizeof(str), "%i %i", 0, file_header.iter));
841 if (rc) {
842 gcry_free(inbuf);
843 return rc;
847 while (xiter < file_header.iter) {
848 if (client && iter_progress > 0 && xiter >= iter_progress) {
849 if (!(xiter % iter_progress)) {
850 rc = assuan_write_status(client->ctx, "ENCRYPT",
851 print_fmt(str, sizeof(str), "%i %i", ++n_iter * iter_progress, file_header.iter));
853 if (rc) {
854 gcry_free(inbuf);
855 return rc;
860 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
861 sizeof(file_header.iv)))) {
862 gcry_free(inbuf);
863 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
864 return rc;
867 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
868 == FALSE) {
869 gcry_free(inbuf);
870 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
871 return rc;
874 xiter++;
875 pth_yield(NULL);
878 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
879 sizeof(file_header.iv)))) {
880 gcry_free(inbuf);
881 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
882 return rc;
885 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
886 gcry_free(inbuf);
887 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
888 return rc;
891 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
892 gcry_free(inbuf);
893 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
894 return rc;
897 if (client && iter_progress && file_header.iter >= iter_progress) {
898 rc = assuan_write_status(client->ctx, "ENCRYPT",
899 print_fmt(str, sizeof(str), "%i %i", file_header.iter, file_header.iter));
901 if (rc) {
902 gcry_free(inbuf);
903 return rc;
907 write_file:
908 if (filename) {
909 if (stat(filename, &st) == 0) {
910 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
913 * FIXME What if the file has an ACL?
915 if (!(mode & S_IWUSR)) {
916 gcry_free(inbuf);
917 return gpg_error_from_errno(EACCES);
920 else {
921 if (errno != ENOENT) {
922 rc = errno;
923 gcry_free(inbuf);
924 return gpg_error_from_errno(rc);
928 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
930 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
931 rc = errno;
932 gcry_free(inbuf);
933 p = strrchr(tmp, '/');
934 p++;
935 log_write("%s: %s", p, strerror(rc));
936 return gpg_error_from_errno(rc);
939 else
941 * xml_import() from command line.
943 fd = STDOUT_FILENO;
945 len = pth_write(fd, &file_header, sizeof(file_header_t));
947 if (len != sizeof(file_header)) {
948 len = errno;
950 if (filename) {
951 close(fd);
952 unlink(tmp);
955 gcry_free(inbuf);
956 return gpg_error_from_errno(len);
959 len = pth_write(fd, inbuf, insize);
961 if (len != insize) {
962 len = errno;
964 if (filename) {
965 close(fd);
966 unlink(tmp);
969 gcry_free(inbuf);
970 return gpg_error_from_errno(len);
973 if (fsync(fd) == -1) {
974 len = errno;
976 if (filename) {
977 close(fd);
978 unlink(tmp);
981 gcry_free(inbuf);
982 return gpg_error_from_errno(len);
985 if (filename) {
986 close(fd);
988 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
989 gchar tmp2[FILENAME_MAX];
991 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
993 if (rename(filename, tmp2) == -1) {
994 unlink(tmp);
995 len = errno;
996 gcry_free(inbuf);
997 return gpg_error_from_errno(len);
1001 if (rename(tmp, filename) == -1) {
1002 len = errno;
1003 unlink(tmp);
1004 gcry_free(inbuf);
1005 return gpg_error_from_errno(len);
1008 if (mode)
1009 chmod(filename, mode);
1012 gcry_free(inbuf);
1013 return 0;
1016 static gpg_error_t save_command_finalize(assuan_context_t ctx,
1017 guchar shakey[], gboolean cached)
1019 struct client_s *client = assuan_get_pointer(ctx);
1020 gpointer xmlbuf;
1021 xmlChar *p;
1022 gint len;
1023 gint iter;
1024 gint timeout;
1025 gpointer outbuf;
1026 glong outsize = 0;
1027 gint zrc;
1028 gpg_error_t rc;
1029 struct stat st;
1031 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
1032 xmlbuf = p;
1034 iter = get_key_file_integer(client->filename, "compression_level");
1036 if (iter < 0)
1037 iter = 0;
1039 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
1040 memset(shakey, 0, sizeof(shakey));
1041 xmlFree(xmlbuf);
1043 if (zrc == Z_MEM_ERROR) {
1044 return send_syserror(ctx, ENOMEM);
1046 else
1047 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1049 else {
1050 gcry_free(xmlbuf);
1051 xmlbuf = outbuf;
1052 len = outsize;
1055 iter = get_key_file_integer(client->filename, "iterations");
1056 rc = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1058 if (rc) {
1059 memset(shakey, 0, sizeof(shakey));
1060 return send_error(ctx, rc);
1063 stat(client->filename, &st);
1064 client->mtime = st.st_mtime;
1065 timeout = get_key_file_integer(client->filename, "cache_timeout");
1066 CACHE_LOCK(client->ctx);
1068 if (cached) {
1069 memset(shakey, 0, sizeof(shakey));
1070 cache_reset_timeout(client->md5file, timeout);
1071 CACHE_UNLOCK;
1073 if (client->new == TRUE)
1074 send_status_all(STATUS_CACHE);
1076 client->new = FALSE;
1077 return send_error(ctx, 0);
1080 if (cache_update_key(client->md5file, shakey) == FALSE) {
1081 memset(shakey, 0, sizeof(shakey));
1082 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1083 CACHE_UNLOCK;
1084 return send_error(ctx, EPWMD_MAX_SLOTS);
1087 client->new = FALSE;
1088 memset(shakey, 0, sizeof(shakey));
1089 cache_reset_timeout(client->md5file, timeout);
1090 CACHE_UNLOCK;
1091 send_status_all(STATUS_CACHE);
1092 return send_error(ctx, 0);
1095 static int save_command(assuan_context_t ctx, char *line)
1097 gboolean cached = FALSE;
1098 guchar shakey[gcrykeysize];
1099 struct stat st;
1100 struct client_s *client = assuan_get_pointer(ctx);
1101 gpg_error_t rc;
1103 memset(shakey, 0, sizeof(shakey));
1104 rc = file_modified(client);
1106 if (rc)
1107 return send_error(ctx, rc);
1109 rc = lock_file_mutex(client);
1111 if (rc)
1112 return send_error(ctx, rc);
1114 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1115 return send_syserror(ctx, errno);
1117 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1118 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1119 return send_error(ctx, EPWMD_INVALID_FILENAME);
1122 if (get_key_file_integer(client->filename, "iterations") == -1)
1123 goto done;
1125 if (!line || !*line) {
1126 guchar tmp[sizeof(shakey)];
1127 CACHE_LOCK(ctx);
1129 memset(tmp, '!', sizeof(tmp));
1131 if (cache_get_key(client->md5file, shakey) == FALSE ||
1132 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1133 CACHE_UNLOCK;
1134 #ifdef WITH_PINENTRY
1135 if (get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1136 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1137 goto done;
1140 lock_pin_mutex(client);
1141 client->pinentry->which = PINENTRY_SAVE;
1142 rc = pinentry_fork(ctx);
1144 if (rc) {
1145 unlock_pin_mutex(client->pinentry);
1146 return send_error(ctx, rc);
1149 client->pinentry->cb = save_command_finalize;
1150 client->pinentry->status = PINENTRY_INIT;
1151 return 0;
1152 #else
1153 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1154 goto done;
1155 #endif
1157 else {
1158 CACHE_UNLOCK;
1159 cached = TRUE;
1162 else {
1163 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1164 memset(line, 0, strlen(line));
1167 done:
1168 return save_command_finalize(ctx, shakey, cached);
1171 static int delete_command(assuan_context_t ctx, char *line)
1173 struct client_s *client = assuan_get_pointer(ctx);
1174 gchar **req;
1175 gpg_error_t rc;
1176 xmlNodePtr n;
1178 rc = file_modified(client);
1180 if (rc)
1181 return send_error(ctx, rc);
1183 if (strchr(line, '\t'))
1184 req = split_input_line(line, "\t", -1);
1185 else
1186 req = split_input_line(line, " ", -1);
1188 if (!req || !*req)
1189 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1191 n = find_account(client->doc, &req, &rc, NULL, 0);
1193 if (!n) {
1194 g_strfreev(req);
1195 return send_error(ctx, rc);
1199 * No sub-node defined. Remove the entire node (account).
1201 if (!req[1]) {
1202 if (n) {
1203 xmlUnlinkNode(n);
1204 xmlFreeNode(n);
1207 g_strfreev(req);
1208 return send_error(ctx, 0);
1211 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1212 g_strfreev(req);
1214 if (!n)
1215 return send_error(ctx, rc);
1217 if (n) {
1218 xmlUnlinkNode(n);
1219 xmlFreeNode(n);
1222 return send_error(ctx, 0);
1226 * Don't return with assuan_process_done() here. This has been called from
1227 * assuan_process_next() and the command should be finished in
1228 * client_thread().
1230 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1231 gsize len)
1233 assuan_context_t ctx = data;
1234 struct client_s *client = assuan_get_pointer(ctx);
1235 gchar **req;
1236 xmlNodePtr n;
1237 gpg_error_t rc = file_modified(client);
1239 if (assuan_rc || rc) {
1240 if (line)
1241 #ifndef MEM_DEBUG
1242 xfree(line);
1243 #else
1244 free(line);
1245 #endif
1246 return assuan_rc ? assuan_rc : rc;
1249 req = split_input_line((gchar *)line, "\t", 0);
1250 #ifndef MEM_DEBUG
1251 xfree(line);
1252 #else
1253 free(line);
1254 #endif
1256 if (!req || !*req)
1257 return EPWMD_COMMAND_SYNTAX;
1259 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1260 g_strfreev(req);
1261 return EPWMD_INVALID_ELEMENT;
1264 if (valid_element_path(req+1, TRUE) == FALSE) {
1265 g_strfreev(req);
1266 return EPWMD_INVALID_ELEMENT;
1269 again:
1270 n = find_account(client->doc, &req, &rc, NULL, 0);
1272 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1273 rc = new_account(client->doc, *req);
1275 if (rc) {
1276 g_strfreev(req);
1277 return rc;
1280 goto again;
1283 if (!n) {
1284 g_strfreev(req);
1285 return rc;
1288 if (req[1]) {
1289 if (!n->children)
1290 create_elements_cb(n, req+1, &rc, NULL);
1291 else
1292 find_elements(client->doc, n->children, req+1, &rc,
1293 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1296 g_strfreev(req);
1297 client->inquire_status = INQUIRE_DONE;
1298 return rc;
1301 static int store_command(assuan_context_t ctx, char *line)
1303 struct client_s *client = assuan_get_pointer(ctx);
1304 gpg_error_t rc = file_modified(client);
1306 if (rc)
1307 return send_error(ctx, rc);
1309 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1311 if (rc)
1312 return send_error(ctx, rc);
1314 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1315 client->inquire_status = INQUIRE_BUSY;
1316 return 0;
1319 static int get_command(assuan_context_t ctx, char *line)
1321 struct client_s *client = assuan_get_pointer(ctx);
1322 gchar **req;
1323 gpg_error_t rc;
1324 xmlNodePtr n;
1326 rc = file_modified(client);
1328 if (rc)
1329 return send_error(ctx, rc);
1331 req = split_input_line(line, "\t", -1);
1333 if (!req || !*req) {
1334 g_strfreev(req);
1335 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1338 n = find_account(client->doc, &req, &rc, NULL, 0);
1340 if (!n) {
1341 g_strfreev(req);
1342 return send_error(ctx, rc);
1345 if (req[1])
1346 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1348 g_strfreev(req);
1350 if (rc)
1351 return send_error(ctx, rc);
1353 if (!n || !n->children)
1354 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1356 n = find_text_node(n->children);
1358 if (!n || !n->content || !*n->content)
1359 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1361 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1362 return send_error(ctx, rc);
1365 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1366 gpg_error_t *rc, gchar **req_orig, void *data)
1368 gchar *path = *(gchar **)data;
1369 gchar *tmp = NULL, *result;
1371 if (path) {
1372 g_free(path);
1373 *(gchar **)data = NULL;
1376 path = g_strjoinv("\t", target);
1378 if (!path) {
1379 *rc = gpg_error_from_errno(ENOMEM);
1380 return NULL;
1383 if (req_orig) {
1384 tmp = g_strjoinv("\t", req_orig);
1386 if (!tmp) {
1387 g_free(path);
1388 *rc = gpg_error_from_errno(ENOMEM);
1389 return NULL;
1393 if (tmp && *tmp)
1394 result = g_strdup_printf("%s\t%s", path, tmp);
1395 else
1396 result = g_strdup(path);
1398 if (!result) {
1399 *rc = gpg_error_from_errno(ENOMEM);
1400 g_free(path);
1401 g_free(tmp);
1402 return NULL;
1405 g_free(path);
1406 g_free(tmp);
1407 *(gchar **)data = result;
1408 return node;
1411 static int realpath_command(assuan_context_t ctx, char *line)
1413 gpg_error_t rc;
1414 struct client_s *client = assuan_get_pointer(ctx);
1415 gchar **req;
1416 gchar *t;
1417 gint i;
1418 xmlNodePtr n;
1419 GString *string;
1420 gchar *rp = NULL;
1422 rc = file_modified(client);
1424 if (rc)
1425 return send_error(ctx, rc);
1427 if (strchr(line, '\t') != NULL) {
1428 if ((req = split_input_line(line, "\t", 0)) == NULL)
1429 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1431 else {
1432 if ((req = split_input_line(line, " ", 0)) == NULL)
1433 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1436 n = find_account(client->doc, &req, &rc, NULL, 0);
1438 if (!n) {
1439 g_strfreev(req);
1440 return send_error(ctx, rc);
1443 rp = g_strjoinv("\t", req);
1445 if (!rp) {
1446 g_strfreev(req);
1447 return send_syserror(ctx, ENOMEM);
1450 if (req[1]) {
1451 n = find_elements(client->doc, n->children, req+1, &rc,
1452 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1454 if (!n) {
1455 g_free(rp);
1456 g_strfreev(req);
1457 return send_error(ctx, rc);
1461 string = g_string_new(rp);
1462 g_free(rp);
1463 g_strfreev(req);
1465 if (!string)
1466 return send_syserror(ctx, ENOMEM);
1468 again:
1469 for (i = 0, t = string->str + i; *t; t++, i++) {
1470 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1471 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1472 goto again;
1476 rc = assuan_send_data(ctx, string->str, string->len);
1477 g_string_free(string, TRUE);
1478 return send_error(ctx, rc);
1481 static int list_command(assuan_context_t ctx, char *line)
1483 struct client_s *client = assuan_get_pointer(ctx);
1484 gpg_error_t rc;
1485 struct element_list_s *elements = NULL;
1486 gchar *tmp;
1488 if (disable_list_and_dump == TRUE)
1489 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1491 rc = file_modified(client);
1493 if (rc)
1494 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 %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 return send_error(ctx, rc);
2060 req = split_input_line(line, " ", 4);
2062 if (!req || !req[0] || !req[1]) {
2063 g_strfreev(req);
2064 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2067 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2068 rc = attribute_set(client, req+1);
2069 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2070 rc = attribute_get(ctx, req+1);
2071 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2072 rc = attribute_delete(client, req+1);
2073 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2074 rc = attribute_list(ctx, req+1);
2075 else
2076 rc = EPWMD_COMMAND_SYNTAX;
2078 g_strfreev(req);
2079 return send_error(ctx, rc);
2082 static int iscached_command(assuan_context_t ctx, char *line)
2084 gchar **req = split_input_line(line, " ", 0);
2085 guchar md5file[16];
2087 if (!req || !*req) {
2088 g_strfreev(req);
2089 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2092 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2093 g_strfreev(req);
2094 CACHE_LOCK(ctx);
2096 if (cache_iscached(md5file) == FALSE) {
2097 CACHE_UNLOCK;
2098 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2101 CACHE_UNLOCK;
2102 return send_error(ctx, 0);
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 return send_error(ctx, rc);
2181 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2183 if (!xml)
2184 return send_syserror(ctx, ENOMEM);
2186 rc = assuan_send_data(ctx, xml, len);
2187 xmlFree(xml);
2188 return send_error(ctx, rc);
2191 static int getconfig_command(assuan_context_t ctx, gchar *line)
2193 struct client_s *client = assuan_get_pointer(ctx);
2194 gpg_error_t rc = 0;
2195 gchar filename[255]={0}, param[747]={0};
2196 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2198 if (strchr(line, ' ')) {
2199 sscanf(line, " %254[a-zA-Z] %746c", filename, param);
2200 fp = filename;
2201 paramp = param;
2204 paramp = g_ascii_strdown(paramp, -1);
2206 if (!paramp)
2207 return send_syserror(ctx, ENOMEM);
2209 if (strcmp(paramp, "key") == 0 || strcmp(paramp, "key_file") == 0) {
2210 g_free(paramp);
2211 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2214 p = get_key_file_string(fp ? fp : "global", paramp);
2215 g_free(paramp);
2217 if (!p)
2218 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2220 tmp = expand_homedir(p);
2222 if (!tmp) {
2223 g_free(p);
2224 return send_syserror(ctx, ENOMEM);
2227 g_free(p);
2228 p = tmp;
2229 rc = assuan_send_data(ctx, p, strlen(p));
2230 g_free(p);
2231 return send_error(ctx, rc);
2234 static int xpath_command(assuan_context_t ctx, gchar *line)
2236 struct client_s *client = assuan_get_pointer(ctx);
2237 gpg_error_t rc;
2238 xmlXPathContextPtr xp;
2239 xmlXPathObjectPtr result;
2240 xmlBufferPtr buf = NULL;
2241 gchar **req = NULL;
2243 rc = file_modified(client);
2245 if (rc)
2246 return send_error(ctx, rc);
2248 if (!line || !*line)
2249 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2251 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2252 if (strv_printf(&req, "%s", line) == FALSE)
2253 return send_syserror(ctx, ENOMEM);
2256 xp = xmlXPathNewContext(client->doc);
2258 if (!xp)
2259 return send_error(ctx, EPWMD_LIBXML_ERROR);
2261 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2263 if (!result) {
2264 xmlXPathFreeContext(xp);
2265 return send_error(ctx, EPWMD_LIBXML_ERROR);
2268 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2269 rc = EPWMD_EMPTY_ELEMENT;
2270 goto fail;
2273 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2274 (xmlChar *)req[1], &buf);
2276 if (rc)
2277 goto fail;
2278 else if (!req[1] && !xmlBufferLength(buf)) {
2279 rc = EPWMD_EMPTY_ELEMENT;
2280 goto fail;
2282 else if (req[1])
2283 goto fail;
2285 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2287 fail:
2288 g_strfreev(req);
2290 if (buf)
2291 xmlBufferFree(buf);
2293 if (result)
2294 xmlXPathFreeObject(result);
2296 if (xp)
2297 xmlXPathFreeContext(xp);
2299 return send_error(ctx, rc);
2302 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2303 gsize len)
2305 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2306 gpg_error_t rc = file_modified(client);
2307 gchar **req, **path = NULL, **path_orig = NULL, *content;
2308 xmlDocPtr doc;
2309 xmlNodePtr n, root, copy;
2311 if (assuan_rc || rc) {
2312 if (line)
2313 #ifndef MEM_DEBUG
2314 xfree(line);
2315 #else
2316 free(line);
2317 #endif
2318 return assuan_rc ? assuan_rc : rc;
2321 req = split_input_line((gchar *)line, " ", 2);
2322 #ifndef MEM_DEBUG
2323 xfree(line);
2324 #else
2325 free(line);
2326 #endif
2328 if (!req || !*req)
2329 return EPWMD_COMMAND_SYNTAX;
2331 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2332 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2333 return EPWMD_COMMAND_SYNTAX;
2336 content = req[1];
2338 if (!content || !*content) {
2339 rc = EPWMD_COMMAND_SYNTAX;
2340 goto fail;
2343 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2344 rc = EPWMD_INVALID_ELEMENT;
2345 goto fail;
2348 if (valid_element_path(path+1, FALSE) == FALSE) {
2349 rc = EPWMD_INVALID_ELEMENT;
2350 goto fail;
2353 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2355 if (!doc) {
2356 rc = EPWMD_LIBXML_ERROR;
2357 goto fail;
2360 root = xmlDocGetRootElement(doc);
2361 path_orig = g_strdupv(path);
2363 if (!path_orig) {
2364 xmlFreeDoc(doc);
2365 rc = gpg_error_from_errno(ENOMEM);
2366 goto fail;
2369 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2370 g_strfreev(path_orig);
2371 xmlFreeDoc(doc);
2372 rc = gpg_error_from_errno(ENOMEM);
2373 goto fail;
2376 n = find_account(client->doc, &path, &rc, NULL, 0);
2378 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2379 g_strfreev(path_orig);
2380 xmlFreeDoc(doc);
2381 goto fail;
2383 else if (!rc) {
2384 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2386 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2387 g_strfreev(path_orig);
2388 xmlFreeDoc(doc);
2389 goto fail;
2391 else if (!rc) {
2392 xmlNodePtr parent = n->parent;
2394 xmlUnlinkNode(n);
2395 xmlFreeNode(n);
2396 n = parent;
2400 g_strfreev(path);
2401 path = path_orig;
2403 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2404 n = create_element_path(client, &path, &rc);
2406 if (rc) {
2407 xmlFreeDoc(doc);
2408 goto fail;
2412 copy = xmlCopyNode(root, 1);
2413 n = xmlAddChild(n, copy);
2414 xmlFreeDoc(doc);
2416 if (!n)
2417 rc = EPWMD_LIBXML_ERROR;
2419 fail:
2420 g_strfreev(path);
2421 g_strfreev(req);
2422 client->inquire_status = INQUIRE_DONE;
2423 return rc;
2426 static int import_command(assuan_context_t ctx, gchar *line)
2428 gpg_error_t rc;
2429 struct client_s *client = assuan_get_pointer(ctx);
2431 rc = file_modified(client);
2433 if (rc)
2434 return send_error(ctx, rc);
2436 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2438 if (rc)
2439 return send_error(ctx, rc);
2441 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2442 client->inquire_status = INQUIRE_BUSY;
2443 return 0;
2446 static int lock_command(assuan_context_t ctx, gchar *line)
2448 gpg_error_t rc;
2449 struct client_s *client = assuan_get_pointer(ctx);
2451 rc = file_modified(client);
2453 if (rc)
2454 return send_error(ctx, rc);
2456 rc = lock_file_mutex(client);
2458 if (!rc)
2459 client->is_lock_cmd = TRUE;
2461 return send_error(ctx, rc);
2464 static int unlock_command(assuan_context_t ctx, gchar *line)
2466 struct client_s *client = assuan_get_pointer(ctx);
2467 gpg_error_t rc = file_modified(client);
2469 if (rc)
2470 return send_error(ctx, rc);
2472 unlock_file_mutex(client);
2473 return send_error(ctx, 0);
2476 static int getpid_command(assuan_context_t ctx, gchar *line)
2478 gpg_error_t rc;
2479 gchar buf[32];
2480 pid_t pid = getpid();
2482 print_fmt(buf, sizeof(buf), "%i", pid);
2483 rc = assuan_send_data(ctx, buf, strlen(buf));
2484 return send_error(ctx, rc);
2487 void cleanup_assuan(assuan_context_t ctx)
2489 struct client_s *cl = assuan_get_pointer(ctx);
2491 if (cl)
2492 cleanup_client(cl);
2495 static void reset_notify(assuan_context_t ctx)
2497 struct client_s *cl = assuan_get_pointer(ctx);
2499 if (cl)
2500 cleanup_client(cl);
2503 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2505 gchar name[32] = {0}, value[256] = {0};
2507 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2508 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2510 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2511 pth_attr_t attr = pth_attr_of(pth_self());
2513 log_write("OPTION CLIENT %s", line);
2514 pth_attr_set(attr, PTH_ATTR_NAME, value);
2515 pth_attr_destroy(attr);
2517 else
2518 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2520 return 0;
2523 static int option_handler(assuan_context_t ctx, const gchar *name,
2524 const gchar *value)
2526 struct client_s *client = assuan_get_pointer(ctx);
2528 if (!value || !*value)
2529 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2531 if (g_strcasecmp(name, (gchar *)"client") == 0)
2532 return parse_client_option(ctx, value);
2534 if (g_strcasecmp(name, (gchar *)"iterations") == 0) {
2535 long n;
2536 gchar *p = NULL;
2538 errno = 0;
2539 n = strtol(value, &p, 10);
2541 if (errno || (p && *p) || n < -1)
2542 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2544 g_key_file_set_integer(keyfileh, client->filename ? client->filename : "global", "iterations", n);
2545 send_status_all(STATUS_CONFIG);
2547 #ifdef WITH_PINENTRY
2548 else if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2549 g_free(client->pinentry->ttyname);
2550 client->pinentry->ttyname = g_strdup(value);
2552 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2553 g_free(client->pinentry->ttytype);
2554 client->pinentry->ttytype = g_strdup(value);
2556 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2557 g_free(client->pinentry->display);
2558 client->pinentry->display = g_strdup(value);
2560 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2561 g_free(client->pinentry->path);
2562 client->pinentry->path = g_strdup(value);
2564 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2565 g_free(client->pinentry->title);
2566 client->pinentry->title = g_strdup(value);
2568 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2569 g_free(client->pinentry->prompt);
2570 client->pinentry->prompt = g_strdup(value);
2572 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2573 g_free(client->pinentry->desc);
2574 client->pinentry->desc = g_strdup(value);
2577 * Look at client_thread() to see how this works.
2579 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2580 gchar *p = NULL;
2581 gint n = strtol(value, &p, 10);
2583 if (*p || n < 0)
2584 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2586 client->pinentry->timeout = n;
2588 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2589 gchar *p = NULL;
2590 gint n = strtol(value, &p, 10);
2592 if (*p || n < 0 || n > 1)
2593 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2595 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2597 #endif
2598 else
2599 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2601 log_write("OPTION %s=%s", name, value);
2602 return 0;
2605 gpg_error_t register_commands(assuan_context_t ctx)
2607 static struct {
2608 const gchar *name;
2609 gint (*handler)(assuan_context_t, gchar *line);
2610 } table[] = {
2611 { "OPEN", open_command },
2612 { "SAVE", save_command },
2613 { "LIST", list_command },
2614 { "REALPATH", realpath_command },
2615 { "STORE", store_command },
2616 { "DELETE", delete_command },
2617 { "GET", get_command },
2618 { "ATTR", attr_command },
2619 { "ISCACHED", iscached_command },
2620 { "CLEARCACHE", clearcache_command },
2621 { "CACHETIMEOUT", cachetimeout_command },
2622 { "GETCONFIG", getconfig_command },
2623 { "DUMP", dump_command },
2624 { "XPATH", xpath_command },
2625 { "IMPORT", import_command },
2626 { "LOCK", lock_command },
2627 { "UNLOCK", unlock_command },
2628 { "GETPID", getpid_command },
2629 { "INPUT", NULL },
2630 { "OUTPUT", NULL },
2631 { NULL, NULL }
2633 gint i, rc;
2635 for (i=0; table[i].name; i++) {
2636 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2638 if (rc)
2639 return rc;
2642 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2644 if (rc)
2645 return rc;
2647 rc = assuan_register_option_handler(ctx, option_handler);
2649 if (rc)
2650 return rc;
2652 rc = assuan_register_reset_notify(ctx, reset_notify);
2654 if (rc)
2655 return rc;
2657 return assuan_register_post_cmd_notify(ctx, command_finalize);
2660 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2661 guchar *key, gint *dst_iter)
2663 guchar *iv;
2664 void *inbuf;
2665 gsize insize, len;
2666 guchar tkey[gcrykeysize];
2667 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2668 gcry_cipher_hd_t gh;
2669 guint iter = 0, n_iter = 0;
2670 gint iter_progress = 0;
2671 void *outbuf = NULL;
2672 gint zrc = 0;
2673 glong outsize = 0;
2674 gpg_error_t rc;
2675 file_header_t file_header;
2676 gchar str[ASSUAN_LINELENGTH];
2678 if (!ctx) {
2679 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2681 if (rc)
2682 return rc;
2684 else
2685 gh = client->gh;
2687 lseek(fd, 0, SEEK_SET);
2688 insize = st.st_size - sizeof(file_header_t);
2689 iv = gcry_malloc(gcryblocksize);
2691 if (!iv) {
2692 if (!ctx)
2693 gcry_cipher_close(gh);
2695 return gpg_error_from_errno(ENOMEM);
2698 len = pth_read(fd, &file_header, sizeof(file_header_t));
2700 if (len != sizeof(file_header_t)) {
2701 len = errno;
2703 if (!ctx)
2704 gcry_cipher_close(gh);
2706 gcry_free(iv);
2707 errno = len;
2708 return gpg_error_from_errno(errno);
2711 *dst_iter = file_header.iter;
2713 /* No encryption iterations. This is a plain (gzipped) file. */
2714 if (file_header.iter == -1) {
2716 * cache_file_count() needs both .used == TRUE and a valid key in
2717 * order for it to count as a used cache entry. Fixes CACHE status
2718 * messages.
2720 memset(key, '!', gcrykeysize);
2721 insize = st.st_size - sizeof(file_header_t);
2724 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2725 inbuf = gcry_malloc(insize);
2727 if (!inbuf) {
2728 if (!ctx)
2729 gcry_cipher_close(gh);
2731 gcry_free(iv);
2732 return gpg_error_from_errno(ENOMEM);
2735 len = pth_read(fd, inbuf, insize);
2737 if (len != insize) {
2738 len = errno;
2740 if (!ctx)
2741 gcry_cipher_close(gh);
2743 gcry_free(iv);
2744 errno = len;
2745 return gpg_error_from_errno(errno);
2748 if (file_header.iter == -1)
2749 goto decompress;
2751 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2752 if (!ctx) {
2753 gcry_cipher_close(gh);
2754 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2756 else
2757 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2759 gcry_free(inbuf);
2760 gcry_free(iv);
2761 return rc;
2764 if ((rc = gcry_cipher_setkey(gh, key, gcrykeysize))) {
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);
2775 if (!ctx)
2776 gcry_cipher_close(gh);
2778 return rc;
2781 if (client && client->filename)
2782 iter_progress = get_key_file_integer(client->filename, "iteration_progress");
2784 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2785 rc = assuan_write_status(client->ctx, "DECRYPT",
2786 print_fmt(str, sizeof(str), "%i %i", 0, file_header.iter));
2788 if (rc) {
2789 gcry_free(inbuf);
2790 gcry_free(iv);
2791 return rc;
2795 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2797 if (rc) {
2798 gcry_free(inbuf);
2799 gcry_free(iv);
2800 return rc;
2803 memcpy(tkey, key, sizeof(tkey));
2804 tkey[0] ^= 1;
2806 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2807 if (!ctx) {
2808 gcry_cipher_close(gh);
2809 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2811 else
2812 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2814 memset(tkey, 0, sizeof(tkey));
2815 gcry_free(inbuf);
2816 gcry_free(iv);
2817 return rc;
2820 memset(tkey, 0, sizeof(tkey));
2822 while (iter < file_header.iter) {
2823 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2824 if (!(iter % iter_progress)) {
2825 rc = assuan_write_status(ctx, "DECRYPT",
2826 print_fmt(str, sizeof(str), "%i %i", ++n_iter * iter_progress, file_header.iter));
2828 if (rc) {
2829 gcry_free(inbuf);
2830 gcry_free(iv);
2831 return rc;
2836 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2837 if (!ctx) {
2838 gcry_cipher_close(gh);
2839 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2841 else
2842 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2844 gcry_free(inbuf);
2845 gcry_free(iv);
2846 return rc;
2849 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2851 if (rc) {
2852 if (!ctx) {
2853 gcry_cipher_close(gh);
2854 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2856 else
2857 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2859 gcry_free(inbuf);
2860 gcry_free(iv);
2861 return rc;
2864 iter++;
2865 pth_yield(NULL);
2868 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2869 rc = assuan_write_status(ctx, "DECRYPT",
2870 print_fmt(str, sizeof(str), "%i %i", file_header.iter, file_header.iter));
2872 if (rc) {
2873 gcry_free(inbuf);
2874 gcry_free(iv);
2875 return rc;
2879 gcry_free(iv);
2881 decompress:
2882 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zrc) == FALSE) {
2884 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2886 if (zrc == Z_MEM_ERROR) {
2887 gcry_free(inbuf);
2888 return gpg_error_from_errno(ENOMEM);
2890 else if (zrc != Z_DATA_ERROR) {
2891 gcry_free(inbuf);
2893 if (!ctx)
2894 gcry_cipher_close(gh);
2896 return EPWMD_BADKEY;
2899 else {
2900 gcry_free(inbuf);
2901 inbuf = outbuf;
2902 insize = outsize;
2905 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2906 gcry_free(inbuf);
2908 if (!ctx)
2909 gcry_cipher_close(gh);
2911 return EPWMD_BADKEY;
2914 if (ctx) {
2915 client->xml = inbuf;
2916 client->len = insize;
2918 else {
2919 gcry_cipher_close(gh);
2920 gcry_free(inbuf);
2923 return 0;
2927 * This is called after every Assuan command.
2929 void command_finalize(assuan_context_t ctx, gint rc)
2931 struct client_s *client = assuan_get_pointer(ctx);
2933 if (!client->is_lock_cmd)
2934 unlock_file_mutex(client);