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
28 #include <sys/types.h>
49 #include "pwmd_error.h"
62 static guchar crypto_magic
[5] = "\177PWMD";
64 static gpg_error_t
do_lock_command(struct client_s
*client
);
66 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
68 return gcry_calloc(items
, size
);
71 static void z_free(void *data
, void *p
)
76 static gpg_error_t
file_modified(struct client_s
*client
)
81 if (client
->state
!= STATE_OPEN
)
84 rc
= lock_file_mutex(client
);
89 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
90 if (client
->mtime
!= st
.st_mtime
)
91 return EPWMD_FILE_MODIFIED
;
98 static gpg_error_t
parse_xml(assuan_context_t ctx
)
100 struct client_s
*client
= assuan_get_pointer(ctx
);
102 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
105 return EPWMD_LIBXML_ERROR
;
107 if (!client
->crypto
->fh
|| client
->crypto
->fh
->ver
.fh2
.version
>= 0x212)
110 return convert_elements(client
->doc
);
113 void unlock_file_mutex(struct client_s
*client
)
117 if (client
->has_lock
== FALSE
)
120 CACHE_LOCK(client
->ctx
);
122 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
129 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
132 gpg_error_t
lock_file_mutex(struct client_s
*client
)
137 if (client
->has_lock
== TRUE
)
140 CACHE_LOCK(client
->ctx
);
142 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
149 if (client
->rc_on_locked
) {
150 if (!pth_mutex_acquire(m
, TRUE
, NULL
))
151 return GPG_ERR_LOCKED
;
157 MUTEX_TRYLOCK(client
, m
, rc
);
160 client
->has_lock
= TRUE
;
165 void free_client(struct client_s
*client
)
168 xmlFreeDoc(client
->doc
);
171 gcry_free(client
->xml
);
173 if (client
->filename
)
174 g_free(client
->filename
);
177 cleanup_crypto(&client
->crypto
);
179 if (client
->xml_error
)
180 xmlResetError(client
->xml_error
);
183 void cleanup_client(struct client_s
*client
)
185 assuan_context_t ctx
= client
->ctx
;
186 struct client_thread_s
*thd
= client
->thd
;
187 gboolean rc_on_locked
= client
->rc_on_locked
;
188 gboolean lock_on_open
= client
->lock_on_open
;
190 struct pinentry_s
*pin
= client
->pinentry
;
193 unlock_file_mutex(client
);
194 CACHE_LOCK(client
->ctx
);
195 cache_decr_refcount(client
->md5file
);
198 * This may be a new file so don't use a cache slot. save_command() will
199 * set this to FALSE on success.
201 if (client
->new == TRUE
)
202 cache_clear(client
->md5file
, 1);
206 memset(client
, 0, sizeof(struct client_s
));
207 client
->state
= STATE_CONNECTED
;
210 client
->freed
= TRUE
;
212 client
->pinentry
= pin
;
214 client
->rc_on_locked
= rc_on_locked
;
215 client
->lock_on_open
= lock_on_open
;
218 static void gz_cleanup(void *arg
)
220 struct gz_s
**gz
= (struct gz_s
**)arg
;
225 if (!(*gz
)->done
&& (*gz
)->out
)
226 gcry_free((*gz
)->out
);
228 if ((*gz
)->which
== STATUS_COMPRESS
) {
230 deflateEnd(&(*gz
)->z
);
234 inflateEnd(&(*gz
)->z
);
241 gpg_error_t
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
242 gpointer
*out
, gulong
*outsize
)
250 gz
= g_malloc0(sizeof(struct gz_s
));
253 return GPG_ERR_ENOMEM
;
255 pth_cleanup_push(gz_cleanup
, &gz
);
256 gz
->which
= STATUS_DECOMPRESS
;
257 gz
->z
.zalloc
= z_alloc
;
258 gz
->z
.zfree
= z_free
;
260 gz
->z
.avail_in
= (uInt
)insize
;
261 gz
->z
.avail_out
= zlib_bufsize
;
262 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
265 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
267 return GPG_ERR_ENOMEM
;
270 zrc
= inflateInit2(&gz
->z
, 47);
273 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
275 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
278 memset(&h
, 0, sizeof(gz_header
));
279 h
.comment
= (guchar
*)buf
;
280 h
.comm_max
= sizeof(buf
);
281 zrc
= inflateGetHeader(&gz
->z
, &h
);
284 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
286 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
289 zrc
= inflate(&gz
->z
, Z_BLOCK
);
292 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
294 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
298 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
303 zrc
= inflate(&gz
->z
, Z_FINISH
);
309 if (!gz
->z
.avail_out
) {
310 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
313 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
319 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
320 gz
->z
.avail_out
= zlib_bufsize
;
321 rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
322 gz
->z
.total_out
, insize
);
331 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
332 rc
= GPG_ERR_COMPR_ALGO
;
336 } while (zrc
!= Z_STREAM_END
);
338 rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
345 *outsize
= gz
->z
.total_out
;
355 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
360 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
367 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
368 *rc
= GPG_ERR_ENOMEM
;
372 pth_cleanup_push(g_free
, fh
);
373 fh_size
= v1
? sizeof(fh
->ver
.fh1
) : sizeof(fh
->ver
.fh2
);
375 if (lstat(filename
, &fh
->st
) == -1) {
376 *rc
= gpg_error_from_syserror();
381 if (!S_ISREG(fh
->st
.st_mode
)) {
382 *rc
= GPG_ERR_ENOANO
;
387 fd
= open(filename
, O_RDONLY
);
390 *rc
= gpg_error_from_syserror();
395 pth_cleanup_push(cleanup_fd_cb
, &fd
);
396 p
= v1
? (void *)&fh
->ver
.fh1
: (void *)&fh
->ver
.fh2
;
397 len
= pth_read(fd
, p
, fh_size
);
399 if (len
!= fh_size
) {
400 *rc
= gpg_error_from_syserror();
413 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*unused
,
416 struct client_s
*client
= assuan_get_pointer(ctx
);
419 guchar
*key
= client
->crypto
->key
;
422 if (!client
->crypto
->fh
) {
429 rc
= init_client_crypto2(client
->filename
, client
->crypto
);
432 cleanup_client(client
);
433 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
436 rc
= try_xml_decrypt(ctx
, client
->crypto
, NULL
, NULL
);
439 cleanup_client(client
);
440 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
444 CACHE_LOCK(client
->ctx
);
446 if (cached
== FALSE
) {
447 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
448 cleanup_client(client
);
450 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
453 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
454 cache_reset_timeout(client
->md5file
, timeout
);
457 cache_set_timeout(client
->md5file
, -2);
465 gcry_free(client
->xml
);
470 if (client
->new == FALSE
)
471 send_status_all(STATUS_CACHE
);
473 client
->state
= STATE_OPEN
;
476 if (!rc
&& client
->new == FALSE
&&
477 client
->crypto
->fh
->ver
.fh2
.iter
!= (guint64
)get_key_file_double(client
->filename
, "iterations")) {
478 MUTEX_LOCK(&rcfile_mutex
);
479 g_key_file_set_double(keyfileh
, client
->filename
, "iterations",
480 client
->crypto
->fh
->ver
.fh2
.iter
);
481 MUTEX_UNLOCK(&rcfile_mutex
);
482 send_status_all(STATUS_CONFIG
);
485 cleanup_crypto(&client
->crypto
);
487 if (!rc
&& client
->lock_on_open
)
488 return do_lock_command(client
);
490 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
493 static void req_cleanup(void *arg
)
498 g_strfreev((gchar
**)arg
);
501 static gpg_error_t
parse_open_opt_lock(gpointer data
, gpointer value
)
503 struct client_s
*client
= data
;
504 const gchar
*p
= value
;
507 long l
= strtol(p
, NULL
, 10);
510 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
512 client
->lock_on_open
= l
? TRUE
: FALSE
;
514 else if ((!p
|| !*p
) && (client
->opts
& OPT_LOCK
))
515 client
->lock_on_open
= FALSE
;
517 client
->lock_on_open
= TRUE
;
522 static gpg_error_t
parse_opt_pinentry(gpointer data
, gpointer value
)
525 struct client_s
*client
= data
;
531 client
->pinentry
->enable
= -1;
532 client
->opts
&= ~(OPT_PINENTRY
);
536 n
= strtol(str
, &p
, 10);
538 if (*p
|| n
< 0 || n
> 1)
539 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
541 client
->pinentry
->enable
= n
? TRUE
: FALSE
;
542 client
->opts
|= OPT_PINENTRY
;
545 return GPG_ERR_NOT_IMPLEMENTED
;
549 static gpg_error_t
parse_opt_inquire(gpointer data
, gpointer value
)
551 struct client_s
*client
= data
;
554 client
->opts
|= OPT_INQUIRE
;
558 static gpg_error_t
parse_opt_base64(gpointer data
, gpointer value
)
560 struct client_s
*client
= data
;
563 client
->opts
|= OPT_BASE64
;
567 static gpg_error_t
hash_key(struct client_s
*client
, const gchar
*key
)
572 if (client
->opts
& OPT_BASE64
)
573 tmp
= g_base64_decode(key
, &len
);
575 tmp
= (guchar
*)g_strdup(key
);
580 return GPG_ERR_ENOMEM
;
582 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, tmp
, len
);
587 static gpg_error_t
open_command_common(assuan_context_t ctx
, gchar
*line
)
589 gboolean cached
= FALSE
;
591 struct client_s
*client
= assuan_get_pointer(ctx
);
593 gchar
*filename
= NULL
;
594 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
596 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
599 pth_cleanup_push(req_cleanup
, req
);
601 if (!filename
|| !*filename
) {
603 return client
->opts
& OPT_INQUIRE
? GPG_ERR_SYNTAX
: send_error(ctx
, GPG_ERR_SYNTAX
);
606 log_write2("ARGS=\"%s\" %s", filename
, req
[1] ? "<passphrase>" : "");
608 if (valid_filename(filename
) == FALSE
) {
610 return client
->opts
& OPT_INQUIRE
? GPG_ERR_INV_VALUE
: send_error(ctx
, GPG_ERR_INV_VALUE
);
613 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
614 CACHE_LOCK(client
->ctx
);
616 if (cache_has_file(client
->md5file
) == FALSE
) {
617 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
620 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
625 rc
= lock_file_mutex(client
);
629 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
632 client
->freed
= FALSE
;
633 CACHE_LOCK(client
->ctx
);
634 cache_incr_refcount(client
->md5file
);
636 client
->crypto
= init_client_crypto();
638 if (!client
->crypto
) {
640 cleanup_client(client
);
641 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
644 client
->crypto
->key
= gcry_malloc(hashlen
);
646 if (!client
->crypto
->key
) {
648 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
650 cleanup_client(client
);
651 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_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__
, pwmd_strerror(GPG_ERR_ENOMEM
));
671 cleanup_client(client
);
672 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_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__
, pwmd_strerror(GPG_ERR_ENOMEM
));
683 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_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__
, pwmd_strerror(GPG_ERR_ENOMEM
));
702 cleanup_client(client
);
703 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_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__
, pwmd_strerror(GPG_ERR_ENOMEM
));
721 cleanup_client(client
);
722 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_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__
, pwmd_strerror(GPG_ERR_ENOMEM
));
734 cleanup_client(client
);
735 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_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", OPTION_TYPE_NOARG
, parse_open_opt_lock
},
860 &(struct argv_s
) { "pinentry", OPTION_TYPE_OPTARG
, parse_opt_pinentry
},
861 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
862 &(struct argv_s
) { "base64", OPTION_TYPE_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 gpg_error_t
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
893 guint size
, gpointer
*out
, gulong
*outsize
)
898 gint cmd
= Z_NO_FLUSH
;
902 gz
= g_malloc0(sizeof(struct gz_s
));
905 return GPG_ERR_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__
, pwmd_strerror(GPG_ERR_ENOMEM
));
919 return GPG_ERR_ENOMEM
;
922 zrc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
925 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
927 return GPG_ERR_COMPR_ALGO
;
930 /* Rather than store the size of the uncompressed data in the file header,
931 * store it in the comment field of the gzip header. Don't give anyone too
932 * much information. Not sure why really, but it seems the right way. :)
934 memset(&h
, 0, sizeof(gz_header
));
935 g_snprintf(buf
, sizeof(buf
), "%u", size
);
936 h
.comment
= (guchar
*)buf
;
937 zrc
= deflateSetHeader(&gz
->z
, &h
);
940 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
942 return GPG_ERR_COMPR_ALGO
;
948 zrc
= deflate(&gz
->z
, cmd
);
954 if (!gz
->z
.avail_out
) {
955 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
958 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
964 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
965 gz
->z
.avail_out
= zlib_bufsize
;
968 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
969 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
970 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
972 gz
->z
.avail_in
= zlib_bufsize
;
974 rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u",
975 gz
->z
.total_in
, size
);
981 if (gz
->z
.total_in
>= size
)
988 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
989 rc
= GPG_ERR_COMPR_ALGO
;
992 } while (zrc
!= Z_STREAM_END
);
994 rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u", gz
->z
.total_in
, size
);
1000 *outsize
= gz
->z
.total_out
;
1010 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1013 * Useful for a large amount of data. Rather than doing all of the data in one
1014 * iteration do it in chunks. This lets the command be cancelable rather than
1015 * waiting for it to complete.
1017 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
1018 struct crypto_s
*crypto
, status_msg_t which
)
1021 goffset len
= CRYPTO_BLOCKSIZE(crypto
);
1022 gpointer p
= gcry_malloc(len
);
1027 return GPG_ERR_ENOMEM
;
1029 if (crypto
->insize
< CRYPTO_BLOCKSIZE(crypto
))
1030 len
= crypto
->insize
;
1032 pth_cleanup_push(gcry_free
, p
);
1035 inbuf
= (guchar
*)crypto
->inbuf
+ total
;
1038 if (len
+ total
> crypto
->insize
)
1039 len
= crypto
->blocksize
;
1041 if (which
== STATUS_ENCRYPT
)
1042 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1044 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1049 tmp
= (guchar
*)crypto
->inbuf
+ total
;
1050 memmove(tmp
, p
, len
);
1053 if (total
>= crypto
->insize
)
1064 /* The crypto struct must be setup for iterations and .key. */
1065 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
1066 struct crypto_s
*crypto
, const gchar
*filename
)
1068 goffset len
= crypto
->insize
;
1072 guint64 iter_progress
= 0ULL, n_iter
= 0ULL, xiter
= 0ULL;
1073 gchar tmp
[FILENAME_MAX
];
1076 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1078 if (!crypto
->fh
->ver
.fh2
.iter
) {
1080 * cache_file_count() needs both .used == TRUE and a valid key in
1081 * order for it to count as a used cache entry. Fixes CACHE status
1084 memset(crypto
->key
, '!', hashlen
);
1089 * Resize the existing xml buffer to the block size required by gcrypt
1090 * rather than duplicating it and wasting memory.
1092 crypto
->insize
+= sizeof(crypto_magic
);
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__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1102 return GPG_ERR_ENOMEM
;
1105 guchar
*tmpbuf
= inbuf
;
1106 memmove(&tmpbuf
[sizeof(crypto_magic
)], tmpbuf
, len
-sizeof(crypto_magic
));
1107 memcpy(tmpbuf
, crypto_magic
, sizeof(crypto_magic
));
1108 crypto
->inbuf
= tmpbuf
;
1109 crypto
->insize
= len
;
1110 gcry_create_nonce(crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
1113 gcry_free(crypto
->tkey
);
1115 crypto
->tkey
= gcry_malloc(hashlen
);
1117 if (!crypto
->tkey
) {
1118 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1119 return GPG_ERR_ENOMEM
;
1122 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
1123 guchar
*tkey
= crypto
->tkey
;
1126 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
1127 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1131 iter_progress
= (guint64
)get_key_file_double(
1132 client
? client
->filename
: "global", "iteration_progress");
1134 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1135 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1136 "0 %llu", crypto
->fh
->ver
.fh2
.iter
);
1142 while (xiter
< crypto
->fh
->ver
.fh2
.iter
-1) {
1143 if (iter_progress
> 0ULL && xiter
>= iter_progress
) {
1144 if (!(xiter
% iter_progress
)) {
1145 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1146 "%llu %llu", ++n_iter
* iter_progress
,
1147 crypto
->fh
->ver
.fh2
.iter
);
1154 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1155 crypto
->blocksize
))) {
1156 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1160 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1163 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1170 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1171 crypto
->blocksize
))) {
1172 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1176 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
1177 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1181 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1186 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1187 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1188 "%llu %llu", crypto
->fh
->ver
.fh2
.iter
, crypto
->fh
->ver
.fh2
.iter
);
1198 if (!client
&& !g_ascii_strcasecmp(filename
, "-")) {
1199 crypto
->fh
->fd
= STDOUT_FILENO
;
1203 if (lstat(filename
, &st
) == 0) {
1204 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1206 if (!(mode
& S_IWUSR
))
1207 return GPG_ERR_EACCES
;
1209 else if (errno
!= ENOENT
)
1210 return gpg_error_from_syserror();
1212 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1213 crypto
->fh
->fd
= mkstemp(tmp
);
1215 if (crypto
->fh
->fd
== -1) {
1216 rc
= gpg_error_from_syserror();
1217 p
= strrchr(tmp
, '/');
1219 log_write("%s: %s", p
, pwmd_strerror(rc
));
1223 pth_cleanup_push(cleanup_unlink_cb
, tmp
);
1227 * xml_import() or convert_file() from command line.
1229 crypto
->fh
->fd
= STDOUT_FILENO
;
1232 crypto
->fh
->ver
.fh2
.magic
[0] = '\177';
1233 crypto
->fh
->ver
.fh2
.magic
[1] = 'P';
1234 crypto
->fh
->ver
.fh2
.magic
[2] = 'W';
1235 crypto
->fh
->ver
.fh2
.magic
[3] = 'M';
1236 crypto
->fh
->ver
.fh2
.magic
[4] = 'D';
1237 crypto
->fh
->ver
.fh2
.version
= VERSION_HEX
;
1238 len
= pth_write(crypto
->fh
->fd
, &crypto
->fh
->ver
.fh2
, sizeof(crypto
->fh
->ver
.fh2
));
1240 if (len
!= sizeof(crypto
->fh
->ver
.fh2
)) {
1241 rc
= gpg_error_from_syserror();
1249 len
= pth_write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1251 if (len
!= crypto
->insize
) {
1252 rc
= gpg_error_from_syserror();
1260 if (fsync(crypto
->fh
->fd
) == -1) {
1261 rc
= gpg_error_from_syserror();
1273 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1274 gchar tmp2
[FILENAME_MAX
];
1276 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1278 acl
= acl_get_file(filename
, ACL_TYPE_ACCESS
);
1281 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1284 if (rename(filename
, tmp2
) == -1) {
1285 rc
= gpg_error_from_syserror();
1296 acl
= acl_get_file(".", ACL_TYPE_DEFAULT
);
1299 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1303 if (rename(tmp
, filename
) == -1) {
1304 rc
= gpg_error_from_syserror();
1316 chmod(filename
, mode
);
1319 if (acl
&& acl_set_file(filename
, ACL_TYPE_ACCESS
, acl
))
1320 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1327 if (client
&& lstat(filename
, &st
) == 0)
1328 client
->mtime
= st
.st_mtime
;
1333 gpg_error_t
update_save_flags(const gchar
*filename
,
1334 struct crypto_s
*crypto
)
1341 crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1344 return GPG_ERR_ENOMEM
;
1347 rc
= init_client_crypto2(filename
, crypto
);
1352 if (filename
&& !crypto
->fh
->v1
) {
1353 iter
= (guint64
)get_key_file_double(filename
, "iterations");
1354 crypto
->fh
->ver
.fh2
.iter
= iter
< 0L ? 0UL : iter
;
1360 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1363 struct client_s
*client
= assuan_get_pointer(ctx
);
1372 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1373 gcry_free(client
->crypto
->key
);
1375 client
->crypto
->key
= key
;
1376 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
));
1379 cleanup_crypto(&client
->crypto
);
1380 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1383 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1384 pth_cleanup_push(xmlFree
, xmlbuf
);
1385 clevel
= get_key_file_integer(client
->filename
, "compression_level");
1390 rc
= do_compress(ctx
, clevel
, xmlbuf
, len
, &outbuf
, &outsize
);
1394 cleanup_crypto(&client
->crypto
);
1396 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1404 client
->crypto
->inbuf
= xmlbuf
;
1405 client
->crypto
->insize
= len
;
1406 rc
= update_save_flags(client
->filename
, client
->crypto
);
1409 cleanup_crypto(&client
->crypto
);
1410 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1411 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1414 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1417 cleanup_crypto(&client
->crypto
);
1418 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1421 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1422 CACHE_LOCK(client
->ctx
);
1425 cache_reset_timeout(client
->md5file
, timeout
);
1428 if (client
->new == TRUE
)
1429 send_status_all(STATUS_CACHE
);
1431 client
->new = FALSE
;
1432 cleanup_crypto(&client
->crypto
);
1433 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1436 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1438 cleanup_crypto(&client
->crypto
);
1439 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1442 client
->new = FALSE
;
1443 cache_reset_timeout(client
->md5file
, timeout
);
1445 send_status_all(STATUS_CACHE
);
1446 cleanup_crypto(&client
->crypto
);
1447 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1450 static gpg_error_t
parse_save_opt_iterations(gpointer data
, gpointer v
)
1452 struct client_s
*client
= data
;
1457 if (!client
->filename
)
1458 return EPWMD_NO_FILE
;
1460 if (!value
|| !*value
)
1464 n
= strtoul(value
, &p
, 10);
1466 if (errno
|| (p
&& *p
) || n
== G_MAXULONG
)
1467 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_ERANGE
);
1469 MUTEX_LOCK(&rcfile_mutex
);
1470 g_key_file_set_double(keyfileh
,
1471 client
->filename
? client
->filename
: "global", "iterations", n
);
1472 MUTEX_UNLOCK(&rcfile_mutex
);
1474 if (client
->filename
)
1475 client
->opts
|= OPT_ITERATIONS
;
1480 static gpg_error_t
parse_save_opt_cipher(gpointer data
, gpointer value
)
1482 struct client_s
*client
= data
;
1483 const gchar
*p
= value
;
1486 if (!client
->filename
)
1487 return EPWMD_NO_FILE
;
1492 flags
= pwmd_cipher_str_to_cipher(p
);
1495 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
1497 MUTEX_LOCK(&rcfile_mutex
);
1498 g_key_file_set_string(keyfileh
, client
->filename
, "cipher", p
);
1499 MUTEX_UNLOCK(&rcfile_mutex
);
1507 static gpg_error_t
parse_save_opt_reset(gpointer data
, gpointer value
)
1509 struct client_s
*client
= data
;
1511 CACHE_LOCK(client
->ctx
);
1512 cache_clear(client
->md5file
, 1);
1517 static gpg_error_t
save_command_common(assuan_context_t ctx
, gchar
*line
)
1519 struct client_s
*client
= assuan_get_pointer(ctx
);
1520 gboolean cached
= FALSE
;
1521 guint hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1524 cached
= cache_iscached(client
->md5file
);
1528 * If a cache entry doesn't exist for this file and the file has a
1529 * "key_file" or "key" parameter, then it's an error. The reason is that
1530 * cache expiration would be useless. Unless this is an inquire, then its
1533 if (cached
== FALSE
) {
1534 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1536 if (tmp
&& !(client
->opts
& OPT_INQUIRE
)) {
1538 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1548 if (!client
->crypto
) {
1549 client
->crypto
= init_client_crypto();
1551 if (!client
->crypto
) {
1552 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1553 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1557 client
->crypto
->key
= gcry_malloc(hashlen
);
1559 if (!client
->crypto
->key
) {
1560 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1561 cleanup_crypto(&client
->crypto
);
1562 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1565 memset(client
->crypto
->key
, '!', hashlen
);
1567 if (get_key_file_double(client
->filename
, "iterations") <= 0L &&
1571 if (!line
|| !*line
) {
1572 /* It doesn't make sense to use an --inquire with an empty
1573 * passphrase. This will prevent a pinentry dialog. */
1574 if (client
->opts
& OPT_INQUIRE
) {
1575 cleanup_crypto(&client
->crypto
);
1576 return GPG_ERR_WRONG_KEY_USAGE
;
1579 client
->crypto
->tkey
= gcry_malloc(hashlen
);
1581 if (!client
->crypto
->tkey
) {
1582 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1583 cleanup_crypto(&client
->crypto
);
1584 return send_error(ctx
, GPG_ERR_ENOMEM
);
1587 memset(client
->crypto
->tkey
, '!', hashlen
);
1590 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1591 !memcmp(client
->crypto
->key
, client
->crypto
->tkey
, hashlen
)) {
1594 #ifdef WITH_PINENTRY
1597 if (client
->pinentry
->enable
== FALSE
||
1598 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1599 /* Empty keys are allowed. */
1600 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1604 lock_pin_mutex(client
);
1605 client
->pinentry
->which
= PINENTRY_SAVE
;
1606 rc
= pinentry_fork(ctx
);
1609 unlock_pin_mutex(client
->pinentry
);
1610 cleanup_crypto(&client
->crypto
);
1611 return send_error(ctx
, rc
);
1614 client
->pinentry
->cb
= save_command_finalize
;
1615 client
->pinentry
->status
= PINENTRY_INIT
;
1618 /* Empty keys are allowed. */
1619 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1631 if (get_key_file_double(client
->filename
, "iterations") <= 0L) {
1632 guint64 iter
= (guint64
)get_key_file_double(NULL
, "iterations");
1637 MUTEX_LOCK(&rcfile_mutex
);
1638 g_key_file_set_double(keyfileh
, client
->filename
, "iterations", iter
);
1639 MUTEX_UNLOCK(&rcfile_mutex
);
1640 client
->opts
|= OPT_ITERATIONS
;
1641 rc
= send_status(ctx
, STATUS_CONFIG
, NULL
);
1644 cleanup_crypto(&client
->crypto
);
1645 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1649 rc
= hash_key(client
, line
);
1652 cleanup_crypto(&client
->crypto
);
1653 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1658 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1661 static gint
save_command_inquire_finalize(gpointer data
, gint assuan_rc
,
1662 guchar
*line
, gsize len
)
1664 assuan_context_t ctx
= data
;
1665 struct client_s
*client
= assuan_get_pointer(ctx
);
1666 gpg_error_t rc
= file_modified(client
);
1668 if (assuan_rc
|| rc
) {
1672 return assuan_rc
? assuan_rc
: rc
;
1675 rc
= save_command_common(ctx
, (gchar
*)line
);
1680 client
->inquire_status
= INQUIRE_DONE
;
1684 static gint
save_command(assuan_context_t ctx
, gchar
*line
)
1687 struct client_s
*client
= assuan_get_pointer(ctx
);
1689 struct argv_s
*args
[] = {
1690 &(struct argv_s
) { "iterations", OPTION_TYPE_OPTARG
, parse_save_opt_iterations
},
1691 &(struct argv_s
) { "cipher", OPTION_TYPE_OPTARG
, parse_save_opt_cipher
},
1692 &(struct argv_s
) { "pinentry", OPTION_TYPE_OPTARG
, parse_opt_pinentry
},
1693 &(struct argv_s
) { "reset", OPTION_TYPE_NOARG
, parse_save_opt_reset
},
1694 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
1695 &(struct argv_s
) { "base64", OPTION_TYPE_NOARG
, parse_opt_base64
},
1699 rc
= parse_options(&line
, args
, client
);
1702 return send_error(ctx
, rc
);
1704 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1705 return send_error(ctx
, gpg_error_from_syserror());
1707 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1708 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1709 return send_error(ctx
, GPG_ERR_ENOANO
);
1712 if ((client
->opts
& OPT_INQUIRE
)) {
1713 rc
= assuan_inquire_ext(ctx
, "SAVE", 0, save_command_inquire_finalize
,
1717 return send_error(ctx
, rc
);
1719 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1720 client
->inquire_status
= INQUIRE_BUSY
;
1725 log_write2("ARGS=%s", "<passphrase>");
1727 return save_command_common(ctx
, line
);
1730 static gint
delete_command(assuan_context_t ctx
, gchar
*line
)
1732 struct client_s
*client
= assuan_get_pointer(ctx
);
1737 log_write2("ARGS=\"%s\"", line
);
1739 if (strchr(line
, '\t'))
1740 req
= split_input_line(line
, "\t", -1);
1742 req
= split_input_line(line
, " ", -1);
1745 return send_error(ctx
, GPG_ERR_SYNTAX
);
1747 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1751 return send_error(ctx
, rc
);
1755 * No sub-node defined. Remove the entire node (root element).
1759 rc
= unlink_node(n
);
1764 return send_error(ctx
, rc
);
1767 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1771 return send_error(ctx
, rc
);
1774 rc
= unlink_node(n
);
1778 return send_error(ctx
, rc
);
1782 * Don't return with assuan_process_done() here. This has been called from
1783 * assuan_process_next() and the command should be finished in
1786 static gint
store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1789 assuan_context_t ctx
= data
;
1790 struct client_s
*client
= assuan_get_pointer(ctx
);
1793 gpg_error_t rc
= file_modified(client
);
1795 if (assuan_rc
|| rc
) {
1798 return assuan_rc
? assuan_rc
: rc
;
1801 req
= split_input_line((gchar
*)line
, "\t", 0);
1805 return GPG_ERR_SYNTAX
;
1808 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1810 if (rc
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
1811 rc
= new_root_element(client
->doc
, *req
);
1828 n
= create_elements_cb(n
, req
+1, &rc
, NULL
);
1830 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1831 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
, FALSE
);
1835 client
->inquire_status
= INQUIRE_DONE
;
1838 rc
= update_element_mtime(n
);
1843 static gint
store_command(assuan_context_t ctx
, gchar
*line
)
1845 struct client_s
*client
= assuan_get_pointer(ctx
);
1848 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1851 return send_error(ctx
, rc
);
1853 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1854 client
->inquire_status
= INQUIRE_BUSY
;
1858 static void *send_data_cb(void *arg
)
1860 struct assuan_cmd_s
*data
= arg
;
1864 pth_cancel_state(PTH_CANCEL_ENABLE
|PTH_CANCEL_ASYNCHRONOUS
, &old
);
1865 rc
= g_malloc(sizeof(gpg_error_t
));
1866 *rc
= assuan_send_data(data
->ctx
, data
->line
, data
->line_len
);
1867 pth_cancel_state(old
, NULL
);
1872 /* For every assuan command that needs to be sent to the client, a timeout is
1873 * needed to determine if the client lost the connection. The timeout is the
1874 * same as the "keepalive" configuration parameter or a default if unset.
1876 gpg_error_t
do_assuan_command(assuan_context_t ctx
,
1877 void *(*cb
)(void *data
), void *data
)
1879 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
);
1890 rc
= gpg_error_from_syserror();
1891 pth_attr_destroy(attr
);
1894 log_write("%s(%i): pth_spawn(): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1898 pth_cleanup_push(cleanup_cancel_cb
, tid
);
1899 to
= to
<= 0 ? DEFAULT_KEEPALIVE_TO
: to
;
1900 ev
= pth_event(PTH_EVENT_TID
|PTH_UNTIL_TID_DEAD
, tid
);
1901 tev
= to
? pth_event(PTH_EVENT_TIME
, pth_timeout(to
, 0)) : NULL
;
1902 ev
= pth_event_concat(ev
, tev
, NULL
);
1903 pth_cleanup_push(cleanup_ev_cb
, ev
);
1908 st
= pth_event_status(tev
);
1910 if (st
== PTH_STATUS_OCCURRED
) {
1913 return GPG_ERR_TIMEOUT
;
1917 st
= pth_event_status(ev
);
1919 if (st
== PTH_STATUS_FAILED
) {
1923 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1925 else if (st
== PTH_STATUS_OCCURRED
) {
1927 rc
= *(gpg_error_t
*)p
;
1936 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
1942 struct assuan_cmd_s data
;
1943 gint progress
= get_key_file_integer("global", "xfer_progress");
1946 progress
= progress
>0 ? (progress
/ASSUAN_LINELENGTH
)*ASSUAN_LINELENGTH
: 0;
1947 to_send
= total
< ASSUAN_LINELENGTH
? total
: ASSUAN_LINELENGTH
;
1949 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1956 if (sent
+ to_send
> total
)
1957 to_send
= total
- sent
;
1959 data
.line
= flush
? NULL
: (gchar
*)line
+sent
;
1960 data
.line_len
= flush
? 0 : to_send
;
1961 rc
= do_assuan_command(ctx
, send_data_cb
, &data
);
1964 sent
+= flush
? 0 : to_send
;
1966 if ((progress
&& !(sent
% progress
) && sent
!= total
) ||
1967 (sent
== total
&& flush
))
1968 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1970 if (!flush
&& !rc
&& sent
== total
) {
1975 } while (!rc
&& sent
< total
);
1980 static gint
get_command(assuan_context_t ctx
, gchar
*line
)
1982 struct client_s
*client
= assuan_get_pointer(ctx
);
1987 log_write2("ARGS=\"%s\"", line
);
1988 req
= split_input_line(line
, "\t", -1);
1990 if (!req
|| !*req
) {
1992 return send_error(ctx
, GPG_ERR_SYNTAX
);
1995 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1999 return send_error(ctx
, rc
);
2003 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2008 return send_error(ctx
, rc
);
2010 if (!n
|| !n
->children
)
2011 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2013 n
= find_text_node(n
->children
);
2015 if (!n
|| !n
->content
|| !*n
->content
)
2016 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2018 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
2019 return send_error(ctx
, rc
);
2022 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
2023 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
2025 gchar
*path
= *(gchar
**)data
;
2026 gchar
*tmp
= NULL
, *result
;
2030 *(gchar
**)data
= NULL
;
2033 path
= g_strjoinv("\t", target
);
2036 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2037 *rc
= GPG_ERR_ENOMEM
;
2042 tmp
= g_strjoinv("\t", req_orig
);
2046 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2047 *rc
= GPG_ERR_ENOMEM
;
2053 result
= g_strdup_printf("%s\t%s", path
, tmp
);
2055 result
= g_strdup(path
);
2058 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2059 *rc
= GPG_ERR_ENOMEM
;
2067 *(gchar
**)data
= result
;
2071 static void list_command_cleanup1(void *arg
);
2072 static gint
realpath_command(assuan_context_t ctx
, gchar
*line
)
2075 struct client_s
*client
= assuan_get_pointer(ctx
);
2083 log_write2("ARGS=\"%s\"", line
);
2085 if (strchr(line
, '\t') != NULL
) {
2086 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
2087 return send_error(ctx
, GPG_ERR_SYNTAX
);
2090 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
2091 return send_error(ctx
, GPG_ERR_SYNTAX
);
2094 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
2098 return send_error(ctx
, rc
);
2101 rp
= g_strjoinv("\t", req
);
2105 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2106 return send_error(ctx
, GPG_ERR_ENOMEM
);
2110 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
2111 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
, FALSE
);
2116 return send_error(ctx
, rc
);
2120 string
= g_string_new(rp
);
2125 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2126 return send_error(ctx
, GPG_ERR_ENOMEM
);
2130 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
2131 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
2132 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
2137 pth_cleanup_push(list_command_cleanup1
, string
);
2138 rc
= xfer_data(ctx
, string
->str
, string
->len
);
2140 return send_error(ctx
, rc
);
2143 static void list_command_cleanup1(void *arg
)
2145 g_string_free((GString
*)arg
, TRUE
);
2148 static void list_command_cleanup2(void *arg
)
2150 struct element_list_s
*elements
= arg
;
2153 if (elements
->list
) {
2154 gint total
= g_slist_length(elements
->list
);
2157 for (i
= 0; i
< total
; i
++) {
2158 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
2162 g_slist_free(elements
->list
);
2165 if (elements
->prefix
)
2166 g_free(elements
->prefix
);
2169 g_strfreev(elements
->req
);
2175 static gpg_error_t
parse_list_opt_norecurse(gpointer data
, gpointer value
)
2177 struct element_list_s
*elements
= data
;
2179 elements
->recurse
= FALSE
;
2183 static gpg_error_t
parse_list_opt_verbose(gpointer data
, gpointer value
)
2185 struct element_list_s
*elements
= data
;
2187 elements
->verbose
= TRUE
;
2191 static gint
list_command(assuan_context_t ctx
, gchar
*line
)
2193 struct client_s
*client
= assuan_get_pointer(ctx
);
2195 struct element_list_s
*elements
= NULL
;
2197 struct argv_s
*args
[] = {
2198 &(struct argv_s
) { "no-recurse", OPTION_TYPE_NOARG
, parse_list_opt_norecurse
},
2199 &(struct argv_s
) { "verbose", OPTION_TYPE_NOARG
, parse_list_opt_verbose
},
2203 if (disable_list_and_dump
== TRUE
)
2204 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2206 elements
= g_malloc0(sizeof(struct element_list_s
));
2209 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2210 return GPG_ERR_ENOMEM
;
2213 elements
->recurse
= TRUE
; // default
2214 pth_cleanup_push(list_command_cleanup2
, elements
);
2215 rc
= parse_options(&line
, args
, elements
);
2223 rc
= list_root_elements(client
->doc
, &str
, elements
->verbose
);
2227 return send_error(ctx
, rc
);
2230 pth_cleanup_push(list_command_cleanup1
, str
);
2231 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2234 return send_error(ctx
, rc
);
2237 elements
->req
= split_input_line(line
, " ", 0);
2240 strv_printf(&elements
->req
, "%s", line
);
2242 rc
= create_path_list(client
->doc
, elements
, *elements
->req
);
2248 gint total
= g_slist_length(elements
->list
);
2253 rc
= GPG_ERR_NO_VALUE
;
2257 str
= g_string_new(NULL
);
2260 rc
= GPG_ERR_ENOMEM
;
2261 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2265 for (i
= 0; i
< total
; i
++) {
2266 tmp
= g_slist_nth_data(elements
->list
, i
);
2267 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
2270 pth_cleanup_push(list_command_cleanup1
, str
);
2271 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2275 rc
= GPG_ERR_NO_VALUE
;
2279 return send_error(ctx
, rc
);
2283 * req[0] - element path
2285 static gpg_error_t
attribute_list(assuan_context_t ctx
, gchar
**req
)
2287 struct client_s
*client
= assuan_get_pointer(ctx
);
2288 gchar
**attrlist
= NULL
;
2290 gchar
**path
= NULL
;
2296 if (!req
|| !req
[0])
2297 return GPG_ERR_SYNTAX
;
2299 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2301 * The first argument may be only a root element.
2303 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2304 return GPG_ERR_SYNTAX
;
2307 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2315 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2316 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2326 for (a
= n
->properties
; a
; a
= a
->next
) {
2329 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
2331 g_strfreev(attrlist
);
2333 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2334 return GPG_ERR_ENOMEM
;
2339 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
,
2340 an
&& an
->content
? (gchar
*)an
->content
: "");
2343 g_strfreev(attrlist
);
2344 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2345 return GPG_ERR_ENOMEM
;
2348 attrlist
[++i
] = NULL
;
2352 return GPG_ERR_NO_VALUE
;
2354 line
= g_strjoinv("\n", attrlist
);
2357 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2358 g_strfreev(attrlist
);
2359 return GPG_ERR_ENOMEM
;
2362 pth_cleanup_push(g_free
, line
);
2363 pth_cleanup_push(req_cleanup
, attrlist
);
2364 rc
= xfer_data(ctx
, line
, strlen(line
));
2371 * req[0] - attribute
2372 * req[1] - element path
2374 static gpg_error_t
attribute_delete(struct client_s
*client
, gchar
**req
)
2377 gchar
**path
= NULL
;
2380 if (!req
|| !req
[0] || !req
[1])
2381 return GPG_ERR_SYNTAX
;
2383 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2385 * The first argument may be only a root element.
2387 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2388 return GPG_ERR_SYNTAX
;
2392 * Don't remove the "_name" attribute for the root element. To remove an
2393 * root element use DELETE <name>.
2395 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"_name")) {
2396 rc
= GPG_ERR_SYNTAX
;
2400 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2406 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2407 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2413 rc
= delete_attribute(n
, (xmlChar
*)req
[0]);
2420 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
2423 gchar
**src
= *path
;
2424 gchar
**src_orig
= g_strdupv(src
);
2425 xmlNodePtr n
= NULL
;
2430 *rc
= GPG_ERR_ENOMEM
;
2431 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2436 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2439 if (*rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
2440 *rc
= new_root_element(client
->doc
, src
[0]);
2453 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
2455 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2456 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
, FALSE
);
2462 * Reset the position of the element tree now that the elements
2463 * have been created.
2468 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2473 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2474 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2482 g_strfreev(src_orig
);
2489 * Creates a "target" attribute. When other commands encounter an element with
2490 * this attribute, the element path is modified to the target value. If the
2491 * source element path doesn't exist when using 'ATTR SET target', it is
2492 * created, but the destination element path must exist.
2494 * req[0] - source element path
2495 * req[1] - destination element path
2497 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2499 gchar
**src
, **dst
, *line
= NULL
, **odst
= NULL
;
2503 if (!req
|| !req
[0] || !req
[1])
2504 return GPG_ERR_SYNTAX
;
2506 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2508 * The first argument may be only a root element.
2510 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2511 return GPG_ERR_SYNTAX
;
2514 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2516 * The first argument may be only a root element.
2518 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2519 rc
= GPG_ERR_SYNTAX
;
2524 odst
= g_strdupv(dst
);
2527 rc
= GPG_ERR_ENOMEM
;
2531 n
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
2534 * Make sure the destination element path exists.
2540 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2541 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2547 n
= create_element_path(client
, &src
, &rc
);
2552 line
= g_strjoinv("\t", odst
);
2555 rc
= GPG_ERR_ENOMEM
;
2556 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2560 rc
= add_attribute(n
, "target", line
);
2574 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2580 tmp
= g_strdupv(req
);
2583 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2584 return GPG_ERR_ENOMEM
;
2587 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2593 if (g_utf8_collate(req
[0], req
[1]) == 0)
2597 * Will not overwrite an existing root.
2599 tmp
= g_strdupv(req
+1);
2602 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2603 return GPG_ERR_ENOMEM
;
2606 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2609 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
2613 return GPG_ERR_AMBIGUOUS_NAME
;
2615 if (!valid_xml_element((xmlChar
*)req
[1]))
2616 return GPG_ERR_SYNTAX
;
2618 tmp
= g_strdupv(req
);
2621 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2622 return GPG_ERR_ENOMEM
;
2625 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2629 return GPG_ERR_ELEMENT_NOT_FOUND
;
2631 return add_attribute(n
, "_name", req
[1]);
2635 * req[0] - attribute
2636 * req[1] - element path
2638 static gpg_error_t
attribute_get(assuan_context_t ctx
, gchar
**req
)
2640 struct client_s
*client
= assuan_get_pointer(ctx
);
2646 if (!req
|| !req
[0] || !req
[1])
2647 return GPG_ERR_SYNTAX
;
2649 if (strchr(req
[1], '\t')) {
2650 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2651 return GPG_ERR_SYNTAX
;
2654 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2655 return GPG_ERR_SYNTAX
;
2658 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2664 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2665 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2673 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2674 return GPG_ERR_NOT_FOUND
;
2676 pth_cleanup_push(xmlFree
, a
);
2679 rc
= xfer_data(ctx
, (gchar
*)a
, xmlStrlen(a
));
2681 rc
= GPG_ERR_NO_VALUE
;
2692 * req[0] - attribute
2693 * req[1] - element path
2696 static gpg_error_t
attribute_set(struct client_s
*client
, gchar
**req
)
2698 gchar
**path
= NULL
;
2702 if (!req
|| !req
[0] || !req
[1])
2703 return GPG_ERR_SYNTAX
;
2706 * Reserved attribute names.
2708 if (!strcmp(req
[0], "_name")) {
2710 * Only reserved for the root element. Not the rest of the
2713 if (strchr(req
[1], '\t') == NULL
)
2714 return name_attribute(client
, req
+ 1);
2716 else if (!strcmp(req
[0], "target"))
2717 return target_attribute(client
, req
+ 1);
2719 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2721 * The first argument may be only a root element.
2723 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2724 return GPG_ERR_SYNTAX
;
2727 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2733 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2734 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2740 rc
= add_attribute(n
, req
[0], req
[2]);
2749 * req[1] - attribute name or element path if command is LIST
2750 * req[2] - element path
2751 * req[2] - element path or value
2753 static gint
attr_command(assuan_context_t ctx
, gchar
*line
)
2755 struct client_s
*client
= assuan_get_pointer(ctx
);
2759 log_write2("ARGS=\"%s\"", line
);
2760 req
= split_input_line(line
, " ", 4);
2762 if (!req
|| !req
[0] || !req
[1]) {
2764 return send_error(ctx
, GPG_ERR_SYNTAX
);
2767 pth_cleanup_push(req_cleanup
, req
);
2769 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2770 rc
= attribute_set(client
, req
+1);
2771 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2772 rc
= attribute_get(ctx
, req
+1);
2773 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2774 rc
= attribute_delete(client
, req
+1);
2775 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2776 rc
= attribute_list(ctx
, req
+1);
2778 rc
= GPG_ERR_SYNTAX
;
2781 return send_error(ctx
, rc
);
2784 static gint
iscached_command(assuan_context_t ctx
, gchar
*line
)
2786 gchar
**req
= split_input_line(line
, " ", 0);
2790 if (!req
|| !*req
) {
2792 return send_error(ctx
, GPG_ERR_SYNTAX
);
2795 log_write2("ARGS=\"%s\"", line
);
2797 if (!valid_filename(req
[0])) {
2799 return GPG_ERR_INV_VALUE
;
2802 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2805 if (cache_iscached(md5file
)) {
2808 return send_error(ctx
, 0);
2812 tmp
= get_key_file_string("global", "data_directory");
2816 return GPG_ERR_ENOMEM
;
2819 path
= expand_homedir(tmp
);
2824 return GPG_ERR_ENOMEM
;
2829 path
= g_strdup_printf("%s/%s", tmp
, req
[0]);
2834 return GPG_ERR_ENOMEM
;
2837 if (access(path
, R_OK
) == -1) {
2838 gpg_error_t rc
= gpg_error_from_syserror();
2842 return send_error(ctx
, rc
);
2846 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2849 static gint
clearcache_command(assuan_context_t ctx
, gchar
*line
)
2851 gchar
**req
= split_input_line(line
, " ", 0);
2854 log_write2("ARGS=\"%s\"", line
);
2857 if (!req
|| !*req
) {
2859 cache_clear(NULL
, 2);
2861 return send_error(ctx
, 0);
2864 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2867 if (cache_clear(md5file
, 1) == FALSE
) {
2869 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2873 return send_error(ctx
, 0);
2876 static gint
cachetimeout_command(assuan_context_t ctx
, gchar
*line
)
2880 gchar
**req
= split_input_line(line
, " ", 0);
2883 if (!req
|| !*req
|| !req
[1]) {
2885 return send_error(ctx
, GPG_ERR_SYNTAX
);
2889 timeout
= strtol(req
[1], &p
, 10);
2891 if (errno
!= 0 || *p
!= 0 || timeout
< -1) {
2893 return send_error(ctx
, GPG_ERR_SYNTAX
);
2896 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2897 CACHE_LOCK(client
->ctx
);
2899 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2901 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2905 return send_error(ctx
, 0);
2908 static gint
dump_command(assuan_context_t ctx
, gchar
*line
)
2912 struct client_s
*client
= assuan_get_pointer(ctx
);
2915 if (disable_list_and_dump
== TRUE
)
2916 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2918 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2921 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2922 return send_error(ctx
, GPG_ERR_ENOMEM
);
2925 pth_cleanup_push(xmlFree
, xml
);
2926 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
2928 return send_error(ctx
, rc
);
2931 static gint
getconfig_command(assuan_context_t ctx
, gchar
*line
)
2933 struct client_s
*client
= assuan_get_pointer(ctx
);
2935 gchar filename
[255]={0}, param
[747]={0};
2936 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2938 log_write2("ARGS=\"%s\"", line
);
2940 if (strchr(line
, ' ')) {
2941 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2946 if (fp
&& !valid_filename(fp
))
2947 return send_error(ctx
, GPG_ERR_INV_VALUE
);
2949 paramp
= g_ascii_strdown(paramp
, -1);
2952 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2953 return send_error(ctx
, GPG_ERR_ENOMEM
);
2956 if (fp
&& !g_ascii_strcasecmp(paramp
, "iterations")) {
2957 if (!(client
->opts
& OPT_ITERATIONS
) || fp
!= client
->filename
) {
2958 file_header_internal_t
*fh
= read_file_header(fp
, FALSE
, &rc
);
2960 if (!fh
&& rc
!= GPG_ERR_ENOENT
)
2961 return send_error(ctx
, rc
);
2965 p
= g_strdup_printf("%lu", (unsigned long)fh
->ver
.fh2
.iter
);
2966 close_file_header(fh
);
2969 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2970 pwmd_strerror(GPG_ERR_ENOMEM
));
2971 return send_error(ctx
, GPG_ERR_ENOMEM
);
2978 else if (!g_ascii_strcasecmp(paramp
, "enable_pinentry")) {
2979 #ifdef WITH_PINENTRY
2982 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY
))
2983 n
= client
->pinentry
->enable
;
2985 n
= get_key_file_boolean(fp
, "enable_pinentry");
2987 p
= g_strdup_printf("%s", n
? "true" : "false");
2990 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2991 pwmd_strerror(GPG_ERR_ENOMEM
));
2992 return send_error(ctx
, GPG_ERR_ENOMEM
);
2997 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3000 else if (!g_ascii_strcasecmp(paramp
, "pinentry_timeout")) {
3001 #ifdef WITH_PINENTRY
3002 p
= g_strdup_printf("%i", get_key_file_integer(fp
, "pinentry_timeout"));
3005 log_write("%s(%i): %s", __FILE__
, __LINE__
,
3006 pwmd_strerror(GPG_ERR_ENOMEM
));
3007 return send_error(ctx
, GPG_ERR_ENOMEM
);
3012 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3016 p
= get_key_file_string(fp
? fp
: "global", paramp
);
3020 return send_error(ctx
, GPG_ERR_NO_VALUE
);
3022 tmp
= expand_homedir(p
);
3026 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3027 return send_error(ctx
, GPG_ERR_ENOMEM
);
3032 pth_cleanup_push(g_free
, p
);
3033 rc
= xfer_data(ctx
, p
, strlen(p
));
3035 return send_error(ctx
, rc
);
3039 xmlXPathContextPtr xp
;
3040 xmlXPathObjectPtr result
;
3045 static void xpath_command_cleanup(void *arg
)
3047 struct xpath_s
*xpath
= arg
;
3049 req_cleanup(xpath
->req
);
3052 xmlBufferFree(xpath
->buf
);
3055 xmlXPathFreeObject(xpath
->result
);
3058 xmlXPathFreeContext(xpath
->xp
);
3061 static gint
xpath_command(assuan_context_t ctx
, gchar
*line
)
3063 struct client_s
*client
= assuan_get_pointer(ctx
);
3065 struct xpath_s xpath
;
3067 log_write2("ARGS=\"%s\"", line
);
3069 if (disable_list_and_dump
== TRUE
)
3070 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3072 if (!line
|| !*line
)
3073 return send_error(ctx
, GPG_ERR_SYNTAX
);
3075 memset(&xpath
, 0, sizeof(struct xpath_s
));
3077 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
3078 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
3079 return send_error(ctx
, GPG_ERR_ENOMEM
);
3082 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3085 xpath_command_cleanup(&xpath
);
3086 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3089 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3091 if (!xpath
.result
) {
3092 xpath_command_cleanup(&xpath
);
3093 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3096 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3097 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3101 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3102 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, 0, NULL
);
3106 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
3107 rc
= GPG_ERR_NO_VALUE
;
3110 else if (xpath
.req
[1])
3113 pth_cleanup_push(xpath_command_cleanup
, &xpath
);
3114 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
.buf
),
3115 xmlBufferLength(xpath
.buf
));
3119 xpath_command_cleanup(&xpath
);
3120 return send_error(ctx
, rc
);
3123 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3124 static gint
xpathattr_command(assuan_context_t ctx
, gchar
*line
)
3126 struct client_s
*client
= assuan_get_pointer(ctx
);
3128 struct xpath_s xpath
;
3130 gboolean cmd
= FALSE
; //SET
3132 log_write2("ARGS=\"%s\"", line
);
3134 if (disable_list_and_dump
== TRUE
)
3135 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3137 if (!line
|| !*line
)
3138 return send_error(ctx
, GPG_ERR_SYNTAX
);
3140 memset(&xpath
, 0, sizeof(struct xpath_s
));
3142 if ((req
= split_input_line(line
, " ", 3)) == NULL
)
3143 return send_error(ctx
, GPG_ERR_ENOMEM
);
3146 rc
= GPG_ERR_SYNTAX
;
3150 if (!g_ascii_strcasecmp(req
[0], "SET"))
3152 else if (!g_ascii_strcasecmp(req
[0], "DELETE"))
3155 rc
= GPG_ERR_SYNTAX
;
3159 if (!req
[1] || !req
[2]) {
3160 rc
= GPG_ERR_SYNTAX
;
3164 if ((xpath
.req
= split_input_line(req
[2], "\t", 3)) == NULL
) {
3165 rc
= GPG_ERR_ENOMEM
;
3169 if (!xpath
.req
[0] || (!xpath
.req
[1] && !cmd
) || (xpath
.req
[1] && cmd
)) {
3170 rc
= GPG_ERR_SYNTAX
;
3174 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3177 rc
= EPWMD_LIBXML_ERROR
;
3181 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3183 if (!xpath
.result
) {
3184 rc
= EPWMD_LIBXML_ERROR
;
3188 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3189 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3193 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3194 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, cmd
, (xmlChar
*)req
[1]);
3198 xpath_command_cleanup(&xpath
);
3199 return send_error(ctx
, rc
);
3202 static gint
import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
3205 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
3206 gpg_error_t rc
= file_modified(client
);
3207 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
3208 xmlDocPtr doc
= NULL
;
3209 xmlNodePtr n
, root
, copy
;
3211 if (assuan_rc
|| rc
) {
3214 return assuan_rc
? assuan_rc
: rc
;
3217 req
= split_input_line((gchar
*)line
, "\t", 2);
3221 return GPG_ERR_SYNTAX
;
3224 path
= split_input_line(req
[1], "\t", 0);
3226 if (!content
|| !*content
) {
3227 rc
= GPG_ERR_SYNTAX
;
3231 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
3234 rc
= EPWMD_LIBXML_ERROR
;
3238 root
= xmlDocGetRootElement(doc
);
3239 rc
= validate_import(root
);
3245 path_orig
= g_strdupv(path
);
3248 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3249 rc
= GPG_ERR_ENOMEM
;
3253 xmlChar
*a
= xmlGetProp(root
, (xmlChar
*)"_name");
3256 g_strfreev(path_orig
);
3257 rc
= GPG_ERR_ENOMEM
;
3261 if (strv_printf(&path
, "%s", (gchar
*)a
) == FALSE
) {
3263 g_strfreev(path_orig
);
3264 rc
= GPG_ERR_ENOMEM
;
3269 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
3271 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3272 g_strfreev(path_orig
);
3277 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, TRUE
);
3279 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3280 g_strfreev(path_orig
);
3284 xmlNodePtr parent
= n
->parent
;
3295 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
3296 n
= create_element_path(client
, &path
, &rc
);
3302 copy
= xmlCopyNodeList(root
);
3303 n
= xmlAddChildList(n
, copy
);
3306 rc
= EPWMD_LIBXML_ERROR
;
3309 /* Check if the content root element can create a DTD root element. */
3310 if (!xmlStrEqual((xmlChar
*)"element", root
->name
)) {
3311 rc
= GPG_ERR_SYNTAX
;
3317 if ((a
= xmlGetProp(root
, (xmlChar
*)"_name")) == NULL
) {
3318 rc
= GPG_ERR_SYNTAX
;
3322 gchar
*tmp
= g_strdup((gchar
*)a
);
3324 gboolean literal
= is_literal_element(&tmp
);
3326 if (!valid_xml_element((xmlChar
*)tmp
) || literal
) {
3328 rc
= GPG_ERR_INV_VALUE
;
3332 if (strv_printf(&path
, "%s", tmp
) == FALSE
) {
3334 rc
= GPG_ERR_ENOMEM
;
3339 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, TRUE
);
3341 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3342 rc
= EPWMD_LIBXML_ERROR
;
3346 /* Overwriting the existing tree. */
3353 xmlSetProp(root
, (xmlChar
*)"_name", (xmlChar
*)path
[0]);
3354 n
= xmlCopyNode(root
, 1);
3355 n
= xmlAddChildList(xmlDocGetRootElement(client
->doc
), n
);
3359 rc
= update_element_mtime(n
->parent
);
3369 client
->inquire_status
= INQUIRE_DONE
;
3373 static gint
import_command(assuan_context_t ctx
, gchar
*line
)
3376 struct client_s
*client
= assuan_get_pointer(ctx
);
3378 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
3381 return send_error(ctx
, rc
);
3383 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3384 client
->inquire_status
= INQUIRE_BUSY
;
3388 static gpg_error_t
do_lock_command(struct client_s
*client
)
3390 gpg_error_t rc
= lock_file_mutex(client
);
3393 client
->is_lock_cmd
= TRUE
;
3395 return client
->opts
& OPT_INQUIRE
? rc
: send_error(client
->ctx
, rc
);
3398 static gint
lock_command(assuan_context_t ctx
, gchar
*line
)
3400 struct client_s
*client
= assuan_get_pointer(ctx
);
3402 return do_lock_command(client
);
3405 static gint
unlock_command(assuan_context_t ctx
, gchar
*line
)
3407 struct client_s
*client
= assuan_get_pointer(ctx
);
3409 unlock_file_mutex(client
);
3410 return send_error(ctx
, 0);
3413 static gint
getpid_command(assuan_context_t ctx
, gchar
*line
)
3417 pid_t pid
= getpid();
3419 print_fmt(buf
, sizeof(buf
), "%i", pid
);
3420 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3421 return send_error(ctx
, rc
);
3424 static gint
version_command(assuan_context_t ctx
, gchar
*line
)
3429 print_fmt(buf
, sizeof(buf
), "0x%X", VERSION_HEX
);
3430 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3431 return send_error(ctx
, rc
);
3434 #ifdef WITH_PINENTRY
3435 static void set_option_value(gchar
**opt
, const gchar
*value
)
3443 *opt
= g_strdup(value
);
3447 static gint
set_unset_common(assuan_context_t ctx
, const gchar
*name
,
3450 struct client_s
*client
= assuan_get_pointer(ctx
);
3453 if (g_ascii_strcasecmp(name
, (gchar
*)"log_level") == 0) {
3457 l
= strtol(value
, NULL
, 10);
3460 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3463 MUTEX_LOCK(&rcfile_mutex
);
3464 g_key_file_set_integer(keyfileh
, "global", "log_level", (gint
)l
);
3465 MUTEX_UNLOCK(&rcfile_mutex
);
3468 else if (g_ascii_strcasecmp(name
, (gchar
*)"rc_on_locked") == 0) {
3472 l
= strtol(value
, NULL
, 10);
3475 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3478 client
->rc_on_locked
= l
? TRUE
: FALSE
;
3481 else if (g_ascii_strcasecmp(name
, (gchar
*)"lock_on_open") == 0) {
3482 rc
= parse_open_opt_lock(client
, (gpointer
)value
);
3487 client
->opts
|= OPT_LOCK
;
3489 else if (g_ascii_strcasecmp(name
, (gchar
*)"cipher") == 0) {
3491 client
->opts
&= ~(OPT_CIPHER
);
3495 rc
= parse_save_opt_cipher(client
, (gpointer
)value
);
3500 client
->opts
|= OPT_CIPHER
;
3503 else if (g_ascii_strcasecmp(name
, (gchar
*)"iterations") == 0) {
3504 rc
= parse_save_opt_iterations(client
, (gpointer
)value
);
3511 else if (g_ascii_strcasecmp(name
, (gchar
*)"NAME") == 0) {
3512 pth_attr_t attr
= pth_attr_of(pth_self());
3516 pth_attr_destroy(attr
);
3520 print_fmt(buf
, sizeof(buf
), "%s", value
);
3521 pth_attr_set(attr
, PTH_ATTR_NAME
, buf
);
3522 pth_attr_destroy(attr
);
3523 #ifdef WITH_PINENTRY
3524 if (client
->pinentry
->name
)
3525 g_free(client
->pinentry
->name
);
3527 client
->pinentry
->name
= g_strdup(buf
);
3529 if (!client
->pinentry
->name
)
3530 return GPG_ERR_ENOMEM
;
3535 #ifdef WITH_PINENTRY
3536 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3537 set_option_value(&client
->pinentry
->lcmessages
, value
);
3538 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3539 set_option_value(&client
->pinentry
->lcctype
, value
);
3540 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3541 set_option_value(&client
->pinentry
->ttyname
, value
);
3542 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3543 set_option_value(&client
->pinentry
->ttytype
, value
);
3544 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3545 set_option_value(&client
->pinentry
->display
, value
);
3546 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3547 set_option_value(&client
->pinentry
->path
, value
);
3548 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3549 set_option_value(&client
->pinentry
->title
, value
);
3550 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3551 set_option_value(&client
->pinentry
->prompt
, value
);
3552 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3553 set_option_value(&client
->pinentry
->desc
, value
);
3554 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0) {
3561 n
= strtol(value
, &p
, 10);
3564 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3566 MUTEX_LOCK(&rcfile_mutex
);
3567 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
:
3568 "global", "pinentry_timeout", n
);
3569 MUTEX_UNLOCK(&rcfile_mutex
);
3572 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0) {
3573 rc
= parse_opt_pinentry(client
, (gpointer
)value
);
3581 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3582 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3583 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3584 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3585 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3586 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3587 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3588 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3589 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3590 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3591 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3592 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3593 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3594 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3595 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3596 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3597 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3598 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3599 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0)
3600 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3601 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0)
3602 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3605 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
3611 static gint
unset_command(assuan_context_t ctx
, gchar
*line
)
3613 log_write2("ARGS=\"%s\"", line
);
3614 return send_error(ctx
, set_unset_common(ctx
, line
, NULL
));
3617 static gint
set_command(assuan_context_t ctx
, gchar
*line
)
3619 gchar name
[64] = {0}, value
[256] = {0};
3621 log_write2("ARGS=\"%s\"", line
);
3623 if (sscanf(line
, " %63[_a-zA-Z] = %255c", name
, value
) != 2)
3624 return send_error(ctx
, gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
));
3626 return send_error(ctx
, set_unset_common(ctx
, name
, value
));
3629 static gint
rename_command(assuan_context_t ctx
, gchar
*line
)
3631 struct client_s
*client
= assuan_get_pointer(ctx
);
3633 gchar
**req
, **src
, *dst
;
3636 log_write2("ARGS=\"%s\"", line
);
3637 req
= split_input_line(line
, " ", -1);
3639 if (!req
|| !req
[0] || !req
[1]) {
3641 return send_error(ctx
, GPG_ERR_SYNTAX
);
3645 is_literal_element(&dst
);
3647 if (!valid_xml_element((xmlChar
*)dst
)) {
3649 return GPG_ERR_INV_VALUE
;
3652 if (strchr(req
[0], '\t'))
3653 src
= split_input_line(req
[0], "\t", -1);
3655 src
= split_input_line(req
[0], " ", -1);
3657 if (!src
|| !*src
) {
3658 rc
= GPG_ERR_SYNTAX
;
3662 n
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3665 n
= find_elements(client
->doc
, n
->children
, src
+1, &rc
, NULL
, NULL
,
3666 NULL
, FALSE
, 0, NULL
, FALSE
);
3672 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
3675 rc
= GPG_ERR_ENOMEM
;
3679 /* To prevent unwanted effects:
3681 * <root name="a"><b/></root>
3685 if (xmlStrEqual(a
, (xmlChar
*)dst
)) {
3687 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3697 for (p
= src
; *p
; p
++) {
3701 strv_printf(&tmp
, "%s", *p
);
3705 strv_printf(&tmp
, "!%s", dst
);
3706 ndst
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
3708 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3714 ndst
= find_elements(client
->doc
, ndst
->children
, tmp
+1, &rc
, NULL
,
3715 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3719 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3724 /* Target may exist:
3727 * <root name="b" target="a"/>
3735 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3741 xmlFreeNodeList(ndst
);
3744 rc
= add_attribute(n
, "_name", dst
);
3749 return send_error(ctx
, rc
);
3752 static gint
copy_command(assuan_context_t ctx
, gchar
*line
)
3754 struct client_s
*client
= assuan_get_pointer(ctx
);
3756 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3757 xmlNodePtr nsrc
, ndst
, new;
3759 log_write2("ARGS=\"%s\"", line
);
3760 req
= split_input_line(line
, " ", -1);
3762 if (!req
|| !req
[0] || !req
[1]) {
3764 return send_error(ctx
, GPG_ERR_SYNTAX
);
3767 if (strchr(req
[0], '\t'))
3768 src
= split_input_line(req
[0], "\t", -1);
3770 src
= split_input_line(req
[0], " ", -1);
3772 if (!src
|| !*src
) {
3773 rc
= GPG_ERR_SYNTAX
;
3777 if (strchr(req
[1], '\t'))
3778 dst
= split_input_line(req
[1], "\t", -1);
3780 dst
= split_input_line(req
[1], " ", -1);
3782 if (!dst
|| !*dst
) {
3783 rc
= GPG_ERR_SYNTAX
;
3787 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3790 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3791 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3796 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3799 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3800 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3802 if (!ndst
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3805 new = xmlCopyNodeList(nsrc
);
3808 rc
= GPG_ERR_ENOMEM
;
3813 ndst
= create_element_path(client
, &dst
, &rc
);
3817 xmlFreeNodeList(new);
3821 /* Merge any attributes from the src node to the initial dst node. */
3822 for (xmlAttrPtr attr
= new->properties
; attr
; attr
= attr
->next
) {
3823 if (xmlStrEqual(attr
->name
, (xmlChar
*)"_name"))
3826 xmlAttrPtr a
= xmlHasProp(ndst
, attr
->name
);
3831 xmlChar
*tmp
= xmlNodeGetContent(attr
->children
);
3832 xmlNewProp(ndst
, attr
->name
, tmp
);
3834 rc
= add_attribute(ndst
, NULL
, NULL
);
3837 xmlNodePtr n
= ndst
->children
;
3840 ndst
->children
= NULL
;
3842 if (!new->children
) {
3844 xmlFreeNodeList(new);
3848 n
= xmlCopyNodeList(new->children
);
3851 rc
= GPG_ERR_ENOMEM
;
3856 xmlFreeNodeList(new);
3857 n
= xmlAddChildList(ndst
, n
);
3860 rc
= GPG_ERR_ENOMEM
;
3864 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
) == ndst
->parent
? ndst
: ndst
->parent
);
3876 return send_error(ctx
, rc
);
3879 static gint
move_command(assuan_context_t ctx
, gchar
*line
)
3881 struct client_s
*client
= assuan_get_pointer(ctx
);
3883 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3884 xmlNodePtr nsrc
, ndst
= NULL
;
3886 log_write2("ARGS=\"%s\"", line
);
3887 req
= split_input_line(line
, " ", -1);
3889 if (!req
|| !req
[0] || !req
[1]) {
3891 return send_error(ctx
, GPG_ERR_SYNTAX
);
3894 if (strchr(req
[0], '\t'))
3895 src
= split_input_line(req
[0], "\t", -1);
3897 src
= split_input_line(req
[0], " ", -1);
3899 if (!src
|| !*src
) {
3900 rc
= GPG_ERR_SYNTAX
;
3904 if (strchr(req
[1], '\t'))
3905 dst
= split_input_line(req
[1], "\t", -1);
3907 dst
= split_input_line(req
[1], " ", -1);
3909 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3912 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3913 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3919 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3922 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3923 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3926 ndst
= xmlDocGetRootElement(client
->doc
);
3928 for (xmlNodePtr n
= ndst
; n
; n
= n
->parent
) {
3930 rc
= GPG_ERR_CONFLICT
;
3935 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3941 xmlChar
*a
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
3942 xmlNodePtr dup
= find_element(ndst
->children
, (gchar
*)a
, NULL
);
3950 if (ndst
== xmlDocGetRootElement(client
->doc
)) {
3951 xmlNodePtr n
= nsrc
;
3952 gboolean match
= FALSE
;
3954 while (n
->parent
&& n
->parent
!= ndst
)
3957 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
3958 xmlChar
*b
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
3960 if (xmlStrEqual(a
, b
)) {
3962 xmlUnlinkNode(nsrc
);
3972 xmlFreeNodeList(dup
);
3981 ndst
= create_element_path(client
, &dst
, &rc
);
3986 update_element_mtime(nsrc
->parent
);
3987 xmlUnlinkNode(nsrc
);
3988 ndst
= xmlAddChildList(ndst
, nsrc
);
3991 rc
= GPG_ERR_ENOMEM
;
3993 update_element_mtime(ndst
->parent
);
4005 return send_error(ctx
, rc
);
4008 static int ls_command(assuan_context_t ctx
, gchar
*line
)
4010 log_write2("ARGS=\"%s\"", line
);
4012 gchar
*tmp
= g_key_file_get_string(keyfileh
, "global", "data_directory", NULL
);
4013 gchar
*dir
= expand_homedir(tmp
);
4014 DIR *d
= opendir(dir
);
4016 rc
= gpg_error_from_syserror();
4021 return send_error(ctx
, rc
);
4024 size_t len
= offsetof(struct dirent
, d_name
)+pathconf(dir
, _PC_NAME_MAX
)+1;
4025 struct dirent
*p
= g_malloc(len
), *cur
= NULL
;
4031 while (!readdir_r(d
, p
, &cur
) && cur
) {
4032 if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '\0')
4034 else if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '.' && cur
->d_name
[2] == '\0')
4037 tmp
= g_strdup_printf("%s%s\n", list
? list
: "", cur
->d_name
);
4043 rc
= GPG_ERR_ENOMEM
;
4055 return send_error(ctx
, rc
);
4058 return send_error(ctx
, GPG_ERR_NO_VALUE
);
4060 list
[strlen(list
)-1] = 0;
4061 rc
= xfer_data(ctx
, list
, strlen(list
));
4063 return send_error(ctx
, rc
);
4066 static void bye_notify(assuan_context_t ctx
)
4068 struct client_s
*cl
= assuan_get_pointer(ctx
);
4070 /* This will let assuan_process_next() return. */
4071 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
4074 static void reset_notify(assuan_context_t ctx
)
4076 struct client_s
*cl
= assuan_get_pointer(ctx
);
4083 * This is called before every Assuan command.
4085 gint
command_startup(assuan_context_t ctx
, const gchar
*name
)
4087 struct client_s
*cl
= assuan_get_pointer(ctx
);
4090 log_write1("%s", name
);
4092 if (!g_ascii_strcasecmp(name
, "ISCACHED") ||
4093 !g_ascii_strcasecmp(name
, "CLEARCACHE") ||
4094 !g_ascii_strcasecmp(name
, "CACHETIMEOUT") ||
4095 !g_ascii_strcasecmp(name
, "GETCONFIG") ||
4096 !g_ascii_strcasecmp(name
, "GETPID") ||
4097 !g_ascii_strcasecmp(name
, "VERSION") ||
4098 !g_ascii_strcasecmp(name
, "SET") ||
4099 !g_ascii_strcasecmp(name
, "BYE") ||
4100 !g_ascii_strcasecmp(name
, "NOP") ||
4101 !g_ascii_strcasecmp(name
, "CANCEL") ||
4102 !g_ascii_strcasecmp(name
, "RESET") ||
4103 !g_ascii_strcasecmp(name
, "END") ||
4104 !g_ascii_strcasecmp(name
, "HELP") ||
4105 !g_ascii_strcasecmp(name
, "OPTION") ||
4106 !g_ascii_strcasecmp(name
, "INPUT") ||
4107 !g_ascii_strcasecmp(name
, "OUTPUT") ||
4108 !g_ascii_strcasecmp(name
, "LS") ||
4109 !g_ascii_strcasecmp(name
, "UNSET"))
4112 #ifdef WITH_PINENTRY
4113 if (!(cl
->opts
& OPT_PINENTRY
))
4114 reset_pin_defaults(cl
->pinentry
);
4117 cl
->last_rc
= rc
= file_modified(cl
);
4120 if ((rc
== EPWMD_NO_FILE
|| rc
== EPWMD_FILE_MODIFIED
) &&
4121 !g_ascii_strcasecmp(name
, "OPEN"))
4129 * This is called after every Assuan command.
4131 void command_finalize(assuan_context_t ctx
, gint rc
)
4133 struct client_s
*client
= assuan_get_pointer(ctx
);
4135 if (!client
->is_lock_cmd
)
4136 unlock_file_mutex(client
);
4138 log_write1(N_("command completed (rc=%u)"), client
->last_rc
);
4139 client
->opts
&= ~(OPT_INQUIRE
);
4140 client
->opts
&= ~(OPT_BASE64
);
4143 gpg_error_t
register_commands(assuan_context_t ctx
)
4147 gint (*handler
)(assuan_context_t
, gchar
*line
);
4149 { "OPEN", open_command
},
4150 { "SAVE", save_command
},
4151 { "LIST", list_command
},
4152 { "REALPATH", realpath_command
},
4153 { "STORE", store_command
},
4154 { "DELETE", delete_command
},
4155 { "GET", get_command
},
4156 { "ATTR", attr_command
},
4157 { "ISCACHED", iscached_command
},
4158 { "CLEARCACHE", clearcache_command
},
4159 { "CACHETIMEOUT", cachetimeout_command
},
4160 { "GETCONFIG", getconfig_command
},
4161 { "DUMP", dump_command
},
4162 { "XPATH", xpath_command
},
4163 { "XPATHATTR", xpathattr_command
},
4164 { "IMPORT", import_command
},
4165 { "LOCK", lock_command
},
4166 { "UNLOCK", unlock_command
},
4167 { "GETPID", getpid_command
},
4168 { "VERSION", version_command
},
4169 { "SET", set_command
},
4170 { "UNSET", unset_command
},
4171 { "RENAME", rename_command
},
4172 { "COPY", copy_command
},
4173 { "LS", ls_command
},
4174 { "MOVE", move_command
},
4181 for (i
=0; table
[i
].name
; i
++) {
4182 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
4188 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
4193 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
4198 rc
= assuan_register_pre_cmd_notify(ctx
, command_startup
);
4203 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
4206 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
,
4207 struct crypto_s
*crypto
, gpointer
*dst
, goffset
*dst_len
)
4209 goffset insize
, len
;
4210 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
4211 guint64 iter
= 0ULL, n_iter
= 0ULL, iter_progress
= 0ULL;
4214 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->ver
.fh1
) : sizeof(crypto
->fh
->ver
.fh2
);
4215 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->ver
.fh1
.iter
: crypto
->fh
->ver
.fh2
.iter
;
4216 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
4218 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
4219 insize
= crypto
->fh
->st
.st_size
- fh_size
;
4220 crypto
->iv
= gcry_malloc(crypto
->blocksize
);
4223 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4224 return GPG_ERR_ENOMEM
;
4228 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh1
.iv
, crypto
->blocksize
);
4230 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
4232 crypto
->inbuf
= gcry_malloc(insize
);
4234 if (!crypto
->inbuf
) {
4235 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4236 return GPG_ERR_ENOMEM
;
4239 crypto
->insize
= insize
;
4240 len
= pth_read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
4242 if (len
!= crypto
->insize
)
4243 return GPG_ERR_INV_LENGTH
;
4245 /* No encryption iterations. This is a plain (gzipped) file. */
4246 if ((crypto
->fh
->v1
&& (long)fh_iter
< 0L) ||
4247 (!crypto
->fh
->v1
&& fh_iter
<= 0L)) {
4249 * cache_file_count() needs both .used == TRUE and a valid key in
4250 * order for it to count as a used cache entry. Fixes CACHE status
4253 memset(crypto
->key
, '!', hashlen
);
4257 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4258 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4262 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
4263 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4267 iter_progress
= (guint64
)get_key_file_double(client
&& client
->filename
?
4268 client
->filename
: "global", "iteration_progress");
4270 if (iter_progress
> 0ULL && fh_iter
>= iter_progress
) {
4271 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
4277 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4282 crypto
->tkey
= gcry_malloc(hashlen
);
4284 if (!crypto
->tkey
) {
4285 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4286 return GPG_ERR_ENOMEM
;
4289 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
4290 guchar
*tkey
= crypto
->tkey
;
4293 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
4294 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4298 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
4299 if (iter_progress
> 0ULL && iter
>= iter_progress
) {
4300 if (!(iter
% iter_progress
)) {
4301 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
4302 ++n_iter
* iter_progress
, fh_iter
);
4309 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4310 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4314 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4317 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4324 if (iter_progress
&& fh_iter
>= iter_progress
) {
4325 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
4332 if (!crypto
->fh
->v1
&& crypto
->fh
->ver
.fh2
.version
>= 0x218) {
4335 if (crypto
->fh
->ver
.fh2
.iter
> 0ULL) {
4336 if (memcmp(crypto
->inbuf
, crypto_magic
, sizeof(crypto_magic
)))
4337 return GPG_ERR_INV_PASSPHRASE
;
4339 len
= sizeof(crypto_magic
);
4342 rc
= do_decompress(ctx
, (guchar
*)crypto
->inbuf
+len
, crypto
->insize
-len
,
4343 (gpointer
*)&crypto
->outbuf
, &outsize
);
4349 rc
= do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
4350 (gpointer
*)&crypto
->outbuf
, &outsize
);
4352 if (rc
== GPG_ERR_ENOMEM
)
4355 return GPG_ERR_INV_PASSPHRASE
; // Not a valid gzip header. Must be a bad key.
4357 if (g_strncasecmp(crypto
->outbuf
, "<?xml ", 6) != 0) {
4358 gcry_free(crypto
->outbuf
);
4359 crypto
->outbuf
= NULL
;
4360 return GPG_ERR_INV_PASSPHRASE
;
4365 client
->xml
= crypto
->outbuf
;
4366 client
->len
= outsize
;
4367 crypto
->outbuf
= NULL
;
4370 *dst
= crypto
->outbuf
;
4372 crypto
->outbuf
= NULL
;
4375 /* The calling function should free the crypto struct. */