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"
50 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
53 return gcry_calloc(items
, size
);
55 return calloc(items
, size
);
59 static void z_free(void *data
, void *p
)
68 static gpg_error_t
file_modified(struct client_s
*client
)
72 if (client
->state
!= STATE_OPEN
)
75 if (stat(client
->filename
, &st
) == 0 && client
->mtime
) {
76 if (client
->mtime
!= st
.st_mtime
)
77 return EPWMD_FILE_MODIFIED
;
83 static gboolean
encrypt_xml(gcry_cipher_hd_t gh
, void *outbuf
, gsize outsize
,
84 void *inbuf
, gsize insize
)
86 if ((gcryerrno
= gcry_cipher_encrypt(gh
, outbuf
, outsize
, inbuf
, insize
))) {
87 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
94 gboolean
decrypt_xml(gcry_cipher_hd_t gh
, void *outbuf
, gsize outsize
,
95 void *inbuf
, gsize insize
)
97 if ((gcryerrno
= gcry_cipher_decrypt(gh
, outbuf
, outsize
, inbuf
, insize
))) {
98 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
105 static gpg_error_t
parse_xml(assuan_context_t ctx
)
107 struct client_s
*client
= assuan_get_pointer(ctx
);
109 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
112 return EPWMD_LIBXML_ERROR
;
117 gboolean
valid_filename(const gchar
*filename
)
121 if (!filename
|| !*filename
)
124 for (p
= filename
; *p
; p
++) {
125 if (g_ascii_isalnum(*p
) == FALSE
&& *p
!= '-' && *p
!= '_' && *p
!= '.')
132 gint
open_file(const gchar
*filename
, struct stat
*st
)
136 if ((fd
= open(filename
, O_RDONLY
)) == -1)
139 if (stat(filename
, st
) == -1) {
147 static void cleanup_client(struct client_s
*client
)
149 assuan_context_t ctx
= client
->ctx
;
152 * This may be a new file so don't use a cache slot. save_command() will
153 * set this to FALSE on success.
155 if (client
->new == TRUE
)
156 cache_clear(client
->md5file
, 1);
159 xmlFreeDoc(client
->doc
);
162 gcry_free(client
->xml
);
164 if (client
->filename
)
165 g_free(client
->filename
);
167 gcry_cipher_close(client
->gh
);
168 memset(client
, 0, sizeof(struct client_s
));
169 client
->state
= STATE_CONNECTED
;
171 client
->freed
= TRUE
;
174 static gchar
*print_fmt(const char *fmt
, ...)
177 static gchar buf
[ASSUAN_LINELENGTH
] = {0};
180 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
185 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gint insize
,
186 gpointer
*out
, glong
*outsize
, gint
*error
)
198 z
.avail_out
= zlib_bufsize
;
199 z
.next_out
= pout
= g_malloc(zlib_bufsize
);
202 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
203 *error
= Z_MEM_ERROR
;
207 ret
= inflateInit2(&z
, 47);
210 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
215 memset(&h
, 0, sizeof(gz_header
));
216 h
.comment
= (guchar
*)buf
;
217 h
.comm_max
= sizeof(buf
);
218 ret
= inflateGetHeader(&z
, &h
);
221 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
227 ret
= inflate(&z
, Z_BLOCK
);
230 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
237 insize
= atoi((gchar
*)h
.comment
);
242 ret
= inflate(&z
, Z_FINISH
);
249 p
= g_realloc(pout
, z
.total_out
+ zlib_bufsize
);
257 z
.next_out
= pout
+ z
.total_out
;
258 z
.avail_out
= zlib_bufsize
;
261 assuan_write_status(ctx
, "DECOMPRESS",
262 print_fmt("%i %i", z
.total_out
, insize
));
271 } while (ret
!= Z_STREAM_END
);
274 assuan_write_status(ctx
, "DECOMPRESS",
275 print_fmt("%i %i", z
.total_out
, insize
));
278 *outsize
= z
.total_out
;
283 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
290 static int open_command(assuan_context_t ctx
, char *line
)
294 guchar shakey
[gcrykeysize
];
298 struct client_s
*client
= assuan_get_pointer(ctx
);
300 gchar
*filename
= NULL
;
304 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
307 if (!filename
|| !*filename
) {
309 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
312 if (valid_filename(filename
) == FALSE
) {
314 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
317 if (client
->state
== STATE_OPEN
)
318 cleanup_client(client
);
320 client
->freed
= FALSE
;
322 if ((gcryerrno
= gcry_cipher_open(&client
->gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0))) {
324 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
325 cleanup_client(client
);
326 return send_error(ctx
, gcryerrno
);
329 if (stat(filename
, &st
) == 0) {
330 if (!S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
331 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_INVALID_FILENAME
));
333 cleanup_client(client
);
334 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
337 client
->mtime
= st
.st_mtime
;
340 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
343 * New files don't need a key.
345 if (access(filename
, R_OK
|W_OK
) != 0) {
346 if (errno
!= ENOENT
) {
348 log_write("%s: %s", filename
, strerror(errno
));
350 cleanup_client(client
);
351 return send_syserror(ctx
, error
);
354 if ((client
->xml
= new_document()) == NULL
) {
355 log_write("%s", strerror(ENOMEM
));
357 cleanup_client(client
);
358 return send_syserror(ctx
, ENOMEM
);
361 client
->len
= xmlStrlen(client
->xml
);
363 if (cache_has_file(client
->md5file
) == TRUE
)
364 cache_clear(client
->md5file
, 1);
366 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
367 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
369 cleanup_client(client
);
370 return send_error(ctx
, EPWMD_MAX_SLOTS
);
374 client
->filename
= g_strdup(filename
);
376 if (!client
->filename
) {
378 cleanup_client(client
);
379 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
380 return send_syserror(ctx
, ENOMEM
);
383 if (req
[1] && *req
[1]) {
384 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, req
[1], strlen(req
[1]));
385 memset(req
[1], 0, strlen(req
[1]));
392 if ((fd
= open_file(filename
, &st
)) == -1) {
394 log_write("%s: %s", filename
, strerror(errno
));
396 cleanup_client(client
);
397 return send_syserror(ctx
, error
);
403 if (cache_get_key(client
->md5file
, shakey
) == TRUE
)
407 * No key specified and no matching filename found in the cache.
409 if (!req
[1] || !*req
[1]) {
412 cleanup_client(client
);
413 return send_error(ctx
, EPWMD_KEY
);
418 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, req
[1], strlen(req
[1]));
419 memset(req
[1], 0, strlen(req
[1]));
422 error
= try_xml_decrypt(ctx
, fd
, st
, shakey
);
426 memset(shakey
, 0, sizeof(shakey
));
428 cleanup_client(client
);
429 return send_error(ctx
, error
);
433 client
->filename
= g_strdup(filename
);
435 if (!client
->filename
) {
436 memset(shakey
, 0, sizeof(shakey
));
437 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
439 cleanup_client(client
);
440 return send_syserror(ctx
, ENOMEM
);
445 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
446 memset(shakey
, 0, sizeof(shakey
));
447 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
449 cleanup_client(client
);
450 return send_error(ctx
, EPWMD_MAX_SLOTS
);
453 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
454 cache_reset_timeout(client
->md5file
, timeout
);
457 cache_set_timeout(client
->md5file
, -2);
459 memset(shakey
, 0, sizeof(shakey
));
463 error
= parse_xml(ctx
);
466 gcry_free(client
->xml
);
471 client
->state
= STATE_OPEN
;
472 send_cache_status(ctx
);
475 return send_error(ctx
, error
);
478 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
479 gint size
, gpointer
*out
, glong
*outsize
, gint
*error
)
486 gint cmd
= Z_NO_FLUSH
;
490 z
.next_in
= pin
= data
;
491 z
.avail_in
= size
< zlib_bufsize
? size
: zlib_bufsize
;
492 z
.avail_out
= zlib_bufsize
;
493 z
.next_out
= pout
= g_malloc(zlib_bufsize
);
496 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
497 *error
= Z_MEM_ERROR
;
501 ret
= deflateInit2(&z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
504 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
510 memset(&h
, 0, sizeof(gz_header
));
511 snprintf(buf
, sizeof(buf
), "%i", size
);
512 h
.comment
= (guchar
*)buf
;
513 ret
= deflateSetHeader(&z
, &h
);
516 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
526 ret
= deflate(&z
, cmd
);
533 p
= g_realloc(pout
, z
.total_out
+ zlib_bufsize
);
541 z
.next_out
= pout
+ z
.total_out
;
542 z
.avail_out
= zlib_bufsize
;
545 if (!z
.avail_in
&& z
.total_in
< size
) {
546 if (z
.total_in
+ zlib_bufsize
> size
)
547 z
.avail_in
= size
- z
.total_in
;
549 z
.avail_in
= zlib_bufsize
;
552 assuan_write_status(ctx
, "COMPRESS",
553 print_fmt("%i %i", z
.total_in
, size
));
556 if (z
.total_in
>= size
)
565 } while (ret
!= Z_STREAM_END
);
568 assuan_write_status(ctx
, "COMPRESS",
569 print_fmt("%i %i", z
.total_in
, size
));
572 *outsize
= z
.total_out
;
577 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
584 gpg_error_t
do_xml_encrypt(struct client_s
*client
, gcry_cipher_hd_t gh
,
585 const gchar
*filename
, gpointer data
, size_t insize
,
586 const guchar
*shakey
, guint iter
)
591 guchar tkey
[gcrykeysize
];
594 guint iter_progress
= 0, n_iter
= 0, xiter
= 0;
595 struct file_header_s
{
597 guchar iv
[gcryblocksize
];
600 if (insize
/ gcryblocksize
) {
601 len
= (insize
/ gcryblocksize
) * gcryblocksize
;
603 if (insize
% gcryblocksize
)
604 len
+= gcryblocksize
;
608 * Resize the existing xml buffer to the block size required by gcrypt
609 * rather than duplicating it and wasting memory.
611 inbuf
= gcry_realloc(data
, len
);
614 return gpg_error_from_errno(ENOMEM
);
617 gcry_create_nonce(file_header
.iv
, sizeof(file_header
.iv
));
618 memcpy(tkey
, shakey
, sizeof(tkey
));
621 if ((gcryerrno
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
623 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
627 file_header
.iter
= iter
;
630 iter_progress
= get_key_file_integer("default", "iteration_progress");
632 if (client
&& iter_progress
&& file_header
.iter
>= iter_progress
)
633 assuan_write_status(client
->ctx
, "ENCRYPT", "0");
635 while (xiter
< file_header
.iter
) {
636 if (client
&& iter_progress
> 0 && xiter
>= iter_progress
) {
637 if (!(xiter
% iter_progress
))
638 assuan_write_status(client
->ctx
, "ENCRYPT", print_fmt("%i",
639 ++n_iter
* iter_progress
));
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 (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0)
652 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
659 if ((gcryerrno
= gcry_cipher_setiv(gh
, file_header
.iv
,
660 sizeof(file_header
.iv
)))) {
662 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
666 if ((gcryerrno
= gcry_cipher_setkey(gh
, shakey
, gcrykeysize
))) {
668 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
672 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
674 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
678 if (client
&& iter_progress
&& file_header
.iter
>= iter_progress
)
679 assuan_write_status(client
->ctx
, "ENCRYPT",
680 print_fmt("%i", file_header
.iter
));
683 if ((fd
= open(filename
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600)) == -1) {
686 p
= strrchr(filename
, '/');
688 log_write("%s: %s", p
, strerror(errno
));
689 return gpg_error_from_errno(error
);
694 * xml_import() from command line.
698 len
= write(fd
, &file_header
, sizeof(struct file_header_s
));
700 if (len
!= sizeof(file_header
)) {
707 return gpg_error_from_errno(len
);
710 len
= write(fd
, inbuf
, insize
);
719 return gpg_error_from_errno(len
);
729 static int save_command(assuan_context_t ctx
, char *line
)
735 guchar shakey
[gcrykeysize
];
738 struct client_s
*client
= assuan_get_pointer(ctx
);
746 error
= file_modified(client
);
749 log_write("%s: %s", client
->filename
? client
->filename
: "",
750 pwmd_strerror(error
));
751 return send_error(ctx
, error
);
754 if (stat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
755 return send_syserror(ctx
, errno
);
757 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
758 log_write("%s: %s", client
->filename
, pwmd_strerror(EPWMD_INVALID_FILENAME
));
759 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
762 if (!line
|| !*line
) {
763 if (cache_get_key(client
->md5file
, shakey
) == FALSE
)
764 return send_error(ctx
, EPWMD_KEY
);
769 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, line
, strlen(line
));
770 memset(line
, 0, strlen(line
));
773 xmlDocDumpFormatMemory(client
->doc
, &p
, &len
, 0);
776 iter
= get_key_file_integer(client
->filename
, "compression_level");
781 if (do_compress(ctx
, iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zerror
) == FALSE
) {
782 memset(shakey
, 0, sizeof(shakey
));
785 if (zerror
== Z_MEM_ERROR
) {
786 return send_syserror(ctx
, ENOMEM
);
789 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
797 if ((iter
= get_key_file_integer(client
->filename
, "iterations")) == -1)
800 error
= do_xml_encrypt(client
, client
->gh
, client
->filename
, xmlbuf
, len
, shakey
, iter
);
803 memset(shakey
, 0, sizeof(shakey
));
804 return send_error(ctx
, error
);
807 stat(client
->filename
, &st
);
808 client
->mtime
= st
.st_mtime
;
809 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
812 memset(shakey
, 0, sizeof(shakey
));
813 cache_reset_timeout(client
->md5file
, timeout
);
818 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
819 memset(shakey
, 0, sizeof(shakey
));
820 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
821 return send_error(ctx
, EPWMD_MAX_SLOTS
);
825 memset(shakey
, 0, sizeof(shakey
));
826 cache_reset_timeout(client
->md5file
, timeout
);
830 static gboolean
contains_whitespace(const gchar
*str
)
832 const gchar
*p
= str
;
836 len
= g_utf8_strlen(p
++, -1) -1;
839 c
= g_utf8_get_char(p
++);
841 if (g_unichar_isspace(c
))
848 static int delete_command(assuan_context_t ctx
, char *line
)
850 struct client_s
*client
= assuan_get_pointer(ctx
);
855 error
= file_modified(client
);
858 log_write("%s: %s", client
->filename
? client
->filename
: "",
859 pwmd_strerror(error
));
860 return send_error(ctx
, error
);
863 if (strchr(line
, '\t'))
864 req
= split_input_line(line
, "\t", -1);
866 req
= split_input_line(line
, " ", -1);
869 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
871 n
= find_account(client
->doc
, &req
, &error
, NULL
);
875 return send_error(ctx
, error
);
879 * No sub-node defined. Remove the entire node (account).
891 n
= find_elements(client
->doc
, n
->children
, req
+1, &error
, NULL
, NULL
, NULL
, NULL
);
895 return send_error(ctx
, error
);
905 static int store_command(assuan_context_t ctx
, char *line
)
907 struct client_s
*client
= assuan_get_pointer(ctx
);
914 error
= file_modified(client
);
917 log_write("%s: %s", client
->filename
? client
->filename
: "",
918 pwmd_strerror(error
));
919 return send_error(ctx
, error
);
922 error
= assuan_inquire(ctx
, "STORE", &result
, &len
, 0);
925 return send_error(ctx
, error
);
927 req
= split_input_line((gchar
*)result
, "\t", 0);
935 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
938 n
= find_account(client
->doc
, &req
, &error
, NULL
);
940 if (error
&& error
== EPWMD_ELEMENT_NOT_FOUND
) {
941 if (contains_whitespace(*req
) == TRUE
) {
943 return send_error(ctx
, EPWMD_INVALID_ELEMENT
);
946 error
= new_account(client
->doc
, *req
);
950 return send_error(ctx
, error
);
958 return send_error(ctx
, error
);
963 create_elements_cb(n
, req
+1, &error
, NULL
);
965 find_elements(client
->doc
, n
->children
, req
+1, &error
,
966 NULL
, NULL
, create_elements_cb
, NULL
);
970 return send_error(ctx
, error
);
973 static int get_command(assuan_context_t ctx
, char *line
)
975 struct client_s
*client
= assuan_get_pointer(ctx
);
980 error
= file_modified(client
);
983 log_write("%s: %s", client
->filename
? client
->filename
: "",
984 pwmd_strerror(error
));
985 return send_error(ctx
, error
);
988 req
= split_input_line(line
, "\t", -1);
992 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
995 n
= find_account(client
->doc
, &req
, &error
, NULL
);
999 return send_error(ctx
, error
);
1003 n
= find_elements(client
->doc
, n
->children
, req
+1, &error
, NULL
, NULL
, NULL
, NULL
);
1008 return send_error(ctx
, error
);
1010 if (!n
|| !n
->children
)
1011 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1015 if (!n
|| !n
->content
|| !*n
->content
)
1016 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1018 error
= assuan_send_data(ctx
, n
->content
, xmlStrlen(n
->content
));
1019 return send_error(ctx
, error
);
1022 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
)
1031 for (n
= 0; *p
&& n
< 3; p
++) {
1036 if (strstr((gchar
*)p
, "text()") != NULL
)
1037 p
[xmlStrlen(p
) - 7] = 0;
1039 for (n
= 0; p
[n
]; n
++) {
1044 buf
= g_strdup_printf("%s\t%s", account
, p
);
1048 gboolean
strv_printf(gchar
***array
, const gchar
*fmt
, ...)
1053 gint len
= *array
? g_strv_length(*array
) : 0;
1059 if ((a
= g_realloc(*array
, (len
+ 2) * sizeof(gchar
*))) == NULL
)
1063 ret
= g_vasprintf(&buf
, fmt
, ap
);
1079 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**req
,
1080 gpg_error_t
*error
, void *data
)
1082 struct realpath_s
*rp
= data
;
1085 g_free(rp
->account
);
1087 rp
->account
= g_strdup(req
[0]);
1090 *error
= gpg_error_from_errno(ENOMEM
);
1097 static int realpath_command(assuan_context_t ctx
, char *line
)
1100 struct client_s
*client
= assuan_get_pointer(ctx
);
1106 struct realpath_s
*rp
;
1109 error
= file_modified(client
);
1112 log_write("%s: %s", client
->filename
? client
->filename
: "",
1113 pwmd_strerror(error
));
1114 return send_error(ctx
, error
);
1117 if (strchr(line
, '\t') != NULL
) {
1118 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1119 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1122 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1123 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1126 n
= find_account(client
->doc
, &req
, &error
, NULL
);
1130 return send_error(ctx
, error
);
1133 rp
= g_malloc(sizeof(struct realpath_s
));
1137 return send_syserror(ctx
, ENOMEM
);
1140 rp
->account
= g_strdup(req
[0]);
1144 return send_syserror(ctx
, ENOMEM
);
1148 n
= find_elements(client
->doc
, n
->children
, req
+1, &error
,
1149 NULL
, realpath_elements_cb
, NULL
, rp
);
1152 g_free(rp
->account
);
1155 return send_error(ctx
, error
);
1159 p
= xmlGetNodePath(n
);
1160 result
= element_path_to_req(rp
->account
, p
);
1164 g_free(rp
->account
);
1168 return send_syserror(ctx
, ENOMEM
);
1171 string
= g_string_new(result
);
1173 g_free(rp
->account
);
1180 for (t
= string
->str
+ i
; *t
; t
++, i
++) {
1181 if (!i
|| *t
== '\t') {
1182 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1187 error
= assuan_send_data(ctx
, string
->str
, string
->len
);
1188 g_string_free(string
, TRUE
);
1189 return send_error(ctx
, error
);
1192 struct list_element_s
{
1197 static gboolean
append_to_element_list(struct list_element_s
*elements
)
1204 if (!elements
|| !elements
->elements
)
1207 tmp
= g_strjoinv("\t", elements
->elements
);
1212 g_strfreev(elements
->elements
);
1213 elements
->elements
= NULL
;
1214 total
= g_slist_length(elements
->list
);
1215 a
= g_utf8_collate_key(tmp
, -1);
1223 * Removes duplicate element paths from the list. This is needed when
1224 * appending an element tree from list_command(). The glib docs recommend
1225 * using g_utf8_collate_key() for a large number of strings.
1227 for (i
= 0; i
< total
; i
++) {
1228 gchar
*p
= g_slist_nth_data(elements
->list
, i
);
1229 gchar
*b
= g_utf8_collate_key(p
, -1);
1237 if (strcmp(a
, b
) == 0) {
1248 list
= g_slist_append(elements
->list
, tmp
);
1253 elements
->list
= list
;
1257 static gpg_error_t
do_list_recurse(xmlDocPtr doc
, xmlNodePtr node
,
1258 struct list_element_s
*elements
, gchar
*prefix
)
1263 if (append_to_element_list(elements
) == FALSE
)
1264 return gpg_error_from_errno(ENOMEM
);
1266 for (n
= node
; n
; n
= n
->next
) {
1267 if (n
->type
== XML_ELEMENT_NODE
) {
1268 xmlChar
*content
= node_has_attribute(n
, (xmlChar
*)"target");
1272 if (strv_printf(&elements
->elements
, "%s\t%s", prefix
, n
->name
) == FALSE
)
1273 return gpg_error_from_errno(ENOMEM
);
1275 if (append_to_element_list(elements
) == FALSE
)
1276 return gpg_error_from_errno(ENOMEM
);
1279 tmp
= g_strdup_printf("%s\t!%s", prefix
, n
->name
);
1282 return gpg_error_from_errno(ENOMEM
);
1284 if (strv_printf(&elements
->elements
, "%s", tmp
) == FALSE
) {
1286 return gpg_error_from_errno(ENOMEM
);
1290 error
= do_list_recurse(doc
, n
->children
, elements
, tmp
);
1293 if (error
&& error
!= EPWMD_ELEMENT_NOT_FOUND
)
1299 if (append_to_element_list(elements
) == FALSE
)
1300 return gpg_error_from_errno(ENOMEM
);
1307 static gpg_error_t
do_list_command(assuan_context_t ctx
, xmlDocPtr doc
,
1308 struct list_element_s
*elements
, char *line
)
1310 gchar
*prefix
= NULL
, *account
;
1311 gchar
**req
= NULL
, **oreq
= NULL
, *tmp
;
1313 gboolean account_is_literal
, account_has_target
= FALSE
;
1318 if ((req
= split_input_line(line
, "\t", 0)) == NULL
) {
1319 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1320 return EPWMD_COMMAND_SYNTAX
;
1323 prefix
= g_strdup(*req
);
1327 return gpg_error_from_errno(ENOMEM
);
1330 account
= g_strdup(*req
);
1335 return gpg_error_from_errno(ENOMEM
);
1338 oreq
= g_strdupv(req
);
1344 return gpg_error_from_errno(ENOMEM
);
1349 account_has_target
= FALSE
;
1350 account_is_literal
= is_literal_element_str(prefix
);
1351 n
= find_account(doc
, &p
, &error
, &account_has_target
);
1361 if (!which
&& account_is_literal
== FALSE
&& account_has_target
== FALSE
) {
1362 tmp
= g_strdup_printf("!%s", prefix
);
1365 error
= gpg_error_from_errno(ENOMEM
);
1376 n
= find_elements(doc
, n
->children
, p
+1, &error
,
1377 NULL
, NULL
, NULL
, NULL
);
1382 tmp
= g_strjoinv("\t", p
+1);
1384 error
= gpg_error_from_errno(ENOMEM
);
1388 t
= g_strdup_printf("%s\t%s", prefix
, tmp
);
1390 error
= gpg_error_from_errno(ENOMEM
);
1399 if (strv_printf(&elements
->elements
, "%s", prefix
) == FALSE
) {
1400 error
= gpg_error_from_errno(ENOMEM
);
1404 if (node_has_child_element(n
->children
) == FALSE
) {
1405 if (append_to_element_list(elements
) == FALSE
) {
1406 error
= gpg_error_from_errno(ENOMEM
);
1411 error
= do_list_recurse(doc
, n
->children
, elements
, prefix
);
1416 if (!which
++ && !*(p
+1) && account_is_literal
== FALSE
&& account_has_target
== TRUE
) {
1418 *oreq
= g_strdup_printf("!%s", account
);
1421 error
= gpg_error_from_errno(ENOMEM
);
1427 prefix
= g_strdup(*oreq
);
1430 error
= gpg_error_from_errno(ENOMEM
);
1449 * This could be faster especially when finding "target" attributes.
1451 static int list_command(assuan_context_t ctx
, char *line
)
1453 struct client_s
*client
= assuan_get_pointer(ctx
);
1455 struct list_element_s
*elements
= NULL
;
1460 if (disable_list_and_dump
== TRUE
)
1461 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1463 error
= file_modified(client
);
1466 log_write("%s: %s", client
->filename
, pwmd_strerror(error
));
1467 return send_error(ctx
, error
);
1473 error
= list_accounts(client
->doc
, &str
);
1476 return send_error(ctx
, error
);
1478 error
= assuan_send_data(ctx
, str
->str
, str
->len
);
1479 g_string_free(str
, TRUE
);
1480 return send_error(ctx
, error
);
1483 elements
= g_malloc0(sizeof(struct list_element_s
));
1486 error
= gpg_error_from_errno(ENOMEM
);
1490 is_list_command
= TRUE
;
1491 error
= do_list_command(ctx
, client
->doc
, elements
, line
);
1497 total
= g_slist_length(elements
->list
);
1500 error
= EPWMD_EMPTY_ELEMENT
;
1505 * Find element paths with a target and append those element trees to
1508 for (i
= 0; i
< total
; i
++) {
1511 tmp
= g_slist_nth_data(elements
->list
, i
);
1512 req
= split_input_line(tmp
, "\t", 0);
1515 if (g_str_has_prefix(tmp
, "!") == TRUE
) {
1523 for (p
= req
; *p
; p
++) {
1524 if (g_str_has_prefix(*p
, "!") == FALSE
)
1535 error
= do_list_command(ctx
, client
->doc
, elements
, tmp
);
1537 if (error
&& error
!= EPWMD_ELEMENT_NOT_FOUND
)
1540 total
= g_slist_length(elements
->list
);
1544 string
= g_string_new(NULL
);
1546 for (i
= 0; i
< total
; i
++) {
1547 tmp
= g_slist_nth_data(elements
->list
, i
);
1548 g_string_append_printf(string
, "%s\n", tmp
);
1552 string
= g_string_truncate(string
, string
->len
- 1);
1553 error
= assuan_send_data(ctx
, string
->str
, string
->len
);
1554 g_string_free(string
, TRUE
);
1557 is_list_command
= FALSE
;
1561 g_slist_free(elements
->list
);
1563 if (elements
->elements
)
1564 g_strfreev(elements
->elements
);
1569 return send_error(ctx
, error
);
1572 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1577 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1578 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1581 return EPWMD_LIBXML_ERROR
;
1584 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1590 * req[0] - element path
1592 static int attribute_list(assuan_context_t ctx
, gchar
**req
)
1594 struct client_s
*client
= assuan_get_pointer(ctx
);
1595 gchar
**attrlist
= NULL
;
1597 gchar
**path
= NULL
;
1603 if (!req
|| !req
[0])
1604 return EPWMD_COMMAND_SYNTAX
;
1606 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1608 * The first argument may be only an account.
1610 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1611 return EPWMD_COMMAND_SYNTAX
;
1614 n
= find_account(client
->doc
, &path
, &error
, NULL
);
1622 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
1623 NULL
, NULL
, NULL
, NULL
);
1633 for (a
= n
->properties
; a
; a
= a
->next
) {
1636 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1638 g_strfreev(attrlist
);
1641 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(errno
));
1642 return gpg_error_from_errno(error
);
1647 attrlist
[i
] = g_strdup_printf("%s\t%s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1650 g_strfreev(attrlist
);
1651 return gpg_error_from_errno(ENOMEM
);
1654 attrlist
[++i
] = NULL
;
1658 return EPWMD_EMPTY_ELEMENT
;
1660 line
= g_strjoinv("\n", attrlist
);
1663 g_strfreev(attrlist
);
1664 return gpg_error_from_errno(ENOMEM
);
1667 error
= assuan_send_data(ctx
, line
, g_utf8_strlen(line
, -1));
1669 g_strfreev(attrlist
);
1674 * req[0] - attribute
1675 * req[1] - element path
1677 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1681 gchar
**path
= NULL
;
1684 if (!req
|| !req
[0] || !req
[1])
1685 return EPWMD_COMMAND_SYNTAX
;
1687 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1689 * The first argument may be only an account.
1691 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1692 return EPWMD_COMMAND_SYNTAX
;
1696 * Don't remove the "name" attribute for the account element. To remove an
1697 * account use DELETE <account>.
1699 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
1700 error
= EPWMD_ATTR_SYNTAX
;
1704 n
= find_account(client
->doc
, &path
, &error
, NULL
);
1710 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
1711 NULL
, NULL
, NULL
, NULL
);
1719 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
1720 return EPWMD_ATTR_NOT_FOUND
;
1722 if (xmlRemoveProp(a
) == -1)
1723 return EPWMD_LIBXML_ERROR
;
1733 * Creates a "target" attribute. When other commands encounter an element with
1734 * this attribute, the element path is modified to the target value. If the
1735 * source element path doesn't exist when using 'ATTR SET target', it is
1736 * created, but the destination element path must exist.
1738 * req[0] - source element path
1739 * req[1] - destination element path
1741 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
1743 gchar
**src
, **dst
, *line
;
1747 if (!req
|| !req
[0] || !req
[1])
1748 return EPWMD_COMMAND_SYNTAX
;
1750 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1752 * The first argument may be only an account.
1754 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
1755 return EPWMD_COMMAND_SYNTAX
;
1758 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1760 * The first argument may be only an account.
1762 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
1763 error
= EPWMD_COMMAND_SYNTAX
;
1768 n
= find_account(client
->doc
, &dst
, &error
, NULL
);
1771 * Make sure the destination element path exists.
1777 n
= find_elements(client
->doc
, n
->children
, dst
+1, &error
,
1778 NULL
, NULL
, NULL
, NULL
);
1785 n
= find_account(client
->doc
, &src
, &error
, NULL
);
1788 if (error
== EPWMD_ELEMENT_NOT_FOUND
) {
1789 error
= new_account(client
->doc
, src
[0]);
1802 n
= create_target_elements_cb(n
, src
+1, &error
, NULL
);
1804 n
= find_elements(client
->doc
, n
->children
, src
+1, &error
,
1805 NULL
, NULL
, create_target_elements_cb
, NULL
);
1811 * Reset the position of the element tree now that the elements
1812 * have been created.
1814 n
= find_account(client
->doc
, &src
, &error
, NULL
);
1819 n
= find_elements(client
->doc
, n
->children
, src
+1, &error
,
1820 NULL
, NULL
, NULL
, NULL
);
1826 line
= g_strjoinv("\t", dst
);
1827 error
= add_attribute(n
, "target", line
);
1846 * req[0] - account name
1849 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
1855 tmp
= g_strdupv(req
);
1858 return gpg_error_from_errno(ENOMEM
);
1860 n
= find_account(client
->doc
, &tmp
, &error
, NULL
);
1866 if (g_utf8_collate(req
[0], req
[1]) == 0)
1870 * Will not overwrite an existing account.
1872 tmp
= g_strdupv(req
+1);
1875 return gpg_error_from_errno(ENOMEM
);
1877 n
= find_account(client
->doc
, &tmp
, &error
, NULL
);
1880 if (error
&& error
!= EPWMD_ELEMENT_NOT_FOUND
)
1884 return EPWMD_ACCOUNT_EXISTS
;
1887 * Whitespace not allowed in account names.
1889 if (contains_whitespace(req
[1]) == TRUE
)
1890 return EPWMD_ATTR_SYNTAX
;
1892 tmp
= g_strdupv(req
);
1895 return gpg_error_from_errno(ENOMEM
);
1897 n
= find_account(client
->doc
, &tmp
, &error
, NULL
);
1901 return EPWMD_ELEMENT_NOT_FOUND
;
1903 return add_attribute(n
, "name", req
[1]);
1907 * req[0] - attribute
1908 * req[1] - element path
1910 static int attribute_get(assuan_context_t ctx
, gchar
**req
)
1912 struct client_s
*client
= assuan_get_pointer(ctx
);
1918 if (!req
|| !req
[0] || !req
[1])
1919 return EPWMD_COMMAND_SYNTAX
;
1921 if (strchr(req
[1], '\t')) {
1922 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
1923 return EPWMD_COMMAND_SYNTAX
;
1926 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1927 return EPWMD_COMMAND_SYNTAX
;
1930 n
= find_account(client
->doc
, &path
, &error
, NULL
);
1936 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
1937 NULL
, NULL
, NULL
, NULL
);
1945 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
1946 return EPWMD_ATTR_NOT_FOUND
;
1948 error
= assuan_send_data(ctx
, a
, xmlStrlen(a
));
1958 * req[0] - attribute
1959 * req[1] - element path
1962 static int attribute_set(struct client_s
*client
, gchar
**req
)
1964 gchar
**path
= NULL
;
1968 if (!req
|| !req
[0] || !req
[1] || !req
[2])
1969 return EPWMD_COMMAND_SYNTAX
;
1972 * Reserved attribute names.
1974 if (g_utf8_collate(req
[0], "name") == 0) {
1976 * Only reserved for the account element. Not the rest of the
1979 if (strchr(req
[1], '\t') == NULL
)
1980 return name_attribute(client
, req
+ 1);
1982 else if (g_utf8_collate(req
[0], "target") == 0)
1983 return target_attribute(client
, req
+ 1);
1985 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1987 * The first argument may be only an account.
1989 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1990 return EPWMD_COMMAND_SYNTAX
;
1993 n
= find_account(client
->doc
, &path
, &error
, NULL
);
1999 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
2000 NULL
, NULL
, NULL
, NULL
);
2007 return add_attribute(n
, req
[0], req
[2]);
2016 * req[1] - attribute name or element path if command is LIST
2017 * req[2] - element path
2018 * req[2] - element path or value
2020 static int attr_command(assuan_context_t ctx
, char *line
)
2022 struct client_s
*client
= assuan_get_pointer(ctx
);
2023 gchar
**req
= split_input_line(line
, " ", 4);
2024 gpg_error_t error
= 0;
2026 error
= file_modified(client
);
2029 log_write("%s: %s", client
->filename
? client
->filename
: "",
2030 pwmd_strerror(error
));
2032 return send_error(ctx
, error
);
2035 if (!req
|| !req
[0] || !req
[1]) {
2037 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2040 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2041 error
= attribute_set(client
, req
+1);
2042 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2043 error
= attribute_get(ctx
, req
+1);
2044 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2045 error
= attribute_delete(client
, req
+1);
2046 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2047 error
= attribute_list(ctx
, req
+1);
2049 error
= EPWMD_COMMAND_SYNTAX
;
2052 return send_error(ctx
, error
);
2055 static int iscached_command(assuan_context_t ctx
, char *line
)
2057 gchar
**req
= split_input_line(line
, " ", 0);
2062 if (!req
|| !*req
) {
2064 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2067 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2070 if (cache_iscached(md5file
) == FALSE
)
2071 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2076 void send_cache_status(assuan_context_t ctx
)
2079 gint i
= MUTEX_OFFSET
;
2081 tmp
= print_fmt("%i %i",
2083 (i
/ sizeof(file_cache_t
)) - cache_file_count());
2086 assuan_write_status(ctx
, "CACHE", tmp
);
2089 static int clearcache_command(assuan_context_t ctx
, char *line
)
2091 struct client_s
*client
= assuan_get_pointer(ctx
);
2092 gchar
**req
= split_input_line(line
, " ", 0);
2097 if (!req
|| !*req
) {
2099 cache_clear(client
->md5file
, 2);
2100 send_cache_status(ctx
);
2104 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2106 cache_clear(md5file
, 1);
2107 send_cache_status(ctx
);
2111 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2115 gchar
**req
= split_input_line(line
, " ", 0);
2120 if (!req
|| !*req
|| !req
[1]) {
2122 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2126 timeout
= strtol(req
[0], &p
, 10);
2128 if (errno
!= 0 || *p
!= 0) {
2130 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2133 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2136 if (cache_set_timeout(md5file
, timeout
) == FALSE
)
2137 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2139 send_cache_status(ctx
);
2143 static int dump_command(assuan_context_t ctx
, char *line
)
2147 struct client_s
*client
= assuan_get_pointer(ctx
);
2150 if (disable_list_and_dump
== TRUE
)
2151 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2153 error
= file_modified(client
);
2156 log_write("%s: %s", client
->filename
? client
->filename
: "",
2157 pwmd_strerror(error
));
2158 return send_error(ctx
, error
);
2161 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2162 error
= assuan_send_data(ctx
, xml
, len
);
2167 static int getconfig_command(assuan_context_t ctx
, gchar
*line
)
2169 struct client_s
*client
= assuan_get_pointer(ctx
);
2170 gpg_error_t error
= 0;
2173 if (g_utf8_collate(line
, "key") == 0 || g_utf8_collate(line
, "key_file") == 0)
2174 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2176 p
= get_key_file_string(client
->filename
? client
->filename
: "default", line
);
2179 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2181 tmp
= expand_homedir(p
);
2184 error
= assuan_send_data(ctx
, p
, g_utf8_strlen(p
, -1));
2186 return send_error(ctx
, error
);
2189 void cleanup_assuan(assuan_context_t ctx
)
2191 struct client_s
*cl
= assuan_get_pointer(ctx
);
2197 gpg_error_t
register_commands(assuan_context_t ctx
)
2201 int (*handler
)(assuan_context_t
, char *line
);
2203 { "OPEN", open_command
},
2204 { "SAVE", save_command
},
2205 { "LIST", list_command
},
2206 { "REALPATH", realpath_command
},
2207 { "STORE", store_command
},
2208 { "DELETE", delete_command
},
2209 { "GET", get_command
},
2210 { "ATTR", attr_command
},
2211 { "ISCACHED", iscached_command
},
2212 { "CLEARCACHE", clearcache_command
},
2213 { "CACHETIMEOUT", cachetimeout_command
},
2214 { "GETCONFIG", getconfig_command
},
2215 { "DUMP", dump_command
},
2222 for (i
=0; table
[i
].name
; i
++) {
2223 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
2229 return assuan_register_bye_notify(ctx
, cleanup_assuan
);
2232 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, gint fd
, struct stat st
,
2238 guchar tkey
[gcrykeysize
];
2239 struct file_header_s
{
2241 guchar iv
[gcryblocksize
];
2243 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
2244 gcry_cipher_hd_t gh
;
2245 guint iter
= 0, n_iter
= 0;
2247 void *outbuf
= NULL
;
2252 gcryerrno
= gcry_cipher_open(&gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0);
2260 lseek(fd
, 0, SEEK_SET
);
2261 insize
= st
.st_size
- sizeof(struct file_header_s
);
2262 iv
= gcry_malloc(gcryblocksize
);
2266 gcry_cipher_close(gh
);
2268 return gpg_error_from_errno(ENOMEM
);
2271 len
= read(fd
, &file_header
, sizeof(struct file_header_s
));
2273 if (len
!= sizeof(file_header
)) {
2277 gcry_cipher_close(gh
);
2281 return gpg_error_from_errno(errno
);
2284 memcpy(iv
, &file_header
.iv
, sizeof(file_header
.iv
));
2285 inbuf
= gcry_malloc(insize
);
2289 gcry_cipher_close(gh
);
2292 return gpg_error_from_errno(ENOMEM
);
2295 len
= read(fd
, inbuf
, insize
);
2297 if (len
!= insize
) {
2301 gcry_cipher_close(gh
);
2305 return gpg_error_from_errno(errno
);
2308 memcpy(tkey
, key
, sizeof(tkey
));
2311 if ((gcryerrno
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
2313 gcry_cipher_close(gh
);
2314 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2317 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2324 if ((gcryerrno
= gcry_cipher_setkey(gh
, key
, gcrykeysize
))) {
2326 gcry_cipher_close(gh
);
2327 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2330 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2336 gcry_cipher_close(gh
);
2341 iter_progress
= get_key_file_integer("default", "iteration_progress");
2343 if (ctx
&& iter_progress
> 0 && file_header
.iter
>= iter_progress
)
2344 assuan_write_status(client
->ctx
, "DECRYPT", "0");
2346 if (decrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
2348 gcry_cipher_close(gh
);
2349 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2352 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2359 if ((gcryerrno
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
2361 gcry_cipher_close(gh
);
2362 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2365 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2372 while (iter
< file_header
.iter
) {
2373 if (ctx
&& iter_progress
> 0 && iter
>= iter_progress
) {
2374 if (!(iter
% iter_progress
))
2375 assuan_write_status(ctx
, "DECRYPT", print_fmt("%i",
2376 ++n_iter
* iter_progress
));
2379 if ((gcryerrno
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
2381 gcry_cipher_close(gh
);
2382 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2385 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2392 if (decrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
2394 gcry_cipher_close(gh
);
2395 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2398 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
2408 if (ctx
&& iter_progress
&& file_header
.iter
>= iter_progress
)
2409 assuan_write_status(ctx
, "DECRYPT", print_fmt("%i", file_header
.iter
));
2413 if (do_decompress(ctx
, inbuf
, insize
, &outbuf
, &outsize
, &zerror
) == FALSE
) {
2415 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2417 if (zerror
== Z_MEM_ERROR
) {
2419 return gpg_error_from_errno(ENOMEM
);
2421 else if (zerror
!= Z_DATA_ERROR
) {
2425 gcry_cipher_close(gh
);
2427 return EPWMD_BADKEY
;
2436 if (g_strncasecmp(inbuf
, "<?xml version=\"1.0\"?>", 21) != 0) {
2440 gcry_cipher_close(gh
);
2442 return EPWMD_BADKEY
;
2446 client
->xml
= inbuf
;
2447 client
->len
= insize
;
2450 gcry_cipher_close(gh
);