Fixed some comple time conditionals.
[pwmd.git] / src / commands.c
blobfc1915c34f0a32e1dadd57d4e79f25ed200de54e
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 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 #include "mem.h"
37 #include "xml.h"
38 #include "common.h"
40 #ifdef WITH_PINENTRY
41 #include "pinentry.h"
42 #endif
44 #include "pwmd_error.h"
45 #include "cache.h"
46 #include "misc.h"
47 #ifdef WITH_GNUTLS
48 #include "tls.h"
49 #endif
50 #include "commands.h"
52 static void *z_alloc(void *data, unsigned items, unsigned size)
54 return gcry_calloc(items, size);
57 static void z_free(void *data, void *p)
59 gcry_free(p);
62 static gpg_error_t file_modified(struct client_s *client)
64 struct stat st;
65 gpg_error_t rc;
67 if (client->state != STATE_OPEN)
68 return EPWMD_NO_FILE;
70 rc = lock_file_mutex(client);
72 if (rc)
73 return rc;
75 if (lstat(client->filename, &st) == 0 && client->mtime) {
76 if (client->mtime != st.st_mtime)
77 return EPWMD_FILE_MODIFIED;
80 return 0;
83 static gboolean encrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
84 void *inbuf, gsize insize)
86 gpg_error_t rc;
88 if ((rc = gcry_cipher_encrypt(gh, outbuf, outsize, inbuf, insize))) {
89 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
90 return FALSE;
93 return TRUE;
96 static gpg_error_t decrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
97 void *inbuf, gsize insize)
99 gpg_error_t rc;
101 if ((rc = gcry_cipher_decrypt(gh, outbuf, outsize, inbuf, insize)))
102 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
104 return rc;
107 static gpg_error_t parse_xml(assuan_context_t ctx)
109 struct client_s *client = assuan_get_pointer(ctx);
111 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
113 if (!client->doc)
114 return EPWMD_LIBXML_ERROR;
116 return 0;
119 void unlock_file_mutex(struct client_s *client)
121 struct file_mutex_s *m;
123 #ifdef WITH_PINENTRY
124 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
125 #else
126 if (client->has_lock == FALSE)
127 #endif
128 return;
130 CACHE_LOCK(client->ctx);
132 if (cache_get_mutex(client->md5file, &m) == FALSE) {
133 CACHE_UNLOCK;
134 return;
137 CACHE_UNLOCK;
138 pthread_mutex_unlock(&m->mutex);
139 client->has_lock = client->is_lock_cmd = FALSE;
142 gpg_error_t lock_file_mutex(struct client_s *client)
144 struct file_mutex_s *m;
145 gint e;
147 if (client->has_lock == TRUE)
148 return 0;
150 CACHE_LOCK(client->ctx);
152 if (cache_get_mutex(client->md5file, &m) == FALSE) {
153 CACHE_UNLOCK;
154 return 0;
157 CACHE_UNLOCK;
158 e = pthread_mutex_trylock(&m->mutex);
160 if (e && e != EBUSY) {
161 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(e));
162 return gpg_error_from_errno(e);
165 if (e == EBUSY) {
166 if (client->ctx) {
168 * If a client disconnects unexpectedly while waiting for a
169 * lock, this lets the thread terminate because send_status()
170 * will return an error. We can't use an PTH_EVENT_FUNC here
171 * because the thread that would call the callback uses it's
172 * own stack space which messes up access to the client data
173 * (if I understand it correctly).
175 while (pthread_mutex_trylock(&m->mutex) == EBUSY) {
176 gpg_error_t rc = send_status(client->ctx, STATUS_LOCKED, NULL);
178 if (rc)
179 return rc;
181 sleep(1);
184 else
185 pthread_mutex_lock(&m->mutex);
188 client->has_lock = TRUE;
189 return 0;
192 void free_client(struct client_s *client)
194 if (client->doc)
195 xmlFreeDoc(client->doc);
197 if (client->xml)
198 gcry_free(client->xml);
200 if (client->filename)
201 g_free(client->filename);
203 if (client->crypto)
204 cleanup_crypto(&client->crypto);
207 void cleanup_client(struct client_s *client)
209 assuan_context_t ctx = client->ctx;
210 struct client_thread_s *thd = client->thd;
211 gboolean has_lock = client->has_lock;
212 #ifdef WITH_PINENTRY
213 struct pinentry_s *pin = client->pinentry;
214 #endif
216 unlock_file_mutex(client);
217 CACHE_LOCK(client->ctx);
218 cache_decr_refcount(client->md5file);
221 * This may be a new file so don't use a cache slot. save_command() will
222 * set this to FALSE on success.
224 if (client->new == TRUE)
225 cache_clear(client->md5file, 1);
227 free_client(client);
228 memset(client, 0, sizeof(struct client_s));
229 client->state = STATE_CONNECTED;
230 client->ctx = ctx;
231 client->thd = thd;
232 client->freed = TRUE;
233 #ifdef WITH_PINENTRY
234 client->pinentry = pin;
235 #endif
236 client->has_lock = has_lock;
237 CACHE_UNLOCK;
240 gboolean do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
241 gpointer *out, gulong *outsize, gint *rc)
243 z_stream z;
244 gpointer pout;
245 gz_header h;
246 gchar buf[17];
248 z.zalloc = z_alloc;
249 z.zfree = z_free;
250 z.next_in = in;
251 z.avail_in = (uInt)insize;
252 z.avail_out = zlib_bufsize;
253 z.next_out = pout = g_malloc(zlib_bufsize);
255 if (!pout) {
256 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
257 *rc = Z_MEM_ERROR;
258 return FALSE;
261 *rc = inflateInit2(&z, 47);
263 if (*rc != Z_OK) {
264 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
265 g_free(pout);
266 return FALSE;
269 memset(&h, 0, sizeof(gz_header));
270 h.comment = (guchar *)buf;
271 h.comm_max = sizeof(buf);
272 *rc = inflateGetHeader(&z, &h);
274 if (*rc != Z_OK) {
275 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
276 g_free(pout);
277 inflateEnd(&z);
278 return FALSE;
281 *rc = inflate(&z, Z_BLOCK);
283 if (*rc != Z_OK) {
284 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
285 g_free(pout);
286 inflateEnd(&z);
287 return FALSE;
290 if (h.comment)
291 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
293 do {
294 gpointer p;
296 *rc = inflate(&z, Z_FINISH);
298 switch (*rc) {
299 case Z_OK:
300 break;
301 case Z_BUF_ERROR:
302 if (!z.avail_out) {
303 p = g_realloc(pout, z.total_out + zlib_bufsize);
305 if (!p) {
306 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
307 *rc = Z_MEM_ERROR;
308 goto fail;
311 pout = p;
312 z.next_out = pout + z.total_out;
313 z.avail_out = zlib_bufsize;
314 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
315 z.total_out, insize);
316 if (*rc)
317 goto fail;
319 break;
320 case Z_STREAM_END:
321 break;
322 default:
323 goto fail;
324 break;
326 } while (*rc != Z_STREAM_END);
328 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", z.total_out,
329 insize);
331 if (*rc)
332 goto fail;
334 *out = pout;
335 *outsize = z.total_out;
336 inflateEnd(&z);
337 *rc = 0;
338 return TRUE;
340 fail:
341 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
342 g_free(pout);
343 inflateEnd(&z);
344 return FALSE;
347 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
348 gpg_error_t *rc)
350 gint fd;
351 gsize len;
352 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
353 gsize fh_size;
355 *rc = 0;
357 if (!fh) {
358 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
359 *rc = gpg_error_from_errno(ENOMEM);
360 return NULL;
363 fh_size = v1 ? sizeof(fh->fh1) : sizeof(fh->fh2);
365 if (lstat(filename, &fh->st) == -1) {
366 *rc = gpg_error_from_syserror();
367 g_free(fh);
368 return NULL;
371 fd = open(filename, O_RDONLY);
373 if (fd == -1) {
374 *rc = gpg_error_from_errno(errno);
375 g_free(fh);
376 return NULL;
379 if (v1)
380 len = read(fd, &fh->fh1, fh_size);
381 else
382 len = read(fd, &fh->fh2, fh_size);
384 if (len != fh_size) {
385 close(fd);
386 *rc = GPG_ERR_INV_LENGTH;
387 g_free(fh);
388 return NULL;
391 fh->v1 = v1;
392 fh->fd = fd;
393 return fh;
396 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *key,
397 gboolean cached)
399 struct client_s *client = assuan_get_pointer(ctx);
400 gpg_error_t rc;
401 gint timeout;
403 /* New file. */
404 if (!client->crypto->fh) {
405 if (key[0])
406 goto update_cache;
408 goto done;
411 rc = try_xml_decrypt(ctx, key, client->crypto, NULL, NULL);
413 if (rc) {
414 cleanup_client(client);
415 return send_error(ctx, rc);
418 update_cache:
419 CACHE_LOCK(client->ctx);
421 if (cached == FALSE) {
422 if (cache_update_key(client->md5file, key) == FALSE) {
423 cleanup_client(client);
424 CACHE_UNLOCK;
425 return send_syserror(ctx, ENOMEM);
428 timeout = get_key_file_integer(client->filename, "cache_timeout");
429 cache_reset_timeout(client->md5file, timeout);
431 else
432 cache_set_timeout(client->md5file, -2);
434 CACHE_UNLOCK;
436 done:
437 if (client->crypto->key != key)
438 gcry_free(key); // This is invokation is a pinentry callback.
440 rc = parse_xml(ctx);
442 if (client->xml) {
443 gcry_free(client->xml);
444 client->xml = NULL;
447 if (!rc) {
448 if (client->new == FALSE)
449 send_status_all(STATUS_CACHE);
451 client->state = STATE_OPEN;
454 if (!rc && client->new == FALSE &&
455 client->crypto->fh->fh2.iter != (guint)get_key_file_integer(client->filename, "iterations")) {
456 g_key_file_set_integer(keyfileh, client->filename, "iterations",
457 client->crypto->fh->fh2.iter);
458 send_status_all(STATUS_CONFIG);
461 if (!rc)
462 log_write("OPEN '%s'", client->filename);
464 cleanup_crypto(&client->crypto);
465 return send_error(ctx, rc);
468 #ifdef WITH_GNUTLS
469 static gboolean validate_access(struct client_s *cl, const gchar *filename)
471 gchar *access = get_key_file_string(filename, "tcp_access");
472 gchar **list, **p;
474 if (!access)
475 return TRUE;
477 list = g_strsplit(access, ",", -1);
478 g_free(access);
480 if (!list) {
481 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
482 return FALSE;
485 for (p = list; *p; p++) {
486 gboolean not = FALSE;
487 gchar *fp = *p;
489 if (*fp == '!') {
490 not = TRUE;
491 fp++;
493 if (!*fp)
494 break;
497 if (strcasecmp(cl->thd->tls->fp, fp) == 0) {
498 if (not == TRUE)
499 continue;
501 g_strfreev(list);
502 return TRUE;
506 /* Not allowed. */
507 g_strfreev(list);
508 return FALSE;
510 #endif
512 static int open_command(assuan_context_t ctx, char *line)
514 gboolean cached = FALSE;
515 gpg_error_t rc;
516 struct client_s *client = assuan_get_pointer(ctx);
517 gchar **req;
518 gchar *filename = NULL;
520 if ((req = split_input_line(line, " ", 2)) != NULL)
521 filename = req[0];
523 if (!filename || !*filename) {
524 g_strfreev(req);
525 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
528 if (valid_filename(filename) == FALSE) {
529 g_strfreev(req);
530 return send_error(ctx, EPWMD_INVALID_FILENAME);
533 if (client->state == STATE_OPEN)
534 cleanup_client(client);
536 #ifdef WITH_GNUTLS
537 if (client->thd->remote == TRUE) {
538 if (validate_access(client, filename) == FALSE) {
539 log_write(N_("client validation failed for file '%s'"), filename);
540 g_strfreev(req);
541 return send_error(ctx, EPWMD_FILE_ACCESS);
544 #endif
546 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
547 CACHE_LOCK(client->ctx);
549 if (cache_has_file(client->md5file) == FALSE) {
550 if (cache_add_file(client->md5file, NULL) == FALSE) {
551 g_strfreev(req);
552 CACHE_UNLOCK;
553 return send_syserror(ctx, ENOMEM);
557 cache_incr_refcount(client->md5file);
558 CACHE_UNLOCK;
559 rc = lock_file_mutex(client);
561 if (rc) {
562 g_strfreev(req);
563 return send_error(ctx, rc);
566 client->freed = FALSE;
567 client->crypto = init_client_crypto();
569 if (!client->crypto) {
570 g_strfreev(req);
571 cleanup_client(client);
572 return send_syserror(ctx, ENOMEM);
575 client->crypto->key = gcry_malloc(gcrykeysize);
577 if (!client->crypto->key) {
578 g_strfreev(req);
579 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
580 gpg_error_from_errno(ENOMEM));
581 cleanup_client(client);
582 return send_syserror(ctx, ENOMEM);
585 memset(client->crypto->key, 0, gcrykeysize);
586 client->crypto->fh = read_file_header(filename, FALSE, &rc);
588 if (!client->crypto->fh) {
589 if (gpg_err_code_to_errno(rc) != ENOENT) {
590 log_write("%s: %s", filename, pwmd_strerror(rc));
591 g_strfreev(req);
592 cleanup_client(client);
593 return send_syserror(ctx, rc);
597 * New files don't need a key.
599 if ((client->xml = new_document()) == NULL) {
600 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
601 g_strfreev(req);
602 cleanup_client(client);
603 return send_syserror(ctx, ENOMEM);
606 client->len = xmlStrlen(client->xml);
607 client->new = TRUE;
608 client->filename = g_strdup(filename);
610 if (!client->filename) {
611 g_strfreev(req);
612 cleanup_client(client);
613 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
614 return send_syserror(ctx, ENOMEM);
617 if (req[1] && *req[1])
618 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
619 strlen(req[1]));
621 g_strfreev(req);
622 #ifdef WITH_PINENTRY
623 client->pinentry->filename = g_strdup(client->filename);
625 if (!client->pinentry->filename) {
626 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
627 cleanup_client(client);
628 return send_syserror(ctx, ENOMEM);
630 #endif
631 return open_command_finalize(ctx, client->crypto->key, cached);
633 else {
634 if (!S_ISREG(client->crypto->fh->st.st_mode)) {
635 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
636 g_strfreev(req);
637 cleanup_client(client);
638 return send_error(ctx, EPWMD_INVALID_FILENAME);
641 client->mtime = client->crypto->fh->st.st_mtime;
644 client->filename = g_strdup(filename);
646 if (!client->filename) {
647 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
648 g_strfreev(req);
649 cleanup_client(client);
650 return send_syserror(ctx, ENOMEM);
653 #ifdef WITH_PINENTRY
654 client->pinentry->filename = g_strdup(client->filename);
656 if (!client->pinentry->filename) {
657 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
658 g_strfreev(req);
659 cleanup_client(client);
660 return send_syserror(ctx, ENOMEM);
662 #endif
664 if (client->crypto->fh->fh2.iter <= 0)
665 goto done;
667 #ifdef WITH_GNUTLS
668 if (client->thd->remote == FALSE ||
669 get_key_file_boolean(client->filename, "tcp_require_key") == FALSE)
671 #endif
672 CACHE_LOCK(client->ctx);
673 cached = cache_get_key(client->md5file, client->crypto->key);
674 CACHE_UNLOCK;
675 #ifdef WITH_GNUTLS
677 else
678 cached = FALSE;
679 #endif
681 if (cached == FALSE) {
682 gchar *tmp = get_key_file_string(filename, "key_file");
684 if (tmp) {
685 g_free(tmp);
686 cleanup_client(client);
687 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
691 * No key specified and no matching filename found in the cache. Use
692 * pinentry to retrieve the key. Cannot return assuan_process_done()
693 * here otherwise the command will be interrupted. The event loop in
694 * client_thread() will poll the file descriptor waiting for it to
695 * become ready to read a pinentry_key_s which will contain the
696 * entered key or rc. It will then call open_command_finalize() to
697 * to finish the command.
699 if (!req[1] || !*req[1]) {
700 #ifdef WITH_PINENTRY
701 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
703 /* From set_pinentry_defaults(). */
704 if (client->pinentry->enable == FALSE ||
705 (client->pinentry->enable == -1 && b == FALSE)) {
706 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
707 goto done;
710 g_strfreev(req);
711 rc = lock_pin_mutex(client);
713 if (rc) {
714 unlock_pin_mutex(client->pinentry);
715 cleanup_client(client);
716 return send_error(ctx, rc);
719 client->pinentry->which = PINENTRY_OPEN;
720 rc = pinentry_fork(ctx);
722 if (rc) {
723 unlock_pin_mutex(client->pinentry);
724 cleanup_client(client);
725 return send_error(ctx, rc);
728 client->pinentry->cb = open_command_finalize;
729 client->pinentry->status = PINENTRY_INIT;
730 return 0;
731 #else
732 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
733 goto done;
734 #endif
737 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
738 strlen(req[1]));
741 done:
742 g_strfreev(req);
743 return open_command_finalize(ctx, client->crypto->key, cached);
746 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
747 gulong size, gpointer *out, gulong *outsize, gint *rc)
749 z_stream z;
750 gpointer pout, pin;
751 gz_header h;
752 gchar buf[17];
753 gint cmd = Z_NO_FLUSH;
755 z.zalloc = z_alloc;
756 z.zfree = z_free;
757 z.next_in = pin = data;
758 z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
759 z.avail_out = (uInt)zlib_bufsize;
760 z.next_out = pout = g_malloc(zlib_bufsize);
762 if (!pout) {
763 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
764 *rc = Z_MEM_ERROR;
765 return FALSE;
768 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
770 if (*rc != Z_OK) {
771 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
772 g_free(pout);
773 return FALSE;
776 /* Rather than store the size of the uncompressed data in the file header,
777 * store it in the comment field of the gzip header. Don't give anyone too
778 * much information. Not sure why really, but it seems the right way. :)
780 memset(&h, 0, sizeof(gz_header));
781 g_snprintf(buf, sizeof(buf), "%li", size);
782 h.comment = (guchar *)buf;
783 *rc = deflateSetHeader(&z, &h);
785 if (*rc != Z_OK) {
786 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
787 g_free(pout);
788 deflateEnd(&z);
789 return FALSE;
792 do {
793 gpointer p;
795 *rc = deflate(&z, cmd);
797 switch (*rc) {
798 case Z_OK:
799 break;
800 case Z_BUF_ERROR:
801 if (!z.avail_out) {
802 p = g_realloc(pout, z.total_out + zlib_bufsize);
804 if (!p) {
805 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
806 *rc = Z_MEM_ERROR;
807 goto fail;
810 pout = p;
811 z.next_out = pout + z.total_out;
812 z.avail_out = zlib_bufsize;
815 if (!z.avail_in && z.total_in < size) {
816 if (z.total_in + zlib_bufsize > size)
817 z.avail_in = size - z.total_in;
818 else
819 z.avail_in = zlib_bufsize;
821 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li",
822 z.total_in, size);
824 if (*rc)
825 goto fail;
828 if (z.total_in >= size)
829 cmd = Z_FINISH;
831 break;
832 case Z_STREAM_END:
833 break;
834 default:
835 goto fail;
837 } while (*rc != Z_STREAM_END);
839 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li", z.total_in, size);
841 if (*rc)
842 goto fail;
844 *out = pout;
845 *outsize = z.total_out;
846 deflateEnd(&z);
847 *rc = 0;
848 return TRUE;
850 fail:
851 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
852 g_free(pout);
853 deflateEnd(&z);
854 return FALSE;
857 /* The crypto struct must be setup for iterations and .key. */
858 gpg_error_t do_xml_encrypt(struct client_s *client,
859 struct client_crypto_s *crypto, const gchar *filename, gpointer data,
860 gsize insize)
862 gsize len = insize;
863 gpointer inbuf;
864 gchar *p;
865 gpg_error_t rc;
866 guint iter_progress = 0, n_iter = 0, xiter = 0;
867 gchar tmp[FILENAME_MAX];
868 struct stat st;
869 mode_t mode = 0;
871 //file_header.iter = iter;
873 if (!crypto->fh->fh2.iter) {
875 * cache_file_count() needs both .used == TRUE and a valid key in
876 * order for it to count as a used cache entry. Fixes CACHE status
877 * messages.
879 memset(crypto->key, '!', gcrykeysize);
880 inbuf = data;
881 goto write_file;
885 * Resize the existing xml buffer to the block size required by gcrypt
886 * rather than duplicating it and wasting memory.
888 if (insize / gcryblocksize) {
889 len = (insize / gcryblocksize) * gcryblocksize;
891 if (insize % gcryblocksize)
892 len += gcryblocksize;
895 inbuf = gcry_realloc(data, len);
897 if (!inbuf) {
898 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
899 return gpg_error_from_errno(ENOMEM);
902 insize = len;
903 gcry_create_nonce(crypto->fh->fh2.iv, sizeof(crypto->fh->fh2.iv));
904 crypto->tkey = gcry_malloc(gcrykeysize);
906 if (!crypto->tkey) {
907 gcry_free(inbuf);
908 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
909 return gpg_error_from_errno(ENOMEM);
912 memcpy(crypto->tkey, crypto->key, gcrykeysize);
913 guchar *tkey = crypto->tkey;
914 tkey[0] ^= 1;
916 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
917 gcry_free(inbuf);
918 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
919 return rc;
922 iter_progress = get_key_file_integer(client ? client->filename : "global",
923 "iteration_progress");
925 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
926 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
927 "%u %u", 0, crypto->fh->fh2.iter);
929 if (rc) {
930 gcry_free(inbuf);
931 return rc;
935 while (xiter < crypto->fh->fh2.iter-1) {
936 if (iter_progress > 0 && xiter >= iter_progress) {
937 if (!(xiter % iter_progress)) {
938 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
939 "%u %u", ++n_iter * iter_progress, crypto->fh->fh2.iter);
941 if (rc) {
942 gcry_free(inbuf);
943 return rc;
948 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
949 sizeof(crypto->fh->fh2.iv)))) {
950 gcry_free(inbuf);
951 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
952 return rc;
955 if (encrypt_xml(crypto->gh, inbuf, insize, NULL, 0) == FALSE) {
956 gcry_free(inbuf);
957 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
958 return rc;
961 xiter++;
964 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
965 sizeof(crypto->fh->fh2.iv)))) {
966 gcry_free(inbuf);
967 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
968 return rc;
971 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, gcrykeysize))) {
972 gcry_free(inbuf);
973 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
974 return rc;
977 if (encrypt_xml(crypto->gh, inbuf, insize, NULL, 0) == FALSE) {
978 gcry_free(inbuf);
979 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
980 return rc;
983 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
984 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
985 "%u %u", crypto->fh->fh2.iter, crypto->fh->fh2.iter);
987 if (rc) {
988 gcry_free(inbuf);
989 return rc;
993 write_file:
994 if (filename) {
995 if (!client && !strcmp(filename, "-")) {
996 crypto->fh->fd = STDOUT_FILENO;
997 goto do_write_file;
1000 if (lstat(filename, &st) == 0) {
1001 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1004 * FIXME What if the file has an ACL?
1006 if (!(mode & S_IWUSR)) {
1007 gcry_free(inbuf);
1008 return gpg_error_from_errno(EACCES);
1011 else {
1012 if (errno != ENOENT) {
1013 rc = errno;
1014 gcry_free(inbuf);
1015 return gpg_error_from_errno(rc);
1019 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1020 crypto->fh->fd = mkstemp(tmp);
1022 if (crypto->fh->fd == -1) {
1023 rc = errno;
1024 gcry_free(inbuf);
1025 p = strrchr(tmp, '/');
1026 p++;
1027 log_write("%s: %s", p, strerror(rc));
1028 return gpg_error_from_errno(rc);
1031 else
1033 * xml_import() or convert_file() from command line.
1035 crypto->fh->fd = STDOUT_FILENO;
1037 do_write_file:
1038 crypto->fh->fh2.version = VERSION_HEX;
1039 len = write(crypto->fh->fd, &crypto->fh->fh2, sizeof(crypto->fh->fh2));
1041 if (len != sizeof(crypto->fh->fh2)) {
1042 len = errno;
1044 if (filename && strcmp(filename, "-"))
1045 unlink(tmp);
1047 gcry_free(inbuf);
1048 return gpg_error_from_errno(len);
1051 len = write(crypto->fh->fd, inbuf, insize);
1053 if (len != insize) {
1054 len = errno;
1056 if (filename && strcmp(filename, "-"))
1057 unlink(tmp);
1059 gcry_free(inbuf);
1060 return gpg_error_from_errno(len);
1063 if (fsync(crypto->fh->fd) == -1) {
1064 len = errno;
1066 if (filename && strcmp(filename, "-"))
1067 unlink(tmp);
1069 gcry_free(inbuf);
1070 return gpg_error_from_errno(len);
1073 if (filename && strcmp(filename, "-")) {
1074 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1075 gchar tmp2[FILENAME_MAX];
1077 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1079 if (rename(filename, tmp2) == -1) {
1080 unlink(tmp);
1081 len = errno;
1082 gcry_free(inbuf);
1083 return gpg_error_from_errno(len);
1087 if (rename(tmp, filename) == -1) {
1088 len = errno;
1089 unlink(tmp);
1090 gcry_free(inbuf);
1091 return gpg_error_from_errno(len);
1094 if (mode)
1095 chmod(filename, mode);
1098 gcry_free(inbuf);
1099 return 0;
1102 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1103 gboolean cached)
1105 struct client_s *client = assuan_get_pointer(ctx);
1106 gpointer xmlbuf;
1107 gulong len, outsize = 0;
1108 guint iter;
1109 gint timeout;
1110 gpointer outbuf;
1111 gint zrc;
1112 gpg_error_t rc;
1113 struct stat st;
1115 if (client->crypto->key && client->crypto->key != key)
1116 gcry_free(client->crypto->key);
1118 client->crypto->key = key;
1119 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1120 iter = (guint)get_key_file_integer(client->filename, "compression_level");
1122 if (iter < 0)
1123 iter = 0;
1125 if (do_compress(ctx, (gint)iter, xmlbuf, len, &outbuf, &outsize, &zrc)
1126 == FALSE) {
1127 if (key != client->crypto->key)
1128 gcry_free(key);
1130 xmlFree(xmlbuf);
1131 cleanup_crypto(&client->crypto);
1133 if (zrc == Z_MEM_ERROR)
1134 return send_syserror(ctx, ENOMEM);
1135 else
1136 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1138 else {
1139 gcry_free(xmlbuf);
1140 xmlbuf = outbuf;
1141 len = outsize;
1144 client->crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1146 if (!client->crypto->fh) {
1147 cleanup_crypto(&client->crypto);
1148 gcry_free(outbuf);
1149 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1150 return send_syserror(ctx, ENOMEM);
1153 iter = get_key_file_integer(client->filename, "iterations");
1154 client->crypto->fh->fh2.iter = iter < 0 ? 0 : iter;
1155 rc = do_xml_encrypt(client, client->crypto, client->filename, xmlbuf, len);
1157 if (rc) {
1158 cleanup_crypto(&client->crypto);
1159 return send_error(ctx, rc);
1162 lstat(client->filename, &st);
1163 client->mtime = st.st_mtime;
1164 timeout = get_key_file_integer(client->filename, "cache_timeout");
1165 CACHE_LOCK(client->ctx);
1167 if (cached) {
1168 cache_reset_timeout(client->md5file, timeout);
1169 CACHE_UNLOCK;
1171 if (client->new == TRUE)
1172 send_status_all(STATUS_CACHE);
1174 client->new = FALSE;
1175 cleanup_crypto(&client->crypto);
1176 return send_error(ctx, 0);
1179 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1180 CACHE_UNLOCK;
1181 cleanup_crypto(&client->crypto);
1182 return send_syserror(ctx, ENOMEM);
1185 client->new = FALSE;
1186 cache_reset_timeout(client->md5file, timeout);
1187 CACHE_UNLOCK;
1188 send_status_all(STATUS_CACHE);
1189 cleanup_crypto(&client->crypto);
1190 return send_error(ctx, 0);
1193 static int save_command(assuan_context_t ctx, char *line)
1195 gboolean cached = FALSE;
1196 struct stat st;
1197 struct client_s *client = assuan_get_pointer(ctx);
1198 gpg_error_t rc;
1200 rc = lock_file_mutex(client);
1202 if (rc)
1203 return send_error(ctx, rc);
1205 rc = file_modified(client);
1207 if (rc)
1208 return send_error(ctx, rc);
1210 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1211 return send_syserror(ctx, errno);
1213 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1214 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1215 return send_error(ctx, EPWMD_INVALID_FILENAME);
1218 CACHE_LOCK(ctx);
1219 cached = cache_iscached(client->md5file);
1220 CACHE_UNLOCK;
1223 * If a cache entry doesn't exist for this file and the file has a
1224 * "key_file" or "key" parameter, then it's an error. The reason is that
1225 * cache expiration would be useless.
1227 if (cached == FALSE) {
1228 gchar *tmp = get_key_file_string(client->filename, "key_file");
1230 if (tmp) {
1231 g_free(tmp);
1232 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1236 cached = FALSE;
1237 client->crypto = init_client_crypto();
1239 if (!client->crypto) {
1240 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1241 return send_syserror(ctx, ENOMEM);
1244 client->crypto->key = gcry_malloc(gcrykeysize);
1246 if (!client->crypto->key) {
1247 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1248 cleanup_crypto(&client->crypto);
1249 return send_syserror(ctx, ENOMEM);
1252 memset(client->crypto->key, '!', gcrykeysize);
1254 if (get_key_file_integer(client->filename, "iterations") <= 0)
1255 goto done;
1257 if (!line || !*line) {
1258 client->crypto->tkey = gcry_malloc(gcrykeysize);
1260 if (!client->crypto->tkey) {
1261 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1262 cleanup_crypto(&client->crypto);
1263 return send_syserror(ctx, ENOMEM);
1266 memset(client->crypto->tkey, '!', gcrykeysize);
1267 CACHE_LOCK(ctx);
1269 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1270 memcmp(client->crypto->key, client->crypto->tkey,
1271 gcrykeysize) == 0) {
1272 CACHE_UNLOCK;
1274 #ifdef WITH_PINENTRY
1275 if (client->pinentry->enable == FALSE ||
1276 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1277 /* Empty keys are allowed. */
1278 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1279 goto done;
1282 lock_pin_mutex(client);
1283 client->pinentry->which = PINENTRY_SAVE;
1284 rc = pinentry_fork(ctx);
1286 if (rc) {
1287 unlock_pin_mutex(client->pinentry);
1288 return send_error(ctx, rc);
1291 client->pinentry->cb = save_command_finalize;
1292 client->pinentry->status = PINENTRY_INIT;
1293 return 0;
1294 #else
1295 /* Empty keys are allowed. */
1296 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1297 goto done;
1298 #endif
1300 else {
1301 CACHE_UNLOCK;
1302 cached = TRUE;
1305 else {
1306 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1307 strlen(line));
1308 memset(line, 0, strlen(line));
1311 done:
1312 return save_command_finalize(ctx, client->crypto->key, cached);
1315 static int delete_command(assuan_context_t ctx, char *line)
1317 struct client_s *client = assuan_get_pointer(ctx);
1318 gchar **req;
1319 gpg_error_t rc;
1320 xmlNodePtr n;
1322 rc = file_modified(client);
1324 if (rc)
1325 return send_error(ctx, rc);
1327 if (strchr(line, '\t'))
1328 req = split_input_line(line, "\t", -1);
1329 else
1330 req = split_input_line(line, " ", -1);
1332 if (!req || !*req)
1333 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1335 n = find_account(client->doc, &req, &rc, NULL, 0);
1337 if (!n) {
1338 g_strfreev(req);
1339 return send_error(ctx, rc);
1343 * No sub-node defined. Remove the entire node (account).
1345 if (!req[1]) {
1346 if (n) {
1347 xmlUnlinkNode(n);
1348 xmlFreeNode(n);
1351 g_strfreev(req);
1352 return send_error(ctx, 0);
1355 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1356 g_strfreev(req);
1358 if (!n)
1359 return send_error(ctx, rc);
1361 if (n) {
1362 xmlUnlinkNode(n);
1363 xmlFreeNode(n);
1366 return send_error(ctx, 0);
1370 * Don't return with assuan_process_done() here. This has been called from
1371 * assuan_process_next() and the command should be finished in
1372 * client_thread().
1374 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1375 gsize len)
1377 assuan_context_t ctx = data;
1378 struct client_s *client = assuan_get_pointer(ctx);
1379 gchar **req;
1380 xmlNodePtr n;
1381 gpg_error_t rc = file_modified(client);
1383 if (assuan_rc || rc) {
1384 if (line)
1385 xfree(line);
1386 return assuan_rc ? assuan_rc : rc;
1389 req = split_input_line((gchar *)line, "\t", 0);
1390 xfree(line);
1392 if (!req || !*req)
1393 return EPWMD_COMMAND_SYNTAX;
1395 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1396 g_strfreev(req);
1397 return EPWMD_INVALID_ELEMENT;
1400 if (valid_element_path(req+1, TRUE) == FALSE) {
1401 g_strfreev(req);
1402 return EPWMD_INVALID_ELEMENT;
1405 again:
1406 n = find_account(client->doc, &req, &rc, NULL, 0);
1408 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1409 rc = new_account(client->doc, *req);
1411 if (rc) {
1412 g_strfreev(req);
1413 return rc;
1416 goto again;
1419 if (!n) {
1420 g_strfreev(req);
1421 return rc;
1424 if (req[1]) {
1425 if (!n->children)
1426 create_elements_cb(n, req+1, &rc, NULL);
1427 else
1428 find_elements(client->doc, n->children, req+1, &rc,
1429 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1432 g_strfreev(req);
1433 client->inquire_status = INQUIRE_DONE;
1434 return rc;
1437 static int store_command(assuan_context_t ctx, char *line)
1439 struct client_s *client = assuan_get_pointer(ctx);
1440 gpg_error_t rc = file_modified(client);
1442 if (rc)
1443 return send_error(ctx, rc);
1445 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1447 if (rc)
1448 return send_error(ctx, rc);
1450 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1451 client->inquire_status = INQUIRE_BUSY;
1452 return 0;
1455 static int get_command(assuan_context_t ctx, char *line)
1457 struct client_s *client = assuan_get_pointer(ctx);
1458 gchar **req;
1459 gpg_error_t rc;
1460 xmlNodePtr n;
1462 rc = file_modified(client);
1464 if (rc)
1465 return send_error(ctx, rc);
1467 req = split_input_line(line, "\t", -1);
1469 if (!req || !*req) {
1470 g_strfreev(req);
1471 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1474 n = find_account(client->doc, &req, &rc, NULL, 0);
1476 if (!n) {
1477 g_strfreev(req);
1478 return send_error(ctx, rc);
1481 if (req[1])
1482 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1484 g_strfreev(req);
1486 if (rc)
1487 return send_error(ctx, rc);
1489 if (!n || !n->children)
1490 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1492 n = find_text_node(n->children);
1494 if (!n || !n->content || !*n->content)
1495 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1497 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1498 return send_error(ctx, rc);
1501 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1502 gpg_error_t *rc, gchar **req_orig, void *data)
1504 gchar *path = *(gchar **)data;
1505 gchar *tmp = NULL, *result;
1507 if (path) {
1508 g_free(path);
1509 *(gchar **)data = NULL;
1512 path = g_strjoinv("\t", target);
1514 if (!path) {
1515 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1516 *rc = gpg_error_from_errno(ENOMEM);
1517 return NULL;
1520 if (req_orig) {
1521 tmp = g_strjoinv("\t", req_orig);
1523 if (!tmp) {
1524 g_free(path);
1525 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1526 *rc = gpg_error_from_errno(ENOMEM);
1527 return NULL;
1531 if (tmp && *tmp)
1532 result = g_strdup_printf("%s\t%s", path, tmp);
1533 else
1534 result = g_strdup(path);
1536 if (!result) {
1537 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1538 *rc = gpg_error_from_errno(ENOMEM);
1539 g_free(path);
1540 g_free(tmp);
1541 return NULL;
1544 g_free(path);
1545 g_free(tmp);
1546 *(gchar **)data = result;
1547 return node;
1550 static int realpath_command(assuan_context_t ctx, char *line)
1552 gpg_error_t rc;
1553 struct client_s *client = assuan_get_pointer(ctx);
1554 gchar **req;
1555 gchar *t;
1556 gint i;
1557 xmlNodePtr n;
1558 GString *string;
1559 gchar *rp = NULL;
1561 rc = file_modified(client);
1563 if (rc)
1564 return send_error(ctx, rc);
1566 if (strchr(line, '\t') != NULL) {
1567 if ((req = split_input_line(line, "\t", 0)) == NULL)
1568 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1570 else {
1571 if ((req = split_input_line(line, " ", 0)) == NULL)
1572 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1575 n = find_account(client->doc, &req, &rc, NULL, 0);
1577 if (!n) {
1578 g_strfreev(req);
1579 return send_error(ctx, rc);
1582 rp = g_strjoinv("\t", req);
1584 if (!rp) {
1585 g_strfreev(req);
1586 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1587 return send_syserror(ctx, ENOMEM);
1590 if (req[1]) {
1591 n = find_elements(client->doc, n->children, req+1, &rc,
1592 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1594 if (!n) {
1595 g_free(rp);
1596 g_strfreev(req);
1597 return send_error(ctx, rc);
1601 string = g_string_new(rp);
1602 g_free(rp);
1603 g_strfreev(req);
1605 if (!string) {
1606 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1607 return send_syserror(ctx, ENOMEM);
1610 again:
1611 for (i = 0, t = string->str + i; *t; t++, i++) {
1612 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1613 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1614 goto again;
1618 rc = assuan_send_data(ctx, string->str, string->len);
1619 g_string_free(string, TRUE);
1620 return send_error(ctx, rc);
1623 static int list_command(assuan_context_t ctx, char *line)
1625 struct client_s *client = assuan_get_pointer(ctx);
1626 gpg_error_t rc;
1627 struct element_list_s *elements = NULL;
1628 gchar *tmp;
1630 if (disable_list_and_dump == TRUE)
1631 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1633 rc = file_modified(client);
1635 if (rc)
1636 return send_error(ctx, rc);
1638 if (!*line) {
1639 GString *str;
1641 rc = list_accounts(client->doc, &str);
1643 if (rc)
1644 return send_error(ctx, rc);
1646 rc = assuan_send_data(ctx, str->str, str->len);
1647 g_string_free(str, TRUE);
1648 return send_error(ctx, rc);
1651 elements = g_malloc0(sizeof(struct element_list_s));
1653 if (!elements) {
1654 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1655 rc = gpg_err_code_from_errno(ENOMEM);
1656 goto fail;
1659 rc = create_path_list(client->doc, elements, line);
1661 if (rc)
1662 goto fail;
1664 if (elements) {
1665 gint total = g_slist_length(elements->list);
1666 gint i;
1667 GString *str;
1669 if (!total) {
1670 rc = EPWMD_EMPTY_ELEMENT;
1671 goto fail;
1674 str = g_string_new(NULL);
1676 if (!str) {
1677 rc = gpg_err_code_from_errno(ENOMEM);
1678 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1679 goto fail;
1682 for (i = 0; i < total; i++) {
1683 tmp = g_slist_nth_data(elements->list, i);
1684 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1687 rc = assuan_send_data(ctx, str->str, str->len);
1688 g_string_free(str, TRUE);
1690 else
1691 rc = EPWMD_EMPTY_ELEMENT;
1693 fail:
1694 if (elements) {
1695 gint total = g_slist_length(elements->list);
1696 gint i;
1698 for (i = 0; i < total; i++) {
1699 tmp = g_slist_nth_data(elements->list, i);
1700 g_free(tmp);
1703 g_slist_free(elements->list);
1705 if (elements->prefix)
1706 g_free(elements->prefix);
1708 g_free(elements);
1711 return send_error(ctx, rc);
1714 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1715 const gchar *value)
1717 xmlAttrPtr a;
1719 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1720 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1722 if (!a)
1723 return EPWMD_LIBXML_ERROR;
1725 else
1726 xmlNodeSetContent(a->children, (xmlChar *)value);
1728 return 0;
1732 * req[0] - element path
1734 static int attribute_list(assuan_context_t ctx, gchar **req)
1736 struct client_s *client = assuan_get_pointer(ctx);
1737 gchar **attrlist = NULL;
1738 gint i = 0;
1739 gchar **path = NULL;
1740 xmlAttrPtr a;
1741 xmlNodePtr n, an;
1742 gchar *line;
1743 gpg_error_t rc;
1745 if (!req || !req[0])
1746 return EPWMD_COMMAND_SYNTAX;
1748 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1750 * The first argument may be only an account.
1752 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1753 return EPWMD_COMMAND_SYNTAX;
1756 n = find_account(client->doc, &path, &rc, NULL, 0);
1758 if (!n) {
1759 g_strfreev(path);
1760 return rc;
1763 if (path[1]) {
1764 n = find_elements(client->doc, n->children, path+1, &rc,
1765 NULL, NULL, NULL, FALSE, 0, NULL);
1767 if (!n) {
1768 g_strfreev(path);
1769 return rc;
1773 g_strfreev(path);
1775 for (a = n->properties; a; a = a->next) {
1776 gchar **pa;
1778 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1779 if (attrlist)
1780 g_strfreev(attrlist);
1782 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1783 return gpg_error_from_errno(ENOMEM);
1786 attrlist = pa;
1787 an = a->children;
1788 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name, (gchar *)an->content);
1790 if (!attrlist[i]) {
1791 g_strfreev(attrlist);
1792 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1793 return gpg_error_from_errno(ENOMEM);
1796 attrlist[++i] = NULL;
1799 if (!attrlist)
1800 return EPWMD_EMPTY_ELEMENT;
1802 line = g_strjoinv("\n", attrlist);
1804 if (!line) {
1805 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1806 g_strfreev(attrlist);
1807 return gpg_error_from_errno(ENOMEM);
1810 rc = assuan_send_data(ctx, line, strlen(line));
1811 g_free(line);
1812 g_strfreev(attrlist);
1813 return rc;
1817 * req[0] - attribute
1818 * req[1] - element path
1820 static int attribute_delete(struct client_s *client, gchar **req)
1822 xmlAttrPtr a;
1823 xmlNodePtr n;
1824 gchar **path = NULL;
1825 gpg_error_t rc;
1827 if (!req || !req[0] || !req[1])
1828 return EPWMD_COMMAND_SYNTAX;
1830 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1832 * The first argument may be only an account.
1834 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1835 return EPWMD_COMMAND_SYNTAX;
1839 * Don't remove the "name" attribute for the account element. To remove an
1840 * account use DELETE <account>.
1842 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1843 rc = EPWMD_ATTR_SYNTAX;
1844 goto fail;
1847 n = find_account(client->doc, &path, &rc, NULL, 0);
1849 if (!n)
1850 goto fail;
1852 if (path[1]) {
1853 n = find_elements(client->doc, n->children, path+1, &rc,
1854 NULL, NULL, NULL, FALSE, 0, NULL);
1856 if (!n)
1857 goto fail;
1860 g_strfreev(path);
1862 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1863 return EPWMD_ATTR_NOT_FOUND;
1865 if (xmlRemoveProp(a) == -1)
1866 return EPWMD_LIBXML_ERROR;
1868 return 0;
1870 fail:
1871 g_strfreev(path);
1872 return rc;
1875 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1876 gpg_error_t *rc)
1878 gchar **src = *path;
1879 gchar **src_orig = g_strdupv(src);
1880 xmlNodePtr n = NULL;
1882 *rc = 0;
1884 if (!src_orig) {
1885 *rc = gpg_error_from_errno(ENOMEM);
1886 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1887 goto fail;
1890 again:
1891 n = find_account(client->doc, &src, rc, NULL, 0);
1893 if (!n) {
1894 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1895 *rc = new_account(client->doc, src[0]);
1897 if (*rc)
1898 goto fail;
1900 goto again;
1902 else
1903 goto fail;
1906 if (src[1]) {
1907 if (!n->children)
1908 n = create_target_elements_cb(n, src+1, rc, NULL);
1909 else
1910 n = find_elements(client->doc, n->children, src+1, rc,
1911 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1913 if (!n)
1914 goto fail;
1917 * Reset the position of the element tree now that the elements
1918 * have been created.
1920 g_strfreev(src);
1921 src = src_orig;
1922 src_orig = NULL;
1923 n = find_account(client->doc, &src, rc, NULL, 0);
1925 if (!n)
1926 goto fail;
1928 n = find_elements(client->doc, n->children, src+1, rc,
1929 NULL, NULL, NULL, FALSE, 0, NULL);
1931 if (!n)
1932 goto fail;
1935 fail:
1936 if (src_orig)
1937 g_strfreev(src_orig);
1939 *path = src;
1940 return n;
1944 * Creates a "target" attribute. When other commands encounter an element with
1945 * this attribute, the element path is modified to the target value. If the
1946 * source element path doesn't exist when using 'ATTR SET target', it is
1947 * created, but the destination element path must exist.
1949 * req[0] - source element path
1950 * req[1] - destination element path
1952 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1954 gchar **src, **dst, *line = NULL;
1955 gpg_error_t rc;
1956 xmlNodePtr n;
1958 if (!req || !req[0] || !req[1])
1959 return EPWMD_COMMAND_SYNTAX;
1961 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1963 * The first argument may be only an account.
1965 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1966 return EPWMD_COMMAND_SYNTAX;
1969 if (valid_element_path(src, FALSE) == FALSE) {
1970 g_strfreev(src);
1971 return EPWMD_INVALID_ELEMENT;
1974 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1976 * The first argument may be only an account.
1978 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1979 rc = EPWMD_COMMAND_SYNTAX;
1980 goto fail;
1984 n = find_account(client->doc, &dst, &rc, NULL, 0);
1987 * Make sure the destination element path exists.
1989 if (!n)
1990 goto fail;
1992 if (dst[1]) {
1993 n = find_elements(client->doc, n->children, dst+1, &rc,
1994 NULL, NULL, NULL, FALSE, 0, NULL);
1996 if (!n)
1997 goto fail;
2000 n = create_element_path(client, &src, &rc);
2002 if (rc)
2003 goto fail;
2005 line = g_strjoinv("\t", dst);
2007 if (!line) {
2008 rc = gpg_error_from_errno(ENOMEM);
2009 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2010 goto fail;
2013 rc = add_attribute(n, "target", line);
2015 fail:
2016 g_free(line);
2017 g_strfreev(src);
2018 g_strfreev(dst);
2019 return rc;
2023 * req[0] - account name
2024 * req[1] - new name
2026 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2028 gpg_error_t rc;
2029 gchar **tmp;
2030 xmlNodePtr n;
2032 tmp = g_strdupv(req);
2034 if (!tmp) {
2035 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2036 return gpg_error_from_errno(ENOMEM);
2039 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2040 g_strfreev(tmp);
2042 if (!n)
2043 return rc;
2045 if (g_utf8_collate(req[0], req[1]) == 0)
2046 return 0;
2049 * Will not overwrite an existing account.
2051 tmp = g_strdupv(req+1);
2053 if (!tmp) {
2054 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2055 return gpg_error_from_errno(ENOMEM);
2058 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2059 g_strfreev(tmp);
2061 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
2062 return rc;
2064 if (n)
2065 return EPWMD_ACCOUNT_EXISTS;
2068 * Whitespace not allowed in account names.
2070 if (contains_whitespace(req[1]) == TRUE)
2071 return EPWMD_ATTR_SYNTAX;
2073 tmp = g_strdupv(req);
2075 if (!tmp) {
2076 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2077 return gpg_error_from_errno(ENOMEM);
2080 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2081 g_strfreev(tmp);
2083 if (!n)
2084 return EPWMD_ELEMENT_NOT_FOUND;
2086 return add_attribute(n, "name", req[1]);
2090 * req[0] - attribute
2091 * req[1] - element path
2093 static int attribute_get(assuan_context_t ctx, gchar **req)
2095 struct client_s *client = assuan_get_pointer(ctx);
2096 xmlNodePtr n;
2097 xmlChar *a;
2098 gchar **path= NULL;
2099 gpg_error_t rc;
2101 if (!req || !req[0] || !req[1])
2102 return EPWMD_COMMAND_SYNTAX;
2104 if (strchr(req[1], '\t')) {
2105 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2106 return EPWMD_COMMAND_SYNTAX;
2108 else {
2109 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2110 return EPWMD_COMMAND_SYNTAX;
2113 n = find_account(client->doc, &path, &rc, NULL, 0);
2115 if (!n)
2116 goto fail;
2118 if (path[1]) {
2119 n = find_elements(client->doc, n->children, path+1, &rc,
2120 NULL, NULL, NULL, FALSE, 0, NULL);
2122 if (!n)
2123 goto fail;
2126 g_strfreev(path);
2128 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2129 return EPWMD_ATTR_NOT_FOUND;
2131 rc = assuan_send_data(ctx, a, xmlStrlen(a));
2132 xmlFree(a);
2133 return rc;
2135 fail:
2136 g_strfreev(path);
2137 return rc;
2141 * req[0] - attribute
2142 * req[1] - element path
2143 * req[2] - value
2145 static int attribute_set(struct client_s *client, gchar **req)
2147 gchar **path = NULL;
2148 gpg_error_t rc;
2149 xmlNodePtr n;
2151 if (!req || !req[0] || !req[1] || !req[2])
2152 return EPWMD_COMMAND_SYNTAX;
2155 * Reserved attribute names.
2157 if (g_utf8_collate(req[0], "name") == 0) {
2159 * Only reserved for the account element. Not the rest of the
2160 * document.
2162 if (strchr(req[1], '\t') == NULL)
2163 return name_attribute(client, req + 1);
2165 else if (g_utf8_collate(req[0], "target") == 0)
2166 return target_attribute(client, req + 1);
2168 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2170 * The first argument may be only an account.
2172 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2173 return EPWMD_COMMAND_SYNTAX;
2176 n = find_account(client->doc, &path, &rc, NULL, 0);
2178 if (!n)
2179 goto fail;
2181 if (path[1]) {
2182 n = find_elements(client->doc, n->children, path+1, &rc,
2183 NULL, NULL, NULL, FALSE, 0, NULL);
2185 if (!n)
2186 goto fail;
2189 g_strfreev(path);
2190 return add_attribute(n, req[0], req[2]);
2192 fail:
2193 g_strfreev(path);
2194 return rc;
2198 * req[0] - command
2199 * req[1] - attribute name or element path if command is LIST
2200 * req[2] - element path
2201 * req[2] - element path or value
2203 static int attr_command(assuan_context_t ctx, char *line)
2205 struct client_s *client = assuan_get_pointer(ctx);
2206 gchar **req;
2207 gpg_error_t rc = 0;
2209 rc = file_modified(client);
2211 if (rc)
2212 return send_error(ctx, rc);
2214 req = split_input_line(line, " ", 4);
2216 if (!req || !req[0] || !req[1]) {
2217 g_strfreev(req);
2218 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2221 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2222 rc = attribute_set(client, req+1);
2223 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2224 rc = attribute_get(ctx, req+1);
2225 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2226 rc = attribute_delete(client, req+1);
2227 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2228 rc = attribute_list(ctx, req+1);
2229 else
2230 rc = EPWMD_COMMAND_SYNTAX;
2232 g_strfreev(req);
2233 return send_error(ctx, rc);
2236 static int iscached_command(assuan_context_t ctx, char *line)
2238 gchar **req = split_input_line(line, " ", 0);
2239 guchar md5file[16];
2241 if (!req || !*req) {
2242 g_strfreev(req);
2243 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2246 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2247 g_strfreev(req);
2248 CACHE_LOCK(ctx);
2250 if (cache_iscached(md5file) == FALSE) {
2251 CACHE_UNLOCK;
2252 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2255 CACHE_UNLOCK;
2256 return send_error(ctx, 0);
2259 static int clearcache_command(assuan_context_t ctx, char *line)
2261 struct client_s *client = assuan_get_pointer(ctx);
2262 gchar **req = split_input_line(line, " ", 0);
2263 guchar md5file[16];
2265 CACHE_LOCK(ctx);
2267 if (!req || !*req) {
2268 g_strfreev(req);
2269 cache_clear(client->md5file, 2);
2270 CACHE_UNLOCK;
2271 return send_error(ctx, 0);
2274 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2275 g_strfreev(req);
2277 if (cache_clear(md5file, 1) == FALSE) {
2278 CACHE_UNLOCK;
2279 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2282 CACHE_UNLOCK;
2283 return send_error(ctx, 0);
2286 static int cachetimeout_command(assuan_context_t ctx, char *line)
2288 guchar md5file[16];
2289 glong timeout;
2290 gchar **req = split_input_line(line, " ", 0);
2291 gchar *p;
2292 struct client_s *client = assuan_get_pointer(ctx);
2294 if (!req || !*req || !req[1]) {
2295 g_strfreev(req);
2296 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2299 errno = 0;
2300 timeout = strtol(req[0], &p, 10);
2302 if (errno != 0 || *p != 0) {
2303 g_strfreev(req);
2304 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2307 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2308 g_strfreev(req);
2309 CACHE_LOCK(client->ctx);
2311 if (cache_set_timeout(md5file, timeout) == FALSE) {
2312 CACHE_UNLOCK;
2313 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2316 CACHE_UNLOCK;
2317 return send_error(ctx, 0);
2320 static int dump_command(assuan_context_t ctx, char *line)
2322 xmlChar *xml;
2323 gssize len;
2324 struct client_s *client = assuan_get_pointer(ctx);
2325 gpg_error_t rc;
2327 if (disable_list_and_dump == TRUE)
2328 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2330 rc = file_modified(client);
2332 if (rc)
2333 return send_error(ctx, rc);
2335 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2337 if (!xml) {
2338 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2339 return send_syserror(ctx, ENOMEM);
2342 rc = assuan_send_data(ctx, xml, len);
2343 xmlFree(xml);
2344 return send_error(ctx, rc);
2347 static int getconfig_command(assuan_context_t ctx, gchar *line)
2349 struct client_s *client = assuan_get_pointer(ctx);
2350 gpg_error_t rc = 0;
2351 gchar filename[255]={0}, param[747]={0};
2352 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2354 if (strchr(line, ' ')) {
2355 sscanf(line, " %254[^ ] %746c", filename, param);
2356 fp = filename;
2357 paramp = param;
2360 if (fp && !valid_filename(fp))
2361 return send_error(ctx, EPWMD_INVALID_FILENAME);
2363 paramp = g_ascii_strdown(paramp, -1);
2365 if (!paramp) {
2366 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2367 return send_syserror(ctx, ENOMEM);
2370 p = get_key_file_string(fp ? fp : "global", paramp);
2371 g_free(paramp);
2373 if (!p)
2374 return send_error(ctx, GPG_ERR_NO_VALUE);
2376 tmp = expand_homedir(p);
2377 g_free(p);
2379 if (!tmp) {
2380 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2381 return send_syserror(ctx, ENOMEM);
2384 p = tmp;
2385 rc = assuan_send_data(ctx, p, strlen(p));
2386 g_free(p);
2387 return send_error(ctx, rc);
2390 static int xpath_command(assuan_context_t ctx, gchar *line)
2392 struct client_s *client = assuan_get_pointer(ctx);
2393 gpg_error_t rc;
2394 xmlXPathContextPtr xp;
2395 xmlXPathObjectPtr result;
2396 xmlBufferPtr buf = NULL;
2397 gchar **req = NULL;
2399 if (disable_list_and_dump == TRUE)
2400 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2402 rc = file_modified(client);
2404 if (rc)
2405 return send_error(ctx, rc);
2407 if (!line || !*line)
2408 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2410 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2411 if (strv_printf(&req, "%s", line) == FALSE)
2412 return send_syserror(ctx, ENOMEM);
2415 xp = xmlXPathNewContext(client->doc);
2417 if (!xp)
2418 return send_error(ctx, EPWMD_LIBXML_ERROR);
2420 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2422 if (!result) {
2423 xmlXPathFreeContext(xp);
2424 return send_error(ctx, EPWMD_LIBXML_ERROR);
2427 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2428 rc = EPWMD_EMPTY_ELEMENT;
2429 goto fail;
2432 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2433 (xmlChar *)req[1], &buf);
2435 if (rc)
2436 goto fail;
2437 else if (!req[1] && !xmlBufferLength(buf)) {
2438 rc = EPWMD_EMPTY_ELEMENT;
2439 goto fail;
2441 else if (req[1])
2442 goto fail;
2444 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2446 fail:
2447 g_strfreev(req);
2449 if (buf)
2450 xmlBufferFree(buf);
2452 if (result)
2453 xmlXPathFreeObject(result);
2455 if (xp)
2456 xmlXPathFreeContext(xp);
2458 return send_error(ctx, rc);
2461 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2462 gsize len)
2464 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2465 gpg_error_t rc = file_modified(client);
2466 gchar **req, **path = NULL, **path_orig = NULL, *content;
2467 xmlDocPtr doc;
2468 xmlNodePtr n, root, copy;
2470 if (assuan_rc || rc) {
2471 if (line)
2472 xfree(line);
2473 return assuan_rc ? assuan_rc : rc;
2476 req = split_input_line((gchar *)line, " ", 2);
2477 xfree(line);
2479 if (!req || !*req)
2480 return EPWMD_COMMAND_SYNTAX;
2482 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2483 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2484 return EPWMD_COMMAND_SYNTAX;
2487 content = req[1];
2489 if (!content || !*content) {
2490 rc = EPWMD_COMMAND_SYNTAX;
2491 goto fail;
2494 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2495 rc = EPWMD_INVALID_ELEMENT;
2496 goto fail;
2499 if (valid_element_path(path+1, FALSE) == FALSE) {
2500 rc = EPWMD_INVALID_ELEMENT;
2501 goto fail;
2504 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2506 if (!doc) {
2507 rc = EPWMD_LIBXML_ERROR;
2508 goto fail;
2511 root = xmlDocGetRootElement(doc);
2512 path_orig = g_strdupv(path);
2514 if (!path_orig) {
2515 xmlFreeDoc(doc);
2516 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2517 rc = gpg_error_from_errno(ENOMEM);
2518 goto fail;
2521 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2522 g_strfreev(path_orig);
2523 xmlFreeDoc(doc);
2524 rc = gpg_error_from_errno(ENOMEM);
2525 goto fail;
2528 n = find_account(client->doc, &path, &rc, NULL, 0);
2530 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2531 g_strfreev(path_orig);
2532 xmlFreeDoc(doc);
2533 goto fail;
2535 else if (!rc) {
2536 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2538 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2539 g_strfreev(path_orig);
2540 xmlFreeDoc(doc);
2541 goto fail;
2543 else if (!rc) {
2544 xmlNodePtr parent = n->parent;
2546 xmlUnlinkNode(n);
2547 xmlFreeNode(n);
2548 n = parent;
2552 g_strfreev(path);
2553 path = path_orig;
2555 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2556 n = create_element_path(client, &path, &rc);
2558 if (rc) {
2559 xmlFreeDoc(doc);
2560 goto fail;
2564 copy = xmlCopyNode(root, 1);
2565 n = xmlAddChild(n, copy);
2566 xmlFreeDoc(doc);
2568 if (!n)
2569 rc = EPWMD_LIBXML_ERROR;
2571 fail:
2572 g_strfreev(path);
2573 g_strfreev(req);
2574 client->inquire_status = INQUIRE_DONE;
2575 return rc;
2578 static int import_command(assuan_context_t ctx, gchar *line)
2580 gpg_error_t rc;
2581 struct client_s *client = assuan_get_pointer(ctx);
2583 rc = file_modified(client);
2585 if (rc)
2586 return send_error(ctx, rc);
2588 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2590 if (rc)
2591 return send_error(ctx, rc);
2593 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2594 client->inquire_status = INQUIRE_BUSY;
2595 return 0;
2598 static int lock_command(assuan_context_t ctx, gchar *line)
2600 gpg_error_t rc;
2601 struct client_s *client = assuan_get_pointer(ctx);
2603 rc = file_modified(client);
2605 if (rc)
2606 return send_error(ctx, rc);
2608 rc = lock_file_mutex(client);
2610 if (!rc)
2611 client->is_lock_cmd = TRUE;
2613 return send_error(ctx, rc);
2616 static int unlock_command(assuan_context_t ctx, gchar *line)
2618 struct client_s *client = assuan_get_pointer(ctx);
2619 gpg_error_t rc = file_modified(client);
2621 if (rc)
2622 return send_error(ctx, rc);
2624 unlock_file_mutex(client);
2625 return send_error(ctx, 0);
2628 static int getpid_command(assuan_context_t ctx, gchar *line)
2630 gpg_error_t rc;
2631 gchar buf[32];
2632 pid_t pid = getpid();
2634 print_fmt(buf, sizeof(buf), "%i", pid);
2635 rc = assuan_send_data(ctx, buf, strlen(buf));
2636 return send_error(ctx, rc);
2639 static int version_command(assuan_context_t ctx, gchar *line)
2641 gpg_error_t rc;
2642 gchar buf[32];
2644 print_fmt(buf, sizeof(buf), "%s", PACKAGE_VERSION);
2645 rc = assuan_send_data(ctx, buf, strlen(buf));
2646 return send_error(ctx, rc);
2649 static void bye_notify(assuan_context_t ctx)
2651 struct client_s *cl = assuan_get_pointer(ctx);
2652 #ifdef WITH_GNUTLS
2653 gint rc;
2655 if (!cl->thd->remote)
2656 return;
2658 do {
2659 rc = gnutls_bye(cl->thd->tls->ses, GNUTLS_SHUT_RDWR);
2660 } while (rc == GNUTLS_E_AGAIN);
2661 #endif
2663 /* This will let assuan_process_next() return. */
2664 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
2667 static void reset_notify(assuan_context_t ctx)
2669 struct client_s *cl = assuan_get_pointer(ctx);
2671 if (cl)
2672 cleanup_client(cl);
2675 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2677 gchar name[32] = {0}, value[256] = {0};
2679 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2680 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2682 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2683 struct client_s *cl = assuan_get_pointer(ctx);
2685 if (cl->thd->name)
2686 g_free(cl->thd->name);
2688 cl->thd->name = g_strdup(value);
2689 log_write("OPTION CLIENT %s", line);
2691 else
2692 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2694 return 0;
2697 static int option_handler(assuan_context_t ctx, const gchar *name,
2698 const gchar *value)
2700 struct client_s *client = assuan_get_pointer(ctx);
2702 if (!value || !*value)
2703 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2705 if (g_strcasecmp(name, (gchar *)"client") == 0)
2706 return parse_client_option(ctx, value);
2708 if (g_strcasecmp(name, (gchar *)"iterations") == 0) {
2709 long n;
2710 gchar *p = NULL;
2712 errno = 0;
2713 n = strtol(value, &p, 10);
2715 if (errno || (p && *p) || n < 0)
2716 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2718 g_key_file_set_integer(keyfileh, client->filename ? client->filename : "global", "iterations", (guint)n);
2719 send_status_all(STATUS_CONFIG);
2721 #ifdef WITH_PINENTRY
2722 else if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2723 g_free(client->pinentry->ttyname);
2724 client->pinentry->ttyname = g_strdup(value);
2726 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2727 g_free(client->pinentry->ttytype);
2728 client->pinentry->ttytype = g_strdup(value);
2730 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2731 g_free(client->pinentry->display);
2732 client->pinentry->display = g_strdup(value);
2734 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2735 g_free(client->pinentry->path);
2736 client->pinentry->path = g_strdup(value);
2738 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2739 g_free(client->pinentry->title);
2740 client->pinentry->title = g_strdup(value);
2742 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2743 g_free(client->pinentry->prompt);
2744 client->pinentry->prompt = g_strdup(value);
2746 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2747 g_free(client->pinentry->desc);
2748 client->pinentry->desc = g_strdup(value);
2751 * Look at client_thread() to see how this works.
2753 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2754 gchar *p = NULL;
2755 gint n = strtol(value, &p, 10);
2757 if (*p || n < 0)
2758 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2760 client->pinentry->timeout = n;
2762 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2763 gchar *p = NULL;
2764 gint n = strtol(value, &p, 10);
2766 if (*p || n < 0 || n > 1)
2767 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2769 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2771 #endif
2772 else
2773 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2775 log_write("OPTION %s=%s", name, value);
2776 return 0;
2779 gpg_error_t register_commands(assuan_context_t ctx)
2781 static struct {
2782 const gchar *name;
2783 gint (*handler)(assuan_context_t, gchar *line);
2784 } table[] = {
2785 { "OPEN", open_command },
2786 { "SAVE", save_command },
2787 { "LIST", list_command },
2788 { "REALPATH", realpath_command },
2789 { "STORE", store_command },
2790 { "DELETE", delete_command },
2791 { "GET", get_command },
2792 { "ATTR", attr_command },
2793 { "ISCACHED", iscached_command },
2794 { "CLEARCACHE", clearcache_command },
2795 { "CACHETIMEOUT", cachetimeout_command },
2796 { "GETCONFIG", getconfig_command },
2797 { "DUMP", dump_command },
2798 { "XPATH", xpath_command },
2799 { "IMPORT", import_command },
2800 { "LOCK", lock_command },
2801 { "UNLOCK", unlock_command },
2802 { "GETPID", getpid_command },
2803 { "VERSION", version_command },
2804 { "INPUT", NULL },
2805 { "OUTPUT", NULL },
2806 { NULL, NULL }
2808 gint i, rc;
2810 for (i=0; table[i].name; i++) {
2811 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2813 if (rc)
2814 return rc;
2817 rc = assuan_register_bye_notify(ctx, bye_notify);
2819 if (rc)
2820 return rc;
2822 rc = assuan_register_option_handler(ctx, option_handler);
2824 if (rc)
2825 return rc;
2827 rc = assuan_register_reset_notify(ctx, reset_notify);
2829 if (rc)
2830 return rc;
2832 return assuan_register_post_cmd_notify(ctx, command_finalize);
2835 gpg_error_t try_xml_decrypt(assuan_context_t ctx, guchar *key,
2836 struct client_crypto_s *crypto, gpointer *dst, gsize *dst_len)
2838 gsize insize, len;
2839 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2840 guint iter = 0, n_iter = 0, iter_progress = 0;
2841 gint zrc = 0;
2842 gulong outsize = 0;
2843 gpg_error_t rc;
2844 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->fh1) : sizeof(crypto->fh->fh2);
2845 glong fh_iter = crypto->fh->v1 ? crypto->fh->fh1.iter : crypto->fh->fh2.iter;
2847 lseek(crypto->fh->fd, fh_size, SEEK_SET);
2848 insize = crypto->fh->st.st_size - fh_size;
2849 crypto->iv = gcry_malloc(gcryblocksize);
2851 if (!crypto->iv) {
2852 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2853 return gpg_error_from_errno(ENOMEM);
2856 /* No encryption iterations. This is a plain (gzipped) file. */
2857 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0)) {
2859 * cache_file_count() needs both .used == TRUE and a valid key in
2860 * order for it to count as a used cache entry. Fixes CACHE status
2861 * messages.
2863 memset(key, '!', gcrykeysize);
2866 if (crypto->fh->v1)
2867 memcpy(crypto->iv, crypto->fh->fh1.iv, gcryblocksize);
2868 else
2869 memcpy(crypto->iv, crypto->fh->fh2.iv, gcryblocksize);
2871 crypto->inbuf = gcry_malloc(insize);
2873 if (!crypto->inbuf) {
2874 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2875 return gpg_error_from_errno(ENOMEM);
2878 len = read(crypto->fh->fd, crypto->inbuf, insize);
2880 if (len != insize)
2881 return GPG_ERR_INV_LENGTH;
2883 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0))
2884 goto decompress;
2886 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
2887 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2888 return rc;
2891 if ((rc = gcry_cipher_setkey(crypto->gh, key, gcrykeysize))) {
2892 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2893 return rc;
2896 iter_progress = (guint)get_key_file_integer(client && client->filename ?
2897 client->filename : "global", "iteration_progress");
2899 if (iter_progress > 0 && fh_iter >= iter_progress) {
2900 rc = send_status(ctx, STATUS_DECRYPT, "%u %u", 0, fh_iter);
2902 if (rc)
2903 return rc;
2906 rc = decrypt_xml(crypto->gh, crypto->inbuf, insize, NULL, 0);
2908 if (rc)
2909 return rc;
2911 crypto->tkey = gcry_malloc(gcrykeysize);
2913 if (!crypto->tkey) {
2914 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
2915 return gpg_error_from_errno(ENOMEM);
2918 memcpy(crypto->tkey, key, gcrykeysize);
2919 guchar *tkey = crypto->tkey;
2920 tkey[0] ^= 1;
2922 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
2923 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2924 return rc;
2927 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
2928 if (iter_progress > 0 && iter >= iter_progress) {
2929 if (!(iter % iter_progress)) {
2930 rc = send_status(ctx, STATUS_DECRYPT, "%u %u",
2931 ++n_iter * iter_progress, fh_iter);
2933 if (rc)
2934 return rc;
2938 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
2939 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2940 return rc;
2943 rc = decrypt_xml(crypto->gh, crypto->inbuf, insize, NULL, 0);
2945 if (rc) {
2946 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2947 return rc;
2950 iter++;
2953 if (iter_progress && fh_iter >= iter_progress) {
2954 rc = send_status(ctx, STATUS_DECRYPT, "%u %u", fh_iter, fh_iter);
2956 if (rc)
2957 return rc;
2960 decompress:
2961 if (do_decompress(ctx, crypto->inbuf, insize, (gpointer *)&crypto->outbuf,
2962 &outsize, &zrc) == FALSE) {
2963 if (zrc == Z_MEM_ERROR)
2964 return gpg_error_from_errno(ENOMEM);
2965 else
2966 return EPWMD_BADKEY; // Not a valid gzip header. Must be a bad key.
2969 if (g_strncasecmp(crypto->outbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2970 gcry_free(crypto->outbuf);
2971 crypto->outbuf = NULL;
2972 return EPWMD_BADKEY;
2975 if (ctx) {
2976 client->xml = crypto->outbuf;
2977 client->len = outsize;
2978 crypto->outbuf = NULL;
2980 else if (dst) {
2981 *dst = crypto->outbuf;
2982 *dst_len = outsize;
2983 crypto->outbuf = NULL;
2986 /* The calling function should free the crypto struct. */
2987 return 0;
2991 * This is called after every Assuan command.
2993 void command_finalize(assuan_context_t ctx, gint rc)
2995 struct client_s *client = assuan_get_pointer(ctx);
2997 if (!client->is_lock_cmd)
2998 unlock_file_mutex(client);