1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2010 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>
49 #include "pwmd_error.h"
62 static gpg_error_t
do_lock_command(struct client_s
*client
);
64 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
66 return gcry_calloc(items
, size
);
69 static void z_free(void *data
, void *p
)
74 static gpg_error_t
file_modified(struct client_s
*client
)
79 if (client
->state
!= STATE_OPEN
)
82 rc
= lock_file_mutex(client
);
87 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
88 if (client
->mtime
!= st
.st_mtime
)
89 return EPWMD_FILE_MODIFIED
;
96 static gpg_error_t
parse_xml(assuan_context_t ctx
)
98 struct client_s
*client
= assuan_get_pointer(ctx
);
100 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
103 return EPWMD_LIBXML_ERROR
;
108 void unlock_file_mutex(struct client_s
*client
)
113 if (client
->has_lock
== FALSE
|| client
->pinentry
->status
!= PINENTRY_NONE
)
115 if (client
->has_lock
== FALSE
)
119 CACHE_LOCK(client
->ctx
);
121 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
128 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
131 gpg_error_t
lock_file_mutex(struct client_s
*client
)
136 if (client
->has_lock
== TRUE
)
139 CACHE_LOCK(client
->ctx
);
141 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
147 MUTEX_TRYLOCK(client
->ctx
, m
, rc
);
150 client
->has_lock
= TRUE
;
155 void free_client(struct client_s
*client
)
158 xmlFreeDoc(client
->doc
);
161 gcry_free(client
->xml
);
163 if (client
->filename
)
164 g_free(client
->filename
);
167 cleanup_crypto(&client
->crypto
);
169 if (client
->xml_error
)
170 xmlResetError(client
->xml_error
);
173 void cleanup_client(struct client_s
*client
)
175 assuan_context_t ctx
= client
->ctx
;
176 struct client_thread_s
*thd
= client
->thd
;
177 gboolean has_lock
= client
->has_lock
;
179 struct pinentry_s
*pin
= client
->pinentry
;
182 unlock_file_mutex(client
);
183 CACHE_LOCK(client
->ctx
);
184 cache_decr_refcount(client
->md5file
);
187 * This may be a new file so don't use a cache slot. save_command() will
188 * set this to FALSE on success.
190 if (client
->new == TRUE
)
191 cache_clear(client
->md5file
, 1);
195 memset(client
, 0, sizeof(struct client_s
));
196 client
->state
= STATE_CONNECTED
;
199 client
->freed
= TRUE
;
201 client
->pinentry
= pin
;
203 client
->has_lock
= has_lock
;
206 static void gz_cleanup(void *arg
)
208 struct gz_s
**gz
= (struct gz_s
**)arg
;
213 if (!(*gz
)->done
&& (*gz
)->out
)
214 gcry_free((*gz
)->out
);
216 if ((*gz
)->which
== STATUS_COMPRESS
) {
218 deflateEnd(&(*gz
)->z
);
222 inflateEnd(&(*gz
)->z
);
229 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
230 gpointer
*out
, gulong
*outsize
, gint
*rc
)
236 gz
= g_malloc0(sizeof(struct gz_s
));
239 *rc
= gpg_error_from_errno(ENOMEM
);
243 pth_cleanup_push(gz_cleanup
, &gz
);
244 gz
->which
= STATUS_DECOMPRESS
;
245 gz
->z
.zalloc
= z_alloc
;
246 gz
->z
.zfree
= z_free
;
248 gz
->z
.avail_in
= (uInt
)insize
;
249 gz
->z
.avail_out
= zlib_bufsize
;
250 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
253 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
259 *rc
= inflateInit2(&gz
->z
, 47);
262 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
267 memset(&h
, 0, sizeof(gz_header
));
268 h
.comment
= (guchar
*)buf
;
269 h
.comm_max
= sizeof(buf
);
270 *rc
= inflateGetHeader(&gz
->z
, &h
);
273 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
278 *rc
= inflate(&gz
->z
, Z_BLOCK
);
281 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
287 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
292 *rc
= inflate(&gz
->z
, Z_FINISH
);
298 if (!gz
->z
.avail_out
) {
299 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
302 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
308 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
309 gz
->z
.avail_out
= zlib_bufsize
;
310 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
311 gz
->z
.total_out
, insize
);
323 } while (*rc
!= Z_STREAM_END
);
325 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
332 *outsize
= gz
->z
.total_out
;
339 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
344 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
349 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
356 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
357 *rc
= gpg_error_from_errno(ENOMEM
);
361 pth_cleanup_push(g_free
, fh
);
362 fh_size
= v1
? sizeof(fh
->ver
.fh1
) : sizeof(fh
->ver
.fh2
);
364 if (lstat(filename
, &fh
->st
) == -1) {
365 *rc
= gpg_error_from_syserror();
370 if (!S_ISREG(fh
->st
.st_mode
)) {
371 *rc
= GPG_ERR_ENOANO
;
376 fd
= open(filename
, O_RDONLY
);
379 *rc
= gpg_error_from_errno(errno
);
384 pth_cleanup_push(cleanup_fd_cb
, &fd
);
385 p
= v1
? (void *)&fh
->ver
.fh1
: (void *)&fh
->ver
.fh2
;
386 len
= pth_read(fd
, p
, fh_size
);
388 if (len
!= fh_size
) {
392 *rc
= gpg_error_from_errno(n
);
403 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*unused
,
406 struct client_s
*client
= assuan_get_pointer(ctx
);
409 guchar
*key
= client
->crypto
->key
;
412 if (!client
->crypto
->fh
) {
419 rc
= init_client_crypto2(client
->filename
, client
->crypto
);
422 cleanup_client(client
);
423 return send_error(ctx
, rc
);
426 rc
= try_xml_decrypt(ctx
, client
->crypto
, NULL
, NULL
);
429 cleanup_client(client
);
430 return send_error(ctx
, rc
);
434 CACHE_LOCK(client
->ctx
);
436 if (cached
== FALSE
) {
437 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
438 cleanup_client(client
);
440 return send_syserror(ctx
, ENOMEM
);
443 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
444 cache_reset_timeout(client
->md5file
, timeout
);
447 cache_set_timeout(client
->md5file
, -2);
455 gcry_free(client
->xml
);
460 if (client
->new == FALSE
)
461 send_status_all(STATUS_CACHE
);
463 client
->state
= STATE_OPEN
;
466 if (!rc
&& client
->new == FALSE
&&
467 client
->crypto
->fh
->ver
.fh2
.iter
!= (guint64
)get_key_file_double(client
->filename
, "iterations")) {
468 MUTEX_LOCK(&rcfile_mutex
);
469 g_key_file_set_double(keyfileh
, client
->filename
, "iterations",
470 client
->crypto
->fh
->ver
.fh2
.iter
);
471 MUTEX_UNLOCK(&rcfile_mutex
);
472 send_status_all(STATUS_CONFIG
);
475 cleanup_crypto(&client
->crypto
);
477 if (client
->lockonopen
)
478 return do_lock_command(client
);
480 return send_error(ctx
, rc
);
483 static void req_cleanup(void *arg
)
488 g_strfreev((gchar
**)arg
);
491 static gint
open_command(assuan_context_t ctx
, gchar
*line
)
493 gboolean cached
= FALSE
;
495 struct client_s
*client
= assuan_get_pointer(ctx
);
497 gchar
*filename
= NULL
;
498 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
500 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
503 pth_cleanup_push(req_cleanup
, req
);
505 if (!filename
|| !*filename
) {
507 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
510 log_write2("ARGS=\"%s\" %s", filename
, req
[1] ? "<passphrase>" : "");
512 if (valid_filename(filename
) == FALSE
) {
514 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
517 if (client
->state
== STATE_OPEN
)
518 cleanup_client(client
);
520 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
521 CACHE_LOCK(client
->ctx
);
523 if (cache_has_file(client
->md5file
) == FALSE
) {
524 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
527 return send_syserror(ctx
, ENOMEM
);
531 cache_incr_refcount(client
->md5file
);
533 rc
= lock_file_mutex(client
);
537 return send_error(ctx
, rc
);
540 client
->freed
= FALSE
;
541 client
->crypto
= init_client_crypto();
543 if (!client
->crypto
) {
545 cleanup_client(client
);
546 return send_syserror(ctx
, ENOMEM
);
549 client
->crypto
->key
= gcry_malloc(hashlen
);
551 if (!client
->crypto
->key
) {
553 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
554 gpg_error_from_errno(ENOMEM
));
555 cleanup_client(client
);
556 return send_syserror(ctx
, ENOMEM
);
559 memset(client
->crypto
->key
, 0, hashlen
);
560 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
562 if (!client
->crypto
->fh
) {
563 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
564 log_write("%s: %s", filename
, pwmd_strerror(rc
));
566 cleanup_client(client
);
567 return send_error(ctx
, rc
);
571 * New files don't need a key.
573 if ((client
->xml
= new_document()) == NULL
) {
574 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
576 cleanup_client(client
);
577 return send_syserror(ctx
, ENOMEM
);
580 client
->len
= xmlStrlen(client
->xml
);
582 client
->filename
= g_strdup(filename
);
584 if (!client
->filename
) {
586 cleanup_client(client
);
587 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
588 return send_syserror(ctx
, ENOMEM
);
591 if (req
[1] && *req
[1])
592 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
597 client
->pinentry
->filename
= g_strdup(client
->filename
);
599 if (!client
->pinentry
->filename
) {
600 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
601 cleanup_client(client
);
602 return send_syserror(ctx
, ENOMEM
);
605 return open_command_finalize(ctx
, NULL
, cached
);
608 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
610 client
->filename
= g_strdup(filename
);
612 if (!client
->filename
) {
613 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
615 cleanup_client(client
);
616 return send_syserror(ctx
, ENOMEM
);
620 if (client
->pinentry
->filename
)
621 g_free(client
->pinentry
->filename
);
623 client
->pinentry
->filename
= g_strdup(client
->filename
);
625 if (!client
->pinentry
->filename
) {
626 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
628 cleanup_client(client
);
629 return send_syserror(ctx
, ENOMEM
);
633 if (client
->crypto
->fh
->ver
.fh2
.iter
<= 0ULL)
636 CACHE_LOCK(client
->ctx
);
637 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
640 if (cached
== FALSE
) {
641 gchar
*tmp
= get_key_file_string(filename
, "key_file");
646 cleanup_client(client
);
647 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
651 * No key specified and no matching filename found in the cache. Use
652 * pinentry to retrieve the key. Cannot return assuan_process_done()
653 * here otherwise the command will be interrupted. The event loop in
654 * client_thread() will poll the file descriptor waiting for it to
655 * become ready to read a pinentry_key_s which will contain the
656 * entered key or an error code. It will then call
657 * open_command_finalize() to to finish the command.
659 if (!req
[1] || !*req
[1]) {
661 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
663 /* From set_pinentry_defaults(). */
664 if (client
->pinentry
->enable
== FALSE
||
665 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
666 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
671 rc
= lock_pin_mutex(client
);
674 unlock_pin_mutex(client
->pinentry
);
675 cleanup_client(client
);
676 return send_error(ctx
, rc
);
679 client
->pinentry
->which
= PINENTRY_OPEN
;
680 rc
= pinentry_fork(ctx
);
683 unlock_pin_mutex(client
->pinentry
);
684 cleanup_client(client
);
685 return send_error(ctx
, rc
);
688 // Called from pinentry iterate.
689 client
->pinentry
->cb
= open_command_finalize
;
690 client
->pinentry
->status
= PINENTRY_INIT
;
693 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
698 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
701 else if (req
&& req
[1] && *req
[1]) {
702 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
703 strlen(req
[1]) ? strlen(req
[1]) : 1);
708 return open_command_finalize(ctx
, NULL
, cached
);
711 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
712 guint size
, gpointer
*out
, gulong
*outsize
, gint
*rc
)
717 gint cmd
= Z_NO_FLUSH
;
719 gz
= g_malloc0(sizeof(struct gz_s
));
722 *rc
= gpg_error_from_errno(ENOMEM
);
726 pth_cleanup_push(gz_cleanup
, &gz
);
727 gz
->which
= STATUS_COMPRESS
;
728 gz
->z
.zalloc
= z_alloc
;
729 gz
->z
.zfree
= z_free
;
730 gz
->z
.next_in
= data
;
731 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
732 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
733 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
736 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
742 *rc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
745 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
750 /* Rather than store the size of the uncompressed data in the file header,
751 * store it in the comment field of the gzip header. Don't give anyone too
752 * much information. Not sure why really, but it seems the right way. :)
754 memset(&h
, 0, sizeof(gz_header
));
755 g_snprintf(buf
, sizeof(buf
), "%u", size
);
756 h
.comment
= (guchar
*)buf
;
757 *rc
= deflateSetHeader(&gz
->z
, &h
);
760 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
768 *rc
= deflate(&gz
->z
, cmd
);
774 if (!gz
->z
.avail_out
) {
775 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
778 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
784 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
785 gz
->z
.avail_out
= zlib_bufsize
;
788 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
789 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
790 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
792 gz
->z
.avail_in
= zlib_bufsize
;
794 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u",
795 gz
->z
.total_in
, size
);
801 if (gz
->z
.total_in
>= size
)
810 } while (*rc
!= Z_STREAM_END
);
812 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u", gz
->z
.total_in
, size
);
818 *outsize
= gz
->z
.total_out
;
825 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
830 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
833 * Useful for a large amount of data. Rather than doing all of the data in one
834 * iteration do it in chunks. This lets the command be cancelable rather than
835 * waiting for it to complete.
837 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
838 struct client_crypto_s
*crypto
, status_msg_t which
)
841 goffset len
= CRYPTO_BLOCKSIZE(crypto
);
842 gpointer p
= gcry_malloc(len
);
847 return gpg_err_code_from_errno(ENOMEM
);
849 if (crypto
->insize
< CRYPTO_BLOCKSIZE(crypto
))
850 len
= crypto
->insize
;
852 pth_cleanup_push(gcry_free
, p
);
855 inbuf
= (guchar
*)crypto
->inbuf
+ total
;
858 if (len
+ total
> crypto
->insize
)
859 len
= crypto
->blocksize
;
861 if (which
== STATUS_ENCRYPT
)
862 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
864 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
869 tmp
= (guchar
*)crypto
->inbuf
+ total
;
870 memmove(tmp
, p
, len
);
873 if (total
>= crypto
->insize
)
884 /* The crypto struct must be setup for iterations and .key. */
885 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
886 struct client_crypto_s
*crypto
, const gchar
*filename
)
888 goffset len
= crypto
->insize
;
892 guint64 iter_progress
= 0ULL, n_iter
= 0ULL, xiter
= 0ULL;
893 gchar tmp
[FILENAME_MAX
];
896 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
898 if (!crypto
->fh
->ver
.fh2
.iter
) {
900 * cache_file_count() needs both .used == TRUE and a valid key in
901 * order for it to count as a used cache entry. Fixes CACHE status
904 memset(crypto
->key
, '!', hashlen
);
909 * Resize the existing xml buffer to the block size required by gcrypt
910 * rather than duplicating it and wasting memory.
912 len
= (crypto
->insize
/ crypto
->blocksize
) * crypto
->blocksize
;
914 if (crypto
->insize
% crypto
->blocksize
)
915 len
+= crypto
->blocksize
;
917 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
920 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
921 return gpg_error_from_errno(ENOMEM
);
924 crypto
->inbuf
= inbuf
;
925 crypto
->insize
= len
;
926 gcry_create_nonce(crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
929 gcry_free(crypto
->tkey
);
931 crypto
->tkey
= gcry_malloc(hashlen
);
934 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
935 return gpg_error_from_errno(ENOMEM
);
938 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
939 guchar
*tkey
= crypto
->tkey
;
942 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
943 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
947 iter_progress
= (guint64
)get_key_file_double(
948 client
? client
->filename
: "global", "iteration_progress");
950 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
951 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
952 "0 %llu", crypto
->fh
->ver
.fh2
.iter
);
958 while (xiter
< crypto
->fh
->ver
.fh2
.iter
-1) {
959 if (iter_progress
> 0ULL && xiter
>= iter_progress
) {
960 if (!(xiter
% iter_progress
)) {
961 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
962 "%llu %llu", ++n_iter
* iter_progress
,
963 crypto
->fh
->ver
.fh2
.iter
);
970 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
971 crypto
->blocksize
))) {
972 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
976 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
979 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
986 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
987 crypto
->blocksize
))) {
988 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
992 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
993 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
997 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1002 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1003 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1004 "%llu %llu", crypto
->fh
->ver
.fh2
.iter
, crypto
->fh
->ver
.fh2
.iter
);
1014 if (!client
&& !g_ascii_strcasecmp(filename
, "-")) {
1015 crypto
->fh
->fd
= STDOUT_FILENO
;
1019 if (lstat(filename
, &st
) == 0) {
1020 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1022 if (!(mode
& S_IWUSR
))
1023 return gpg_error_from_errno(EACCES
);
1025 else if (errno
!= ENOENT
)
1026 return gpg_error_from_errno(errno
);
1028 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1029 crypto
->fh
->fd
= mkstemp(tmp
);
1031 if (crypto
->fh
->fd
== -1) {
1033 p
= strrchr(tmp
, '/');
1035 log_write("%s: %s", p
, strerror(rc
));
1036 return gpg_error_from_errno(rc
);
1039 pth_cleanup_push(cleanup_unlink_cb
, tmp
);
1043 * xml_import() or convert_file() from command line.
1045 crypto
->fh
->fd
= STDOUT_FILENO
;
1048 crypto
->fh
->ver
.fh2
.magic
[0] = '\177';
1049 crypto
->fh
->ver
.fh2
.magic
[1] = 'P';
1050 crypto
->fh
->ver
.fh2
.magic
[2] = 'W';
1051 crypto
->fh
->ver
.fh2
.magic
[3] = 'M';
1052 crypto
->fh
->ver
.fh2
.magic
[4] = 'D';
1053 crypto
->fh
->ver
.fh2
.version
= VERSION_HEX
;
1054 len
= pth_write(crypto
->fh
->fd
, &crypto
->fh
->ver
.fh2
, sizeof(crypto
->fh
->ver
.fh2
));
1056 if (len
!= sizeof(crypto
->fh
->ver
.fh2
)) {
1062 return gpg_error_from_errno(len
);
1065 len
= pth_write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1067 if (len
!= crypto
->insize
) {
1073 return gpg_error_from_errno(len
);
1076 if (fsync(crypto
->fh
->fd
) == -1) {
1082 return gpg_error_from_errno(len
);
1089 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1090 gchar tmp2
[FILENAME_MAX
];
1092 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1094 acl
= acl_get_file(filename
, ACL_TYPE_ACCESS
);
1097 log_write("ACL: %s: %s", filename
, strerror(errno
));
1100 if (rename(filename
, tmp2
) == -1) {
1107 return gpg_error_from_errno(len
);
1112 acl
= acl_get_file(".", ACL_TYPE_DEFAULT
);
1115 log_write("ACL: %s: %s", filename
, strerror(errno
));
1119 if (rename(tmp
, filename
) == -1) {
1126 return gpg_error_from_errno(len
);
1132 chmod(filename
, mode
);
1135 if (acl
&& acl_set_file(filename
, ACL_TYPE_ACCESS
, acl
))
1136 log_write("ACL: %s: %s", filename
, strerror(errno
));
1143 if (client
&& lstat(filename
, &st
) == 0)
1144 client
->mtime
= st
.st_mtime
;
1149 gpg_error_t
update_save_flags(const gchar
*filename
,
1150 struct client_crypto_s
*crypto
)
1157 crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1160 return GPG_ERR_ENOMEM
;
1163 rc
= init_client_crypto2(filename
, crypto
);
1168 if (filename
&& !crypto
->fh
->v1
) {
1169 iter
= (guint64
)get_key_file_double(filename
, "iterations");
1170 crypto
->fh
->ver
.fh2
.iter
= iter
< 0L ? 0UL : iter
;
1176 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1179 struct client_s
*client
= assuan_get_pointer(ctx
);
1189 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1190 gcry_free(client
->crypto
->key
);
1192 client
->crypto
->key
= key
;
1193 rc
= update_timestamp(client
->doc
);
1196 return send_error(ctx
, rc
);
1198 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1199 pth_cleanup_push(xmlFree
, xmlbuf
);
1200 clevel
= get_key_file_integer(client
->filename
, "compression_level");
1205 if (do_compress(ctx
, clevel
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
) == FALSE
) {
1207 cleanup_crypto(&client
->crypto
);
1209 if (zrc
== Z_MEM_ERROR
)
1210 return send_syserror(ctx
, ENOMEM
);
1212 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1220 client
->crypto
->inbuf
= xmlbuf
;
1221 client
->crypto
->insize
= len
;
1222 rc
= update_save_flags(client
->filename
, client
->crypto
);
1225 cleanup_crypto(&client
->crypto
);
1226 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1227 return send_error(ctx
, rc
);
1230 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1233 cleanup_crypto(&client
->crypto
);
1234 return send_error(ctx
, rc
);
1237 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1238 CACHE_LOCK(client
->ctx
);
1241 cache_reset_timeout(client
->md5file
, timeout
);
1244 if (client
->new == TRUE
)
1245 send_status_all(STATUS_CACHE
);
1247 client
->new = FALSE
;
1248 cleanup_crypto(&client
->crypto
);
1249 return send_error(ctx
, 0);
1252 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1254 cleanup_crypto(&client
->crypto
);
1255 return send_syserror(ctx
, ENOMEM
);
1258 client
->new = FALSE
;
1259 cache_reset_timeout(client
->md5file
, timeout
);
1261 send_status_all(STATUS_CACHE
);
1262 cleanup_crypto(&client
->crypto
);
1263 return send_error(ctx
, 0);
1266 static gint
save_command(assuan_context_t ctx
, gchar
*line
)
1268 gboolean cached
= FALSE
;
1270 struct client_s
*client
= assuan_get_pointer(ctx
);
1271 guint hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1274 log_write2("ARGS=%s", "<passphrase>");
1276 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1277 return send_syserror(ctx
, errno
);
1279 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1280 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1281 return send_error(ctx
, GPG_ERR_ENOANO
);
1285 cached
= cache_iscached(client
->md5file
);
1289 * If a cache entry doesn't exist for this file and the file has a
1290 * "key_file" or "key" parameter, then it's an error. The reason is that
1291 * cache expiration would be useless.
1293 if (cached
== FALSE
) {
1294 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1298 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1305 if (!client
->crypto
) {
1306 client
->crypto
= init_client_crypto();
1308 if (!client
->crypto
) {
1309 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1310 return send_syserror(ctx
, ENOMEM
);
1314 client
->crypto
->key
= gcry_malloc(hashlen
);
1316 if (!client
->crypto
->key
) {
1317 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1318 cleanup_crypto(&client
->crypto
);
1319 return send_syserror(ctx
, ENOMEM
);
1322 memset(client
->crypto
->key
, '!', hashlen
);
1324 if (get_key_file_double(client
->filename
, "iterations") <= 0L)
1327 if (!line
|| !*line
) {
1328 client
->crypto
->tkey
= gcry_malloc(hashlen
);
1330 if (!client
->crypto
->tkey
) {
1331 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1332 cleanup_crypto(&client
->crypto
);
1333 return send_syserror(ctx
, ENOMEM
);
1336 memset(client
->crypto
->tkey
, '!', hashlen
);
1339 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1340 !memcmp(client
->crypto
->key
, client
->crypto
->tkey
, hashlen
)) {
1343 #ifdef WITH_PINENTRY
1346 if (client
->pinentry
->enable
== FALSE
||
1347 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1348 /* Empty keys are allowed. */
1349 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1353 lock_pin_mutex(client
);
1354 client
->pinentry
->which
= PINENTRY_SAVE
;
1355 rc
= pinentry_fork(ctx
);
1358 unlock_pin_mutex(client
->pinentry
);
1359 cleanup_crypto(&client
->crypto
);
1360 return send_error(ctx
, rc
);
1363 client
->pinentry
->cb
= save_command_finalize
;
1364 client
->pinentry
->status
= PINENTRY_INIT
;
1367 /* Empty keys are allowed. */
1368 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1378 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, line
,
1382 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1385 static gint
delete_command(assuan_context_t ctx
, gchar
*line
)
1387 struct client_s
*client
= assuan_get_pointer(ctx
);
1392 log_write2("ARGS=\"%s\"", line
);
1394 if (strchr(line
, '\t'))
1395 req
= split_input_line(line
, "\t", -1);
1397 req
= split_input_line(line
, " ", -1);
1400 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1402 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1406 return send_error(ctx
, rc
);
1410 * No sub-node defined. Remove the entire node (root element).
1419 return send_error(ctx
, 0);
1422 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1426 return send_error(ctx
, rc
);
1433 return send_error(ctx
, 0);
1437 * Don't return with assuan_process_done() here. This has been called from
1438 * assuan_process_next() and the command should be finished in
1441 static gint
store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1444 assuan_context_t ctx
= data
;
1445 struct client_s
*client
= assuan_get_pointer(ctx
);
1448 gpg_error_t rc
= file_modified(client
);
1450 if (assuan_rc
|| rc
) {
1453 return assuan_rc
? assuan_rc
: rc
;
1456 req
= split_input_line((gchar
*)line
, "\t", 0);
1460 return EPWMD_COMMAND_SYNTAX
;
1463 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1465 if (rc
&& rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1466 rc
= new_root_element(client
->doc
, *req
);
1483 create_elements_cb(n
, req
+1, &rc
, NULL
);
1485 find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1486 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
, FALSE
);
1490 client
->inquire_status
= INQUIRE_DONE
;
1494 static gint
store_command(assuan_context_t ctx
, gchar
*line
)
1496 struct client_s
*client
= assuan_get_pointer(ctx
);
1499 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1502 return send_error(ctx
, rc
);
1504 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1505 client
->inquire_status
= INQUIRE_BUSY
;
1509 static void *send_data_cb(void *arg
)
1511 struct assuan_cmd_s
*data
= arg
;
1515 pth_cancel_state(PTH_CANCEL_ENABLE
|PTH_CANCEL_ASYNCHRONOUS
, &old
);
1516 rc
= g_malloc(sizeof(gpg_error_t
));
1517 *rc
= assuan_send_data(data
->ctx
, data
->line
, data
->line_len
);
1518 pth_cancel_state(old
, NULL
);
1523 /* For every assuan command that needs to be sent to the client, a timeout is
1524 * needed to determine if the client lost the connection. The timeout is the
1525 * same as the "keepalive" configuration parameter or a default if unset.
1527 gpg_error_t
do_assuan_command(assuan_context_t ctx
,
1528 void *(*cb
)(void *data
), void *data
)
1530 pth_attr_t attr
= pth_attr_new();
1533 gint to
= get_key_file_integer("global", "keepalive");
1534 pth_event_t ev
, tev
;
1539 pth_attr_init(attr
);
1540 pth_attr_set(attr
, PTH_ATTR_JOINABLE
, TRUE
);
1541 tid
= pth_spawn(attr
, cb
, data
);
1543 pth_attr_destroy(attr
);
1546 log_write("%s(%i): pth_spawn(): %s", __FILE__
, __LINE__
,
1547 _gpg_strerror(gpg_error_from_errno(n
)));
1548 return gpg_error_from_errno(n
);
1551 pth_cleanup_push(cleanup_cancel_cb
, tid
);
1552 to
= to
<= 0 ? DEFAULT_KEEPALIVE_TO
: to
;
1553 ev
= pth_event(PTH_EVENT_TID
|PTH_UNTIL_TID_DEAD
, tid
);
1554 tev
= pth_event(PTH_EVENT_TIME
, pth_timeout(to
, 0));
1555 ev
= pth_event_concat(ev
, tev
, NULL
);
1556 pth_cleanup_push(cleanup_ev_cb
, ev
);
1559 st
= pth_event_status(ev
);
1561 if (st
== PTH_STATUS_FAILED
) {
1565 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1567 else if (st
== PTH_STATUS_OCCURRED
) {
1569 rc
= *(gpg_error_t
*)p
;
1573 st
= pth_event_status(tev
);
1575 if (st
== PTH_STATUS_OCCURRED
) {
1579 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1588 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
1594 struct assuan_cmd_s data
;
1595 gint progress
= get_key_file_integer("global", "xfer_progress");
1598 progress
= progress
>0 ? (progress
/ASSUAN_LINELENGTH
)*ASSUAN_LINELENGTH
: 0;
1599 to_send
= total
< ASSUAN_LINELENGTH
? total
: ASSUAN_LINELENGTH
;
1601 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1608 if (sent
+ to_send
> total
)
1609 to_send
= total
- sent
;
1611 data
.line
= flush
? NULL
: (gchar
*)line
+sent
;
1612 data
.line_len
= flush
? 0 : to_send
;
1613 rc
= do_assuan_command(ctx
, send_data_cb
, &data
);
1616 sent
+= flush
? 0 : to_send
;
1618 if ((progress
&& !(sent
% progress
) && sent
!= total
) ||
1619 (sent
== total
&& flush
))
1620 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1622 if (!flush
&& !rc
&& sent
== total
) {
1627 } while (!rc
&& sent
< total
);
1632 static gint
get_command(assuan_context_t ctx
, gchar
*line
)
1634 struct client_s
*client
= assuan_get_pointer(ctx
);
1639 log_write2("ARGS=\"%s\"", line
);
1640 req
= split_input_line(line
, "\t", -1);
1642 if (!req
|| !*req
) {
1644 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1647 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1651 return send_error(ctx
, rc
);
1655 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1660 return send_error(ctx
, rc
);
1662 if (!n
|| !n
->children
)
1663 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1665 n
= find_text_node(n
->children
);
1667 if (!n
|| !n
->content
|| !*n
->content
)
1668 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1670 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
1671 return send_error(ctx
, rc
);
1674 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
1675 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
1677 gchar
*path
= *(gchar
**)data
;
1678 gchar
*tmp
= NULL
, *result
;
1682 *(gchar
**)data
= NULL
;
1685 path
= g_strjoinv("\t", target
);
1688 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1689 *rc
= gpg_error_from_errno(ENOMEM
);
1694 tmp
= g_strjoinv("\t", req_orig
);
1698 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1699 *rc
= gpg_error_from_errno(ENOMEM
);
1705 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1707 result
= g_strdup(path
);
1710 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1711 *rc
= gpg_error_from_errno(ENOMEM
);
1719 *(gchar
**)data
= result
;
1723 static void list_command_cleanup1(void *arg
);
1724 static gint
realpath_command(assuan_context_t ctx
, gchar
*line
)
1727 struct client_s
*client
= assuan_get_pointer(ctx
);
1735 log_write2("ARGS=\"%s\"", line
);
1737 if (strchr(line
, '\t') != NULL
) {
1738 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1739 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1742 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1743 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1746 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1750 return send_error(ctx
, rc
);
1753 rp
= g_strjoinv("\t", req
);
1757 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1758 return send_syserror(ctx
, ENOMEM
);
1762 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1763 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
, FALSE
);
1768 return send_error(ctx
, rc
);
1772 string
= g_string_new(rp
);
1777 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1778 return send_syserror(ctx
, ENOMEM
);
1782 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
1783 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
1784 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1789 pth_cleanup_push(list_command_cleanup1
, string
);
1790 rc
= xfer_data(ctx
, string
->str
, string
->len
);
1792 return send_error(ctx
, rc
);
1795 static void list_command_cleanup1(void *arg
)
1797 g_string_free((GString
*)arg
, TRUE
);
1800 static void list_command_cleanup2(void *arg
)
1802 struct element_list_s
*elements
= arg
;
1805 gint total
= g_slist_length(elements
->list
);
1808 for (i
= 0; i
< total
; i
++) {
1809 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
1813 g_slist_free(elements
->list
);
1815 if (elements
->prefix
)
1816 g_free(elements
->prefix
);
1822 static gint
list_command(assuan_context_t ctx
, gchar
*line
)
1824 struct client_s
*client
= assuan_get_pointer(ctx
);
1826 struct element_list_s
*elements
= NULL
;
1829 if (disable_list_and_dump
== TRUE
)
1830 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1832 log_write2("ARGS=\"%s\"", line
);
1837 rc
= list_root_elements(client
->doc
, &str
);
1840 return send_error(ctx
, rc
);
1842 pth_cleanup_push(list_command_cleanup1
, str
);
1843 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1845 return send_error(ctx
, rc
);
1848 elements
= g_malloc0(sizeof(struct element_list_s
));
1851 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1852 rc
= gpg_err_code_from_errno(ENOMEM
);
1856 pth_cleanup_push(list_command_cleanup2
, elements
);
1857 rc
= create_path_list(client
->doc
, elements
, line
);
1863 gint total
= g_slist_length(elements
->list
);
1868 rc
= EPWMD_EMPTY_ELEMENT
;
1872 str
= g_string_new(NULL
);
1875 rc
= gpg_err_code_from_errno(ENOMEM
);
1876 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1880 for (i
= 0; i
< total
; i
++) {
1881 tmp
= g_slist_nth_data(elements
->list
, i
);
1882 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
1885 pth_cleanup_push(list_command_cleanup1
, str
);
1886 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1890 rc
= EPWMD_EMPTY_ELEMENT
;
1894 return send_error(ctx
, rc
);
1898 * req[0] - element path
1900 static gint
attribute_list(assuan_context_t ctx
, gchar
**req
)
1902 struct client_s
*client
= assuan_get_pointer(ctx
);
1903 gchar
**attrlist
= NULL
;
1905 gchar
**path
= NULL
;
1911 if (!req
|| !req
[0])
1912 return EPWMD_COMMAND_SYNTAX
;
1914 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1916 * The first argument may be only a root element.
1918 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1919 return EPWMD_COMMAND_SYNTAX
;
1922 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
1930 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1931 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1941 for (a
= n
->properties
; a
; a
= a
->next
) {
1944 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1946 g_strfreev(attrlist
);
1948 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1949 return gpg_error_from_errno(ENOMEM
);
1954 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
,
1955 an
&& an
->content
? (gchar
*)an
->content
: "");
1958 g_strfreev(attrlist
);
1959 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1960 return gpg_error_from_errno(ENOMEM
);
1963 attrlist
[++i
] = NULL
;
1967 return EPWMD_EMPTY_ELEMENT
;
1969 line
= g_strjoinv("\n", attrlist
);
1972 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1973 g_strfreev(attrlist
);
1974 return gpg_error_from_errno(ENOMEM
);
1977 pth_cleanup_push(g_free
, line
);
1978 pth_cleanup_push(req_cleanup
, attrlist
);
1979 rc
= xfer_data(ctx
, line
, strlen(line
));
1986 * req[0] - attribute
1987 * req[1] - element path
1989 static gint
attribute_delete(struct client_s
*client
, gchar
**req
)
1992 gchar
**path
= NULL
;
1995 if (!req
|| !req
[0] || !req
[1])
1996 return EPWMD_COMMAND_SYNTAX
;
1998 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2000 * The first argument may be only a root element.
2002 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2003 return EPWMD_COMMAND_SYNTAX
;
2007 * Don't remove the "name" attribute for the root element. To remove an
2008 * root element use DELETE <name>.
2010 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
2011 rc
= EPWMD_ATTR_SYNTAX
;
2015 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2021 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2022 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2029 return delete_attribute(n
, (xmlChar
*)req
[0]);
2036 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
2039 gchar
**src
= *path
;
2040 gchar
**src_orig
= g_strdupv(src
);
2041 xmlNodePtr n
= NULL
;
2046 *rc
= gpg_error_from_errno(ENOMEM
);
2047 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2052 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2055 if (*rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2056 *rc
= new_root_element(client
->doc
, src
[0]);
2069 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
2071 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2072 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
, FALSE
);
2078 * Reset the position of the element tree now that the elements
2079 * have been created.
2084 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2089 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2090 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2098 g_strfreev(src_orig
);
2105 * Creates a "target" attribute. When other commands encounter an element with
2106 * this attribute, the element path is modified to the target value. If the
2107 * source element path doesn't exist when using 'ATTR SET target', it is
2108 * created, but the destination element path must exist.
2110 * req[0] - source element path
2111 * req[1] - destination element path
2113 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2115 gchar
**src
, **dst
, *line
= NULL
, **odst
= NULL
;
2119 if (!req
|| !req
[0] || !req
[1])
2120 return EPWMD_COMMAND_SYNTAX
;
2122 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2124 * The first argument may be only a root element.
2126 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2127 return EPWMD_COMMAND_SYNTAX
;
2130 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2132 * The first argument may be only a root element.
2134 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2135 rc
= EPWMD_COMMAND_SYNTAX
;
2140 odst
= g_strdupv(dst
);
2143 rc
= gpg_error_from_errno(ENOMEM
);
2147 n
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
2150 * Make sure the destination element path exists.
2156 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2157 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2163 n
= create_element_path(client
, &src
, &rc
);
2168 line
= g_strjoinv("\t", odst
);
2171 rc
= gpg_error_from_errno(ENOMEM
);
2172 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2176 rc
= add_attribute(n
, "target", line
);
2190 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2196 tmp
= g_strdupv(req
);
2199 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2200 return gpg_error_from_errno(ENOMEM
);
2203 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2209 if (g_utf8_collate(req
[0], req
[1]) == 0)
2213 * Will not overwrite an existing root.
2215 tmp
= g_strdupv(req
+1);
2218 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2219 return gpg_error_from_errno(ENOMEM
);
2222 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2225 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
2229 return GPG_ERR_AMBIGUOUS_NAME
;
2232 * Whitespace not allowed in root names.
2234 if (contains_whitespace(req
[1]) == TRUE
)
2235 return EPWMD_ATTR_SYNTAX
;
2237 tmp
= g_strdupv(req
);
2240 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2241 return gpg_error_from_errno(ENOMEM
);
2244 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2248 return EPWMD_ELEMENT_NOT_FOUND
;
2250 return add_attribute(n
, "name", req
[1]);
2254 * req[0] - attribute
2255 * req[1] - element path
2257 static gint
attribute_get(assuan_context_t ctx
, gchar
**req
)
2259 struct client_s
*client
= assuan_get_pointer(ctx
);
2265 if (!req
|| !req
[0] || !req
[1])
2266 return EPWMD_COMMAND_SYNTAX
;
2268 if (strchr(req
[1], '\t')) {
2269 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2270 return EPWMD_COMMAND_SYNTAX
;
2273 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2274 return EPWMD_COMMAND_SYNTAX
;
2277 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2283 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2284 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2292 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2293 return EPWMD_ATTR_NOT_FOUND
;
2295 pth_cleanup_push(xmlFree
, a
);
2298 rc
= xfer_data(ctx
, (gchar
*)a
, xmlStrlen(a
));
2300 rc
= GPG_ERR_NO_VALUE
;
2311 * req[0] - attribute
2312 * req[1] - element path
2315 static gint
attribute_set(struct client_s
*client
, gchar
**req
)
2317 gchar
**path
= NULL
;
2321 if (!req
|| !req
[0] || !req
[1])
2322 return EPWMD_COMMAND_SYNTAX
;
2325 * Reserved attribute names.
2327 if (!strcmp(req
[0], "name")) {
2329 * Only reserved for the root element. Not the rest of the
2332 if (strchr(req
[1], '\t') == NULL
)
2333 return name_attribute(client
, req
+ 1);
2335 else if (!strcmp(req
[0], "target"))
2336 return target_attribute(client
, req
+ 1);
2338 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2340 * The first argument may be only a root element.
2342 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2343 return EPWMD_COMMAND_SYNTAX
;
2346 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2352 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2353 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2360 return add_attribute(n
, req
[0], req
[2]);
2369 * req[1] - attribute name or element path if command is LIST
2370 * req[2] - element path
2371 * req[2] - element path or value
2373 static gint
attr_command(assuan_context_t ctx
, gchar
*line
)
2375 struct client_s
*client
= assuan_get_pointer(ctx
);
2379 log_write2("ARGS=\"%s\"", line
);
2380 req
= split_input_line(line
, " ", 4);
2382 if (!req
|| !req
[0] || !req
[1]) {
2384 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2387 pth_cleanup_push(req_cleanup
, req
);
2389 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2390 rc
= attribute_set(client
, req
+1);
2391 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2392 rc
= attribute_get(ctx
, req
+1);
2393 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2394 rc
= attribute_delete(client
, req
+1);
2395 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2396 rc
= attribute_list(ctx
, req
+1);
2398 rc
= EPWMD_COMMAND_SYNTAX
;
2401 return send_error(ctx
, rc
);
2404 static gint
iscached_command(assuan_context_t ctx
, gchar
*line
)
2406 gchar
**req
= split_input_line(line
, " ", 0);
2410 if (!req
|| !*req
) {
2412 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2415 log_write2("ARGS=\"%s\"", line
);
2417 if (!valid_filename(req
[0])) {
2419 return EPWMD_INVALID_FILENAME
;
2422 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2425 if (cache_iscached(md5file
)) {
2428 return send_error(ctx
, 0);
2432 tmp
= get_key_file_string("global", "data_directory");
2436 return gpg_error_from_errno(ENOMEM
);
2439 path
= expand_homedir(tmp
);
2444 return gpg_error_from_errno(ENOMEM
);
2449 path
= g_strdup_printf("%s/%s", tmp
, req
[0]);
2454 return gpg_error_from_errno(ENOMEM
);
2457 if (access(path
, R_OK
) == -1) {
2458 gpg_error_t rc
= gpg_error_from_syserror();
2462 return send_error(ctx
, rc
);
2466 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2469 static gint
clearcache_command(assuan_context_t ctx
, gchar
*line
)
2471 struct client_s
*client
= assuan_get_pointer(ctx
);
2472 gchar
**req
= split_input_line(line
, " ", 0);
2475 log_write2("ARGS=\"%s\"", line
);
2478 if (!req
|| !*req
) {
2480 cache_clear(client
->md5file
, 2);
2482 return send_error(ctx
, 0);
2485 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2488 if (cache_clear(md5file
, 1) == FALSE
) {
2490 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2494 return send_error(ctx
, 0);
2497 static gint
cachetimeout_command(assuan_context_t ctx
, gchar
*line
)
2501 gchar
**req
= split_input_line(line
, " ", 0);
2504 if (!req
|| !*req
|| !req
[1]) {
2506 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2510 timeout
= strtol(req
[1], &p
, 10);
2512 if (errno
!= 0 || *p
!= 0 || timeout
< -1) {
2514 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2517 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2518 CACHE_LOCK(client
->ctx
);
2520 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2522 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2526 return send_error(ctx
, 0);
2529 static gint
dump_command(assuan_context_t ctx
, gchar
*line
)
2533 struct client_s
*client
= assuan_get_pointer(ctx
);
2536 if (disable_list_and_dump
== TRUE
)
2537 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2539 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2542 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2543 return send_syserror(ctx
, ENOMEM
);
2546 pth_cleanup_push(xmlFree
, xml
);
2547 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
2549 return send_error(ctx
, rc
);
2552 static gint
getconfig_command(assuan_context_t ctx
, gchar
*line
)
2554 struct client_s
*client
= assuan_get_pointer(ctx
);
2556 gchar filename
[255]={0}, param
[747]={0};
2557 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2559 log_write2("ARGS=\"%s\"", line
);
2561 if (strchr(line
, ' ')) {
2562 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2567 if (fp
&& !valid_filename(fp
))
2568 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
2570 paramp
= g_ascii_strdown(paramp
, -1);
2573 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2574 return send_syserror(ctx
, ENOMEM
);
2577 if (fp
&& !g_ascii_strcasecmp(paramp
, "iterations")) {
2578 if (!(client
->opts
& OPT_ITERATIONS
) || fp
!= client
->filename
) {
2579 file_header_internal_t
*fh
= read_file_header(fp
, FALSE
, &rc
);
2581 if (!fh
&& rc
!= GPG_ERR_ENOENT
)
2582 return send_error(ctx
, rc
);
2586 p
= g_strdup_printf("%lu", (unsigned long)fh
->ver
.fh2
.iter
);
2587 close_file_header(fh
);
2590 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2592 return send_syserror(ctx
, ENOMEM
);
2599 else if (!g_ascii_strcasecmp(paramp
, "enable_pinentry")) {
2600 #ifdef WITH_PINENTRY
2603 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY
))
2604 n
= client
->pinentry
->enable
;
2606 n
= get_key_file_boolean(fp
, "enable_pinentry");
2608 p
= g_strdup_printf("%s", n
? "true" : "false");
2611 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2613 return send_syserror(ctx
, ENOMEM
);
2618 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2621 else if (!g_ascii_strcasecmp(paramp
, "pinentry_timeout")) {
2622 #ifdef WITH_PINENTRY
2623 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY_TO
))
2624 p
= g_strdup_printf("%i", client
->pinentry
->timeout
);
2626 p
= g_strdup_printf("%i",
2627 get_key_file_integer(fp
, "pinentry_timeout"));
2630 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2632 return send_syserror(ctx
, ENOMEM
);
2637 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2641 p
= get_key_file_string(fp
? fp
: "global", paramp
);
2645 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2647 tmp
= expand_homedir(p
);
2651 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2652 return send_syserror(ctx
, ENOMEM
);
2657 pth_cleanup_push(g_free
, p
);
2658 rc
= xfer_data(ctx
, p
, strlen(p
));
2660 return send_error(ctx
, rc
);
2664 xmlXPathContextPtr xp
;
2665 xmlXPathObjectPtr result
;
2670 static void xpath_command_cleanup(void *arg
)
2672 struct xpath_s
*xpath
= arg
;
2674 req_cleanup(xpath
->req
);
2677 xmlBufferFree(xpath
->buf
);
2680 xmlXPathFreeObject(xpath
->result
);
2683 xmlXPathFreeContext(xpath
->xp
);
2686 static gint
xpath_command(assuan_context_t ctx
, gchar
*line
)
2688 struct client_s
*client
= assuan_get_pointer(ctx
);
2690 struct xpath_s xpath
;
2692 log_write2("ARGS=\"%s\"", line
);
2694 if (disable_list_and_dump
== TRUE
)
2695 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2697 if (!line
|| !*line
)
2698 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2700 memset(&xpath
, 0, sizeof(struct xpath_s
));
2702 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
2703 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
2704 return send_syserror(ctx
, ENOMEM
);
2707 xpath
.xp
= xmlXPathNewContext(client
->doc
);
2710 xpath_command_cleanup(&xpath
);
2711 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2714 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
2716 if (!xpath
.result
) {
2717 xpath_command_cleanup(&xpath
);
2718 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2721 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
2722 rc
= EPWMD_ELEMENT_NOT_FOUND
;
2726 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
2727 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, 0, NULL
);
2731 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
2732 rc
= EPWMD_EMPTY_ELEMENT
;
2735 else if (xpath
.req
[1])
2738 pth_cleanup_push(xpath_command_cleanup
, &xpath
);
2739 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
.buf
),
2740 xmlBufferLength(xpath
.buf
));
2744 xpath_command_cleanup(&xpath
);
2745 return send_error(ctx
, rc
);
2748 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
2749 static gint
xpathattr_command(assuan_context_t ctx
, gchar
*line
)
2751 struct client_s
*client
= assuan_get_pointer(ctx
);
2753 struct xpath_s xpath
;
2755 gboolean cmd
= FALSE
; //SET
2757 log_write2("ARGS=\"%s\"", line
);
2759 if (disable_list_and_dump
== TRUE
)
2760 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2762 if (!line
|| !*line
)
2763 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2765 memset(&xpath
, 0, sizeof(struct xpath_s
));
2767 if ((req
= split_input_line(line
, " ", 3)) == NULL
)
2768 return send_syserror(ctx
, ENOMEM
);
2771 rc
= GPG_ERR_SYNTAX
;
2775 if (!g_ascii_strcasecmp(req
[0], "SET"))
2777 else if (!g_ascii_strcasecmp(req
[0], "DELETE"))
2780 rc
= GPG_ERR_SYNTAX
;
2784 if (!req
[1] || !req
[2]) {
2785 rc
= GPG_ERR_SYNTAX
;
2789 if ((xpath
.req
= split_input_line(req
[2], "\t", 3)) == NULL
) {
2790 rc
= gpg_err_code_from_errno(ENOMEM
);
2794 if (!xpath
.req
[0] || (!xpath
.req
[1] && !cmd
) || (xpath
.req
[1] && cmd
)) {
2795 rc
= GPG_ERR_SYNTAX
;
2799 xpath
.xp
= xmlXPathNewContext(client
->doc
);
2802 rc
= EPWMD_LIBXML_ERROR
;
2806 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
2808 if (!xpath
.result
) {
2809 rc
= EPWMD_LIBXML_ERROR
;
2813 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
2814 rc
= EPWMD_ELEMENT_NOT_FOUND
;
2818 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
2819 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, cmd
, (xmlChar
*)req
[1]);
2823 xpath_command_cleanup(&xpath
);
2824 return send_error(ctx
, rc
);
2827 static gint
import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
2830 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
2831 gpg_error_t rc
= file_modified(client
);
2832 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
2833 xmlDocPtr doc
= NULL
;
2834 xmlNodePtr n
, root
, copy
;
2836 if (assuan_rc
|| rc
) {
2839 return assuan_rc
? assuan_rc
: rc
;
2842 req
= split_input_line((gchar
*)line
, "\t", 2);
2846 return EPWMD_COMMAND_SYNTAX
;
2849 path
= split_input_line(req
[1], "\t", 0);
2851 if (!content
|| !*content
) {
2852 rc
= EPWMD_COMMAND_SYNTAX
;
2856 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2859 rc
= EPWMD_LIBXML_ERROR
;
2863 root
= xmlDocGetRootElement(doc
);
2866 path_orig
= g_strdupv(path
);
2869 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2870 rc
= gpg_error_from_errno(ENOMEM
);
2874 if (strv_printf(&path
, "%s", (gchar
*)root
->name
) == FALSE
) {
2875 g_strfreev(path_orig
);
2876 rc
= gpg_error_from_errno(ENOMEM
);
2880 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2882 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2883 g_strfreev(path_orig
);
2888 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, TRUE
);
2890 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2891 g_strfreev(path_orig
);
2895 xmlNodePtr parent
= n
->parent
;
2906 if (rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2907 n
= create_element_path(client
, &path
, &rc
);
2913 copy
= xmlCopyNode(root
, 1);
2914 n
= xmlAddChild(n
, copy
);
2917 rc
= EPWMD_LIBXML_ERROR
;
2920 /* Check if the content root element can create a DTD root element. */
2921 if (xmlStrcmp((xmlChar
*)"root", root
->name
)) {
2922 rc
= EPWMD_COMMAND_SYNTAX
;
2928 if ((a
= xmlGetProp(root
, (xmlChar
*)"name")) == NULL
) {
2929 rc
= EPWMD_COMMAND_SYNTAX
;
2933 gchar
*tmp
= g_strdup((gchar
*)a
);
2935 gboolean literal
= is_literal_element(&tmp
);
2937 if (!valid_xml_element((xmlChar
*)tmp
) || literal
) {
2939 rc
= EPWMD_INVALID_ELEMENT
;
2943 if (strv_printf(&path
, "%s", tmp
) == FALSE
) {
2945 rc
= gpg_error_from_errno(ENOMEM
);
2950 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, TRUE
);
2952 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2953 rc
= EPWMD_LIBXML_ERROR
;
2957 /* Overwriting the existing tree. */
2964 xmlSetProp(root
, (xmlChar
*)"name", (xmlChar
*)path
[0]);
2965 n
= xmlCopyNode(root
, 1);
2966 n
= xmlAddChild(xmlDocGetRootElement(client
->doc
), n
);
2977 client
->inquire_status
= INQUIRE_DONE
;
2981 static gint
import_command(assuan_context_t ctx
, gchar
*line
)
2984 struct client_s
*client
= assuan_get_pointer(ctx
);
2986 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
2989 return send_error(ctx
, rc
);
2991 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2992 client
->inquire_status
= INQUIRE_BUSY
;
2996 static gpg_error_t
do_lock_command(struct client_s
*client
)
2998 gpg_error_t rc
= lock_file_mutex(client
);
3001 client
->is_lock_cmd
= TRUE
;
3003 return send_error(client
->ctx
, rc
);
3006 static gint
lock_command(assuan_context_t ctx
, gchar
*line
)
3008 struct client_s
*client
= assuan_get_pointer(ctx
);
3010 return do_lock_command(client
);
3013 static gint
unlock_command(assuan_context_t ctx
, gchar
*line
)
3015 struct client_s
*client
= assuan_get_pointer(ctx
);
3017 unlock_file_mutex(client
);
3018 return send_error(ctx
, 0);
3021 static gint
getpid_command(assuan_context_t ctx
, gchar
*line
)
3025 pid_t pid
= getpid();
3027 print_fmt(buf
, sizeof(buf
), "%i", pid
);
3028 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3029 return send_error(ctx
, rc
);
3032 static gint
version_command(assuan_context_t ctx
, gchar
*line
)
3037 print_fmt(buf
, sizeof(buf
), "0x%X", VERSION_HEX
);
3038 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3039 return send_error(ctx
, rc
);
3042 #ifdef WITH_PINENTRY
3043 static void set_option_value(gchar
**opt
, const gchar
*value
)
3051 *opt
= g_strdup(value
);
3055 static gint
set_unset_common(assuan_context_t ctx
, const gchar
*name
,
3058 struct client_s
*client
= assuan_get_pointer(ctx
);
3060 if (g_ascii_strcasecmp(name
, (gchar
*)"log_level") == 0) {
3064 l
= strtol(value
, NULL
, 10);
3067 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3070 log_write1("log_level=%li", l
);
3071 MUTEX_LOCK(&rcfile_mutex
);
3072 g_key_file_set_integer(keyfileh
, "global", "log_level", (gint
)l
);
3073 MUTEX_UNLOCK(&rcfile_mutex
);
3076 else if (g_ascii_strcasecmp(name
, (gchar
*)"lock_on_open") == 0) {
3080 l
= strtol(value
, NULL
, 10);
3083 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3086 log_write1("lock_on_open=%li", l
);
3087 client
->lockonopen
= l
? TRUE
: FALSE
;
3090 else if (g_ascii_strcasecmp(name
, (gchar
*)"cipher") == 0) {
3092 const gchar
*p
= value
;
3094 if (!client
->filename
)
3095 return EPWMD_NO_FILE
;
3098 flags
= pwmd_cipher_str_to_cipher(value
);
3101 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3104 p
= get_key_file_string("global", "cipher");
3106 MUTEX_LOCK(&rcfile_mutex
);
3107 g_key_file_set_string(keyfileh
, client
->filename
, "cipher", p
);
3108 MUTEX_UNLOCK(&rcfile_mutex
);
3109 log_write1("cipher=%s", p
);
3116 else if (g_ascii_strcasecmp(name
, (gchar
*)"iterations") == 0) {
3120 if (!client
->filename
)
3121 return EPWMD_NO_FILE
;
3124 MUTEX_LOCK(&rcfile_mutex
);
3125 g_key_file_set_double(keyfileh
, client
->filename
, "iterations",
3126 get_key_file_double("global", "iterations"));
3127 MUTEX_UNLOCK(&rcfile_mutex
);
3128 log_write1("iterations=%lu",
3129 (guint64
)get_key_file_double(client
->filename
, "iterations"));
3134 n
= strtoul(value
, &p
, 10);
3136 if (errno
|| (p
&& *p
) || n
== G_MAXULONG
)
3137 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3139 MUTEX_LOCK(&rcfile_mutex
);
3140 g_key_file_set_double(keyfileh
,
3141 client
->filename
? client
->filename
: "global", "iterations", n
);
3142 MUTEX_UNLOCK(&rcfile_mutex
);
3144 if (client
->filename
)
3145 client
->opts
|= OPT_ITERATIONS
;
3147 log_write1("iterations=%lu", n
);
3150 else if (g_ascii_strcasecmp(name
, (gchar
*)"NAME") == 0) {
3151 pth_attr_t attr
= pth_attr_of(pth_self());
3155 pth_attr_destroy(attr
);
3159 print_fmt(buf
, sizeof(buf
), "%s", value
);
3160 pth_attr_set(attr
, PTH_ATTR_NAME
, buf
);
3161 pth_attr_destroy(attr
);
3162 log_write1("name=%s", buf
);
3163 #ifdef WITH_PINENTRY
3164 if (client
->pinentry
->name
)
3165 g_free(client
->pinentry
->name
);
3167 client
->pinentry
->name
= g_strdup(buf
);
3169 if (!client
->pinentry
->name
)
3170 return gpg_error_from_errno(ENOMEM
);
3175 #ifdef WITH_PINENTRY
3176 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3177 set_option_value(&client
->pinentry
->lcmessages
, value
);
3178 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3179 set_option_value(&client
->pinentry
->lcctype
, value
);
3180 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3181 set_option_value(&client
->pinentry
->ttyname
, value
);
3182 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3183 set_option_value(&client
->pinentry
->ttytype
, value
);
3184 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3185 set_option_value(&client
->pinentry
->display
, value
);
3186 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3187 set_option_value(&client
->pinentry
->path
, value
);
3188 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3189 set_option_value(&client
->pinentry
->title
, value
);
3190 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3191 set_option_value(&client
->pinentry
->prompt
, value
);
3192 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3193 set_option_value(&client
->pinentry
->desc
, value
);
3194 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0) {
3199 client
->pinentry
->timeout
=
3200 get_key_file_integer(client
->filename
, "pinentry_timeout");
3201 client
->opts
&= ~(OPT_PINENTRY_TO
);
3202 log_write1("pinentry_timeout=%i",
3203 get_key_file_integer(client
->filename
, "pinentry_timeout"));
3207 n
= strtol(value
, &p
, 10);
3210 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3212 client
->pinentry
->timeout
= n
;
3213 client
->opts
|= OPT_PINENTRY_TO
;
3214 log_write1("pinentry_timeout=%i", n
);
3217 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0) {
3222 client
->pinentry
->enable
= -1;
3223 client
->opts
&= ~(OPT_PINENTRY
);
3227 n
= strtol(value
, &p
, 10);
3229 if (*p
|| n
< 0 || n
> 1)
3230 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3232 client
->pinentry
->enable
= n
== 0 ? FALSE
: TRUE
;
3233 client
->opts
|= OPT_PINENTRY
;
3234 log_write1("enable_pinentry=%i", n
);
3239 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
3241 log_write1("%s=%s", name
, value
? value
: "");
3247 static gint
unset_command(assuan_context_t ctx
, gchar
*line
)
3249 log_write2("ARGS=\"%s\"", line
);
3250 return send_error(ctx
, set_unset_common(ctx
, line
, NULL
));
3253 static gint
set_command(assuan_context_t ctx
, gchar
*line
)
3255 gchar name
[64] = {0}, value
[256] = {0};
3257 log_write2("ARGS=\"%s\"", line
);
3259 if (sscanf(line
, " %63[_a-zA-Z] = %255c", name
, value
) != 2)
3260 return send_error(ctx
, gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
));
3262 return send_error(ctx
, set_unset_common(ctx
, name
, value
));
3265 static gint
rename_command(assuan_context_t ctx
, gchar
*line
)
3267 struct client_s
*client
= assuan_get_pointer(ctx
);
3269 gchar
**req
, **src
, *dst
;
3272 log_write2("ARGS=\"%s\"", line
);
3273 req
= split_input_line(line
, " ", -1);
3275 if (!req
|| !req
[0] || !req
[1]) {
3277 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
3281 is_literal_element(&dst
);
3283 if (!valid_xml_element((xmlChar
*)dst
)) {
3285 return EPWMD_INVALID_ELEMENT
;
3288 if (strchr(req
[0], '\t'))
3289 src
= split_input_line(req
[0], "\t", -1);
3291 src
= split_input_line(req
[0], " ", -1);
3293 if (!src
|| !*src
) {
3294 rc
= EPWMD_COMMAND_SYNTAX
;
3298 n
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3301 n
= find_elements(client
->doc
, n
->children
, src
+1, &rc
, NULL
, NULL
,
3302 NULL
, FALSE
, 0, NULL
, FALSE
);
3307 /* To prevent unwanted effects:
3309 * <root name="a"><b/></root>
3313 if (xmlStrEqual(n
->name
, (xmlChar
*)dst
)) {
3314 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3323 for (p
= src
; *p
; p
++) {
3327 strv_printf(&tmp
, "%s", *p
);
3331 strv_printf(&tmp
, "!%s", dst
);
3332 ndst
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
3334 if (!ndst
&& rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
3340 ndst
= find_elements(client
->doc
, ndst
->children
, tmp
+1, &rc
, NULL
,
3341 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3345 if (!ndst
&& rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
3350 /* Target may exist:
3353 * <root name="b" target="a"/>
3361 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3366 xmlUnlinkNode(ndst
);
3367 xmlFreeNodeList(ndst
);
3371 xmlNodeSetName(n
, (xmlChar
*)dst
);
3373 rc
= add_attribute(n
, "name", dst
);
3378 return send_error(ctx
, rc
);
3381 static gint
copy_command(assuan_context_t ctx
, gchar
*line
)
3383 struct client_s
*client
= assuan_get_pointer(ctx
);
3385 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3386 xmlNodePtr nsrc
, ndst
, new;
3388 log_write2("ARGS=\"%s\"", line
);
3389 req
= split_input_line(line
, " ", -1);
3391 if (!req
|| !req
[0] || !req
[1]) {
3393 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
3396 if (strchr(req
[0], '\t'))
3397 src
= split_input_line(req
[0], "\t", -1);
3399 src
= split_input_line(req
[0], " ", -1);
3401 if (!src
|| !*src
) {
3402 rc
= EPWMD_COMMAND_SYNTAX
;
3406 if (strchr(req
[1], '\t'))
3407 dst
= split_input_line(req
[1], "\t", -1);
3409 dst
= split_input_line(req
[1], " ", -1);
3411 if (!dst
|| !*dst
) {
3412 rc
= EPWMD_COMMAND_SYNTAX
;
3416 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3419 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3420 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3425 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3428 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3429 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3431 if (!ndst
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
3434 new = xmlCopyNodeList(nsrc
);
3437 rc
= GPG_ERR_ENOMEM
;
3442 ndst
= create_element_path(client
, &dst
, &rc
);
3446 xmlFreeNodeList(new);
3450 /* Merge any attributes from the src node to the initial dst node. */
3451 for (xmlAttrPtr attr
= new->properties
; attr
; attr
= attr
->next
) {
3452 if ((!src
[1] || !dst
[1]) && xmlStrEqual(attr
->name
, (xmlChar
*)"name"))
3455 xmlAttrPtr a
= xmlHasProp(ndst
, attr
->name
);
3460 xmlNewProp(ndst
, attr
->name
, attr
->children
->content
);
3463 xmlNodePtr n
= ndst
->children
;
3464 xmlUnlinkNode(ndst
->children
);
3466 n
= xmlCopyNodeList(new->children
);
3467 xmlFreeNodeList(new);
3468 ndst
->children
= NULL
;
3469 xmlAddChild(ndst
, n
);
3481 return send_error(ctx
, rc
);
3484 static int ls_command(assuan_context_t ctx
, gchar
*line
)
3486 log_write2("ARGS=\"%s\"", line
);
3488 gchar
*tmp
= g_key_file_get_string(keyfileh
, "global", "data_directory", NULL
);
3489 gchar
*dir
= expand_homedir(tmp
);
3490 DIR *d
= opendir(dir
);
3497 return send_syserror(ctx
, n
);
3500 size_t len
= offsetof(struct dirent
, d_name
)+pathconf(dir
, _PC_NAME_MAX
)+1;
3501 struct dirent
*p
= g_malloc(len
), *cur
= NULL
;
3507 while (!readdir_r(d
, p
, &cur
) && cur
) {
3508 if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '\0')
3510 else if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '.' && cur
->d_name
[2] == '\0')
3513 tmp
= g_strdup_printf("%s%s\n", list
? list
: "", cur
->d_name
);
3519 rc
= GPG_ERR_ENOMEM
;
3531 return send_error(ctx
, rc
);
3534 return send_error(ctx
, GPG_ERR_NO_VALUE
);
3536 list
[strlen(list
)-1] = 0;
3537 rc
= xfer_data(ctx
, list
, strlen(list
));
3539 return send_error(ctx
, rc
);
3542 static void bye_notify(assuan_context_t ctx
)
3544 struct client_s
*cl
= assuan_get_pointer(ctx
);
3546 /* This will let assuan_process_next() return. */
3547 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
3550 static void reset_notify(assuan_context_t ctx
)
3552 struct client_s
*cl
= assuan_get_pointer(ctx
);
3559 * This is called before every Assuan command.
3561 gint
command_startup(assuan_context_t ctx
, const gchar
*name
)
3563 struct client_s
*cl
= assuan_get_pointer(ctx
);
3566 log_write1("%s", name
);
3568 if (!g_ascii_strcasecmp(name
, "ISCACHED") ||
3569 !g_ascii_strcasecmp(name
, "CLEARCACHE") ||
3570 !g_ascii_strcasecmp(name
, "CACHETIMEOUT") ||
3571 !g_ascii_strcasecmp(name
, "GETCONFIG") ||
3572 !g_ascii_strcasecmp(name
, "GETPID") ||
3573 !g_ascii_strcasecmp(name
, "VERSION") ||
3574 !g_ascii_strcasecmp(name
, "SET") ||
3575 !g_ascii_strcasecmp(name
, "BYE") ||
3576 !g_ascii_strcasecmp(name
, "NOP") ||
3577 !g_ascii_strcasecmp(name
, "CANCEL") ||
3578 !g_ascii_strcasecmp(name
, "RESET") ||
3579 !g_ascii_strcasecmp(name
, "END") ||
3580 !g_ascii_strcasecmp(name
, "HELP") ||
3581 !g_ascii_strcasecmp(name
, "OPTION") ||
3582 !g_ascii_strcasecmp(name
, "INPUT") ||
3583 !g_ascii_strcasecmp(name
, "OUTPUT") ||
3584 !g_ascii_strcasecmp(name
, "LS") ||
3585 !g_ascii_strcasecmp(name
, "UNSET"))
3588 cl
->last_rc
= rc
= file_modified(cl
);
3591 if ((rc
== EPWMD_NO_FILE
|| rc
== EPWMD_FILE_MODIFIED
) &&
3592 !g_ascii_strcasecmp(name
, "OPEN"))
3600 * This is called after every Assuan command.
3602 void command_finalize(assuan_context_t ctx
, gint rc
)
3604 struct client_s
*client
= assuan_get_pointer(ctx
);
3606 if (!client
->is_lock_cmd
)
3607 unlock_file_mutex(client
);
3609 log_write1(N_("command completed (rc=%u)"), client
->last_rc
);
3612 gpg_error_t
register_commands(assuan_context_t ctx
)
3616 gint (*handler
)(assuan_context_t
, gchar
*line
);
3618 { "OPEN", open_command
},
3619 { "SAVE", save_command
},
3620 { "LIST", list_command
},
3621 { "REALPATH", realpath_command
},
3622 { "STORE", store_command
},
3623 { "DELETE", delete_command
},
3624 { "GET", get_command
},
3625 { "ATTR", attr_command
},
3626 { "ISCACHED", iscached_command
},
3627 { "CLEARCACHE", clearcache_command
},
3628 { "CACHETIMEOUT", cachetimeout_command
},
3629 { "GETCONFIG", getconfig_command
},
3630 { "DUMP", dump_command
},
3631 { "XPATH", xpath_command
},
3632 { "XPATHATTR", xpathattr_command
},
3633 { "IMPORT", import_command
},
3634 { "LOCK", lock_command
},
3635 { "UNLOCK", unlock_command
},
3636 { "GETPID", getpid_command
},
3637 { "VERSION", version_command
},
3638 { "SET", set_command
},
3639 { "UNSET", unset_command
},
3640 { "RENAME", rename_command
},
3641 { "COPY", copy_command
},
3642 { "LS", ls_command
},
3649 for (i
=0; table
[i
].name
; i
++) {
3650 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
3656 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
3661 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
3666 rc
= assuan_register_pre_cmd_notify(ctx
, command_startup
);
3671 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
3674 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
,
3675 struct client_crypto_s
*crypto
, gpointer
*dst
, goffset
*dst_len
)
3677 goffset insize
, len
;
3678 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
3679 guint64 iter
= 0ULL, n_iter
= 0ULL, iter_progress
= 0ULL;
3683 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->ver
.fh1
) : sizeof(crypto
->fh
->ver
.fh2
);
3684 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->ver
.fh1
.iter
: crypto
->fh
->ver
.fh2
.iter
;
3685 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
3687 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
3688 insize
= crypto
->fh
->st
.st_size
- fh_size
;
3689 crypto
->iv
= gcry_malloc(crypto
->blocksize
);
3692 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3693 return gpg_error_from_errno(ENOMEM
);
3697 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh1
.iv
, crypto
->blocksize
);
3699 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
3701 crypto
->inbuf
= gcry_malloc(insize
);
3703 if (!crypto
->inbuf
) {
3704 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3705 return gpg_error_from_errno(ENOMEM
);
3708 crypto
->insize
= insize
;
3709 len
= pth_read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
3711 if (len
!= crypto
->insize
)
3712 return GPG_ERR_INV_LENGTH
;
3714 /* No encryption iterations. This is a plain (gzipped) file. */
3715 if ((crypto
->fh
->v1
&& (long)fh_iter
< 0L) ||
3716 (!crypto
->fh
->v1
&& fh_iter
<= 0L)) {
3718 * cache_file_count() needs both .used == TRUE and a valid key in
3719 * order for it to count as a used cache entry. Fixes CACHE status
3722 memset(crypto
->key
, '!', hashlen
);
3726 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
3727 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3731 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
3732 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3736 iter_progress
= (guint64
)get_key_file_double(client
&& client
->filename
?
3737 client
->filename
: "global", "iteration_progress");
3739 if (iter_progress
> 0ULL && fh_iter
>= iter_progress
) {
3740 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
3746 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3751 crypto
->tkey
= gcry_malloc(hashlen
);
3753 if (!crypto
->tkey
) {
3754 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
3755 return gpg_error_from_errno(ENOMEM
);
3758 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
3759 guchar
*tkey
= crypto
->tkey
;
3762 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
3763 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3767 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
3768 if (iter_progress
> 0ULL && iter
>= iter_progress
) {
3769 if (!(iter
% iter_progress
)) {
3770 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
3771 ++n_iter
* iter_progress
, fh_iter
);
3778 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
3779 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3783 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3786 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3793 if (iter_progress
&& fh_iter
>= iter_progress
) {
3794 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
3801 if (do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
3802 (gpointer
*)&crypto
->outbuf
, &outsize
, &zrc
) == FALSE
) {
3803 if (zrc
== Z_MEM_ERROR
)
3804 return gpg_error_from_errno(ENOMEM
);
3806 return EPWMD_BADKEY
; // Not a valid gzip header. Must be a bad key.
3809 if (g_strncasecmp(crypto
->outbuf
, "<?xml ", 6) != 0) {
3810 gcry_free(crypto
->outbuf
);
3811 crypto
->outbuf
= NULL
;
3812 return EPWMD_BADKEY
;
3816 client
->xml
= crypto
->outbuf
;
3817 client
->len
= outsize
;
3818 crypto
->outbuf
= NULL
;
3821 *dst
= crypto
->outbuf
;
3823 crypto
->outbuf
= NULL
;
3826 /* The calling function should free the crypto struct. */