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"
57 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
59 return gcry_calloc(items
, size
);
62 static void z_free(void *data
, void *p
)
67 static gpg_error_t
file_modified(struct client_s
*client
)
72 if (client
->state
!= STATE_OPEN
)
75 rc
= lock_file_mutex(client
);
80 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
81 if (client
->mtime
!= st
.st_mtime
)
82 return EPWMD_FILE_MODIFIED
;
89 static gpg_error_t
parse_xml(assuan_context_t ctx
)
91 struct client_s
*client
= assuan_get_pointer(ctx
);
93 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
96 return EPWMD_LIBXML_ERROR
;
101 void unlock_file_mutex(struct client_s
*client
)
106 if (client
->has_lock
== FALSE
|| client
->pinentry
->status
!= PINENTRY_NONE
)
108 if (client
->has_lock
== FALSE
)
112 CACHE_LOCK(client
->ctx
);
114 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
121 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
124 gpg_error_t
lock_file_mutex(struct client_s
*client
)
129 if (client
->has_lock
== TRUE
)
132 CACHE_LOCK(client
->ctx
);
134 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
140 MUTEX_TRYLOCK(client
->ctx
, m
, rc
);
143 client
->has_lock
= TRUE
;
148 void free_client(struct client_s
*client
)
151 xmlFreeDoc(client
->doc
);
154 gcry_free(client
->xml
);
156 if (client
->filename
)
157 g_free(client
->filename
);
160 cleanup_crypto(&client
->crypto
);
162 if (client
->xml_error
)
163 xmlResetError(client
->xml_error
);
166 void cleanup_client(struct client_s
*client
)
168 assuan_context_t ctx
= client
->ctx
;
169 struct client_thread_s
*thd
= client
->thd
;
170 gboolean has_lock
= client
->has_lock
;
172 struct pinentry_s
*pin
= client
->pinentry
;
175 unlock_file_mutex(client
);
176 CACHE_LOCK(client
->ctx
);
177 cache_decr_refcount(client
->md5file
);
180 * This may be a new file so don't use a cache slot. save_command() will
181 * set this to FALSE on success.
183 if (client
->new == TRUE
)
184 cache_clear(client
->md5file
, 1);
188 memset(client
, 0, sizeof(struct client_s
));
189 client
->state
= STATE_CONNECTED
;
192 client
->freed
= TRUE
;
194 client
->pinentry
= pin
;
196 client
->has_lock
= has_lock
;
199 static void gz_cleanup(void *arg
)
201 struct gz_s
**gz
= (struct gz_s
**)arg
;
206 if (!(*gz
)->done
&& (*gz
)->out
)
207 gcry_free((*gz
)->out
);
210 if ((*gz
)->which
== STATUS_COMPRESS
) {
212 deflateEnd(&(*gz
)->z
);
216 inflateEnd(&(*gz
)->z
);
223 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
224 gpointer
*out
, gulong
*outsize
, gint
*rc
)
230 gz
= g_malloc0(sizeof(struct gz_s
));
233 *rc
= gpg_error_from_errno(ENOMEM
);
237 gz
->which
= STATUS_DECOMPRESS
;
238 gz
->z
.zalloc
= z_alloc
;
239 gz
->z
.zfree
= z_free
;
241 gz
->z
.avail_in
= (uInt
)insize
;
242 gz
->z
.avail_out
= zlib_bufsize
;
243 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
246 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
252 *rc
= inflateInit2(&gz
->z
, 47);
255 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
260 memset(&h
, 0, sizeof(gz_header
));
261 h
.comment
= (guchar
*)buf
;
262 h
.comm_max
= sizeof(buf
);
263 *rc
= inflateGetHeader(&gz
->z
, &h
);
266 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
271 *rc
= inflate(&gz
->z
, Z_BLOCK
);
274 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
280 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
285 *rc
= inflate(&gz
->z
, Z_FINISH
);
291 if (!gz
->z
.avail_out
) {
292 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
295 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
301 gz
->z
.next_out
= gz
->out
+ gz
->z
.total_out
;
302 gz
->z
.avail_out
= zlib_bufsize
;
303 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
304 gz
->z
.total_out
, insize
);
316 } while (*rc
!= Z_STREAM_END
);
319 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
327 *outsize
= gz
->z
.total_out
;
334 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
339 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
344 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
350 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
351 *rc
= gpg_error_from_errno(ENOMEM
);
355 fh_size
= v1
? sizeof(fh
->fh1
) : sizeof(fh
->fh2
);
357 if (lstat(filename
, &fh
->st
) == -1) {
358 *rc
= gpg_error_from_syserror();
363 if (!S_ISREG(fh
->st
.st_mode
)) {
364 *rc
= GPG_ERR_ENOANO
;
369 fd
= open(filename
, O_RDONLY
);
372 *rc
= gpg_error_from_errno(errno
);
378 len
= pth_read(fd
, &fh
->fh1
, fh_size
);
380 len
= pth_read(fd
, &fh
->fh2
, fh_size
);
382 if (len
!= fh_size
) {
386 *rc
= gpg_error_from_errno(n
);
395 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*key
,
398 struct client_s
*client
= assuan_get_pointer(ctx
);
403 if (!client
->crypto
->fh
) {
410 rc
= try_xml_decrypt(ctx
, key
, client
->crypto
, NULL
, NULL
);
413 cleanup_client(client
);
414 return send_error(ctx
, rc
);
418 CACHE_LOCK(client
->ctx
);
420 if (cached
== FALSE
) {
421 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
422 cleanup_client(client
);
424 return send_syserror(ctx
, ENOMEM
);
427 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
428 cache_reset_timeout(client
->md5file
, timeout
);
431 cache_set_timeout(client
->md5file
, -2);
439 gcry_free(client
->xml
);
444 if (client
->new == FALSE
)
445 send_status_all(STATUS_CACHE
);
447 client
->state
= STATE_OPEN
;
450 if (!rc
&& client
->new == FALSE
&&
451 client
->crypto
->fh
->fh2
.iter
!= (guint64
)get_key_file_integer(client
->filename
, "iterations")) {
452 MUTEX_LOCK(&rcfile_mutex
);
453 g_key_file_set_integer(keyfileh
, client
->filename
, "iterations",
454 client
->crypto
->fh
->fh2
.iter
);
455 MUTEX_UNLOCK(&rcfile_mutex
);
456 send_status_all(STATUS_CONFIG
);
460 log_write("OPEN '%s'", client
->filename
);
462 cleanup_crypto(&client
->crypto
);
463 return send_error(ctx
, rc
);
466 static void req_cleanup(void *arg
)
471 g_strfreev((gchar
**)arg
);
474 static int open_command(assuan_context_t ctx
, char *line
)
476 gboolean cached
= FALSE
;
478 struct client_s
*client
= assuan_get_pointer(ctx
);
480 gchar
*filename
= NULL
;
482 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
485 if (!filename
|| !*filename
) {
487 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
490 if (valid_filename(filename
) == FALSE
) {
492 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
495 if (client
->state
== STATE_OPEN
)
496 cleanup_client(client
);
498 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
499 CACHE_LOCK(client
->ctx
);
501 if (cache_has_file(client
->md5file
) == FALSE
) {
502 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
505 return send_syserror(ctx
, ENOMEM
);
509 cache_incr_refcount(client
->md5file
);
511 rc
= lock_file_mutex(client
);
515 return send_error(ctx
, rc
);
518 client
->freed
= FALSE
;
519 client
->crypto
= init_client_crypto();
521 if (!client
->crypto
) {
523 cleanup_client(client
);
524 return send_syserror(ctx
, ENOMEM
);
527 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
529 if (!client
->crypto
->key
) {
531 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
532 gpg_error_from_errno(ENOMEM
));
533 cleanup_client(client
);
534 return send_syserror(ctx
, ENOMEM
);
537 memset(client
->crypto
->key
, 0, gcrykeysize
);
538 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
541 if (!client
->crypto
->fh
) {
542 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
543 log_write("%s: %s", filename
, pwmd_strerror(rc
));
545 cleanup_client(client
);
546 return send_error(ctx
, rc
);
550 * New files don't need a key.
552 if ((client
->xml
= new_document()) == NULL
) {
553 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
555 cleanup_client(client
);
556 return send_syserror(ctx
, ENOMEM
);
559 client
->len
= xmlStrlen(client
->xml
);
561 client
->filename
= g_strdup(filename
);
563 if (!client
->filename
) {
565 cleanup_client(client
);
566 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
567 return send_syserror(ctx
, ENOMEM
);
570 if (req
[1] && *req
[1])
571 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
576 client
->pinentry
->filename
= g_strdup(client
->filename
);
578 if (!client
->pinentry
->filename
) {
579 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
580 cleanup_client(client
);
581 return send_syserror(ctx
, ENOMEM
);
584 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
587 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
589 client
->filename
= g_strdup(filename
);
591 if (!client
->filename
) {
592 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
594 cleanup_client(client
);
595 return send_syserror(ctx
, ENOMEM
);
599 client
->pinentry
->filename
= g_strdup(client
->filename
);
601 if (!client
->pinentry
->filename
) {
602 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
604 cleanup_client(client
);
605 return send_syserror(ctx
, ENOMEM
);
609 if (client
->crypto
->fh
->fh2
.iter
<= 0)
612 CACHE_LOCK(client
->ctx
);
613 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
616 if (cached
== FALSE
) {
617 gchar
*tmp
= get_key_file_string(filename
, "key_file");
621 cleanup_client(client
);
622 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
626 * No key specified and no matching filename found in the cache. Use
627 * pinentry to retrieve the key. Cannot return assuan_process_done()
628 * here otherwise the command will be interrupted. The event loop in
629 * client_thread() will poll the file descriptor waiting for it to
630 * become ready to read a pinentry_key_s which will contain the
631 * entered key or an error code. It will then call
632 * open_command_finalize() to to finish the command.
634 if (!req
[1] || !*req
[1]) {
636 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
638 /* From set_pinentry_defaults(). */
639 if (client
->pinentry
->enable
== FALSE
||
640 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
641 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
646 rc
= lock_pin_mutex(client
);
649 unlock_pin_mutex(client
->pinentry
);
650 cleanup_client(client
);
651 return send_error(ctx
, rc
);
654 client
->pinentry
->which
= PINENTRY_OPEN
;
655 rc
= pinentry_fork(ctx
);
658 unlock_pin_mutex(client
->pinentry
);
659 cleanup_client(client
);
660 return send_error(ctx
, rc
);
663 // Called from pinentry iterate.
664 client
->pinentry
->cb
= open_command_finalize
;
665 client
->pinentry
->status
= PINENTRY_INIT
;
668 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
673 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
679 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
682 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
683 gulong size
, gpointer
*out
, gulong
*outsize
, gint
*rc
)
688 gint cmd
= Z_NO_FLUSH
;
690 gz
= g_malloc0(sizeof(struct gz_s
));
693 *rc
= gpg_error_from_errno(ENOMEM
);
697 gz
->which
= STATUS_COMPRESS
;
698 gz
->z
.zalloc
= z_alloc
;
699 gz
->z
.zfree
= z_free
;
700 gz
->z
.next_in
= data
;
701 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
702 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
703 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
706 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
712 *rc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
715 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
720 /* Rather than store the size of the uncompressed data in the file header,
721 * store it in the comment field of the gzip header. Don't give anyone too
722 * much information. Not sure why really, but it seems the right way. :)
724 memset(&h
, 0, sizeof(gz_header
));
725 g_snprintf(buf
, sizeof(buf
), "%li", size
);
726 h
.comment
= (guchar
*)buf
;
727 *rc
= deflateSetHeader(&gz
->z
, &h
);
730 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
738 *rc
= deflate(&gz
->z
, cmd
);
744 if (!gz
->z
.avail_out
) {
745 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
748 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
754 gz
->z
.next_out
= gz
->out
+ gz
->z
.total_out
;
755 gz
->z
.avail_out
= zlib_bufsize
;
758 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
759 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
760 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
762 gz
->z
.avail_in
= zlib_bufsize
;
764 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li",
765 gz
->z
.total_in
, size
);
771 if (gz
->z
.total_in
>= size
)
780 } while (*rc
!= Z_STREAM_END
);
783 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li", gz
->z
.total_in
, size
);
790 *outsize
= gz
->z
.total_out
;
797 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
802 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
804 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
805 struct client_crypto_s
*crypto
, status_msg_t which
)
808 goffset len
= CRYPTO_BLOCKSIZE
;
809 gpointer p
= gcry_malloc(len
);
814 return gpg_err_code_from_errno(ENOMEM
);
816 if (crypto
->insize
< CRYPTO_BLOCKSIZE
)
817 len
= crypto
->insize
;
820 inbuf
= crypto
->inbuf
+ total
;
823 if (len
+ total
> crypto
->insize
)
826 if (which
== STATUS_ENCRYPT
)
827 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
829 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
834 tmp
= crypto
->inbuf
+total
;
835 memmove(tmp
, p
, len
);
838 if (total
>= crypto
->insize
)
849 /* The crypto struct must be setup for iterations and .key. */
850 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
851 struct client_crypto_s
*crypto
, const gchar
*filename
)
853 goffset len
= crypto
->insize
;
857 guint64 iter_progress
= 0, n_iter
= 0, xiter
= 0;
858 gchar tmp
[FILENAME_MAX
];
862 if (!crypto
->fh
->fh2
.iter
) {
864 * cache_file_count() needs both .used == TRUE and a valid key in
865 * order for it to count as a used cache entry. Fixes CACHE status
868 memset(crypto
->key
, '!', gcrykeysize
);
873 * Resize the existing xml buffer to the block size required by gcrypt
874 * rather than duplicating it and wasting memory.
876 if (crypto
->insize
/ gcryblocksize
) {
877 len
= (crypto
->insize
/ gcryblocksize
) * gcryblocksize
;
879 if (crypto
->insize
% gcryblocksize
)
880 len
+= gcryblocksize
;
883 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
886 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
887 return gpg_error_from_errno(ENOMEM
);
890 crypto
->inbuf
= inbuf
;
891 crypto
->insize
= len
;
892 gcry_create_nonce(crypto
->fh
->fh2
.iv
, sizeof(crypto
->fh
->fh2
.iv
));
893 crypto
->tkey
= gcry_malloc(gcrykeysize
);
896 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
897 return gpg_error_from_errno(ENOMEM
);
900 memcpy(crypto
->tkey
, crypto
->key
, gcrykeysize
);
901 guchar
*tkey
= crypto
->tkey
;
904 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
905 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
909 iter_progress
= (guint64
)get_key_file_integer(
910 client
? client
->filename
: "global", "iteration_progress");
912 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
913 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
914 "0 %llu", crypto
->fh
->fh2
.iter
);
921 while (xiter
< crypto
->fh
->fh2
.iter
-1) {
922 if (iter_progress
> 0 && xiter
>= iter_progress
) {
923 if (!(xiter
% iter_progress
)) {
924 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
925 "%llu %llu", ++n_iter
* iter_progress
,
926 crypto
->fh
->fh2
.iter
);
934 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
935 sizeof(crypto
->fh
->fh2
.iv
)))) {
936 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
940 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
943 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
950 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
951 sizeof(crypto
->fh
->fh2
.iv
)))) {
952 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
956 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, gcrykeysize
))) {
957 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
961 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
966 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
967 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
968 "%llu %llu", crypto
->fh
->fh2
.iter
, crypto
->fh
->fh2
.iter
);
977 if (!client
&& !strcmp(filename
, "-")) {
978 crypto
->fh
->fd
= STDOUT_FILENO
;
982 if (lstat(filename
, &st
) == 0) {
984 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
987 * FIXME What if the file has an ACL?
989 if (!(mode
& S_IWUSR
))
990 return gpg_error_from_errno(EACCES
);
995 return gpg_error_from_errno(errno
);
998 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
999 crypto
->fh
->fd
= mkstemp(tmp
);
1001 if (crypto
->fh
->fd
== -1) {
1003 p
= strrchr(tmp
, '/');
1005 log_write("%s: %s", p
, strerror(rc
));
1006 return gpg_error_from_errno(rc
);
1011 * xml_import() or convert_file() from command line.
1013 crypto
->fh
->fd
= STDOUT_FILENO
;
1016 crypto
->fh
->fh2
.version
= VERSION_HEX
;
1017 len
= pth_write(crypto
->fh
->fd
, &crypto
->fh
->fh2
, sizeof(crypto
->fh
->fh2
));
1020 if (len
!= sizeof(crypto
->fh
->fh2
)) {
1023 if (filename
&& strcmp(filename
, "-"))
1026 return gpg_error_from_errno(len
);
1029 len
= pth_write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1032 if (len
!= crypto
->insize
) {
1036 if (filename
&& strcmp(filename
, "-")) {
1041 return gpg_error_from_errno(len
);
1044 if (fsync(crypto
->fh
->fd
) == -1) {
1048 if (filename
&& strcmp(filename
, "-"))
1051 return gpg_error_from_errno(len
);
1054 if (filename
&& strcmp(filename
, "-")) {
1055 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1056 gchar tmp2
[FILENAME_MAX
];
1058 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1060 if (rename(filename
, tmp2
) == -1) {
1064 return gpg_error_from_errno(len
);
1068 if (rename(tmp
, filename
) == -1) {
1072 return gpg_error_from_errno(len
);
1076 chmod(filename
, mode
);
1081 if (client
&& lstat(filename
, &st
) == 0)
1082 client
->mtime
= st
.st_mtime
;
1088 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1091 struct client_s
*client
= assuan_get_pointer(ctx
);
1093 gulong len
, outsize
= 0;
1100 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1101 gcry_free(client
->crypto
->key
);
1103 client
->crypto
->key
= key
;
1104 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1105 iter
= (guint
)get_key_file_integer(client
->filename
, "compression_level");
1110 if (do_compress(ctx
, (gint
)iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
)
1113 cleanup_crypto(&client
->crypto
);
1115 if (zrc
== Z_MEM_ERROR
)
1116 return send_syserror(ctx
, ENOMEM
);
1118 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1126 client
->crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1128 if (!client
->crypto
->fh
) {
1129 cleanup_crypto(&client
->crypto
);
1131 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1132 return send_syserror(ctx
, ENOMEM
);
1135 iter
= get_key_file_integer(client
->filename
, "iterations");
1136 client
->crypto
->fh
->fh2
.iter
= iter
< 0 ? 0 : iter
;
1137 client
->crypto
->inbuf
= xmlbuf
;
1138 client
->crypto
->insize
= len
;
1139 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1142 cleanup_crypto(&client
->crypto
);
1143 return send_error(ctx
, rc
);
1146 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1147 CACHE_LOCK(client
->ctx
);
1150 cache_reset_timeout(client
->md5file
, timeout
);
1153 if (client
->new == TRUE
)
1154 send_status_all(STATUS_CACHE
);
1156 client
->new = FALSE
;
1157 cleanup_crypto(&client
->crypto
);
1158 return send_error(ctx
, 0);
1161 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1163 cleanup_crypto(&client
->crypto
);
1164 return send_syserror(ctx
, ENOMEM
);
1167 client
->new = FALSE
;
1168 cache_reset_timeout(client
->md5file
, timeout
);
1170 send_status_all(STATUS_CACHE
);
1171 cleanup_crypto(&client
->crypto
);
1172 return send_error(ctx
, 0);
1175 static int save_command(assuan_context_t ctx
, char *line
)
1177 gboolean cached
= FALSE
;
1179 struct client_s
*client
= assuan_get_pointer(ctx
);
1182 rc
= lock_file_mutex(client
);
1185 return send_error(ctx
, rc
);
1187 rc
= file_modified(client
);
1190 return send_error(ctx
, rc
);
1192 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1193 return send_syserror(ctx
, errno
);
1195 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1196 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1197 return send_error(ctx
, GPG_ERR_ENOANO
);
1201 cached
= cache_iscached(client
->md5file
);
1205 * If a cache entry doesn't exist for this file and the file has a
1206 * "key_file" or "key" parameter, then it's an error. The reason is that
1207 * cache expiration would be useless.
1209 if (cached
== FALSE
) {
1210 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1214 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1219 client
->crypto
= init_client_crypto();
1221 if (!client
->crypto
) {
1222 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1223 return send_syserror(ctx
, ENOMEM
);
1226 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
1228 if (!client
->crypto
->key
) {
1229 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1230 cleanup_crypto(&client
->crypto
);
1231 return send_syserror(ctx
, ENOMEM
);
1234 memset(client
->crypto
->key
, '!', gcrykeysize
);
1236 if (get_key_file_integer(client
->filename
, "iterations") <= 0)
1239 if (!line
|| !*line
) {
1240 client
->crypto
->tkey
= gcry_malloc(gcrykeysize
);
1242 if (!client
->crypto
->tkey
) {
1243 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1244 cleanup_crypto(&client
->crypto
);
1245 return send_syserror(ctx
, ENOMEM
);
1248 memset(client
->crypto
->tkey
, '!', gcrykeysize
);
1251 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1252 memcmp(client
->crypto
->key
, client
->crypto
->tkey
,
1253 gcrykeysize
) == 0) {
1256 #ifdef WITH_PINENTRY
1257 if (client
->pinentry
->enable
== FALSE
||
1258 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1259 /* Empty keys are allowed. */
1260 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1264 lock_pin_mutex(client
);
1265 client
->pinentry
->which
= PINENTRY_SAVE
;
1266 rc
= pinentry_fork(ctx
);
1269 unlock_pin_mutex(client
->pinentry
);
1270 return send_error(ctx
, rc
);
1273 client
->pinentry
->cb
= save_command_finalize
;
1274 client
->pinentry
->status
= PINENTRY_INIT
;
1277 /* Empty keys are allowed. */
1278 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1288 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, line
,
1290 memset(line
, 0, strlen(line
));
1294 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1297 static int delete_command(assuan_context_t ctx
, char *line
)
1299 struct client_s
*client
= assuan_get_pointer(ctx
);
1304 rc
= file_modified(client
);
1307 return send_error(ctx
, rc
);
1309 if (strchr(line
, '\t'))
1310 req
= split_input_line(line
, "\t", -1);
1312 req
= split_input_line(line
, " ", -1);
1315 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1317 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1321 return send_error(ctx
, rc
);
1325 * No sub-node defined. Remove the entire node (account).
1334 return send_error(ctx
, 0);
1337 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1341 return send_error(ctx
, rc
);
1348 return send_error(ctx
, 0);
1352 * Don't return with assuan_process_done() here. This has been called from
1353 * assuan_process_next() and the command should be finished in
1356 static int store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1359 assuan_context_t ctx
= data
;
1360 struct client_s
*client
= assuan_get_pointer(ctx
);
1363 gpg_error_t rc
= file_modified(client
);
1365 if (assuan_rc
|| rc
) {
1368 return assuan_rc
? assuan_rc
: rc
;
1371 req
= split_input_line((gchar
*)line
, "\t", 0);
1375 return EPWMD_COMMAND_SYNTAX
;
1377 if (valid_xml_element((xmlChar
*)*req
) == FALSE
) {
1379 return EPWMD_INVALID_ELEMENT
;
1382 if (valid_element_path(req
+1, TRUE
) == FALSE
) {
1384 return EPWMD_INVALID_ELEMENT
;
1388 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1390 if (rc
&& rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1391 rc
= new_account(client
->doc
, *req
);
1408 create_elements_cb(n
, req
+1, &rc
, NULL
);
1410 find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1411 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
);
1415 client
->inquire_status
= INQUIRE_DONE
;
1419 static int store_command(assuan_context_t ctx
, char *line
)
1421 struct client_s
*client
= assuan_get_pointer(ctx
);
1422 gpg_error_t rc
= file_modified(client
);
1425 return send_error(ctx
, rc
);
1428 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1432 return send_error(ctx
, rc
);
1434 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1435 client
->inquire_status
= INQUIRE_BUSY
;
1439 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
1446 if (total
< ASSUAN_LINELENGTH
)
1449 to_send
= ASSUAN_LINELENGTH
;
1452 if (sent
+ to_send
> total
)
1453 to_send
= total
- sent
;
1455 rc
= assuan_send_data(ctx
, line
+sent
, to_send
);
1459 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1461 } while (!rc
&& sent
< total
);
1466 static int get_command(assuan_context_t ctx
, char *line
)
1468 struct client_s
*client
= assuan_get_pointer(ctx
);
1473 rc
= file_modified(client
);
1476 return send_error(ctx
, rc
);
1478 req
= split_input_line(line
, "\t", -1);
1480 if (!req
|| !*req
) {
1482 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1485 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1489 return send_error(ctx
, rc
);
1493 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1498 return send_error(ctx
, rc
);
1500 if (!n
|| !n
->children
)
1501 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1503 n
= find_text_node(n
->children
);
1505 if (!n
|| !n
->content
|| !*n
->content
)
1506 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1509 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
1510 return send_error(ctx
, rc
);
1513 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
1514 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
1516 gchar
*path
= *(gchar
**)data
;
1517 gchar
*tmp
= NULL
, *result
;
1521 *(gchar
**)data
= NULL
;
1524 path
= g_strjoinv("\t", target
);
1527 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1528 *rc
= gpg_error_from_errno(ENOMEM
);
1533 tmp
= g_strjoinv("\t", req_orig
);
1537 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1538 *rc
= gpg_error_from_errno(ENOMEM
);
1544 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1546 result
= g_strdup(path
);
1549 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1550 *rc
= gpg_error_from_errno(ENOMEM
);
1558 *(gchar
**)data
= result
;
1562 static void list_command_cleanup1(void *arg
);
1563 static int realpath_command(assuan_context_t ctx
, char *line
)
1566 struct client_s
*client
= assuan_get_pointer(ctx
);
1574 rc
= file_modified(client
);
1577 return send_error(ctx
, rc
);
1579 if (strchr(line
, '\t') != NULL
) {
1580 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1581 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1584 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1585 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1588 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1592 return send_error(ctx
, rc
);
1595 rp
= g_strjoinv("\t", req
);
1599 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1600 return send_syserror(ctx
, ENOMEM
);
1604 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1605 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
);
1610 return send_error(ctx
, rc
);
1614 string
= g_string_new(rp
);
1619 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1620 return send_syserror(ctx
, ENOMEM
);
1624 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
1625 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
1626 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1631 rc
= assuan_send_data(ctx
, string
->str
, string
->len
);
1632 list_command_cleanup1(string
);
1633 return send_error(ctx
, rc
);
1636 static void list_command_cleanup1(void *arg
)
1638 g_string_free((GString
*)arg
, TRUE
);
1641 static void list_command_cleanup2(void *arg
)
1643 struct element_list_s
*elements
= arg
;
1646 gint total
= g_slist_length(elements
->list
);
1649 for (i
= 0; i
< total
; i
++) {
1650 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
1654 g_slist_free(elements
->list
);
1656 if (elements
->prefix
)
1657 g_free(elements
->prefix
);
1663 static int list_command(assuan_context_t ctx
, char *line
)
1665 struct client_s
*client
= assuan_get_pointer(ctx
);
1667 struct element_list_s
*elements
= NULL
;
1670 if (disable_list_and_dump
== TRUE
)
1671 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1673 rc
= file_modified(client
);
1676 return send_error(ctx
, rc
);
1681 rc
= list_accounts(client
->doc
, &str
);
1684 return send_error(ctx
, rc
);
1686 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1687 list_command_cleanup1(str
);
1688 return send_error(ctx
, rc
);
1691 elements
= g_malloc0(sizeof(struct element_list_s
));
1694 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1695 rc
= gpg_err_code_from_errno(ENOMEM
);
1699 rc
= create_path_list(client
->doc
, elements
, line
);
1705 gint total
= g_slist_length(elements
->list
);
1710 rc
= EPWMD_EMPTY_ELEMENT
;
1714 str
= g_string_new(NULL
);
1717 rc
= gpg_err_code_from_errno(ENOMEM
);
1718 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1722 for (i
= 0; i
< total
; i
++) {
1723 tmp
= g_slist_nth_data(elements
->list
, i
);
1724 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
1727 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1728 list_command_cleanup1(str
);
1731 rc
= EPWMD_EMPTY_ELEMENT
;
1734 list_command_cleanup2(elements
);
1735 return send_error(ctx
, rc
);
1738 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1743 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1744 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1747 return EPWMD_LIBXML_ERROR
;
1750 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1756 * req[0] - element path
1758 static int attribute_list(assuan_context_t ctx
, gchar
**req
)
1760 struct client_s
*client
= assuan_get_pointer(ctx
);
1761 gchar
**attrlist
= NULL
;
1763 gchar
**path
= NULL
;
1769 if (!req
|| !req
[0])
1770 return EPWMD_COMMAND_SYNTAX
;
1772 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1774 * The first argument may be only an account.
1776 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1777 return EPWMD_COMMAND_SYNTAX
;
1780 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1788 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1789 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1799 for (a
= n
->properties
; a
; a
= a
->next
) {
1802 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1804 g_strfreev(attrlist
);
1806 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1807 return gpg_error_from_errno(ENOMEM
);
1812 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1815 g_strfreev(attrlist
);
1816 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1817 return gpg_error_from_errno(ENOMEM
);
1820 attrlist
[++i
] = NULL
;
1824 return EPWMD_EMPTY_ELEMENT
;
1826 line
= g_strjoinv("\n", attrlist
);
1829 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1830 g_strfreev(attrlist
);
1831 return gpg_error_from_errno(ENOMEM
);
1834 rc
= assuan_send_data(ctx
, line
, strlen(line
));
1836 req_cleanup(attrlist
);
1841 * req[0] - attribute
1842 * req[1] - element path
1844 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1848 gchar
**path
= NULL
;
1851 if (!req
|| !req
[0] || !req
[1])
1852 return EPWMD_COMMAND_SYNTAX
;
1854 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1856 * The first argument may be only an account.
1858 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1859 return EPWMD_COMMAND_SYNTAX
;
1863 * Don't remove the "name" attribute for the account element. To remove an
1864 * account use DELETE <account>.
1866 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
1867 rc
= EPWMD_ATTR_SYNTAX
;
1871 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1877 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1878 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1886 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
1887 return EPWMD_ATTR_NOT_FOUND
;
1889 if (xmlRemoveProp(a
) == -1)
1890 return EPWMD_LIBXML_ERROR
;
1899 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
1902 gchar
**src
= *path
;
1903 gchar
**src_orig
= g_strdupv(src
);
1904 xmlNodePtr n
= NULL
;
1909 *rc
= gpg_error_from_errno(ENOMEM
);
1910 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1915 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
1918 if (*rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1919 *rc
= new_account(client
->doc
, src
[0]);
1932 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
1934 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
1935 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
);
1941 * Reset the position of the element tree now that the elements
1942 * have been created.
1947 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
1952 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
1953 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1961 g_strfreev(src_orig
);
1968 * Creates a "target" attribute. When other commands encounter an element with
1969 * this attribute, the element path is modified to the target value. If the
1970 * source element path doesn't exist when using 'ATTR SET target', it is
1971 * created, but the destination element path must exist.
1973 * req[0] - source element path
1974 * req[1] - destination element path
1976 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
1978 gchar
**src
, **dst
, *line
= NULL
;
1982 if (!req
|| !req
[0] || !req
[1])
1983 return EPWMD_COMMAND_SYNTAX
;
1985 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1987 * The first argument may be only an account.
1989 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
1990 return EPWMD_COMMAND_SYNTAX
;
1993 if (valid_element_path(src
, FALSE
) == FALSE
) {
1995 return EPWMD_INVALID_ELEMENT
;
1998 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2000 * The first argument may be only an account.
2002 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2003 rc
= EPWMD_COMMAND_SYNTAX
;
2008 n
= find_account(client
->doc
, &dst
, &rc
, NULL
, 0);
2011 * Make sure the destination element path exists.
2017 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2018 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2024 n
= create_element_path(client
, &src
, &rc
);
2029 line
= g_strjoinv("\t", dst
);
2032 rc
= gpg_error_from_errno(ENOMEM
);
2033 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2037 rc
= add_attribute(n
, "target", line
);
2047 * req[0] - account name
2050 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2056 tmp
= g_strdupv(req
);
2059 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2060 return gpg_error_from_errno(ENOMEM
);
2063 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2069 if (g_utf8_collate(req
[0], req
[1]) == 0)
2073 * Will not overwrite an existing account.
2075 tmp
= g_strdupv(req
+1);
2078 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2079 return gpg_error_from_errno(ENOMEM
);
2082 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2085 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
2089 return EPWMD_ACCOUNT_EXISTS
;
2092 * Whitespace not allowed in account names.
2094 if (contains_whitespace(req
[1]) == TRUE
)
2095 return EPWMD_ATTR_SYNTAX
;
2097 tmp
= g_strdupv(req
);
2100 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2101 return gpg_error_from_errno(ENOMEM
);
2104 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2108 return EPWMD_ELEMENT_NOT_FOUND
;
2110 return add_attribute(n
, "name", req
[1]);
2114 * req[0] - attribute
2115 * req[1] - element path
2117 static int attribute_get(assuan_context_t ctx
, gchar
**req
)
2119 struct client_s
*client
= assuan_get_pointer(ctx
);
2125 if (!req
|| !req
[0] || !req
[1])
2126 return EPWMD_COMMAND_SYNTAX
;
2128 if (strchr(req
[1], '\t')) {
2129 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2130 return EPWMD_COMMAND_SYNTAX
;
2133 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2134 return EPWMD_COMMAND_SYNTAX
;
2137 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2143 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2144 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2152 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2153 return EPWMD_ATTR_NOT_FOUND
;
2155 rc
= assuan_send_data(ctx
, a
, xmlStrlen(a
));
2165 * req[0] - attribute
2166 * req[1] - element path
2169 static int attribute_set(struct client_s
*client
, gchar
**req
)
2171 gchar
**path
= NULL
;
2175 if (!req
|| !req
[0] || !req
[1] || !req
[2])
2176 return EPWMD_COMMAND_SYNTAX
;
2179 * Reserved attribute names.
2181 if (g_utf8_collate(req
[0], "name") == 0) {
2183 * Only reserved for the account element. Not the rest of the
2186 if (strchr(req
[1], '\t') == NULL
)
2187 return name_attribute(client
, req
+ 1);
2189 else if (g_utf8_collate(req
[0], "target") == 0)
2190 return target_attribute(client
, req
+ 1);
2192 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2194 * The first argument may be only an account.
2196 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2197 return EPWMD_COMMAND_SYNTAX
;
2200 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2206 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2207 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2214 return add_attribute(n
, req
[0], req
[2]);
2223 * req[1] - attribute name or element path if command is LIST
2224 * req[2] - element path
2225 * req[2] - element path or value
2227 static int attr_command(assuan_context_t ctx
, char *line
)
2229 struct client_s
*client
= assuan_get_pointer(ctx
);
2233 rc
= file_modified(client
);
2236 return send_error(ctx
, rc
);
2238 req
= split_input_line(line
, " ", 4);
2240 if (!req
|| !req
[0] || !req
[1]) {
2242 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2245 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2246 rc
= attribute_set(client
, req
+1);
2247 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2248 rc
= attribute_get(ctx
, req
+1);
2249 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2250 rc
= attribute_delete(client
, req
+1);
2251 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2252 rc
= attribute_list(ctx
, req
+1);
2254 rc
= EPWMD_COMMAND_SYNTAX
;
2257 return send_error(ctx
, rc
);
2260 static int iscached_command(assuan_context_t ctx
, char *line
)
2262 gchar
**req
= split_input_line(line
, " ", 0);
2266 if (!req
|| !*req
) {
2268 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2271 if (!valid_filename(req
[0])) {
2273 return EPWMD_INVALID_FILENAME
;
2276 tmp
= get_key_file_string("global", "data_directory");
2280 return gpg_error_from_errno(ENOMEM
);
2283 path
= expand_homedir(tmp
);
2288 return gpg_error_from_errno(ENOMEM
);
2293 path
= g_strdup_printf("%s/%s", tmp
, req
[0]);
2298 return gpg_error_from_errno(ENOMEM
);
2301 if (access(path
, R_OK
) == -1) {
2302 gpg_error_t rc
= gpg_error_from_syserror();
2306 return send_error(ctx
, rc
);
2310 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2314 if (cache_iscached(md5file
) == FALSE
) {
2316 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2320 return send_error(ctx
, 0);
2323 static int clearcache_command(assuan_context_t ctx
, char *line
)
2325 struct client_s
*client
= assuan_get_pointer(ctx
);
2326 gchar
**req
= split_input_line(line
, " ", 0);
2331 if (!req
|| !*req
) {
2333 cache_clear(client
->md5file
, 2);
2335 return send_error(ctx
, 0);
2338 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2341 if (cache_clear(md5file
, 1) == FALSE
) {
2343 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2347 return send_error(ctx
, 0);
2350 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2354 gchar
**req
= split_input_line(line
, " ", 0);
2357 if (!req
|| !*req
|| !req
[1]) {
2359 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2363 timeout
= strtol(req
[0], &p
, 10);
2365 if (errno
!= 0 || *p
!= 0) {
2367 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2370 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2371 CACHE_LOCK(client
->ctx
);
2373 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2375 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2379 return send_error(ctx
, 0);
2382 static int dump_command(assuan_context_t ctx
, char *line
)
2386 struct client_s
*client
= assuan_get_pointer(ctx
);
2389 if (disable_list_and_dump
== TRUE
)
2390 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2392 rc
= file_modified(client
);
2395 return send_error(ctx
, rc
);
2397 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2400 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2401 return send_syserror(ctx
, ENOMEM
);
2404 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
2406 return send_error(ctx
, rc
);
2409 static int getconfig_command(assuan_context_t ctx
, gchar
*line
)
2411 struct client_s
*client
= assuan_get_pointer(ctx
);
2413 gchar filename
[255]={0}, param
[747]={0};
2414 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2416 if (strchr(line
, ' ')) {
2417 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2422 if (fp
&& !valid_filename(fp
))
2423 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
2425 paramp
= g_ascii_strdown(paramp
, -1);
2428 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2429 return send_syserror(ctx
, ENOMEM
);
2432 p
= get_key_file_string(fp
? fp
: "global", paramp
);
2436 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2438 tmp
= expand_homedir(p
);
2442 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2443 return send_syserror(ctx
, ENOMEM
);
2447 rc
= assuan_send_data(ctx
, p
, strlen(p
));
2449 return send_error(ctx
, rc
);
2453 xmlXPathContextPtr xp
;
2454 xmlXPathObjectPtr result
;
2459 static void xpath_command_cleanup(void *arg
)
2461 struct xpath_s
*xpath
= arg
;
2463 req_cleanup(xpath
->req
);
2466 xmlBufferFree(xpath
->buf
);
2469 xmlXPathFreeObject(xpath
->result
);
2472 xmlXPathFreeContext(xpath
->xp
);
2475 static int xpath_command(assuan_context_t ctx
, gchar
*line
)
2477 struct client_s
*client
= assuan_get_pointer(ctx
);
2479 struct xpath_s xpath
;
2481 if (disable_list_and_dump
== TRUE
)
2482 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2484 rc
= file_modified(client
);
2487 return send_error(ctx
, rc
);
2489 if (!line
|| !*line
)
2490 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2492 memset(&xpath
, 0, sizeof(struct xpath_s
));
2494 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
2495 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
2496 return send_syserror(ctx
, ENOMEM
);
2499 xpath
.xp
= xmlXPathNewContext(client
->doc
);
2502 xpath_command_cleanup(&xpath
);
2503 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2506 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
2508 if (!xpath
.result
) {
2509 xpath_command_cleanup(&xpath
);
2510 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2513 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
2514 rc
= EPWMD_EMPTY_ELEMENT
;
2518 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
2519 (xmlChar
*)xpath
.req
[1], &xpath
.buf
);
2523 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
2524 rc
= EPWMD_EMPTY_ELEMENT
;
2527 else if (xpath
.req
[1])
2531 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
.buf
),
2532 xmlBufferLength(xpath
.buf
));
2535 xpath_command_cleanup(&xpath
);
2536 return send_error(ctx
, rc
);
2539 static int import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
2542 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
2543 gpg_error_t rc
= file_modified(client
);
2544 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
2546 xmlNodePtr n
, root
, copy
;
2548 if (assuan_rc
|| rc
) {
2551 return assuan_rc
? assuan_rc
: rc
;
2554 req
= split_input_line((gchar
*)line
, " ", 2);
2558 return EPWMD_COMMAND_SYNTAX
;
2560 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2561 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2562 return EPWMD_COMMAND_SYNTAX
;
2567 if (!content
|| !*content
) {
2568 rc
= EPWMD_COMMAND_SYNTAX
;
2572 if (valid_xml_element((xmlChar
*)*path
) == FALSE
) {
2573 rc
= EPWMD_INVALID_ELEMENT
;
2577 if (valid_element_path(path
+1, FALSE
) == FALSE
) {
2578 rc
= EPWMD_INVALID_ELEMENT
;
2582 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2585 rc
= EPWMD_LIBXML_ERROR
;
2589 root
= xmlDocGetRootElement(doc
);
2590 path_orig
= g_strdupv(path
);
2594 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2595 rc
= gpg_error_from_errno(ENOMEM
);
2599 if (strv_printf(&path
, "%s", (gchar
*)root
->name
) == FALSE
) {
2600 g_strfreev(path_orig
);
2602 rc
= gpg_error_from_errno(ENOMEM
);
2606 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2608 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2609 g_strfreev(path_orig
);
2614 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2616 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2617 g_strfreev(path_orig
);
2622 xmlNodePtr parent
= n
->parent
;
2633 if (rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2634 n
= create_element_path(client
, &path
, &rc
);
2642 copy
= xmlCopyNode(root
, 1);
2643 n
= xmlAddChild(n
, copy
);
2647 rc
= EPWMD_LIBXML_ERROR
;
2652 client
->inquire_status
= INQUIRE_DONE
;
2656 static int import_command(assuan_context_t ctx
, gchar
*line
)
2659 struct client_s
*client
= assuan_get_pointer(ctx
);
2661 rc
= file_modified(client
);
2664 return send_error(ctx
, rc
);
2667 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
2671 return send_error(ctx
, rc
);
2673 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2674 client
->inquire_status
= INQUIRE_BUSY
;
2678 static int lock_command(assuan_context_t ctx
, gchar
*line
)
2681 struct client_s
*client
= assuan_get_pointer(ctx
);
2683 rc
= file_modified(client
);
2686 return send_error(ctx
, rc
);
2688 rc
= lock_file_mutex(client
);
2691 client
->is_lock_cmd
= TRUE
;
2693 return send_error(ctx
, rc
);
2696 static int unlock_command(assuan_context_t ctx
, gchar
*line
)
2698 struct client_s
*client
= assuan_get_pointer(ctx
);
2699 gpg_error_t rc
= file_modified(client
);
2702 return send_error(ctx
, rc
);
2704 unlock_file_mutex(client
);
2705 return send_error(ctx
, 0);
2708 static int getpid_command(assuan_context_t ctx
, gchar
*line
)
2712 pid_t pid
= getpid();
2714 print_fmt(buf
, sizeof(buf
), "%i", pid
);
2716 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2718 return send_error(ctx
, rc
);
2721 static int version_command(assuan_context_t ctx
, gchar
*line
)
2726 print_fmt(buf
, sizeof(buf
), "%s", PACKAGE_VERSION
);
2728 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2730 return send_error(ctx
, rc
);
2733 static void bye_notify(assuan_context_t ctx
)
2735 struct client_s
*cl
= assuan_get_pointer(ctx
);
2737 /* This will let assuan_process_next() return. */
2738 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
2741 static void reset_notify(assuan_context_t ctx
)
2743 struct client_s
*cl
= assuan_get_pointer(ctx
);
2749 static gpg_error_t
parse_client_option(assuan_context_t ctx
, const gchar
*line
)
2751 gchar name
[32] = {0}, value
[256] = {0};
2752 struct client_s
*cl
= assuan_get_pointer(ctx
);
2754 if (sscanf(line
, " %31[a-zA-Z] = %255c", name
, value
) != 2)
2755 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
);
2757 if (g_strcasecmp(name
, (gchar
*)"NAME") == 0) {
2758 pth_attr_t attr
= pth_attr_of(pth_self());
2761 if (!strcmp(value
, "NULL")) {
2762 pth_attr_set(attr
, PTH_ATTR_NAME
, NULL
);
2763 pth_attr_destroy(attr
);
2767 print_fmt(buf
, sizeof(buf
), "%s", value
);
2768 pth_attr_set(attr
, PTH_ATTR_NAME
, buf
);
2769 pth_attr_destroy(attr
);
2770 #ifdef WITH_PINENTRY
2771 if (cl
->pinentry
->name
)
2772 g_free(cl
->pinentry
->name
);
2774 cl
->pinentry
->name
= g_strdup(buf
);
2776 log_write("OPTION CLIENT %s=%s", name
, buf
);
2779 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2784 static void set_option_value(gchar
**opt
, const gchar
*val
)
2791 if (val
&& strcmp(val
, "NULL"))
2792 *opt
= g_strdup(val
);
2795 static int option_handler(assuan_context_t ctx
, const gchar
*name
,
2798 struct client_s
*client
= assuan_get_pointer(ctx
);
2800 if (!value
|| !*value
)
2801 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2803 if (g_strcasecmp(name
, (gchar
*)"client") == 0)
2804 return parse_client_option(ctx
, value
);
2806 if (g_strcasecmp(name
, (gchar
*)"iterations") == 0) {
2811 n
= strtol(value
, &p
, 10);
2813 if (errno
|| (p
&& *p
) || n
< 0)
2814 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2816 MUTEX_LOCK(&rcfile_mutex
);
2817 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
: "global", "iterations", (guint
)n
);
2818 MUTEX_UNLOCK(&rcfile_mutex
);
2819 send_status_all(STATUS_CONFIG
);
2821 #ifdef WITH_PINENTRY
2822 else if (g_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
2823 set_option_value(&client
->pinentry
->lcmessages
, value
);
2824 else if (g_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
2825 set_option_value(&client
->pinentry
->lcctype
, value
);
2826 else if (g_strcasecmp(name
, (gchar
*)"ttyname") == 0)
2827 set_option_value(&client
->pinentry
->ttyname
, value
);
2828 else if (g_strcasecmp(name
, (gchar
*)"ttytype") == 0)
2829 set_option_value(&client
->pinentry
->ttytype
, value
);
2830 else if (g_strcasecmp(name
, (gchar
*)"display") == 0)
2831 set_option_value(&client
->pinentry
->display
, value
);
2832 else if (g_strcasecmp(name
, (gchar
*)"path") == 0)
2833 set_option_value(&client
->pinentry
->path
, value
);
2834 else if (g_strcasecmp(name
, (gchar
*)"title") == 0)
2835 set_option_value(&client
->pinentry
->title
, value
);
2836 else if (g_strcasecmp(name
, (gchar
*)"prompt") == 0)
2837 set_option_value(&client
->pinentry
->prompt
, value
);
2838 else if (g_strcasecmp(name
, (gchar
*)"desc") == 0)
2839 set_option_value(&client
->pinentry
->desc
, value
);
2841 * Look at client_thread() to see how this works.
2843 else if (g_strcasecmp(name
, (gchar
*)"timeout") == 0) {
2845 gint n
= strtol(value
, &p
, 10);
2848 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2850 client
->pinentry
->timeout
= n
;
2852 else if (g_strcasecmp(name
, (gchar
*)"pinentry") == 0) {
2854 gint n
= strtol(value
, &p
, 10);
2856 if (*p
|| n
< 0 || n
> 1)
2857 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2859 client
->pinentry
->enable
= n
== 0 ? FALSE
: TRUE
;
2863 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2865 log_write("OPTION %s=%s", name
, value
);
2869 gpg_error_t
register_commands(assuan_context_t ctx
)
2873 gint (*handler
)(assuan_context_t
, gchar
*line
);
2875 { "OPEN", open_command
},
2876 { "SAVE", save_command
},
2877 { "LIST", list_command
},
2878 { "REALPATH", realpath_command
},
2879 { "STORE", store_command
},
2880 { "DELETE", delete_command
},
2881 { "GET", get_command
},
2882 { "ATTR", attr_command
},
2883 { "ISCACHED", iscached_command
},
2884 { "CLEARCACHE", clearcache_command
},
2885 { "CACHETIMEOUT", cachetimeout_command
},
2886 { "GETCONFIG", getconfig_command
},
2887 { "DUMP", dump_command
},
2888 { "XPATH", xpath_command
},
2889 { "IMPORT", import_command
},
2890 { "LOCK", lock_command
},
2891 { "UNLOCK", unlock_command
},
2892 { "GETPID", getpid_command
},
2893 { "VERSION", version_command
},
2900 for (i
=0; table
[i
].name
; i
++) {
2901 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
2907 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
2912 rc
= assuan_register_option_handler(ctx
, option_handler
);
2917 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
2922 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
2925 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, guchar
*key
,
2926 struct client_crypto_s
*crypto
, gpointer
*dst
, goffset
*dst_len
)
2928 goffset insize
, len
;
2929 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
2930 guint64 iter
= 0, n_iter
= 0, iter_progress
= 0;
2934 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->fh1
) : sizeof(crypto
->fh
->fh2
);
2935 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->fh1
.iter
: crypto
->fh
->fh2
.iter
;
2937 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
2938 insize
= crypto
->fh
->st
.st_size
- fh_size
;
2939 crypto
->iv
= gcry_malloc(gcryblocksize
);
2942 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2943 return gpg_error_from_errno(ENOMEM
);
2946 /* No encryption iterations. This is a plain (gzipped) file. */
2947 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0)) {
2949 * cache_file_count() needs both .used == TRUE and a valid key in
2950 * order for it to count as a used cache entry. Fixes CACHE status
2953 memset(key
, '!', gcrykeysize
);
2957 memcpy(crypto
->iv
, crypto
->fh
->fh1
.iv
, gcryblocksize
);
2959 memcpy(crypto
->iv
, crypto
->fh
->fh2
.iv
, gcryblocksize
);
2961 crypto
->inbuf
= gcry_malloc(insize
);
2963 if (!crypto
->inbuf
) {
2964 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2965 return gpg_error_from_errno(ENOMEM
);
2968 crypto
->insize
= insize
;
2969 len
= pth_read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
2972 if (len
!= crypto
->insize
)
2973 return GPG_ERR_INV_LENGTH
;
2975 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0))
2978 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
2979 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
2983 if ((rc
= gcry_cipher_setkey(crypto
->gh
, key
, gcrykeysize
))) {
2984 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
2988 iter_progress
= (guint64
)get_key_file_integer(client
&& client
->filename
?
2989 client
->filename
: "global", "iteration_progress");
2991 if (iter_progress
> 0 && fh_iter
>= iter_progress
) {
2992 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
2999 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3004 crypto
->tkey
= gcry_malloc(gcrykeysize
);
3006 if (!crypto
->tkey
) {
3007 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
3008 return gpg_error_from_errno(ENOMEM
);
3011 memcpy(crypto
->tkey
, key
, gcrykeysize
);
3012 guchar
*tkey
= crypto
->tkey
;
3015 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
3016 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3020 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
3021 if (iter_progress
> 0 && iter
>= iter_progress
) {
3022 if (!(iter
% iter_progress
)) {
3023 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
3024 ++n_iter
* iter_progress
, fh_iter
);
3032 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
3033 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3037 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3040 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3047 if (iter_progress
&& fh_iter
>= iter_progress
) {
3048 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
3056 if (do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
3057 (gpointer
*)&crypto
->outbuf
, &outsize
, &zrc
) == FALSE
) {
3058 if (zrc
== Z_MEM_ERROR
)
3059 return gpg_error_from_errno(ENOMEM
);
3061 return EPWMD_BADKEY
; // Not a valid gzip header. Must be a bad key.
3064 if (g_strncasecmp(crypto
->outbuf
, "<?xml version=", 14) != 0) {
3065 gcry_free(crypto
->outbuf
);
3066 crypto
->outbuf
= NULL
;
3067 return EPWMD_BADKEY
;
3071 client
->xml
= crypto
->outbuf
;
3072 client
->len
= outsize
;
3073 crypto
->outbuf
= NULL
;
3076 *dst
= crypto
->outbuf
;
3078 crypto
->outbuf
= NULL
;
3081 /* The calling function should free the crypto struct. */
3086 * This is called after every Assuan command.
3088 void command_finalize(assuan_context_t ctx
, gint rc
)
3090 struct client_s
*client
= assuan_get_pointer(ctx
);
3092 if (!client
->is_lock_cmd
)
3093 unlock_file_mutex(client
);