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 struct command_table_s
{
64 gint (*handler
)(assuan_context_t
, gchar
*line
);
68 static struct command_table_s
**command_table
;
69 static guchar crypto_magic
[5] = "\177PWMD";
71 static gpg_error_t
do_lock_command(struct client_s
*client
);
73 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
75 return gcry_calloc(items
, size
);
78 static void z_free(void *data
, void *p
)
83 static gpg_error_t
file_modified(struct client_s
*client
)
88 if (client
->state
!= STATE_OPEN
)
91 rc
= lock_file_mutex(client
);
96 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
97 if (client
->mtime
!= st
.st_mtime
)
98 return EPWMD_FILE_MODIFIED
;
105 static gpg_error_t
parse_xml(assuan_context_t ctx
)
107 struct client_s
*client
= assuan_get_pointer(ctx
);
109 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
112 return EPWMD_LIBXML_ERROR
;
114 if (!client
->crypto
->fh
|| client
->crypto
->fh
->ver
.fh2
.version
>= 0x212)
117 return convert_elements(client
->doc
);
120 void unlock_file_mutex(struct client_s
*client
)
124 if (client
->has_lock
== FALSE
)
127 CACHE_LOCK(client
->ctx
);
129 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
136 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
139 gpg_error_t
lock_file_mutex(struct client_s
*client
)
144 if (client
->has_lock
== TRUE
)
147 CACHE_LOCK(client
->ctx
);
149 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
156 if (client
->rc_on_locked
) {
157 if (!pth_mutex_acquire(m
, TRUE
, NULL
))
158 return GPG_ERR_LOCKED
;
164 MUTEX_TRYLOCK(client
, m
, rc
);
167 client
->has_lock
= TRUE
;
172 void free_client(struct client_s
*client
)
175 xmlFreeDoc(client
->doc
);
178 gcry_free(client
->xml
);
180 if (client
->filename
)
181 g_free(client
->filename
);
184 cleanup_crypto(&client
->crypto
);
186 if (client
->xml_error
)
187 xmlResetError(client
->xml_error
);
190 void cleanup_client(struct client_s
*client
)
192 assuan_context_t ctx
= client
->ctx
;
193 struct client_thread_s
*thd
= client
->thd
;
194 gboolean rc_on_locked
= client
->rc_on_locked
;
195 gboolean lock_on_open
= client
->lock_on_open
;
197 struct pinentry_s
*pin
= client
->pinentry
;
200 unlock_file_mutex(client
);
201 CACHE_LOCK(client
->ctx
);
202 cache_decr_refcount(client
->md5file
);
205 * This may be a new file so don't use a cache slot. save_command() will
206 * set this to FALSE on success.
208 if (client
->new == TRUE
)
209 cache_clear(client
->md5file
, 1);
213 memset(client
, 0, sizeof(struct client_s
));
214 client
->state
= STATE_CONNECTED
;
217 client
->freed
= TRUE
;
219 client
->pinentry
= pin
;
221 client
->rc_on_locked
= rc_on_locked
;
222 client
->lock_on_open
= lock_on_open
;
225 static void gz_cleanup(void *arg
)
227 struct gz_s
**gz
= (struct gz_s
**)arg
;
232 if (!(*gz
)->done
&& (*gz
)->out
)
233 gcry_free((*gz
)->out
);
235 if ((*gz
)->which
== STATUS_COMPRESS
) {
237 deflateEnd(&(*gz
)->z
);
241 inflateEnd(&(*gz
)->z
);
248 gpg_error_t
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
249 gpointer
*out
, gulong
*outsize
)
257 gz
= g_malloc0(sizeof(struct gz_s
));
260 return GPG_ERR_ENOMEM
;
262 pth_cleanup_push(gz_cleanup
, &gz
);
263 gz
->which
= STATUS_DECOMPRESS
;
264 gz
->z
.zalloc
= z_alloc
;
265 gz
->z
.zfree
= z_free
;
267 gz
->z
.avail_in
= (uInt
)insize
;
268 gz
->z
.avail_out
= zlib_bufsize
;
269 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
272 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
274 return GPG_ERR_ENOMEM
;
277 zrc
= inflateInit2(&gz
->z
, 47);
280 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
282 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
285 memset(&h
, 0, sizeof(gz_header
));
286 h
.comment
= (guchar
*)buf
;
287 h
.comm_max
= sizeof(buf
);
288 zrc
= inflateGetHeader(&gz
->z
, &h
);
291 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
293 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
296 zrc
= inflate(&gz
->z
, Z_BLOCK
);
299 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
301 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
305 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
310 zrc
= inflate(&gz
->z
, Z_FINISH
);
316 if (!gz
->z
.avail_out
) {
317 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
320 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
326 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
327 gz
->z
.avail_out
= zlib_bufsize
;
328 rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
329 gz
->z
.total_out
, insize
);
338 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
339 rc
= GPG_ERR_COMPR_ALGO
;
343 } while (zrc
!= Z_STREAM_END
);
345 rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
352 *outsize
= gz
->z
.total_out
;
362 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
367 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
374 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
375 *rc
= GPG_ERR_ENOMEM
;
379 pth_cleanup_push(g_free
, fh
);
380 fh_size
= v1
? sizeof(fh
->ver
.fh1
) : sizeof(fh
->ver
.fh2
);
382 if (lstat(filename
, &fh
->st
) == -1) {
383 *rc
= gpg_error_from_syserror();
388 if (!S_ISREG(fh
->st
.st_mode
)) {
389 *rc
= GPG_ERR_ENOANO
;
394 fd
= open(filename
, O_RDONLY
);
397 *rc
= gpg_error_from_syserror();
402 pth_cleanup_push(cleanup_fd_cb
, &fd
);
403 p
= v1
? (void *)&fh
->ver
.fh1
: (void *)&fh
->ver
.fh2
;
404 len
= pth_read(fd
, p
, fh_size
);
406 if (len
!= fh_size
) {
407 *rc
= gpg_error_from_syserror();
420 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*unused
,
423 struct client_s
*client
= assuan_get_pointer(ctx
);
426 guchar
*key
= client
->crypto
->key
;
429 if (!client
->crypto
->fh
) {
436 rc
= init_client_crypto2(client
->filename
, client
->crypto
);
439 cleanup_client(client
);
440 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
443 rc
= try_xml_decrypt(ctx
, client
->crypto
, NULL
, NULL
);
446 cleanup_client(client
);
447 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
451 CACHE_LOCK(client
->ctx
);
453 if (cached
== FALSE
) {
454 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
455 cleanup_client(client
);
457 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
460 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
461 cache_reset_timeout(client
->md5file
, timeout
);
464 cache_set_timeout(client
->md5file
, -2);
472 gcry_free(client
->xml
);
477 if (client
->new == FALSE
)
478 send_status_all(STATUS_CACHE
);
480 client
->state
= STATE_OPEN
;
483 if (!rc
&& client
->new == FALSE
&&
484 client
->crypto
->fh
->ver
.fh2
.iter
!= (guint64
)get_key_file_double(client
->filename
, "iterations")) {
485 MUTEX_LOCK(&rcfile_mutex
);
486 g_key_file_set_double(keyfileh
, client
->filename
, "iterations",
487 client
->crypto
->fh
->ver
.fh2
.iter
);
488 MUTEX_UNLOCK(&rcfile_mutex
);
489 send_status_all(STATUS_CONFIG
);
492 cleanup_crypto(&client
->crypto
);
494 if (!rc
&& client
->lock_on_open
)
495 return do_lock_command(client
);
497 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
500 static void req_cleanup(void *arg
)
505 g_strfreev((gchar
**)arg
);
508 static gpg_error_t
parse_open_opt_lock(gpointer data
, gpointer value
)
510 struct client_s
*client
= data
;
511 const gchar
*p
= value
;
514 long l
= strtol(p
, NULL
, 10);
517 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
519 client
->lock_on_open
= l
? TRUE
: FALSE
;
521 else if ((!p
|| !*p
) && (client
->opts
& OPT_LOCK
))
522 client
->lock_on_open
= FALSE
;
524 client
->lock_on_open
= TRUE
;
529 static gpg_error_t
parse_opt_pinentry(gpointer data
, gpointer value
)
532 struct client_s
*client
= data
;
538 client
->pinentry
->enable
= -1;
539 client
->opts
&= ~(OPT_PINENTRY
);
543 n
= strtol(str
, &p
, 10);
545 if (*p
|| n
< 0 || n
> 1)
546 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
548 client
->pinentry
->enable
= n
? TRUE
: FALSE
;
549 client
->opts
|= OPT_PINENTRY
;
552 return GPG_ERR_NOT_IMPLEMENTED
;
556 static gpg_error_t
parse_opt_inquire(gpointer data
, gpointer value
)
558 struct client_s
*client
= data
;
561 client
->opts
|= OPT_INQUIRE
;
565 static gpg_error_t
parse_opt_base64(gpointer data
, gpointer value
)
567 struct client_s
*client
= data
;
570 client
->opts
|= OPT_BASE64
;
574 static gpg_error_t
hash_key(struct client_s
*client
, const gchar
*key
)
579 if (client
->opts
& OPT_BASE64
)
580 tmp
= g_base64_decode(key
, &len
);
582 tmp
= (guchar
*)g_strdup(key
);
587 return GPG_ERR_ENOMEM
;
589 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, tmp
, len
);
594 static gpg_error_t
open_command_common(assuan_context_t ctx
, gchar
*line
)
596 gboolean cached
= FALSE
;
598 struct client_s
*client
= assuan_get_pointer(ctx
);
600 gchar
*filename
= NULL
;
601 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
603 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
606 pth_cleanup_push(req_cleanup
, req
);
608 if (!filename
|| !*filename
) {
610 return client
->opts
& OPT_INQUIRE
? GPG_ERR_SYNTAX
: send_error(ctx
, GPG_ERR_SYNTAX
);
613 log_write2("ARGS=\"%s\" %s", filename
, req
[1] ? "<passphrase>" : "");
615 if (valid_filename(filename
) == FALSE
) {
617 return client
->opts
& OPT_INQUIRE
? GPG_ERR_INV_VALUE
: send_error(ctx
, GPG_ERR_INV_VALUE
);
620 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
621 CACHE_LOCK(client
->ctx
);
623 if (cache_has_file(client
->md5file
) == FALSE
) {
624 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
627 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
632 rc
= lock_file_mutex(client
);
636 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
639 client
->freed
= FALSE
;
640 CACHE_LOCK(client
->ctx
);
641 cache_incr_refcount(client
->md5file
);
643 client
->crypto
= init_client_crypto();
645 if (!client
->crypto
) {
647 cleanup_client(client
);
648 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
651 client
->crypto
->key
= gcry_malloc(hashlen
);
653 if (!client
->crypto
->key
) {
655 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
657 cleanup_client(client
);
658 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
661 memset(client
->crypto
->key
, 0, hashlen
);
662 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
664 if (!client
->crypto
->fh
) {
665 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
666 log_write("%s: %s", filename
, pwmd_strerror(rc
));
668 cleanup_client(client
);
669 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
673 * New files don't need a key.
675 if ((client
->xml
= new_document()) == NULL
) {
676 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
678 cleanup_client(client
);
679 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
682 client
->len
= xmlStrlen(client
->xml
);
684 client
->filename
= g_strdup(filename
);
686 if (!client
->filename
) {
688 cleanup_client(client
);
689 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
690 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
693 if (req
[1] && *req
[1]) {
694 rc
= hash_key(client
, req
[1]);
698 cleanup_client(client
);
699 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
705 client
->pinentry
->filename
= g_strdup(client
->filename
);
707 if (!client
->pinentry
->filename
) {
708 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
709 cleanup_client(client
);
710 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
713 return open_command_finalize(ctx
, NULL
, cached
);
716 if (!(client
->opts
& OPT_CIPHER
))
717 g_key_file_set_string(keyfileh
, filename
, "cipher",
718 pwmd_cipher_to_str(client
->crypto
->fh
->ver
.fh2
.flags
));
720 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
723 client
->filename
= g_strdup(filename
);
725 if (!client
->filename
) {
726 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
728 cleanup_client(client
);
729 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
733 if (client
->pinentry
->filename
)
734 g_free(client
->pinentry
->filename
);
736 client
->pinentry
->filename
= g_strdup(client
->filename
);
738 if (!client
->pinentry
->filename
) {
739 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
741 cleanup_client(client
);
742 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
746 if (client
->crypto
->fh
->ver
.fh2
.iter
<= 0ULL)
749 CACHE_LOCK(client
->ctx
);
750 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
753 if (cached
== FALSE
) {
754 gchar
*tmp
= get_key_file_string(filename
, "key_file");
756 if (tmp
&& !(client
->opts
& OPT_INQUIRE
)) {
759 cleanup_client(client
);
760 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
767 * No key specified and no matching filename found in the cache. Use
768 * pinentry to retrieve the key. Cannot return assuan_process_done()
769 * here otherwise the command will be interrupted. The event loop in
770 * client_thread() will poll the file descriptor waiting for it to
771 * become ready to read a pinentry_key_s which will contain the
772 * entered key or an error code. It will then call
773 * open_command_finalize() to to finish the command.
775 if (!req
[1] || !*req
[1]) {
777 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
779 /* From set_pinentry_defaults(). */
780 if (client
->opts
& OPT_INQUIRE
||
781 client
->pinentry
->enable
== FALSE
||
782 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
783 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
788 rc
= lock_pin_mutex(client
);
791 unlock_pin_mutex(client
->pinentry
);
792 cleanup_client(client
);
793 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
796 client
->pinentry
->which
= PINENTRY_OPEN
;
797 rc
= pinentry_fork(ctx
);
800 unlock_pin_mutex(client
->pinentry
);
801 cleanup_client(client
);
802 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
805 // Called from pinentry iterate.
806 client
->pinentry
->cb
= open_command_finalize
;
807 client
->pinentry
->status
= PINENTRY_INIT
;
810 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
815 rc
= hash_key(client
, req
[1]);
819 cleanup_client(client
);
820 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
823 else if (req
&& req
[1] && *req
[1]) {
824 rc
= hash_key(client
, req
[1]);
828 cleanup_client(client
);
829 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
835 return open_command_finalize(ctx
, NULL
, cached
);
838 static gint
open_command_inquire_finalize(gpointer data
, gint assuan_rc
,
839 guchar
*line
, gsize len
)
841 assuan_context_t ctx
= data
;
842 struct client_s
*client
= assuan_get_pointer(ctx
);
843 gpg_error_t rc
= file_modified(client
);
845 if (assuan_rc
|| (rc
&& rc
!= EPWMD_NO_FILE
)) {
849 return assuan_rc
? assuan_rc
: rc
;
852 rc
= open_command_common(ctx
, (gchar
*)line
);
857 client
->inquire_status
= INQUIRE_DONE
;
861 static gint
open_command(assuan_context_t ctx
, gchar
*line
)
864 struct client_s
*client
= assuan_get_pointer(ctx
);
865 struct argv_s
*args
[] = {
866 &(struct argv_s
) { "lock", OPTION_TYPE_NOARG
, parse_open_opt_lock
},
867 &(struct argv_s
) { "pinentry", OPTION_TYPE_OPTARG
, parse_opt_pinentry
},
868 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
869 &(struct argv_s
) { "base64", OPTION_TYPE_NOARG
, parse_opt_base64
},
873 if (client
->state
== STATE_OPEN
)
874 cleanup_client(client
);
876 if (!(client
->opts
& OPT_LOCK
))
877 client
->lock_on_open
= FALSE
;
879 rc
= parse_options(&line
, args
, client
);
882 return send_error(ctx
, rc
);
884 if ((client
->opts
& OPT_INQUIRE
)) {
885 rc
= assuan_inquire_ext(ctx
, "OPEN", 0, open_command_inquire_finalize
,
889 return send_error(ctx
, rc
);
891 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
892 client
->inquire_status
= INQUIRE_BUSY
;
896 return open_command_common(ctx
, line
);
899 gpg_error_t
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
900 guint size
, gpointer
*out
, gulong
*outsize
)
905 gint cmd
= Z_NO_FLUSH
;
909 gz
= g_malloc0(sizeof(struct gz_s
));
912 return GPG_ERR_ENOMEM
;
914 pth_cleanup_push(gz_cleanup
, &gz
);
915 gz
->which
= STATUS_COMPRESS
;
916 gz
->z
.zalloc
= z_alloc
;
917 gz
->z
.zfree
= z_free
;
918 gz
->z
.next_in
= data
;
919 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
920 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
921 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
924 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
926 return GPG_ERR_ENOMEM
;
929 zrc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
932 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
934 return GPG_ERR_COMPR_ALGO
;
937 /* Rather than store the size of the uncompressed data in the file header,
938 * store it in the comment field of the gzip header. Don't give anyone too
939 * much information. Not sure why really, but it seems the right way. :)
941 memset(&h
, 0, sizeof(gz_header
));
942 g_snprintf(buf
, sizeof(buf
), "%u", size
);
943 h
.comment
= (guchar
*)buf
;
944 zrc
= deflateSetHeader(&gz
->z
, &h
);
947 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
949 return GPG_ERR_COMPR_ALGO
;
955 zrc
= deflate(&gz
->z
, cmd
);
961 if (!gz
->z
.avail_out
) {
962 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
965 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
971 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
972 gz
->z
.avail_out
= zlib_bufsize
;
975 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
976 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
977 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
979 gz
->z
.avail_in
= zlib_bufsize
;
981 rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u",
982 gz
->z
.total_in
, size
);
988 if (gz
->z
.total_in
>= size
)
995 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
996 rc
= GPG_ERR_COMPR_ALGO
;
999 } while (zrc
!= Z_STREAM_END
);
1001 rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u", gz
->z
.total_in
, size
);
1007 *outsize
= gz
->z
.total_out
;
1017 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1020 * Useful for a large amount of data. Rather than doing all of the data in one
1021 * iteration do it in chunks. This lets the command be cancelable rather than
1022 * waiting for it to complete.
1024 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
1025 struct crypto_s
*crypto
, status_msg_t which
)
1028 goffset len
= CRYPTO_BLOCKSIZE(crypto
);
1029 gpointer p
= gcry_malloc(len
);
1034 return GPG_ERR_ENOMEM
;
1036 if (crypto
->insize
< CRYPTO_BLOCKSIZE(crypto
))
1037 len
= crypto
->insize
;
1039 pth_cleanup_push(gcry_free
, p
);
1042 inbuf
= (guchar
*)crypto
->inbuf
+ total
;
1045 if (len
+ total
> crypto
->insize
)
1046 len
= crypto
->blocksize
;
1048 if (which
== STATUS_ENCRYPT
)
1049 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1051 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1056 tmp
= (guchar
*)crypto
->inbuf
+ total
;
1057 memmove(tmp
, p
, len
);
1060 if (total
>= crypto
->insize
)
1071 /* The crypto struct must be setup for iterations and .key. */
1072 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
1073 struct crypto_s
*crypto
, const gchar
*filename
)
1075 goffset len
= crypto
->insize
;
1079 guint64 iter_progress
= 0ULL, n_iter
= 0ULL, xiter
= 0ULL;
1080 gchar tmp
[FILENAME_MAX
];
1083 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1085 if (!crypto
->fh
->ver
.fh2
.iter
) {
1087 * cache_file_count() needs both .used == TRUE and a valid key in
1088 * order for it to count as a used cache entry. Fixes CACHE status
1091 memset(crypto
->key
, '!', hashlen
);
1096 * Resize the existing xml buffer to the block size required by gcrypt
1097 * rather than duplicating it and wasting memory.
1099 crypto
->insize
+= sizeof(crypto_magic
);
1100 len
= (crypto
->insize
/ crypto
->blocksize
) * crypto
->blocksize
;
1102 if (crypto
->insize
% crypto
->blocksize
)
1103 len
+= crypto
->blocksize
;
1105 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
1108 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1109 return GPG_ERR_ENOMEM
;
1112 guchar
*tmpbuf
= inbuf
;
1113 memmove(&tmpbuf
[sizeof(crypto_magic
)], tmpbuf
, len
-sizeof(crypto_magic
));
1114 memcpy(tmpbuf
, crypto_magic
, sizeof(crypto_magic
));
1115 crypto
->inbuf
= tmpbuf
;
1116 crypto
->insize
= len
;
1117 gcry_create_nonce(crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
1120 gcry_free(crypto
->tkey
);
1122 crypto
->tkey
= gcry_malloc(hashlen
);
1124 if (!crypto
->tkey
) {
1125 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1126 return GPG_ERR_ENOMEM
;
1129 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
1130 guchar
*tkey
= crypto
->tkey
;
1133 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
1134 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1138 iter_progress
= (guint64
)get_key_file_double(
1139 client
? client
->filename
: "global", "iteration_progress");
1141 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1142 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1143 "0 %llu", crypto
->fh
->ver
.fh2
.iter
);
1149 while (xiter
< crypto
->fh
->ver
.fh2
.iter
-1) {
1150 if (iter_progress
> 0ULL && xiter
>= iter_progress
) {
1151 if (!(xiter
% iter_progress
)) {
1152 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1153 "%llu %llu", ++n_iter
* iter_progress
,
1154 crypto
->fh
->ver
.fh2
.iter
);
1161 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1162 crypto
->blocksize
))) {
1163 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1167 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1170 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1177 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1178 crypto
->blocksize
))) {
1179 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1183 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
1184 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1188 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1193 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1194 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1195 "%llu %llu", crypto
->fh
->ver
.fh2
.iter
, crypto
->fh
->ver
.fh2
.iter
);
1205 if (!client
&& !g_ascii_strcasecmp(filename
, "-")) {
1206 crypto
->fh
->fd
= STDOUT_FILENO
;
1210 if (lstat(filename
, &st
) == 0) {
1211 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1213 if (!(mode
& S_IWUSR
))
1214 return GPG_ERR_EACCES
;
1216 else if (errno
!= ENOENT
)
1217 return gpg_error_from_syserror();
1219 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1220 crypto
->fh
->fd
= mkstemp(tmp
);
1222 if (crypto
->fh
->fd
== -1) {
1223 rc
= gpg_error_from_syserror();
1224 p
= strrchr(tmp
, '/');
1226 log_write("%s: %s", p
, pwmd_strerror(rc
));
1230 pth_cleanup_push(cleanup_unlink_cb
, tmp
);
1234 * xml_import() or convert_file() from command line.
1236 crypto
->fh
->fd
= STDOUT_FILENO
;
1239 crypto
->fh
->ver
.fh2
.magic
[0] = '\177';
1240 crypto
->fh
->ver
.fh2
.magic
[1] = 'P';
1241 crypto
->fh
->ver
.fh2
.magic
[2] = 'W';
1242 crypto
->fh
->ver
.fh2
.magic
[3] = 'M';
1243 crypto
->fh
->ver
.fh2
.magic
[4] = 'D';
1244 crypto
->fh
->ver
.fh2
.version
= VERSION_HEX
;
1245 len
= pth_write(crypto
->fh
->fd
, &crypto
->fh
->ver
.fh2
, sizeof(crypto
->fh
->ver
.fh2
));
1247 if (len
!= sizeof(crypto
->fh
->ver
.fh2
)) {
1248 rc
= gpg_error_from_syserror();
1256 len
= pth_write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1258 if (len
!= crypto
->insize
) {
1259 rc
= gpg_error_from_syserror();
1267 if (fsync(crypto
->fh
->fd
) == -1) {
1268 rc
= gpg_error_from_syserror();
1280 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1281 gchar tmp2
[FILENAME_MAX
];
1283 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1285 acl
= acl_get_file(filename
, ACL_TYPE_ACCESS
);
1288 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1291 if (rename(filename
, tmp2
) == -1) {
1292 rc
= gpg_error_from_syserror();
1303 acl
= acl_get_file(".", ACL_TYPE_DEFAULT
);
1306 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1310 if (rename(tmp
, filename
) == -1) {
1311 rc
= gpg_error_from_syserror();
1323 chmod(filename
, mode
);
1326 if (acl
&& acl_set_file(filename
, ACL_TYPE_ACCESS
, acl
))
1327 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1334 if (client
&& lstat(filename
, &st
) == 0)
1335 client
->mtime
= st
.st_mtime
;
1340 gpg_error_t
update_save_flags(const gchar
*filename
,
1341 struct crypto_s
*crypto
)
1348 crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1351 return GPG_ERR_ENOMEM
;
1354 rc
= init_client_crypto2(filename
, crypto
);
1359 if (filename
&& !crypto
->fh
->v1
) {
1360 iter
= (guint64
)get_key_file_double(filename
, "iterations");
1361 crypto
->fh
->ver
.fh2
.iter
= iter
< 0L ? 0UL : iter
;
1367 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1370 struct client_s
*client
= assuan_get_pointer(ctx
);
1379 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1380 gcry_free(client
->crypto
->key
);
1382 client
->crypto
->key
= key
;
1383 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
));
1386 cleanup_crypto(&client
->crypto
);
1387 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1390 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1391 pth_cleanup_push(xmlFree
, xmlbuf
);
1392 clevel
= get_key_file_integer(client
->filename
, "compression_level");
1397 rc
= do_compress(ctx
, clevel
, xmlbuf
, len
, &outbuf
, &outsize
);
1401 cleanup_crypto(&client
->crypto
);
1403 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1411 client
->crypto
->inbuf
= xmlbuf
;
1412 client
->crypto
->insize
= len
;
1413 rc
= update_save_flags(client
->filename
, client
->crypto
);
1416 cleanup_crypto(&client
->crypto
);
1417 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1418 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1421 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1424 cleanup_crypto(&client
->crypto
);
1425 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1428 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1429 CACHE_LOCK(client
->ctx
);
1432 cache_reset_timeout(client
->md5file
, timeout
);
1435 if (client
->new == TRUE
)
1436 send_status_all(STATUS_CACHE
);
1438 client
->new = FALSE
;
1439 cleanup_crypto(&client
->crypto
);
1440 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1443 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1445 cleanup_crypto(&client
->crypto
);
1446 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1449 client
->new = FALSE
;
1450 cache_reset_timeout(client
->md5file
, timeout
);
1452 send_status_all(STATUS_CACHE
);
1453 cleanup_crypto(&client
->crypto
);
1454 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1457 static gpg_error_t
parse_save_opt_iterations(gpointer data
, gpointer v
)
1459 struct client_s
*client
= data
;
1464 if (!client
->filename
)
1465 return EPWMD_NO_FILE
;
1467 if (!value
|| !*value
)
1471 n
= strtoul(value
, &p
, 10);
1473 if (errno
|| (p
&& *p
) || n
== G_MAXULONG
)
1474 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_ERANGE
);
1476 MUTEX_LOCK(&rcfile_mutex
);
1477 g_key_file_set_double(keyfileh
,
1478 client
->filename
? client
->filename
: "global", "iterations", n
);
1479 MUTEX_UNLOCK(&rcfile_mutex
);
1481 if (client
->filename
)
1482 client
->opts
|= OPT_ITERATIONS
;
1487 static gpg_error_t
parse_save_opt_cipher(gpointer data
, gpointer value
)
1489 struct client_s
*client
= data
;
1490 const gchar
*p
= value
;
1493 if (!client
->filename
)
1494 return EPWMD_NO_FILE
;
1499 flags
= pwmd_cipher_str_to_cipher(p
);
1502 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
1504 MUTEX_LOCK(&rcfile_mutex
);
1505 g_key_file_set_string(keyfileh
, client
->filename
, "cipher", p
);
1506 MUTEX_UNLOCK(&rcfile_mutex
);
1514 static gpg_error_t
parse_save_opt_reset(gpointer data
, gpointer value
)
1516 struct client_s
*client
= data
;
1518 CACHE_LOCK(client
->ctx
);
1519 cache_clear(client
->md5file
, 1);
1524 static gpg_error_t
save_command_common(assuan_context_t ctx
, gchar
*line
)
1526 struct client_s
*client
= assuan_get_pointer(ctx
);
1527 gboolean cached
= FALSE
;
1528 guint hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1531 cached
= cache_iscached(client
->md5file
);
1535 * If a cache entry doesn't exist for this file and the file has a
1536 * "key_file" or "key" parameter, then it's an error. The reason is that
1537 * cache expiration would be useless. Unless this is an inquire, then its
1540 if (cached
== FALSE
) {
1541 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1543 if (tmp
&& !(client
->opts
& OPT_INQUIRE
)) {
1545 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1555 if (!client
->crypto
) {
1556 client
->crypto
= init_client_crypto();
1558 if (!client
->crypto
) {
1559 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1560 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1564 client
->crypto
->key
= gcry_malloc(hashlen
);
1566 if (!client
->crypto
->key
) {
1567 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1568 cleanup_crypto(&client
->crypto
);
1569 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1572 memset(client
->crypto
->key
, '!', hashlen
);
1574 if (get_key_file_double(client
->filename
, "iterations") <= 0L &&
1578 if (!line
|| !*line
) {
1579 /* It doesn't make sense to use an --inquire with an empty
1580 * passphrase. This will prevent a pinentry dialog. */
1581 if (client
->opts
& OPT_INQUIRE
) {
1582 cleanup_crypto(&client
->crypto
);
1583 return GPG_ERR_WRONG_KEY_USAGE
;
1586 client
->crypto
->tkey
= gcry_malloc(hashlen
);
1588 if (!client
->crypto
->tkey
) {
1589 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1590 cleanup_crypto(&client
->crypto
);
1591 return send_error(ctx
, GPG_ERR_ENOMEM
);
1594 memset(client
->crypto
->tkey
, '!', hashlen
);
1597 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1598 !memcmp(client
->crypto
->key
, client
->crypto
->tkey
, hashlen
)) {
1601 #ifdef WITH_PINENTRY
1604 if (client
->pinentry
->enable
== FALSE
||
1605 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1606 /* Empty keys are allowed. */
1607 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1611 lock_pin_mutex(client
);
1612 client
->pinentry
->which
= PINENTRY_SAVE
;
1613 rc
= pinentry_fork(ctx
);
1616 unlock_pin_mutex(client
->pinentry
);
1617 cleanup_crypto(&client
->crypto
);
1618 return send_error(ctx
, rc
);
1621 client
->pinentry
->cb
= save_command_finalize
;
1622 client
->pinentry
->status
= PINENTRY_INIT
;
1625 /* Empty keys are allowed. */
1626 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1638 if (get_key_file_double(client
->filename
, "iterations") <= 0L) {
1639 guint64 iter
= (guint64
)get_key_file_double(NULL
, "iterations");
1644 MUTEX_LOCK(&rcfile_mutex
);
1645 g_key_file_set_double(keyfileh
, client
->filename
, "iterations", iter
);
1646 MUTEX_UNLOCK(&rcfile_mutex
);
1647 client
->opts
|= OPT_ITERATIONS
;
1648 rc
= send_status(ctx
, STATUS_CONFIG
, NULL
);
1651 cleanup_crypto(&client
->crypto
);
1652 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1656 rc
= hash_key(client
, line
);
1659 cleanup_crypto(&client
->crypto
);
1660 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1665 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1668 static gint
save_command_inquire_finalize(gpointer data
, gint assuan_rc
,
1669 guchar
*line
, gsize len
)
1671 assuan_context_t ctx
= data
;
1672 struct client_s
*client
= assuan_get_pointer(ctx
);
1673 gpg_error_t rc
= file_modified(client
);
1675 if (assuan_rc
|| rc
) {
1679 return assuan_rc
? assuan_rc
: rc
;
1682 rc
= save_command_common(ctx
, (gchar
*)line
);
1687 client
->inquire_status
= INQUIRE_DONE
;
1691 static gint
save_command(assuan_context_t ctx
, gchar
*line
)
1694 struct client_s
*client
= assuan_get_pointer(ctx
);
1696 struct argv_s
*args
[] = {
1697 &(struct argv_s
) { "iterations", OPTION_TYPE_OPTARG
, parse_save_opt_iterations
},
1698 &(struct argv_s
) { "cipher", OPTION_TYPE_OPTARG
, parse_save_opt_cipher
},
1699 &(struct argv_s
) { "pinentry", OPTION_TYPE_OPTARG
, parse_opt_pinentry
},
1700 &(struct argv_s
) { "reset", OPTION_TYPE_NOARG
, parse_save_opt_reset
},
1701 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
1702 &(struct argv_s
) { "base64", OPTION_TYPE_NOARG
, parse_opt_base64
},
1706 rc
= parse_options(&line
, args
, client
);
1709 return send_error(ctx
, rc
);
1711 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1712 return send_error(ctx
, gpg_error_from_syserror());
1714 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1715 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1716 return send_error(ctx
, GPG_ERR_ENOANO
);
1719 if ((client
->opts
& OPT_INQUIRE
)) {
1720 rc
= assuan_inquire_ext(ctx
, "SAVE", 0, save_command_inquire_finalize
,
1724 return send_error(ctx
, rc
);
1726 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1727 client
->inquire_status
= INQUIRE_BUSY
;
1732 log_write2("ARGS=%s", "<passphrase>");
1734 return save_command_common(ctx
, line
);
1737 static gint
delete_command(assuan_context_t ctx
, gchar
*line
)
1739 struct client_s
*client
= assuan_get_pointer(ctx
);
1744 log_write2("ARGS=\"%s\"", line
);
1746 if (strchr(line
, '\t'))
1747 req
= split_input_line(line
, "\t", -1);
1749 req
= split_input_line(line
, " ", -1);
1752 return send_error(ctx
, GPG_ERR_SYNTAX
);
1754 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1758 return send_error(ctx
, rc
);
1762 * No sub-node defined. Remove the entire node (root element).
1766 rc
= unlink_node(n
);
1771 return send_error(ctx
, rc
);
1774 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1778 return send_error(ctx
, rc
);
1781 rc
= unlink_node(n
);
1785 return send_error(ctx
, rc
);
1789 * Don't return with assuan_process_done() here. This has been called from
1790 * assuan_process_next() and the command should be finished in
1793 static gint
store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1796 assuan_context_t ctx
= data
;
1797 struct client_s
*client
= assuan_get_pointer(ctx
);
1800 gpg_error_t rc
= file_modified(client
);
1802 if (assuan_rc
|| rc
) {
1805 return assuan_rc
? assuan_rc
: rc
;
1808 req
= split_input_line((gchar
*)line
, "\t", 0);
1812 return GPG_ERR_SYNTAX
;
1815 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1817 if (rc
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
1818 rc
= new_root_element(client
->doc
, *req
);
1835 n
= create_elements_cb(n
, req
+1, &rc
, NULL
);
1837 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1838 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
, FALSE
);
1842 client
->inquire_status
= INQUIRE_DONE
;
1845 rc
= update_element_mtime(n
);
1850 static gint
store_command(assuan_context_t ctx
, gchar
*line
)
1852 struct client_s
*client
= assuan_get_pointer(ctx
);
1855 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1858 return send_error(ctx
, rc
);
1860 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1861 client
->inquire_status
= INQUIRE_BUSY
;
1865 static void *send_data_cb(void *arg
)
1867 struct assuan_cmd_s
*data
= arg
;
1871 pth_cancel_state(PTH_CANCEL_ENABLE
|PTH_CANCEL_ASYNCHRONOUS
, &old
);
1872 rc
= g_malloc(sizeof(gpg_error_t
));
1873 *rc
= assuan_send_data(data
->ctx
, data
->line
, data
->line_len
);
1874 pth_cancel_state(old
, NULL
);
1879 /* For every assuan command that needs to be sent to the client, a timeout is
1880 * needed to determine if the client lost the connection. The timeout is the
1881 * same as the "keepalive" configuration parameter or a default if unset.
1883 gpg_error_t
do_assuan_command(assuan_context_t ctx
,
1884 void *(*cb
)(void *data
), void *data
)
1886 pth_attr_t attr
= pth_attr_new();
1888 gint to
= get_key_file_integer("global", "keepalive");
1889 pth_event_t ev
, tev
;
1894 pth_attr_init(attr
);
1895 pth_attr_set(attr
, PTH_ATTR_JOINABLE
, TRUE
);
1896 tid
= pth_spawn(attr
, cb
, data
);
1897 rc
= gpg_error_from_syserror();
1898 pth_attr_destroy(attr
);
1901 log_write("%s(%i): pth_spawn(): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1905 pth_cleanup_push(cleanup_cancel_cb
, tid
);
1906 to
= to
<= 0 ? DEFAULT_KEEPALIVE_TO
: to
;
1907 ev
= pth_event(PTH_EVENT_TID
|PTH_UNTIL_TID_DEAD
, tid
);
1908 tev
= to
? pth_event(PTH_EVENT_TIME
, pth_timeout(to
, 0)) : NULL
;
1909 ev
= pth_event_concat(ev
, tev
, NULL
);
1910 pth_cleanup_push(cleanup_ev_cb
, ev
);
1915 st
= pth_event_status(tev
);
1917 if (st
== PTH_STATUS_OCCURRED
) {
1920 return GPG_ERR_TIMEOUT
;
1924 st
= pth_event_status(ev
);
1926 if (st
== PTH_STATUS_FAILED
) {
1930 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1932 else if (st
== PTH_STATUS_OCCURRED
) {
1934 rc
= *(gpg_error_t
*)p
;
1943 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
1949 struct assuan_cmd_s data
;
1950 gint progress
= get_key_file_integer("global", "xfer_progress");
1953 progress
= progress
>0 ? (progress
/ASSUAN_LINELENGTH
)*ASSUAN_LINELENGTH
: 0;
1954 to_send
= total
< ASSUAN_LINELENGTH
? total
: ASSUAN_LINELENGTH
;
1956 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1963 if (sent
+ to_send
> total
)
1964 to_send
= total
- sent
;
1966 data
.line
= flush
? NULL
: (gchar
*)line
+sent
;
1967 data
.line_len
= flush
? 0 : to_send
;
1968 rc
= do_assuan_command(ctx
, send_data_cb
, &data
);
1971 sent
+= flush
? 0 : to_send
;
1973 if ((progress
&& !(sent
% progress
) && sent
!= total
) ||
1974 (sent
== total
&& flush
))
1975 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1977 if (!flush
&& !rc
&& sent
== total
) {
1982 } while (!rc
&& sent
< total
);
1987 static gint
get_command(assuan_context_t ctx
, gchar
*line
)
1989 struct client_s
*client
= assuan_get_pointer(ctx
);
1994 log_write2("ARGS=\"%s\"", line
);
1995 req
= split_input_line(line
, "\t", -1);
1997 if (!req
|| !*req
) {
1999 return send_error(ctx
, GPG_ERR_SYNTAX
);
2002 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
2006 return send_error(ctx
, rc
);
2010 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2015 return send_error(ctx
, rc
);
2017 if (!n
|| !n
->children
)
2018 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2020 n
= find_text_node(n
->children
);
2022 if (!n
|| !n
->content
|| !*n
->content
)
2023 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2025 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
2026 return send_error(ctx
, rc
);
2029 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
2030 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
2032 gchar
*path
= *(gchar
**)data
;
2033 gchar
*tmp
= NULL
, *result
;
2037 *(gchar
**)data
= NULL
;
2040 path
= g_strjoinv("\t", target
);
2043 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2044 *rc
= GPG_ERR_ENOMEM
;
2049 tmp
= g_strjoinv("\t", req_orig
);
2053 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2054 *rc
= GPG_ERR_ENOMEM
;
2060 result
= g_strdup_printf("%s\t%s", path
, tmp
);
2062 result
= g_strdup(path
);
2065 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2066 *rc
= GPG_ERR_ENOMEM
;
2074 *(gchar
**)data
= result
;
2078 static void list_command_cleanup1(void *arg
);
2079 static gint
realpath_command(assuan_context_t ctx
, gchar
*line
)
2082 struct client_s
*client
= assuan_get_pointer(ctx
);
2090 log_write2("ARGS=\"%s\"", line
);
2092 if (strchr(line
, '\t') != NULL
) {
2093 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
2094 return send_error(ctx
, GPG_ERR_SYNTAX
);
2097 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
2098 return send_error(ctx
, GPG_ERR_SYNTAX
);
2101 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
2105 return send_error(ctx
, rc
);
2108 rp
= g_strjoinv("\t", req
);
2112 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2113 return send_error(ctx
, GPG_ERR_ENOMEM
);
2117 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
2118 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
, FALSE
);
2123 return send_error(ctx
, rc
);
2127 string
= g_string_new(rp
);
2132 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2133 return send_error(ctx
, GPG_ERR_ENOMEM
);
2137 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
2138 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
2139 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
2144 pth_cleanup_push(list_command_cleanup1
, string
);
2145 rc
= xfer_data(ctx
, string
->str
, string
->len
);
2147 return send_error(ctx
, rc
);
2150 static void list_command_cleanup1(void *arg
)
2152 g_string_free((GString
*)arg
, TRUE
);
2155 static void list_command_cleanup2(void *arg
)
2157 struct element_list_s
*elements
= arg
;
2160 if (elements
->list
) {
2161 gint total
= g_slist_length(elements
->list
);
2164 for (i
= 0; i
< total
; i
++) {
2165 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
2169 g_slist_free(elements
->list
);
2172 if (elements
->prefix
)
2173 g_free(elements
->prefix
);
2176 g_strfreev(elements
->req
);
2182 static gpg_error_t
parse_list_opt_norecurse(gpointer data
, gpointer value
)
2184 struct element_list_s
*elements
= data
;
2186 elements
->recurse
= FALSE
;
2190 static gpg_error_t
parse_list_opt_verbose(gpointer data
, gpointer value
)
2192 struct element_list_s
*elements
= data
;
2194 elements
->verbose
= TRUE
;
2198 static gint
list_command(assuan_context_t ctx
, gchar
*line
)
2200 struct client_s
*client
= assuan_get_pointer(ctx
);
2202 struct element_list_s
*elements
= NULL
;
2204 struct argv_s
*args
[] = {
2205 &(struct argv_s
) { "no-recurse", OPTION_TYPE_NOARG
, parse_list_opt_norecurse
},
2206 &(struct argv_s
) { "verbose", OPTION_TYPE_NOARG
, parse_list_opt_verbose
},
2210 if (disable_list_and_dump
== TRUE
)
2211 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2213 elements
= g_malloc0(sizeof(struct element_list_s
));
2216 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2217 return GPG_ERR_ENOMEM
;
2220 elements
->recurse
= TRUE
; // default
2221 pth_cleanup_push(list_command_cleanup2
, elements
);
2222 rc
= parse_options(&line
, args
, elements
);
2230 rc
= list_root_elements(client
->doc
, &str
, elements
->verbose
);
2234 return send_error(ctx
, rc
);
2237 pth_cleanup_push(list_command_cleanup1
, str
);
2238 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2241 return send_error(ctx
, rc
);
2244 elements
->req
= split_input_line(line
, " ", 0);
2247 strv_printf(&elements
->req
, "%s", line
);
2249 rc
= create_path_list(client
->doc
, elements
, *elements
->req
);
2255 gint total
= g_slist_length(elements
->list
);
2260 rc
= GPG_ERR_NO_VALUE
;
2264 str
= g_string_new(NULL
);
2267 rc
= GPG_ERR_ENOMEM
;
2268 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2272 for (i
= 0; i
< total
; i
++) {
2273 tmp
= g_slist_nth_data(elements
->list
, i
);
2274 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
2277 pth_cleanup_push(list_command_cleanup1
, str
);
2278 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2282 rc
= GPG_ERR_NO_VALUE
;
2286 return send_error(ctx
, rc
);
2290 * req[0] - element path
2292 static gpg_error_t
attribute_list(assuan_context_t ctx
, gchar
**req
)
2294 struct client_s
*client
= assuan_get_pointer(ctx
);
2295 gchar
**attrlist
= NULL
;
2297 gchar
**path
= NULL
;
2303 if (!req
|| !req
[0])
2304 return GPG_ERR_SYNTAX
;
2306 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2308 * The first argument may be only a root element.
2310 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2311 return GPG_ERR_SYNTAX
;
2314 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2322 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2323 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2333 for (a
= n
->properties
; a
; a
= a
->next
) {
2336 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
2338 g_strfreev(attrlist
);
2340 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2341 return GPG_ERR_ENOMEM
;
2346 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
,
2347 an
&& an
->content
? (gchar
*)an
->content
: "");
2350 g_strfreev(attrlist
);
2351 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2352 return GPG_ERR_ENOMEM
;
2355 attrlist
[++i
] = NULL
;
2359 return GPG_ERR_NO_VALUE
;
2361 line
= g_strjoinv("\n", attrlist
);
2364 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2365 g_strfreev(attrlist
);
2366 return GPG_ERR_ENOMEM
;
2369 pth_cleanup_push(g_free
, line
);
2370 pth_cleanup_push(req_cleanup
, attrlist
);
2371 rc
= xfer_data(ctx
, line
, strlen(line
));
2378 * req[0] - attribute
2379 * req[1] - element path
2381 static gpg_error_t
attribute_delete(struct client_s
*client
, gchar
**req
)
2384 gchar
**path
= NULL
;
2387 if (!req
|| !req
[0] || !req
[1])
2388 return GPG_ERR_SYNTAX
;
2390 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2392 * The first argument may be only a root element.
2394 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2395 return GPG_ERR_SYNTAX
;
2399 * Don't remove the "_name" attribute for the root element. To remove an
2400 * root element use DELETE <name>.
2402 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"_name")) {
2403 rc
= GPG_ERR_SYNTAX
;
2407 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2413 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2414 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2420 rc
= delete_attribute(n
, (xmlChar
*)req
[0]);
2427 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
2430 gchar
**src
= *path
;
2431 gchar
**src_orig
= g_strdupv(src
);
2432 xmlNodePtr n
= NULL
;
2437 *rc
= GPG_ERR_ENOMEM
;
2438 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2443 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2446 if (*rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
2447 *rc
= new_root_element(client
->doc
, src
[0]);
2460 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
2462 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2463 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
, FALSE
);
2469 * Reset the position of the element tree now that the elements
2470 * have been created.
2475 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2480 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2481 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2489 g_strfreev(src_orig
);
2496 * Creates a "target" attribute. When other commands encounter an element with
2497 * this attribute, the element path is modified to the target value. If the
2498 * source element path doesn't exist when using 'ATTR SET target', it is
2499 * created, but the destination element path must exist.
2501 * req[0] - source element path
2502 * req[1] - destination element path
2504 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2506 gchar
**src
, **dst
, *line
= NULL
, **odst
= NULL
;
2510 if (!req
|| !req
[0] || !req
[1])
2511 return GPG_ERR_SYNTAX
;
2513 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2515 * The first argument may be only a root element.
2517 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2518 return GPG_ERR_SYNTAX
;
2521 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2523 * The first argument may be only a root element.
2525 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2526 rc
= GPG_ERR_SYNTAX
;
2531 odst
= g_strdupv(dst
);
2534 rc
= GPG_ERR_ENOMEM
;
2538 n
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
2541 * Make sure the destination element path exists.
2547 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2548 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2554 n
= create_element_path(client
, &src
, &rc
);
2559 line
= g_strjoinv("\t", odst
);
2562 rc
= GPG_ERR_ENOMEM
;
2563 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2567 rc
= add_attribute(n
, "target", line
);
2581 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2587 tmp
= g_strdupv(req
);
2590 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2591 return GPG_ERR_ENOMEM
;
2594 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2600 if (g_utf8_collate(req
[0], req
[1]) == 0)
2604 * Will not overwrite an existing root.
2606 tmp
= g_strdupv(req
+1);
2609 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2610 return GPG_ERR_ENOMEM
;
2613 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2616 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
2620 return GPG_ERR_AMBIGUOUS_NAME
;
2622 if (!valid_xml_element((xmlChar
*)req
[1]))
2623 return GPG_ERR_SYNTAX
;
2625 tmp
= g_strdupv(req
);
2628 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2629 return GPG_ERR_ENOMEM
;
2632 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2636 return GPG_ERR_ELEMENT_NOT_FOUND
;
2638 return add_attribute(n
, "_name", req
[1]);
2642 * req[0] - attribute
2643 * req[1] - element path
2645 static gpg_error_t
attribute_get(assuan_context_t ctx
, gchar
**req
)
2647 struct client_s
*client
= assuan_get_pointer(ctx
);
2653 if (!req
|| !req
[0] || !req
[1])
2654 return GPG_ERR_SYNTAX
;
2656 if (strchr(req
[1], '\t')) {
2657 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2658 return GPG_ERR_SYNTAX
;
2661 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2662 return GPG_ERR_SYNTAX
;
2665 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2671 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2672 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2680 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2681 return GPG_ERR_NOT_FOUND
;
2683 pth_cleanup_push(xmlFree
, a
);
2686 rc
= xfer_data(ctx
, (gchar
*)a
, xmlStrlen(a
));
2688 rc
= GPG_ERR_NO_VALUE
;
2699 * req[0] - attribute
2700 * req[1] - element path
2703 static gpg_error_t
attribute_set(struct client_s
*client
, gchar
**req
)
2705 gchar
**path
= NULL
;
2709 if (!req
|| !req
[0] || !req
[1])
2710 return GPG_ERR_SYNTAX
;
2713 * Reserved attribute names.
2715 if (!strcmp(req
[0], "_name")) {
2717 * Only reserved for the root element. Not the rest of the
2720 if (strchr(req
[1], '\t') == NULL
)
2721 return name_attribute(client
, req
+ 1);
2723 else if (!strcmp(req
[0], "target"))
2724 return target_attribute(client
, req
+ 1);
2726 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2728 * The first argument may be only a root element.
2730 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2731 return GPG_ERR_SYNTAX
;
2734 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2740 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2741 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2747 rc
= add_attribute(n
, req
[0], req
[2]);
2756 * req[1] - attribute name or element path if command is LIST
2757 * req[2] - element path
2758 * req[2] - element path or value
2760 static gint
attr_command(assuan_context_t ctx
, gchar
*line
)
2762 struct client_s
*client
= assuan_get_pointer(ctx
);
2766 log_write2("ARGS=\"%s\"", line
);
2767 req
= split_input_line(line
, " ", 4);
2769 if (!req
|| !req
[0] || !req
[1]) {
2771 return send_error(ctx
, GPG_ERR_SYNTAX
);
2774 pth_cleanup_push(req_cleanup
, req
);
2776 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2777 rc
= attribute_set(client
, req
+1);
2778 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2779 rc
= attribute_get(ctx
, req
+1);
2780 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2781 rc
= attribute_delete(client
, req
+1);
2782 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2783 rc
= attribute_list(ctx
, req
+1);
2785 rc
= GPG_ERR_SYNTAX
;
2788 return send_error(ctx
, rc
);
2791 static gint
iscached_command(assuan_context_t ctx
, gchar
*line
)
2793 gchar
**req
= split_input_line(line
, " ", 0);
2797 if (!req
|| !*req
) {
2799 return send_error(ctx
, GPG_ERR_SYNTAX
);
2802 log_write2("ARGS=\"%s\"", line
);
2804 if (!valid_filename(req
[0])) {
2806 return GPG_ERR_INV_VALUE
;
2809 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2812 if (cache_iscached(md5file
)) {
2815 return send_error(ctx
, 0);
2819 tmp
= get_key_file_string("global", "data_directory");
2823 return GPG_ERR_ENOMEM
;
2826 path
= expand_homedir(tmp
);
2831 return GPG_ERR_ENOMEM
;
2836 path
= g_strdup_printf("%s/%s", tmp
, req
[0]);
2841 return GPG_ERR_ENOMEM
;
2844 if (access(path
, R_OK
) == -1) {
2845 gpg_error_t rc
= gpg_error_from_syserror();
2849 return send_error(ctx
, rc
);
2853 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2856 static gint
clearcache_command(assuan_context_t ctx
, gchar
*line
)
2858 gchar
**req
= split_input_line(line
, " ", 0);
2861 log_write2("ARGS=\"%s\"", line
);
2864 if (!req
|| !*req
) {
2866 cache_clear(NULL
, 2);
2868 return send_error(ctx
, 0);
2871 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2874 if (cache_clear(md5file
, 1) == FALSE
) {
2876 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2880 return send_error(ctx
, 0);
2883 static gint
cachetimeout_command(assuan_context_t ctx
, gchar
*line
)
2887 gchar
**req
= split_input_line(line
, " ", 0);
2890 if (!req
|| !*req
|| !req
[1]) {
2892 return send_error(ctx
, GPG_ERR_SYNTAX
);
2896 timeout
= strtol(req
[1], &p
, 10);
2898 if (errno
!= 0 || *p
!= 0 || timeout
< -1) {
2900 return send_error(ctx
, GPG_ERR_SYNTAX
);
2903 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2904 CACHE_LOCK(client
->ctx
);
2906 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2908 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2912 return send_error(ctx
, 0);
2915 static gint
dump_command(assuan_context_t ctx
, gchar
*line
)
2919 struct client_s
*client
= assuan_get_pointer(ctx
);
2922 if (disable_list_and_dump
== TRUE
)
2923 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2925 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2928 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2929 return send_error(ctx
, GPG_ERR_ENOMEM
);
2932 pth_cleanup_push(xmlFree
, xml
);
2933 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
2935 return send_error(ctx
, rc
);
2938 static gint
getconfig_command(assuan_context_t ctx
, gchar
*line
)
2940 struct client_s
*client
= assuan_get_pointer(ctx
);
2942 gchar filename
[255]={0}, param
[747]={0};
2943 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2945 log_write2("ARGS=\"%s\"", line
);
2947 if (strchr(line
, ' ')) {
2948 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2953 if (fp
&& !valid_filename(fp
))
2954 return send_error(ctx
, GPG_ERR_INV_VALUE
);
2956 paramp
= g_ascii_strdown(paramp
, -1);
2959 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2960 return send_error(ctx
, GPG_ERR_ENOMEM
);
2963 if (fp
&& !g_ascii_strcasecmp(paramp
, "iterations")) {
2964 if (!(client
->opts
& OPT_ITERATIONS
) || fp
!= client
->filename
) {
2965 file_header_internal_t
*fh
= read_file_header(fp
, FALSE
, &rc
);
2967 if (!fh
&& rc
!= GPG_ERR_ENOENT
)
2968 return send_error(ctx
, rc
);
2972 p
= g_strdup_printf("%lu", (unsigned long)fh
->ver
.fh2
.iter
);
2973 close_file_header(fh
);
2976 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2977 pwmd_strerror(GPG_ERR_ENOMEM
));
2978 return send_error(ctx
, GPG_ERR_ENOMEM
);
2985 else if (!g_ascii_strcasecmp(paramp
, "enable_pinentry")) {
2986 #ifdef WITH_PINENTRY
2989 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY
))
2990 n
= client
->pinentry
->enable
;
2992 n
= get_key_file_boolean(fp
, "enable_pinentry");
2994 p
= g_strdup_printf("%s", n
? "true" : "false");
2997 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2998 pwmd_strerror(GPG_ERR_ENOMEM
));
2999 return send_error(ctx
, GPG_ERR_ENOMEM
);
3004 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3007 else if (!g_ascii_strcasecmp(paramp
, "pinentry_timeout")) {
3008 #ifdef WITH_PINENTRY
3009 p
= g_strdup_printf("%i", get_key_file_integer(fp
, "pinentry_timeout"));
3012 log_write("%s(%i): %s", __FILE__
, __LINE__
,
3013 pwmd_strerror(GPG_ERR_ENOMEM
));
3014 return send_error(ctx
, GPG_ERR_ENOMEM
);
3019 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3023 p
= get_key_file_string(fp
? fp
: "global", paramp
);
3027 return send_error(ctx
, GPG_ERR_NO_VALUE
);
3029 tmp
= expand_homedir(p
);
3033 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3034 return send_error(ctx
, GPG_ERR_ENOMEM
);
3039 pth_cleanup_push(g_free
, p
);
3040 rc
= xfer_data(ctx
, p
, strlen(p
));
3042 return send_error(ctx
, rc
);
3046 xmlXPathContextPtr xp
;
3047 xmlXPathObjectPtr result
;
3052 static void xpath_command_cleanup(void *arg
)
3054 struct xpath_s
*xpath
= arg
;
3056 req_cleanup(xpath
->req
);
3059 xmlBufferFree(xpath
->buf
);
3062 xmlXPathFreeObject(xpath
->result
);
3065 xmlXPathFreeContext(xpath
->xp
);
3068 static gint
xpath_command(assuan_context_t ctx
, gchar
*line
)
3070 struct client_s
*client
= assuan_get_pointer(ctx
);
3072 struct xpath_s xpath
;
3074 log_write2("ARGS=\"%s\"", line
);
3076 if (disable_list_and_dump
== TRUE
)
3077 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3079 if (!line
|| !*line
)
3080 return send_error(ctx
, GPG_ERR_SYNTAX
);
3082 memset(&xpath
, 0, sizeof(struct xpath_s
));
3084 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
3085 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
3086 return send_error(ctx
, GPG_ERR_ENOMEM
);
3089 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3092 xpath_command_cleanup(&xpath
);
3093 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3096 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3098 if (!xpath
.result
) {
3099 xpath_command_cleanup(&xpath
);
3100 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3103 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3104 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3108 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3109 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, 0, NULL
);
3113 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
3114 rc
= GPG_ERR_NO_VALUE
;
3117 else if (xpath
.req
[1])
3120 pth_cleanup_push(xpath_command_cleanup
, &xpath
);
3121 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
.buf
),
3122 xmlBufferLength(xpath
.buf
));
3126 xpath_command_cleanup(&xpath
);
3127 return send_error(ctx
, rc
);
3130 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3131 static gint
xpathattr_command(assuan_context_t ctx
, gchar
*line
)
3133 struct client_s
*client
= assuan_get_pointer(ctx
);
3135 struct xpath_s xpath
;
3137 gboolean cmd
= FALSE
; //SET
3139 log_write2("ARGS=\"%s\"", line
);
3141 if (disable_list_and_dump
== TRUE
)
3142 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3144 if (!line
|| !*line
)
3145 return send_error(ctx
, GPG_ERR_SYNTAX
);
3147 memset(&xpath
, 0, sizeof(struct xpath_s
));
3149 if ((req
= split_input_line(line
, " ", 3)) == NULL
)
3150 return send_error(ctx
, GPG_ERR_ENOMEM
);
3153 rc
= GPG_ERR_SYNTAX
;
3157 if (!g_ascii_strcasecmp(req
[0], "SET"))
3159 else if (!g_ascii_strcasecmp(req
[0], "DELETE"))
3162 rc
= GPG_ERR_SYNTAX
;
3166 if (!req
[1] || !req
[2]) {
3167 rc
= GPG_ERR_SYNTAX
;
3171 if ((xpath
.req
= split_input_line(req
[2], "\t", 3)) == NULL
) {
3172 rc
= GPG_ERR_ENOMEM
;
3176 if (!xpath
.req
[0] || (!xpath
.req
[1] && !cmd
) || (xpath
.req
[1] && cmd
)) {
3177 rc
= GPG_ERR_SYNTAX
;
3181 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3184 rc
= EPWMD_LIBXML_ERROR
;
3188 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3190 if (!xpath
.result
) {
3191 rc
= EPWMD_LIBXML_ERROR
;
3195 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3196 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3200 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3201 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, cmd
, (xmlChar
*)req
[1]);
3205 xpath_command_cleanup(&xpath
);
3206 return send_error(ctx
, rc
);
3209 static gint
import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
3212 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
3213 gpg_error_t rc
= file_modified(client
);
3214 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
3215 xmlDocPtr doc
= NULL
;
3216 xmlNodePtr n
, root
, copy
;
3218 if (assuan_rc
|| rc
) {
3221 return assuan_rc
? assuan_rc
: rc
;
3224 req
= split_input_line((gchar
*)line
, "\t", 2);
3228 return GPG_ERR_SYNTAX
;
3231 path
= split_input_line(req
[1], "\t", 0);
3233 if (!content
|| !*content
) {
3234 rc
= GPG_ERR_SYNTAX
;
3238 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
3241 rc
= EPWMD_LIBXML_ERROR
;
3245 root
= xmlDocGetRootElement(doc
);
3246 rc
= validate_import(root
);
3252 path_orig
= g_strdupv(path
);
3255 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3256 rc
= GPG_ERR_ENOMEM
;
3260 xmlChar
*a
= xmlGetProp(root
, (xmlChar
*)"_name");
3263 g_strfreev(path_orig
);
3264 rc
= GPG_ERR_ENOMEM
;
3268 if (strv_printf(&path
, "%s", (gchar
*)a
) == FALSE
) {
3270 g_strfreev(path_orig
);
3271 rc
= GPG_ERR_ENOMEM
;
3276 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
3278 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3279 g_strfreev(path_orig
);
3284 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, TRUE
);
3286 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3287 g_strfreev(path_orig
);
3291 xmlNodePtr parent
= n
->parent
;
3302 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
3303 n
= create_element_path(client
, &path
, &rc
);
3309 copy
= xmlCopyNodeList(root
);
3310 n
= xmlAddChildList(n
, copy
);
3313 rc
= EPWMD_LIBXML_ERROR
;
3316 /* Check if the content root element can create a DTD root element. */
3317 if (!xmlStrEqual((xmlChar
*)"element", root
->name
)) {
3318 rc
= GPG_ERR_SYNTAX
;
3324 if ((a
= xmlGetProp(root
, (xmlChar
*)"_name")) == NULL
) {
3325 rc
= GPG_ERR_SYNTAX
;
3329 gchar
*tmp
= g_strdup((gchar
*)a
);
3331 gboolean literal
= is_literal_element(&tmp
);
3333 if (!valid_xml_element((xmlChar
*)tmp
) || literal
) {
3335 rc
= GPG_ERR_INV_VALUE
;
3339 if (strv_printf(&path
, "%s", tmp
) == FALSE
) {
3341 rc
= GPG_ERR_ENOMEM
;
3346 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, TRUE
);
3348 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3349 rc
= EPWMD_LIBXML_ERROR
;
3353 /* Overwriting the existing tree. */
3360 xmlSetProp(root
, (xmlChar
*)"_name", (xmlChar
*)path
[0]);
3361 n
= xmlCopyNode(root
, 1);
3362 n
= xmlAddChildList(xmlDocGetRootElement(client
->doc
), n
);
3366 rc
= update_element_mtime(n
->parent
);
3376 client
->inquire_status
= INQUIRE_DONE
;
3380 static gint
import_command(assuan_context_t ctx
, gchar
*line
)
3383 struct client_s
*client
= assuan_get_pointer(ctx
);
3385 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
3388 return send_error(ctx
, rc
);
3390 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3391 client
->inquire_status
= INQUIRE_BUSY
;
3395 static gpg_error_t
do_lock_command(struct client_s
*client
)
3397 gpg_error_t rc
= lock_file_mutex(client
);
3400 client
->is_lock_cmd
= TRUE
;
3402 return client
->opts
& OPT_INQUIRE
? rc
: send_error(client
->ctx
, rc
);
3405 static gint
lock_command(assuan_context_t ctx
, gchar
*line
)
3407 struct client_s
*client
= assuan_get_pointer(ctx
);
3409 return do_lock_command(client
);
3412 static gint
unlock_command(assuan_context_t ctx
, gchar
*line
)
3414 struct client_s
*client
= assuan_get_pointer(ctx
);
3416 unlock_file_mutex(client
);
3417 return send_error(ctx
, 0);
3420 static gint
getpid_command(assuan_context_t ctx
, gchar
*line
)
3424 pid_t pid
= getpid();
3426 print_fmt(buf
, sizeof(buf
), "%i", pid
);
3427 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3428 return send_error(ctx
, rc
);
3431 static gint
version_command(assuan_context_t ctx
, gchar
*line
)
3436 print_fmt(buf
, sizeof(buf
), "0x%X", VERSION_HEX
);
3437 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3438 return send_error(ctx
, rc
);
3441 #ifdef WITH_PINENTRY
3442 static void set_option_value(gchar
**opt
, const gchar
*value
)
3450 *opt
= g_strdup(value
);
3454 static gint
set_unset_common(assuan_context_t ctx
, const gchar
*name
,
3457 struct client_s
*client
= assuan_get_pointer(ctx
);
3460 if (g_ascii_strcasecmp(name
, (gchar
*)"log_level") == 0) {
3464 l
= strtol(value
, NULL
, 10);
3467 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3470 MUTEX_LOCK(&rcfile_mutex
);
3471 g_key_file_set_integer(keyfileh
, "global", "log_level", (gint
)l
);
3472 MUTEX_UNLOCK(&rcfile_mutex
);
3475 else if (g_ascii_strcasecmp(name
, (gchar
*)"rc_on_locked") == 0) {
3479 l
= strtol(value
, NULL
, 10);
3482 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3485 client
->rc_on_locked
= l
? TRUE
: FALSE
;
3488 else if (g_ascii_strcasecmp(name
, (gchar
*)"lock_on_open") == 0) {
3489 rc
= parse_open_opt_lock(client
, (gpointer
)value
);
3494 client
->opts
|= OPT_LOCK
;
3496 else if (g_ascii_strcasecmp(name
, (gchar
*)"cipher") == 0) {
3498 client
->opts
&= ~(OPT_CIPHER
);
3502 rc
= parse_save_opt_cipher(client
, (gpointer
)value
);
3507 client
->opts
|= OPT_CIPHER
;
3510 else if (g_ascii_strcasecmp(name
, (gchar
*)"iterations") == 0) {
3511 rc
= parse_save_opt_iterations(client
, (gpointer
)value
);
3518 else if (g_ascii_strcasecmp(name
, (gchar
*)"NAME") == 0) {
3519 pth_attr_t attr
= pth_attr_of(pth_self());
3523 pth_attr_destroy(attr
);
3527 print_fmt(buf
, sizeof(buf
), "%s", value
);
3528 pth_attr_set(attr
, PTH_ATTR_NAME
, buf
);
3529 pth_attr_destroy(attr
);
3530 #ifdef WITH_PINENTRY
3531 if (client
->pinentry
->name
)
3532 g_free(client
->pinentry
->name
);
3534 client
->pinentry
->name
= g_strdup(buf
);
3536 if (!client
->pinentry
->name
)
3537 return GPG_ERR_ENOMEM
;
3542 #ifdef WITH_PINENTRY
3543 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3544 set_option_value(&client
->pinentry
->lcmessages
, value
);
3545 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3546 set_option_value(&client
->pinentry
->lcctype
, value
);
3547 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3548 set_option_value(&client
->pinentry
->ttyname
, value
);
3549 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3550 set_option_value(&client
->pinentry
->ttytype
, value
);
3551 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3552 set_option_value(&client
->pinentry
->display
, value
);
3553 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3554 set_option_value(&client
->pinentry
->path
, value
);
3555 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3556 set_option_value(&client
->pinentry
->title
, value
);
3557 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3558 set_option_value(&client
->pinentry
->prompt
, value
);
3559 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3560 set_option_value(&client
->pinentry
->desc
, value
);
3561 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0) {
3568 n
= strtol(value
, &p
, 10);
3571 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3573 MUTEX_LOCK(&rcfile_mutex
);
3574 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
:
3575 "global", "pinentry_timeout", n
);
3576 MUTEX_UNLOCK(&rcfile_mutex
);
3579 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0) {
3580 rc
= parse_opt_pinentry(client
, (gpointer
)value
);
3588 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3589 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3590 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3591 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3592 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3593 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3594 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3595 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3596 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3597 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3598 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3599 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3600 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3601 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3602 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3603 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3604 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3605 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3606 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0)
3607 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3608 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0)
3609 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3612 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
3618 static gint
unset_command(assuan_context_t ctx
, gchar
*line
)
3620 log_write2("ARGS=\"%s\"", line
);
3621 return send_error(ctx
, set_unset_common(ctx
, line
, NULL
));
3624 static gint
set_command(assuan_context_t ctx
, gchar
*line
)
3626 gchar name
[64] = {0}, value
[256] = {0};
3628 log_write2("ARGS=\"%s\"", line
);
3630 if (sscanf(line
, " %63[_a-zA-Z] = %255c", name
, value
) != 2)
3631 return send_error(ctx
, gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
));
3633 return send_error(ctx
, set_unset_common(ctx
, name
, value
));
3636 static gint
rename_command(assuan_context_t ctx
, gchar
*line
)
3638 struct client_s
*client
= assuan_get_pointer(ctx
);
3640 gchar
**req
, **src
, *dst
;
3643 log_write2("ARGS=\"%s\"", line
);
3644 req
= split_input_line(line
, " ", -1);
3646 if (!req
|| !req
[0] || !req
[1]) {
3648 return send_error(ctx
, GPG_ERR_SYNTAX
);
3652 is_literal_element(&dst
);
3654 if (!valid_xml_element((xmlChar
*)dst
)) {
3656 return GPG_ERR_INV_VALUE
;
3659 if (strchr(req
[0], '\t'))
3660 src
= split_input_line(req
[0], "\t", -1);
3662 src
= split_input_line(req
[0], " ", -1);
3664 if (!src
|| !*src
) {
3665 rc
= GPG_ERR_SYNTAX
;
3669 n
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3672 n
= find_elements(client
->doc
, n
->children
, src
+1, &rc
, NULL
, NULL
,
3673 NULL
, FALSE
, 0, NULL
, FALSE
);
3679 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
3682 rc
= GPG_ERR_ENOMEM
;
3686 /* To prevent unwanted effects:
3688 * <root name="a"><b/></root>
3692 if (xmlStrEqual(a
, (xmlChar
*)dst
)) {
3694 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3704 for (p
= src
; *p
; p
++) {
3708 strv_printf(&tmp
, "%s", *p
);
3712 strv_printf(&tmp
, "!%s", dst
);
3713 ndst
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
3715 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3721 ndst
= find_elements(client
->doc
, ndst
->children
, tmp
+1, &rc
, NULL
,
3722 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3726 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3731 /* Target may exist:
3734 * <root name="b" target="a"/>
3742 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3748 xmlFreeNodeList(ndst
);
3751 rc
= add_attribute(n
, "_name", dst
);
3756 return send_error(ctx
, rc
);
3759 static gint
copy_command(assuan_context_t ctx
, gchar
*line
)
3761 struct client_s
*client
= assuan_get_pointer(ctx
);
3763 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3764 xmlNodePtr nsrc
, ndst
, new;
3766 log_write2("ARGS=\"%s\"", line
);
3767 req
= split_input_line(line
, " ", -1);
3769 if (!req
|| !req
[0] || !req
[1]) {
3771 return send_error(ctx
, GPG_ERR_SYNTAX
);
3774 if (strchr(req
[0], '\t'))
3775 src
= split_input_line(req
[0], "\t", -1);
3777 src
= split_input_line(req
[0], " ", -1);
3779 if (!src
|| !*src
) {
3780 rc
= GPG_ERR_SYNTAX
;
3784 if (strchr(req
[1], '\t'))
3785 dst
= split_input_line(req
[1], "\t", -1);
3787 dst
= split_input_line(req
[1], " ", -1);
3789 if (!dst
|| !*dst
) {
3790 rc
= GPG_ERR_SYNTAX
;
3794 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3797 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3798 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3803 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3806 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3807 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3809 if (!ndst
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3812 new = xmlCopyNodeList(nsrc
);
3815 rc
= GPG_ERR_ENOMEM
;
3820 ndst
= create_element_path(client
, &dst
, &rc
);
3824 xmlFreeNodeList(new);
3828 /* Merge any attributes from the src node to the initial dst node. */
3829 for (xmlAttrPtr attr
= new->properties
; attr
; attr
= attr
->next
) {
3830 if (xmlStrEqual(attr
->name
, (xmlChar
*)"_name"))
3833 xmlAttrPtr a
= xmlHasProp(ndst
, attr
->name
);
3838 xmlChar
*tmp
= xmlNodeGetContent(attr
->children
);
3839 xmlNewProp(ndst
, attr
->name
, tmp
);
3841 rc
= add_attribute(ndst
, NULL
, NULL
);
3844 xmlNodePtr n
= ndst
->children
;
3847 ndst
->children
= NULL
;
3849 if (!new->children
) {
3851 xmlFreeNodeList(new);
3855 n
= xmlCopyNodeList(new->children
);
3858 rc
= GPG_ERR_ENOMEM
;
3863 xmlFreeNodeList(new);
3864 n
= xmlAddChildList(ndst
, n
);
3867 rc
= GPG_ERR_ENOMEM
;
3871 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
) == ndst
->parent
? ndst
: ndst
->parent
);
3883 return send_error(ctx
, rc
);
3886 static gint
move_command(assuan_context_t ctx
, gchar
*line
)
3888 struct client_s
*client
= assuan_get_pointer(ctx
);
3890 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3891 xmlNodePtr nsrc
, ndst
= NULL
;
3893 log_write2("ARGS=\"%s\"", line
);
3894 req
= split_input_line(line
, " ", -1);
3896 if (!req
|| !req
[0] || !req
[1]) {
3898 return send_error(ctx
, GPG_ERR_SYNTAX
);
3901 if (strchr(req
[0], '\t'))
3902 src
= split_input_line(req
[0], "\t", -1);
3904 src
= split_input_line(req
[0], " ", -1);
3906 if (!src
|| !*src
) {
3907 rc
= GPG_ERR_SYNTAX
;
3911 if (strchr(req
[1], '\t'))
3912 dst
= split_input_line(req
[1], "\t", -1);
3914 dst
= split_input_line(req
[1], " ", -1);
3916 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3919 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3920 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3926 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3929 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3930 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3933 ndst
= xmlDocGetRootElement(client
->doc
);
3935 for (xmlNodePtr n
= ndst
; n
; n
= n
->parent
) {
3937 rc
= GPG_ERR_CONFLICT
;
3942 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3948 xmlChar
*a
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
3949 xmlNodePtr dup
= find_element(ndst
->children
, (gchar
*)a
, NULL
);
3957 if (ndst
== xmlDocGetRootElement(client
->doc
)) {
3958 xmlNodePtr n
= nsrc
;
3959 gboolean match
= FALSE
;
3961 while (n
->parent
&& n
->parent
!= ndst
)
3964 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
3965 xmlChar
*b
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
3967 if (xmlStrEqual(a
, b
)) {
3969 xmlUnlinkNode(nsrc
);
3979 xmlFreeNodeList(dup
);
3988 ndst
= create_element_path(client
, &dst
, &rc
);
3993 update_element_mtime(nsrc
->parent
);
3994 xmlUnlinkNode(nsrc
);
3995 ndst
= xmlAddChildList(ndst
, nsrc
);
3998 rc
= GPG_ERR_ENOMEM
;
4000 update_element_mtime(ndst
->parent
);
4012 return send_error(ctx
, rc
);
4015 static int ls_command(assuan_context_t ctx
, gchar
*line
)
4017 log_write2("ARGS=\"%s\"", line
);
4019 gchar
*tmp
= g_key_file_get_string(keyfileh
, "global", "data_directory", NULL
);
4020 gchar
*dir
= expand_homedir(tmp
);
4021 DIR *d
= opendir(dir
);
4023 rc
= gpg_error_from_syserror();
4028 return send_error(ctx
, rc
);
4031 size_t len
= offsetof(struct dirent
, d_name
)+pathconf(dir
, _PC_NAME_MAX
)+1;
4032 struct dirent
*p
= g_malloc(len
), *cur
= NULL
;
4038 while (!readdir_r(d
, p
, &cur
) && cur
) {
4039 if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '\0')
4041 else if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '.' && cur
->d_name
[2] == '\0')
4044 tmp
= g_strdup_printf("%s%s\n", list
? list
: "", cur
->d_name
);
4050 rc
= GPG_ERR_ENOMEM
;
4062 return send_error(ctx
, rc
);
4065 return send_error(ctx
, GPG_ERR_NO_VALUE
);
4067 list
[strlen(list
)-1] = 0;
4068 rc
= xfer_data(ctx
, list
, strlen(list
));
4070 return send_error(ctx
, rc
);
4073 static void bye_notify(assuan_context_t ctx
)
4075 struct client_s
*cl
= assuan_get_pointer(ctx
);
4077 /* This will let assuan_process_next() return. */
4078 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
4079 cl
->last_rc
= 0; // BYE command result
4082 static void reset_notify(assuan_context_t ctx
)
4084 struct client_s
*cl
= assuan_get_pointer(ctx
);
4091 * This is called before every Assuan command.
4093 gint
command_startup(assuan_context_t ctx
, const gchar
*name
)
4095 struct client_s
*cl
= assuan_get_pointer(ctx
);
4098 log_write1("%s", name
);
4100 if (!g_ascii_strcasecmp(name
, "ISCACHED") ||
4101 !g_ascii_strcasecmp(name
, "CLEARCACHE") ||
4102 !g_ascii_strcasecmp(name
, "CACHETIMEOUT") ||
4103 !g_ascii_strcasecmp(name
, "GETCONFIG") ||
4104 !g_ascii_strcasecmp(name
, "GETPID") ||
4105 !g_ascii_strcasecmp(name
, "VERSION") ||
4106 !g_ascii_strcasecmp(name
, "SET") ||
4107 !g_ascii_strcasecmp(name
, "BYE") ||
4108 !g_ascii_strcasecmp(name
, "NOP") ||
4109 !g_ascii_strcasecmp(name
, "CANCEL") ||
4110 !g_ascii_strcasecmp(name
, "RESET") ||
4111 !g_ascii_strcasecmp(name
, "END") ||
4112 !g_ascii_strcasecmp(name
, "HELP") ||
4113 !g_ascii_strcasecmp(name
, "OPTION") ||
4114 !g_ascii_strcasecmp(name
, "INPUT") ||
4115 !g_ascii_strcasecmp(name
, "OUTPUT") ||
4116 !g_ascii_strcasecmp(name
, "LS") ||
4117 !g_ascii_strcasecmp(name
, "UNSET"))
4120 #ifdef WITH_PINENTRY
4121 if (!(cl
->opts
& OPT_PINENTRY
))
4122 reset_pin_defaults(cl
->pinentry
);
4125 cl
->last_rc
= rc
= file_modified(cl
);
4128 if ((rc
== EPWMD_NO_FILE
|| rc
== EPWMD_FILE_MODIFIED
) &&
4129 !g_ascii_strcasecmp(name
, "OPEN"))
4137 * This is called after every Assuan command.
4139 void command_finalize(assuan_context_t ctx
, gint rc
)
4141 struct client_s
*client
= assuan_get_pointer(ctx
);
4143 if (!client
->is_lock_cmd
)
4144 unlock_file_mutex(client
);
4146 log_write1(N_("command completed (rc=%u)"), client
->last_rc
);
4147 client
->opts
&= ~(OPT_INQUIRE
);
4148 client
->opts
&= ~(OPT_BASE64
);
4151 static gint
help_command(assuan_context_t ctx
, gchar
*line
)
4156 if (!line
|| !*line
) {
4157 gchar
*buf
= g_strdup(N_("Usage: help [<COMMAND>]\nCOMMANDS:"));
4160 for (i
= 0; command_table
[i
]; i
++) {
4161 gchar
*p
= strrchr(buf
, '\n');
4162 gboolean newline
= FALSE
;
4164 if (p
&& strlen(p
)+strlen(command_table
[i
]->name
) > 79) {
4165 tmp
= g_strdup_printf("%s\n", buf
);
4171 tmp
= g_strdup_printf("%s%s%s", buf
, !newline
? " " : "",
4172 command_table
[i
]->name
);
4177 tmp
= g_strdup_printf("%s\n", buf
);
4180 rc
= xfer_data(ctx
, buf
, strlen(buf
));
4182 return send_error(ctx
, rc
);
4185 for (i
= 0; command_table
[i
]; i
++) {
4186 if (!g_strcasecmp(line
, command_table
[i
]->name
)) {
4187 gchar
*tmp
= g_strdup_printf(N_("Usage: %s"), command_table
[i
]->help
);
4188 rc
= xfer_data(ctx
, tmp
, strlen(tmp
));
4190 return send_error(ctx
, rc
);
4194 return send_error(ctx
, GPG_ERR_UNKNOWN_COMMAND
);
4197 void new_command(const gchar
*name
,
4198 gint (*handler
)(assuan_context_t
, gchar
*), const gchar
*help
)
4203 for (i
= 0; command_table
[i
]; i
++);
4205 command_table
= g_realloc(command_table
, (i
+2)*sizeof(struct command_table_s
*));
4206 command_table
[i
] = g_malloc0(sizeof(struct command_table_s
));
4207 command_table
[i
]->name
= name
;
4208 command_table
[i
]->handler
= handler
;
4209 command_table
[i
++]->help
= help
;
4210 command_table
[i
] = NULL
;
4213 void deinit_commands()
4217 for (i
= 0; command_table
[i
]; i
++)
4218 g_free(command_table
[i
]);
4220 g_free(command_table
);
4223 void init_commands()
4225 /* !BEGIN-HELP-TEXT!
4227 * This comment is used as a marker to generate the offline documentation
4228 * for commands found in doc/COMMANDS.
4230 new_command("HELP", help_command
, N_(
4231 "HELP [<COMMAND>]\n"
4232 " Show available commands or command specific help text.\n"
4235 new_command("OPEN", open_command
, N_(
4236 "OPEN [--lock] [--inquire | --pinentry=[0|1]] [--base64] <filename> [<key>]\n"
4237 " Opens <filename> using <key>. When the filename is not found on the\n"
4238 " file-system a new document will be created. If the file is found, it is\n"
4239 " looked for in the file cache for an existing key. When found and no key\n"
4240 " was specified, the cached key will be used for decryption (if encrypted).\n"
4241 " When not found, pinentry(1) will be used to retrieve the key (see the\n"
4242 " OPTIONS documentation).\n"
4244 " When the --lock option is passed then the file mutex will be locked as if\n"
4245 " the LOCK command had been sent after the file had been opened.\n"
4247 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4248 " retrieve the filename and key arguments.\n"
4250 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4251 " specifying the --pinentry option with the value 1 or 0 respectively. When\n"
4252 " no value is specified then the configuration file value will be used. If\n"
4253 " the passphrase is invalid then it is up to the client whether to retry or\n"
4254 " not. To decrypt an encrypted file with an empty passphrase and avoid the\n"
4255 " pinentry dialog, use --pinentry=0.\n"
4257 " When a \"key_file\" configuration parameter has been set for the current\n"
4258 " file and there is no cache entry, then an --inquire must be used to\n"
4259 " retrieve the key.\n"
4261 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4262 " decoded before doing decryption. This allows for binary keys and may also\n"
4263 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4266 new_command("SAVE", save_command
, N_(
4267 "SAVE [--reset] [--inquire | --pinentry=[0|1]] [--cipher=[<string>]]\n"
4268 " [--iterations=[N]] [--base64] [<key>]\n"
4269 " Writes the XML document to disk. The file written to is the file that was\n"
4270 " opened using the OPEN command. If <key> is not specified then the\n"
4271 " currently cached key will be used. If the file is a new file or the file\n"
4272 " isn't found in the file cache then <key> will be used. If both <key> is\n"
4273 " not specified and the file is not cached then pinentry(1) will be used to\n"
4274 " retrieve the key (see below) unless the configured number of iterations is\n"
4275 " 0 in which case the file will be saved unencrypted.\n"
4277 " Note that when both <key> is specified and the configured number of\n"
4278 " iterations is 0 the iterations for the current filename will be reset to\n"
4279 " 1. This is to be on the safe side and prevent misuse.\n"
4281 " The --iterations option can be used to change the number of encryption\n"
4282 " iterations for the opened file. When 0 no encryption will be performed.\n"
4283 " When this option is either not passed or is specified without a value then\n"
4284 " previous setting obtained from the file header will be used.\n"
4286 " You can specify an alternate cipher to encrypt with by specifying a cipher\n"
4287 " string with the --cipher option. Omitting the string uses the current\n"
4288 " cipher of the opened file or the default if the file is a new one. The\n"
4289 " default is specified in the configuration file. See pwmd(1) for available\n"
4292 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4293 " specifying the --pinentry option with the value 1 or 0, respectively. When\n"
4294 " no value is specified then the configuration file value will be used.\n"
4295 " When enabled and the passphrase confirmation fails, the pinentry process\n"
4296 " is started over again until either the passphrases match or until the\n"
4297 " input is canceled by the user. To save with encryption and with an empty\n"
4298 " passphrase, use --pinentry=0.\n"
4300 " When --reset is specified then the cached passphrase for the opened file\n"
4301 " will be cleared before doing the actual SAVE as if the CLEARCACHE command\n"
4304 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4305 " retrieve the key.\n"
4307 " When a \"key_file\" configuration parameter has been set for the current\n"
4308 " file and there is no cache entry, then an --inquire must be used to\n"
4309 " retrieve the key.\n"
4311 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4312 " decoded before doing encryption. This allows for binary keys and may also\n"
4313 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4316 new_command("ISCACHED", iscached_command
, N_(
4317 "ISCACHED <filename>\n"
4318 " An OK response is returned if the specified file is found in the file\n"
4319 " cache. If not found in the cache but exists on the filesystem,\n"
4320 " GPG_ERR_NOT_FOUND is returned. Otherwise a filesystem error is returned.\n"
4323 new_command("CLEARCACHE", clearcache_command
, N_(
4324 "CLEARCACHE [<filename>]\n"
4325 " Clears a file cache entry. This will forget the timeout and key for all or\n"
4326 " the specified file. Always returns an OK response.\n"
4329 new_command("CACHETIMEOUT", cachetimeout_command
, N_(
4330 "CACHETIMEOUT <filename> <seconds>\n"
4331 " Specify the number of seconds the specified file will be cached. -1 will\n"
4332 " keep the cache entry forever, 0 will require the key each time the OPEN or\n"
4333 " SAVE commands are used. Also see the \"cache_timeout\" configuration\n"
4334 " parameter. Returns ERR if the filename isn't cached or if the timeout is\n"
4335 " invalid. OK otherwise.\n"
4338 new_command("LIST", list_command
, N_(
4339 "LIST [--no-recurse] [--verbose] [[!]element[<TAB>[!]element[...]]]\n"
4340 " If no element path is given then a newline separated list of root elements\n"
4341 " is returned with the data response. If given, then all reachable elements\n"
4342 " for the specified element path are returned unless the --no-recurse option\n"
4343 " is specified. If specified, only the child elements of the element path\n"
4344 " are returned without recursing into grandchildren. Each element in the\n"
4345 " path is prefixed with the literal '!' character when the element contains\n"
4346 " no \"target\" attribute. Refer to THE TARGET ATTRIBUTE for more information.\n"
4348 " When the --verbose option is passed then each element path returned in the\n"
4349 " list will have a single space character followed by either a 0 or 1\n"
4350 " appended to it. When 0, the element path has no children, otherwise it\n"
4351 " does have children. When used with the --no-recurse option this may be\n"
4352 " useful to limit the amount of data transferred to the client.\n"
4355 new_command("REALPATH", realpath_command
, N_(
4356 "REALPATH [!]element[<TAB>[!]element[...]]\n"
4357 " Resolves all \"target\" attributes of the specified element path and returns\n"
4358 " the result with a data response.\n"
4361 new_command("STORE", store_command
, N_(
4362 "STORE [!]element[[<TAB>[!]element[...]]<TAB>[content]]\n"
4363 " Creates a new element tree or modifies the content of an existing element\n"
4364 " path. If only a single element is specified, a new root element is\n"
4365 " created. Otherwise, elements are TAB delimited and the content will be set\n"
4366 " to the last TAB delimited argument. If no content is specified after the\n"
4367 " last TAB then the content for the last specified element will be removed\n"
4368 " or empty when creating a new element.\n"
4370 " The only restriction of an element name is that it not contain whitespace\n"
4371 " or begin with the literal element character '!' unless specifying a\n"
4372 " literal element. There is no whitespace between the TAB delimited\n"
4373 " elements. It is recommended that the value or content be base 64 encoded\n"
4374 " when it contains control or TAB characters to prevent XML and pwmd parsing\n"
4377 " PWMD reads the element path from the client via the Assuan INQUIRE\n"
4378 " protocol response: the STORE command is sent by itself without arguments,\n"
4379 " then the server responds with INQUIRE. The client then sends the element\n"
4380 " path prefixed with a \"D \" data response. The element path may extend\n"
4381 " multiple lines but each must be prefixed with the data \"D \" response. When\n"
4382 " finished, the client sends \"END\" on an empty line. This is needed so an\n"
4383 " element path and value can be more than 1000 bytes long, the Assuan\n"
4384 " protocol line limit.\n"
4387 new_command("RENAME", rename_command
, N_(
4388 "RENAME [!]element[<TAB>[!]element[...]] <value>\n"
4389 " Renames the specified element to the new value. If an element of the same\n"
4390 " name as the value exists then it will be overwritten.\n"
4393 new_command("COPY", copy_command
, N_(
4394 "COPY [!]element[<TAB>[!]element[...]] [!]element[<TAB>[!]element[...]]\n"
4395 " Copies the entire element tree starting from the child node of the source\n"
4396 " element path, to the destination element path. If the destination element\n"
4397 " path doesn't exist then it is created; otherwise it is overwritten.\n"
4399 " Note that attributes from the source element path are merged into the\n"
4400 " destination element path when the destination element path exists. When an\n"
4401 " attribute of the same name exists in both the source and destination\n"
4402 " element paths then the destination attribute will be updated to the source\n"
4403 " attribute value.\n"
4406 new_command("MOVE", move_command
, N_(
4407 "MOVE [!]element[<TAB>[!]element[...]] [[!]element[<TAB>[!]element[...]]]\n"
4408 " Moves the source element path to the destination element path. If the\n"
4409 " destination is not specified then it will be moved to the root of the\n"
4410 " document. If the destination is specified and exists then it will be\n"
4411 " overwritten; otherwise it will be created.\n"
4414 new_command("DELETE", delete_command
, N_(
4415 "DELETE [!]element[<TAB>[!]element[...]]\n"
4416 " Removes the specified element path from the XML document.\n"
4419 new_command("GET", get_command
, N_(
4420 "GET [!]element[<TAB>[!]element[...]]\n"
4421 " Retrieves the content or XML text node of the specified element path. The\n"
4422 " data is returned with a data response.\n"
4425 new_command("ATTR", attr_command
, N_(
4426 "ATTR SET|GET|DELETE|LIST [<attribute>] [!]<arg1> [!][arg2]\n"
4427 " ATTR SET attribute [!]element[<TAB>[!]element[...]] [attribute_value]\n"
4428 " Stores or updates an attribute name and optional value of an element\n"
4431 " ATTR DELETE attribute [!]element[<TAB>[!]element[...]]\n"
4432 " Removes an attribute from an element path.\n"
4434 " ATTR LIST [!]element[<TAB>[!]element[...]]\n"
4435 " Gets a newline separated list of attributes from an element path.\n"
4437 " ATTR GET attribute [!]element[<TAB>[!]element[...]]\n"
4438 " Gets the value of an attribute from an element path.\n"
4440 " The \"_name\" attribute (case sensitive) cannot be removed with ATTR DELETE\n"
4441 " if the element path is the root element. Although it can be SET to change\n"
4442 " the element name but only if the destination element name doesn't exist.\n"
4443 " Use the RENAME command for that instead.\n"
4445 " There is another special attribute \"_mtime\" which is updated each time an\n"
4446 " element is modified: either by storing content, editing attributes or\n"
4447 " deleting a child element.\n"
4449 " Also see THE TARGET ATTRIBUTE.\n"
4452 new_command("XPATH", xpath_command
, N_(
4453 "XPATH <expression>[<TAB>[value]]\n"
4454 " Evaluates an XPath expression. If no value argument is specified, it is\n"
4455 " assumed the expression is a request to return a result. Otherwise, the\n"
4456 " result is set to the value argument and the document is updated. If there\n"
4457 " is no value after the <TAB> character, the value is assumed to be empty\n"
4458 " and the document is updated.\n"
4461 new_command("XPATHATTR", xpathattr_command
, N_(
4462 "XPATHATTR SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
4463 " Like the XPATH command but operates on element attributes and won't return\n"
4464 " a result. For the SET operation the <value> is optional but the field is\n"
4465 " required in which case the value will be empty.\n"
4468 new_command("IMPORT", import_command
, N_(
4469 "IMPORT <content>[<TAB>[!]element[<TAB>[!]element[...]]]\n"
4470 " Like the STORE command (an INQUIRE), but the content argument is raw XML\n"
4471 " data. The content is created as a child of the specified element path. If\n"
4472 " an element of the element path does not exist then it is created. If no\n"
4473 " element path is specified then the content must begin with an pwmd DTD\n"
4476 " Note that the new content must begin with an XML element node. Also note\n"
4477 " that an existing child node of the same element name as the root node of\n"
4478 " the imported content will be overwritten.\n"
4481 new_command("DUMP", dump_command
, N_(
4483 " Shows the in memory XML document with indenting. To dump a specific\n"
4484 " element tree, use the XPATH command.\n"
4487 new_command("LOCK", lock_command
, N_(
4489 " Locks the mutex associated with the opened file. This prevents other\n"
4490 " clients from sending commands to the same opened file until the client\n"
4491 " that sent this command either disconnects or sends the UNLOCK command.\n"
4494 new_command("UNLOCK", unlock_command
, N_(
4496 " Unlocks the file mutex which was locked with the LOCK command.\n"
4499 new_command("GETPID", getpid_command
, N_(
4501 " Retrieves the process id of the server.\n"
4504 new_command("GETCONFIG", getconfig_command
, N_(
4505 "GETCONFIG [filename] <parameter>\n"
4506 " Returns the value of a pwmd configuration variable with a data response.\n"
4507 " If no file has been opened then the value for the specified file or the\n"
4508 " default from the \"global\" section will be returned. If a file has been\n"
4509 " opened and no filename is specified, the value previously set with the SET\n"
4510 " command, if any, will be returned.\n"
4512 " If there is no such configuration parameter defined, GPG_ERR_NO_VALUE is\n"
4516 new_command("VERSION", version_command
, N_(
4518 " Returns the server version number with a data response.\n"
4521 new_command("SET", set_command
, N_(
4522 "SET <NAME>=<VALUE>\n"
4523 " Sets an option NAME to VALUE. Refer to the OPTIONS section for available\n"
4527 new_command("UNSET", unset_command
, N_(
4529 " Resets option NAME to the value specified in the server configuration\n"
4530 " file. Some options have no default and will be reset to NULL or 0\n"
4531 " depending on the type.\n"
4534 new_command("LS", ls_command
, N_(
4536 " Lists the contents of the configured data_directory. The result is a\n"
4537 " newline separated list of filenames.\n"
4539 /* !END-HELP-TEXT! */
4542 gpg_error_t
register_commands(assuan_context_t ctx
)
4546 for (; command_table
[i
]; i
++) {
4547 rc
= assuan_register_command (ctx
, command_table
[i
]->name
,
4548 command_table
[i
]->handler
);
4554 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
4559 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
4564 rc
= assuan_register_pre_cmd_notify(ctx
, command_startup
);
4569 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
4572 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
,
4573 struct crypto_s
*crypto
, gpointer
*dst
, goffset
*dst_len
)
4575 goffset insize
, len
;
4576 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
4577 guint64 iter
= 0ULL, n_iter
= 0ULL, iter_progress
= 0ULL;
4580 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->ver
.fh1
) : sizeof(crypto
->fh
->ver
.fh2
);
4581 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->ver
.fh1
.iter
: crypto
->fh
->ver
.fh2
.iter
;
4582 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
4584 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
4585 insize
= crypto
->fh
->st
.st_size
- fh_size
;
4586 crypto
->iv
= gcry_malloc(crypto
->blocksize
);
4589 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4590 return GPG_ERR_ENOMEM
;
4594 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh1
.iv
, crypto
->blocksize
);
4596 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
4598 crypto
->inbuf
= gcry_malloc(insize
);
4600 if (!crypto
->inbuf
) {
4601 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4602 return GPG_ERR_ENOMEM
;
4605 crypto
->insize
= insize
;
4606 len
= pth_read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
4608 if (len
!= crypto
->insize
)
4609 return GPG_ERR_INV_LENGTH
;
4611 /* No encryption iterations. This is a plain (gzipped) file. */
4612 if ((crypto
->fh
->v1
&& (long)fh_iter
< 0L) ||
4613 (!crypto
->fh
->v1
&& fh_iter
<= 0L)) {
4615 * cache_file_count() needs both .used == TRUE and a valid key in
4616 * order for it to count as a used cache entry. Fixes CACHE status
4619 memset(crypto
->key
, '!', hashlen
);
4623 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4624 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4628 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
4629 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4633 iter_progress
= (guint64
)get_key_file_double(client
&& client
->filename
?
4634 client
->filename
: "global", "iteration_progress");
4636 if (iter_progress
> 0ULL && fh_iter
>= iter_progress
) {
4637 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
4643 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4648 crypto
->tkey
= gcry_malloc(hashlen
);
4650 if (!crypto
->tkey
) {
4651 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4652 return GPG_ERR_ENOMEM
;
4655 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
4656 guchar
*tkey
= crypto
->tkey
;
4659 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
4660 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4664 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
4665 if (iter_progress
> 0ULL && iter
>= iter_progress
) {
4666 if (!(iter
% iter_progress
)) {
4667 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
4668 ++n_iter
* iter_progress
, fh_iter
);
4675 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4676 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4680 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4683 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4690 if (iter_progress
&& fh_iter
>= iter_progress
) {
4691 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
4698 if (!crypto
->fh
->v1
&& crypto
->fh
->ver
.fh2
.version
>= 0x218) {
4701 if (crypto
->fh
->ver
.fh2
.iter
> 0ULL) {
4702 if (memcmp(crypto
->inbuf
, crypto_magic
, sizeof(crypto_magic
)))
4703 return GPG_ERR_INV_PASSPHRASE
;
4705 len
= sizeof(crypto_magic
);
4708 rc
= do_decompress(ctx
, (guchar
*)crypto
->inbuf
+len
, crypto
->insize
-len
,
4709 (gpointer
*)&crypto
->outbuf
, &outsize
);
4715 rc
= do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
4716 (gpointer
*)&crypto
->outbuf
, &outsize
);
4718 if (rc
== GPG_ERR_ENOMEM
)
4721 return GPG_ERR_INV_PASSPHRASE
; // Not a valid gzip header. Must be a bad key.
4723 if (g_strncasecmp(crypto
->outbuf
, "<?xml ", 6) != 0) {
4724 gcry_free(crypto
->outbuf
);
4725 crypto
->outbuf
= NULL
;
4726 return GPG_ERR_INV_PASSPHRASE
;
4731 client
->xml
= crypto
->outbuf
;
4732 client
->len
= outsize
;
4733 crypto
->outbuf
= NULL
;
4736 *dst
= crypto
->outbuf
;
4738 crypto
->outbuf
= NULL
;
4741 /* The calling function should free the crypto struct. */