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"
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
)
62 static gpg_error_t
file_modified(struct client_s
*client
)
67 if (client
->state
!= STATE_OPEN
)
70 rc
= lock_file_mutex(client
);
75 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
76 if (client
->mtime
!= st
.st_mtime
)
77 return EPWMD_FILE_MODIFIED
;
83 static gboolean
encrypt_xml(gcry_cipher_hd_t gh
, void *outbuf
, gsize outsize
,
84 void *inbuf
, gsize insize
)
88 if ((rc
= gcry_cipher_encrypt(gh
, outbuf
, outsize
, inbuf
, insize
))) {
89 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
96 static gpg_error_t
decrypt_xml(gcry_cipher_hd_t gh
, void *outbuf
, gsize outsize
,
97 void *inbuf
, gsize insize
)
101 if ((rc
= gcry_cipher_decrypt(gh
, outbuf
, outsize
, inbuf
, insize
)))
102 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(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
);
114 return EPWMD_LIBXML_ERROR
;
119 void unlock_file_mutex(struct client_s
*client
)
121 struct file_mutex_s
*m
;
124 if (client
->has_lock
== FALSE
|| client
->pinentry
->status
!= PINENTRY_NONE
)
126 if (client
->has_lock
== FALSE
)
130 CACHE_LOCK(client
->ctx
);
132 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
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
;
147 if (client
->has_lock
== TRUE
)
150 CACHE_LOCK(client
->ctx
);
152 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
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
);
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
);
185 pthread_mutex_lock(&m
->mutex
);
188 client
->has_lock
= TRUE
;
192 void free_client(struct client_s
*client
)
195 xmlFreeDoc(client
->doc
);
198 gcry_free(client
->xml
);
200 if (client
->filename
)
201 g_free(client
->filename
);
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
;
213 struct pinentry_s
*pin
= client
->pinentry
;
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);
228 memset(client
, 0, sizeof(struct client_s
));
229 client
->state
= STATE_CONNECTED
;
232 client
->freed
= TRUE
;
234 client
->pinentry
= pin
;
236 client
->has_lock
= has_lock
;
240 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
241 gpointer
*out
, gulong
*outsize
, gint
*rc
)
251 z
.avail_in
= (uInt
)insize
;
252 z
.avail_out
= zlib_bufsize
;
253 z
.next_out
= pout
= g_malloc(zlib_bufsize
);
256 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
261 *rc
= inflateInit2(&z
, 47);
264 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
269 memset(&h
, 0, sizeof(gz_header
));
270 h
.comment
= (guchar
*)buf
;
271 h
.comm_max
= sizeof(buf
);
272 *rc
= inflateGetHeader(&z
, &h
);
275 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
281 *rc
= inflate(&z
, Z_BLOCK
);
284 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
291 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
296 *rc
= inflate(&z
, Z_FINISH
);
303 p
= g_realloc(pout
, z
.total_out
+ zlib_bufsize
);
306 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
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
);
326 } while (*rc
!= Z_STREAM_END
);
328 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", z
.total_out
,
335 *outsize
= z
.total_out
;
341 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
347 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
352 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
358 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
359 *rc
= gpg_error_from_errno(ENOMEM
);
363 fh_size
= v1
? sizeof(fh
->fh1
) : sizeof(fh
->fh2
);
365 if (lstat(filename
, &fh
->st
) == -1) {
366 *rc
= gpg_error_from_syserror();
371 fd
= open(filename
, O_RDONLY
);
374 *rc
= gpg_error_from_errno(errno
);
380 len
= read(fd
, &fh
->fh1
, fh_size
);
382 len
= read(fd
, &fh
->fh2
, fh_size
);
384 if (len
!= fh_size
) {
386 *rc
= GPG_ERR_INV_LENGTH
;
396 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*key
,
399 struct client_s
*client
= assuan_get_pointer(ctx
);
404 if (!client
->crypto
->fh
) {
411 rc
= try_xml_decrypt(ctx
, key
, client
->crypto
, NULL
, NULL
);
414 cleanup_client(client
);
415 return send_error(ctx
, rc
);
419 CACHE_LOCK(client
->ctx
);
421 if (cached
== FALSE
) {
422 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
423 cleanup_client(client
);
425 return send_syserror(ctx
, ENOMEM
);
428 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
429 cache_reset_timeout(client
->md5file
, timeout
);
432 cache_set_timeout(client
->md5file
, -2);
437 if (client
->crypto
->key
!= key
)
438 gcry_free(key
); // This is invokation is a pinentry callback.
443 gcry_free(client
->xml
);
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
);
462 log_write("OPEN '%s'", client
->filename
);
464 cleanup_crypto(&client
->crypto
);
465 return send_error(ctx
, rc
);
469 static gboolean
validate_access(struct client_s
*cl
, const gchar
*filename
)
471 gchar
*access
= get_key_file_string(filename
, "tcp_access");
477 list
= g_strsplit(access
, ",", -1);
481 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
485 for (p
= list
; *p
; p
++) {
486 gboolean
not = FALSE
;
497 if (strcasecmp(cl
->thd
->tls
->fp
, fp
) == 0) {
512 static int open_command(assuan_context_t ctx
, char *line
)
514 gboolean cached
= FALSE
;
516 struct client_s
*client
= assuan_get_pointer(ctx
);
518 gchar
*filename
= NULL
;
520 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
523 if (!filename
|| !*filename
) {
525 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
528 if (valid_filename(filename
) == FALSE
) {
530 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
533 if (client
->state
== STATE_OPEN
)
534 cleanup_client(client
);
537 if (client
->thd
->remote
== TRUE
) {
538 if (validate_access(client
, filename
) == FALSE
) {
539 log_write(N_("client validation failed for file '%s'"), filename
);
541 return send_error(ctx
, EPWMD_FILE_ACCESS
);
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
) {
553 return send_syserror(ctx
, ENOMEM
);
557 cache_incr_refcount(client
->md5file
);
559 rc
= lock_file_mutex(client
);
563 return send_error(ctx
, rc
);
566 client
->freed
= FALSE
;
567 client
->crypto
= init_client_crypto();
569 if (!client
->crypto
) {
571 cleanup_client(client
);
572 return send_syserror(ctx
, ENOMEM
);
575 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
577 if (!client
->crypto
->key
) {
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
));
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
));
602 cleanup_client(client
);
603 return send_syserror(ctx
, ENOMEM
);
606 client
->len
= xmlStrlen(client
->xml
);
608 client
->filename
= g_strdup(filename
);
610 if (!client
->filename
) {
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],
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
);
631 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
634 if (!S_ISREG(client
->crypto
->fh
->st
.st_mode
)) {
635 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_INVALID_FILENAME
));
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
));
649 cleanup_client(client
);
650 return send_syserror(ctx
, ENOMEM
);
654 client
->pinentry
->filename
= g_strdup(client
->filename
);
656 if (!client
->pinentry
->filename
) {
657 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
659 cleanup_client(client
);
660 return send_syserror(ctx
, ENOMEM
);
664 if (client
->crypto
->fh
->fh2
.iter
<= 0)
668 if (client
->thd
->remote
== FALSE
||
669 get_key_file_boolean(client
->filename
, "tcp_require_key") == FALSE
)
672 CACHE_LOCK(client
->ctx
);
673 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
681 if (cached
== FALSE
) {
682 gchar
*tmp
= get_key_file_string(filename
, "key_file");
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]) {
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);
711 rc
= lock_pin_mutex(client
);
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
);
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
;
732 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
737 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
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
)
753 gint cmd
= Z_NO_FLUSH
;
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
);
763 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
768 *rc
= deflateInit2(&z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
771 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
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
);
786 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
795 *rc
= deflate(&z
, cmd
);
802 p
= g_realloc(pout
, z
.total_out
+ zlib_bufsize
);
805 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
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
;
819 z
.avail_in
= zlib_bufsize
;
821 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li",
828 if (z
.total_in
>= size
)
837 } while (*rc
!= Z_STREAM_END
);
839 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li", z
.total_in
, size
);
845 *outsize
= z
.total_out
;
851 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
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
,
866 guint iter_progress
= 0, n_iter
= 0, xiter
= 0;
867 gchar tmp
[FILENAME_MAX
];
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
879 memset(crypto
->key
, '!', gcrykeysize
);
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
);
898 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
899 return gpg_error_from_errno(ENOMEM
);
903 gcry_create_nonce(crypto
->fh
->fh2
.iv
, sizeof(crypto
->fh
->fh2
.iv
));
904 crypto
->tkey
= gcry_malloc(gcrykeysize
);
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
;
916 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
918 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(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
);
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
);
948 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
949 sizeof(crypto
->fh
->fh2
.iv
)))) {
951 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
955 if (encrypt_xml(crypto
->gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
957 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
964 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
965 sizeof(crypto
->fh
->fh2
.iv
)))) {
967 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
971 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, gcrykeysize
))) {
973 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
977 if (encrypt_xml(crypto
->gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
979 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(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
);
995 if (!client
&& !strcmp(filename
, "-")) {
996 crypto
->fh
->fd
= STDOUT_FILENO
;
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
)) {
1008 return gpg_error_from_errno(EACCES
);
1012 if (errno
!= ENOENT
) {
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) {
1025 p
= strrchr(tmp
, '/');
1027 log_write("%s: %s", p
, strerror(rc
));
1028 return gpg_error_from_errno(rc
);
1033 * xml_import() or convert_file() from command line.
1035 crypto
->fh
->fd
= STDOUT_FILENO
;
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
)) {
1044 if (filename
&& strcmp(filename
, "-"))
1048 return gpg_error_from_errno(len
);
1051 len
= write(crypto
->fh
->fd
, inbuf
, insize
);
1053 if (len
!= insize
) {
1056 if (filename
&& strcmp(filename
, "-"))
1060 return gpg_error_from_errno(len
);
1063 if (fsync(crypto
->fh
->fd
) == -1) {
1066 if (filename
&& strcmp(filename
, "-"))
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) {
1083 return gpg_error_from_errno(len
);
1087 if (rename(tmp
, filename
) == -1) {
1091 return gpg_error_from_errno(len
);
1095 chmod(filename
, mode
);
1102 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1105 struct client_s
*client
= assuan_get_pointer(ctx
);
1107 gulong len
, outsize
= 0;
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");
1125 if (do_compress(ctx
, (gint
)iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
)
1127 if (key
!= client
->crypto
->key
)
1131 cleanup_crypto(&client
->crypto
);
1133 if (zrc
== Z_MEM_ERROR
)
1134 return send_syserror(ctx
, ENOMEM
);
1136 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1144 client
->crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1146 if (!client
->crypto
->fh
) {
1147 cleanup_crypto(&client
->crypto
);
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
);
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
);
1168 cache_reset_timeout(client
->md5file
, timeout
);
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
) {
1181 cleanup_crypto(&client
->crypto
);
1182 return send_syserror(ctx
, ENOMEM
);
1185 client
->new = FALSE
;
1186 cache_reset_timeout(client
->md5file
, timeout
);
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
;
1197 struct client_s
*client
= assuan_get_pointer(ctx
);
1200 rc
= lock_file_mutex(client
);
1203 return send_error(ctx
, rc
);
1205 rc
= file_modified(client
);
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
);
1219 cached
= cache_iscached(client
->md5file
);
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");
1232 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
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)
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
);
1269 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1270 memcmp(client
->crypto
->key
, client
->crypto
->tkey
,
1271 gcrykeysize
) == 0) {
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);
1282 lock_pin_mutex(client
);
1283 client
->pinentry
->which
= PINENTRY_SAVE
;
1284 rc
= pinentry_fork(ctx
);
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
;
1295 /* Empty keys are allowed. */
1296 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1306 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, line
,
1308 memset(line
, 0, strlen(line
));
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
);
1322 rc
= file_modified(client
);
1325 return send_error(ctx
, rc
);
1327 if (strchr(line
, '\t'))
1328 req
= split_input_line(line
, "\t", -1);
1330 req
= split_input_line(line
, " ", -1);
1333 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1335 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1339 return send_error(ctx
, rc
);
1343 * No sub-node defined. Remove the entire node (account).
1352 return send_error(ctx
, 0);
1355 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1359 return send_error(ctx
, rc
);
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
1374 static int store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1377 assuan_context_t ctx
= data
;
1378 struct client_s
*client
= assuan_get_pointer(ctx
);
1381 gpg_error_t rc
= file_modified(client
);
1383 if (assuan_rc
|| rc
) {
1386 return assuan_rc
? assuan_rc
: rc
;
1389 req
= split_input_line((gchar
*)line
, "\t", 0);
1393 return EPWMD_COMMAND_SYNTAX
;
1395 if (valid_xml_element((xmlChar
*)*req
) == FALSE
) {
1397 return EPWMD_INVALID_ELEMENT
;
1400 if (valid_element_path(req
+1, TRUE
) == FALSE
) {
1402 return EPWMD_INVALID_ELEMENT
;
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
);
1426 create_elements_cb(n
, req
+1, &rc
, NULL
);
1428 find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1429 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
);
1433 client
->inquire_status
= INQUIRE_DONE
;
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
);
1443 return send_error(ctx
, rc
);
1445 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
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
;
1455 static int get_command(assuan_context_t ctx
, char *line
)
1457 struct client_s
*client
= assuan_get_pointer(ctx
);
1462 rc
= file_modified(client
);
1465 return send_error(ctx
, rc
);
1467 req
= split_input_line(line
, "\t", -1);
1469 if (!req
|| !*req
) {
1471 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1474 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1478 return send_error(ctx
, rc
);
1482 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
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
;
1509 *(gchar
**)data
= NULL
;
1512 path
= g_strjoinv("\t", target
);
1515 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1516 *rc
= gpg_error_from_errno(ENOMEM
);
1521 tmp
= g_strjoinv("\t", req_orig
);
1525 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1526 *rc
= gpg_error_from_errno(ENOMEM
);
1532 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1534 result
= g_strdup(path
);
1537 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1538 *rc
= gpg_error_from_errno(ENOMEM
);
1546 *(gchar
**)data
= result
;
1550 static int realpath_command(assuan_context_t ctx
, char *line
)
1553 struct client_s
*client
= assuan_get_pointer(ctx
);
1561 rc
= file_modified(client
);
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
);
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);
1579 return send_error(ctx
, rc
);
1582 rp
= g_strjoinv("\t", req
);
1586 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1587 return send_syserror(ctx
, ENOMEM
);
1591 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1592 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
);
1597 return send_error(ctx
, rc
);
1601 string
= g_string_new(rp
);
1606 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1607 return send_syserror(ctx
, ENOMEM
);
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
, '!');
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
);
1627 struct element_list_s
*elements
= NULL
;
1630 if (disable_list_and_dump
== TRUE
)
1631 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1633 rc
= file_modified(client
);
1636 return send_error(ctx
, rc
);
1641 rc
= list_accounts(client
->doc
, &str
);
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
));
1654 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1655 rc
= gpg_err_code_from_errno(ENOMEM
);
1659 rc
= create_path_list(client
->doc
, elements
, line
);
1665 gint total
= g_slist_length(elements
->list
);
1670 rc
= EPWMD_EMPTY_ELEMENT
;
1674 str
= g_string_new(NULL
);
1677 rc
= gpg_err_code_from_errno(ENOMEM
);
1678 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
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
);
1691 rc
= EPWMD_EMPTY_ELEMENT
;
1695 gint total
= g_slist_length(elements
->list
);
1698 for (i
= 0; i
< total
; i
++) {
1699 tmp
= g_slist_nth_data(elements
->list
, i
);
1703 g_slist_free(elements
->list
);
1705 if (elements
->prefix
)
1706 g_free(elements
->prefix
);
1711 return send_error(ctx
, rc
);
1714 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1719 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1720 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1723 return EPWMD_LIBXML_ERROR
;
1726 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
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
;
1739 gchar
**path
= NULL
;
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);
1764 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1765 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1775 for (a
= n
->properties
; a
; a
= a
->next
) {
1778 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1780 g_strfreev(attrlist
);
1782 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1783 return gpg_error_from_errno(ENOMEM
);
1788 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
, (gchar
*)an
->content
);
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
;
1800 return EPWMD_EMPTY_ELEMENT
;
1802 line
= g_strjoinv("\n", attrlist
);
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
));
1812 g_strfreev(attrlist
);
1817 * req[0] - attribute
1818 * req[1] - element path
1820 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1824 gchar
**path
= NULL
;
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
;
1847 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1853 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1854 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
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
;
1875 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
1878 gchar
**src
= *path
;
1879 gchar
**src_orig
= g_strdupv(src
);
1880 xmlNodePtr n
= NULL
;
1885 *rc
= gpg_error_from_errno(ENOMEM
);
1886 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1891 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
1894 if (*rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1895 *rc
= new_account(client
->doc
, src
[0]);
1908 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
1910 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
1911 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
);
1917 * Reset the position of the element tree now that the elements
1918 * have been created.
1923 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
1928 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
1929 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1937 g_strfreev(src_orig
);
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
;
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
) {
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
;
1984 n
= find_account(client
->doc
, &dst
, &rc
, NULL
, 0);
1987 * Make sure the destination element path exists.
1993 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
1994 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2000 n
= create_element_path(client
, &src
, &rc
);
2005 line
= g_strjoinv("\t", dst
);
2008 rc
= gpg_error_from_errno(ENOMEM
);
2009 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2013 rc
= add_attribute(n
, "target", line
);
2023 * req[0] - account name
2026 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2032 tmp
= g_strdupv(req
);
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);
2045 if (g_utf8_collate(req
[0], req
[1]) == 0)
2049 * Will not overwrite an existing account.
2051 tmp
= g_strdupv(req
+1);
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);
2061 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
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
);
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);
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
);
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
;
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);
2119 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2120 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2128 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2129 return EPWMD_ATTR_NOT_FOUND
;
2131 rc
= assuan_send_data(ctx
, a
, xmlStrlen(a
));
2141 * req[0] - attribute
2142 * req[1] - element path
2145 static int attribute_set(struct client_s
*client
, gchar
**req
)
2147 gchar
**path
= NULL
;
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
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);
2182 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2183 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2190 return add_attribute(n
, req
[0], req
[2]);
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
);
2209 rc
= file_modified(client
);
2212 return send_error(ctx
, rc
);
2214 req
= split_input_line(line
, " ", 4);
2216 if (!req
|| !req
[0] || !req
[1]) {
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);
2230 rc
= EPWMD_COMMAND_SYNTAX
;
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);
2241 if (!req
|| !*req
) {
2243 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2246 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2250 if (cache_iscached(md5file
) == FALSE
) {
2252 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
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);
2267 if (!req
|| !*req
) {
2269 cache_clear(client
->md5file
, 2);
2271 return send_error(ctx
, 0);
2274 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2277 if (cache_clear(md5file
, 1) == FALSE
) {
2279 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2283 return send_error(ctx
, 0);
2286 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2290 gchar
**req
= split_input_line(line
, " ", 0);
2292 struct client_s
*client
= assuan_get_pointer(ctx
);
2294 if (!req
|| !*req
|| !req
[1]) {
2296 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2300 timeout
= strtol(req
[0], &p
, 10);
2302 if (errno
!= 0 || *p
!= 0) {
2304 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2307 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2309 CACHE_LOCK(client
->ctx
);
2311 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2313 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2317 return send_error(ctx
, 0);
2320 static int dump_command(assuan_context_t ctx
, char *line
)
2324 struct client_s
*client
= assuan_get_pointer(ctx
);
2327 if (disable_list_and_dump
== TRUE
)
2328 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2330 rc
= file_modified(client
);
2333 return send_error(ctx
, rc
);
2335 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2338 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2339 return send_syserror(ctx
, ENOMEM
);
2342 rc
= assuan_send_data(ctx
, xml
, len
);
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
);
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
);
2360 if (fp
&& !valid_filename(fp
))
2361 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
2363 paramp
= g_ascii_strdown(paramp
, -1);
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
);
2374 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2376 tmp
= expand_homedir(p
);
2380 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2381 return send_syserror(ctx
, ENOMEM
);
2385 rc
= assuan_send_data(ctx
, p
, strlen(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
);
2394 xmlXPathContextPtr xp
;
2395 xmlXPathObjectPtr result
;
2396 xmlBufferPtr buf
= NULL
;
2399 if (disable_list_and_dump
== TRUE
)
2400 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2402 rc
= file_modified(client
);
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
);
2418 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2420 result
= xmlXPathEvalExpression((xmlChar
*)req
[0], xp
);
2423 xmlXPathFreeContext(xp
);
2424 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2427 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2428 rc
= EPWMD_EMPTY_ELEMENT
;
2432 rc
= recurse_xpath_nodeset(client
->doc
, result
->nodesetval
,
2433 (xmlChar
*)req
[1], &buf
);
2437 else if (!req
[1] && !xmlBufferLength(buf
)) {
2438 rc
= EPWMD_EMPTY_ELEMENT
;
2444 rc
= assuan_send_data(ctx
, xmlBufferContent(buf
), xmlBufferLength(buf
));
2453 xmlXPathFreeObject(result
);
2456 xmlXPathFreeContext(xp
);
2458 return send_error(ctx
, rc
);
2461 static int import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
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
;
2468 xmlNodePtr n
, root
, copy
;
2470 if (assuan_rc
|| rc
) {
2473 return assuan_rc
? assuan_rc
: rc
;
2476 req
= split_input_line((gchar
*)line
, " ", 2);
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
;
2489 if (!content
|| !*content
) {
2490 rc
= EPWMD_COMMAND_SYNTAX
;
2494 if (valid_xml_element((xmlChar
*)*path
) == FALSE
) {
2495 rc
= EPWMD_INVALID_ELEMENT
;
2499 if (valid_element_path(path
+1, FALSE
) == FALSE
) {
2500 rc
= EPWMD_INVALID_ELEMENT
;
2504 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2507 rc
= EPWMD_LIBXML_ERROR
;
2511 root
= xmlDocGetRootElement(doc
);
2512 path_orig
= g_strdupv(path
);
2516 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2517 rc
= gpg_error_from_errno(ENOMEM
);
2521 if (strv_printf(&path
, "%s", (gchar
*)root
->name
) == FALSE
) {
2522 g_strfreev(path_orig
);
2524 rc
= gpg_error_from_errno(ENOMEM
);
2528 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2530 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2531 g_strfreev(path_orig
);
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
);
2544 xmlNodePtr parent
= n
->parent
;
2555 if (rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2556 n
= create_element_path(client
, &path
, &rc
);
2564 copy
= xmlCopyNode(root
, 1);
2565 n
= xmlAddChild(n
, copy
);
2569 rc
= EPWMD_LIBXML_ERROR
;
2574 client
->inquire_status
= INQUIRE_DONE
;
2578 static int import_command(assuan_context_t ctx
, gchar
*line
)
2581 struct client_s
*client
= assuan_get_pointer(ctx
);
2583 rc
= file_modified(client
);
2586 return send_error(ctx
, rc
);
2588 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
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
;
2598 static int lock_command(assuan_context_t ctx
, gchar
*line
)
2601 struct client_s
*client
= assuan_get_pointer(ctx
);
2603 rc
= file_modified(client
);
2606 return send_error(ctx
, rc
);
2608 rc
= lock_file_mutex(client
);
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
);
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
)
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
)
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
);
2655 if (!cl
->thd
->remote
)
2659 rc
= gnutls_bye(cl
->thd
->tls
->ses
, GNUTLS_SHUT_RDWR
);
2660 } while (rc
== GNUTLS_E_AGAIN
);
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
);
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
);
2686 g_free(cl
->thd
->name
);
2688 cl
->thd
->name
= g_strdup(value
);
2689 log_write("OPTION CLIENT %s", line
);
2692 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2697 static int option_handler(assuan_context_t ctx
, const gchar
*name
,
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) {
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) {
2755 gint n
= strtol(value
, &p
, 10);
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) {
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
;
2773 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2775 log_write("OPTION %s=%s", name
, value
);
2779 gpg_error_t
register_commands(assuan_context_t ctx
)
2783 gint (*handler
)(assuan_context_t
, gchar
*line
);
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
},
2810 for (i
=0; table
[i
].name
; i
++) {
2811 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
2817 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
2822 rc
= assuan_register_option_handler(ctx
, option_handler
);
2827 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
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
)
2839 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
2840 guint iter
= 0, n_iter
= 0, iter_progress
= 0;
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
);
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
2863 memset(key
, '!', gcrykeysize
);
2867 memcpy(crypto
->iv
, crypto
->fh
->fh1
.iv
, gcryblocksize
);
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
);
2881 return GPG_ERR_INV_LENGTH
;
2883 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0))
2886 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
2887 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2891 if ((rc
= gcry_cipher_setkey(crypto
->gh
, key
, gcrykeysize
))) {
2892 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(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
);
2906 rc
= decrypt_xml(crypto
->gh
, crypto
->inbuf
, insize
, NULL
, 0);
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
;
2922 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
2923 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(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
);
2938 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
2939 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2943 rc
= decrypt_xml(crypto
->gh
, crypto
->inbuf
, insize
, NULL
, 0);
2946 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2953 if (iter_progress
&& fh_iter
>= iter_progress
) {
2954 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u", fh_iter
, fh_iter
);
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
);
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
;
2976 client
->xml
= crypto
->outbuf
;
2977 client
->len
= outsize
;
2978 crypto
->outbuf
= NULL
;
2981 *dst
= crypto
->outbuf
;
2983 crypto
->outbuf
= NULL
;
2986 /* The calling function should free the crypto struct. */
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
);