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
)
88 if ((rc
= gcry_cipher_encrypt(gh
, outbuf
, outsize
, inbuf
, insize
))) {
89 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
96 gpg_error_t
decrypt_xml(gcry_cipher_hd_t gh
, void *outbuf
, gsize outsize
,
97 void *inbuf
, gsize insize
)
101 if ((rc
= gcry_cipher_decrypt(gh
, outbuf
, outsize
, inbuf
, insize
)))
102 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
107 static gpg_error_t
parse_xml(assuan_context_t ctx
)
109 struct client_s
*client
= assuan_get_pointer(ctx
);
111 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
114 return EPWMD_LIBXML_ERROR
;
119 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_client(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
);
187 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gint insize
,
188 gpointer
*out
, glong
*outsize
, gint
*error
)
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
= inflateInit2(&z
, 47);
213 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
218 memset(&h
, 0, sizeof(gz_header
));
219 h
.comment
= (guchar
*)buf
;
220 h
.comm_max
= sizeof(buf
);
221 ret
= inflateGetHeader(&z
, &h
);
224 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
230 ret
= inflate(&z
, Z_BLOCK
);
233 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
240 insize
= atoi((gchar
*)h
.comment
);
245 ret
= inflate(&z
, Z_FINISH
);
252 p
= g_realloc(pout
, z
.total_out
+ zlib_bufsize
);
260 z
.next_out
= pout
+ z
.total_out
;
261 z
.avail_out
= zlib_bufsize
;
264 rc
= assuan_write_status(ctx
, "DECOMPRESS",
265 print_fmt("%i %i", z
.total_out
, insize
));
282 } while (ret
!= Z_STREAM_END
);
285 rc
= assuan_write_status(ctx
, "DECOMPRESS",
286 print_fmt("%i %i", z
.total_out
, insize
));
295 *outsize
= z
.total_out
;
300 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
307 static int open_command(assuan_context_t ctx
, char *line
)
311 guchar shakey
[gcrykeysize
];
315 struct client_s
*client
= assuan_get_pointer(ctx
);
317 gchar
*filename
= NULL
;
319 CACHE_LOCK(ctx
, NULL
);
321 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
324 if (!filename
|| !*filename
) {
326 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
329 if (valid_filename(filename
) == FALSE
) {
331 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
334 if (client
->state
== STATE_OPEN
)
335 cleanup_client(client
);
337 client
->freed
= FALSE
;
339 if ((error
= gcry_cipher_open(&client
->gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0))) {
341 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
342 cleanup_client(client
);
343 return send_error(ctx
, error
);
346 if (stat(filename
, &st
) == 0) {
347 if (!S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
348 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_INVALID_FILENAME
));
350 cleanup_client(client
);
351 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
354 client
->mtime
= st
.st_mtime
;
357 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
360 * New files don't need a key.
362 if (access(filename
, R_OK
|W_OK
) != 0) {
363 if (errno
!= ENOENT
) {
365 log_write("%s: %s", filename
, strerror(errno
));
367 cleanup_client(client
);
368 return send_syserror(ctx
, error
);
371 if ((client
->xml
= new_document()) == NULL
) {
372 log_write("%s", strerror(ENOMEM
));
374 cleanup_client(client
);
375 return send_syserror(ctx
, ENOMEM
);
378 client
->len
= xmlStrlen(client
->xml
);
380 if (cache_has_file(client
->md5file
) == TRUE
)
381 cache_clear(client
->md5file
, 1);
383 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
384 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
386 cleanup_client(client
);
387 return send_error(ctx
, EPWMD_MAX_SLOTS
);
391 client
->filename
= g_strdup(filename
);
393 if (!client
->filename
) {
395 cleanup_client(client
);
396 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
397 return send_syserror(ctx
, ENOMEM
);
400 if (req
[1] && *req
[1]) {
401 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, req
[1], strlen(req
[1]));
402 memset(req
[1], 0, strlen(req
[1]));
409 if ((fd
= open_file(filename
, &st
)) == -1) {
411 log_write("%s: %s", filename
, strerror(errno
));
413 cleanup_client(client
);
414 return send_syserror(ctx
, error
);
420 if (cache_get_key(client
->md5file
, shakey
) == TRUE
)
424 * No key specified and no matching filename found in the cache.
426 if (!req
[1] || !*req
[1]) {
429 cleanup_client(client
);
430 return send_error(ctx
, EPWMD_KEY
);
435 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, req
[1], strlen(req
[1]));
436 memset(req
[1], 0, strlen(req
[1]));
439 error
= try_xml_decrypt(ctx
, fd
, st
, shakey
);
443 memset(shakey
, 0, sizeof(shakey
));
445 cleanup_client(client
);
446 return send_error(ctx
, error
);
450 client
->filename
= g_strdup(filename
);
452 if (!client
->filename
) {
453 memset(shakey
, 0, sizeof(shakey
));
454 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
456 cleanup_client(client
);
457 return send_syserror(ctx
, ENOMEM
);
462 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
463 memset(shakey
, 0, sizeof(shakey
));
464 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
466 cleanup_client(client
);
467 return send_error(ctx
, EPWMD_MAX_SLOTS
);
470 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
471 cache_reset_timeout(client
->md5file
, timeout
);
474 cache_set_timeout(client
->md5file
, -2);
476 memset(shakey
, 0, sizeof(shakey
));
480 error
= parse_xml(ctx
);
483 gcry_free(client
->xml
);
488 client
->state
= STATE_OPEN
;
490 return send_error(ctx
, error
);
493 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
494 gint size
, gpointer
*out
, glong
*outsize
, gint
*error
)
501 gint cmd
= Z_NO_FLUSH
;
506 z
.next_in
= pin
= data
;
507 z
.avail_in
= size
< zlib_bufsize
? size
: zlib_bufsize
;
508 z
.avail_out
= zlib_bufsize
;
509 z
.next_out
= pout
= g_malloc(zlib_bufsize
);
512 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
513 *error
= Z_MEM_ERROR
;
517 ret
= deflateInit2(&z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
520 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
526 memset(&h
, 0, sizeof(gz_header
));
527 snprintf(buf
, sizeof(buf
), "%i", size
);
528 h
.comment
= (guchar
*)buf
;
529 ret
= deflateSetHeader(&z
, &h
);
532 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
542 ret
= deflate(&z
, cmd
);
549 p
= g_realloc(pout
, z
.total_out
+ zlib_bufsize
);
557 z
.next_out
= pout
+ z
.total_out
;
558 z
.avail_out
= zlib_bufsize
;
561 if (!z
.avail_in
&& z
.total_in
< size
) {
562 if (z
.total_in
+ zlib_bufsize
> size
)
563 z
.avail_in
= size
- z
.total_in
;
565 z
.avail_in
= zlib_bufsize
;
568 rc
= assuan_write_status(ctx
, "COMPRESS",
569 print_fmt("%i %i", z
.total_in
, size
));
578 if (z
.total_in
>= size
)
589 } while (ret
!= Z_STREAM_END
);
592 rc
= assuan_write_status(ctx
, "COMPRESS",
593 print_fmt("%i %i", z
.total_in
, size
));
602 *outsize
= z
.total_out
;
607 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
614 gpg_error_t
do_xml_encrypt(struct client_s
*client
, gcry_cipher_hd_t gh
,
615 const gchar
*filename
, gpointer data
, size_t insize
,
616 const guchar
*shakey
, guint iter
)
621 guchar tkey
[gcrykeysize
];
625 guint iter_progress
= 0, n_iter
= 0, xiter
= 0;
626 gchar tmp
[FILENAME_MAX
];
627 struct file_header_s
{
629 guchar iv
[gcryblocksize
];
632 if (insize
/ gcryblocksize
) {
633 len
= (insize
/ gcryblocksize
) * gcryblocksize
;
635 if (insize
% gcryblocksize
)
636 len
+= gcryblocksize
;
640 * Resize the existing xml buffer to the block size required by gcrypt
641 * rather than duplicating it and wasting memory.
643 inbuf
= gcry_realloc(data
, len
);
646 return gpg_error_from_errno(ENOMEM
);
649 gcry_create_nonce(file_header
.iv
, sizeof(file_header
.iv
));
650 memcpy(tkey
, shakey
, sizeof(tkey
));
653 if ((rc
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
655 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
659 file_header
.iter
= iter
;
662 iter_progress
= get_key_file_integer("default", "iteration_progress");
664 if (client
&& iter_progress
&& file_header
.iter
>= iter_progress
) {
665 error
= assuan_write_status(client
->ctx
, "ENCRYPT", "0");
673 while (xiter
< file_header
.iter
) {
674 if (client
&& iter_progress
> 0 && xiter
>= iter_progress
) {
675 if (!(xiter
% iter_progress
)) {
676 error
= assuan_write_status(client
->ctx
, "ENCRYPT", print_fmt("%i",
677 ++n_iter
* iter_progress
));
686 if ((rc
= gcry_cipher_setiv(gh
, file_header
.iv
,
687 sizeof(file_header
.iv
)))) {
689 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
693 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0)
696 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
704 if ((rc
= gcry_cipher_setiv(gh
, file_header
.iv
,
705 sizeof(file_header
.iv
)))) {
707 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
711 if ((rc
= gcry_cipher_setkey(gh
, shakey
, gcrykeysize
))) {
713 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
717 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
719 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
723 if (client
&& iter_progress
&& file_header
.iter
>= iter_progress
) {
724 error
= assuan_write_status(client
->ctx
, "ENCRYPT",
725 print_fmt("%i", file_header
.iter
));
734 g_snprintf(tmp
, sizeof(tmp
), ".%s.tmp", filename
);
736 if ((fd
= open(tmp
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600)) == -1) {
739 p
= strrchr(tmp
, '/');
741 log_write("%s: %s", p
, strerror(errno
));
742 return gpg_error_from_errno(error
);
747 * xml_import() from command line.
751 len
= pth_write(fd
, &file_header
, sizeof(struct file_header_s
));
753 if (len
!= sizeof(file_header
)) {
760 return gpg_error_from_errno(len
);
763 len
= pth_write(fd
, inbuf
, insize
);
772 return gpg_error_from_errno(len
);
775 if (fsync(fd
) == -1) {
779 return gpg_error_from_errno(len
);
788 if (stat(filename
, &st
) == 0)
789 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
791 if (rename(tmp
, filename
) == -1) {
794 return gpg_error_from_errno(len
);
798 chmod(filename
, mode
);
805 static int save_command(assuan_context_t ctx
, char *line
)
811 guchar shakey
[gcrykeysize
];
814 struct client_s
*client
= assuan_get_pointer(ctx
);
821 CACHE_LOCK(ctx
, NULL
);
822 error
= file_modified(client
);
825 log_write("%s: %s", client
->filename
? client
->filename
: "",
826 pwmd_strerror(error
));
827 return send_error(ctx
, error
);
830 if (stat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
831 return send_syserror(ctx
, errno
);
833 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
834 log_write("%s: %s", client
->filename
, pwmd_strerror(EPWMD_INVALID_FILENAME
));
835 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
838 if (!line
|| !*line
) {
839 if (cache_get_key(client
->md5file
, shakey
) == FALSE
)
840 return send_error(ctx
, EPWMD_KEY
);
845 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, line
, strlen(line
));
846 memset(line
, 0, strlen(line
));
849 xmlDocDumpFormatMemory(client
->doc
, &p
, &len
, 0);
852 iter
= get_key_file_integer(client
->filename
, "compression_level");
857 if (do_compress(ctx
, iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zerror
) == FALSE
) {
858 memset(shakey
, 0, sizeof(shakey
));
861 if (zerror
== Z_MEM_ERROR
) {
862 return send_syserror(ctx
, ENOMEM
);
865 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
873 if ((iter
= get_key_file_integer(client
->filename
, "iterations")) == -1)
876 error
= do_xml_encrypt(client
, client
->gh
, client
->filename
, xmlbuf
, len
, shakey
, iter
);
879 memset(shakey
, 0, sizeof(shakey
));
880 return send_error(ctx
, error
);
883 stat(client
->filename
, &st
);
884 client
->mtime
= st
.st_mtime
;
885 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
888 memset(shakey
, 0, sizeof(shakey
));
889 cache_reset_timeout(client
->md5file
, timeout
);
891 return send_error(ctx
, 0);
894 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
895 memset(shakey
, 0, sizeof(shakey
));
896 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
897 return send_error(ctx
, EPWMD_MAX_SLOTS
);
901 memset(shakey
, 0, sizeof(shakey
));
902 cache_reset_timeout(client
->md5file
, timeout
);
903 return send_error(ctx
, 0);
906 static gboolean
contains_whitespace(const gchar
*str
)
908 const gchar
*p
= str
;
912 len
= g_utf8_strlen(p
++, -1) -1;
915 c
= g_utf8_get_char(p
++);
917 if (g_unichar_isspace(c
))
924 static int delete_command(assuan_context_t ctx
, char *line
)
926 struct client_s
*client
= assuan_get_pointer(ctx
);
931 error
= file_modified(client
);
934 log_write("%s: %s", client
->filename
? client
->filename
: "",
935 pwmd_strerror(error
));
936 return send_error(ctx
, error
);
939 if (strchr(line
, '\t'))
940 req
= split_input_line(line
, "\t", -1);
942 req
= split_input_line(line
, " ", -1);
945 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
947 n
= find_account(client
->doc
, &req
, &error
, NULL
, 0);
951 return send_error(ctx
, error
);
955 * No sub-node defined. Remove the entire node (account).
964 return send_error(ctx
, 0);
967 n
= find_elements(client
->doc
, n
->children
, req
+1, &error
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
971 return send_error(ctx
, error
);
978 return send_error(ctx
, 0);
982 * Don't return with assuan_process_done() here. This has been called from
983 * assuan_process_next() and the command should be finished in
986 #define INQUIRE_RETURN(client, rc) {client->inquire_error = rc; return rc;}
988 static int store_command_finalize(gpointer data
, gint rc
, guchar
*line
,
991 assuan_context_t ctx
= data
;
992 struct client_s
*client
= assuan_get_pointer(ctx
);
994 guchar
*result
= line
;
996 gpg_error_t error
= file_modified(client
);
1008 req
= split_input_line((gchar
*)result
, "\t", 0);
1019 INQUIRE_RETURN(client
, rc
);
1023 INQUIRE_RETURN(client
, EPWMD_COMMAND_SYNTAX
);
1026 n
= find_account(client
->doc
, &req
, &error
, NULL
, 0);
1028 if (error
&& error
== EPWMD_ELEMENT_NOT_FOUND
) {
1029 if (contains_whitespace(*req
) == TRUE
) {
1031 INQUIRE_RETURN(client
, EPWMD_INVALID_ELEMENT
);
1034 error
= new_account(client
->doc
, *req
);
1038 INQUIRE_RETURN(client
, error
);
1046 INQUIRE_RETURN(client
, error
);
1051 create_elements_cb(n
, req
+1, &error
, NULL
);
1053 find_elements(client
->doc
, n
->children
, req
+1, &error
,
1054 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
);
1058 client
->inquire
= INQUIRE_OK
;
1059 INQUIRE_RETURN(client
, error
);
1062 static int store_command(assuan_context_t ctx
, char *line
)
1064 struct client_s
*client
= assuan_get_pointer(ctx
);
1065 gpg_error_t error
= file_modified(client
);
1068 log_write("%s: %s", client
->filename
? client
->filename
: "",
1069 pwmd_strerror(error
));
1070 return send_error(ctx
, error
);
1073 error
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1076 return send_error(ctx
, error
);
1078 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1079 client
->inquire
= INQUIRE_INPROGRESS
;
1083 static int get_command(assuan_context_t ctx
, char *line
)
1085 struct client_s
*client
= assuan_get_pointer(ctx
);
1090 error
= file_modified(client
);
1093 log_write("%s: %s", client
->filename
? client
->filename
: "",
1094 pwmd_strerror(error
));
1095 return send_error(ctx
, error
);
1098 req
= split_input_line(line
, "\t", -1);
1100 if (!req
|| !*req
) {
1102 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1105 n
= find_account(client
->doc
, &req
, &error
, NULL
, 0);
1109 return send_error(ctx
, error
);
1113 n
= find_elements(client
->doc
, n
->children
, req
+1, &error
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1118 return send_error(ctx
, error
);
1120 if (!n
|| !n
->children
)
1121 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1125 if (!n
|| !n
->content
|| !*n
->content
)
1126 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1128 error
= assuan_send_data(ctx
, n
->content
, xmlStrlen(n
->content
));
1129 return send_error(ctx
, error
);
1132 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
)
1141 for (n
= 0; *p
&& n
< 3; p
++) {
1146 if (strstr((gchar
*)p
, "text()") != NULL
)
1147 p
[xmlStrlen(p
) - 7] = 0;
1149 for (n
= 0; p
[n
]; n
++) {
1154 buf
= g_strdup_printf("%s\t%s", account
, p
);
1158 gboolean
strv_printf(gchar
***array
, const gchar
*fmt
, ...)
1163 gint len
= *array
? g_strv_length(*array
) : 0;
1169 if ((a
= g_realloc(*array
, (len
+ 2) * sizeof(gchar
*))) == NULL
)
1173 ret
= g_vasprintf(&buf
, fmt
, ap
);
1189 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**req
,
1190 gpg_error_t
*error
, void *data
)
1192 struct realpath_s
*rp
= data
;
1195 g_free(rp
->account
);
1197 rp
->account
= g_strdup(req
[0]);
1200 *error
= gpg_error_from_errno(ENOMEM
);
1207 static int realpath_command(assuan_context_t ctx
, char *line
)
1210 struct client_s
*client
= assuan_get_pointer(ctx
);
1216 struct realpath_s
*rp
;
1219 error
= file_modified(client
);
1222 log_write("%s: %s", client
->filename
? client
->filename
: "",
1223 pwmd_strerror(error
));
1224 return send_error(ctx
, error
);
1227 if (strchr(line
, '\t') != NULL
) {
1228 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1229 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1232 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1233 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1236 n
= find_account(client
->doc
, &req
, &error
, NULL
, 0);
1240 return send_error(ctx
, error
);
1243 rp
= g_malloc(sizeof(struct realpath_s
));
1247 return send_syserror(ctx
, ENOMEM
);
1250 rp
->account
= g_strdup(req
[0]);
1254 return send_syserror(ctx
, ENOMEM
);
1258 n
= find_elements(client
->doc
, n
->children
, req
+1, &error
,
1259 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, rp
);
1262 g_free(rp
->account
);
1265 return send_error(ctx
, error
);
1269 p
= xmlGetNodePath(n
);
1270 result
= element_path_to_req(rp
->account
, p
);
1274 g_free(rp
->account
);
1278 return send_syserror(ctx
, ENOMEM
);
1281 string
= g_string_new(result
);
1283 g_free(rp
->account
);
1290 for (t
= string
->str
+ i
; *t
; t
++, i
++) {
1291 if (!i
|| *t
== '\t') {
1292 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1297 error
= assuan_send_data(ctx
, string
->str
, string
->len
);
1298 g_string_free(string
, TRUE
);
1299 return send_error(ctx
, error
);
1302 struct list_element_s
{
1307 static gboolean
append_to_element_list(struct list_element_s
*elements
)
1314 if (!elements
|| !elements
->elements
)
1317 tmp
= g_strjoinv("\t", elements
->elements
);
1322 g_strfreev(elements
->elements
);
1323 elements
->elements
= NULL
;
1324 total
= g_slist_length(elements
->list
);
1325 a
= g_utf8_collate_key(tmp
, -1);
1333 * Removes duplicate element paths from the list. This is needed when
1334 * appending an element tree from list_command(). The glib docs recommend
1335 * using g_utf8_collate_key() for a large number of strings.
1337 for (i
= 0; i
< total
; i
++) {
1338 gchar
*p
= g_slist_nth_data(elements
->list
, i
);
1339 gchar
*b
= g_utf8_collate_key(p
, -1);
1347 if (strcmp(a
, b
) == 0) {
1358 list
= g_slist_append(elements
->list
, tmp
);
1363 elements
->list
= list
;
1367 static gpg_error_t
do_list_recurse(xmlDocPtr doc
, xmlNodePtr node
,
1368 struct list_element_s
*elements
, gchar
*prefix
)
1373 if (append_to_element_list(elements
) == FALSE
)
1374 return gpg_error_from_errno(ENOMEM
);
1376 for (n
= node
; n
; n
= n
->next
) {
1377 if (n
->type
== XML_ELEMENT_NODE
) {
1378 xmlChar
*content
= node_has_attribute(n
, (xmlChar
*)"target");
1382 if (strv_printf(&elements
->elements
, "%s\t%s", prefix
, n
->name
) == FALSE
)
1383 return gpg_error_from_errno(ENOMEM
);
1385 if (append_to_element_list(elements
) == FALSE
)
1386 return gpg_error_from_errno(ENOMEM
);
1389 tmp
= g_strdup_printf("%s\t!%s", prefix
, n
->name
);
1392 return gpg_error_from_errno(ENOMEM
);
1394 if (strv_printf(&elements
->elements
, "%s", tmp
) == FALSE
) {
1396 return gpg_error_from_errno(ENOMEM
);
1400 error
= do_list_recurse(doc
, n
->children
, elements
, tmp
);
1403 if (error
&& error
!= EPWMD_ELEMENT_NOT_FOUND
)
1409 if (append_to_element_list(elements
) == FALSE
)
1410 return gpg_error_from_errno(ENOMEM
);
1417 static gpg_error_t
do_list_command(assuan_context_t ctx
, xmlDocPtr doc
,
1418 struct list_element_s
*elements
, char *line
)
1420 gchar
*prefix
= NULL
, *account
;
1421 gchar
**req
= NULL
, **oreq
= NULL
, *tmp
;
1423 gboolean account_is_literal
, account_has_target
= FALSE
;
1428 if ((req
= split_input_line(line
, "\t", 0)) == NULL
) {
1429 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1430 return EPWMD_COMMAND_SYNTAX
;
1433 prefix
= g_strdup(*req
);
1437 return gpg_error_from_errno(ENOMEM
);
1440 account
= g_strdup(*req
);
1445 return gpg_error_from_errno(ENOMEM
);
1448 oreq
= g_strdupv(req
);
1454 return gpg_error_from_errno(ENOMEM
);
1459 account_has_target
= FALSE
;
1460 account_is_literal
= is_literal_element_str(prefix
);
1461 n
= find_account(doc
, &p
, &error
, &account_has_target
, 0);
1471 if (!which
&& account_is_literal
== FALSE
&& account_has_target
== FALSE
) {
1472 tmp
= g_strdup_printf("!%s", prefix
);
1475 error
= gpg_error_from_errno(ENOMEM
);
1486 n
= find_elements(doc
, n
->children
, p
+1, &error
, NULL
, NULL
, NULL
,
1492 tmp
= g_strjoinv("\t", p
+1);
1494 error
= gpg_error_from_errno(ENOMEM
);
1498 t
= g_strdup_printf("%s\t%s", prefix
, tmp
);
1500 error
= gpg_error_from_errno(ENOMEM
);
1509 if (strv_printf(&elements
->elements
, "%s", prefix
) == FALSE
) {
1510 error
= gpg_error_from_errno(ENOMEM
);
1514 if (node_has_child_element(n
->children
) == FALSE
) {
1515 if (append_to_element_list(elements
) == FALSE
) {
1516 error
= gpg_error_from_errno(ENOMEM
);
1521 error
= do_list_recurse(doc
, n
->children
, elements
, prefix
);
1526 if (!which
++ && !*(p
+1) && account_is_literal
== FALSE
&& account_has_target
== TRUE
) {
1528 *oreq
= g_strdup_printf("!%s", account
);
1531 error
= gpg_error_from_errno(ENOMEM
);
1537 prefix
= g_strdup(*oreq
);
1540 error
= gpg_error_from_errno(ENOMEM
);
1559 * This could be faster especially when finding "target" attributes.
1561 static int list_command(assuan_context_t ctx
, char *line
)
1563 struct client_s
*client
= assuan_get_pointer(ctx
);
1565 struct list_element_s
*elements
= NULL
;
1570 if (disable_list_and_dump
== TRUE
)
1571 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1573 error
= file_modified(client
);
1576 log_write("%s: %s", client
->filename
, pwmd_strerror(error
));
1577 return send_error(ctx
, error
);
1583 error
= list_accounts(client
->doc
, &str
);
1586 return send_error(ctx
, error
);
1588 error
= assuan_send_data(ctx
, str
->str
, str
->len
);
1589 g_string_free(str
, TRUE
);
1590 return send_error(ctx
, error
);
1593 elements
= g_malloc0(sizeof(struct list_element_s
));
1596 error
= gpg_error_from_errno(ENOMEM
);
1600 error
= do_list_command(ctx
, client
->doc
, elements
, line
);
1606 total
= g_slist_length(elements
->list
);
1609 error
= EPWMD_EMPTY_ELEMENT
;
1614 * Find element paths with a target and append those element trees to
1617 for (i
= 0; i
< total
; i
++) {
1620 tmp
= g_slist_nth_data(elements
->list
, i
);
1621 req
= split_input_line(tmp
, "\t", 0);
1624 if (g_str_has_prefix(tmp
, "!") == TRUE
) {
1632 for (p
= req
; *p
; p
++) {
1633 if (g_str_has_prefix(*p
, "!") == FALSE
)
1644 error
= do_list_command(ctx
, client
->doc
, elements
, tmp
);
1646 if (error
&& error
!= EPWMD_ELEMENT_NOT_FOUND
)
1649 total
= g_slist_length(elements
->list
);
1653 string
= g_string_new(NULL
);
1655 for (i
= 0; i
< total
; i
++) {
1656 tmp
= g_slist_nth_data(elements
->list
, i
);
1657 g_string_append_printf(string
, "%s\n", tmp
);
1661 string
= g_string_truncate(string
, string
->len
- 1);
1662 error
= assuan_send_data(ctx
, string
->str
, string
->len
);
1663 g_string_free(string
, TRUE
);
1668 g_slist_free(elements
->list
);
1670 if (elements
->elements
)
1671 g_strfreev(elements
->elements
);
1676 return send_error(ctx
, error
);
1679 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1684 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1685 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1688 return EPWMD_LIBXML_ERROR
;
1691 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1697 * req[0] - element path
1699 static int attribute_list(assuan_context_t ctx
, gchar
**req
)
1701 struct client_s
*client
= assuan_get_pointer(ctx
);
1702 gchar
**attrlist
= NULL
;
1704 gchar
**path
= NULL
;
1710 if (!req
|| !req
[0])
1711 return EPWMD_COMMAND_SYNTAX
;
1713 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1715 * The first argument may be only an account.
1717 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1718 return EPWMD_COMMAND_SYNTAX
;
1721 n
= find_account(client
->doc
, &path
, &error
, NULL
, 0);
1729 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
1730 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1740 for (a
= n
->properties
; a
; a
= a
->next
) {
1743 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1745 g_strfreev(attrlist
);
1748 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(errno
));
1749 return gpg_error_from_errno(error
);
1754 attrlist
[i
] = g_strdup_printf("%s\t%s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1757 g_strfreev(attrlist
);
1758 return gpg_error_from_errno(ENOMEM
);
1761 attrlist
[++i
] = NULL
;
1765 return EPWMD_EMPTY_ELEMENT
;
1767 line
= g_strjoinv("\n", attrlist
);
1770 g_strfreev(attrlist
);
1771 return gpg_error_from_errno(ENOMEM
);
1774 error
= assuan_send_data(ctx
, line
, strlen(line
));
1776 g_strfreev(attrlist
);
1781 * req[0] - attribute
1782 * req[1] - element path
1784 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1788 gchar
**path
= NULL
;
1791 if (!req
|| !req
[0] || !req
[1])
1792 return EPWMD_COMMAND_SYNTAX
;
1794 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1796 * The first argument may be only an account.
1798 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1799 return EPWMD_COMMAND_SYNTAX
;
1803 * Don't remove the "name" attribute for the account element. To remove an
1804 * account use DELETE <account>.
1806 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
1807 error
= EPWMD_ATTR_SYNTAX
;
1811 n
= find_account(client
->doc
, &path
, &error
, NULL
, 0);
1817 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
1818 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1826 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
1827 return EPWMD_ATTR_NOT_FOUND
;
1829 if (xmlRemoveProp(a
) == -1)
1830 return EPWMD_LIBXML_ERROR
;
1840 * Creates a "target" attribute. When other commands encounter an element with
1841 * this attribute, the element path is modified to the target value. If the
1842 * source element path doesn't exist when using 'ATTR SET target', it is
1843 * created, but the destination element path must exist.
1845 * req[0] - source element path
1846 * req[1] - destination element path
1848 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
1850 gchar
**src
, **dst
, *line
;
1854 if (!req
|| !req
[0] || !req
[1])
1855 return EPWMD_COMMAND_SYNTAX
;
1857 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1859 * The first argument may be only an account.
1861 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
1862 return EPWMD_COMMAND_SYNTAX
;
1865 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1867 * The first argument may be only an account.
1869 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
1870 error
= EPWMD_COMMAND_SYNTAX
;
1875 n
= find_account(client
->doc
, &dst
, &error
, NULL
, 0);
1878 * Make sure the destination element path exists.
1884 n
= find_elements(client
->doc
, n
->children
, dst
+1, &error
,
1885 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1892 n
= find_account(client
->doc
, &src
, &error
, NULL
, 0);
1895 if (error
== EPWMD_ELEMENT_NOT_FOUND
) {
1896 error
= new_account(client
->doc
, src
[0]);
1909 n
= create_target_elements_cb(n
, src
+1, &error
, NULL
);
1911 n
= find_elements(client
->doc
, n
->children
, src
+1, &error
,
1912 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
);
1918 * Reset the position of the element tree now that the elements
1919 * have been created.
1921 n
= find_account(client
->doc
, &src
, &error
, NULL
, 0);
1926 n
= find_elements(client
->doc
, n
->children
, src
+1, &error
,
1927 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1933 line
= g_strjoinv("\t", dst
);
1934 error
= add_attribute(n
, "target", line
);
1953 * req[0] - account name
1956 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
1962 tmp
= g_strdupv(req
);
1965 return gpg_error_from_errno(ENOMEM
);
1967 n
= find_account(client
->doc
, &tmp
, &error
, NULL
, 0);
1973 if (g_utf8_collate(req
[0], req
[1]) == 0)
1977 * Will not overwrite an existing account.
1979 tmp
= g_strdupv(req
+1);
1982 return gpg_error_from_errno(ENOMEM
);
1984 n
= find_account(client
->doc
, &tmp
, &error
, NULL
, 0);
1987 if (error
&& error
!= EPWMD_ELEMENT_NOT_FOUND
)
1991 return EPWMD_ACCOUNT_EXISTS
;
1994 * Whitespace not allowed in account names.
1996 if (contains_whitespace(req
[1]) == TRUE
)
1997 return EPWMD_ATTR_SYNTAX
;
1999 tmp
= g_strdupv(req
);
2002 return gpg_error_from_errno(ENOMEM
);
2004 n
= find_account(client
->doc
, &tmp
, &error
, NULL
, 0);
2008 return EPWMD_ELEMENT_NOT_FOUND
;
2010 return add_attribute(n
, "name", req
[1]);
2014 * req[0] - attribute
2015 * req[1] - element path
2017 static int attribute_get(assuan_context_t ctx
, gchar
**req
)
2019 struct client_s
*client
= assuan_get_pointer(ctx
);
2025 if (!req
|| !req
[0] || !req
[1])
2026 return EPWMD_COMMAND_SYNTAX
;
2028 if (strchr(req
[1], '\t')) {
2029 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2030 return EPWMD_COMMAND_SYNTAX
;
2033 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2034 return EPWMD_COMMAND_SYNTAX
;
2037 n
= find_account(client
->doc
, &path
, &error
, NULL
, 0);
2043 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
2044 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2052 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2053 return EPWMD_ATTR_NOT_FOUND
;
2055 error
= assuan_send_data(ctx
, a
, xmlStrlen(a
));
2065 * req[0] - attribute
2066 * req[1] - element path
2069 static int attribute_set(struct client_s
*client
, gchar
**req
)
2071 gchar
**path
= NULL
;
2075 if (!req
|| !req
[0] || !req
[1] || !req
[2])
2076 return EPWMD_COMMAND_SYNTAX
;
2079 * Reserved attribute names.
2081 if (g_utf8_collate(req
[0], "name") == 0) {
2083 * Only reserved for the account element. Not the rest of the
2086 if (strchr(req
[1], '\t') == NULL
)
2087 return name_attribute(client
, req
+ 1);
2089 else if (g_utf8_collate(req
[0], "target") == 0)
2090 return target_attribute(client
, req
+ 1);
2092 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2094 * The first argument may be only an account.
2096 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2097 return EPWMD_COMMAND_SYNTAX
;
2100 n
= find_account(client
->doc
, &path
, &error
, NULL
, 0);
2106 n
= find_elements(client
->doc
, n
->children
, path
+1, &error
,
2107 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2114 return add_attribute(n
, req
[0], req
[2]);
2123 * req[1] - attribute name or element path if command is LIST
2124 * req[2] - element path
2125 * req[2] - element path or value
2127 static int attr_command(assuan_context_t ctx
, char *line
)
2129 struct client_s
*client
= assuan_get_pointer(ctx
);
2130 gchar
**req
= split_input_line(line
, " ", 4);
2131 gpg_error_t error
= 0;
2133 error
= file_modified(client
);
2136 log_write("%s: %s", client
->filename
? client
->filename
: "",
2137 pwmd_strerror(error
));
2139 return send_error(ctx
, error
);
2142 if (!req
|| !req
[0] || !req
[1]) {
2144 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2147 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2148 error
= attribute_set(client
, req
+1);
2149 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2150 error
= attribute_get(ctx
, req
+1);
2151 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2152 error
= attribute_delete(client
, req
+1);
2153 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2154 error
= attribute_list(ctx
, req
+1);
2156 error
= EPWMD_COMMAND_SYNTAX
;
2159 return send_error(ctx
, error
);
2162 static int iscached_command(assuan_context_t ctx
, char *line
)
2164 gchar
**req
= split_input_line(line
, " ", 0);
2167 CACHE_LOCK(ctx
, NULL
);
2169 if (!req
|| !*req
) {
2171 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2174 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2177 if (cache_iscached(md5file
) == FALSE
)
2178 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2180 return send_error(ctx
, 0);
2183 gpg_error_t
send_cache_status(assuan_context_t ctx
)
2187 tmp
= print_fmt("%i %i",
2189 (cache_size
/ sizeof(file_cache_t
)) - cache_file_count());
2191 return assuan_write_status(ctx
, "CACHE", tmp
);
2194 static int clearcache_command(assuan_context_t ctx
, char *line
)
2196 struct client_s
*client
= assuan_get_pointer(ctx
);
2197 gchar
**req
= split_input_line(line
, " ", 0);
2200 CACHE_LOCK(ctx
, NULL
);
2202 if (!req
|| !*req
) {
2204 cache_clear(client
->md5file
, 2);
2205 return send_error(ctx
, 0);
2208 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2211 if (cache_clear(md5file
, 1) == FALSE
)
2212 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2214 return send_error(ctx
, 0);
2217 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2221 gchar
**req
= split_input_line(line
, " ", 0);
2224 CACHE_LOCK(ctx
, NULL
);
2226 if (!req
|| !*req
|| !req
[1]) {
2228 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2232 timeout
= strtol(req
[0], &p
, 10);
2234 if (errno
!= 0 || *p
!= 0) {
2236 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2239 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2242 if (cache_set_timeout(md5file
, timeout
) == FALSE
)
2243 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2245 send_cache_status_all();
2246 return send_error(ctx
, 0);
2249 static int dump_command(assuan_context_t ctx
, char *line
)
2253 struct client_s
*client
= assuan_get_pointer(ctx
);
2256 if (disable_list_and_dump
== TRUE
)
2257 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2259 error
= file_modified(client
);
2262 log_write("%s: %s", client
->filename
? client
->filename
: "",
2263 pwmd_strerror(error
));
2264 return send_error(ctx
, error
);
2267 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2268 error
= assuan_send_data(ctx
, xml
, len
);
2270 return send_error(ctx
, error
);
2273 static int getconfig_command(assuan_context_t ctx
, gchar
*line
)
2275 struct client_s
*client
= assuan_get_pointer(ctx
);
2276 gpg_error_t error
= 0;
2279 if (strcmp(line
, "key") == 0 || strcmp(line
, "key_file") == 0)
2280 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2282 p
= get_key_file_string(client
->filename
? client
->filename
: "default", line
);
2285 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2287 tmp
= expand_homedir(p
);
2290 error
= assuan_send_data(ctx
, p
, strlen(p
));
2292 return send_error(ctx
, error
);
2295 void cleanup_assuan(assuan_context_t ctx
)
2297 struct client_s
*cl
= assuan_get_pointer(ctx
);
2302 static void reset_notify(assuan_context_t ctx
)
2304 struct client_s
*cl
= assuan_get_pointer(ctx
);
2309 gpg_error_t
register_commands(assuan_context_t ctx
)
2313 int (*handler
)(assuan_context_t
, char *line
);
2315 { "OPEN", open_command
},
2316 { "SAVE", save_command
},
2317 { "LIST", list_command
},
2318 { "REALPATH", realpath_command
},
2319 { "STORE", store_command
},
2320 { "DELETE", delete_command
},
2321 { "GET", get_command
},
2322 { "ATTR", attr_command
},
2323 { "ISCACHED", iscached_command
},
2324 { "CLEARCACHE", clearcache_command
},
2325 { "CACHETIMEOUT", cachetimeout_command
},
2326 { "GETCONFIG", getconfig_command
},
2327 { "DUMP", dump_command
},
2334 for (i
=0; table
[i
].name
; i
++) {
2335 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
2341 rc
= assuan_register_bye_notify(ctx
, cleanup_assuan
);
2345 return assuan_register_reset_notify(ctx
, reset_notify
);
2348 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, gint fd
, struct stat st
,
2354 guchar tkey
[gcrykeysize
];
2355 struct file_header_s
{
2357 guchar iv
[gcryblocksize
];
2359 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
2360 gcry_cipher_hd_t gh
;
2361 guint iter
= 0, n_iter
= 0;
2363 void *outbuf
= NULL
;
2369 error
= gcry_cipher_open(&gh
, GCRY_CIPHER_AES256
, GCRY_CIPHER_MODE_CBC
, 0);
2377 lseek(fd
, 0, SEEK_SET
);
2378 insize
= st
.st_size
- sizeof(struct file_header_s
);
2379 iv
= gcry_malloc(gcryblocksize
);
2383 gcry_cipher_close(gh
);
2385 return gpg_error_from_errno(ENOMEM
);
2388 len
= pth_read(fd
, &file_header
, sizeof(struct file_header_s
));
2390 if (len
!= sizeof(file_header
)) {
2394 gcry_cipher_close(gh
);
2398 return gpg_error_from_errno(errno
);
2401 memcpy(iv
, &file_header
.iv
, sizeof(file_header
.iv
));
2402 inbuf
= gcry_malloc(insize
);
2406 gcry_cipher_close(gh
);
2409 return gpg_error_from_errno(ENOMEM
);
2412 len
= pth_read(fd
, inbuf
, insize
);
2414 if (len
!= insize
) {
2418 gcry_cipher_close(gh
);
2422 return gpg_error_from_errno(errno
);
2425 memcpy(tkey
, key
, sizeof(tkey
));
2428 if ((error
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
2430 gcry_cipher_close(gh
);
2431 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2434 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2441 if ((error
= gcry_cipher_setkey(gh
, key
, gcrykeysize
))) {
2443 gcry_cipher_close(gh
);
2444 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2447 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2453 gcry_cipher_close(gh
);
2458 iter_progress
= get_key_file_integer("default", "iteration_progress");
2460 if (ctx
&& iter_progress
> 0 && file_header
.iter
>= iter_progress
) {
2461 error
= assuan_write_status(client
->ctx
, "DECRYPT", "0");
2470 error
= decrypt_xml(gh
, inbuf
, insize
, NULL
, 0);
2478 if ((error
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
2480 gcry_cipher_close(gh
);
2481 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2484 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2491 while (iter
< file_header
.iter
) {
2492 if (ctx
&& iter_progress
> 0 && iter
>= iter_progress
) {
2493 if (!(iter
% iter_progress
)) {
2494 error
= assuan_write_status(ctx
, "DECRYPT", print_fmt("%i",
2495 ++n_iter
* iter_progress
));
2505 if ((error
= gcry_cipher_setiv(gh
, iv
, gcryblocksize
))) {
2507 gcry_cipher_close(gh
);
2508 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2511 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2518 error
= decrypt_xml(gh
, inbuf
, insize
, NULL
, 0);
2522 gcry_cipher_close(gh
);
2523 warnx("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2526 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(error
));
2537 if (ctx
&& iter_progress
&& file_header
.iter
>= iter_progress
) {
2538 error
= assuan_write_status(ctx
, "DECRYPT", print_fmt("%i", file_header
.iter
));
2549 if (do_decompress(ctx
, inbuf
, insize
, &outbuf
, &outsize
, &zerror
) == FALSE
) {
2551 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2553 if (zerror
== Z_MEM_ERROR
) {
2555 return gpg_error_from_errno(ENOMEM
);
2557 else if (zerror
!= Z_DATA_ERROR
) {
2561 gcry_cipher_close(gh
);
2563 return EPWMD_BADKEY
;
2572 if (g_strncasecmp(inbuf
, "<?xml version=\"1.0\"?>", 21) != 0) {
2576 gcry_cipher_close(gh
);
2578 return EPWMD_BADKEY
;
2582 client
->xml
= inbuf
;
2583 client
->len
= insize
;
2586 gcry_cipher_close(gh
);
2594 * This is called after every Assuan command.
2596 void command_finalize(assuan_context_t ctx
, gint error
)