1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2007 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 02111-1307 USA
24 #include <sys/types.h>
29 #include <glib/gprintf.h>
46 #include "pwmd_error.h"
51 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
54 return gcry_calloc(items
, size
);
56 return calloc(items
, size
);
60 static void z_free(void *data
, void *p
)
70 static gpg_error_t
file_modified(struct client_s
*client
)
74 if (client
->state
!= STATE_OPEN
)
77 if (stat(client
->filename
, &st
) == 0 && client
->mtime
) {
78 if (client
->mtime
!= st
.st_mtime
)
79 return EPWMD_FILE_MODIFIED
;
85 static gboolean
encrypt_xml(gcry_cipher_hd_t gh
, void *outbuf
, gsize outsize
,
86 void *inbuf
, gsize insize
)
88 if ((gcryerrno
= gcry_cipher_encrypt(gh
, outbuf
, outsize
, inbuf
, insize
))) {
89 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
96 gboolean
decrypt_xml(gcry_cipher_hd_t gh
, void *outbuf
, gsize outsize
,
97 void *inbuf
, gsize insize
)
99 if ((gcryerrno
= gcry_cipher_decrypt(gh
, outbuf
, outsize
, inbuf
, insize
))) {
100 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
107 static gpg_error_t
parse_xml(assuan_context_t ctx
)
109 struct client_s
*client
= assuan_get_pointer(ctx
);
111 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
114 return EPWMD_LIBXML_ERROR
;
119 gboolean
valid_filename(const gchar
*filename
)
123 if (!filename
|| !*filename
)
126 for (p
= filename
; *p
; p
++) {
127 if (g_ascii_isalnum(*p
) == FALSE
&& *p
!= '-' && *p
!= '_' && *p
!= '.')
134 gint
open_file(const gchar
*filename
, struct stat
*st
)
138 if ((fd
= open(filename
, O_RDONLY
)) == -1)
141 if (stat(filename
, st
) == -1) {
149 static void cleanup(struct client_s
*client
)
151 assuan_context_t ctx
= client
->ctx
;
154 * This may be a new file so don't use a cache slot. save_command() will
155 * set this to FALSE on success.
157 if (client
->new == TRUE
)
158 cache_clear(client
->md5file
, 1);
161 xmlFreeDoc(client
->doc
);
164 gcry_free(client
->xml
);
166 if (client
->filename
)
167 g_free(client
->filename
);
169 gcry_cipher_close(client
->gh
);
170 memset(client
, 0, sizeof(struct client_s
));
171 client
->state
= STATE_CONNECTED
;
173 client
->freed
= TRUE
;
176 static gchar
*print_fmt(const char *fmt
, ...)
179 static gchar buf
[ASSUAN_LINELENGTH
] = {0};
182 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
188 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gint insize
,
189 gpointer
*out
, glong
*outsize
, gint
*error
)
194 gint cmd
= Z_NO_FLUSH
;
200 z
.avail_in
= total
= insize
< zlib_bufsize
? insize
: zlib_bufsize
;
201 z
.avail_out
= zlib_bufsize
;
202 z
.next_out
= pout
= g_malloc(zlib_bufsize
);
205 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
206 *error
= Z_MEM_ERROR
;
210 ret
= inflateInit(&z
);
213 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
221 ret
= inflate(&z
, cmd
);
228 p
= g_realloc(pout
, z
.total_out
+ zlib_bufsize
);
236 z
.next_out
= pout
+ z
.total_out
;
237 z
.avail_out
= zlib_bufsize
;
240 if (!z
.avail_in
&& total
< insize
) {
241 if (total
+ zlib_bufsize
> insize
)
242 z
.avail_in
= insize
- total
;
244 z
.avail_in
= zlib_bufsize
;
246 z
.next_in
= in
+ total
;
249 assuan_write_status(ctx
, "DECOMPRESS",
250 print_fmt("%i %i", total
, insize
));
254 else if (!z
.avail_in
)
264 } while (ret
!= Z_STREAM_END
);
267 assuan_write_status(ctx
, "DECOMPRESS",
268 print_fmt("%i %i", total
, insize
));
271 *outsize
= z
.total_out
;
276 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
284 static int open_command(assuan_context_t ctx
, char *line
)
288 guchar shakey
[gcrykeysize
];
292 struct client_s
*client
= assuan_get_pointer(ctx
);
294 gchar
*filename
= NULL
;
296 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
299 if (!filename
|| !*filename
) {
301 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
304 if (valid_filename(filename
) == FALSE
) {
306 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
309 if (client
->state
== STATE_OPEN
)
312 client
->freed
= FALSE
;
314 if ((gcryerrno
= gcry_cipher_open(&client
->gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0))) {
316 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
318 return send_error(ctx
, gcryerrno
);
321 if (stat(filename
, &st
) == 0) {
322 if (!S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
323 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_INVALID_FILENAME
));
326 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
329 client
->mtime
= st
.st_mtime
;
332 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
335 * New files don't need a key.
337 if (access(filename
, R_OK
|W_OK
) != 0) {
338 if (errno
!= ENOENT
) {
340 log_write("%s: %s", filename
, strerror(errno
));
343 return send_syserror(ctx
, error
);
346 if ((client
->xml
= new_document()) == NULL
) {
348 log_write("%s", strerror(errno
));
351 return send_syserror(ctx
, error
);
354 client
->len
= xmlStrlen(client
->xml
);
356 if (cache_has_file(client
->md5file
) == TRUE
)
357 cache_clear(client
->md5file
, 1);
359 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
360 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
363 return send_error(ctx
, EPWMD_MAX_SLOTS
);
367 client
->filename
= g_strdup(filename
);
369 if (!client
->filename
) {
372 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
373 return send_syserror(ctx
, ENOMEM
);
376 if (req
[1] && *req
[1]) {
377 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, req
[1], strlen(req
[1]));
378 memset(req
[1], 0, strlen(req
[1]));
385 if ((fd
= open_file(filename
, &st
)) == -1) {
387 log_write("%s: %s", filename
, strerror(errno
));
390 return send_syserror(ctx
, error
);
396 if (cache_get_key(client
->md5file
, shakey
) == TRUE
)
400 * No key specified and no matching filename found in the cache.
402 if (!req
[1] || !*req
[1]) {
406 return send_error(ctx
, EPWMD_KEY
);
411 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, req
[1], strlen(req
[1]));
412 memset(req
[1], 0, strlen(req
[1]));
415 error
= try_xml_decrypt(ctx
, fd
, st
, shakey
);
419 memset(shakey
, 0, sizeof(shakey
));
422 return send_error(ctx
, error
);
426 client
->filename
= g_strdup(filename
);
428 if (!client
->filename
) {
429 memset(shakey
, 0, sizeof(shakey
));
430 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
433 return send_syserror(ctx
, ENOMEM
);
438 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
439 memset(shakey
, 0, sizeof(shakey
));
440 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
443 return send_error(ctx
, EPWMD_MAX_SLOTS
);
446 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
447 cache_reset_timeout(client
->md5file
, timeout
);
450 cache_set_timeout(client
->md5file
, -2);
452 memset(shakey
, 0, sizeof(shakey
));
456 error
= parse_xml(ctx
);
459 gcry_free(client
->xml
);
464 client
->state
= STATE_OPEN
;
465 send_cache_status(ctx
);
468 return send_error(ctx
, error
);
472 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
473 gint size
, gpointer
*out
, glong
*outsize
, gint
*error
)
479 gint cmd
= Z_NO_FLUSH
;
483 z
.next_in
= pin
= data
;
484 z
.avail_in
= size
< zlib_bufsize
? size
: zlib_bufsize
;
485 z
.avail_out
= zlib_bufsize
;
486 z
.next_out
= pout
= g_malloc(zlib_bufsize
);
489 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
490 *error
= Z_MEM_ERROR
;
494 ret
= deflateInit(&z
, level
);
497 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
506 ret
= deflate(&z
, cmd
);
513 p
= g_realloc(pout
, z
.total_out
+ zlib_bufsize
);
521 z
.next_out
= pout
+ z
.total_out
;
522 z
.avail_out
= zlib_bufsize
;
531 if (total
+ zlib_bufsize
> size
) {
532 z
.avail_in
= size
- total
;
533 total
+= size
- total
;
536 total
+= zlib_bufsize
;
537 z
.avail_in
= zlib_bufsize
;
544 assuan_write_status(ctx
, "COMPRESS",
545 print_fmt("%i %i", total
, size
));
554 } while (ret
!= Z_STREAM_END
);
557 *outsize
= z
.total_out
;
562 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
570 gpg_error_t
do_xml_encrypt(struct client_s
*client
, gcry_cipher_hd_t gh
,
571 const gchar
*filename
, gpointer data
, size_t insize
,
572 const guchar
*shakey
, guint iter
)
577 guchar tkey
[gcrykeysize
];
580 guint iter_progress
= 0, n_iter
= 0;
581 struct file_header_s
{
583 guchar iv
[gcryblocksize
];
586 if (insize
/ gcryblocksize
) {
587 len
= (insize
/ gcryblocksize
) * gcryblocksize
;
589 if (insize
% gcryblocksize
)
590 len
+= gcryblocksize
;
594 * Resize the existing xml buffer to the block size required by gcrypt
595 * rather than duplicating it and wasting memory.
597 inbuf
= gcry_realloc(data
, len
);
600 return gpg_error_from_errno(ENOMEM
);
603 gcry_create_nonce(file_header
.iv
, sizeof(file_header
.iv
));
604 memcpy(tkey
, shakey
, sizeof(tkey
));
607 if ((gcryerrno
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
609 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
613 file_header
.iter
= iter
;
616 iter_progress
= get_key_file_integer("default", "iteration_progress");
619 if (client
&& iter_progress
> 0 && iter_progress
<= iter
) {
620 if (!(iter
% iter_progress
))
621 assuan_write_status(client
->ctx
, "ENCRYPT", print_fmt("%i",
622 ++n_iter
* iter_progress
));
625 if ((gcryerrno
= gcry_cipher_setiv(gh
, file_header
.iv
,
626 sizeof(file_header
.iv
)))) {
628 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
632 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0)
635 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
642 if ((gcryerrno
= gcry_cipher_setiv(gh
, file_header
.iv
,
643 sizeof(file_header
.iv
)))) {
645 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
649 if ((gcryerrno
= gcry_cipher_setkey(gh
, shakey
, gcrykeysize
))) {
651 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
655 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
657 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
661 if (client
&& iter_progress
&& file_header
.iter
>= iter_progress
) {
662 if ((file_header
.iter
% iter_progress
))
663 assuan_write_status(client
->ctx
, "ENCRYPT",
664 print_fmt("%i", file_header
.iter
));
668 if ((fd
= open(filename
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600)) == -1) {
671 p
= strrchr(filename
, '/');
673 log_write("%s: %s", p
, strerror(errno
));
674 return gpg_error_from_errno(error
);
679 * xml_import() from command line.
683 write(fd
, &file_header
, sizeof(struct file_header_s
));
684 write(fd
, inbuf
, insize
);
693 static int save_command(assuan_context_t ctx
, char *line
)
699 guchar shakey
[gcrykeysize
];
702 struct client_s
*client
= assuan_get_pointer(ctx
);
710 error
= file_modified(client
);
713 log_write("%s: %s", client
->filename
? client
->filename
: "",
714 pwmd_strerror(error
));
715 return send_error(ctx
, error
);
718 if (stat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
719 return send_syserror(ctx
, errno
);
721 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
722 log_write("%s: %s", client
->filename
, pwmd_strerror(EPWMD_INVALID_FILENAME
));
723 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
726 if (!line
|| !*line
) {
727 if (cache_get_key(client
->md5file
, shakey
) == FALSE
)
728 return send_error(ctx
, EPWMD_KEY
);
733 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, line
, strlen(line
));
734 memset(line
, 0, strlen(line
));
737 xmlDocDumpFormatMemory(client
->doc
, &p
, &len
, 0);
741 iter
= get_key_file_integer(client
->filename
, "compression_level");
746 if (do_compress(ctx
, iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zerror
) == FALSE
) {
747 memset(shakey
, 0, sizeof(shakey
));
750 if (zerror
== Z_MEM_ERROR
)
751 return send_syserror(ctx
, ENOMEM
);
753 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
763 if ((iter
= get_key_file_integer(client
->filename
, "iterations")) == -1)
766 error
= do_xml_encrypt(client
, client
->gh
, client
->filename
, xmlbuf
, len
, shakey
, iter
);
769 memset(shakey
, 0, sizeof(shakey
));
770 return send_error(ctx
, error
);
773 stat(client
->filename
, &st
);
774 client
->mtime
= st
.st_mtime
;
775 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
778 memset(shakey
, 0, sizeof(shakey
));
779 cache_reset_timeout(client
->md5file
, timeout
);
784 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
785 memset(shakey
, 0, sizeof(shakey
));
786 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
787 return send_error(ctx
, EPWMD_MAX_SLOTS
);
791 memset(shakey
, 0, sizeof(shakey
));
792 cache_reset_timeout(client
->md5file
, timeout
);
796 static gboolean
contains_whitespace(const gchar
*str
)
798 const gchar
*p
= str
;
802 len
= g_utf8_strlen(p
++, -1) -1;
805 c
= g_utf8_get_char(p
++);
807 if (g_unichar_isspace(c
))
814 static int delete_command(assuan_context_t ctx
, char *line
)
816 struct client_s
*client
= assuan_get_pointer(ctx
);
821 error
= file_modified(client
);
824 log_write("%s: %s", client
->filename
? client
->filename
: "",
825 pwmd_strerror(error
));
826 return send_error(ctx
, error
);
829 if (strchr(line
, '\t'))
830 req
= split_input_line(line
, "\t", -1);
832 req
= split_input_line(line
, " ", -1);
835 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
837 n
= find_account(client
->doc
, &req
, &error
, NULL
);
841 return send_error(ctx
, error
);
845 * No sub-node defined. Remove the entire node (account).
857 n
= find_elements(client
->doc
, n
->children
, req
+1, &error
, NULL
, NULL
, NULL
, NULL
);
861 return send_error(ctx
, error
);
871 static int store_command(assuan_context_t ctx
, char *line
)
873 struct client_s
*client
= assuan_get_pointer(ctx
);
880 error
= file_modified(client
);
883 log_write("%s: %s", client
->filename
? client
->filename
: "",
884 pwmd_strerror(error
));
885 return send_error(ctx
, error
);
888 error
= assuan_inquire(ctx
, "STORE", &result
, &len
, 0);
891 return send_error(ctx
, error
);
893 req
= split_input_line((gchar
*)result
, "\t", 0);
901 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
904 n
= find_account(client
->doc
, &req
, &error
, NULL
);
906 if (error
&& error
== EPWMD_ELEMENT_NOT_FOUND
) {
907 if (contains_whitespace(*req
) == TRUE
) {
909 return send_error(ctx
, EPWMD_INVALID_ELEMENT
);
912 error
= new_account(client
->doc
, *req
);
916 return send_error(ctx
, error
);
924 return send_error(ctx
, error
);
929 create_elements_cb(n
, req
+1, &error
, NULL
);
931 find_elements(client
->doc
, n
->children
, req
+1, &error
,
932 NULL
, NULL
, create_elements_cb
, NULL
);
936 return send_error(ctx
, error
);
939 static int get_command(assuan_context_t ctx
, char *line
)
941 struct client_s
*client
= assuan_get_pointer(ctx
);
946 error
= file_modified(client
);
949 log_write("%s: %s", client
->filename
? client
->filename
: "",
950 pwmd_strerror(error
));
951 return send_error(ctx
, error
);
954 req
= split_input_line(line
, "\t", -1);
958 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
961 n
= find_account(client
->doc
, &req
, &error
, NULL
);
965 return send_error(ctx
, error
);
969 n
= find_elements(client
->doc
, n
->children
, req
+1, &error
, NULL
, NULL
, NULL
, NULL
);
974 return send_error(ctx
, error
);
976 if (!n
|| !n
->children
)
977 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
981 if (!n
|| !n
->content
|| !*n
->content
)
982 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
984 error
= assuan_send_data(ctx
, n
->content
, xmlStrlen(n
->content
));
985 return send_error(ctx
, error
);
988 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
)
997 for (n
= 0; *p
&& n
< 3; p
++) {
1002 if (strstr((gchar
*)p
, "text()") != NULL
)
1003 p
[xmlStrlen(p
) - 7] = 0;
1005 for (n
= 0; p
[n
]; n
++) {
1010 buf
= g_strdup_printf("%s\t%s", account
, p
);
1014 gboolean
strv_printf(gchar
***array
, const gchar
*fmt
, ...)
1019 gint len
= *array
? g_strv_length(*array
) : 0;
1024 if ((a
= g_realloc(*array
, (len
+ 2) * sizeof(gchar
*))) == NULL
)
1028 g_vasprintf(&buf
, fmt
, ap
);
1041 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**req
,
1042 gpg_error_t
*error
, void *data
)
1044 struct realpath_s
*rp
= data
;
1047 g_free(rp
->account
);
1049 rp
->account
= g_strdup(req
[0]);
1052 *error
= gpg_error_from_errno(ENOMEM
);
1059 static int realpath_command(assuan_context_t ctx
, char *line
)
1062 struct client_s
*client
= assuan_get_pointer(ctx
);
1068 struct realpath_s
*rp
;
1071 error
= file_modified(client
);
1074 log_write("%s: %s", client
->filename
? client
->filename
: "",
1075 pwmd_strerror(error
));
1076 return send_error(ctx
, error
);
1079 if (strchr(line
, '\t') != NULL
) {
1080 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1081 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1084 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1085 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1088 n
= find_account(client
->doc
, &req
, &error
, NULL
);
1092 return send_error(ctx
, error
);
1095 rp
= g_malloc(sizeof(struct realpath_s
));
1099 return send_syserror(ctx
, ENOMEM
);
1102 rp
->account
= g_strdup(req
[0]);
1106 return send_syserror(ctx
, ENOMEM
);
1110 n
= find_elements(client
->doc
, n
->children
, req
+1, &error
,
1111 NULL
, realpath_elements_cb
, NULL
, rp
);
1114 g_free(rp
->account
);
1117 return send_error(ctx
, error
);
1121 p
= xmlGetNodePath(n
);
1122 result
= element_path_to_req(rp
->account
, p
);
1126 g_free(rp
->account
);
1130 return send_syserror(ctx
, ENOMEM
);
1133 string
= g_string_new(result
);
1135 g_free(rp
->account
);
1142 for (t
= string
->str
+ i
; *t
; t
++, i
++) {
1143 if (!i
|| *t
== '\t') {
1144 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1149 error
= assuan_send_data(ctx
, string
->str
, string
->len
);
1150 g_string_free(string
, TRUE
);
1151 return send_error(ctx
, error
);
1154 struct list_element_s
{
1159 static gboolean
append_to_element_list(struct list_element_s
*elements
)
1166 if (!elements
|| !elements
->elements
)
1169 tmp
= g_strjoinv("\t", elements
->elements
);
1174 g_strfreev(elements
->elements
);
1175 elements
->elements
= NULL
;
1176 total
= g_slist_length(elements
->list
);
1177 a
= g_utf8_collate_key(tmp
, -1);
1185 * Removes duplicate element paths from the list. This is needed when
1186 * appending an element tree from list_command(). The glib docs recommend
1187 * using g_utf8_collate_key() for a large number of strings.
1189 for (i
= 0; i
< total
; i
++) {
1190 gchar
*p
= g_slist_nth_data(elements
->list
, i
);
1191 gchar
*b
= g_utf8_collate_key(p
, -1);
1199 if (strcmp(a
, b
) == 0) {
1210 list
= g_slist_append(elements
->list
, tmp
);
1215 elements
->list
= list
;
1219 static gpg_error_t
do_list_recurse(xmlDocPtr doc
, xmlNodePtr node
,
1220 struct list_element_s
*elements
, gchar
*prefix
)
1225 if (append_to_element_list(elements
) == FALSE
)
1226 return gpg_error_from_errno(ENOMEM
);
1228 for (n
= node
; n
; n
= n
->next
) {
1229 if (n
->type
== XML_ELEMENT_NODE
) {
1230 xmlChar
*content
= node_has_attribute(n
, (xmlChar
*)"target");
1234 strv_printf(&elements
->elements
, "%s\t%s", prefix
, n
->name
);
1236 if (append_to_element_list(elements
) == FALSE
)
1237 return gpg_error_from_errno(ENOMEM
);
1240 tmp
= g_strdup_printf("%s\t!%s", prefix
, n
->name
);
1243 return gpg_error_from_errno(ENOMEM
);
1245 strv_printf(&elements
->elements
, "%s", tmp
);
1248 error
= do_list_recurse(doc
, n
->children
, elements
, tmp
);
1251 if (error
&& error
!= EPWMD_ELEMENT_NOT_FOUND
)
1257 if (append_to_element_list(elements
) == FALSE
)
1258 return gpg_error_from_errno(ENOMEM
);
1265 static gpg_error_t
do_list_command(assuan_context_t ctx
, xmlDocPtr doc
,
1266 struct list_element_s
*elements
, char *line
)
1268 gchar
*prefix
= NULL
, *account
;
1269 gchar
**req
= NULL
, **oreq
= NULL
, *tmp
;
1271 gboolean account_is_literal
, account_has_target
= FALSE
;
1276 if ((req
= split_input_line(line
, "\t", 0)) == NULL
) {
1277 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1278 return EPWMD_COMMAND_SYNTAX
;
1281 prefix
= g_strdup(*req
);
1285 return gpg_error_from_errno(ENOMEM
);
1288 account
= g_strdup(*req
);
1293 return gpg_error_from_errno(ENOMEM
);
1296 oreq
= g_strdupv(req
);
1302 return gpg_error_from_errno(ENOMEM
);
1307 account_has_target
= FALSE
;
1308 account_is_literal
= is_literal_element_str(prefix
);
1309 n
= find_account(doc
, &p
, &error
, &account_has_target
);
1319 if (!which
&& account_is_literal
== FALSE
&& account_has_target
== FALSE
) {
1320 tmp
= g_strdup_printf("!%s", prefix
);
1323 error
= gpg_error_from_errno(ENOMEM
);
1334 n
= find_elements(doc
, n
->children
, p
+1, &error
,
1335 NULL
, NULL
, NULL
, NULL
);
1340 tmp
= g_strjoinv("\t", p
+1);
1342 error
= gpg_error_from_errno(ENOMEM
);
1346 t
= g_strdup_printf("%s\t%s", prefix
, tmp
);
1348 error
= gpg_error_from_errno(ENOMEM
);
1357 strv_printf(&elements
->elements
, "%s", prefix
);
1359 if (node_has_child_element(n
->children
) == FALSE
) {
1360 if (append_to_element_list(elements
) == FALSE
) {
1361 error
= gpg_error_from_errno(ENOMEM
);
1366 error
= do_list_recurse(doc
, n
->children
, elements
, prefix
);
1371 if (!which
++ && !*(p
+1) && account_is_literal
== FALSE
&& account_has_target
== TRUE
) {
1373 *oreq
= g_strdup_printf("!%s", account
);
1376 error
= gpg_error_from_errno(ENOMEM
);
1382 prefix
= g_strdup(*oreq
);
1385 error
= gpg_error_from_errno(ENOMEM
);
1404 * This could be faster especially when finding "target" attributes.
1406 static int list_command(assuan_context_t ctx
, char *line
)
1408 struct client_s
*client
= assuan_get_pointer(ctx
);
1410 struct list_element_s
*elements
= NULL
;
1415 if (disable_list_and_dump
== TRUE
)
1416 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1418 error
= file_modified(client
);
1421 log_write("%s: %s", client
->filename
, pwmd_strerror(error
));
1422 return send_error(ctx
, error
);
1428 error
= list_accounts(client
->doc
, &str
);
1431 return send_error(ctx
, error
);
1433 error
= assuan_send_data(ctx
, str
->str
, str
->len
);
1434 g_string_free(str
, TRUE
);
1435 return send_error(ctx
, error
);
1438 elements
= g_malloc0(sizeof(struct list_element_s
));
1441 error
= gpg_error_from_errno(ENOMEM
);
1445 error
= do_list_command(ctx
, client
->doc
, elements
, line
);
1451 total
= g_slist_length(elements
->list
);
1454 error
= EPWMD_EMPTY_ELEMENT
;
1459 * Find element paths with a target and append those element trees to
1462 for (i
= 0; i
< total
; i
++) {
1465 tmp
= g_slist_nth_data(elements
->list
, i
);
1466 req
= split_input_line(tmp
, "\t", 0);
1469 if (g_str_has_prefix(tmp
, "!") == TRUE
) {
1477 for (p
= req
; *p
; p
++) {
1478 if (g_str_has_prefix(*p
, "!") == FALSE
)
1489 error
= do_list_command(ctx
, client
->doc
, elements
, tmp
);
1491 if (error
&& error
!= EPWMD_ELEMENT_NOT_FOUND
)
1494 total
= g_slist_length(elements
->list
);
1498 string
= g_string_new(NULL
);
1500 for (i
= 0; i
< total
; i
++) {
1501 tmp
= g_slist_nth_data(elements
->list
, i
);
1502 g_string_append_printf(string
, "%s\n", tmp
);
1506 string
= g_string_truncate(string
, string
->len
- 1);
1507 error
= assuan_send_data(ctx
, string
->str
, string
->len
);
1508 g_string_free(string
, TRUE
);
1513 g_slist_free(elements
->list
);
1515 if (elements
->elements
)
1516 g_strfreev(elements
->elements
);
1521 return send_error(ctx
, error
);
1524 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1529 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1530 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1533 return EPWMD_LIBXML_ERROR
;
1536 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1542 * req[0] - element path
1544 static int attribute_list(assuan_context_t ctx
, gchar
**req
)
1546 struct client_s
*client
= assuan_get_pointer(ctx
);
1547 gchar
**attrlist
= NULL
;
1549 gchar
**path
= NULL
;
1555 if (!req
|| !req
[0])
1556 return EPWMD_COMMAND_SYNTAX
;
1558 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1560 * The first argument may be only an account.
1562 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1563 return EPWMD_COMMAND_SYNTAX
;
1566 n
= find_account(client
->doc
, &path
, &error
, NULL
);
1574 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
1575 NULL
, NULL
, NULL
, NULL
);
1585 for (a
= n
->properties
; a
; a
= a
->next
) {
1588 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1590 g_strfreev(attrlist
);
1593 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(errno
));
1594 return gpg_error_from_errno(error
);
1599 attrlist
[i
] = g_strdup_printf("%s\t%s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1602 g_strfreev(attrlist
);
1603 return gpg_error_from_errno(ENOMEM
);
1606 attrlist
[++i
] = NULL
;
1610 return EPWMD_EMPTY_ELEMENT
;
1612 line
= g_strjoinv("\n", attrlist
);
1615 g_strfreev(attrlist
);
1616 return gpg_error_from_errno(ENOMEM
);
1619 error
= assuan_send_data(ctx
, line
, g_utf8_strlen(line
, -1));
1621 g_strfreev(attrlist
);
1626 * req[0] - attribute
1627 * req[1] - element path
1629 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1633 gchar
**path
= NULL
;
1636 if (!req
|| !req
[0] || !req
[1])
1637 return EPWMD_COMMAND_SYNTAX
;
1639 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1641 * The first argument may be only an account.
1643 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1644 return EPWMD_COMMAND_SYNTAX
;
1648 * Don't remove the "name" attribute for the account element. To remove an
1649 * account use DELETE <account>.
1651 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
1652 error
= EPWMD_ATTR_SYNTAX
;
1656 n
= find_account(client
->doc
, &path
, &error
, NULL
);
1662 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
1663 NULL
, NULL
, NULL
, NULL
);
1671 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
1672 return EPWMD_ATTR_NOT_FOUND
;
1674 if (xmlRemoveProp(a
) == -1)
1675 return EPWMD_LIBXML_ERROR
;
1685 * Creates a "target" attribute. When other commands encounter an element with
1686 * this attribute, the element path is modified to the target value. If the
1687 * source element path doesn't exist when using 'ATTR SET target', it is
1688 * created, but the destination element path must exist.
1690 * req[0] - source element path
1691 * req[1] - destination element path
1693 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
1695 gchar
**src
, **dst
, *line
;
1699 if (!req
|| !req
[0] || !req
[1])
1700 return EPWMD_COMMAND_SYNTAX
;
1702 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1704 * The first argument may be only an account.
1706 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
1707 return EPWMD_COMMAND_SYNTAX
;
1710 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1712 * The first argument may be only an account.
1714 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
1715 error
= EPWMD_COMMAND_SYNTAX
;
1720 n
= find_account(client
->doc
, &dst
, &error
, NULL
);
1723 * Make sure the destination element path exists.
1729 n
= find_elements(client
->doc
, n
->children
, dst
+1, &error
,
1730 NULL
, NULL
, NULL
, NULL
);
1737 n
= find_account(client
->doc
, &src
, &error
, NULL
);
1740 if (error
== EPWMD_ELEMENT_NOT_FOUND
) {
1741 error
= new_account(client
->doc
, src
[0]);
1754 n
= create_target_elements_cb(n
, src
+1, &error
, NULL
);
1756 n
= find_elements(client
->doc
, n
->children
, src
+1, &error
,
1757 NULL
, NULL
, create_target_elements_cb
, NULL
);
1763 * Reset the position of the element tree now that the elements
1764 * have been created.
1766 n
= find_account(client
->doc
, &src
, &error
, NULL
);
1771 n
= find_elements(client
->doc
, n
->children
, src
+1, &error
,
1772 NULL
, NULL
, NULL
, NULL
);
1778 line
= g_strjoinv("\t", dst
);
1779 error
= add_attribute(n
, "target", line
);
1798 * req[0] - account name
1801 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
1807 tmp
= g_strdupv(req
);
1810 return gpg_error_from_errno(ENOMEM
);
1812 n
= find_account(client
->doc
, &tmp
, &error
, NULL
);
1818 if (g_utf8_collate(req
[0], req
[1]) == 0)
1822 * Will not overwrite an existing account.
1824 tmp
= g_strdupv(req
+1);
1827 return gpg_error_from_errno(ENOMEM
);
1829 n
= find_account(client
->doc
, &tmp
, &error
, NULL
);
1832 if (error
&& error
!= EPWMD_ELEMENT_NOT_FOUND
)
1836 return EPWMD_ACCOUNT_EXISTS
;
1839 * Whitespace not allowed in account names.
1841 if (contains_whitespace(req
[1]) == TRUE
)
1842 return EPWMD_ATTR_SYNTAX
;
1844 tmp
= g_strdupv(req
);
1847 return gpg_error_from_errno(ENOMEM
);
1849 n
= find_account(client
->doc
, &tmp
, &error
, NULL
);
1853 return EPWMD_ELEMENT_NOT_FOUND
;
1855 return add_attribute(n
, "name", req
[1]);
1859 * req[0] - attribute
1860 * req[1] - element path
1862 static int attribute_get(assuan_context_t ctx
, gchar
**req
)
1864 struct client_s
*client
= assuan_get_pointer(ctx
);
1870 if (!req
|| !req
[0] || !req
[1])
1871 return EPWMD_COMMAND_SYNTAX
;
1873 if (strchr(req
[1], '\t')) {
1874 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
1875 return EPWMD_COMMAND_SYNTAX
;
1878 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1879 return EPWMD_COMMAND_SYNTAX
;
1882 n
= find_account(client
->doc
, &path
, &error
, NULL
);
1888 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
1889 NULL
, NULL
, NULL
, NULL
);
1897 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
1898 return EPWMD_ATTR_NOT_FOUND
;
1900 error
= assuan_send_data(ctx
, a
, xmlStrlen(a
));
1910 * req[0] - attribute
1911 * req[1] - element path
1914 static int attribute_set(struct client_s
*client
, gchar
**req
)
1916 gchar
**path
= NULL
;
1920 if (!req
|| !req
[0] || !req
[1] || !req
[2])
1921 return EPWMD_COMMAND_SYNTAX
;
1924 * Reserved attribute names.
1926 if (g_utf8_collate(req
[0], "name") == 0) {
1928 * Only reserved for the account element. Not the rest of the
1931 if (strchr(req
[1], '\t') == NULL
)
1932 return name_attribute(client
, req
+ 1);
1934 else if (g_utf8_collate(req
[0], "target") == 0)
1935 return target_attribute(client
, req
+ 1);
1937 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1939 * The first argument may be only an account.
1941 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1942 return EPWMD_COMMAND_SYNTAX
;
1945 n
= find_account(client
->doc
, &path
, &error
, NULL
);
1951 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
1952 NULL
, NULL
, NULL
, NULL
);
1959 return add_attribute(n
, req
[0], req
[2]);
1968 * req[1] - attribute name or element path if command is LIST
1969 * req[2] - element path
1970 * req[2] - element path or value
1972 static int attr_command(assuan_context_t ctx
, char *line
)
1974 struct client_s
*client
= assuan_get_pointer(ctx
);
1975 gchar
**req
= split_input_line(line
, " ", 4);
1976 gpg_error_t error
= 0;
1978 error
= file_modified(client
);
1981 log_write("%s: %s", client
->filename
? client
->filename
: "",
1982 pwmd_strerror(error
));
1984 return send_error(ctx
, error
);
1987 if (!req
|| !req
[0] || !req
[1]) {
1989 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1992 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
1993 error
= attribute_set(client
, req
+1);
1994 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
1995 error
= attribute_get(ctx
, req
+1);
1996 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
1997 error
= attribute_delete(client
, req
+1);
1998 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
1999 error
= attribute_list(ctx
, req
+1);
2001 error
= EPWMD_COMMAND_SYNTAX
;
2004 return send_error(ctx
, error
);
2007 static int iscached_command(assuan_context_t ctx
, char *line
)
2009 gchar
**req
= split_input_line(line
, " ", 0);
2012 if (!req
|| !*req
) {
2014 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2017 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2020 if (cache_iscached(md5file
) == FALSE
)
2021 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2026 void send_cache_status(assuan_context_t ctx
)
2028 char *tmp
= print_fmt("%li %li",
2029 cache_file_count(), cache_size
/ sizeof(file_cache_t
) - cache_file_count());
2032 assuan_write_status(ctx
, "CACHE", tmp
);
2035 static int clearcache_command(assuan_context_t ctx
, char *line
)
2037 struct client_s
*client
= assuan_get_pointer(ctx
);
2038 gchar
**req
= split_input_line(line
, " ", 0);
2041 if (!req
|| !*req
) {
2043 cache_clear(client
->md5file
, 2);
2044 send_cache_status(ctx
);
2048 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2050 cache_clear(md5file
, 1);
2051 send_cache_status(ctx
);
2055 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2059 gchar
**req
= split_input_line(line
, " ", 0);
2062 if (!req
|| !*req
|| !req
[1]) {
2064 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2068 timeout
= strtol(req
[0], &p
, 10);
2070 if (errno
!= 0 || *p
!= 0) {
2072 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2075 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2078 if (cache_set_timeout(md5file
, timeout
) == FALSE
)
2079 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2081 send_cache_status(ctx
);
2085 static int dump_command(assuan_context_t ctx
, char *line
)
2089 struct client_s
*client
= assuan_get_pointer(ctx
);
2092 if (disable_list_and_dump
== TRUE
)
2093 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2095 error
= file_modified(client
);
2098 log_write("%s: %s", client
->filename
? client
->filename
: "",
2099 pwmd_strerror(error
));
2100 return send_error(ctx
, error
);
2103 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2104 error
= assuan_send_data(ctx
, xml
, len
);
2109 static int getconfig_command(assuan_context_t ctx
, gchar
*line
)
2111 struct client_s
*client
= assuan_get_pointer(ctx
);
2112 gpg_error_t error
= 0;
2115 if (g_utf8_collate(line
, "key") == 0 || g_utf8_collate(line
, "key_file") == 0)
2116 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2118 p
= get_key_file_string(client
->filename
? client
->filename
: "default", line
);
2121 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2123 tmp
= expand_homedir(p
);
2126 error
= assuan_send_data(ctx
, p
, g_utf8_strlen(p
, -1));
2128 return send_error(ctx
, error
);
2131 void cleanup_assuan(assuan_context_t ctx
)
2133 struct client_s
*cl
= assuan_get_pointer(ctx
);
2138 gpg_error_t
register_commands(assuan_context_t ctx
)
2142 int (*handler
)(assuan_context_t
, char *line
);
2144 { "OPEN", open_command
},
2145 { "SAVE", save_command
},
2146 { "LIST", list_command
},
2147 { "REALPATH", realpath_command
},
2148 { "STORE", store_command
},
2149 { "DELETE", delete_command
},
2150 { "GET", get_command
},
2151 { "ATTR", attr_command
},
2152 { "ISCACHED", iscached_command
},
2153 { "CLEARCACHE", clearcache_command
},
2154 { "CACHETIMEOUT", cachetimeout_command
},
2155 { "GETCONFIG", getconfig_command
},
2156 { "DUMP", dump_command
},
2163 for (i
=0; table
[i
].name
; i
++) {
2164 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
2170 return assuan_register_bye_notify(ctx
, cleanup_assuan
);
2173 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, gint fd
, struct stat st
,
2179 guchar tkey
[gcrykeysize
];
2180 struct file_header_s
{
2182 guchar iv
[gcryblocksize
];
2184 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
2185 gcry_cipher_hd_t gh
;
2186 guint iter
, n_iter
= 0;
2189 void *outbuf
= NULL
;
2195 gcryerrno
= gcry_cipher_open(&gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0);
2203 lseek(fd
, 0, SEEK_SET
);
2204 insize
= st
.st_size
- sizeof(struct file_header_s
);
2205 iv
= gcry_malloc(gcryblocksize
);
2208 gcry_cipher_close(gh
);
2209 return gpg_error_from_errno(ENOMEM
);
2212 read(fd
, &file_header
, sizeof(struct file_header_s
));
2213 memcpy(iv
, &file_header
.iv
, sizeof(file_header
.iv
));
2214 inbuf
= gcry_malloc(insize
);
2217 gcry_cipher_close(gh
);
2219 return gpg_error_from_errno(ENOMEM
);
2222 read(fd
, inbuf
, insize
);
2223 memcpy(tkey
, key
, sizeof(tkey
));
2226 if ((gcryerrno
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
2228 gcry_cipher_close(gh
);
2229 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2232 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2239 if ((gcryerrno
= gcry_cipher_setkey(gh
, key
, gcrykeysize
))) {
2241 gcry_cipher_close(gh
);
2242 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2245 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2251 gcry_cipher_close(gh
);
2256 if (decrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
2258 gcry_cipher_close(gh
);
2259 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2262 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2269 if ((gcryerrno
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
2271 gcry_cipher_close(gh
);
2272 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2275 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2282 iter
= file_header
.iter
;
2283 iter_progress
= get_key_file_integer("default", "iteration_progress");
2286 if (ctx
&& iter_progress
> 0 && iter
>= iter_progress
) {
2287 if (!(iter
% iter_progress
))
2288 assuan_write_status(ctx
, "DECRYPT", print_fmt("%i",
2289 ++n_iter
* iter_progress
));
2292 if ((gcryerrno
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
2294 gcry_cipher_close(gh
);
2295 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2298 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2305 if (decrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
2307 gcry_cipher_close(gh
);
2308 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2311 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2321 if (ctx
&& iter_progress
&& file_header
.iter
>= iter_progress
) {
2322 if ((file_header
.iter
% iter_progress
))
2323 assuan_write_status(ctx
, "DECRYPT", print_fmt("%i", file_header
.iter
));
2329 if (do_decompress(ctx
, inbuf
, insize
, &outbuf
, &outsize
, &zerror
) == FALSE
) {
2331 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2333 if (zerror
== Z_MEM_ERROR
) {
2335 return gpg_error_from_errno(ENOMEM
);
2337 else if (zerror
!= Z_DATA_ERROR
) {
2341 gcry_cipher_close(gh
);
2342 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gpg_strerror(GPG_ERR_COMPR_ALGO
));
2345 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gpg_strerror(GPG_ERR_COMPR_ALGO
));
2347 return GPG_ERR_COMPR_ALGO
;
2357 if (g_strncasecmp(inbuf
, "<?xml version=\"1.0\"?>", 21) != 0) {
2361 gcry_cipher_close(gh
);
2363 return EPWMD_BADKEY
;
2367 client
->xml
= inbuf
;
2368 client
->len
= insize
;
2371 gcry_cipher_close(gh
);