Don't set the iterations configuration parameter when the file is a
[pwmd.git] / src / commands.c
blob4ba0215dff7126c752d1b1d77e3de0ca4b3ea9ef
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;
386 gint iter;
388 if ((fd = open_file(client->filename, &st)) == -1) {
389 /* New file. */
390 if (errno == ENOENT) {
391 if (shakey[0])
392 goto update_cache;
394 goto done;
397 rc = errno;
398 log_write("%s: %s", client->filename, strerror(errno));
399 cleanup_client(client);
400 memset(shakey, 0, sizeof(shakey));
401 return send_syserror(ctx, rc);
404 rc = try_xml_decrypt(ctx, fd, st, shakey, &iter);
405 close(fd);
407 if (rc) {
408 memset(shakey, 0, sizeof(shakey));
409 cleanup_client(client);
410 return send_error(ctx, rc);
413 update_cache:
414 CACHE_LOCK(client->ctx);
416 if (cached == FALSE) {
417 if (cache_update_key(client->md5file, shakey) == FALSE) {
418 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
419 cleanup_client(client);
420 CACHE_UNLOCK;
421 return send_error(ctx, EPWMD_MAX_SLOTS);
424 timeout = get_key_file_integer(client->filename, "cache_timeout");
425 cache_reset_timeout(client->md5file, timeout);
427 else
428 cache_set_timeout(client->md5file, -2);
430 CACHE_UNLOCK;
432 done:
433 memset(shakey, 0, sizeof(shakey));
434 rc = parse_xml(ctx);
436 if (client->xml) {
437 gcry_free(client->xml);
438 client->xml = NULL;
441 if (!rc) {
442 if (client->new == FALSE)
443 send_status_all(STATUS_CACHE);
445 client->state = STATE_OPEN;
448 if (!rc && client->new == FALSE &&
449 iter != get_key_file_integer(client->filename, "iterations")) {
450 g_key_file_set_integer(keyfileh, client->filename, "iterations", iter);
451 send_status_all(STATUS_CONFIG);
454 return send_error(ctx, rc);
457 static int open_command(assuan_context_t ctx, char *line)
459 struct stat st;
460 guchar shakey[gcrykeysize];
461 gboolean cached = FALSE;
462 gpg_error_t rc;
463 struct client_s *client = assuan_get_pointer(ctx);
464 gchar **req;
465 gchar *filename = NULL;
466 file_header_t file_header;
468 memset(shakey, 0, sizeof(shakey));
470 if ((req = split_input_line(line, " ", 2)) != NULL)
471 filename = req[0];
473 if (!filename || !*filename) {
474 g_strfreev(req);
475 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
478 if (valid_filename(filename) == FALSE) {
479 g_strfreev(req);
480 return send_error(ctx, EPWMD_INVALID_FILENAME);
483 if (client->state == STATE_OPEN)
484 cleanup_client(client);
486 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
487 CACHE_LOCK(client->ctx);
489 if (cache_has_file(client->md5file) == FALSE) {
490 if (cache_add_file(client->md5file, NULL) == FALSE) {
491 g_strfreev(req);
492 CACHE_UNLOCK;
493 return send_error(ctx, EPWMD_MAX_SLOTS);
497 cache_incr_refcount(client->md5file);
498 CACHE_UNLOCK;
499 rc = lock_file_mutex(client);
501 if (rc) {
502 g_strfreev(req);
503 return send_error(ctx, rc);
506 client->freed = FALSE;
508 if ((rc = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
509 g_strfreev(req);
510 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
511 cleanup_client(client);
512 return send_error(ctx, rc);
515 if (stat(filename, &st) == 0) {
516 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
517 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
518 g_strfreev(req);
519 cleanup_client(client);
520 return send_error(ctx, EPWMD_INVALID_FILENAME);
523 client->mtime = st.st_mtime;
526 client->filename = g_strdup(filename);
528 if (!client->filename) {
529 memset(shakey, 0, sizeof(shakey));
530 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
531 cleanup_client(client);
532 g_strfreev(req);
533 return send_syserror(ctx, ENOMEM);
536 #ifdef WITH_PINENTRY
537 client->pinentry->filename = g_strdup(client->filename);
539 if (!client->pinentry->filename) {
540 memset(shakey, 0, sizeof(shakey));
541 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
542 cleanup_client(client);
543 g_strfreev(req);
544 return send_syserror(ctx, ENOMEM);
546 #endif
549 * New files don't need a key.
551 if (access(filename, R_OK) != 0) {
552 if (errno != ENOENT) {
553 rc = errno;
554 log_write("%s: %s", filename, strerror(errno));
555 g_strfreev(req);
556 cleanup_client(client);
557 return send_syserror(ctx, rc);
560 if ((client->xml = new_document()) == NULL) {
561 log_write("%s", strerror(ENOMEM));
562 g_strfreev(req);
563 cleanup_client(client);
564 return send_syserror(ctx, ENOMEM);
567 client->len = xmlStrlen(client->xml);
568 client->new = TRUE;
569 client->filename = g_strdup(filename);
571 if (!client->filename) {
572 g_strfreev(req);
573 cleanup_client(client);
574 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
575 return send_syserror(ctx, ENOMEM);
578 memset(shakey, 0, sizeof(shakey));
580 if (req[1] && *req[1])
581 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
583 g_strfreev(req);
584 return open_command_finalize(ctx, shakey, cached);
587 rc = read_file_header(filename, &file_header);
589 if (rc) {
590 g_strfreev(req);
591 cleanup_client(client);
592 return send_error(ctx, rc);
595 if (file_header.iter == -1)
596 goto done;
598 CACHE_LOCK(client->ctx);
599 cached = cache_get_key(client->md5file, shakey);
600 CACHE_UNLOCK;
602 if (cached == FALSE) {
604 * No key specified and no matching filename found in the cache. Use
605 * pinentry to retrieve the key. Cannot return assuan_process_done()
606 * here otherwise the command will be interrupted. The event loop in
607 * client_thread() will poll the file descriptor waiting for it to
608 * become ready to read a pinentry_key_s which will contain the
609 * entered key or rc. It will then call open_command_finalize() to
610 * to finish the command.
612 if (!req[1] || !*req[1]) {
613 #ifdef WITH_PINENTRY
614 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
616 /* From set_pinentry_defaults(). */
617 if (client->pinentry->enable == FALSE ||
618 (client->pinentry->enable == -1 && b == FALSE)) {
619 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
620 goto done;
623 g_strfreev(req);
624 lock_pin_mutex(client);
625 client->pinentry->which = PINENTRY_OPEN;
626 rc = pinentry_fork(ctx);
628 if (rc) {
629 unlock_pin_mutex(client->pinentry);
630 cleanup_client(client);
631 return send_error(ctx, rc);
634 client->pinentry->cb = open_command_finalize;
635 client->pinentry->status = PINENTRY_INIT;
636 return 0;
637 #else
638 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
639 goto done;
640 #endif
643 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
646 done:
647 g_strfreev(req);
648 return open_command_finalize(ctx, shakey, cached);
651 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
652 gint size, gpointer *out, glong *outsize, gint *rc)
654 z_stream z;
655 gpointer pout, pin;
656 gz_header h;
657 gchar buf[17];
658 gint cmd = Z_NO_FLUSH;
659 gchar str[ASSUAN_LINELENGTH];
661 z.zalloc = z_alloc;
662 z.zfree = z_free;
663 z.next_in = pin = data;
664 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
665 z.avail_out = zlib_bufsize;
666 z.next_out = pout = g_malloc(zlib_bufsize);
668 if (!pout) {
669 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
670 *rc = Z_MEM_ERROR;
671 return FALSE;
674 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
676 if (*rc != Z_OK) {
677 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
678 g_free(pout);
679 return FALSE;
682 memset(&h, 0, sizeof(gz_header));
683 g_snprintf(buf, sizeof(buf), "%i", size);
684 h.comment = (guchar *)buf;
685 *rc = deflateSetHeader(&z, &h);
687 if (*rc != Z_OK) {
688 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
689 g_free(pout);
690 deflateEnd(&z);
691 return FALSE;
694 do {
695 gpointer p;
697 *rc = deflate(&z, cmd);
699 switch (*rc) {
700 case Z_OK:
701 break;
702 case Z_BUF_ERROR:
703 if (!z.avail_out) {
704 p = g_realloc(pout, z.total_out + zlib_bufsize);
706 if (!p) {
707 *rc = Z_MEM_ERROR;
708 goto fail;
711 pout = p;
712 z.next_out = pout + z.total_out;
713 z.avail_out = zlib_bufsize;
716 if (!z.avail_in && z.total_in < size) {
717 if (z.total_in + zlib_bufsize > size)
718 z.avail_in = size - z.total_in;
719 else
720 z.avail_in = zlib_bufsize;
722 if (ctx) {
723 *rc = assuan_write_status(ctx, "COMPRESS",
724 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
726 if (*rc)
727 goto fail;
731 if (z.total_in >= size)
732 cmd = Z_FINISH;
734 break;
735 case Z_STREAM_END:
736 break;
737 default:
738 goto fail;
741 pth_yield(NULL);
742 } while (*rc != Z_STREAM_END);
744 if (ctx) {
745 *rc = assuan_write_status(ctx, "COMPRESS",
746 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
748 if (*rc)
749 goto fail;
752 *out = pout;
753 *outsize = z.total_out;
754 deflateEnd(&z);
755 *rc = 0;
756 return TRUE;
758 fail:
759 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
760 g_free(pout);
761 deflateEnd(&z);
762 return FALSE;
765 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
766 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
767 gint iter)
769 gsize len = insize;
770 gint fd;
771 gpointer inbuf;
772 guchar tkey[gcrykeysize];
773 gchar *p;
774 gpg_error_t rc;
775 guint iter_progress = 0, n_iter = 0, xiter = 0;
776 gchar tmp[FILENAME_MAX];
777 struct stat st;
778 mode_t mode = 0;
779 file_header_t file_header;
780 gchar str[ASSUAN_LINELENGTH];
782 if (iter == -1) {
784 * cache_file_count() needs both .used == TRUE and a valid key in
785 * order for it to count as a used cache entry. Fixes CACHE status
786 * messages.
788 memset(shakey, '!', gcrykeysize);
789 inbuf = data;
790 file_header.iter = iter;
791 goto write_file;
794 if (insize / gcryblocksize) {
795 len = (insize / gcryblocksize) * gcryblocksize;
797 if (insize % gcryblocksize)
798 len += gcryblocksize;
802 * Resize the existing xml buffer to the block size required by gcrypt
803 * rather than duplicating it and wasting memory.
805 inbuf = gcry_realloc(data, len);
807 if (!inbuf)
808 return gpg_error_from_errno(ENOMEM);
810 insize = len;
811 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
812 memcpy(tkey, shakey, sizeof(tkey));
813 tkey[0] ^= 1;
815 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
816 memset(tkey, 0, sizeof(tkey));
817 gcry_free(inbuf);
818 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
819 return rc;
822 memset(tkey, 0, sizeof(tkey));
823 file_header.iter = iter;
825 if (client)
826 iter_progress = get_key_file_integer(client->filename, "iteration_progress");
828 if (client && iter_progress && file_header.iter >= iter_progress) {
829 rc = assuan_write_status(client->ctx, "ENCRYPT",
830 print_fmt(str, sizeof(str), "%i %i", 0, file_header.iter));
832 if (rc) {
833 gcry_free(inbuf);
834 return rc;
838 while (xiter < file_header.iter) {
839 if (client && iter_progress > 0 && xiter >= iter_progress) {
840 if (!(xiter % iter_progress)) {
841 rc = assuan_write_status(client->ctx, "ENCRYPT",
842 print_fmt(str, sizeof(str), "%i %i", ++n_iter * iter_progress, file_header.iter));
844 if (rc) {
845 gcry_free(inbuf);
846 return rc;
851 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
852 sizeof(file_header.iv)))) {
853 gcry_free(inbuf);
854 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
855 return rc;
858 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
859 == FALSE) {
860 gcry_free(inbuf);
861 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
862 return rc;
865 xiter++;
866 pth_yield(NULL);
869 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
870 sizeof(file_header.iv)))) {
871 gcry_free(inbuf);
872 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
873 return rc;
876 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
877 gcry_free(inbuf);
878 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
879 return rc;
882 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
883 gcry_free(inbuf);
884 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
885 return rc;
888 if (client && iter_progress && file_header.iter >= iter_progress) {
889 rc = assuan_write_status(client->ctx, "ENCRYPT",
890 print_fmt(str, sizeof(str), "%i %i", file_header.iter, file_header.iter));
892 if (rc) {
893 gcry_free(inbuf);
894 return rc;
898 write_file:
899 if (filename) {
900 if (stat(filename, &st) == 0) {
901 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
904 * FIXME What if the file has an ACL?
906 if (!(mode & S_IWUSR)) {
907 gcry_free(inbuf);
908 return gpg_error_from_errno(EACCES);
911 else {
912 if (errno != ENOENT) {
913 rc = errno;
914 gcry_free(inbuf);
915 return gpg_error_from_errno(rc);
919 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
921 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
922 rc = errno;
923 gcry_free(inbuf);
924 p = strrchr(tmp, '/');
925 p++;
926 log_write("%s: %s", p, strerror(rc));
927 return gpg_error_from_errno(rc);
930 else
932 * xml_import() from command line.
934 fd = STDOUT_FILENO;
936 len = pth_write(fd, &file_header, sizeof(file_header_t));
938 if (len != sizeof(file_header)) {
939 len = errno;
941 if (filename) {
942 close(fd);
943 unlink(tmp);
946 gcry_free(inbuf);
947 return gpg_error_from_errno(len);
950 len = pth_write(fd, inbuf, insize);
952 if (len != insize) {
953 len = errno;
955 if (filename) {
956 close(fd);
957 unlink(tmp);
960 gcry_free(inbuf);
961 return gpg_error_from_errno(len);
964 if (fsync(fd) == -1) {
965 len = errno;
967 if (filename) {
968 close(fd);
969 unlink(tmp);
972 gcry_free(inbuf);
973 return gpg_error_from_errno(len);
976 if (filename) {
977 close(fd);
979 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
980 gchar tmp2[FILENAME_MAX];
982 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
984 if (rename(filename, tmp2) == -1) {
985 unlink(tmp);
986 len = errno;
987 gcry_free(inbuf);
988 return gpg_error_from_errno(len);
992 if (rename(tmp, filename) == -1) {
993 len = errno;
994 unlink(tmp);
995 gcry_free(inbuf);
996 return gpg_error_from_errno(len);
999 if (mode)
1000 chmod(filename, mode);
1003 gcry_free(inbuf);
1004 return 0;
1007 static gpg_error_t save_command_finalize(assuan_context_t ctx,
1008 guchar shakey[], gboolean cached)
1010 struct client_s *client = assuan_get_pointer(ctx);
1011 gpointer xmlbuf;
1012 xmlChar *p;
1013 gint len;
1014 gint iter;
1015 gint timeout;
1016 gpointer outbuf;
1017 glong outsize = 0;
1018 gint zrc;
1019 gpg_error_t rc;
1020 struct stat st;
1022 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
1023 xmlbuf = p;
1025 iter = get_key_file_integer(client->filename, "compression_level");
1027 if (iter < 0)
1028 iter = 0;
1030 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
1031 memset(shakey, 0, sizeof(shakey));
1032 xmlFree(xmlbuf);
1034 if (zrc == Z_MEM_ERROR) {
1035 return send_syserror(ctx, ENOMEM);
1037 else
1038 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1040 else {
1041 gcry_free(xmlbuf);
1042 xmlbuf = outbuf;
1043 len = outsize;
1046 iter = get_key_file_integer(client->filename, "iterations");
1047 rc = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1049 if (rc) {
1050 memset(shakey, 0, sizeof(shakey));
1051 return send_error(ctx, rc);
1054 stat(client->filename, &st);
1055 client->mtime = st.st_mtime;
1056 timeout = get_key_file_integer(client->filename, "cache_timeout");
1057 CACHE_LOCK(client->ctx);
1059 if (cached) {
1060 memset(shakey, 0, sizeof(shakey));
1061 cache_reset_timeout(client->md5file, timeout);
1062 CACHE_UNLOCK;
1064 if (client->new == TRUE)
1065 send_status_all(STATUS_CACHE);
1067 client->new = FALSE;
1068 return send_error(ctx, 0);
1071 if (cache_update_key(client->md5file, shakey) == FALSE) {
1072 memset(shakey, 0, sizeof(shakey));
1073 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1074 CACHE_UNLOCK;
1075 return send_error(ctx, EPWMD_MAX_SLOTS);
1078 client->new = FALSE;
1079 memset(shakey, 0, sizeof(shakey));
1080 cache_reset_timeout(client->md5file, timeout);
1081 CACHE_UNLOCK;
1082 send_status_all(STATUS_CACHE);
1083 return send_error(ctx, 0);
1086 static int save_command(assuan_context_t ctx, char *line)
1088 gboolean cached = FALSE;
1089 guchar shakey[gcrykeysize];
1090 struct stat st;
1091 struct client_s *client = assuan_get_pointer(ctx);
1092 gpg_error_t rc;
1094 memset(shakey, 0, sizeof(shakey));
1095 rc = file_modified(client);
1097 if (rc) {
1098 log_write("%s: %s", client->filename ? client->filename : "",
1099 pwmd_strerror(rc));
1100 return send_error(ctx, rc);
1103 rc = lock_file_mutex(client);
1105 if (rc)
1106 return send_error(ctx, rc);
1108 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1109 return send_syserror(ctx, errno);
1111 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1112 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1113 return send_error(ctx, EPWMD_INVALID_FILENAME);
1116 if (get_key_file_integer(client->filename, "iterations") == -1)
1117 goto done;
1119 if (!line || !*line) {
1120 guchar tmp[sizeof(shakey)];
1121 CACHE_LOCK(ctx);
1123 memset(tmp, '!', sizeof(tmp));
1125 if (cache_get_key(client->md5file, shakey) == FALSE ||
1126 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1127 CACHE_UNLOCK;
1128 #ifdef WITH_PINENTRY
1129 if (get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1130 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1131 goto done;
1134 lock_pin_mutex(client);
1135 client->pinentry->which = PINENTRY_SAVE;
1136 rc = pinentry_fork(ctx);
1138 if (rc) {
1139 unlock_pin_mutex(client->pinentry);
1140 return send_error(ctx, rc);
1143 client->pinentry->cb = save_command_finalize;
1144 client->pinentry->status = PINENTRY_INIT;
1145 return 0;
1146 #else
1147 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1148 goto done;
1149 #endif
1151 else {
1152 CACHE_UNLOCK;
1153 cached = TRUE;
1156 else {
1157 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1158 memset(line, 0, strlen(line));
1161 done:
1162 return save_command_finalize(ctx, shakey, cached);
1165 static int delete_command(assuan_context_t ctx, char *line)
1167 struct client_s *client = assuan_get_pointer(ctx);
1168 gchar **req;
1169 gpg_error_t rc;
1170 xmlNodePtr n;
1172 rc = file_modified(client);
1174 if (rc) {
1175 log_write("%s: %s", client->filename ? client->filename : "",
1176 pwmd_strerror(rc));
1177 return send_error(ctx, rc);
1180 if (strchr(line, '\t'))
1181 req = split_input_line(line, "\t", -1);
1182 else
1183 req = split_input_line(line, " ", -1);
1185 if (!req || !*req)
1186 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1188 n = find_account(client->doc, &req, &rc, NULL, 0);
1190 if (!n) {
1191 g_strfreev(req);
1192 return send_error(ctx, rc);
1196 * No sub-node defined. Remove the entire node (account).
1198 if (!req[1]) {
1199 if (n) {
1200 xmlUnlinkNode(n);
1201 xmlFreeNode(n);
1204 g_strfreev(req);
1205 return send_error(ctx, 0);
1208 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1209 g_strfreev(req);
1211 if (!n)
1212 return send_error(ctx, rc);
1214 if (n) {
1215 xmlUnlinkNode(n);
1216 xmlFreeNode(n);
1219 return send_error(ctx, 0);
1223 * Don't return with assuan_process_done() here. This has been called from
1224 * assuan_process_next() and the command should be finished in
1225 * client_thread().
1227 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1228 gsize len)
1230 assuan_context_t ctx = data;
1231 struct client_s *client = assuan_get_pointer(ctx);
1232 gchar **req;
1233 xmlNodePtr n;
1234 gpg_error_t rc = file_modified(client);
1236 if (assuan_rc || rc) {
1237 if (line)
1238 #ifndef MEM_DEBUG
1239 xfree(line);
1240 #else
1241 free(line);
1242 #endif
1243 return assuan_rc ? assuan_rc : rc;
1246 req = split_input_line((gchar *)line, "\t", 0);
1247 #ifndef MEM_DEBUG
1248 xfree(line);
1249 #else
1250 free(line);
1251 #endif
1253 if (!req || !*req)
1254 return EPWMD_COMMAND_SYNTAX;
1256 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1257 g_strfreev(req);
1258 return EPWMD_INVALID_ELEMENT;
1261 if (valid_element_path(req+1, TRUE) == FALSE) {
1262 g_strfreev(req);
1263 return EPWMD_INVALID_ELEMENT;
1266 again:
1267 n = find_account(client->doc, &req, &rc, NULL, 0);
1269 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1270 rc = new_account(client->doc, *req);
1272 if (rc) {
1273 g_strfreev(req);
1274 return rc;
1277 goto again;
1280 if (!n) {
1281 g_strfreev(req);
1282 return rc;
1285 if (req[1]) {
1286 if (!n->children)
1287 create_elements_cb(n, req+1, &rc, NULL);
1288 else
1289 find_elements(client->doc, n->children, req+1, &rc,
1290 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1293 g_strfreev(req);
1294 client->inquire_status = INQUIRE_DONE;
1295 return rc;
1298 static int store_command(assuan_context_t ctx, char *line)
1300 struct client_s *client = assuan_get_pointer(ctx);
1301 gpg_error_t rc = file_modified(client);
1303 if (rc) {
1304 log_write("%s: %s", client->filename ? client->filename : "",
1305 pwmd_strerror(rc));
1306 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 log_write("%s: %s", client->filename ? client->filename : "",
1330 pwmd_strerror(rc));
1331 return send_error(ctx, rc);
1334 req = split_input_line(line, "\t", -1);
1336 if (!req || !*req) {
1337 g_strfreev(req);
1338 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1341 n = find_account(client->doc, &req, &rc, NULL, 0);
1343 if (!n) {
1344 g_strfreev(req);
1345 return send_error(ctx, rc);
1348 if (req[1])
1349 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1351 g_strfreev(req);
1353 if (rc)
1354 return send_error(ctx, rc);
1356 if (!n || !n->children)
1357 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1359 n = find_text_node(n->children);
1361 if (!n || !n->content || !*n->content)
1362 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1364 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1365 return send_error(ctx, rc);
1368 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1369 gpg_error_t *rc, gchar **req_orig, void *data)
1371 gchar *path = *(gchar **)data;
1372 gchar *tmp = NULL, *result;
1374 if (path) {
1375 g_free(path);
1376 *(gchar **)data = NULL;
1379 path = g_strjoinv("\t", target);
1381 if (!path) {
1382 *rc = gpg_error_from_errno(ENOMEM);
1383 return NULL;
1386 if (req_orig) {
1387 tmp = g_strjoinv("\t", req_orig);
1389 if (!tmp) {
1390 g_free(path);
1391 *rc = gpg_error_from_errno(ENOMEM);
1392 return NULL;
1396 if (tmp && *tmp)
1397 result = g_strdup_printf("%s\t%s", path, tmp);
1398 else
1399 result = g_strdup(path);
1401 if (!result) {
1402 *rc = gpg_error_from_errno(ENOMEM);
1403 g_free(path);
1404 g_free(tmp);
1405 return NULL;
1408 g_free(path);
1409 g_free(tmp);
1410 *(gchar **)data = result;
1411 return node;
1414 static int realpath_command(assuan_context_t ctx, char *line)
1416 gpg_error_t rc;
1417 struct client_s *client = assuan_get_pointer(ctx);
1418 gchar **req;
1419 gchar *t;
1420 gint i;
1421 xmlNodePtr n;
1422 GString *string;
1423 gchar *rp = NULL;
1425 rc = file_modified(client);
1427 if (rc) {
1428 log_write("%s: %s", client->filename ? client->filename : "",
1429 pwmd_strerror(rc));
1430 return send_error(ctx, rc);
1433 if (strchr(line, '\t') != NULL) {
1434 if ((req = split_input_line(line, "\t", 0)) == NULL)
1435 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1437 else {
1438 if ((req = split_input_line(line, " ", 0)) == NULL)
1439 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1442 n = find_account(client->doc, &req, &rc, NULL, 0);
1444 if (!n) {
1445 g_strfreev(req);
1446 return send_error(ctx, rc);
1449 rp = g_strjoinv("\t", req);
1451 if (!rp) {
1452 g_strfreev(req);
1453 return send_syserror(ctx, ENOMEM);
1456 if (req[1]) {
1457 n = find_elements(client->doc, n->children, req+1, &rc,
1458 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1460 if (!n) {
1461 g_free(rp);
1462 g_strfreev(req);
1463 return send_error(ctx, rc);
1467 string = g_string_new(rp);
1468 g_free(rp);
1469 g_strfreev(req);
1471 if (!string)
1472 return send_syserror(ctx, ENOMEM);
1474 again:
1475 for (i = 0, t = string->str + i; *t; t++, i++) {
1476 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1477 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1478 goto again;
1482 rc = assuan_send_data(ctx, string->str, string->len);
1483 g_string_free(string, TRUE);
1484 return send_error(ctx, rc);
1487 static int list_command(assuan_context_t ctx, char *line)
1489 struct client_s *client = assuan_get_pointer(ctx);
1490 gpg_error_t rc;
1491 struct element_list_s *elements = NULL;
1492 gchar *tmp;
1494 if (disable_list_and_dump == TRUE)
1495 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1497 rc = file_modified(client);
1499 if (rc) {
1500 log_write("%s: %s", client->filename, pwmd_strerror(rc));
1501 return send_error(ctx, rc);
1504 if (!*line) {
1505 GString *str;
1507 rc = list_accounts(client->doc, &str);
1509 if (rc)
1510 return send_error(ctx, rc);
1512 rc = assuan_send_data(ctx, str->str, str->len);
1513 g_string_free(str, TRUE);
1514 return send_error(ctx, rc);
1517 elements = g_malloc0(sizeof(struct element_list_s));
1519 if (!elements) {
1520 rc = gpg_err_code_from_errno(ENOMEM);
1521 goto fail;
1524 rc = create_path_list(client->doc, elements, line);
1526 if (rc)
1527 goto fail;
1529 if (elements) {
1530 gint total = g_slist_length(elements->list);
1531 gint i;
1532 GString *str;
1534 if (!total) {
1535 rc = EPWMD_EMPTY_ELEMENT;
1536 goto fail;
1539 str = g_string_new(NULL);
1541 if (!str) {
1542 rc = gpg_err_code_from_errno(ENOMEM);
1543 goto fail;
1546 for (i = 0; i < total; i++) {
1547 tmp = g_slist_nth_data(elements->list, i);
1548 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1551 rc = assuan_send_data(ctx, str->str, str->len);
1552 g_string_free(str, TRUE);
1554 else
1555 rc = EPWMD_EMPTY_ELEMENT;
1557 fail:
1558 if (elements) {
1559 gint total = g_slist_length(elements->list);
1560 gint i;
1562 for (i = 0; i < total; i++) {
1563 tmp = g_slist_nth_data(elements->list, i);
1564 g_free(tmp);
1567 g_slist_free(elements->list);
1569 if (elements->prefix)
1570 g_free(elements->prefix);
1572 g_free(elements);
1575 return send_error(ctx, rc);
1578 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1579 const gchar *value)
1581 xmlAttrPtr a;
1583 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1584 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1586 if (!a)
1587 return EPWMD_LIBXML_ERROR;
1589 else
1590 xmlNodeSetContent(a->children, (xmlChar *)value);
1592 return 0;
1596 * req[0] - element path
1598 static int attribute_list(assuan_context_t ctx, gchar **req)
1600 struct client_s *client = assuan_get_pointer(ctx);
1601 gchar **attrlist = NULL;
1602 gint i = 0;
1603 gchar **path = NULL;
1604 xmlAttrPtr a;
1605 xmlNodePtr n, an;
1606 gchar *line;
1607 gpg_error_t rc;
1609 if (!req || !req[0])
1610 return EPWMD_COMMAND_SYNTAX;
1612 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1614 * The first argument may be only an account.
1616 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1617 return EPWMD_COMMAND_SYNTAX;
1620 n = find_account(client->doc, &path, &rc, NULL, 0);
1622 if (!n) {
1623 g_strfreev(path);
1624 return rc;
1627 if (path[1]) {
1628 n = find_elements(client->doc, n->children, path+1, &rc,
1629 NULL, NULL, NULL, FALSE, 0, NULL);
1631 if (!n) {
1632 g_strfreev(path);
1633 return rc;
1637 g_strfreev(path);
1639 for (a = n->properties; a; a = a->next) {
1640 gchar **pa;
1642 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1643 if (attrlist)
1644 g_strfreev(attrlist);
1646 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1647 return gpg_error_from_errno(ENOMEM);
1650 attrlist = pa;
1651 an = a->children;
1652 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1654 if (!attrlist[i]) {
1655 g_strfreev(attrlist);
1656 return gpg_error_from_errno(ENOMEM);
1659 attrlist[++i] = NULL;
1662 if (!attrlist)
1663 return EPWMD_EMPTY_ELEMENT;
1665 line = g_strjoinv("\n", attrlist);
1667 if (!line) {
1668 g_strfreev(attrlist);
1669 return gpg_error_from_errno(ENOMEM);
1672 rc = assuan_send_data(ctx, line, strlen(line));
1673 g_free(line);
1674 g_strfreev(attrlist);
1675 return rc;
1679 * req[0] - attribute
1680 * req[1] - element path
1682 static int attribute_delete(struct client_s *client, gchar **req)
1684 xmlAttrPtr a;
1685 xmlNodePtr n;
1686 gchar **path = NULL;
1687 gpg_error_t rc;
1689 if (!req || !req[0] || !req[1])
1690 return EPWMD_COMMAND_SYNTAX;
1692 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1694 * The first argument may be only an account.
1696 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1697 return EPWMD_COMMAND_SYNTAX;
1701 * Don't remove the "name" attribute for the account element. To remove an
1702 * account use DELETE <account>.
1704 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1705 rc = EPWMD_ATTR_SYNTAX;
1706 goto fail;
1709 n = find_account(client->doc, &path, &rc, NULL, 0);
1711 if (!n)
1712 goto fail;
1714 if (path[1]) {
1715 n = find_elements(client->doc, n->children, path+1, &rc,
1716 NULL, NULL, NULL, FALSE, 0, NULL);
1718 if (!n)
1719 goto fail;
1722 g_strfreev(path);
1724 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1725 return EPWMD_ATTR_NOT_FOUND;
1727 if (xmlRemoveProp(a) == -1)
1728 return EPWMD_LIBXML_ERROR;
1730 return 0;
1732 fail:
1733 g_strfreev(path);
1734 return rc;
1737 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1738 gpg_error_t *rc)
1740 gchar **src = *path;
1741 gchar **src_orig = g_strdupv(src);
1742 xmlNodePtr n = NULL;
1744 *rc = 0;
1746 if (!src_orig) {
1747 *rc = gpg_error_from_errno(ENOMEM);
1748 goto fail;
1751 again:
1752 n = find_account(client->doc, &src, rc, NULL, 0);
1754 if (!n) {
1755 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1756 *rc = new_account(client->doc, src[0]);
1758 if (*rc)
1759 goto fail;
1761 goto again;
1763 else
1764 goto fail;
1767 if (src[1]) {
1768 if (!n->children)
1769 n = create_target_elements_cb(n, src+1, rc, NULL);
1770 else
1771 n = find_elements(client->doc, n->children, src+1, rc,
1772 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1774 if (!n)
1775 goto fail;
1778 * Reset the position of the element tree now that the elements
1779 * have been created.
1781 g_strfreev(src);
1782 src = src_orig;
1783 src_orig = NULL;
1784 n = find_account(client->doc, &src, rc, NULL, 0);
1786 if (!n)
1787 goto fail;
1789 n = find_elements(client->doc, n->children, src+1, rc,
1790 NULL, NULL, NULL, FALSE, 0, NULL);
1792 if (!n)
1793 goto fail;
1796 fail:
1797 if (src_orig)
1798 g_strfreev(src_orig);
1800 *path = src;
1801 return n;
1805 * Creates a "target" attribute. When other commands encounter an element with
1806 * this attribute, the element path is modified to the target value. If the
1807 * source element path doesn't exist when using 'ATTR SET target', it is
1808 * created, but the destination element path must exist.
1810 * req[0] - source element path
1811 * req[1] - destination element path
1813 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1815 gchar **src, **dst, *line = NULL;
1816 gpg_error_t rc;
1817 xmlNodePtr n;
1819 if (!req || !req[0] || !req[1])
1820 return EPWMD_COMMAND_SYNTAX;
1822 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1824 * The first argument may be only an account.
1826 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1827 return EPWMD_COMMAND_SYNTAX;
1830 if (valid_element_path(src, FALSE) == FALSE) {
1831 g_strfreev(src);
1832 return EPWMD_INVALID_ELEMENT;
1835 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1837 * The first argument may be only an account.
1839 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1840 rc = EPWMD_COMMAND_SYNTAX;
1841 goto fail;
1845 n = find_account(client->doc, &dst, &rc, NULL, 0);
1848 * Make sure the destination element path exists.
1850 if (!n)
1851 goto fail;
1853 if (dst[1]) {
1854 n = find_elements(client->doc, n->children, dst+1, &rc,
1855 NULL, NULL, NULL, FALSE, 0, NULL);
1857 if (!n)
1858 goto fail;
1861 n = create_element_path(client, &src, &rc);
1863 if (rc)
1864 goto fail;
1866 line = g_strjoinv("\t", dst);
1868 if (!line) {
1869 rc = gpg_error_from_errno(ENOMEM);
1870 goto fail;
1873 rc = add_attribute(n, "target", line);
1875 fail:
1876 g_free(line);
1877 g_strfreev(src);
1878 g_strfreev(dst);
1879 return rc;
1883 * req[0] - account name
1884 * req[1] - new name
1886 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
1888 gpg_error_t rc;
1889 gchar **tmp;
1890 xmlNodePtr n;
1892 tmp = g_strdupv(req);
1894 if (!tmp)
1895 return gpg_error_from_errno(ENOMEM);
1897 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1898 g_strfreev(tmp);
1900 if (!n)
1901 return rc;
1903 if (g_utf8_collate(req[0], req[1]) == 0)
1904 return 0;
1907 * Will not overwrite an existing account.
1909 tmp = g_strdupv(req+1);
1911 if (!tmp)
1912 return gpg_error_from_errno(ENOMEM);
1914 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1915 g_strfreev(tmp);
1917 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
1918 return rc;
1920 if (n)
1921 return EPWMD_ACCOUNT_EXISTS;
1924 * Whitespace not allowed in account names.
1926 if (contains_whitespace(req[1]) == TRUE)
1927 return EPWMD_ATTR_SYNTAX;
1929 tmp = g_strdupv(req);
1931 if (!tmp)
1932 return gpg_error_from_errno(ENOMEM);
1934 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1935 g_strfreev(tmp);
1937 if (!n)
1938 return EPWMD_ELEMENT_NOT_FOUND;
1940 return add_attribute(n, "name", req[1]);
1944 * req[0] - attribute
1945 * req[1] - element path
1947 static int attribute_get(assuan_context_t ctx, gchar **req)
1949 struct client_s *client = assuan_get_pointer(ctx);
1950 xmlNodePtr n;
1951 xmlChar *a;
1952 gchar **path= NULL;
1953 gpg_error_t rc;
1955 if (!req || !req[0] || !req[1])
1956 return EPWMD_COMMAND_SYNTAX;
1958 if (strchr(req[1], '\t')) {
1959 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
1960 return EPWMD_COMMAND_SYNTAX;
1962 else {
1963 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1964 return EPWMD_COMMAND_SYNTAX;
1967 n = find_account(client->doc, &path, &rc, NULL, 0);
1969 if (!n)
1970 goto fail;
1972 if (path[1]) {
1973 n = find_elements(client->doc, n->children, path+1, &rc,
1974 NULL, NULL, NULL, FALSE, 0, NULL);
1976 if (!n)
1977 goto fail;
1980 g_strfreev(path);
1982 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
1983 return EPWMD_ATTR_NOT_FOUND;
1985 rc = assuan_send_data(ctx, a, xmlStrlen(a));
1986 xmlFree(a);
1987 return rc;
1989 fail:
1990 g_strfreev(path);
1991 return rc;
1995 * req[0] - attribute
1996 * req[1] - element path
1997 * req[2] - value
1999 static int attribute_set(struct client_s *client, gchar **req)
2001 gchar **path = NULL;
2002 gpg_error_t rc;
2003 xmlNodePtr n;
2005 if (!req || !req[0] || !req[1] || !req[2])
2006 return EPWMD_COMMAND_SYNTAX;
2009 * Reserved attribute names.
2011 if (g_utf8_collate(req[0], "name") == 0) {
2013 * Only reserved for the account element. Not the rest of the
2014 * document.
2016 if (strchr(req[1], '\t') == NULL)
2017 return name_attribute(client, req + 1);
2019 else if (g_utf8_collate(req[0], "target") == 0)
2020 return target_attribute(client, req + 1);
2022 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2024 * The first argument may be only an account.
2026 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2027 return EPWMD_COMMAND_SYNTAX;
2030 n = find_account(client->doc, &path, &rc, NULL, 0);
2032 if (!n)
2033 goto fail;
2035 if (path[1]) {
2036 n = find_elements(client->doc, n->children, path+1, &rc,
2037 NULL, NULL, NULL, FALSE, 0, NULL);
2039 if (!n)
2040 goto fail;
2043 g_strfreev(path);
2044 return add_attribute(n, req[0], req[2]);
2046 fail:
2047 g_strfreev(path);
2048 return rc;
2052 * req[0] - command
2053 * req[1] - attribute name or element path if command is LIST
2054 * req[2] - element path
2055 * req[2] - element path or value
2057 static int attr_command(assuan_context_t ctx, char *line)
2059 struct client_s *client = assuan_get_pointer(ctx);
2060 gchar **req;
2061 gpg_error_t rc = 0;
2063 rc = file_modified(client);
2065 if (rc) {
2066 log_write("%s: %s", client->filename ? client->filename : "",
2067 pwmd_strerror(rc));
2068 return send_error(ctx, rc);
2071 req = split_input_line(line, " ", 4);
2073 if (!req || !req[0] || !req[1]) {
2074 g_strfreev(req);
2075 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2078 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2079 rc = attribute_set(client, req+1);
2080 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2081 rc = attribute_get(ctx, req+1);
2082 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2083 rc = attribute_delete(client, req+1);
2084 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2085 rc = attribute_list(ctx, req+1);
2086 else
2087 rc = EPWMD_COMMAND_SYNTAX;
2089 g_strfreev(req);
2090 return send_error(ctx, rc);
2093 static int iscached_command(assuan_context_t ctx, char *line)
2095 gchar **req = split_input_line(line, " ", 0);
2096 guchar md5file[16];
2098 if (!req || !*req) {
2099 g_strfreev(req);
2100 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2103 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2104 g_strfreev(req);
2105 CACHE_LOCK(ctx);
2107 if (cache_iscached(md5file) == FALSE) {
2108 CACHE_UNLOCK;
2109 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2112 CACHE_UNLOCK;
2113 return send_error(ctx, 0);
2116 static int clearcache_command(assuan_context_t ctx, char *line)
2118 struct client_s *client = assuan_get_pointer(ctx);
2119 gchar **req = split_input_line(line, " ", 0);
2120 guchar md5file[16];
2122 CACHE_LOCK(ctx);
2124 if (!req || !*req) {
2125 g_strfreev(req);
2126 cache_clear(client->md5file, 2);
2127 CACHE_UNLOCK;
2128 return send_error(ctx, 0);
2131 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2132 g_strfreev(req);
2134 if (cache_clear(md5file, 1) == FALSE) {
2135 CACHE_UNLOCK;
2136 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2139 CACHE_UNLOCK;
2140 return send_error(ctx, 0);
2143 static int cachetimeout_command(assuan_context_t ctx, char *line)
2145 guchar md5file[16];
2146 glong timeout;
2147 gchar **req = split_input_line(line, " ", 0);
2148 gchar *p;
2149 struct client_s *client = assuan_get_pointer(ctx);
2151 if (!req || !*req || !req[1]) {
2152 g_strfreev(req);
2153 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2156 errno = 0;
2157 timeout = strtol(req[0], &p, 10);
2159 if (errno != 0 || *p != 0) {
2160 g_strfreev(req);
2161 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2164 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2165 g_strfreev(req);
2166 CACHE_LOCK(client->ctx);
2168 if (cache_set_timeout(md5file, timeout) == FALSE) {
2169 CACHE_UNLOCK;
2170 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2173 CACHE_UNLOCK;
2174 return send_error(ctx, 0);
2177 static int dump_command(assuan_context_t ctx, char *line)
2179 xmlChar *xml;
2180 gssize len;
2181 struct client_s *client = assuan_get_pointer(ctx);
2182 gpg_error_t rc;
2184 if (disable_list_and_dump == TRUE)
2185 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2187 rc = file_modified(client);
2189 if (rc) {
2190 log_write("%s: %s", client->filename ? client->filename : "",
2191 pwmd_strerror(rc));
2192 return send_error(ctx, rc);
2195 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2197 if (!xml)
2198 return send_syserror(ctx, ENOMEM);
2200 rc = assuan_send_data(ctx, xml, len);
2201 xmlFree(xml);
2202 return send_error(ctx, rc);
2205 static int getconfig_command(assuan_context_t ctx, gchar *line)
2207 struct client_s *client = assuan_get_pointer(ctx);
2208 gpg_error_t rc = 0;
2209 gchar filename[255]={0}, param[747]={0};
2210 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2212 if (strchr(line, ' ')) {
2213 sscanf(line, " %254[a-zA-Z] %746c", filename, param);
2214 fp = filename;
2215 paramp = param;
2218 paramp = g_ascii_strdown(paramp, -1);
2220 if (!paramp)
2221 return send_syserror(ctx, ENOMEM);
2223 if (strcmp(paramp, "key") == 0 || strcmp(paramp, "key_file") == 0) {
2224 g_free(paramp);
2225 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2228 p = get_key_file_string(fp ? fp : "global", paramp);
2229 g_free(paramp);
2231 if (!p)
2232 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2234 tmp = expand_homedir(p);
2236 if (!tmp) {
2237 g_free(p);
2238 return send_syserror(ctx, ENOMEM);
2241 g_free(p);
2242 p = tmp;
2243 rc = assuan_send_data(ctx, p, strlen(p));
2244 g_free(p);
2245 return send_error(ctx, rc);
2248 static int xpath_command(assuan_context_t ctx, gchar *line)
2250 struct client_s *client = assuan_get_pointer(ctx);
2251 gpg_error_t rc;
2252 xmlXPathContextPtr xp;
2253 xmlXPathObjectPtr result;
2254 xmlBufferPtr buf = NULL;
2255 gchar **req = NULL;
2257 rc = file_modified(client);
2259 if (rc) {
2260 log_write("%s: %s", client->filename ? client->filename : "",
2261 pwmd_strerror(rc));
2262 return send_error(ctx, rc);
2265 if (!line || !*line)
2266 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2268 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2269 if (strv_printf(&req, "%s", line) == FALSE)
2270 return send_syserror(ctx, ENOMEM);
2273 xp = xmlXPathNewContext(client->doc);
2275 if (!xp)
2276 return send_error(ctx, EPWMD_LIBXML_ERROR);
2278 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2280 if (!result) {
2281 xmlXPathFreeContext(xp);
2282 return send_error(ctx, EPWMD_LIBXML_ERROR);
2285 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2286 rc = EPWMD_EMPTY_ELEMENT;
2287 goto fail;
2290 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2291 (xmlChar *)req[1], &buf);
2293 if (rc)
2294 goto fail;
2295 else if (!req[1] && !xmlBufferLength(buf)) {
2296 rc = EPWMD_EMPTY_ELEMENT;
2297 goto fail;
2299 else if (req[1])
2300 goto fail;
2302 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2304 fail:
2305 g_strfreev(req);
2307 if (buf)
2308 xmlBufferFree(buf);
2310 if (result)
2311 xmlXPathFreeObject(result);
2313 if (xp)
2314 xmlXPathFreeContext(xp);
2316 return send_error(ctx, rc);
2319 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2320 gsize len)
2322 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2323 gpg_error_t rc = file_modified(client);
2324 gchar **req, **path = NULL, **path_orig = NULL, *content;
2325 xmlDocPtr doc;
2326 xmlNodePtr n, root, copy;
2328 if (assuan_rc || rc) {
2329 if (line)
2330 #ifndef MEM_DEBUG
2331 xfree(line);
2332 #else
2333 free(line);
2334 #endif
2335 return assuan_rc ? assuan_rc : rc;
2338 req = split_input_line((gchar *)line, " ", 2);
2339 #ifndef MEM_DEBUG
2340 xfree(line);
2341 #else
2342 free(line);
2343 #endif
2345 if (!req || !*req)
2346 return EPWMD_COMMAND_SYNTAX;
2348 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2349 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2350 return EPWMD_COMMAND_SYNTAX;
2353 content = req[1];
2355 if (!content || !*content) {
2356 rc = EPWMD_COMMAND_SYNTAX;
2357 goto fail;
2360 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2361 rc = EPWMD_INVALID_ELEMENT;
2362 goto fail;
2365 if (valid_element_path(path+1, FALSE) == FALSE) {
2366 rc = EPWMD_INVALID_ELEMENT;
2367 goto fail;
2370 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2372 if (!doc) {
2373 rc = EPWMD_LIBXML_ERROR;
2374 goto fail;
2377 root = xmlDocGetRootElement(doc);
2378 path_orig = g_strdupv(path);
2380 if (!path_orig) {
2381 xmlFreeDoc(doc);
2382 rc = gpg_error_from_errno(ENOMEM);
2383 goto fail;
2386 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2387 g_strfreev(path_orig);
2388 xmlFreeDoc(doc);
2389 rc = gpg_error_from_errno(ENOMEM);
2390 goto fail;
2393 n = find_account(client->doc, &path, &rc, NULL, 0);
2395 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2396 g_strfreev(path_orig);
2397 xmlFreeDoc(doc);
2398 goto fail;
2400 else if (!rc) {
2401 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2403 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2404 g_strfreev(path_orig);
2405 xmlFreeDoc(doc);
2406 goto fail;
2408 else if (!rc) {
2409 xmlNodePtr parent = n->parent;
2411 xmlUnlinkNode(n);
2412 xmlFreeNode(n);
2413 n = parent;
2417 g_strfreev(path);
2418 path = path_orig;
2420 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2421 n = create_element_path(client, &path, &rc);
2423 if (rc) {
2424 xmlFreeDoc(doc);
2425 goto fail;
2429 copy = xmlCopyNode(root, 1);
2430 n = xmlAddChild(n, copy);
2431 xmlFreeDoc(doc);
2433 if (!n)
2434 rc = EPWMD_LIBXML_ERROR;
2436 fail:
2437 g_strfreev(path);
2438 g_strfreev(req);
2439 client->inquire_status = INQUIRE_DONE;
2440 return rc;
2443 static int import_command(assuan_context_t ctx, gchar *line)
2445 gpg_error_t rc;
2446 struct client_s *client = assuan_get_pointer(ctx);
2448 rc = file_modified(client);
2450 if (rc) {
2451 log_write("%s: %s", client->filename ? client->filename : "",
2452 pwmd_strerror(rc));
2453 return send_error(ctx, rc);
2456 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2458 if (rc)
2459 return send_error(ctx, rc);
2461 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2462 client->inquire_status = INQUIRE_BUSY;
2463 return 0;
2466 static int lock_command(assuan_context_t ctx, gchar *line)
2468 gpg_error_t rc;
2469 struct client_s *client = assuan_get_pointer(ctx);
2471 rc = file_modified(client);
2473 if (rc) {
2474 log_write("%s: %s", client->filename ? client->filename : "",
2475 pwmd_strerror(rc));
2476 return send_error(ctx, rc);
2479 rc = lock_file_mutex(client);
2481 if (!rc)
2482 client->is_lock_cmd = TRUE;
2484 return send_error(ctx, rc);
2487 static int unlock_command(assuan_context_t ctx, gchar *line)
2489 gpg_error_t rc;
2490 struct client_s *client = assuan_get_pointer(ctx);
2492 rc = file_modified(client);
2494 if (rc) {
2495 log_write("%s: %s", client->filename ? client->filename : "",
2496 pwmd_strerror(rc));
2497 return send_error(ctx, rc);
2500 unlock_file_mutex(client);
2501 return send_error(ctx, 0);
2504 static int getpid_command(assuan_context_t ctx, gchar *line)
2506 gpg_error_t rc;
2507 gchar buf[32];
2508 pid_t pid = getpid();
2510 print_fmt(buf, sizeof(buf), "%i", pid);
2511 rc = assuan_send_data(ctx, buf, strlen(buf));
2512 return send_error(ctx, rc);
2515 void cleanup_assuan(assuan_context_t ctx)
2517 struct client_s *cl = assuan_get_pointer(ctx);
2519 if (cl)
2520 cleanup_client(cl);
2523 static void reset_notify(assuan_context_t ctx)
2525 struct client_s *cl = assuan_get_pointer(ctx);
2527 if (cl)
2528 cleanup_client(cl);
2531 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2533 gchar name[32] = {0}, value[256] = {0};
2535 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2536 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2538 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2539 pth_attr_t attr = pth_attr_of(pth_self());
2541 log_write("OPTION CLIENT %s", line);
2542 pth_attr_set(attr, PTH_ATTR_NAME, value);
2543 pth_attr_destroy(attr);
2545 else
2546 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2548 return 0;
2551 static int option_handler(assuan_context_t ctx, const gchar *name,
2552 const gchar *value)
2554 #ifdef WITH_PINENTRY
2555 struct client_s *client = assuan_get_pointer(ctx);
2556 #endif
2558 if (!value || !*value)
2559 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2561 if (g_strcasecmp(name, (gchar *)"client") == 0)
2562 return parse_client_option(ctx, value);
2564 if (g_strcasecmp(name, (gchar *)"iterations") == 0) {
2565 long n;
2566 gchar *p = NULL;
2568 errno = 0;
2569 n = strtol(value, &p, 10);
2571 if (errno || (p && *p))
2572 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2574 g_key_file_set_integer(keyfileh, client->filename ? client->filename : "global", "iterations", n);
2575 send_status_all(STATUS_CONFIG);
2577 #ifdef WITH_PINENTRY
2578 else if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2579 g_free(client->pinentry->ttyname);
2580 client->pinentry->ttyname = g_strdup(value);
2582 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2583 g_free(client->pinentry->ttytype);
2584 client->pinentry->ttytype = g_strdup(value);
2586 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2587 g_free(client->pinentry->display);
2588 client->pinentry->display = g_strdup(value);
2590 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2591 g_free(client->pinentry->path);
2592 client->pinentry->path = g_strdup(value);
2594 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2595 g_free(client->pinentry->title);
2596 client->pinentry->title = g_strdup(value);
2598 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2599 g_free(client->pinentry->prompt);
2600 client->pinentry->prompt = g_strdup(value);
2602 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2603 g_free(client->pinentry->desc);
2604 client->pinentry->desc = g_strdup(value);
2606 #if 0
2607 /* Need to wait for pinentry to support a --timeout option so it can
2608 * terminate itself. Cannot do it here because assuan_pipe_connect() calls
2609 * execv() which replaces the pid of the fork()ed thread from
2610 * pinentry_fork(). So pinentry will become a real process after the
2611 * thread terminates and won't be able to be kill()ed from pwmd.
2613 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2614 gchar *p = NULL;
2615 gint n = strtol(value, &p, 10);
2617 if (*p || n < 0)
2618 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2620 client->pinentry->timeout = n;
2622 #endif
2623 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2624 gchar *p = NULL;
2625 gint n = strtol(value, &p, 10);
2627 if (*p || n < 0 || n > 1)
2628 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2630 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2632 #else
2633 else
2634 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2635 #endif
2637 log_write("OPTION %s=%s", name, value);
2638 return 0;
2641 gpg_error_t register_commands(assuan_context_t ctx)
2643 static struct {
2644 const gchar *name;
2645 gint (*handler)(assuan_context_t, gchar *line);
2646 } table[] = {
2647 { "OPEN", open_command },
2648 { "SAVE", save_command },
2649 { "LIST", list_command },
2650 { "REALPATH", realpath_command },
2651 { "STORE", store_command },
2652 { "DELETE", delete_command },
2653 { "GET", get_command },
2654 { "ATTR", attr_command },
2655 { "ISCACHED", iscached_command },
2656 { "CLEARCACHE", clearcache_command },
2657 { "CACHETIMEOUT", cachetimeout_command },
2658 { "GETCONFIG", getconfig_command },
2659 { "DUMP", dump_command },
2660 { "XPATH", xpath_command },
2661 { "IMPORT", import_command },
2662 { "LOCK", lock_command },
2663 { "UNLOCK", unlock_command },
2664 { "GETPID", getpid_command },
2665 { "INPUT", NULL },
2666 { "OUTPUT", NULL },
2667 { NULL, NULL }
2669 gint i, rc;
2671 for (i=0; table[i].name; i++) {
2672 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2674 if (rc)
2675 return rc;
2678 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2680 if (rc)
2681 return rc;
2683 rc = assuan_register_option_handler(ctx, option_handler);
2685 if (rc)
2686 return rc;
2688 return assuan_register_reset_notify(ctx, reset_notify);
2691 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2692 guchar *key, gint *dst_iter)
2694 guchar *iv;
2695 void *inbuf;
2696 gsize insize, len;
2697 guchar tkey[gcrykeysize];
2698 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2699 gcry_cipher_hd_t gh;
2700 guint iter = 0, n_iter = 0;
2701 gint iter_progress;
2702 void *outbuf = NULL;
2703 gint zrc = 0;
2704 glong outsize = 0;
2705 gpg_error_t rc;
2706 file_header_t file_header;
2707 gchar str[ASSUAN_LINELENGTH];
2709 if (!ctx) {
2710 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2712 if (rc)
2713 return rc;
2715 else
2716 gh = client->gh;
2718 lseek(fd, 0, SEEK_SET);
2719 insize = st.st_size - sizeof(file_header_t);
2720 iv = gcry_malloc(gcryblocksize);
2722 if (!iv) {
2723 if (!ctx)
2724 gcry_cipher_close(gh);
2726 return gpg_error_from_errno(ENOMEM);
2729 len = pth_read(fd, &file_header, sizeof(file_header_t));
2731 if (len != sizeof(file_header_t)) {
2732 len = errno;
2734 if (!ctx)
2735 gcry_cipher_close(gh);
2737 gcry_free(iv);
2738 errno = len;
2739 return gpg_error_from_errno(errno);
2742 *dst_iter = file_header.iter;
2744 /* No encryption iterations. This is a plain (gzipped) file. */
2745 if (file_header.iter == -1) {
2747 * cache_file_count() needs both .used == TRUE and a valid key in
2748 * order for it to count as a used cache entry. Fixes CACHE status
2749 * messages.
2751 memset(key, '!', gcrykeysize);
2752 insize = st.st_size - sizeof(file_header_t);
2755 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2756 inbuf = gcry_malloc(insize);
2758 if (!inbuf) {
2759 if (!ctx)
2760 gcry_cipher_close(gh);
2762 gcry_free(iv);
2763 return gpg_error_from_errno(ENOMEM);
2766 len = pth_read(fd, inbuf, insize);
2768 if (len != insize) {
2769 len = errno;
2771 if (!ctx)
2772 gcry_cipher_close(gh);
2774 gcry_free(iv);
2775 errno = len;
2776 return gpg_error_from_errno(errno);
2779 if (file_header.iter == -1)
2780 goto decompress;
2782 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2783 if (!ctx) {
2784 gcry_cipher_close(gh);
2785 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2787 else
2788 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2790 gcry_free(inbuf);
2791 gcry_free(iv);
2792 return rc;
2795 if ((rc = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2796 if (!ctx) {
2797 gcry_cipher_close(gh);
2798 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2800 else
2801 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2803 gcry_free(inbuf);
2804 gcry_free(iv);
2806 if (!ctx)
2807 gcry_cipher_close(gh);
2809 return rc;
2812 iter_progress = get_key_file_integer(client->filename, "iteration_progress");
2814 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2815 rc = assuan_write_status(client->ctx, "DECRYPT",
2816 print_fmt(str, sizeof(str), "%i %i", 0, file_header.iter));
2818 if (rc) {
2819 gcry_free(inbuf);
2820 gcry_free(iv);
2821 return rc;
2825 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2827 if (rc) {
2828 gcry_free(inbuf);
2829 gcry_free(iv);
2830 return rc;
2833 memcpy(tkey, key, sizeof(tkey));
2834 tkey[0] ^= 1;
2836 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
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 memset(tkey, 0, sizeof(tkey));
2845 gcry_free(inbuf);
2846 gcry_free(iv);
2847 return rc;
2850 memset(tkey, 0, sizeof(tkey));
2852 while (iter < file_header.iter) {
2853 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2854 if (!(iter % iter_progress)) {
2855 rc = assuan_write_status(ctx, "DECRYPT",
2856 print_fmt(str, sizeof(str), "%i %i", ++n_iter * iter_progress, file_header.iter));
2858 if (rc) {
2859 gcry_free(inbuf);
2860 gcry_free(iv);
2861 return rc;
2866 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2867 if (!ctx) {
2868 gcry_cipher_close(gh);
2869 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2871 else
2872 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2874 gcry_free(inbuf);
2875 gcry_free(iv);
2876 return rc;
2879 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2881 if (rc) {
2882 if (!ctx) {
2883 gcry_cipher_close(gh);
2884 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2886 else
2887 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2889 gcry_free(inbuf);
2890 gcry_free(iv);
2891 return rc;
2894 iter++;
2895 pth_yield(NULL);
2898 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2899 rc = assuan_write_status(ctx, "DECRYPT",
2900 print_fmt(str, sizeof(str), "%i %i", file_header.iter, file_header.iter));
2902 if (rc) {
2903 gcry_free(inbuf);
2904 gcry_free(iv);
2905 return rc;
2909 gcry_free(iv);
2911 decompress:
2912 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zrc) == FALSE) {
2914 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2916 if (zrc == Z_MEM_ERROR) {
2917 gcry_free(inbuf);
2918 return gpg_error_from_errno(ENOMEM);
2920 else if (zrc != Z_DATA_ERROR) {
2921 gcry_free(inbuf);
2923 if (!ctx)
2924 gcry_cipher_close(gh);
2926 return EPWMD_BADKEY;
2929 else {
2930 gcry_free(inbuf);
2931 inbuf = outbuf;
2932 insize = outsize;
2935 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2936 gcry_free(inbuf);
2938 if (!ctx)
2939 gcry_cipher_close(gh);
2941 return EPWMD_BADKEY;
2944 if (ctx) {
2945 client->xml = inbuf;
2946 client->len = insize;
2948 else {
2949 gcry_cipher_close(gh);
2950 gcry_free(inbuf);
2953 return 0;
2957 * This is called after every Assuan command.
2959 void command_finalize(assuan_context_t ctx, gint rc)
2961 struct client_s *client = assuan_get_pointer(ctx);
2963 if (!client->is_lock_cmd)
2964 unlock_file_mutex(client);