1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
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
24 #include <sys/types.h>
44 #include "pwmd_error.h"
53 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
55 return gcry_calloc(items
, size
);
58 static void z_free(void *data
, void *p
)
63 static gpg_error_t
file_modified(struct client_s
*client
)
68 if (client
->state
!= STATE_OPEN
)
71 rc
= lock_file_mutex(client
);
76 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
77 if (client
->mtime
!= st
.st_mtime
)
78 return EPWMD_FILE_MODIFIED
;
84 static gpg_error_t
parse_xml(assuan_context_t ctx
)
86 struct client_s
*client
= assuan_get_pointer(ctx
);
88 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
91 return EPWMD_LIBXML_ERROR
;
96 void unlock_file_mutex(struct client_s
*client
)
98 struct file_mutex_s
*m
;
101 if (client
->has_lock
== FALSE
|| client
->pinentry
->status
!= PINENTRY_NONE
)
103 if (client
->has_lock
== FALSE
)
107 CACHE_LOCK(client
->ctx
);
109 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
115 MUTEX_UNLOCK(&m
->mutex
);
116 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
119 gpg_error_t
lock_file_mutex(struct client_s
*client
)
121 struct file_mutex_s
*m
;
123 if (client
->has_lock
== TRUE
)
126 CACHE_LOCK(client
->ctx
);
128 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
135 if (pthread_mutex_trylock(&m
->mutex
) == EBUSY
) {
138 * If a client disconnects unexpectedly while waiting for a
139 * lock, this lets the thread terminate because send_status()
140 * will return an error.
142 while (pthread_mutex_trylock(&m
->mutex
) == EBUSY
) {
143 gpg_error_t rc
= send_status(client
->ctx
, STATUS_LOCKED
, NULL
);
152 MUTEX_LOCK(&m
->mutex
);
159 client
->has_lock
= TRUE
;
163 void free_client(struct client_s
*client
)
166 xmlFreeDoc(client
->doc
);
169 gcry_free(client
->xml
);
171 if (client
->filename
)
172 g_free(client
->filename
);
175 cleanup_crypto(&client
->crypto
);
178 void cleanup_client(struct client_s
*client
)
180 assuan_context_t ctx
= client
->ctx
;
181 struct client_thread_s
*thd
= client
->thd
;
182 gboolean has_lock
= client
->has_lock
;
184 struct pinentry_s
*pin
= client
->pinentry
;
187 unlock_file_mutex(client
);
188 CACHE_LOCK(client
->ctx
);
189 cache_decr_refcount(client
->md5file
);
192 * This may be a new file so don't use a cache slot. save_command() will
193 * set this to FALSE on success.
195 if (client
->new == TRUE
)
196 cache_clear(client
->md5file
, 1);
199 memset(client
, 0, sizeof(struct client_s
));
200 client
->state
= STATE_CONNECTED
;
203 client
->freed
= TRUE
;
205 client
->pinentry
= pin
;
207 client
->has_lock
= has_lock
;
211 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
212 gpointer
*out
, gulong
*outsize
, gint
*rc
)
222 z
.avail_in
= (uInt
)insize
;
223 z
.avail_out
= zlib_bufsize
;
224 z
.next_out
= pout
= gcry_malloc(zlib_bufsize
);
227 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
232 *rc
= inflateInit2(&z
, 47);
235 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
240 memset(&h
, 0, sizeof(gz_header
));
241 h
.comment
= (guchar
*)buf
;
242 h
.comm_max
= sizeof(buf
);
243 *rc
= inflateGetHeader(&z
, &h
);
246 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
252 *rc
= inflate(&z
, Z_BLOCK
);
255 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
262 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
267 *rc
= inflate(&z
, Z_FINISH
);
274 p
= gcry_realloc(pout
, z
.total_out
+ zlib_bufsize
);
277 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
283 z
.next_out
= pout
+ z
.total_out
;
284 z
.avail_out
= zlib_bufsize
;
285 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
286 z
.total_out
, insize
);
297 } while (*rc
!= Z_STREAM_END
);
299 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", z
.total_out
,
306 *outsize
= z
.total_out
;
312 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
318 static void read_file_header_handler(void *arg
)
323 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
328 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
334 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
335 *rc
= gpg_error_from_errno(ENOMEM
);
339 fh_size
= v1
? sizeof(fh
->fh1
) : sizeof(fh
->fh2
);
341 if (lstat(filename
, &fh
->st
) == -1) {
342 *rc
= gpg_error_from_syserror();
347 if (!S_ISREG(fh
->st
.st_mode
)) {
348 *rc
= GPG_ERR_ENOANO
;
353 fd
= open(filename
, O_RDONLY
);
356 *rc
= gpg_error_from_errno(errno
);
362 len
= read(fd
, &fh
->fh1
, fh_size
);
364 len
= read(fd
, &fh
->fh2
, fh_size
);
366 if (len
!= fh_size
) {
368 pthread_cleanup_push(read_file_header_handler
, (void *)fd
);
370 pthread_cleanup_pop(1);
371 *rc
= gpg_error_from_errno(n
);
380 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*key
,
383 struct client_s
*client
= assuan_get_pointer(ctx
);
388 if (!client
->crypto
->fh
) {
395 rc
= try_xml_decrypt(ctx
, key
, client
->crypto
, NULL
, NULL
);
398 cleanup_client(client
);
399 return send_error(ctx
, rc
);
403 CACHE_LOCK(client
->ctx
);
405 if (cached
== FALSE
) {
406 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
407 cleanup_client(client
);
409 return send_syserror(ctx
, ENOMEM
);
412 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
413 cache_reset_timeout(client
->md5file
, timeout
);
416 cache_set_timeout(client
->md5file
, -2);
424 gcry_free(client
->xml
);
429 if (client
->new == FALSE
)
430 send_status_all(STATUS_CACHE
);
432 client
->state
= STATE_OPEN
;
435 if (!rc
&& client
->new == FALSE
&&
436 client
->crypto
->fh
->fh2
.iter
!= (guint
)get_key_file_integer(client
->filename
, "iterations")) {
437 g_key_file_set_integer(keyfileh
, client
->filename
, "iterations",
438 client
->crypto
->fh
->fh2
.iter
);
439 send_status_all(STATUS_CONFIG
);
443 log_write("OPEN '%s'", client
->filename
);
445 cleanup_crypto(&client
->crypto
);
446 return send_error(ctx
, rc
);
450 static gboolean
validate_access(struct client_s
*cl
, const gchar
*filename
)
452 gchar
*access
= get_key_file_string(filename
, "tcp_access");
458 list
= g_strsplit(access
, ",", -1);
462 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
466 for (p
= list
; *p
; p
++) {
467 gboolean
not = FALSE
;
478 if (strcasecmp(cl
->thd
->tls
->fp
, fp
) == 0) {
493 static void open_command_cleanup_handler(void *arg
)
495 g_strfreev((gchar
**)arg
);
498 static int open_command(assuan_context_t ctx
, char *line
)
500 gboolean cached
= FALSE
;
502 struct client_s
*client
= assuan_get_pointer(ctx
);
504 gchar
*filename
= NULL
;
506 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
509 pthread_cleanup_push(open_command_cleanup_handler
, req
);
511 if (!filename
|| !*filename
) {
513 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
516 if (valid_filename(filename
) == FALSE
) {
518 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
521 if (client
->state
== STATE_OPEN
)
522 cleanup_client(client
);
525 if (client
->thd
->remote
== TRUE
) {
526 if (validate_access(client
, filename
) == FALSE
) {
527 log_write(N_("client validation failed for file '%s'"), filename
);
529 return send_error(ctx
, EPWMD_FILE_ACCESS
);
534 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
535 CACHE_LOCK(client
->ctx
);
537 if (cache_has_file(client
->md5file
) == FALSE
) {
538 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
541 return send_syserror(ctx
, ENOMEM
);
545 cache_incr_refcount(client
->md5file
);
547 rc
= lock_file_mutex(client
);
551 return send_error(ctx
, rc
);
554 client
->freed
= FALSE
;
555 client
->crypto
= init_client_crypto();
557 if (!client
->crypto
) {
559 cleanup_client(client
);
560 return send_syserror(ctx
, ENOMEM
);
563 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
565 if (!client
->crypto
->key
) {
567 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
568 gpg_error_from_errno(ENOMEM
));
569 cleanup_client(client
);
570 return send_syserror(ctx
, ENOMEM
);
573 memset(client
->crypto
->key
, 0, gcrykeysize
);
574 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
575 pthread_testcancel();
577 if (!client
->crypto
->fh
) {
578 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
579 log_write("%s: %s", filename
, pwmd_strerror(rc
));
581 cleanup_client(client
);
582 return send_error(ctx
, rc
);
586 * New files don't need a key.
588 if ((client
->xml
= new_document()) == NULL
) {
589 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
591 cleanup_client(client
);
592 return send_syserror(ctx
, ENOMEM
);
595 client
->len
= xmlStrlen(client
->xml
);
597 client
->filename
= g_strdup(filename
);
599 if (!client
->filename
) {
601 cleanup_client(client
);
602 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
603 return send_syserror(ctx
, ENOMEM
);
606 if (req
[1] && *req
[1])
607 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
612 client
->pinentry
->filename
= g_strdup(client
->filename
);
614 if (!client
->pinentry
->filename
) {
615 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
616 cleanup_client(client
);
617 return send_syserror(ctx
, ENOMEM
);
620 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
623 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
625 client
->filename
= g_strdup(filename
);
627 if (!client
->filename
) {
628 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
630 cleanup_client(client
);
631 return send_syserror(ctx
, ENOMEM
);
635 client
->pinentry
->filename
= g_strdup(client
->filename
);
637 if (!client
->pinentry
->filename
) {
638 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
640 cleanup_client(client
);
641 return send_syserror(ctx
, ENOMEM
);
645 if (client
->crypto
->fh
->fh2
.iter
<= 0)
649 if (client
->thd
->remote
== FALSE
||
650 get_key_file_boolean(client
->filename
, "tcp_require_key") == FALSE
)
653 CACHE_LOCK(client
->ctx
);
654 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
662 if (cached
== FALSE
) {
663 gchar
*tmp
= get_key_file_string(filename
, "key_file");
667 cleanup_client(client
);
668 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
672 * No key specified and no matching filename found in the cache. Use
673 * pinentry to retrieve the key. Cannot return assuan_process_done()
674 * here otherwise the command will be interrupted. The event loop in
675 * client_thread() will poll the file descriptor waiting for it to
676 * become ready to read a pinentry_key_s which will contain the
677 * entered key or an error code. It will then call
678 * open_command_finalize() to to finish the command.
680 if (!req
[1] || !*req
[1]) {
682 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
684 /* From set_pinentry_defaults(). */
685 if (client
->pinentry
->enable
== FALSE
||
686 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
687 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
692 rc
= lock_pin_mutex(client
);
695 unlock_pin_mutex(client
->pinentry
);
696 cleanup_client(client
);
697 return send_error(ctx
, rc
);
700 client
->pinentry
->which
= PINENTRY_OPEN
;
701 rc
= pinentry_fork(ctx
);
704 unlock_pin_mutex(client
->pinentry
);
705 cleanup_client(client
);
706 return send_error(ctx
, rc
);
709 // Called from pinentry iterate.
710 client
->pinentry
->cb
= open_command_finalize
;
711 client
->pinentry
->status
= PINENTRY_INIT
;
714 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
719 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
725 pthread_cleanup_pop(1);
726 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
729 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
730 gulong size
, gpointer
*out
, gulong
*outsize
, gint
*rc
)
736 gint cmd
= Z_NO_FLUSH
;
740 z
.next_in
= pin
= data
;
741 z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
742 z
.avail_out
= (uInt
)zlib_bufsize
;
743 z
.next_out
= pout
= gcry_malloc(zlib_bufsize
);
746 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
751 *rc
= deflateInit2(&z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
754 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
759 /* Rather than store the size of the uncompressed data in the file header,
760 * store it in the comment field of the gzip header. Don't give anyone too
761 * much information. Not sure why really, but it seems the right way. :)
763 memset(&h
, 0, sizeof(gz_header
));
764 g_snprintf(buf
, sizeof(buf
), "%li", size
);
765 h
.comment
= (guchar
*)buf
;
766 *rc
= deflateSetHeader(&z
, &h
);
769 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
778 *rc
= deflate(&z
, cmd
);
785 p
= gcry_realloc(pout
, z
.total_out
+ zlib_bufsize
);
788 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
794 z
.next_out
= pout
+ z
.total_out
;
795 z
.avail_out
= zlib_bufsize
;
798 if (!z
.avail_in
&& z
.total_in
< size
) {
799 if (z
.total_in
+ zlib_bufsize
> size
)
800 z
.avail_in
= size
- z
.total_in
;
802 z
.avail_in
= zlib_bufsize
;
804 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li",
811 if (z
.total_in
>= size
)
820 } while (*rc
!= Z_STREAM_END
);
822 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li", z
.total_in
, size
);
828 *outsize
= z
.total_out
;
834 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
840 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
842 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
843 struct client_crypto_s
*crypto
, status_msg_t which
)
846 gsize len
= CRYPTO_BLOCKSIZE
;
847 gpointer p
= gcry_malloc(len
);
852 return gpg_err_code_from_errno(ENOMEM
);
854 pthread_cleanup_push(gcry_free
, p
);
856 if (crypto
->insize
< CRYPTO_BLOCKSIZE
)
857 len
= crypto
->insize
;
860 inbuf
= crypto
->inbuf
+ total
;
863 if (len
+ total
> crypto
->insize
)
866 if (which
== STATUS_ENCRYPT
)
867 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
869 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
874 tmp
= crypto
->inbuf
+total
;
875 memmove(tmp
, p
, len
);
878 if (total
>= crypto
->insize
)
881 pthread_testcancel();
886 pthread_cleanup_pop(1);
890 /* The crypto struct must be setup for iterations and .key. */
891 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
892 struct client_crypto_s
*crypto
, const gchar
*filename
)
894 gsize len
= crypto
->insize
;
898 guint iter_progress
= 0, n_iter
= 0, xiter
= 0;
899 gchar tmp
[FILENAME_MAX
];
903 if (!crypto
->fh
->fh2
.iter
) {
905 * cache_file_count() needs both .used == TRUE and a valid key in
906 * order for it to count as a used cache entry. Fixes CACHE status
909 memset(crypto
->key
, '!', gcrykeysize
);
914 * Resize the existing xml buffer to the block size required by gcrypt
915 * rather than duplicating it and wasting memory.
917 if (crypto
->insize
/ gcryblocksize
) {
918 len
= (crypto
->insize
/ gcryblocksize
) * gcryblocksize
;
920 if (crypto
->insize
% gcryblocksize
)
921 len
+= gcryblocksize
;
924 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
927 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
928 return gpg_error_from_errno(ENOMEM
);
931 crypto
->inbuf
= inbuf
;
932 crypto
->insize
= len
;
933 gcry_create_nonce(crypto
->fh
->fh2
.iv
, sizeof(crypto
->fh
->fh2
.iv
));
934 crypto
->tkey
= gcry_malloc(gcrykeysize
);
937 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
938 return gpg_error_from_errno(ENOMEM
);
941 memcpy(crypto
->tkey
, crypto
->key
, gcrykeysize
);
942 guchar
*tkey
= crypto
->tkey
;
945 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
946 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
950 iter_progress
= get_key_file_integer(client
? client
->filename
: "global",
951 "iteration_progress");
953 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
954 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
955 "%u %u", 0, crypto
->fh
->fh2
.iter
);
961 while (xiter
< crypto
->fh
->fh2
.iter
-1) {
962 if (iter_progress
> 0 && xiter
>= iter_progress
) {
963 if (!(xiter
% iter_progress
)) {
964 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
965 "%u %u", ++n_iter
* iter_progress
, crypto
->fh
->fh2
.iter
);
972 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
973 sizeof(crypto
->fh
->fh2
.iv
)))) {
974 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
978 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
981 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
988 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
989 sizeof(crypto
->fh
->fh2
.iv
)))) {
990 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
994 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, gcrykeysize
))) {
995 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
999 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1004 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
1005 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1006 "%u %u", crypto
->fh
->fh2
.iter
, crypto
->fh
->fh2
.iter
);
1014 if (!client
&& !strcmp(filename
, "-")) {
1015 crypto
->fh
->fd
= STDOUT_FILENO
;
1019 if (lstat(filename
, &st
) == 0) {
1020 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1023 * FIXME What if the file has an ACL?
1025 if (!(mode
& S_IWUSR
))
1026 return gpg_error_from_errno(EACCES
);
1029 if (errno
!= ENOENT
)
1030 return gpg_error_from_errno(errno
);
1033 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1034 crypto
->fh
->fd
= mkstemp(tmp
);
1036 if (crypto
->fh
->fd
== -1) {
1038 p
= strrchr(tmp
, '/');
1040 log_write("%s: %s", p
, strerror(rc
));
1041 return gpg_error_from_errno(rc
);
1046 * xml_import() or convert_file() from command line.
1048 crypto
->fh
->fd
= STDOUT_FILENO
;
1051 crypto
->fh
->fh2
.version
= VERSION_HEX
;
1052 len
= write(crypto
->fh
->fd
, &crypto
->fh
->fh2
, sizeof(crypto
->fh
->fh2
));
1054 if (len
!= sizeof(crypto
->fh
->fh2
)) {
1057 if (filename
&& strcmp(filename
, "-"))
1060 return gpg_error_from_errno(len
);
1063 len
= write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1065 if (len
!= crypto
->insize
) {
1068 if (filename
&& strcmp(filename
, "-"))
1071 return gpg_error_from_errno(len
);
1074 if (fsync(crypto
->fh
->fd
) == -1) {
1077 if (filename
&& strcmp(filename
, "-"))
1080 return gpg_error_from_errno(len
);
1083 if (filename
&& strcmp(filename
, "-")) {
1084 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1085 gchar tmp2
[FILENAME_MAX
];
1087 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1089 if (rename(filename
, tmp2
) == -1) {
1092 return gpg_error_from_errno(len
);
1096 if (rename(tmp
, filename
) == -1) {
1099 return gpg_error_from_errno(len
);
1103 chmod(filename
, mode
);
1106 if (client
&& lstat(filename
, &st
) == 0)
1107 client
->mtime
= st
.st_mtime
;
1112 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1115 struct client_s
*client
= assuan_get_pointer(ctx
);
1117 gulong len
, outsize
= 0;
1124 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1125 gcry_free(client
->crypto
->key
);
1127 client
->crypto
->key
= key
;
1128 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1129 iter
= (guint
)get_key_file_integer(client
->filename
, "compression_level");
1134 if (do_compress(ctx
, (gint
)iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
)
1136 if (key
!= client
->crypto
->key
)
1140 cleanup_crypto(&client
->crypto
);
1142 if (zrc
== Z_MEM_ERROR
)
1143 return send_syserror(ctx
, ENOMEM
);
1145 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1153 client
->crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1155 if (!client
->crypto
->fh
) {
1156 cleanup_crypto(&client
->crypto
);
1158 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1159 return send_syserror(ctx
, ENOMEM
);
1162 iter
= get_key_file_integer(client
->filename
, "iterations");
1163 client
->crypto
->fh
->fh2
.iter
= iter
< 0 ? 0 : iter
;
1164 client
->crypto
->inbuf
= xmlbuf
;
1165 client
->crypto
->insize
= len
;
1166 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1169 cleanup_crypto(&client
->crypto
);
1170 return send_error(ctx
, rc
);
1173 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1174 CACHE_LOCK(client
->ctx
);
1177 cache_reset_timeout(client
->md5file
, timeout
);
1180 if (client
->new == TRUE
)
1181 send_status_all(STATUS_CACHE
);
1183 client
->new = FALSE
;
1184 cleanup_crypto(&client
->crypto
);
1185 return send_error(ctx
, 0);
1188 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1190 cleanup_crypto(&client
->crypto
);
1191 return send_syserror(ctx
, ENOMEM
);
1194 client
->new = FALSE
;
1195 cache_reset_timeout(client
->md5file
, timeout
);
1197 send_status_all(STATUS_CACHE
);
1198 cleanup_crypto(&client
->crypto
);
1199 return send_error(ctx
, 0);
1202 static int save_command(assuan_context_t ctx
, char *line
)
1204 gboolean cached
= FALSE
;
1206 struct client_s
*client
= assuan_get_pointer(ctx
);
1209 rc
= lock_file_mutex(client
);
1212 return send_error(ctx
, rc
);
1214 rc
= file_modified(client
);
1217 return send_error(ctx
, rc
);
1219 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1220 return send_syserror(ctx
, errno
);
1222 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1223 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1224 return send_error(ctx
, GPG_ERR_ENOANO
);
1228 cached
= cache_iscached(client
->md5file
);
1232 * If a cache entry doesn't exist for this file and the file has a
1233 * "key_file" or "key" parameter, then it's an error. The reason is that
1234 * cache expiration would be useless.
1236 if (cached
== FALSE
) {
1237 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1241 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1246 client
->crypto
= init_client_crypto();
1248 if (!client
->crypto
) {
1249 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1250 return send_syserror(ctx
, ENOMEM
);
1253 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
1255 if (!client
->crypto
->key
) {
1256 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1257 cleanup_crypto(&client
->crypto
);
1258 return send_syserror(ctx
, ENOMEM
);
1261 memset(client
->crypto
->key
, '!', gcrykeysize
);
1263 if (get_key_file_integer(client
->filename
, "iterations") <= 0)
1266 if (!line
|| !*line
) {
1267 client
->crypto
->tkey
= gcry_malloc(gcrykeysize
);
1269 if (!client
->crypto
->tkey
) {
1270 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1271 cleanup_crypto(&client
->crypto
);
1272 return send_syserror(ctx
, ENOMEM
);
1275 memset(client
->crypto
->tkey
, '!', gcrykeysize
);
1278 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1279 memcmp(client
->crypto
->key
, client
->crypto
->tkey
,
1280 gcrykeysize
) == 0) {
1283 #ifdef WITH_PINENTRY
1284 if (client
->pinentry
->enable
== FALSE
||
1285 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1286 /* Empty keys are allowed. */
1287 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1291 lock_pin_mutex(client
);
1292 client
->pinentry
->which
= PINENTRY_SAVE
;
1293 rc
= pinentry_fork(ctx
);
1296 unlock_pin_mutex(client
->pinentry
);
1297 return send_error(ctx
, rc
);
1300 client
->pinentry
->cb
= save_command_finalize
;
1301 client
->pinentry
->status
= PINENTRY_INIT
;
1304 /* Empty keys are allowed. */
1305 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1315 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, line
,
1317 memset(line
, 0, strlen(line
));
1321 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1324 static int delete_command(assuan_context_t ctx
, char *line
)
1326 struct client_s
*client
= assuan_get_pointer(ctx
);
1331 rc
= file_modified(client
);
1334 return send_error(ctx
, rc
);
1336 if (strchr(line
, '\t'))
1337 req
= split_input_line(line
, "\t", -1);
1339 req
= split_input_line(line
, " ", -1);
1342 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1344 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1348 return send_error(ctx
, rc
);
1352 * No sub-node defined. Remove the entire node (account).
1361 return send_error(ctx
, 0);
1364 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1368 return send_error(ctx
, rc
);
1375 return send_error(ctx
, 0);
1379 * Don't return with assuan_process_done() here. This has been called from
1380 * assuan_process_next() and the command should be finished in
1383 static int store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1386 assuan_context_t ctx
= data
;
1387 struct client_s
*client
= assuan_get_pointer(ctx
);
1390 gpg_error_t rc
= file_modified(client
);
1392 if (assuan_rc
|| rc
) {
1395 return assuan_rc
? assuan_rc
: rc
;
1398 req
= split_input_line((gchar
*)line
, "\t", 0);
1402 return EPWMD_COMMAND_SYNTAX
;
1404 if (valid_xml_element((xmlChar
*)*req
) == FALSE
) {
1406 return EPWMD_INVALID_ELEMENT
;
1409 if (valid_element_path(req
+1, TRUE
) == FALSE
) {
1411 return EPWMD_INVALID_ELEMENT
;
1415 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1417 if (rc
&& rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1418 rc
= new_account(client
->doc
, *req
);
1435 create_elements_cb(n
, req
+1, &rc
, NULL
);
1437 find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1438 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
);
1442 client
->inquire_status
= INQUIRE_DONE
;
1446 static int store_command(assuan_context_t ctx
, char *line
)
1448 struct client_s
*client
= assuan_get_pointer(ctx
);
1449 gpg_error_t rc
= file_modified(client
);
1452 return send_error(ctx
, rc
);
1454 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1457 return send_error(ctx
, rc
);
1459 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1460 client
->inquire_status
= INQUIRE_BUSY
;
1464 static int get_command(assuan_context_t ctx
, char *line
)
1466 struct client_s
*client
= assuan_get_pointer(ctx
);
1471 rc
= file_modified(client
);
1474 return send_error(ctx
, rc
);
1476 req
= split_input_line(line
, "\t", -1);
1478 if (!req
|| !*req
) {
1480 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1483 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1487 return send_error(ctx
, rc
);
1491 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1496 return send_error(ctx
, rc
);
1498 if (!n
|| !n
->children
)
1499 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1501 n
= find_text_node(n
->children
);
1503 if (!n
|| !n
->content
|| !*n
->content
)
1504 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1506 rc
= assuan_send_data(ctx
, n
->content
, xmlStrlen(n
->content
));
1507 return send_error(ctx
, rc
);
1510 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
1511 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
1513 gchar
*path
= *(gchar
**)data
;
1514 gchar
*tmp
= NULL
, *result
;
1518 *(gchar
**)data
= NULL
;
1521 path
= g_strjoinv("\t", target
);
1524 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1525 *rc
= gpg_error_from_errno(ENOMEM
);
1530 tmp
= g_strjoinv("\t", req_orig
);
1534 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1535 *rc
= gpg_error_from_errno(ENOMEM
);
1541 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1543 result
= g_strdup(path
);
1546 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1547 *rc
= gpg_error_from_errno(ENOMEM
);
1555 *(gchar
**)data
= result
;
1559 static int realpath_command(assuan_context_t ctx
, char *line
)
1562 struct client_s
*client
= assuan_get_pointer(ctx
);
1570 rc
= file_modified(client
);
1573 return send_error(ctx
, rc
);
1575 if (strchr(line
, '\t') != NULL
) {
1576 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1577 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1580 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1581 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1584 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1588 return send_error(ctx
, rc
);
1591 rp
= g_strjoinv("\t", req
);
1595 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1596 return send_syserror(ctx
, ENOMEM
);
1600 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1601 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
);
1606 return send_error(ctx
, rc
);
1610 string
= g_string_new(rp
);
1615 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1616 return send_syserror(ctx
, ENOMEM
);
1620 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
1621 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
1622 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1627 rc
= assuan_send_data(ctx
, string
->str
, string
->len
);
1628 g_string_free(string
, TRUE
);
1629 return send_error(ctx
, rc
);
1632 static int list_command(assuan_context_t ctx
, char *line
)
1634 struct client_s
*client
= assuan_get_pointer(ctx
);
1636 struct element_list_s
*elements
= NULL
;
1639 if (disable_list_and_dump
== TRUE
)
1640 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1642 rc
= file_modified(client
);
1645 return send_error(ctx
, rc
);
1650 rc
= list_accounts(client
->doc
, &str
);
1653 return send_error(ctx
, rc
);
1655 rc
= assuan_send_data(ctx
, str
->str
, str
->len
);
1656 g_string_free(str
, TRUE
);
1657 return send_error(ctx
, rc
);
1660 elements
= g_malloc0(sizeof(struct element_list_s
));
1663 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1664 rc
= gpg_err_code_from_errno(ENOMEM
);
1668 rc
= create_path_list(client
->doc
, elements
, line
);
1674 gint total
= g_slist_length(elements
->list
);
1679 rc
= EPWMD_EMPTY_ELEMENT
;
1683 str
= g_string_new(NULL
);
1686 rc
= gpg_err_code_from_errno(ENOMEM
);
1687 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1691 for (i
= 0; i
< total
; i
++) {
1692 tmp
= g_slist_nth_data(elements
->list
, i
);
1693 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
1696 rc
= assuan_send_data(ctx
, str
->str
, str
->len
);
1697 g_string_free(str
, TRUE
);
1700 rc
= EPWMD_EMPTY_ELEMENT
;
1704 gint total
= g_slist_length(elements
->list
);
1707 for (i
= 0; i
< total
; i
++) {
1708 tmp
= g_slist_nth_data(elements
->list
, i
);
1712 g_slist_free(elements
->list
);
1714 if (elements
->prefix
)
1715 g_free(elements
->prefix
);
1720 return send_error(ctx
, rc
);
1723 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1728 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1729 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1732 return EPWMD_LIBXML_ERROR
;
1735 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1741 * req[0] - element path
1743 static int attribute_list(assuan_context_t ctx
, gchar
**req
)
1745 struct client_s
*client
= assuan_get_pointer(ctx
);
1746 gchar
**attrlist
= NULL
;
1748 gchar
**path
= NULL
;
1754 if (!req
|| !req
[0])
1755 return EPWMD_COMMAND_SYNTAX
;
1757 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1759 * The first argument may be only an account.
1761 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1762 return EPWMD_COMMAND_SYNTAX
;
1765 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1773 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1774 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1784 for (a
= n
->properties
; a
; a
= a
->next
) {
1787 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1789 g_strfreev(attrlist
);
1791 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1792 return gpg_error_from_errno(ENOMEM
);
1797 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1800 g_strfreev(attrlist
);
1801 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1802 return gpg_error_from_errno(ENOMEM
);
1805 attrlist
[++i
] = NULL
;
1809 return EPWMD_EMPTY_ELEMENT
;
1811 line
= g_strjoinv("\n", attrlist
);
1814 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1815 g_strfreev(attrlist
);
1816 return gpg_error_from_errno(ENOMEM
);
1819 rc
= assuan_send_data(ctx
, line
, strlen(line
));
1821 g_strfreev(attrlist
);
1826 * req[0] - attribute
1827 * req[1] - element path
1829 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1833 gchar
**path
= NULL
;
1836 if (!req
|| !req
[0] || !req
[1])
1837 return EPWMD_COMMAND_SYNTAX
;
1839 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1841 * The first argument may be only an account.
1843 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1844 return EPWMD_COMMAND_SYNTAX
;
1848 * Don't remove the "name" attribute for the account element. To remove an
1849 * account use DELETE <account>.
1851 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
1852 rc
= EPWMD_ATTR_SYNTAX
;
1856 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1862 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1863 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1871 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
1872 return EPWMD_ATTR_NOT_FOUND
;
1874 if (xmlRemoveProp(a
) == -1)
1875 return EPWMD_LIBXML_ERROR
;
1884 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
1887 gchar
**src
= *path
;
1888 gchar
**src_orig
= g_strdupv(src
);
1889 xmlNodePtr n
= NULL
;
1894 *rc
= gpg_error_from_errno(ENOMEM
);
1895 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1900 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
1903 if (*rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1904 *rc
= new_account(client
->doc
, src
[0]);
1917 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
1919 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
1920 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
);
1926 * Reset the position of the element tree now that the elements
1927 * have been created.
1932 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
1937 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
1938 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1946 g_strfreev(src_orig
);
1953 * Creates a "target" attribute. When other commands encounter an element with
1954 * this attribute, the element path is modified to the target value. If the
1955 * source element path doesn't exist when using 'ATTR SET target', it is
1956 * created, but the destination element path must exist.
1958 * req[0] - source element path
1959 * req[1] - destination element path
1961 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
1963 gchar
**src
, **dst
, *line
= NULL
;
1967 if (!req
|| !req
[0] || !req
[1])
1968 return EPWMD_COMMAND_SYNTAX
;
1970 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1972 * The first argument may be only an account.
1974 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
1975 return EPWMD_COMMAND_SYNTAX
;
1978 if (valid_element_path(src
, FALSE
) == FALSE
) {
1980 return EPWMD_INVALID_ELEMENT
;
1983 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1985 * The first argument may be only an account.
1987 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
1988 rc
= EPWMD_COMMAND_SYNTAX
;
1993 n
= find_account(client
->doc
, &dst
, &rc
, NULL
, 0);
1996 * Make sure the destination element path exists.
2002 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2003 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2009 n
= create_element_path(client
, &src
, &rc
);
2014 line
= g_strjoinv("\t", dst
);
2017 rc
= gpg_error_from_errno(ENOMEM
);
2018 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2022 rc
= add_attribute(n
, "target", line
);
2032 * req[0] - account name
2035 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2041 tmp
= g_strdupv(req
);
2044 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2045 return gpg_error_from_errno(ENOMEM
);
2048 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2054 if (g_utf8_collate(req
[0], req
[1]) == 0)
2058 * Will not overwrite an existing account.
2060 tmp
= g_strdupv(req
+1);
2063 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2064 return gpg_error_from_errno(ENOMEM
);
2067 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2070 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
2074 return EPWMD_ACCOUNT_EXISTS
;
2077 * Whitespace not allowed in account names.
2079 if (contains_whitespace(req
[1]) == TRUE
)
2080 return EPWMD_ATTR_SYNTAX
;
2082 tmp
= g_strdupv(req
);
2085 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2086 return gpg_error_from_errno(ENOMEM
);
2089 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2093 return EPWMD_ELEMENT_NOT_FOUND
;
2095 return add_attribute(n
, "name", req
[1]);
2099 * req[0] - attribute
2100 * req[1] - element path
2102 static int attribute_get(assuan_context_t ctx
, gchar
**req
)
2104 struct client_s
*client
= assuan_get_pointer(ctx
);
2110 if (!req
|| !req
[0] || !req
[1])
2111 return EPWMD_COMMAND_SYNTAX
;
2113 if (strchr(req
[1], '\t')) {
2114 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2115 return EPWMD_COMMAND_SYNTAX
;
2118 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2119 return EPWMD_COMMAND_SYNTAX
;
2122 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2128 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2129 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2137 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2138 return EPWMD_ATTR_NOT_FOUND
;
2140 rc
= assuan_send_data(ctx
, a
, xmlStrlen(a
));
2150 * req[0] - attribute
2151 * req[1] - element path
2154 static int attribute_set(struct client_s
*client
, gchar
**req
)
2156 gchar
**path
= NULL
;
2160 if (!req
|| !req
[0] || !req
[1] || !req
[2])
2161 return EPWMD_COMMAND_SYNTAX
;
2164 * Reserved attribute names.
2166 if (g_utf8_collate(req
[0], "name") == 0) {
2168 * Only reserved for the account element. Not the rest of the
2171 if (strchr(req
[1], '\t') == NULL
)
2172 return name_attribute(client
, req
+ 1);
2174 else if (g_utf8_collate(req
[0], "target") == 0)
2175 return target_attribute(client
, req
+ 1);
2177 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2179 * The first argument may be only an account.
2181 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2182 return EPWMD_COMMAND_SYNTAX
;
2185 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2191 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2192 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2199 return add_attribute(n
, req
[0], req
[2]);
2208 * req[1] - attribute name or element path if command is LIST
2209 * req[2] - element path
2210 * req[2] - element path or value
2212 static int attr_command(assuan_context_t ctx
, char *line
)
2214 struct client_s
*client
= assuan_get_pointer(ctx
);
2218 rc
= file_modified(client
);
2221 return send_error(ctx
, rc
);
2223 req
= split_input_line(line
, " ", 4);
2225 if (!req
|| !req
[0] || !req
[1]) {
2227 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2230 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2231 rc
= attribute_set(client
, req
+1);
2232 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2233 rc
= attribute_get(ctx
, req
+1);
2234 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2235 rc
= attribute_delete(client
, req
+1);
2236 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2237 rc
= attribute_list(ctx
, req
+1);
2239 rc
= EPWMD_COMMAND_SYNTAX
;
2242 return send_error(ctx
, rc
);
2245 static int iscached_command(assuan_context_t ctx
, char *line
)
2247 gchar
**req
= split_input_line(line
, " ", 0);
2250 if (!req
|| !*req
) {
2252 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2255 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2259 if (cache_iscached(md5file
) == FALSE
) {
2261 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2265 return send_error(ctx
, 0);
2268 static int clearcache_command(assuan_context_t ctx
, char *line
)
2270 struct client_s
*client
= assuan_get_pointer(ctx
);
2271 gchar
**req
= split_input_line(line
, " ", 0);
2276 if (!req
|| !*req
) {
2278 cache_clear(client
->md5file
, 2);
2280 return send_error(ctx
, 0);
2283 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2286 if (cache_clear(md5file
, 1) == FALSE
) {
2288 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2292 return send_error(ctx
, 0);
2295 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2299 gchar
**req
= split_input_line(line
, " ", 0);
2301 struct client_s
*client
= assuan_get_pointer(ctx
);
2303 if (!req
|| !*req
|| !req
[1]) {
2305 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2309 timeout
= strtol(req
[0], &p
, 10);
2311 if (errno
!= 0 || *p
!= 0) {
2313 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2316 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2318 CACHE_LOCK(client
->ctx
);
2320 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2322 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2326 return send_error(ctx
, 0);
2329 static int dump_command(assuan_context_t ctx
, char *line
)
2333 struct client_s
*client
= assuan_get_pointer(ctx
);
2336 if (disable_list_and_dump
== TRUE
)
2337 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2339 rc
= file_modified(client
);
2342 return send_error(ctx
, rc
);
2344 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2347 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2348 return send_syserror(ctx
, ENOMEM
);
2351 rc
= assuan_send_data(ctx
, xml
, len
);
2353 return send_error(ctx
, rc
);
2356 static int getconfig_command(assuan_context_t ctx
, gchar
*line
)
2358 struct client_s
*client
= assuan_get_pointer(ctx
);
2360 gchar filename
[255]={0}, param
[747]={0};
2361 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2363 if (strchr(line
, ' ')) {
2364 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2369 if (fp
&& !valid_filename(fp
))
2370 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
2372 paramp
= g_ascii_strdown(paramp
, -1);
2375 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2376 return send_syserror(ctx
, ENOMEM
);
2379 p
= get_key_file_string(fp
? fp
: "global", paramp
);
2383 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2385 tmp
= expand_homedir(p
);
2389 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2390 return send_syserror(ctx
, ENOMEM
);
2394 rc
= assuan_send_data(ctx
, p
, strlen(p
));
2396 return send_error(ctx
, rc
);
2399 static int xpath_command(assuan_context_t ctx
, gchar
*line
)
2401 struct client_s
*client
= assuan_get_pointer(ctx
);
2403 xmlXPathContextPtr xp
;
2404 xmlXPathObjectPtr result
;
2405 xmlBufferPtr buf
= NULL
;
2408 if (disable_list_and_dump
== TRUE
)
2409 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2411 rc
= file_modified(client
);
2414 return send_error(ctx
, rc
);
2416 if (!line
|| !*line
)
2417 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2419 if ((req
= split_input_line(line
, "\t", 2)) == NULL
) {
2420 if (strv_printf(&req
, "%s", line
) == FALSE
)
2421 return send_syserror(ctx
, ENOMEM
);
2424 xp
= xmlXPathNewContext(client
->doc
);
2427 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2429 result
= xmlXPathEvalExpression((xmlChar
*)req
[0], xp
);
2432 xmlXPathFreeContext(xp
);
2433 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2436 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2437 rc
= EPWMD_EMPTY_ELEMENT
;
2441 rc
= recurse_xpath_nodeset(client
->doc
, result
->nodesetval
,
2442 (xmlChar
*)req
[1], &buf
);
2446 else if (!req
[1] && !xmlBufferLength(buf
)) {
2447 rc
= EPWMD_EMPTY_ELEMENT
;
2453 rc
= assuan_send_data(ctx
, xmlBufferContent(buf
), xmlBufferLength(buf
));
2462 xmlXPathFreeObject(result
);
2465 xmlXPathFreeContext(xp
);
2467 return send_error(ctx
, rc
);
2470 static int import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
2473 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
2474 gpg_error_t rc
= file_modified(client
);
2475 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
2477 xmlNodePtr n
, root
, copy
;
2479 if (assuan_rc
|| rc
) {
2482 return assuan_rc
? assuan_rc
: rc
;
2485 req
= split_input_line((gchar
*)line
, " ", 2);
2489 return EPWMD_COMMAND_SYNTAX
;
2491 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2492 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2493 return EPWMD_COMMAND_SYNTAX
;
2498 if (!content
|| !*content
) {
2499 rc
= EPWMD_COMMAND_SYNTAX
;
2503 if (valid_xml_element((xmlChar
*)*path
) == FALSE
) {
2504 rc
= EPWMD_INVALID_ELEMENT
;
2508 if (valid_element_path(path
+1, FALSE
) == FALSE
) {
2509 rc
= EPWMD_INVALID_ELEMENT
;
2513 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2516 rc
= EPWMD_LIBXML_ERROR
;
2520 root
= xmlDocGetRootElement(doc
);
2521 path_orig
= g_strdupv(path
);
2525 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2526 rc
= gpg_error_from_errno(ENOMEM
);
2530 if (strv_printf(&path
, "%s", (gchar
*)root
->name
) == FALSE
) {
2531 g_strfreev(path_orig
);
2533 rc
= gpg_error_from_errno(ENOMEM
);
2537 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2539 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2540 g_strfreev(path_orig
);
2545 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2547 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2548 g_strfreev(path_orig
);
2553 xmlNodePtr parent
= n
->parent
;
2564 if (rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2565 n
= create_element_path(client
, &path
, &rc
);
2573 copy
= xmlCopyNode(root
, 1);
2574 n
= xmlAddChild(n
, copy
);
2578 rc
= EPWMD_LIBXML_ERROR
;
2583 client
->inquire_status
= INQUIRE_DONE
;
2587 static int import_command(assuan_context_t ctx
, gchar
*line
)
2590 struct client_s
*client
= assuan_get_pointer(ctx
);
2592 rc
= file_modified(client
);
2595 return send_error(ctx
, rc
);
2597 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
2600 return send_error(ctx
, rc
);
2602 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2603 client
->inquire_status
= INQUIRE_BUSY
;
2607 static int lock_command(assuan_context_t ctx
, gchar
*line
)
2610 struct client_s
*client
= assuan_get_pointer(ctx
);
2612 rc
= file_modified(client
);
2615 return send_error(ctx
, rc
);
2617 rc
= lock_file_mutex(client
);
2620 client
->is_lock_cmd
= TRUE
;
2622 return send_error(ctx
, rc
);
2625 static int unlock_command(assuan_context_t ctx
, gchar
*line
)
2627 struct client_s
*client
= assuan_get_pointer(ctx
);
2628 gpg_error_t rc
= file_modified(client
);
2631 return send_error(ctx
, rc
);
2633 unlock_file_mutex(client
);
2634 return send_error(ctx
, 0);
2637 static int getpid_command(assuan_context_t ctx
, gchar
*line
)
2641 pid_t pid
= getpid();
2643 print_fmt(buf
, sizeof(buf
), "%i", pid
);
2644 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2645 return send_error(ctx
, rc
);
2648 static int version_command(assuan_context_t ctx
, gchar
*line
)
2653 print_fmt(buf
, sizeof(buf
), "%s", PACKAGE_VERSION
);
2654 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2655 return send_error(ctx
, rc
);
2658 static void bye_notify(assuan_context_t ctx
)
2660 struct client_s
*cl
= assuan_get_pointer(ctx
);
2664 if (!cl
->thd
->remote
)
2668 rc
= gnutls_bye(cl
->thd
->tls
->ses
, GNUTLS_SHUT_RDWR
);
2669 } while (rc
== GNUTLS_E_AGAIN
);
2672 /* This will let assuan_process_next() return. */
2673 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
2676 static void reset_notify(assuan_context_t ctx
)
2678 struct client_s
*cl
= assuan_get_pointer(ctx
);
2684 static gpg_error_t
parse_client_option(assuan_context_t ctx
, const gchar
*line
)
2686 gchar name
[32] = {0}, value
[256] = {0};
2688 if (sscanf(line
, " %31[a-zA-Z] = %255c", name
, value
) != 2)
2689 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
);
2691 if (g_strcasecmp(name
, (gchar
*)"NAME") == 0) {
2692 struct client_s
*cl
= assuan_get_pointer(ctx
);
2695 g_free(cl
->thd
->name
);
2697 cl
->thd
->name
= g_strdup(value
);
2698 log_write("OPTION CLIENT %s", line
);
2701 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2706 static int option_handler(assuan_context_t ctx
, const gchar
*name
,
2709 struct client_s
*client
= assuan_get_pointer(ctx
);
2711 if (!value
|| !*value
)
2712 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2714 if (g_strcasecmp(name
, (gchar
*)"client") == 0)
2715 return parse_client_option(ctx
, value
);
2717 if (g_strcasecmp(name
, (gchar
*)"iterations") == 0) {
2722 n
= strtol(value
, &p
, 10);
2724 if (errno
|| (p
&& *p
) || n
< 0)
2725 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2727 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
: "global", "iterations", (guint
)n
);
2728 send_status_all(STATUS_CONFIG
);
2730 #ifdef WITH_PINENTRY
2731 else if (g_strcasecmp(name
, (gchar
*)"ttyname") == 0) {
2732 g_free(client
->pinentry
->ttyname
);
2733 client
->pinentry
->ttyname
= g_strdup(value
);
2735 else if (g_strcasecmp(name
, (gchar
*)"ttytype") == 0) {
2736 g_free(client
->pinentry
->ttytype
);
2737 client
->pinentry
->ttytype
= g_strdup(value
);
2739 else if (g_strcasecmp(name
, (gchar
*)"display") == 0) {
2740 g_free(client
->pinentry
->display
);
2741 client
->pinentry
->display
= g_strdup(value
);
2743 else if (g_strcasecmp(name
, (gchar
*)"path") == 0) {
2744 g_free(client
->pinentry
->path
);
2745 client
->pinentry
->path
= g_strdup(value
);
2747 else if (g_strcasecmp(name
, (gchar
*)"title") == 0) {
2748 g_free(client
->pinentry
->title
);
2749 client
->pinentry
->title
= g_strdup(value
);
2751 else if (g_strcasecmp(name
, (gchar
*)"prompt") == 0) {
2752 g_free(client
->pinentry
->prompt
);
2753 client
->pinentry
->prompt
= g_strdup(value
);
2755 else if (g_strcasecmp(name
, (gchar
*)"desc") == 0) {
2756 g_free(client
->pinentry
->desc
);
2757 client
->pinentry
->desc
= g_strdup(value
);
2760 * Look at client_thread() to see how this works.
2762 else if (g_strcasecmp(name
, (gchar
*)"timeout") == 0) {
2764 gint n
= strtol(value
, &p
, 10);
2767 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2769 client
->pinentry
->timeout
= n
;
2771 else if (g_strcasecmp(name
, (gchar
*)"pinentry") == 0) {
2773 gint n
= strtol(value
, &p
, 10);
2775 if (*p
|| n
< 0 || n
> 1)
2776 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2778 client
->pinentry
->enable
= n
== 0 ? FALSE
: TRUE
;
2782 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2784 log_write("OPTION %s=%s", name
, value
);
2788 gpg_error_t
register_commands(assuan_context_t ctx
)
2792 gint (*handler
)(assuan_context_t
, gchar
*line
);
2794 { "OPEN", open_command
},
2795 { "SAVE", save_command
},
2796 { "LIST", list_command
},
2797 { "REALPATH", realpath_command
},
2798 { "STORE", store_command
},
2799 { "DELETE", delete_command
},
2800 { "GET", get_command
},
2801 { "ATTR", attr_command
},
2802 { "ISCACHED", iscached_command
},
2803 { "CLEARCACHE", clearcache_command
},
2804 { "CACHETIMEOUT", cachetimeout_command
},
2805 { "GETCONFIG", getconfig_command
},
2806 { "DUMP", dump_command
},
2807 { "XPATH", xpath_command
},
2808 { "IMPORT", import_command
},
2809 { "LOCK", lock_command
},
2810 { "UNLOCK", unlock_command
},
2811 { "GETPID", getpid_command
},
2812 { "VERSION", version_command
},
2819 for (i
=0; table
[i
].name
; i
++) {
2820 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
2826 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
2831 rc
= assuan_register_option_handler(ctx
, option_handler
);
2836 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
2841 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
2844 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, guchar
*key
,
2845 struct client_crypto_s
*crypto
, gpointer
*dst
, gsize
*dst_len
)
2848 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
2849 guint iter
= 0, n_iter
= 0, iter_progress
= 0;
2853 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->fh1
) : sizeof(crypto
->fh
->fh2
);
2854 glong fh_iter
= crypto
->fh
->v1
? crypto
->fh
->fh1
.iter
: crypto
->fh
->fh2
.iter
;
2856 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
2857 insize
= crypto
->fh
->st
.st_size
- fh_size
;
2858 crypto
->iv
= gcry_malloc(gcryblocksize
);
2861 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2862 return gpg_error_from_errno(ENOMEM
);
2865 /* No encryption iterations. This is a plain (gzipped) file. */
2866 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0)) {
2868 * cache_file_count() needs both .used == TRUE and a valid key in
2869 * order for it to count as a used cache entry. Fixes CACHE status
2872 memset(key
, '!', gcrykeysize
);
2876 memcpy(crypto
->iv
, crypto
->fh
->fh1
.iv
, gcryblocksize
);
2878 memcpy(crypto
->iv
, crypto
->fh
->fh2
.iv
, gcryblocksize
);
2880 crypto
->inbuf
= gcry_malloc(insize
);
2882 if (!crypto
->inbuf
) {
2883 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2884 return gpg_error_from_errno(ENOMEM
);
2887 crypto
->insize
= insize
;
2888 len
= read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
2890 if (len
!= crypto
->insize
)
2891 return GPG_ERR_INV_LENGTH
;
2893 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0))
2896 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
2897 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2901 if ((rc
= gcry_cipher_setkey(crypto
->gh
, key
, gcrykeysize
))) {
2902 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2906 iter_progress
= (guint
)get_key_file_integer(client
&& client
->filename
?
2907 client
->filename
: "global", "iteration_progress");
2909 if (iter_progress
> 0 && fh_iter
>= iter_progress
) {
2910 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u", 0, fh_iter
);
2916 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
2921 crypto
->tkey
= gcry_malloc(gcrykeysize
);
2923 if (!crypto
->tkey
) {
2924 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
2925 return gpg_error_from_errno(ENOMEM
);
2928 memcpy(crypto
->tkey
, key
, gcrykeysize
);
2929 guchar
*tkey
= crypto
->tkey
;
2932 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
2933 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2937 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
2938 if (iter_progress
> 0 && iter
>= iter_progress
) {
2939 if (!(iter
% iter_progress
)) {
2940 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u",
2941 ++n_iter
* iter_progress
, fh_iter
);
2948 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
2949 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2953 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
2956 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2963 if (iter_progress
&& fh_iter
>= iter_progress
) {
2964 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u", fh_iter
, fh_iter
);
2971 if (do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
2972 (gpointer
*)&crypto
->outbuf
, &outsize
, &zrc
) == FALSE
) {
2973 if (zrc
== Z_MEM_ERROR
)
2974 return gpg_error_from_errno(ENOMEM
);
2976 return EPWMD_BADKEY
; // Not a valid gzip header. Must be a bad key.
2979 if (g_strncasecmp(crypto
->outbuf
, "<?xml version=\"1.0\"?>", 21) != 0) {
2980 gcry_free(crypto
->outbuf
);
2981 crypto
->outbuf
= NULL
;
2982 return EPWMD_BADKEY
;
2986 client
->xml
= crypto
->outbuf
;
2987 client
->len
= outsize
;
2988 crypto
->outbuf
= NULL
;
2991 *dst
= crypto
->outbuf
;
2993 crypto
->outbuf
= NULL
;
2996 /* The calling function should free the crypto struct. */
3001 * This is called after every Assuan command.
3003 void command_finalize(assuan_context_t ctx
, gint rc
)
3005 struct client_s
*client
= assuan_get_pointer(ctx
);
3007 if (!client
->is_lock_cmd
)
3008 unlock_file_mutex(client
);