1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2010 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
24 #include <sys/types.h>
49 #include "pwmd_error.h"
62 static gpg_error_t
do_lock_command(struct client_s
*client
);
64 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
66 return gcry_calloc(items
, size
);
69 static void z_free(void *data
, void *p
)
74 static gpg_error_t
file_modified(struct client_s
*client
)
79 if (client
->state
!= STATE_OPEN
)
82 rc
= lock_file_mutex(client
);
87 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
88 if (client
->mtime
!= st
.st_mtime
)
89 return EPWMD_FILE_MODIFIED
;
96 static gpg_error_t
parse_xml(assuan_context_t ctx
)
98 struct client_s
*client
= assuan_get_pointer(ctx
);
100 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
103 return EPWMD_LIBXML_ERROR
;
105 if (!client
->crypto
->fh
|| client
->crypto
->fh
->ver
.fh2
.version
>= 0x212)
108 return convert_elements(client
->doc
);
111 void unlock_file_mutex(struct client_s
*client
)
116 if (client
->has_lock
== FALSE
|| client
->pinentry
->status
!= PINENTRY_NONE
)
118 if (client
->has_lock
== FALSE
)
122 CACHE_LOCK(client
->ctx
);
124 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
131 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
134 gpg_error_t
lock_file_mutex(struct client_s
*client
)
139 if (client
->has_lock
== TRUE
)
142 CACHE_LOCK(client
->ctx
);
144 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
151 if (client
->rc_on_locked
) {
152 if (!pth_mutex_acquire(m
, TRUE
, NULL
))
153 return GPG_ERR_LOCKED
;
159 MUTEX_TRYLOCK(client
, m
, rc
);
162 client
->has_lock
= TRUE
;
167 void free_client(struct client_s
*client
)
170 xmlFreeDoc(client
->doc
);
173 gcry_free(client
->xml
);
175 if (client
->filename
)
176 g_free(client
->filename
);
179 cleanup_crypto(&client
->crypto
);
181 if (client
->xml_error
)
182 xmlResetError(client
->xml_error
);
185 void cleanup_client(struct client_s
*client
)
187 assuan_context_t ctx
= client
->ctx
;
188 struct client_thread_s
*thd
= client
->thd
;
189 gboolean rc_on_locked
= client
->rc_on_locked
;
190 gboolean lock_on_open
= client
->lock_on_open
;
192 struct pinentry_s
*pin
= client
->pinentry
;
195 unlock_file_mutex(client
);
196 CACHE_LOCK(client
->ctx
);
197 cache_decr_refcount(client
->md5file
);
200 * This may be a new file so don't use a cache slot. save_command() will
201 * set this to FALSE on success.
203 if (client
->new == TRUE
)
204 cache_clear(client
->md5file
, 1);
208 memset(client
, 0, sizeof(struct client_s
));
209 client
->state
= STATE_CONNECTED
;
212 client
->freed
= TRUE
;
214 client
->pinentry
= pin
;
216 client
->rc_on_locked
= rc_on_locked
;
217 client
->lock_on_open
= lock_on_open
;
220 static void gz_cleanup(void *arg
)
222 struct gz_s
**gz
= (struct gz_s
**)arg
;
227 if (!(*gz
)->done
&& (*gz
)->out
)
228 gcry_free((*gz
)->out
);
230 if ((*gz
)->which
== STATUS_COMPRESS
) {
232 deflateEnd(&(*gz
)->z
);
236 inflateEnd(&(*gz
)->z
);
243 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
244 gpointer
*out
, gulong
*outsize
, gint
*rc
)
250 gz
= g_malloc0(sizeof(struct gz_s
));
253 *rc
= gpg_error_from_errno(ENOMEM
);
257 pth_cleanup_push(gz_cleanup
, &gz
);
258 gz
->which
= STATUS_DECOMPRESS
;
259 gz
->z
.zalloc
= z_alloc
;
260 gz
->z
.zfree
= z_free
;
262 gz
->z
.avail_in
= (uInt
)insize
;
263 gz
->z
.avail_out
= zlib_bufsize
;
264 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
267 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
273 *rc
= inflateInit2(&gz
->z
, 47);
276 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
281 memset(&h
, 0, sizeof(gz_header
));
282 h
.comment
= (guchar
*)buf
;
283 h
.comm_max
= sizeof(buf
);
284 *rc
= inflateGetHeader(&gz
->z
, &h
);
287 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
292 *rc
= inflate(&gz
->z
, Z_BLOCK
);
295 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
301 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
306 *rc
= inflate(&gz
->z
, Z_FINISH
);
312 if (!gz
->z
.avail_out
) {
313 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
316 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
322 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
323 gz
->z
.avail_out
= zlib_bufsize
;
324 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
325 gz
->z
.total_out
, insize
);
337 } while (*rc
!= Z_STREAM_END
);
339 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
346 *outsize
= gz
->z
.total_out
;
353 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
358 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
363 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
370 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
371 *rc
= gpg_error_from_errno(ENOMEM
);
375 pth_cleanup_push(g_free
, fh
);
376 fh_size
= v1
? sizeof(fh
->ver
.fh1
) : sizeof(fh
->ver
.fh2
);
378 if (lstat(filename
, &fh
->st
) == -1) {
379 *rc
= gpg_error_from_syserror();
384 if (!S_ISREG(fh
->st
.st_mode
)) {
385 *rc
= GPG_ERR_ENOANO
;
390 fd
= open(filename
, O_RDONLY
);
393 *rc
= gpg_error_from_errno(errno
);
398 pth_cleanup_push(cleanup_fd_cb
, &fd
);
399 p
= v1
? (void *)&fh
->ver
.fh1
: (void *)&fh
->ver
.fh2
;
400 len
= pth_read(fd
, p
, fh_size
);
402 if (len
!= fh_size
) {
406 *rc
= gpg_error_from_errno(n
);
417 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*unused
,
420 struct client_s
*client
= assuan_get_pointer(ctx
);
423 guchar
*key
= client
->crypto
->key
;
426 if (!client
->crypto
->fh
) {
433 rc
= init_client_crypto2(client
->filename
, client
->crypto
);
436 cleanup_client(client
);
437 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
440 rc
= try_xml_decrypt(ctx
, client
->crypto
, NULL
, NULL
);
443 cleanup_client(client
);
444 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
448 CACHE_LOCK(client
->ctx
);
450 if (cached
== FALSE
) {
451 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
452 cleanup_client(client
);
454 return client
->opts
& OPT_INQUIRE
? gpg_err_code_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
457 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
458 cache_reset_timeout(client
->md5file
, timeout
);
461 cache_set_timeout(client
->md5file
, -2);
469 gcry_free(client
->xml
);
474 if (client
->new == FALSE
)
475 send_status_all(STATUS_CACHE
);
477 client
->state
= STATE_OPEN
;
480 if (!rc
&& client
->new == FALSE
&&
481 client
->crypto
->fh
->ver
.fh2
.iter
!= (guint64
)get_key_file_double(client
->filename
, "iterations")) {
482 MUTEX_LOCK(&rcfile_mutex
);
483 g_key_file_set_double(keyfileh
, client
->filename
, "iterations",
484 client
->crypto
->fh
->ver
.fh2
.iter
);
485 MUTEX_UNLOCK(&rcfile_mutex
);
486 send_status_all(STATUS_CONFIG
);
489 cleanup_crypto(&client
->crypto
);
491 if (!rc
&& client
->lock_on_open
)
492 return do_lock_command(client
);
494 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
497 static void req_cleanup(void *arg
)
502 g_strfreev((gchar
**)arg
);
505 static gpg_error_t
parse_open_opt_lock(gpointer data
, gpointer value
)
507 struct client_s
*client
= data
;
508 const gchar
*p
= value
;
511 long l
= strtol(p
, NULL
, 10);
514 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
516 client
->lock_on_open
= l
? TRUE
: FALSE
;
518 else if ((!p
|| !*p
) && (client
->opts
& OPT_LOCK
))
519 client
->lock_on_open
= FALSE
;
521 client
->lock_on_open
= TRUE
;
526 static gpg_error_t
parse_opt_pinentry(gpointer data
, gpointer value
)
529 struct client_s
*client
= data
;
535 client
->pinentry
->enable
= -1;
536 client
->opts
&= ~(OPT_PINENTRY
);
540 n
= strtol(str
, &p
, 10);
542 if (*p
|| n
< 0 || n
> 1)
543 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
545 client
->pinentry
->enable
= n
? TRUE
: FALSE
;
546 client
->opts
|= OPT_PINENTRY
;
551 static gpg_error_t
parse_opt_inquire(gpointer data
, gpointer value
)
553 struct client_s
*client
= data
;
556 client
->opts
|= OPT_INQUIRE
;
560 static gpg_error_t
parse_opt_base64(gpointer data
, gpointer value
)
562 struct client_s
*client
= data
;
565 client
->opts
|= OPT_BASE64
;
569 static gpg_error_t
hash_key(struct client_s
*client
, const gchar
*key
)
574 if (client
->opts
& OPT_BASE64
)
575 tmp
= g_base64_decode(key
, &len
);
577 tmp
= (guchar
*)g_strdup(key
);
582 return GPG_ERR_ENOMEM
;
584 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, tmp
, len
);
589 static gpg_error_t
open_command_common(assuan_context_t ctx
, gchar
*line
)
591 gboolean cached
= FALSE
;
593 struct client_s
*client
= assuan_get_pointer(ctx
);
595 gchar
*filename
= NULL
;
596 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
598 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
601 pth_cleanup_push(req_cleanup
, req
);
603 if (!filename
|| !*filename
) {
605 return client
->opts
& OPT_INQUIRE
? GPG_ERR_SYNTAX
: send_error(ctx
, GPG_ERR_SYNTAX
);
608 log_write2("ARGS=\"%s\" %s", filename
, req
[1] ? "<passphrase>" : "");
610 if (valid_filename(filename
) == FALSE
) {
612 return client
->opts
& OPT_INQUIRE
? GPG_ERR_INV_VALUE
: send_error(ctx
, GPG_ERR_INV_VALUE
);
615 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
616 CACHE_LOCK(client
->ctx
);
618 if (cache_has_file(client
->md5file
) == FALSE
) {
619 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
622 return client
->opts
& OPT_INQUIRE
? gpg_err_code_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
626 cache_incr_refcount(client
->md5file
);
628 rc
= lock_file_mutex(client
);
632 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
635 client
->freed
= FALSE
;
636 client
->crypto
= init_client_crypto();
638 if (!client
->crypto
) {
640 cleanup_client(client
);
641 return client
->opts
& OPT_INQUIRE
? gpg_error_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
644 client
->crypto
->key
= gcry_malloc(hashlen
);
646 if (!client
->crypto
->key
) {
648 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
649 gpg_error_from_errno(ENOMEM
));
650 cleanup_client(client
);
651 return client
->opts
& OPT_INQUIRE
? gpg_err_code_to_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
654 memset(client
->crypto
->key
, 0, hashlen
);
655 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
657 if (!client
->crypto
->fh
) {
658 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
659 log_write("%s: %s", filename
, pwmd_strerror(rc
));
661 cleanup_client(client
);
662 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
666 * New files don't need a key.
668 if ((client
->xml
= new_document()) == NULL
) {
669 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
671 cleanup_client(client
);
672 return client
->opts
& OPT_INQUIRE
? gpg_err_code_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
675 client
->len
= xmlStrlen(client
->xml
);
677 client
->filename
= g_strdup(filename
);
679 if (!client
->filename
) {
681 cleanup_client(client
);
682 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
683 return client
->opts
& OPT_INQUIRE
? gpg_err_code_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
686 if (req
[1] && *req
[1]) {
687 rc
= hash_key(client
, req
[1]);
691 cleanup_client(client
);
692 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
698 client
->pinentry
->filename
= g_strdup(client
->filename
);
700 if (!client
->pinentry
->filename
) {
701 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
702 cleanup_client(client
);
703 return client
->opts
& OPT_INQUIRE
? gpg_err_code_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
706 return open_command_finalize(ctx
, NULL
, cached
);
709 if (!(client
->opts
& OPT_CIPHER
))
710 g_key_file_set_string(keyfileh
, filename
, "cipher",
711 pwmd_cipher_to_str(client
->crypto
->fh
->ver
.fh2
.flags
));
713 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
716 client
->filename
= g_strdup(filename
);
718 if (!client
->filename
) {
719 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
721 cleanup_client(client
);
722 return client
->opts
& OPT_INQUIRE
? gpg_err_code_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
726 if (client
->pinentry
->filename
)
727 g_free(client
->pinentry
->filename
);
729 client
->pinentry
->filename
= g_strdup(client
->filename
);
731 if (!client
->pinentry
->filename
) {
732 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
734 cleanup_client(client
);
735 return client
->opts
& OPT_INQUIRE
? gpg_err_code_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
739 if (client
->crypto
->fh
->ver
.fh2
.iter
<= 0ULL)
742 CACHE_LOCK(client
->ctx
);
743 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
746 if (cached
== FALSE
) {
747 gchar
*tmp
= get_key_file_string(filename
, "key_file");
749 if (tmp
&& !(client
->opts
& OPT_INQUIRE
)) {
752 cleanup_client(client
);
753 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
760 * No key specified and no matching filename found in the cache. Use
761 * pinentry to retrieve the key. Cannot return assuan_process_done()
762 * here otherwise the command will be interrupted. The event loop in
763 * client_thread() will poll the file descriptor waiting for it to
764 * become ready to read a pinentry_key_s which will contain the
765 * entered key or an error code. It will then call
766 * open_command_finalize() to to finish the command.
768 if (!req
[1] || !*req
[1]) {
770 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
772 /* From set_pinentry_defaults(). */
773 if (client
->opts
& OPT_INQUIRE
||
774 client
->pinentry
->enable
== FALSE
||
775 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
776 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
781 rc
= lock_pin_mutex(client
);
784 unlock_pin_mutex(client
->pinentry
);
785 cleanup_client(client
);
786 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
789 client
->pinentry
->which
= PINENTRY_OPEN
;
790 rc
= pinentry_fork(ctx
);
793 unlock_pin_mutex(client
->pinentry
);
794 cleanup_client(client
);
795 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
798 // Called from pinentry iterate.
799 client
->pinentry
->cb
= open_command_finalize
;
800 client
->pinentry
->status
= PINENTRY_INIT
;
803 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
808 rc
= hash_key(client
, req
[1]);
812 cleanup_client(client
);
813 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
816 else if (req
&& req
[1] && *req
[1]) {
817 rc
= hash_key(client
, req
[1]);
821 cleanup_client(client
);
822 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
828 return open_command_finalize(ctx
, NULL
, cached
);
831 static gint
open_command_inquire_finalize(gpointer data
, gint assuan_rc
,
832 guchar
*line
, gsize len
)
834 assuan_context_t ctx
= data
;
835 struct client_s
*client
= assuan_get_pointer(ctx
);
836 gpg_error_t rc
= file_modified(client
);
838 if (assuan_rc
|| (rc
&& rc
!= EPWMD_NO_FILE
)) {
842 return assuan_rc
? assuan_rc
: rc
;
845 rc
= open_command_common(ctx
, (gchar
*)line
);
850 client
->inquire_status
= INQUIRE_DONE
;
854 static gint
open_command(assuan_context_t ctx
, gchar
*line
)
857 struct client_s
*client
= assuan_get_pointer(ctx
);
858 struct argv_s
*args
[] = {
859 &(struct argv_s
) { "lock", OPT_NOARG
, parse_open_opt_lock
},
860 &(struct argv_s
) { "pinentry", OPT_OPTARG
, parse_opt_pinentry
},
861 &(struct argv_s
) { "inquire", OPT_NOARG
, parse_opt_inquire
},
862 &(struct argv_s
) { "base64", OPT_NOARG
, parse_opt_base64
},
866 if (client
->state
== STATE_OPEN
)
867 cleanup_client(client
);
869 if (!(client
->opts
& OPT_LOCK
))
870 client
->lock_on_open
= FALSE
;
872 rc
= parse_options(&line
, args
, client
);
875 return send_error(ctx
, rc
);
877 if ((client
->opts
& OPT_INQUIRE
)) {
878 rc
= assuan_inquire_ext(ctx
, "OPEN", 0, open_command_inquire_finalize
,
882 return send_error(ctx
, rc
);
884 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
885 client
->inquire_status
= INQUIRE_BUSY
;
889 return open_command_common(ctx
, line
);
892 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
893 guint size
, gpointer
*out
, gulong
*outsize
, gint
*rc
)
898 gint cmd
= Z_NO_FLUSH
;
900 gz
= g_malloc0(sizeof(struct gz_s
));
903 *rc
= gpg_error_from_errno(ENOMEM
);
907 pth_cleanup_push(gz_cleanup
, &gz
);
908 gz
->which
= STATUS_COMPRESS
;
909 gz
->z
.zalloc
= z_alloc
;
910 gz
->z
.zfree
= z_free
;
911 gz
->z
.next_in
= data
;
912 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
913 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
914 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
917 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
923 *rc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
926 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
931 /* Rather than store the size of the uncompressed data in the file header,
932 * store it in the comment field of the gzip header. Don't give anyone too
933 * much information. Not sure why really, but it seems the right way. :)
935 memset(&h
, 0, sizeof(gz_header
));
936 g_snprintf(buf
, sizeof(buf
), "%u", size
);
937 h
.comment
= (guchar
*)buf
;
938 *rc
= deflateSetHeader(&gz
->z
, &h
);
941 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
949 *rc
= deflate(&gz
->z
, cmd
);
955 if (!gz
->z
.avail_out
) {
956 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
959 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
965 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
966 gz
->z
.avail_out
= zlib_bufsize
;
969 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
970 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
971 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
973 gz
->z
.avail_in
= zlib_bufsize
;
975 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u",
976 gz
->z
.total_in
, size
);
982 if (gz
->z
.total_in
>= size
)
991 } while (*rc
!= Z_STREAM_END
);
993 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u", gz
->z
.total_in
, size
);
999 *outsize
= gz
->z
.total_out
;
1006 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
1011 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1014 * Useful for a large amount of data. Rather than doing all of the data in one
1015 * iteration do it in chunks. This lets the command be cancelable rather than
1016 * waiting for it to complete.
1018 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
1019 struct crypto_s
*crypto
, status_msg_t which
)
1022 goffset len
= CRYPTO_BLOCKSIZE(crypto
);
1023 gpointer p
= gcry_malloc(len
);
1028 return gpg_err_code_from_errno(ENOMEM
);
1030 if (crypto
->insize
< CRYPTO_BLOCKSIZE(crypto
))
1031 len
= crypto
->insize
;
1033 pth_cleanup_push(gcry_free
, p
);
1036 inbuf
= (guchar
*)crypto
->inbuf
+ total
;
1039 if (len
+ total
> crypto
->insize
)
1040 len
= crypto
->blocksize
;
1042 if (which
== STATUS_ENCRYPT
)
1043 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1045 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1050 tmp
= (guchar
*)crypto
->inbuf
+ total
;
1051 memmove(tmp
, p
, len
);
1054 if (total
>= crypto
->insize
)
1065 /* The crypto struct must be setup for iterations and .key. */
1066 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
1067 struct crypto_s
*crypto
, const gchar
*filename
)
1069 goffset len
= crypto
->insize
;
1073 guint64 iter_progress
= 0ULL, n_iter
= 0ULL, xiter
= 0ULL;
1074 gchar tmp
[FILENAME_MAX
];
1077 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1079 if (!crypto
->fh
->ver
.fh2
.iter
) {
1081 * cache_file_count() needs both .used == TRUE and a valid key in
1082 * order for it to count as a used cache entry. Fixes CACHE status
1085 memset(crypto
->key
, '!', hashlen
);
1090 * Resize the existing xml buffer to the block size required by gcrypt
1091 * rather than duplicating it and wasting memory.
1093 len
= (crypto
->insize
/ crypto
->blocksize
) * crypto
->blocksize
;
1095 if (crypto
->insize
% crypto
->blocksize
)
1096 len
+= crypto
->blocksize
;
1098 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
1101 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1102 return gpg_error_from_errno(ENOMEM
);
1105 crypto
->inbuf
= inbuf
;
1106 crypto
->insize
= len
;
1107 gcry_create_nonce(crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
1110 gcry_free(crypto
->tkey
);
1112 crypto
->tkey
= gcry_malloc(hashlen
);
1114 if (!crypto
->tkey
) {
1115 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1116 return gpg_error_from_errno(ENOMEM
);
1119 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
1120 guchar
*tkey
= crypto
->tkey
;
1123 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
1124 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
1128 iter_progress
= (guint64
)get_key_file_double(
1129 client
? client
->filename
: "global", "iteration_progress");
1131 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1132 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1133 "0 %llu", crypto
->fh
->ver
.fh2
.iter
);
1139 while (xiter
< crypto
->fh
->ver
.fh2
.iter
-1) {
1140 if (iter_progress
> 0ULL && xiter
>= iter_progress
) {
1141 if (!(xiter
% iter_progress
)) {
1142 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1143 "%llu %llu", ++n_iter
* iter_progress
,
1144 crypto
->fh
->ver
.fh2
.iter
);
1151 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1152 crypto
->blocksize
))) {
1153 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
1157 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1160 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
1167 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1168 crypto
->blocksize
))) {
1169 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
1173 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
1174 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
1178 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1183 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1184 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1185 "%llu %llu", crypto
->fh
->ver
.fh2
.iter
, crypto
->fh
->ver
.fh2
.iter
);
1195 if (!client
&& !g_ascii_strcasecmp(filename
, "-")) {
1196 crypto
->fh
->fd
= STDOUT_FILENO
;
1200 if (lstat(filename
, &st
) == 0) {
1201 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1203 if (!(mode
& S_IWUSR
))
1204 return gpg_error_from_errno(EACCES
);
1206 else if (errno
!= ENOENT
)
1207 return gpg_error_from_errno(errno
);
1209 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1210 crypto
->fh
->fd
= mkstemp(tmp
);
1212 if (crypto
->fh
->fd
== -1) {
1214 p
= strrchr(tmp
, '/');
1216 log_write("%s: %s", p
, strerror(rc
));
1217 return gpg_error_from_errno(rc
);
1220 pth_cleanup_push(cleanup_unlink_cb
, tmp
);
1224 * xml_import() or convert_file() from command line.
1226 crypto
->fh
->fd
= STDOUT_FILENO
;
1229 crypto
->fh
->ver
.fh2
.magic
[0] = '\177';
1230 crypto
->fh
->ver
.fh2
.magic
[1] = 'P';
1231 crypto
->fh
->ver
.fh2
.magic
[2] = 'W';
1232 crypto
->fh
->ver
.fh2
.magic
[3] = 'M';
1233 crypto
->fh
->ver
.fh2
.magic
[4] = 'D';
1234 crypto
->fh
->ver
.fh2
.version
= VERSION_HEX
;
1235 len
= pth_write(crypto
->fh
->fd
, &crypto
->fh
->ver
.fh2
, sizeof(crypto
->fh
->ver
.fh2
));
1237 if (len
!= sizeof(crypto
->fh
->ver
.fh2
)) {
1243 return gpg_error_from_errno(len
);
1246 len
= pth_write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1248 if (len
!= crypto
->insize
) {
1254 return gpg_error_from_errno(len
);
1257 if (fsync(crypto
->fh
->fd
) == -1) {
1263 return gpg_error_from_errno(len
);
1270 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1271 gchar tmp2
[FILENAME_MAX
];
1273 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1275 acl
= acl_get_file(filename
, ACL_TYPE_ACCESS
);
1278 log_write("ACL: %s: %s", filename
, strerror(errno
));
1281 if (rename(filename
, tmp2
) == -1) {
1288 return gpg_error_from_errno(len
);
1293 acl
= acl_get_file(".", ACL_TYPE_DEFAULT
);
1296 log_write("ACL: %s: %s", filename
, strerror(errno
));
1300 if (rename(tmp
, filename
) == -1) {
1307 return gpg_error_from_errno(len
);
1313 chmod(filename
, mode
);
1316 if (acl
&& acl_set_file(filename
, ACL_TYPE_ACCESS
, acl
))
1317 log_write("ACL: %s: %s", filename
, strerror(errno
));
1324 if (client
&& lstat(filename
, &st
) == 0)
1325 client
->mtime
= st
.st_mtime
;
1330 gpg_error_t
update_save_flags(const gchar
*filename
,
1331 struct crypto_s
*crypto
)
1338 crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1341 return GPG_ERR_ENOMEM
;
1344 rc
= init_client_crypto2(filename
, crypto
);
1349 if (filename
&& !crypto
->fh
->v1
) {
1350 iter
= (guint64
)get_key_file_double(filename
, "iterations");
1351 crypto
->fh
->ver
.fh2
.iter
= iter
< 0L ? 0UL : iter
;
1357 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1360 struct client_s
*client
= assuan_get_pointer(ctx
);
1370 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1371 gcry_free(client
->crypto
->key
);
1373 client
->crypto
->key
= key
;
1374 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
));
1377 cleanup_crypto(&client
->crypto
);
1378 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1381 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1382 pth_cleanup_push(xmlFree
, xmlbuf
);
1383 clevel
= get_key_file_integer(client
->filename
, "compression_level");
1388 if (do_compress(ctx
, clevel
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
) == FALSE
) {
1390 cleanup_crypto(&client
->crypto
);
1392 if (zrc
== Z_MEM_ERROR
)
1393 return client
->opts
& OPT_INQUIRE
? gpg_error_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
1395 return client
->opts
& OPT_INQUIRE
? GPG_ERR_COMPR_ALGO
: send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1403 client
->crypto
->inbuf
= xmlbuf
;
1404 client
->crypto
->insize
= len
;
1405 rc
= update_save_flags(client
->filename
, client
->crypto
);
1408 cleanup_crypto(&client
->crypto
);
1409 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1410 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1413 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1416 cleanup_crypto(&client
->crypto
);
1417 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1420 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1421 CACHE_LOCK(client
->ctx
);
1424 cache_reset_timeout(client
->md5file
, timeout
);
1427 if (client
->new == TRUE
)
1428 send_status_all(STATUS_CACHE
);
1430 client
->new = FALSE
;
1431 cleanup_crypto(&client
->crypto
);
1432 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1435 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1437 cleanup_crypto(&client
->crypto
);
1438 return client
->opts
& OPT_INQUIRE
? gpg_error_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
1441 client
->new = FALSE
;
1442 cache_reset_timeout(client
->md5file
, timeout
);
1444 send_status_all(STATUS_CACHE
);
1445 cleanup_crypto(&client
->crypto
);
1446 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1449 static gpg_error_t
parse_save_opt_iterations(gpointer data
, gpointer v
)
1451 struct client_s
*client
= data
;
1456 if (!client
->filename
)
1457 return EPWMD_NO_FILE
;
1459 if (!value
|| !*value
)
1463 n
= strtoul(value
, &p
, 10);
1465 if (errno
|| (p
&& *p
) || n
== G_MAXULONG
)
1466 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
1468 MUTEX_LOCK(&rcfile_mutex
);
1469 g_key_file_set_double(keyfileh
,
1470 client
->filename
? client
->filename
: "global", "iterations", n
);
1471 MUTEX_UNLOCK(&rcfile_mutex
);
1473 if (client
->filename
)
1474 client
->opts
|= OPT_ITERATIONS
;
1479 static gpg_error_t
parse_save_opt_cipher(gpointer data
, gpointer value
)
1481 struct client_s
*client
= data
;
1482 const gchar
*p
= value
;
1485 if (!client
->filename
)
1486 return EPWMD_NO_FILE
;
1491 flags
= pwmd_cipher_str_to_cipher(p
);
1494 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
1496 MUTEX_LOCK(&rcfile_mutex
);
1497 g_key_file_set_string(keyfileh
, client
->filename
, "cipher", p
);
1498 MUTEX_UNLOCK(&rcfile_mutex
);
1506 static gpg_error_t
parse_save_opt_reset(gpointer data
, gpointer value
)
1508 struct client_s
*client
= data
;
1510 CACHE_LOCK(client
->ctx
);
1511 cache_clear(client
->md5file
, 1);
1516 static gpg_error_t
save_command_common(assuan_context_t ctx
, gchar
*line
)
1518 struct client_s
*client
= assuan_get_pointer(ctx
);
1519 gboolean cached
= FALSE
;
1520 guint hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1523 cached
= cache_iscached(client
->md5file
);
1527 * If a cache entry doesn't exist for this file and the file has a
1528 * "key_file" or "key" parameter, then it's an error. The reason is that
1529 * cache expiration would be useless. Unless this is an inquire, then its
1532 if (cached
== FALSE
) {
1533 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1535 if (tmp
&& !(client
->opts
& OPT_INQUIRE
)) {
1537 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1547 if (!client
->crypto
) {
1548 client
->crypto
= init_client_crypto();
1550 if (!client
->crypto
) {
1551 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1552 return client
->opts
& OPT_INQUIRE
? gpg_error_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
1556 client
->crypto
->key
= gcry_malloc(hashlen
);
1558 if (!client
->crypto
->key
) {
1559 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1560 cleanup_crypto(&client
->crypto
);
1561 return client
->opts
& OPT_INQUIRE
? gpg_error_from_errno(ENOMEM
) : send_syserror(ctx
, ENOMEM
);
1564 memset(client
->crypto
->key
, '!', hashlen
);
1566 if (get_key_file_double(client
->filename
, "iterations") <= 0L &&
1570 if (!line
|| !*line
) {
1571 /* It doesn't make sense to use an --inquire with an empty
1572 * passphrase. This will prevent a pinentry dialog. */
1573 if (client
->opts
& OPT_INQUIRE
) {
1574 cleanup_crypto(&client
->crypto
);
1575 return GPG_ERR_WRONG_KEY_USAGE
;
1578 client
->crypto
->tkey
= gcry_malloc(hashlen
);
1580 if (!client
->crypto
->tkey
) {
1581 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1582 cleanup_crypto(&client
->crypto
);
1583 return send_syserror(ctx
, ENOMEM
);
1586 memset(client
->crypto
->tkey
, '!', hashlen
);
1589 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1590 !memcmp(client
->crypto
->key
, client
->crypto
->tkey
, hashlen
)) {
1593 #ifdef WITH_PINENTRY
1596 if (client
->pinentry
->enable
== FALSE
||
1597 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1598 /* Empty keys are allowed. */
1599 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1603 lock_pin_mutex(client
);
1604 client
->pinentry
->which
= PINENTRY_SAVE
;
1605 rc
= pinentry_fork(ctx
);
1608 unlock_pin_mutex(client
->pinentry
);
1609 cleanup_crypto(&client
->crypto
);
1610 return send_error(ctx
, rc
);
1613 client
->pinentry
->cb
= save_command_finalize
;
1614 client
->pinentry
->status
= PINENTRY_INIT
;
1617 /* Empty keys are allowed. */
1618 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1630 if (get_key_file_double(client
->filename
, "iterations") <= 0L) {
1631 guint64 iter
= (guint64
)get_key_file_double(NULL
, "iterations");
1636 MUTEX_LOCK(&rcfile_mutex
);
1637 g_key_file_set_double(keyfileh
, client
->filename
, "iterations", iter
);
1638 MUTEX_UNLOCK(&rcfile_mutex
);
1639 client
->opts
|= OPT_ITERATIONS
;
1640 rc
= send_status(ctx
, STATUS_CONFIG
, NULL
);
1643 cleanup_crypto(&client
->crypto
);
1644 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1648 rc
= hash_key(client
, line
);
1651 cleanup_crypto(&client
->crypto
);
1652 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1657 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1660 static gint
save_command_inquire_finalize(gpointer data
, gint assuan_rc
,
1661 guchar
*line
, gsize len
)
1663 assuan_context_t ctx
= data
;
1664 struct client_s
*client
= assuan_get_pointer(ctx
);
1665 gpg_error_t rc
= file_modified(client
);
1667 if (assuan_rc
|| rc
) {
1671 return assuan_rc
? assuan_rc
: rc
;
1674 rc
= save_command_common(ctx
, (gchar
*)line
);
1679 client
->inquire_status
= INQUIRE_DONE
;
1683 static gint
save_command(assuan_context_t ctx
, gchar
*line
)
1686 struct client_s
*client
= assuan_get_pointer(ctx
);
1688 struct argv_s
*args
[] = {
1689 &(struct argv_s
) { "iterations", OPT_OPTARG
, parse_save_opt_iterations
},
1690 &(struct argv_s
) { "cipher", OPT_OPTARG
, parse_save_opt_cipher
},
1691 &(struct argv_s
) { "pinentry", OPT_OPTARG
, parse_opt_pinentry
},
1692 &(struct argv_s
) { "reset", OPT_NOARG
, parse_save_opt_reset
},
1693 &(struct argv_s
) { "inquire", OPT_NOARG
, parse_opt_inquire
},
1694 &(struct argv_s
) { "base64", OPT_NOARG
, parse_opt_base64
},
1698 rc
= parse_options(&line
, args
, client
);
1701 return send_error(ctx
, rc
);
1703 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1704 return send_syserror(ctx
, errno
);
1706 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1707 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1708 return send_error(ctx
, GPG_ERR_ENOANO
);
1711 if ((client
->opts
& OPT_INQUIRE
)) {
1712 rc
= assuan_inquire_ext(ctx
, "SAVE", 0, save_command_inquire_finalize
,
1716 return send_error(ctx
, rc
);
1718 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1719 client
->inquire_status
= INQUIRE_BUSY
;
1724 log_write2("ARGS=%s", "<passphrase>");
1726 return save_command_common(ctx
, line
);
1729 static gint
delete_command(assuan_context_t ctx
, gchar
*line
)
1731 struct client_s
*client
= assuan_get_pointer(ctx
);
1736 log_write2("ARGS=\"%s\"", line
);
1738 if (strchr(line
, '\t'))
1739 req
= split_input_line(line
, "\t", -1);
1741 req
= split_input_line(line
, " ", -1);
1744 return send_error(ctx
, GPG_ERR_SYNTAX
);
1746 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1750 return send_error(ctx
, rc
);
1754 * No sub-node defined. Remove the entire node (root element).
1758 rc
= unlink_node(n
);
1763 return send_error(ctx
, rc
);
1766 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1770 return send_error(ctx
, rc
);
1773 rc
= unlink_node(n
);
1777 return send_error(ctx
, rc
);
1781 * Don't return with assuan_process_done() here. This has been called from
1782 * assuan_process_next() and the command should be finished in
1785 static gint
store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1788 assuan_context_t ctx
= data
;
1789 struct client_s
*client
= assuan_get_pointer(ctx
);
1792 gpg_error_t rc
= file_modified(client
);
1794 if (assuan_rc
|| rc
) {
1797 return assuan_rc
? assuan_rc
: rc
;
1800 req
= split_input_line((gchar
*)line
, "\t", 0);
1804 return GPG_ERR_SYNTAX
;
1807 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1809 if (rc
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
1810 rc
= new_root_element(client
->doc
, *req
);
1827 n
= create_elements_cb(n
, req
+1, &rc
, NULL
);
1829 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1830 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
, FALSE
);
1834 client
->inquire_status
= INQUIRE_DONE
;
1837 rc
= update_element_mtime(n
);
1842 static gint
store_command(assuan_context_t ctx
, gchar
*line
)
1844 struct client_s
*client
= assuan_get_pointer(ctx
);
1847 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1850 return send_error(ctx
, rc
);
1852 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1853 client
->inquire_status
= INQUIRE_BUSY
;
1857 static void *send_data_cb(void *arg
)
1859 struct assuan_cmd_s
*data
= arg
;
1863 pth_cancel_state(PTH_CANCEL_ENABLE
|PTH_CANCEL_ASYNCHRONOUS
, &old
);
1864 rc
= g_malloc(sizeof(gpg_error_t
));
1865 *rc
= assuan_send_data(data
->ctx
, data
->line
, data
->line_len
);
1866 pth_cancel_state(old
, NULL
);
1871 /* For every assuan command that needs to be sent to the client, a timeout is
1872 * needed to determine if the client lost the connection. The timeout is the
1873 * same as the "keepalive" configuration parameter or a default if unset.
1875 gpg_error_t
do_assuan_command(assuan_context_t ctx
,
1876 void *(*cb
)(void *data
), void *data
)
1878 pth_attr_t attr
= pth_attr_new();
1881 gint to
= get_key_file_integer("global", "keepalive");
1882 pth_event_t ev
, tev
;
1887 pth_attr_init(attr
);
1888 pth_attr_set(attr
, PTH_ATTR_JOINABLE
, TRUE
);
1889 tid
= pth_spawn(attr
, cb
, data
);
1891 pth_attr_destroy(attr
);
1894 log_write("%s(%i): pth_spawn(): %s", __FILE__
, __LINE__
,
1895 _gpg_strerror(gpg_error_from_errno(n
)));
1896 return gpg_error_from_errno(n
);
1899 pth_cleanup_push(cleanup_cancel_cb
, tid
);
1900 to
= to
<= 0 ? DEFAULT_KEEPALIVE_TO
: to
;
1901 ev
= pth_event(PTH_EVENT_TID
|PTH_UNTIL_TID_DEAD
, tid
);
1902 tev
= to
? pth_event(PTH_EVENT_TIME
, pth_timeout(to
, 0)) : NULL
;
1903 ev
= pth_event_concat(ev
, tev
, NULL
);
1904 pth_cleanup_push(cleanup_ev_cb
, ev
);
1909 st
= pth_event_status(tev
);
1911 if (st
== PTH_STATUS_OCCURRED
) {
1914 return GPG_ERR_TIMEOUT
;
1918 st
= pth_event_status(ev
);
1920 if (st
== PTH_STATUS_FAILED
) {
1924 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1926 else if (st
== PTH_STATUS_OCCURRED
) {
1928 rc
= *(gpg_error_t
*)p
;
1937 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
1943 struct assuan_cmd_s data
;
1944 gint progress
= get_key_file_integer("global", "xfer_progress");
1947 progress
= progress
>0 ? (progress
/ASSUAN_LINELENGTH
)*ASSUAN_LINELENGTH
: 0;
1948 to_send
= total
< ASSUAN_LINELENGTH
? total
: ASSUAN_LINELENGTH
;
1950 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1957 if (sent
+ to_send
> total
)
1958 to_send
= total
- sent
;
1960 data
.line
= flush
? NULL
: (gchar
*)line
+sent
;
1961 data
.line_len
= flush
? 0 : to_send
;
1962 rc
= do_assuan_command(ctx
, send_data_cb
, &data
);
1965 sent
+= flush
? 0 : to_send
;
1967 if ((progress
&& !(sent
% progress
) && sent
!= total
) ||
1968 (sent
== total
&& flush
))
1969 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1971 if (!flush
&& !rc
&& sent
== total
) {
1976 } while (!rc
&& sent
< total
);
1981 static gint
get_command(assuan_context_t ctx
, gchar
*line
)
1983 struct client_s
*client
= assuan_get_pointer(ctx
);
1988 log_write2("ARGS=\"%s\"", line
);
1989 req
= split_input_line(line
, "\t", -1);
1991 if (!req
|| !*req
) {
1993 return send_error(ctx
, GPG_ERR_SYNTAX
);
1996 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
2000 return send_error(ctx
, rc
);
2004 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2009 return send_error(ctx
, rc
);
2011 if (!n
|| !n
->children
)
2012 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2014 n
= find_text_node(n
->children
);
2016 if (!n
|| !n
->content
|| !*n
->content
)
2017 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2019 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
2020 return send_error(ctx
, rc
);
2023 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
2024 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
2026 gchar
*path
= *(gchar
**)data
;
2027 gchar
*tmp
= NULL
, *result
;
2031 *(gchar
**)data
= NULL
;
2034 path
= g_strjoinv("\t", target
);
2037 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2038 *rc
= gpg_error_from_errno(ENOMEM
);
2043 tmp
= g_strjoinv("\t", req_orig
);
2047 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2048 *rc
= gpg_error_from_errno(ENOMEM
);
2054 result
= g_strdup_printf("%s\t%s", path
, tmp
);
2056 result
= g_strdup(path
);
2059 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2060 *rc
= gpg_error_from_errno(ENOMEM
);
2068 *(gchar
**)data
= result
;
2072 static void list_command_cleanup1(void *arg
);
2073 static gint
realpath_command(assuan_context_t ctx
, gchar
*line
)
2076 struct client_s
*client
= assuan_get_pointer(ctx
);
2084 log_write2("ARGS=\"%s\"", line
);
2086 if (strchr(line
, '\t') != NULL
) {
2087 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
2088 return send_error(ctx
, GPG_ERR_SYNTAX
);
2091 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
2092 return send_error(ctx
, GPG_ERR_SYNTAX
);
2095 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
2099 return send_error(ctx
, rc
);
2102 rp
= g_strjoinv("\t", req
);
2106 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2107 return send_syserror(ctx
, ENOMEM
);
2111 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
2112 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
, FALSE
);
2117 return send_error(ctx
, rc
);
2121 string
= g_string_new(rp
);
2126 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2127 return send_syserror(ctx
, ENOMEM
);
2131 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
2132 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
2133 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
2138 pth_cleanup_push(list_command_cleanup1
, string
);
2139 rc
= xfer_data(ctx
, string
->str
, string
->len
);
2141 return send_error(ctx
, rc
);
2144 static void list_command_cleanup1(void *arg
)
2146 g_string_free((GString
*)arg
, TRUE
);
2149 static void list_command_cleanup2(void *arg
)
2151 struct element_list_s
*elements
= arg
;
2154 if (elements
->list
) {
2155 gint total
= g_slist_length(elements
->list
);
2158 for (i
= 0; i
< total
; i
++) {
2159 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
2163 g_slist_free(elements
->list
);
2166 if (elements
->prefix
)
2167 g_free(elements
->prefix
);
2170 g_strfreev(elements
->req
);
2176 static gpg_error_t
parse_list_opt_norecurse(gpointer data
, gpointer value
)
2178 struct element_list_s
*elements
= data
;
2180 elements
->recurse
= FALSE
;
2184 static gpg_error_t
parse_list_opt_verbose(gpointer data
, gpointer value
)
2186 struct element_list_s
*elements
= data
;
2188 elements
->verbose
= TRUE
;
2192 static gint
list_command(assuan_context_t ctx
, gchar
*line
)
2194 struct client_s
*client
= assuan_get_pointer(ctx
);
2196 struct element_list_s
*elements
= NULL
;
2198 struct argv_s
*args
[] = {
2199 &(struct argv_s
) { "no-recurse", OPT_NOARG
, parse_list_opt_norecurse
},
2200 &(struct argv_s
) { "verbose", OPT_NOARG
, parse_list_opt_verbose
},
2204 if (disable_list_and_dump
== TRUE
)
2205 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2207 elements
= g_malloc0(sizeof(struct element_list_s
));
2210 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2211 return gpg_err_code_from_errno(ENOMEM
);
2214 elements
->recurse
= TRUE
; // default
2215 pth_cleanup_push(list_command_cleanup2
, elements
);
2216 rc
= parse_options(&line
, args
, elements
);
2224 rc
= list_root_elements(client
->doc
, &str
, elements
->verbose
);
2228 return send_error(ctx
, rc
);
2231 pth_cleanup_push(list_command_cleanup1
, str
);
2232 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2235 return send_error(ctx
, rc
);
2238 elements
->req
= split_input_line(line
, " ", 0);
2241 strv_printf(&elements
->req
, "%s", line
);
2243 rc
= create_path_list(client
->doc
, elements
, *elements
->req
);
2249 gint total
= g_slist_length(elements
->list
);
2254 rc
= GPG_ERR_NO_VALUE
;
2258 str
= g_string_new(NULL
);
2261 rc
= gpg_err_code_from_errno(ENOMEM
);
2262 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2266 for (i
= 0; i
< total
; i
++) {
2267 tmp
= g_slist_nth_data(elements
->list
, i
);
2268 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
2271 pth_cleanup_push(list_command_cleanup1
, str
);
2272 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2276 rc
= GPG_ERR_NO_VALUE
;
2280 return send_error(ctx
, rc
);
2284 * req[0] - element path
2286 static gpg_error_t
attribute_list(assuan_context_t ctx
, gchar
**req
)
2288 struct client_s
*client
= assuan_get_pointer(ctx
);
2289 gchar
**attrlist
= NULL
;
2291 gchar
**path
= NULL
;
2297 if (!req
|| !req
[0])
2298 return GPG_ERR_SYNTAX
;
2300 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2302 * The first argument may be only a root element.
2304 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2305 return GPG_ERR_SYNTAX
;
2308 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2316 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2317 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2327 for (a
= n
->properties
; a
; a
= a
->next
) {
2330 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
2332 g_strfreev(attrlist
);
2334 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2335 return gpg_error_from_errno(ENOMEM
);
2340 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
,
2341 an
&& an
->content
? (gchar
*)an
->content
: "");
2344 g_strfreev(attrlist
);
2345 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2346 return gpg_error_from_errno(ENOMEM
);
2349 attrlist
[++i
] = NULL
;
2353 return GPG_ERR_NO_VALUE
;
2355 line
= g_strjoinv("\n", attrlist
);
2358 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2359 g_strfreev(attrlist
);
2360 return gpg_error_from_errno(ENOMEM
);
2363 pth_cleanup_push(g_free
, line
);
2364 pth_cleanup_push(req_cleanup
, attrlist
);
2365 rc
= xfer_data(ctx
, line
, strlen(line
));
2372 * req[0] - attribute
2373 * req[1] - element path
2375 static gpg_error_t
attribute_delete(struct client_s
*client
, gchar
**req
)
2378 gchar
**path
= NULL
;
2381 if (!req
|| !req
[0] || !req
[1])
2382 return GPG_ERR_SYNTAX
;
2384 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2386 * The first argument may be only a root element.
2388 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2389 return GPG_ERR_SYNTAX
;
2393 * Don't remove the "_name" attribute for the root element. To remove an
2394 * root element use DELETE <name>.
2396 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"_name")) {
2397 rc
= GPG_ERR_SYNTAX
;
2401 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2407 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2408 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2414 rc
= delete_attribute(n
, (xmlChar
*)req
[0]);
2421 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
2424 gchar
**src
= *path
;
2425 gchar
**src_orig
= g_strdupv(src
);
2426 xmlNodePtr n
= NULL
;
2431 *rc
= gpg_error_from_errno(ENOMEM
);
2432 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2437 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2440 if (*rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
2441 *rc
= new_root_element(client
->doc
, src
[0]);
2454 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
2456 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2457 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
, FALSE
);
2463 * Reset the position of the element tree now that the elements
2464 * have been created.
2469 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2474 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2475 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2483 g_strfreev(src_orig
);
2490 * Creates a "target" attribute. When other commands encounter an element with
2491 * this attribute, the element path is modified to the target value. If the
2492 * source element path doesn't exist when using 'ATTR SET target', it is
2493 * created, but the destination element path must exist.
2495 * req[0] - source element path
2496 * req[1] - destination element path
2498 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2500 gchar
**src
, **dst
, *line
= NULL
, **odst
= NULL
;
2504 if (!req
|| !req
[0] || !req
[1])
2505 return GPG_ERR_SYNTAX
;
2507 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2509 * The first argument may be only a root element.
2511 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2512 return GPG_ERR_SYNTAX
;
2515 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2517 * The first argument may be only a root element.
2519 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2520 rc
= GPG_ERR_SYNTAX
;
2525 odst
= g_strdupv(dst
);
2528 rc
= gpg_error_from_errno(ENOMEM
);
2532 n
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
2535 * Make sure the destination element path exists.
2541 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2542 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2548 n
= create_element_path(client
, &src
, &rc
);
2553 line
= g_strjoinv("\t", odst
);
2556 rc
= gpg_error_from_errno(ENOMEM
);
2557 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2561 rc
= add_attribute(n
, "target", line
);
2575 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2581 tmp
= g_strdupv(req
);
2584 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2585 return gpg_error_from_errno(ENOMEM
);
2588 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2594 if (g_utf8_collate(req
[0], req
[1]) == 0)
2598 * Will not overwrite an existing root.
2600 tmp
= g_strdupv(req
+1);
2603 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2604 return gpg_error_from_errno(ENOMEM
);
2607 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2610 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
2614 return GPG_ERR_AMBIGUOUS_NAME
;
2617 * Whitespace not allowed in root names.
2619 if (contains_whitespace(req
[1]) == TRUE
)
2620 return GPG_ERR_SYNTAX
;
2622 tmp
= g_strdupv(req
);
2625 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2626 return gpg_error_from_errno(ENOMEM
);
2629 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2633 return GPG_ERR_ELEMENT_NOT_FOUND
;
2635 return add_attribute(n
, "_name", req
[1]);
2639 * req[0] - attribute
2640 * req[1] - element path
2642 static gpg_error_t
attribute_get(assuan_context_t ctx
, gchar
**req
)
2644 struct client_s
*client
= assuan_get_pointer(ctx
);
2650 if (!req
|| !req
[0] || !req
[1])
2651 return GPG_ERR_SYNTAX
;
2653 if (strchr(req
[1], '\t')) {
2654 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2655 return GPG_ERR_SYNTAX
;
2658 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2659 return GPG_ERR_SYNTAX
;
2662 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2668 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2669 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2677 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2678 return GPG_ERR_NOT_FOUND
;
2680 pth_cleanup_push(xmlFree
, a
);
2683 rc
= xfer_data(ctx
, (gchar
*)a
, xmlStrlen(a
));
2685 rc
= GPG_ERR_NO_VALUE
;
2696 * req[0] - attribute
2697 * req[1] - element path
2700 static gpg_error_t
attribute_set(struct client_s
*client
, gchar
**req
)
2702 gchar
**path
= NULL
;
2706 if (!req
|| !req
[0] || !req
[1])
2707 return GPG_ERR_SYNTAX
;
2710 * Reserved attribute names.
2712 if (!strcmp(req
[0], "_name")) {
2714 * Only reserved for the root element. Not the rest of the
2717 if (strchr(req
[1], '\t') == NULL
)
2718 return name_attribute(client
, req
+ 1);
2720 else if (!strcmp(req
[0], "target"))
2721 return target_attribute(client
, req
+ 1);
2723 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2725 * The first argument may be only a root element.
2727 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2728 return GPG_ERR_SYNTAX
;
2731 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2737 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2738 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2744 rc
= add_attribute(n
, req
[0], req
[2]);
2753 * req[1] - attribute name or element path if command is LIST
2754 * req[2] - element path
2755 * req[2] - element path or value
2757 static gint
attr_command(assuan_context_t ctx
, gchar
*line
)
2759 struct client_s
*client
= assuan_get_pointer(ctx
);
2763 log_write2("ARGS=\"%s\"", line
);
2764 req
= split_input_line(line
, " ", 4);
2766 if (!req
|| !req
[0] || !req
[1]) {
2768 return send_error(ctx
, GPG_ERR_SYNTAX
);
2771 pth_cleanup_push(req_cleanup
, req
);
2773 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2774 rc
= attribute_set(client
, req
+1);
2775 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2776 rc
= attribute_get(ctx
, req
+1);
2777 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2778 rc
= attribute_delete(client
, req
+1);
2779 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2780 rc
= attribute_list(ctx
, req
+1);
2782 rc
= GPG_ERR_SYNTAX
;
2785 return send_error(ctx
, rc
);
2788 static gint
iscached_command(assuan_context_t ctx
, gchar
*line
)
2790 gchar
**req
= split_input_line(line
, " ", 0);
2794 if (!req
|| !*req
) {
2796 return send_error(ctx
, GPG_ERR_SYNTAX
);
2799 log_write2("ARGS=\"%s\"", line
);
2801 if (!valid_filename(req
[0])) {
2803 return GPG_ERR_INV_VALUE
;
2806 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2809 if (cache_iscached(md5file
)) {
2812 return send_error(ctx
, 0);
2816 tmp
= get_key_file_string("global", "data_directory");
2820 return gpg_error_from_errno(ENOMEM
);
2823 path
= expand_homedir(tmp
);
2828 return gpg_error_from_errno(ENOMEM
);
2833 path
= g_strdup_printf("%s/%s", tmp
, req
[0]);
2838 return gpg_error_from_errno(ENOMEM
);
2841 if (access(path
, R_OK
) == -1) {
2842 gpg_error_t rc
= gpg_error_from_syserror();
2846 return send_error(ctx
, rc
);
2850 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2853 static gint
clearcache_command(assuan_context_t ctx
, gchar
*line
)
2855 struct client_s
*client
= assuan_get_pointer(ctx
);
2856 gchar
**req
= split_input_line(line
, " ", 0);
2859 log_write2("ARGS=\"%s\"", line
);
2862 if (!req
|| !*req
) {
2864 cache_clear(client
->md5file
, 2);
2866 return send_error(ctx
, 0);
2869 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2872 if (cache_clear(md5file
, 1) == FALSE
) {
2874 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2878 return send_error(ctx
, 0);
2881 static gint
cachetimeout_command(assuan_context_t ctx
, gchar
*line
)
2885 gchar
**req
= split_input_line(line
, " ", 0);
2888 if (!req
|| !*req
|| !req
[1]) {
2890 return send_error(ctx
, GPG_ERR_SYNTAX
);
2894 timeout
= strtol(req
[1], &p
, 10);
2896 if (errno
!= 0 || *p
!= 0 || timeout
< -1) {
2898 return send_error(ctx
, GPG_ERR_SYNTAX
);
2901 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2902 CACHE_LOCK(client
->ctx
);
2904 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2906 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2910 return send_error(ctx
, 0);
2913 static gint
dump_command(assuan_context_t ctx
, gchar
*line
)
2917 struct client_s
*client
= assuan_get_pointer(ctx
);
2920 if (disable_list_and_dump
== TRUE
)
2921 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2923 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2926 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2927 return send_syserror(ctx
, ENOMEM
);
2930 pth_cleanup_push(xmlFree
, xml
);
2931 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
2933 return send_error(ctx
, rc
);
2936 static gint
getconfig_command(assuan_context_t ctx
, gchar
*line
)
2938 struct client_s
*client
= assuan_get_pointer(ctx
);
2940 gchar filename
[255]={0}, param
[747]={0};
2941 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2943 log_write2("ARGS=\"%s\"", line
);
2945 if (strchr(line
, ' ')) {
2946 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2951 if (fp
&& !valid_filename(fp
))
2952 return send_error(ctx
, GPG_ERR_INV_VALUE
);
2954 paramp
= g_ascii_strdown(paramp
, -1);
2957 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2958 return send_syserror(ctx
, ENOMEM
);
2961 if (fp
&& !g_ascii_strcasecmp(paramp
, "iterations")) {
2962 if (!(client
->opts
& OPT_ITERATIONS
) || fp
!= client
->filename
) {
2963 file_header_internal_t
*fh
= read_file_header(fp
, FALSE
, &rc
);
2965 if (!fh
&& rc
!= GPG_ERR_ENOENT
)
2966 return send_error(ctx
, rc
);
2970 p
= g_strdup_printf("%lu", (unsigned long)fh
->ver
.fh2
.iter
);
2971 close_file_header(fh
);
2974 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2976 return send_syserror(ctx
, ENOMEM
);
2983 else if (!g_ascii_strcasecmp(paramp
, "enable_pinentry")) {
2984 #ifdef WITH_PINENTRY
2987 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY
))
2988 n
= client
->pinentry
->enable
;
2990 n
= get_key_file_boolean(fp
, "enable_pinentry");
2992 p
= g_strdup_printf("%s", n
? "true" : "false");
2995 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2997 return send_syserror(ctx
, ENOMEM
);
3002 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3005 else if (!g_ascii_strcasecmp(paramp
, "pinentry_timeout")) {
3006 #ifdef WITH_PINENTRY
3007 p
= g_strdup_printf("%i", get_key_file_integer(fp
, "pinentry_timeout"));
3010 log_write("%s(%i): %s", __FILE__
, __LINE__
,
3012 return send_syserror(ctx
, ENOMEM
);
3017 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3021 p
= get_key_file_string(fp
? fp
: "global", paramp
);
3025 return send_error(ctx
, GPG_ERR_NO_VALUE
);
3027 tmp
= expand_homedir(p
);
3031 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3032 return send_syserror(ctx
, ENOMEM
);
3037 pth_cleanup_push(g_free
, p
);
3038 rc
= xfer_data(ctx
, p
, strlen(p
));
3040 return send_error(ctx
, rc
);
3044 xmlXPathContextPtr xp
;
3045 xmlXPathObjectPtr result
;
3050 static void xpath_command_cleanup(void *arg
)
3052 struct xpath_s
*xpath
= arg
;
3054 req_cleanup(xpath
->req
);
3057 xmlBufferFree(xpath
->buf
);
3060 xmlXPathFreeObject(xpath
->result
);
3063 xmlXPathFreeContext(xpath
->xp
);
3066 static gint
xpath_command(assuan_context_t ctx
, gchar
*line
)
3068 struct client_s
*client
= assuan_get_pointer(ctx
);
3070 struct xpath_s xpath
;
3072 log_write2("ARGS=\"%s\"", line
);
3074 if (disable_list_and_dump
== TRUE
)
3075 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3077 if (!line
|| !*line
)
3078 return send_error(ctx
, GPG_ERR_SYNTAX
);
3080 memset(&xpath
, 0, sizeof(struct xpath_s
));
3082 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
3083 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
3084 return send_syserror(ctx
, ENOMEM
);
3087 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3090 xpath_command_cleanup(&xpath
);
3091 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3094 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3096 if (!xpath
.result
) {
3097 xpath_command_cleanup(&xpath
);
3098 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3101 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3102 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3106 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3107 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, 0, NULL
);
3111 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
3112 rc
= GPG_ERR_NO_VALUE
;
3115 else if (xpath
.req
[1])
3118 pth_cleanup_push(xpath_command_cleanup
, &xpath
);
3119 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
.buf
),
3120 xmlBufferLength(xpath
.buf
));
3124 xpath_command_cleanup(&xpath
);
3125 return send_error(ctx
, rc
);
3128 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3129 static gint
xpathattr_command(assuan_context_t ctx
, gchar
*line
)
3131 struct client_s
*client
= assuan_get_pointer(ctx
);
3133 struct xpath_s xpath
;
3135 gboolean cmd
= FALSE
; //SET
3137 log_write2("ARGS=\"%s\"", line
);
3139 if (disable_list_and_dump
== TRUE
)
3140 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3142 if (!line
|| !*line
)
3143 return send_error(ctx
, GPG_ERR_SYNTAX
);
3145 memset(&xpath
, 0, sizeof(struct xpath_s
));
3147 if ((req
= split_input_line(line
, " ", 3)) == NULL
)
3148 return send_syserror(ctx
, ENOMEM
);
3151 rc
= GPG_ERR_SYNTAX
;
3155 if (!g_ascii_strcasecmp(req
[0], "SET"))
3157 else if (!g_ascii_strcasecmp(req
[0], "DELETE"))
3160 rc
= GPG_ERR_SYNTAX
;
3164 if (!req
[1] || !req
[2]) {
3165 rc
= GPG_ERR_SYNTAX
;
3169 if ((xpath
.req
= split_input_line(req
[2], "\t", 3)) == NULL
) {
3170 rc
= gpg_err_code_from_errno(ENOMEM
);
3174 if (!xpath
.req
[0] || (!xpath
.req
[1] && !cmd
) || (xpath
.req
[1] && cmd
)) {
3175 rc
= GPG_ERR_SYNTAX
;
3179 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3182 rc
= EPWMD_LIBXML_ERROR
;
3186 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3188 if (!xpath
.result
) {
3189 rc
= EPWMD_LIBXML_ERROR
;
3193 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3194 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3198 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3199 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, cmd
, (xmlChar
*)req
[1]);
3203 xpath_command_cleanup(&xpath
);
3204 return send_error(ctx
, rc
);
3207 static gint
import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
3210 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
3211 gpg_error_t rc
= file_modified(client
);
3212 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
3213 xmlDocPtr doc
= NULL
;
3214 xmlNodePtr n
, root
, copy
;
3216 if (assuan_rc
|| rc
) {
3219 return assuan_rc
? assuan_rc
: rc
;
3222 req
= split_input_line((gchar
*)line
, "\t", 2);
3226 return GPG_ERR_SYNTAX
;
3229 path
= split_input_line(req
[1], "\t", 0);
3231 if (!content
|| !*content
) {
3232 rc
= GPG_ERR_SYNTAX
;
3236 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
3239 rc
= EPWMD_LIBXML_ERROR
;
3243 root
= xmlDocGetRootElement(doc
);
3244 rc
= validate_import(root
);
3250 path_orig
= g_strdupv(path
);
3253 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3254 rc
= gpg_error_from_errno(ENOMEM
);
3258 xmlChar
*a
= xmlGetProp(root
, (xmlChar
*)"_name");
3261 g_strfreev(path_orig
);
3262 rc
= gpg_error_from_errno(ENOMEM
);
3266 if (strv_printf(&path
, "%s", (gchar
*)a
) == FALSE
) {
3268 g_strfreev(path_orig
);
3269 rc
= gpg_error_from_errno(ENOMEM
);
3274 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
3276 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3277 g_strfreev(path_orig
);
3282 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, TRUE
);
3284 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3285 g_strfreev(path_orig
);
3289 xmlNodePtr parent
= n
->parent
;
3300 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
3301 n
= create_element_path(client
, &path
, &rc
);
3307 copy
= xmlCopyNodeList(root
);
3308 n
= xmlAddChildList(n
, copy
);
3311 rc
= EPWMD_LIBXML_ERROR
;
3314 /* Check if the content root element can create a DTD root element. */
3315 if (!xmlStrEqual((xmlChar
*)"element", root
->name
)) {
3316 rc
= GPG_ERR_SYNTAX
;
3322 if ((a
= xmlGetProp(root
, (xmlChar
*)"_name")) == NULL
) {
3323 rc
= GPG_ERR_SYNTAX
;
3327 gchar
*tmp
= g_strdup((gchar
*)a
);
3329 gboolean literal
= is_literal_element(&tmp
);
3331 if (!valid_xml_element((xmlChar
*)tmp
) || literal
) {
3333 rc
= GPG_ERR_INV_VALUE
;
3337 if (strv_printf(&path
, "%s", tmp
) == FALSE
) {
3339 rc
= gpg_error_from_errno(ENOMEM
);
3344 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, TRUE
);
3346 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3347 rc
= EPWMD_LIBXML_ERROR
;
3351 /* Overwriting the existing tree. */
3358 xmlSetProp(root
, (xmlChar
*)"_name", (xmlChar
*)path
[0]);
3359 n
= xmlCopyNode(root
, 1);
3360 n
= xmlAddChildList(xmlDocGetRootElement(client
->doc
), n
);
3364 rc
= update_element_mtime(n
->parent
);
3374 client
->inquire_status
= INQUIRE_DONE
;
3378 static gint
import_command(assuan_context_t ctx
, gchar
*line
)
3381 struct client_s
*client
= assuan_get_pointer(ctx
);
3383 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
3386 return send_error(ctx
, rc
);
3388 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3389 client
->inquire_status
= INQUIRE_BUSY
;
3393 static gpg_error_t
do_lock_command(struct client_s
*client
)
3395 gpg_error_t rc
= lock_file_mutex(client
);
3398 client
->is_lock_cmd
= TRUE
;
3400 return client
->opts
& OPT_INQUIRE
? rc
: send_error(client
->ctx
, rc
);
3403 static gint
lock_command(assuan_context_t ctx
, gchar
*line
)
3405 struct client_s
*client
= assuan_get_pointer(ctx
);
3407 return do_lock_command(client
);
3410 static gint
unlock_command(assuan_context_t ctx
, gchar
*line
)
3412 struct client_s
*client
= assuan_get_pointer(ctx
);
3414 unlock_file_mutex(client
);
3415 return send_error(ctx
, 0);
3418 static gint
getpid_command(assuan_context_t ctx
, gchar
*line
)
3422 pid_t pid
= getpid();
3424 print_fmt(buf
, sizeof(buf
), "%i", pid
);
3425 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3426 return send_error(ctx
, rc
);
3429 static gint
version_command(assuan_context_t ctx
, gchar
*line
)
3434 print_fmt(buf
, sizeof(buf
), "0x%X", VERSION_HEX
);
3435 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3436 return send_error(ctx
, rc
);
3439 #ifdef WITH_PINENTRY
3440 static void set_option_value(gchar
**opt
, const gchar
*value
)
3448 *opt
= g_strdup(value
);
3452 static gint
set_unset_common(assuan_context_t ctx
, const gchar
*name
,
3455 struct client_s
*client
= assuan_get_pointer(ctx
);
3458 if (g_ascii_strcasecmp(name
, (gchar
*)"log_level") == 0) {
3462 l
= strtol(value
, NULL
, 10);
3465 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3468 MUTEX_LOCK(&rcfile_mutex
);
3469 g_key_file_set_integer(keyfileh
, "global", "log_level", (gint
)l
);
3470 MUTEX_UNLOCK(&rcfile_mutex
);
3473 else if (g_ascii_strcasecmp(name
, (gchar
*)"rc_on_locked") == 0) {
3477 l
= strtol(value
, NULL
, 10);
3480 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3483 client
->rc_on_locked
= l
? TRUE
: FALSE
;
3486 else if (g_ascii_strcasecmp(name
, (gchar
*)"lock_on_open") == 0) {
3487 rc
= parse_open_opt_lock(client
, (gpointer
)value
);
3492 client
->opts
|= OPT_LOCK
;
3494 else if (g_ascii_strcasecmp(name
, (gchar
*)"cipher") == 0) {
3496 client
->opts
&= ~(OPT_CIPHER
);
3500 rc
= parse_save_opt_cipher(client
, (gpointer
)value
);
3505 client
->opts
|= OPT_CIPHER
;
3508 else if (g_ascii_strcasecmp(name
, (gchar
*)"iterations") == 0) {
3509 rc
= parse_save_opt_iterations(client
, (gpointer
)value
);
3516 else if (g_ascii_strcasecmp(name
, (gchar
*)"NAME") == 0) {
3517 pth_attr_t attr
= pth_attr_of(pth_self());
3521 pth_attr_destroy(attr
);
3525 print_fmt(buf
, sizeof(buf
), "%s", value
);
3526 pth_attr_set(attr
, PTH_ATTR_NAME
, buf
);
3527 pth_attr_destroy(attr
);
3528 #ifdef WITH_PINENTRY
3529 if (client
->pinentry
->name
)
3530 g_free(client
->pinentry
->name
);
3532 client
->pinentry
->name
= g_strdup(buf
);
3534 if (!client
->pinentry
->name
)
3535 return gpg_error_from_errno(ENOMEM
);
3540 #ifdef WITH_PINENTRY
3541 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3542 set_option_value(&client
->pinentry
->lcmessages
, value
);
3543 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3544 set_option_value(&client
->pinentry
->lcctype
, value
);
3545 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3546 set_option_value(&client
->pinentry
->ttyname
, value
);
3547 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3548 set_option_value(&client
->pinentry
->ttytype
, value
);
3549 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3550 set_option_value(&client
->pinentry
->display
, value
);
3551 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3552 set_option_value(&client
->pinentry
->path
, value
);
3553 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3554 set_option_value(&client
->pinentry
->title
, value
);
3555 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3556 set_option_value(&client
->pinentry
->prompt
, value
);
3557 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3558 set_option_value(&client
->pinentry
->desc
, value
);
3559 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0) {
3566 n
= strtol(value
, &p
, 10);
3569 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3571 MUTEX_LOCK(&rcfile_mutex
);
3572 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
:
3573 "global", "pinentry_timeout", n
);
3574 MUTEX_UNLOCK(&rcfile_mutex
);
3577 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0) {
3578 rc
= parse_opt_pinentry(client
, (gpointer
)value
);
3587 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
3593 static gint
unset_command(assuan_context_t ctx
, gchar
*line
)
3595 log_write2("ARGS=\"%s\"", line
);
3596 return send_error(ctx
, set_unset_common(ctx
, line
, NULL
));
3599 static gint
set_command(assuan_context_t ctx
, gchar
*line
)
3601 gchar name
[64] = {0}, value
[256] = {0};
3603 log_write2("ARGS=\"%s\"", line
);
3605 if (sscanf(line
, " %63[_a-zA-Z] = %255c", name
, value
) != 2)
3606 return send_error(ctx
, gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
));
3608 return send_error(ctx
, set_unset_common(ctx
, name
, value
));
3611 static gint
rename_command(assuan_context_t ctx
, gchar
*line
)
3613 struct client_s
*client
= assuan_get_pointer(ctx
);
3615 gchar
**req
, **src
, *dst
;
3618 log_write2("ARGS=\"%s\"", line
);
3619 req
= split_input_line(line
, " ", -1);
3621 if (!req
|| !req
[0] || !req
[1]) {
3623 return send_error(ctx
, GPG_ERR_SYNTAX
);
3627 is_literal_element(&dst
);
3629 if (!valid_xml_element((xmlChar
*)dst
)) {
3631 return GPG_ERR_INV_VALUE
;
3634 if (strchr(req
[0], '\t'))
3635 src
= split_input_line(req
[0], "\t", -1);
3637 src
= split_input_line(req
[0], " ", -1);
3639 if (!src
|| !*src
) {
3640 rc
= GPG_ERR_SYNTAX
;
3644 n
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3647 n
= find_elements(client
->doc
, n
->children
, src
+1, &rc
, NULL
, NULL
,
3648 NULL
, FALSE
, 0, NULL
, FALSE
);
3654 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
3657 rc
= gpg_error_from_errno(ENOMEM
);
3661 /* To prevent unwanted effects:
3663 * <root name="a"><b/></root>
3667 if (xmlStrEqual(a
, (xmlChar
*)dst
)) {
3669 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3679 for (p
= src
; *p
; p
++) {
3683 strv_printf(&tmp
, "%s", *p
);
3687 strv_printf(&tmp
, "!%s", dst
);
3688 ndst
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
3690 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3696 ndst
= find_elements(client
->doc
, ndst
->children
, tmp
+1, &rc
, NULL
,
3697 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3701 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3706 /* Target may exist:
3709 * <root name="b" target="a"/>
3717 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3723 xmlFreeNodeList(ndst
);
3726 rc
= add_attribute(n
, "_name", dst
);
3731 return send_error(ctx
, rc
);
3734 static gint
copy_command(assuan_context_t ctx
, gchar
*line
)
3736 struct client_s
*client
= assuan_get_pointer(ctx
);
3738 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3739 xmlNodePtr nsrc
, ndst
, new;
3741 log_write2("ARGS=\"%s\"", line
);
3742 req
= split_input_line(line
, " ", -1);
3744 if (!req
|| !req
[0] || !req
[1]) {
3746 return send_error(ctx
, GPG_ERR_SYNTAX
);
3749 if (strchr(req
[0], '\t'))
3750 src
= split_input_line(req
[0], "\t", -1);
3752 src
= split_input_line(req
[0], " ", -1);
3754 if (!src
|| !*src
) {
3755 rc
= GPG_ERR_SYNTAX
;
3759 if (strchr(req
[1], '\t'))
3760 dst
= split_input_line(req
[1], "\t", -1);
3762 dst
= split_input_line(req
[1], " ", -1);
3764 if (!dst
|| !*dst
) {
3765 rc
= GPG_ERR_SYNTAX
;
3769 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3772 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3773 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3778 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3781 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3782 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3784 if (!ndst
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3787 new = xmlCopyNodeList(nsrc
);
3790 rc
= GPG_ERR_ENOMEM
;
3795 ndst
= create_element_path(client
, &dst
, &rc
);
3799 xmlFreeNodeList(new);
3803 /* Merge any attributes from the src node to the initial dst node. */
3804 for (xmlAttrPtr attr
= new->properties
; attr
; attr
= attr
->next
) {
3805 if (xmlStrEqual(attr
->name
, (xmlChar
*)"_name"))
3808 xmlAttrPtr a
= xmlHasProp(ndst
, attr
->name
);
3813 xmlChar
*tmp
= xmlNodeGetContent(attr
->children
);
3814 xmlNewProp(ndst
, attr
->name
, tmp
);
3816 rc
= add_attribute(ndst
, NULL
, NULL
);
3819 xmlNodePtr n
= ndst
->children
;
3822 ndst
->children
= NULL
;
3824 if (!new->children
) {
3826 xmlFreeNodeList(new);
3830 n
= xmlCopyNodeList(new->children
);
3833 rc
= GPG_ERR_ENOMEM
;
3838 xmlFreeNodeList(new);
3839 n
= xmlAddChildList(ndst
, n
);
3842 rc
= GPG_ERR_ENOMEM
;
3846 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
) == ndst
->parent
? ndst
: ndst
->parent
);
3858 return send_error(ctx
, rc
);
3861 static gint
move_command(assuan_context_t ctx
, gchar
*line
)
3863 struct client_s
*client
= assuan_get_pointer(ctx
);
3865 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3866 xmlNodePtr nsrc
, ndst
= NULL
;
3868 log_write2("ARGS=\"%s\"", line
);
3869 req
= split_input_line(line
, " ", -1);
3871 if (!req
|| !req
[0] || !req
[1]) {
3873 return send_error(ctx
, GPG_ERR_SYNTAX
);
3876 if (strchr(req
[0], '\t'))
3877 src
= split_input_line(req
[0], "\t", -1);
3879 src
= split_input_line(req
[0], " ", -1);
3881 if (!src
|| !*src
) {
3882 rc
= GPG_ERR_SYNTAX
;
3886 if (strchr(req
[1], '\t'))
3887 dst
= split_input_line(req
[1], "\t", -1);
3889 dst
= split_input_line(req
[1], " ", -1);
3891 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3894 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3895 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3901 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3904 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3905 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3908 ndst
= xmlDocGetRootElement(client
->doc
);
3910 for (xmlNodePtr n
= ndst
; n
; n
= n
->parent
) {
3912 rc
= GPG_ERR_CONFLICT
;
3917 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3923 xmlChar
*a
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
3924 xmlNodePtr dup
= find_element(ndst
->children
, (gchar
*)a
, NULL
);
3932 if (ndst
== xmlDocGetRootElement(client
->doc
)) {
3933 xmlNodePtr n
= nsrc
;
3934 gboolean match
= FALSE
;
3936 while (n
->parent
&& n
->parent
!= ndst
)
3939 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
3940 xmlChar
*b
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
3942 if (xmlStrEqual(a
, b
)) {
3944 xmlUnlinkNode(nsrc
);
3954 xmlFreeNodeList(dup
);
3963 ndst
= create_element_path(client
, &dst
, &rc
);
3968 update_element_mtime(nsrc
->parent
);
3969 xmlUnlinkNode(nsrc
);
3970 ndst
= xmlAddChildList(ndst
, nsrc
);
3973 rc
= GPG_ERR_ENOMEM
;
3975 update_element_mtime(ndst
->parent
);
3987 return send_error(ctx
, rc
);
3990 static int ls_command(assuan_context_t ctx
, gchar
*line
)
3992 log_write2("ARGS=\"%s\"", line
);
3994 gchar
*tmp
= g_key_file_get_string(keyfileh
, "global", "data_directory", NULL
);
3995 gchar
*dir
= expand_homedir(tmp
);
3996 DIR *d
= opendir(dir
);
4003 return send_syserror(ctx
, n
);
4006 size_t len
= offsetof(struct dirent
, d_name
)+pathconf(dir
, _PC_NAME_MAX
)+1;
4007 struct dirent
*p
= g_malloc(len
), *cur
= NULL
;
4013 while (!readdir_r(d
, p
, &cur
) && cur
) {
4014 if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '\0')
4016 else if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '.' && cur
->d_name
[2] == '\0')
4019 tmp
= g_strdup_printf("%s%s\n", list
? list
: "", cur
->d_name
);
4025 rc
= GPG_ERR_ENOMEM
;
4037 return send_error(ctx
, rc
);
4040 return send_error(ctx
, GPG_ERR_NO_VALUE
);
4042 list
[strlen(list
)-1] = 0;
4043 rc
= xfer_data(ctx
, list
, strlen(list
));
4045 return send_error(ctx
, rc
);
4048 static void bye_notify(assuan_context_t ctx
)
4050 struct client_s
*cl
= assuan_get_pointer(ctx
);
4052 /* This will let assuan_process_next() return. */
4053 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
4056 static void reset_notify(assuan_context_t ctx
)
4058 struct client_s
*cl
= assuan_get_pointer(ctx
);
4065 * This is called before every Assuan command.
4067 gint
command_startup(assuan_context_t ctx
, const gchar
*name
)
4069 struct client_s
*cl
= assuan_get_pointer(ctx
);
4072 log_write1("%s", name
);
4074 if (!g_ascii_strcasecmp(name
, "ISCACHED") ||
4075 !g_ascii_strcasecmp(name
, "CLEARCACHE") ||
4076 !g_ascii_strcasecmp(name
, "CACHETIMEOUT") ||
4077 !g_ascii_strcasecmp(name
, "GETCONFIG") ||
4078 !g_ascii_strcasecmp(name
, "GETPID") ||
4079 !g_ascii_strcasecmp(name
, "VERSION") ||
4080 !g_ascii_strcasecmp(name
, "SET") ||
4081 !g_ascii_strcasecmp(name
, "BYE") ||
4082 !g_ascii_strcasecmp(name
, "NOP") ||
4083 !g_ascii_strcasecmp(name
, "CANCEL") ||
4084 !g_ascii_strcasecmp(name
, "RESET") ||
4085 !g_ascii_strcasecmp(name
, "END") ||
4086 !g_ascii_strcasecmp(name
, "HELP") ||
4087 !g_ascii_strcasecmp(name
, "OPTION") ||
4088 !g_ascii_strcasecmp(name
, "INPUT") ||
4089 !g_ascii_strcasecmp(name
, "OUTPUT") ||
4090 !g_ascii_strcasecmp(name
, "LS") ||
4091 !g_ascii_strcasecmp(name
, "UNSET"))
4094 #ifdef WITH_PINENTRY
4095 if (!(cl
->opts
& OPT_PINENTRY
))
4096 reset_pin_defaults(cl
->pinentry
);
4099 cl
->last_rc
= rc
= file_modified(cl
);
4102 if ((rc
== EPWMD_NO_FILE
|| rc
== EPWMD_FILE_MODIFIED
) &&
4103 !g_ascii_strcasecmp(name
, "OPEN"))
4111 * This is called after every Assuan command.
4113 void command_finalize(assuan_context_t ctx
, gint rc
)
4115 struct client_s
*client
= assuan_get_pointer(ctx
);
4117 if (!client
->is_lock_cmd
)
4118 unlock_file_mutex(client
);
4120 log_write1(N_("command completed (rc=%u)"), client
->last_rc
);
4121 client
->opts
&= ~(OPT_INQUIRE
);
4122 client
->opts
&= ~(OPT_BASE64
);
4125 gpg_error_t
register_commands(assuan_context_t ctx
)
4129 gint (*handler
)(assuan_context_t
, gchar
*line
);
4131 { "OPEN", open_command
},
4132 { "SAVE", save_command
},
4133 { "LIST", list_command
},
4134 { "REALPATH", realpath_command
},
4135 { "STORE", store_command
},
4136 { "DELETE", delete_command
},
4137 { "GET", get_command
},
4138 { "ATTR", attr_command
},
4139 { "ISCACHED", iscached_command
},
4140 { "CLEARCACHE", clearcache_command
},
4141 { "CACHETIMEOUT", cachetimeout_command
},
4142 { "GETCONFIG", getconfig_command
},
4143 { "DUMP", dump_command
},
4144 { "XPATH", xpath_command
},
4145 { "XPATHATTR", xpathattr_command
},
4146 { "IMPORT", import_command
},
4147 { "LOCK", lock_command
},
4148 { "UNLOCK", unlock_command
},
4149 { "GETPID", getpid_command
},
4150 { "VERSION", version_command
},
4151 { "SET", set_command
},
4152 { "UNSET", unset_command
},
4153 { "RENAME", rename_command
},
4154 { "COPY", copy_command
},
4155 { "LS", ls_command
},
4156 { "MOVE", move_command
},
4163 for (i
=0; table
[i
].name
; i
++) {
4164 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
4170 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
4175 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
4180 rc
= assuan_register_pre_cmd_notify(ctx
, command_startup
);
4185 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
4188 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
,
4189 struct crypto_s
*crypto
, gpointer
*dst
, goffset
*dst_len
)
4191 goffset insize
, len
;
4192 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
4193 guint64 iter
= 0ULL, n_iter
= 0ULL, iter_progress
= 0ULL;
4197 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->ver
.fh1
) : sizeof(crypto
->fh
->ver
.fh2
);
4198 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->ver
.fh1
.iter
: crypto
->fh
->ver
.fh2
.iter
;
4199 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
4201 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
4202 insize
= crypto
->fh
->st
.st_size
- fh_size
;
4203 crypto
->iv
= gcry_malloc(crypto
->blocksize
);
4206 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
4207 return gpg_error_from_errno(ENOMEM
);
4211 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh1
.iv
, crypto
->blocksize
);
4213 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
4215 crypto
->inbuf
= gcry_malloc(insize
);
4217 if (!crypto
->inbuf
) {
4218 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
4219 return gpg_error_from_errno(ENOMEM
);
4222 crypto
->insize
= insize
;
4223 len
= pth_read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
4225 if (len
!= crypto
->insize
)
4226 return GPG_ERR_INV_LENGTH
;
4228 /* No encryption iterations. This is a plain (gzipped) file. */
4229 if ((crypto
->fh
->v1
&& (long)fh_iter
< 0L) ||
4230 (!crypto
->fh
->v1
&& fh_iter
<= 0L)) {
4232 * cache_file_count() needs both .used == TRUE and a valid key in
4233 * order for it to count as a used cache entry. Fixes CACHE status
4236 memset(crypto
->key
, '!', hashlen
);
4240 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4241 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
4245 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
4246 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
4250 iter_progress
= (guint64
)get_key_file_double(client
&& client
->filename
?
4251 client
->filename
: "global", "iteration_progress");
4253 if (iter_progress
> 0ULL && fh_iter
>= iter_progress
) {
4254 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
4260 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4265 crypto
->tkey
= gcry_malloc(hashlen
);
4267 if (!crypto
->tkey
) {
4268 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
4269 return gpg_error_from_errno(ENOMEM
);
4272 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
4273 guchar
*tkey
= crypto
->tkey
;
4276 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
4277 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
4281 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
4282 if (iter_progress
> 0ULL && iter
>= iter_progress
) {
4283 if (!(iter
% iter_progress
)) {
4284 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
4285 ++n_iter
* iter_progress
, fh_iter
);
4292 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4293 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
4297 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4300 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
4307 if (iter_progress
&& fh_iter
>= iter_progress
) {
4308 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
4315 if (do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
4316 (gpointer
*)&crypto
->outbuf
, &outsize
, &zrc
) == FALSE
) {
4317 if (zrc
== Z_MEM_ERROR
)
4318 return gpg_error_from_errno(ENOMEM
);
4320 return GPG_ERR_INV_PASSPHRASE
; // Not a valid gzip header. Must be a bad key.
4323 if (g_strncasecmp(crypto
->outbuf
, "<?xml ", 6) != 0) {
4324 gcry_free(crypto
->outbuf
);
4325 crypto
->outbuf
= NULL
;
4326 return GPG_ERR_INV_PASSPHRASE
;
4330 client
->xml
= crypto
->outbuf
;
4331 client
->len
= outsize
;
4332 crypto
->outbuf
= NULL
;
4335 *dst
= crypto
->outbuf
;
4337 crypto
->outbuf
= NULL
;
4340 /* The calling function should free the crypto struct. */