1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2011 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"
63 struct command_table_s
{
65 gint (*handler
)(assuan_context_t
, gchar
*line
);
67 gboolean ignore_startup
;
70 static struct command_table_s
**command_table
;
71 static guchar crypto_magic
[5] = "\177PWMD";
73 static gpg_error_t
do_lock_command(struct client_s
*client
);
75 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
77 return gcry_calloc(items
, size
);
80 static void z_free(void *data
, void *p
)
85 static gpg_error_t
file_modified(struct client_s
*client
)
90 if (client
->state
!= STATE_OPEN
)
93 rc
= lock_file_mutex(client
);
98 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
99 if (client
->mtime
!= st
.st_mtime
)
100 return EPWMD_FILE_MODIFIED
;
107 static gpg_error_t
parse_xml(assuan_context_t ctx
)
109 struct client_s
*client
= assuan_get_pointer(ctx
);
111 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
114 return EPWMD_LIBXML_ERROR
;
116 if (!client
->crypto
->fh
|| client
->crypto
->fh
->ver
.fh2
.version
>= 0x212)
119 return convert_elements(client
->doc
);
122 void unlock_file_mutex(struct client_s
*client
)
126 if (client
->has_lock
== FALSE
)
129 CACHE_LOCK(client
->ctx
);
131 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
138 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
141 gpg_error_t
lock_file_mutex(struct client_s
*client
)
146 if (client
->has_lock
== TRUE
)
149 CACHE_LOCK(client
->ctx
);
151 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
158 if (client
->rc_on_locked
) {
159 if (!pth_mutex_acquire(m
, TRUE
, NULL
))
160 return GPG_ERR_LOCKED
;
166 MUTEX_TRYLOCK(client
, m
, rc
);
169 client
->has_lock
= TRUE
;
174 void free_client(struct client_s
*client
)
177 xmlFreeDoc(client
->doc
);
180 gcry_free(client
->xml
);
182 if (client
->filename
)
183 g_free(client
->filename
);
186 cleanup_crypto(&client
->crypto
);
188 if (client
->xml_error
)
189 xmlResetError(client
->xml_error
);
192 void cleanup_client(struct client_s
*client
)
194 assuan_context_t ctx
= client
->ctx
;
195 struct client_thread_s
*thd
= client
->thd
;
196 gboolean rc_on_locked
= client
->rc_on_locked
;
197 gboolean lock_on_open
= client
->lock_on_open
;
199 struct pinentry_s
*pin
= client
->pinentry
;
202 unlock_file_mutex(client
);
203 CACHE_LOCK(client
->ctx
);
204 cache_decr_refcount(client
->md5file
);
207 * This may be a new file so don't use a cache slot. save_command() will
208 * set this to FALSE on success.
210 if (client
->new == TRUE
)
211 cache_clear(client
->md5file
, 1);
215 memset(client
, 0, sizeof(struct client_s
));
216 client
->state
= STATE_CONNECTED
;
219 client
->freed
= TRUE
;
221 client
->pinentry
= pin
;
223 client
->rc_on_locked
= rc_on_locked
;
224 client
->lock_on_open
= lock_on_open
;
227 static void gz_cleanup(void *arg
)
229 struct gz_s
**gz
= (struct gz_s
**)arg
;
234 if (!(*gz
)->done
&& (*gz
)->out
)
235 gcry_free((*gz
)->out
);
237 if ((*gz
)->which
== STATUS_COMPRESS
) {
239 deflateEnd(&(*gz
)->z
);
243 inflateEnd(&(*gz
)->z
);
250 gpg_error_t
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
251 gpointer
*out
, gulong
*outsize
)
259 gz
= g_malloc0(sizeof(struct gz_s
));
262 return GPG_ERR_ENOMEM
;
264 pth_cleanup_push(gz_cleanup
, &gz
);
265 gz
->which
= STATUS_DECOMPRESS
;
266 gz
->z
.zalloc
= z_alloc
;
267 gz
->z
.zfree
= z_free
;
269 gz
->z
.avail_in
= (uInt
)insize
;
270 gz
->z
.avail_out
= zlib_bufsize
;
271 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
274 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
276 return GPG_ERR_ENOMEM
;
279 zrc
= inflateInit2(&gz
->z
, 47);
282 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
284 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
287 memset(&h
, 0, sizeof(gz_header
));
288 h
.comment
= (guchar
*)buf
;
289 h
.comm_max
= sizeof(buf
);
290 zrc
= inflateGetHeader(&gz
->z
, &h
);
293 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
295 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
298 zrc
= inflate(&gz
->z
, Z_BLOCK
);
301 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
303 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
307 insize
= strtoul((gchar
*)h
.comment
, NULL
, 10);
312 zrc
= inflate(&gz
->z
, Z_FINISH
);
318 if (!gz
->z
.avail_out
) {
319 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
322 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
328 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
329 gz
->z
.avail_out
= zlib_bufsize
;
330 rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
331 gz
->z
.total_out
, insize
);
340 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
341 rc
= GPG_ERR_COMPR_ALGO
;
345 } while (zrc
!= Z_STREAM_END
);
347 rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
354 *outsize
= gz
->z
.total_out
;
364 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
369 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
376 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
377 *rc
= GPG_ERR_ENOMEM
;
381 pth_cleanup_push(g_free
, fh
);
382 fh_size
= v1
? sizeof(fh
->ver
.fh1
) : sizeof(fh
->ver
.fh2
);
384 if (lstat(filename
, &fh
->st
) == -1) {
385 *rc
= gpg_error_from_syserror();
390 if (!S_ISREG(fh
->st
.st_mode
)) {
391 *rc
= GPG_ERR_ENOANO
;
396 fd
= open(filename
, O_RDONLY
);
399 *rc
= gpg_error_from_syserror();
404 pth_cleanup_push(cleanup_fd_cb
, &fd
);
405 p
= v1
? (void *)&fh
->ver
.fh1
: (void *)&fh
->ver
.fh2
;
406 len
= pth_read(fd
, p
, fh_size
);
408 if (len
!= fh_size
) {
409 *rc
= gpg_error_from_syserror();
422 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*unused
,
425 struct client_s
*client
= assuan_get_pointer(ctx
);
428 guchar
*key
= client
->crypto
->key
;
431 if (!client
->crypto
->fh
) {
438 rc
= init_client_crypto2(client
->filename
, client
->crypto
);
441 cleanup_client(client
);
442 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
445 rc
= try_xml_decrypt(ctx
, client
->crypto
, NULL
, NULL
);
448 cleanup_client(client
);
449 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
453 CACHE_LOCK(client
->ctx
);
455 if (cached
== FALSE
) {
456 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
457 cleanup_client(client
);
459 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
462 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
463 cache_reset_timeout(client
->md5file
, timeout
);
466 cache_set_timeout(client
->md5file
, -2);
474 gcry_free(client
->xml
);
479 if (client
->new == FALSE
)
480 send_status_all(STATUS_CACHE
);
482 client
->state
= STATE_OPEN
;
485 if (!rc
&& client
->new == FALSE
&&
486 client
->crypto
->fh
->ver
.fh2
.iter
!= get_key_file_uint64(client
->filename
, "iterations")) {
487 gchar
*s
= g_strdup_printf("%llu", client
->crypto
->fh
->ver
.fh2
.iter
);
489 MUTEX_LOCK(&rcfile_mutex
);
490 g_key_file_set_value(keyfileh
, client
->filename
, "iterations", s
);
492 MUTEX_UNLOCK(&rcfile_mutex
);
493 send_status_all(STATUS_CONFIG
);
496 cleanup_crypto(&client
->crypto
);
498 if (!rc
&& client
->lock_on_open
)
499 return do_lock_command(client
);
501 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
504 static void req_cleanup(void *arg
)
509 g_strfreev((gchar
**)arg
);
512 static gpg_error_t
parse_open_opt_lock(gpointer data
, gpointer value
)
514 struct client_s
*client
= data
;
515 const gchar
*p
= value
;
521 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
523 client
->lock_on_open
= n
? TRUE
: FALSE
;
525 else if ((!p
|| !*p
) && (client
->opts
& OPT_LOCK
))
526 client
->lock_on_open
= FALSE
;
528 client
->lock_on_open
= TRUE
;
533 static gpg_error_t
parse_opt_pinentry(gpointer data
, gpointer value
)
536 struct client_s
*client
= data
;
542 client
->pinentry
->enable
= -1;
543 client
->opts
&= ~(OPT_PINENTRY
);
549 if (*p
|| n
< 0 || n
> 1)
550 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
552 client
->pinentry
->enable
= n
? TRUE
: FALSE
;
553 client
->opts
|= OPT_PINENTRY
;
556 return GPG_ERR_NOT_IMPLEMENTED
;
560 static gpg_error_t
parse_opt_inquire(gpointer data
, gpointer value
)
562 struct client_s
*client
= data
;
565 client
->opts
|= OPT_INQUIRE
;
569 static gpg_error_t
parse_opt_base64(gpointer data
, gpointer value
)
571 struct client_s
*client
= data
;
574 client
->opts
|= OPT_BASE64
;
578 static gpg_error_t
hash_key(struct client_s
*client
, const gchar
*key
)
583 if (client
->opts
& OPT_BASE64
)
584 tmp
= g_base64_decode(key
, &len
);
586 tmp
= (guchar
*)g_strdup(key
);
591 return GPG_ERR_ENOMEM
;
593 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, tmp
, len
);
598 static gpg_error_t
open_command_common(assuan_context_t ctx
, gchar
*line
)
600 gboolean cached
= FALSE
;
602 struct client_s
*client
= assuan_get_pointer(ctx
);
604 gchar
*filename
= NULL
;
605 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
607 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
610 pth_cleanup_push(req_cleanup
, req
);
612 if (!filename
|| !*filename
) {
614 return client
->opts
& OPT_INQUIRE
? GPG_ERR_SYNTAX
: send_error(ctx
, GPG_ERR_SYNTAX
);
617 log_write2("ARGS=\"%s\" %s", filename
, req
[1] ? "<passphrase>" : "");
619 if (valid_filename(filename
) == FALSE
) {
621 return client
->opts
& OPT_INQUIRE
? GPG_ERR_INV_VALUE
: send_error(ctx
, GPG_ERR_INV_VALUE
);
624 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
625 CACHE_LOCK(client
->ctx
);
627 if (cache_has_file(client
->md5file
) == FALSE
) {
628 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
631 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
636 rc
= lock_file_mutex(client
);
640 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
643 client
->freed
= FALSE
;
644 CACHE_LOCK(client
->ctx
);
645 cache_incr_refcount(client
->md5file
);
647 client
->crypto
= init_client_crypto();
649 if (!client
->crypto
) {
651 cleanup_client(client
);
652 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
655 client
->crypto
->key
= gcry_malloc(hashlen
);
657 if (!client
->crypto
->key
) {
659 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
661 cleanup_client(client
);
662 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
665 memset(client
->crypto
->key
, 0, hashlen
);
666 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
668 if (!client
->crypto
->fh
) {
669 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
670 log_write("%s: %s", filename
, pwmd_strerror(rc
));
672 cleanup_client(client
);
673 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
677 * New files don't need a key.
679 if ((client
->xml
= new_document()) == NULL
) {
680 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
682 cleanup_client(client
);
683 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
686 client
->len
= xmlStrlen(client
->xml
);
688 client
->filename
= g_strdup(filename
);
690 if (!client
->filename
) {
692 cleanup_client(client
);
693 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
694 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
697 if (req
[1] && *req
[1]) {
698 rc
= hash_key(client
, req
[1]);
702 cleanup_client(client
);
703 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
709 client
->pinentry
->filename
= g_strdup(client
->filename
);
711 if (!client
->pinentry
->filename
) {
712 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
713 cleanup_client(client
);
714 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
717 return open_command_finalize(ctx
, NULL
, cached
);
720 if (!(client
->opts
& OPT_CIPHER
))
721 g_key_file_set_string(keyfileh
, filename
, "cipher",
722 pwmd_cipher_to_str(client
->crypto
->fh
->ver
.fh2
.flags
));
724 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
727 client
->filename
= g_strdup(filename
);
729 if (!client
->filename
) {
730 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
732 cleanup_client(client
);
733 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
737 if (client
->pinentry
->filename
)
738 g_free(client
->pinentry
->filename
);
740 client
->pinentry
->filename
= g_strdup(client
->filename
);
742 if (!client
->pinentry
->filename
) {
743 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
745 cleanup_client(client
);
746 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
750 if (client
->crypto
->fh
->ver
.fh2
.iter
<= 0ULL)
753 CACHE_LOCK(client
->ctx
);
754 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
757 if (cached
== FALSE
) {
758 gchar
*tmp
= get_key_file_string(filename
, "key_file");
760 if (tmp
&& !(client
->opts
& OPT_INQUIRE
)) {
763 cleanup_client(client
);
764 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
771 * No key specified and no matching filename found in the cache. Use
772 * pinentry to retrieve the key. Cannot return assuan_process_done()
773 * here otherwise the command will be interrupted. The event loop in
774 * client_thread() will poll the file descriptor waiting for it to
775 * become ready to read a pinentry_key_s which will contain the
776 * entered key or an error code. It will then call
777 * open_command_finalize() to to finish the command.
779 if (!req
[1] || !*req
[1]) {
781 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
783 /* From set_pinentry_defaults(). */
784 if (client
->opts
& OPT_INQUIRE
||
785 client
->pinentry
->enable
== FALSE
||
786 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
787 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
792 rc
= lock_pin_mutex(client
);
795 unlock_pin_mutex(client
->pinentry
);
796 cleanup_client(client
);
797 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
800 client
->pinentry
->which
= PINENTRY_OPEN
;
801 rc
= pinentry_fork(ctx
);
804 unlock_pin_mutex(client
->pinentry
);
805 cleanup_client(client
);
806 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
809 // Called from pinentry iterate.
810 client
->pinentry
->cb
= open_command_finalize
;
811 client
->pinentry
->status
= PINENTRY_INIT
;
814 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
819 rc
= hash_key(client
, req
[1]);
823 cleanup_client(client
);
824 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
827 else if (req
&& req
[1] && *req
[1]) {
828 rc
= hash_key(client
, req
[1]);
832 cleanup_client(client
);
833 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
839 return open_command_finalize(ctx
, NULL
, cached
);
842 static gint
open_command_inquire_finalize(gpointer data
, gint assuan_rc
,
843 guchar
*line
, gsize len
)
845 assuan_context_t ctx
= data
;
846 struct client_s
*client
= assuan_get_pointer(ctx
);
847 gpg_error_t rc
= file_modified(client
);
849 if (assuan_rc
|| (rc
&& rc
!= EPWMD_NO_FILE
)) {
853 return assuan_rc
? assuan_rc
: rc
;
856 rc
= open_command_common(ctx
, (gchar
*)line
);
861 client
->inquire_status
= INQUIRE_DONE
;
865 static gint
open_command(assuan_context_t ctx
, gchar
*line
)
868 struct client_s
*client
= assuan_get_pointer(ctx
);
869 struct argv_s
*args
[] = {
870 &(struct argv_s
) { "lock", OPTION_TYPE_NOARG
, parse_open_opt_lock
},
871 &(struct argv_s
) { "pinentry", OPTION_TYPE_OPTARG
, parse_opt_pinentry
},
872 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
873 &(struct argv_s
) { "base64", OPTION_TYPE_NOARG
, parse_opt_base64
},
877 if (client
->state
== STATE_OPEN
)
878 cleanup_client(client
);
880 if (!(client
->opts
& OPT_LOCK
))
881 client
->lock_on_open
= FALSE
;
883 rc
= parse_options(&line
, args
, client
);
886 return send_error(ctx
, rc
);
888 if ((client
->opts
& OPT_INQUIRE
)) {
889 rc
= assuan_inquire_ext(ctx
, "OPEN", 0, open_command_inquire_finalize
,
893 return send_error(ctx
, rc
);
895 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
896 client
->inquire_status
= INQUIRE_BUSY
;
900 return open_command_common(ctx
, line
);
903 gpg_error_t
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
904 guint size
, gpointer
*out
, gulong
*outsize
)
909 gint cmd
= Z_NO_FLUSH
;
913 gz
= g_malloc0(sizeof(struct gz_s
));
916 return GPG_ERR_ENOMEM
;
918 pth_cleanup_push(gz_cleanup
, &gz
);
919 gz
->which
= STATUS_COMPRESS
;
920 gz
->z
.zalloc
= z_alloc
;
921 gz
->z
.zfree
= z_free
;
922 gz
->z
.next_in
= data
;
923 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
924 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
925 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
928 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
930 return GPG_ERR_ENOMEM
;
933 zrc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
936 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
938 return GPG_ERR_COMPR_ALGO
;
941 /* Rather than store the size of the uncompressed data in the file header,
942 * store it in the comment field of the gzip header. Don't give anyone too
943 * much information. Not sure why really, but it seems the right way. :)
945 memset(&h
, 0, sizeof(gz_header
));
946 g_snprintf(buf
, sizeof(buf
), "%u", size
);
947 h
.comment
= (guchar
*)buf
;
948 zrc
= deflateSetHeader(&gz
->z
, &h
);
951 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
953 return GPG_ERR_COMPR_ALGO
;
959 zrc
= deflate(&gz
->z
, cmd
);
965 if (!gz
->z
.avail_out
) {
966 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
969 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
975 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
976 gz
->z
.avail_out
= zlib_bufsize
;
979 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
980 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
981 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
983 gz
->z
.avail_in
= zlib_bufsize
;
985 rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u",
986 gz
->z
.total_in
, size
);
992 if (gz
->z
.total_in
>= size
)
999 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
1000 rc
= GPG_ERR_COMPR_ALGO
;
1003 } while (zrc
!= Z_STREAM_END
);
1005 rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u", gz
->z
.total_in
, size
);
1011 *outsize
= gz
->z
.total_out
;
1021 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1024 * Useful for a large amount of data. Rather than doing all of the data in one
1025 * iteration do it in chunks. This lets the command be cancelable rather than
1026 * waiting for it to complete.
1028 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
1029 struct crypto_s
*crypto
, status_msg_t which
)
1032 goffset len
= CRYPTO_BLOCKSIZE(crypto
);
1033 gpointer p
= gcry_malloc(len
);
1038 return GPG_ERR_ENOMEM
;
1040 if (crypto
->insize
< CRYPTO_BLOCKSIZE(crypto
))
1041 len
= crypto
->insize
;
1043 pth_cleanup_push(gcry_free
, p
);
1046 inbuf
= (guchar
*)crypto
->inbuf
+ total
;
1049 if (len
+ total
> crypto
->insize
)
1050 len
= crypto
->blocksize
;
1052 if (which
== STATUS_ENCRYPT
)
1053 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1055 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1060 tmp
= (guchar
*)crypto
->inbuf
+ total
;
1061 memmove(tmp
, p
, len
);
1064 if (total
>= crypto
->insize
)
1075 /* The crypto struct must be setup for iterations and .key. */
1076 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
1077 struct crypto_s
*crypto
, const gchar
*filename
)
1079 goffset len
= crypto
->insize
;
1083 guint64 iter_progress
= 0, n_iter
= 0, xiter
= 0;
1084 gchar tmp
[FILENAME_MAX
];
1087 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1089 if (!crypto
->fh
->ver
.fh2
.iter
) {
1091 * cache_file_count() needs both .used == TRUE and a valid key in
1092 * order for it to count as a used cache entry. Fixes CACHE status
1095 memset(crypto
->key
, '!', hashlen
);
1100 * Resize the existing xml buffer to the block size required by gcrypt
1101 * rather than duplicating it and wasting memory.
1103 crypto
->insize
+= sizeof(crypto_magic
);
1104 len
= (crypto
->insize
/ crypto
->blocksize
) * crypto
->blocksize
;
1106 if (crypto
->insize
% crypto
->blocksize
)
1107 len
+= crypto
->blocksize
;
1109 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
1112 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1113 return GPG_ERR_ENOMEM
;
1116 guchar
*tmpbuf
= inbuf
;
1117 memmove(&tmpbuf
[sizeof(crypto_magic
)], tmpbuf
, len
-sizeof(crypto_magic
));
1118 memcpy(tmpbuf
, crypto_magic
, sizeof(crypto_magic
));
1119 crypto
->inbuf
= tmpbuf
;
1120 crypto
->insize
= len
;
1121 gcry_create_nonce(crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
1124 gcry_free(crypto
->tkey
);
1126 crypto
->tkey
= gcry_malloc(hashlen
);
1128 if (!crypto
->tkey
) {
1129 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1130 return GPG_ERR_ENOMEM
;
1133 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
1134 guchar
*tkey
= crypto
->tkey
;
1137 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
1138 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1142 iter_progress
= get_key_file_uint64(
1143 client
? client
->filename
: "global", "iteration_progress");
1145 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1146 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1147 "0 %llu", crypto
->fh
->ver
.fh2
.iter
);
1153 while (xiter
< crypto
->fh
->ver
.fh2
.iter
-1) {
1154 if (iter_progress
> 0ULL && xiter
>= iter_progress
) {
1155 if (!(xiter
% iter_progress
)) {
1156 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1157 "%llu %llu", ++n_iter
* iter_progress
,
1158 crypto
->fh
->ver
.fh2
.iter
);
1165 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1166 crypto
->blocksize
))) {
1167 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1171 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1174 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1181 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1182 crypto
->blocksize
))) {
1183 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1187 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
1188 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1192 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1197 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1198 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1199 "%llu %llu", crypto
->fh
->ver
.fh2
.iter
, crypto
->fh
->ver
.fh2
.iter
);
1209 if (!client
&& !g_ascii_strcasecmp(filename
, "-")) {
1210 crypto
->fh
->fd
= STDOUT_FILENO
;
1214 if (lstat(filename
, &st
) == 0) {
1215 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1217 if (!(mode
& S_IWUSR
))
1218 return GPG_ERR_EACCES
;
1220 else if (errno
!= ENOENT
)
1221 return gpg_error_from_syserror();
1223 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1224 #if GLIB_CHECK_VERSION(2, 22, 0)
1225 crypto
->fh
->fd
= g_mkstemp_full(tmp
, O_WRONLY
, 0600);
1227 crypto
->fh
->fd
= mkstemp(tmp
);
1230 if (crypto
->fh
->fd
== -1) {
1231 rc
= gpg_error_from_syserror();
1232 p
= strrchr(tmp
, '/');
1234 log_write("%s: %s", p
, pwmd_strerror(rc
));
1238 pth_cleanup_push(cleanup_unlink_cb
, tmp
);
1242 * xml_import() or convert_file() from command line.
1244 crypto
->fh
->fd
= STDOUT_FILENO
;
1247 crypto
->fh
->ver
.fh2
.magic
[0] = '\177';
1248 crypto
->fh
->ver
.fh2
.magic
[1] = 'P';
1249 crypto
->fh
->ver
.fh2
.magic
[2] = 'W';
1250 crypto
->fh
->ver
.fh2
.magic
[3] = 'M';
1251 crypto
->fh
->ver
.fh2
.magic
[4] = 'D';
1252 crypto
->fh
->ver
.fh2
.version
= VERSION_HEX
;
1253 len
= pth_write(crypto
->fh
->fd
, &crypto
->fh
->ver
.fh2
, sizeof(crypto
->fh
->ver
.fh2
));
1255 if (len
!= sizeof(crypto
->fh
->ver
.fh2
)) {
1256 rc
= gpg_error_from_syserror();
1264 len
= pth_write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1266 if (len
!= crypto
->insize
) {
1267 rc
= gpg_error_from_syserror();
1275 if (fsync(crypto
->fh
->fd
) == -1) {
1276 rc
= gpg_error_from_syserror();
1288 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1289 gchar tmp2
[FILENAME_MAX
];
1291 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1293 acl
= acl_get_file(filename
, ACL_TYPE_ACCESS
);
1296 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1299 if (rename(filename
, tmp2
) == -1) {
1300 rc
= gpg_error_from_syserror();
1311 acl
= acl_get_file(".", ACL_TYPE_DEFAULT
);
1314 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1318 if (rename(tmp
, filename
) == -1) {
1319 rc
= gpg_error_from_syserror();
1331 chmod(filename
, mode
);
1334 if (acl
&& acl_set_file(filename
, ACL_TYPE_ACCESS
, acl
))
1335 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1342 if (client
&& lstat(filename
, &st
) == 0)
1343 client
->mtime
= st
.st_mtime
;
1348 gpg_error_t
update_save_flags(const gchar
*filename
,
1349 struct crypto_s
*crypto
)
1355 crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1358 return GPG_ERR_ENOMEM
;
1361 rc
= init_client_crypto2(filename
, crypto
);
1366 if (filename
&& !crypto
->fh
->v1
)
1367 crypto
->fh
->ver
.fh2
.iter
= get_key_file_uint64(filename
, "iterations");
1372 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1375 struct client_s
*client
= assuan_get_pointer(ctx
);
1384 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1385 gcry_free(client
->crypto
->key
);
1387 client
->crypto
->key
= key
;
1388 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
));
1391 cleanup_crypto(&client
->crypto
);
1392 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1395 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1396 pth_cleanup_push(xmlFree
, xmlbuf
);
1397 clevel
= get_key_file_integer(client
->filename
, "compression_level");
1402 rc
= do_compress(ctx
, clevel
, xmlbuf
, len
, &outbuf
, &outsize
);
1406 cleanup_crypto(&client
->crypto
);
1408 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1416 client
->crypto
->inbuf
= xmlbuf
;
1417 client
->crypto
->insize
= len
;
1418 rc
= update_save_flags(client
->filename
, client
->crypto
);
1421 cleanup_crypto(&client
->crypto
);
1422 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1423 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1426 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1429 cleanup_crypto(&client
->crypto
);
1430 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1433 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1434 CACHE_LOCK(client
->ctx
);
1437 cache_reset_timeout(client
->md5file
, timeout
);
1440 if (client
->new == TRUE
)
1441 send_status_all(STATUS_CACHE
);
1443 client
->new = FALSE
;
1444 cleanup_crypto(&client
->crypto
);
1445 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1448 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1450 cleanup_crypto(&client
->crypto
);
1451 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1454 client
->new = FALSE
;
1455 cache_reset_timeout(client
->md5file
, timeout
);
1457 send_status_all(STATUS_CACHE
);
1458 cleanup_crypto(&client
->crypto
);
1459 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1462 static gpg_error_t
parse_save_opt_iterations(gpointer data
, gpointer v
)
1464 struct client_s
*client
= data
;
1469 if (!client
->filename
)
1470 return EPWMD_NO_FILE
;
1472 if (!value
|| !*value
)
1476 n
= g_ascii_strtoull(value
, &p
, 10);
1478 if (errno
|| (p
&& *p
) || n
== G_MAXUINT64
)
1479 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_ERANGE
);
1481 MUTEX_LOCK(&rcfile_mutex
);
1482 p
= g_strdup_printf("%llu", n
);
1483 g_key_file_set_value(keyfileh
,
1484 client
->filename
? client
->filename
: "global", "iterations", p
);
1486 MUTEX_UNLOCK(&rcfile_mutex
);
1488 if (client
->filename
)
1489 client
->opts
|= OPT_ITERATIONS
;
1494 static gpg_error_t
parse_save_opt_cipher(gpointer data
, gpointer value
)
1496 struct client_s
*client
= data
;
1497 const gchar
*p
= value
;
1500 if (!client
->filename
)
1501 return EPWMD_NO_FILE
;
1506 flags
= pwmd_cipher_str_to_cipher(p
);
1509 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
1511 MUTEX_LOCK(&rcfile_mutex
);
1512 g_key_file_set_string(keyfileh
, client
->filename
, "cipher", p
);
1513 MUTEX_UNLOCK(&rcfile_mutex
);
1521 static gpg_error_t
parse_save_opt_reset(gpointer data
, gpointer value
)
1523 struct client_s
*client
= data
;
1525 CACHE_LOCK(client
->ctx
);
1526 cache_clear(client
->md5file
, 1);
1531 static gpg_error_t
save_command_common(assuan_context_t ctx
, gchar
*line
)
1533 struct client_s
*client
= assuan_get_pointer(ctx
);
1534 gboolean cached
= FALSE
;
1535 guint hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1538 cached
= cache_iscached(client
->md5file
);
1542 * If a cache entry doesn't exist for this file and the file has a
1543 * "key_file" or "key" parameter, then it's an error. The reason is that
1544 * cache expiration would be useless. Unless this is an inquire, then its
1547 if (cached
== FALSE
) {
1548 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1550 if (tmp
&& !(client
->opts
& OPT_INQUIRE
)) {
1552 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1562 if (!client
->crypto
) {
1563 client
->crypto
= init_client_crypto();
1565 if (!client
->crypto
) {
1566 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1567 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1571 client
->crypto
->key
= gcry_malloc(hashlen
);
1573 if (!client
->crypto
->key
) {
1574 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1575 cleanup_crypto(&client
->crypto
);
1576 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1579 memset(client
->crypto
->key
, '!', hashlen
);
1581 if (!get_key_file_uint64(client
->filename
, "iterations") &&
1585 if (!line
|| !*line
) {
1586 /* It doesn't make sense to use an --inquire with an empty
1587 * passphrase. This will prevent a pinentry dialog. */
1588 if (client
->opts
& OPT_INQUIRE
) {
1589 cleanup_crypto(&client
->crypto
);
1590 return GPG_ERR_WRONG_KEY_USAGE
;
1593 client
->crypto
->tkey
= gcry_malloc(hashlen
);
1595 if (!client
->crypto
->tkey
) {
1596 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1597 cleanup_crypto(&client
->crypto
);
1598 return send_error(ctx
, GPG_ERR_ENOMEM
);
1601 memset(client
->crypto
->tkey
, '!', hashlen
);
1604 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1605 !memcmp(client
->crypto
->key
, client
->crypto
->tkey
, hashlen
)) {
1608 #ifdef WITH_PINENTRY
1611 if (client
->pinentry
->enable
== FALSE
||
1612 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1613 /* Empty keys are allowed. */
1614 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1618 lock_pin_mutex(client
);
1619 client
->pinentry
->which
= PINENTRY_SAVE
;
1620 rc
= pinentry_fork(ctx
);
1623 unlock_pin_mutex(client
->pinentry
);
1624 cleanup_crypto(&client
->crypto
);
1625 return send_error(ctx
, rc
);
1628 client
->pinentry
->cb
= save_command_finalize
;
1629 client
->pinentry
->status
= PINENTRY_INIT
;
1632 /* Empty keys are allowed. */
1633 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1645 if (!get_key_file_uint64(client
->filename
, "iterations")) {
1646 guint64 iter
= get_key_file_uint64(NULL
, "iterations");
1650 iter
= 1; // default? what about the "global" section?
1652 MUTEX_LOCK(&rcfile_mutex
);
1653 p
= g_strdup_printf("%llu", iter
);
1654 g_key_file_set_value(keyfileh
, client
->filename
, "iterations", p
);
1656 MUTEX_UNLOCK(&rcfile_mutex
);
1657 client
->opts
|= OPT_ITERATIONS
;
1658 rc
= send_status(ctx
, STATUS_CONFIG
, NULL
);
1661 cleanup_crypto(&client
->crypto
);
1662 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1666 rc
= hash_key(client
, line
);
1669 cleanup_crypto(&client
->crypto
);
1670 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1675 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1678 static gint
save_command_inquire_finalize(gpointer data
, gint assuan_rc
,
1679 guchar
*line
, gsize len
)
1681 assuan_context_t ctx
= data
;
1682 struct client_s
*client
= assuan_get_pointer(ctx
);
1683 gpg_error_t rc
= file_modified(client
);
1685 if (assuan_rc
|| rc
) {
1689 return assuan_rc
? assuan_rc
: rc
;
1692 rc
= save_command_common(ctx
, (gchar
*)line
);
1697 client
->inquire_status
= INQUIRE_DONE
;
1701 static gint
save_command(assuan_context_t ctx
, gchar
*line
)
1704 struct client_s
*client
= assuan_get_pointer(ctx
);
1706 struct argv_s
*args
[] = {
1707 &(struct argv_s
) { "iterations", OPTION_TYPE_OPTARG
, parse_save_opt_iterations
},
1708 &(struct argv_s
) { "cipher", OPTION_TYPE_OPTARG
, parse_save_opt_cipher
},
1709 &(struct argv_s
) { "pinentry", OPTION_TYPE_OPTARG
, parse_opt_pinentry
},
1710 &(struct argv_s
) { "reset", OPTION_TYPE_NOARG
, parse_save_opt_reset
},
1711 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
1712 &(struct argv_s
) { "base64", OPTION_TYPE_NOARG
, parse_opt_base64
},
1716 rc
= parse_options(&line
, args
, client
);
1719 return send_error(ctx
, rc
);
1721 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1722 return send_error(ctx
, gpg_error_from_syserror());
1724 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1725 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1726 return send_error(ctx
, GPG_ERR_ENOANO
);
1729 if ((client
->opts
& OPT_INQUIRE
)) {
1730 rc
= assuan_inquire_ext(ctx
, "SAVE", 0, save_command_inquire_finalize
,
1734 return send_error(ctx
, rc
);
1736 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1737 client
->inquire_status
= INQUIRE_BUSY
;
1742 log_write2("ARGS=%s", "<passphrase>");
1744 return save_command_common(ctx
, line
);
1747 static gint
delete_command(assuan_context_t ctx
, gchar
*line
)
1749 struct client_s
*client
= assuan_get_pointer(ctx
);
1754 log_write2("ARGS=\"%s\"", line
);
1756 if (strchr(line
, '\t'))
1757 req
= split_input_line(line
, "\t", -1);
1759 req
= split_input_line(line
, " ", -1);
1762 return send_error(ctx
, GPG_ERR_SYNTAX
);
1764 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1768 return send_error(ctx
, rc
);
1772 * No sub-node defined. Remove the entire node (root element).
1776 rc
= unlink_node(n
);
1781 return send_error(ctx
, rc
);
1784 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1788 return send_error(ctx
, rc
);
1791 rc
= unlink_node(n
);
1795 return send_error(ctx
, rc
);
1799 * Don't return with assuan_process_done() here. This has been called from
1800 * assuan_process_next() and the command should be finished in
1803 static gint
store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1806 assuan_context_t ctx
= data
;
1807 struct client_s
*client
= assuan_get_pointer(ctx
);
1810 gpg_error_t rc
= file_modified(client
);
1812 if (assuan_rc
|| rc
) {
1815 return assuan_rc
? assuan_rc
: rc
;
1818 req
= split_input_line((gchar
*)line
, "\t", 0);
1822 return GPG_ERR_SYNTAX
;
1825 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1827 if (rc
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
1828 rc
= new_root_element(client
->doc
, *req
);
1845 n
= create_elements_cb(n
, req
+1, &rc
, NULL
);
1847 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1848 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
, FALSE
);
1852 client
->inquire_status
= INQUIRE_DONE
;
1855 rc
= update_element_mtime(n
);
1860 static gint
store_command(assuan_context_t ctx
, gchar
*line
)
1862 struct client_s
*client
= assuan_get_pointer(ctx
);
1865 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1868 return send_error(ctx
, rc
);
1870 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1871 client
->inquire_status
= INQUIRE_BUSY
;
1875 static void *send_data_cb(void *arg
)
1877 struct assuan_cmd_s
*data
= arg
;
1881 pth_cancel_state(PTH_CANCEL_ENABLE
|PTH_CANCEL_ASYNCHRONOUS
, &old
);
1882 rc
= g_malloc(sizeof(gpg_error_t
));
1883 *rc
= assuan_send_data(data
->ctx
, data
->line
, data
->line_len
);
1884 pth_cancel_state(old
, NULL
);
1889 /* For every assuan command that needs to be sent to the client, a timeout is
1890 * needed to determine if the client lost the connection. The timeout is the
1891 * same as the "keepalive" configuration parameter or a default if unset.
1893 gpg_error_t
do_assuan_command(assuan_context_t ctx
,
1894 void *(*cb
)(void *data
), void *data
)
1896 pth_attr_t attr
= pth_attr_new();
1898 gint to
= get_key_file_integer("global", "keepalive");
1899 pth_event_t ev
, tev
;
1904 pth_attr_init(attr
);
1905 pth_attr_set(attr
, PTH_ATTR_JOINABLE
, TRUE
);
1906 tid
= pth_spawn(attr
, cb
, data
);
1907 rc
= gpg_error_from_syserror();
1908 pth_attr_destroy(attr
);
1911 log_write("%s(%i): pth_spawn(): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1915 pth_cleanup_push(cleanup_cancel_cb
, tid
);
1916 to
= to
<= 0 ? DEFAULT_KEEPALIVE_TO
: to
;
1917 ev
= pth_event(PTH_EVENT_TID
|PTH_UNTIL_TID_DEAD
, tid
);
1918 tev
= to
? pth_event(PTH_EVENT_TIME
, pth_timeout(to
, 0)) : NULL
;
1919 ev
= pth_event_concat(ev
, tev
, NULL
);
1920 pth_cleanup_push(cleanup_ev_cb
, ev
);
1925 st
= pth_event_status(tev
);
1927 if (st
== PTH_STATUS_OCCURRED
) {
1930 return GPG_ERR_TIMEOUT
;
1934 st
= pth_event_status(ev
);
1936 if (st
== PTH_STATUS_FAILED
) {
1940 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1942 else if (st
== PTH_STATUS_OCCURRED
) {
1944 rc
= *(gpg_error_t
*)p
;
1953 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
1959 struct assuan_cmd_s data
;
1960 gint progress
= get_key_file_integer("global", "xfer_progress");
1963 progress
= progress
>0 ? (progress
/ASSUAN_LINELENGTH
)*ASSUAN_LINELENGTH
: 0;
1964 to_send
= total
< ASSUAN_LINELENGTH
? total
: ASSUAN_LINELENGTH
;
1966 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1973 if (sent
+ to_send
> total
)
1974 to_send
= total
- sent
;
1976 data
.line
= flush
? NULL
: (gchar
*)line
+sent
;
1977 data
.line_len
= flush
? 0 : to_send
;
1978 rc
= do_assuan_command(ctx
, send_data_cb
, &data
);
1981 sent
+= flush
? 0 : to_send
;
1983 if ((progress
&& !(sent
% progress
) && sent
!= total
) ||
1984 (sent
== total
&& flush
))
1985 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1987 if (!flush
&& !rc
&& sent
== total
) {
1992 } while (!rc
&& sent
< total
);
1997 static gint
get_command(assuan_context_t ctx
, gchar
*line
)
1999 struct client_s
*client
= assuan_get_pointer(ctx
);
2004 log_write2("ARGS=\"%s\"", line
);
2005 req
= split_input_line(line
, "\t", -1);
2007 if (!req
|| !*req
) {
2009 return send_error(ctx
, GPG_ERR_SYNTAX
);
2012 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
2016 return send_error(ctx
, rc
);
2020 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2025 return send_error(ctx
, rc
);
2027 if (!n
|| !n
->children
)
2028 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2030 n
= find_text_node(n
->children
);
2032 if (!n
|| !n
->content
|| !*n
->content
)
2033 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2035 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
2036 return send_error(ctx
, rc
);
2039 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
2040 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
2042 gchar
*path
= *(gchar
**)data
;
2043 gchar
*tmp
= NULL
, *result
;
2047 *(gchar
**)data
= NULL
;
2050 path
= g_strjoinv("\t", target
);
2053 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2054 *rc
= GPG_ERR_ENOMEM
;
2059 tmp
= g_strjoinv("\t", req_orig
);
2063 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2064 *rc
= GPG_ERR_ENOMEM
;
2070 result
= g_strdup_printf("%s\t%s", path
, tmp
);
2072 result
= g_strdup(path
);
2075 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2076 *rc
= GPG_ERR_ENOMEM
;
2084 *(gchar
**)data
= result
;
2088 static void list_command_cleanup1(void *arg
);
2089 static gint
realpath_command(assuan_context_t ctx
, gchar
*line
)
2092 struct client_s
*client
= assuan_get_pointer(ctx
);
2100 log_write2("ARGS=\"%s\"", line
);
2102 if (strchr(line
, '\t') != NULL
) {
2103 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
2104 return send_error(ctx
, GPG_ERR_SYNTAX
);
2107 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
2108 return send_error(ctx
, GPG_ERR_SYNTAX
);
2111 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
2115 return send_error(ctx
, rc
);
2118 rp
= g_strjoinv("\t", req
);
2122 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2123 return send_error(ctx
, GPG_ERR_ENOMEM
);
2127 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
2128 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
, FALSE
);
2133 return send_error(ctx
, rc
);
2137 string
= g_string_new(rp
);
2142 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2143 return send_error(ctx
, GPG_ERR_ENOMEM
);
2147 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
2148 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
2149 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
2154 pth_cleanup_push(list_command_cleanup1
, string
);
2155 rc
= xfer_data(ctx
, string
->str
, string
->len
);
2157 return send_error(ctx
, rc
);
2160 static void list_command_cleanup1(void *arg
)
2162 g_string_free((GString
*)arg
, TRUE
);
2165 static void list_command_cleanup2(void *arg
)
2167 struct element_list_s
*elements
= arg
;
2170 if (elements
->list
) {
2171 gint total
= g_slist_length(elements
->list
);
2174 for (i
= 0; i
< total
; i
++) {
2175 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
2179 g_slist_free(elements
->list
);
2182 if (elements
->prefix
)
2183 g_free(elements
->prefix
);
2186 g_strfreev(elements
->req
);
2192 static gpg_error_t
parse_list_opt_norecurse(gpointer data
, gpointer value
)
2194 struct element_list_s
*elements
= data
;
2196 elements
->recurse
= FALSE
;
2200 static gpg_error_t
parse_list_opt_verbose(gpointer data
, gpointer value
)
2202 struct element_list_s
*elements
= data
;
2204 elements
->verbose
= TRUE
;
2208 static gint
list_command(assuan_context_t ctx
, gchar
*line
)
2210 struct client_s
*client
= assuan_get_pointer(ctx
);
2212 struct element_list_s
*elements
= NULL
;
2214 struct argv_s
*args
[] = {
2215 &(struct argv_s
) { "no-recurse", OPTION_TYPE_NOARG
, parse_list_opt_norecurse
},
2216 &(struct argv_s
) { "verbose", OPTION_TYPE_NOARG
, parse_list_opt_verbose
},
2220 if (disable_list_and_dump
== TRUE
)
2221 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2223 elements
= g_malloc0(sizeof(struct element_list_s
));
2226 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2227 return GPG_ERR_ENOMEM
;
2230 elements
->recurse
= TRUE
; // default
2231 pth_cleanup_push(list_command_cleanup2
, elements
);
2232 rc
= parse_options(&line
, args
, elements
);
2240 rc
= list_root_elements(client
->doc
, &str
, elements
->verbose
);
2244 return send_error(ctx
, rc
);
2247 pth_cleanup_push(list_command_cleanup1
, str
);
2248 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2251 return send_error(ctx
, rc
);
2254 elements
->req
= split_input_line(line
, " ", 0);
2257 strv_printf(&elements
->req
, "%s", line
);
2259 rc
= create_path_list(client
->doc
, elements
, *elements
->req
);
2265 gint total
= g_slist_length(elements
->list
);
2270 rc
= GPG_ERR_NO_VALUE
;
2274 str
= g_string_new(NULL
);
2277 rc
= GPG_ERR_ENOMEM
;
2278 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2282 for (i
= 0; i
< total
; i
++) {
2283 tmp
= g_slist_nth_data(elements
->list
, i
);
2284 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
2287 pth_cleanup_push(list_command_cleanup1
, str
);
2288 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2292 rc
= GPG_ERR_NO_VALUE
;
2296 return send_error(ctx
, rc
);
2300 * req[0] - element path
2302 static gpg_error_t
attribute_list(assuan_context_t ctx
, gchar
**req
)
2304 struct client_s
*client
= assuan_get_pointer(ctx
);
2305 gchar
**attrlist
= NULL
;
2307 gchar
**path
= NULL
;
2313 if (!req
|| !req
[0])
2314 return GPG_ERR_SYNTAX
;
2316 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2318 * The first argument may be only a root element.
2320 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2321 return GPG_ERR_SYNTAX
;
2324 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2332 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2333 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2343 for (a
= n
->properties
; a
; a
= a
->next
) {
2346 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
2348 g_strfreev(attrlist
);
2350 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2351 return GPG_ERR_ENOMEM
;
2356 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
,
2357 an
&& an
->content
? (gchar
*)an
->content
: "");
2360 g_strfreev(attrlist
);
2361 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2362 return GPG_ERR_ENOMEM
;
2365 attrlist
[++i
] = NULL
;
2369 return GPG_ERR_NO_VALUE
;
2371 line
= g_strjoinv("\n", attrlist
);
2374 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2375 g_strfreev(attrlist
);
2376 return GPG_ERR_ENOMEM
;
2379 pth_cleanup_push(g_free
, line
);
2380 pth_cleanup_push(req_cleanup
, attrlist
);
2381 rc
= xfer_data(ctx
, line
, strlen(line
));
2388 * req[0] - attribute
2389 * req[1] - element path
2391 static gpg_error_t
attribute_delete(struct client_s
*client
, gchar
**req
)
2394 gchar
**path
= NULL
;
2397 if (!req
|| !req
[0] || !req
[1])
2398 return GPG_ERR_SYNTAX
;
2400 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2402 * The first argument may be only a root element.
2404 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2405 return GPG_ERR_SYNTAX
;
2409 * Don't remove the "_name" attribute for the root element. To remove an
2410 * root element use DELETE <name>.
2412 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"_name")) {
2413 rc
= GPG_ERR_SYNTAX
;
2417 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2423 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2424 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2430 rc
= delete_attribute(n
, (xmlChar
*)req
[0]);
2437 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
2440 gchar
**src
= *path
;
2441 gchar
**src_orig
= g_strdupv(src
);
2442 xmlNodePtr n
= NULL
;
2447 *rc
= GPG_ERR_ENOMEM
;
2448 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2453 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2456 if (*rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
2457 *rc
= new_root_element(client
->doc
, src
[0]);
2470 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
2472 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2473 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
, FALSE
);
2479 * Reset the position of the element tree now that the elements
2480 * have been created.
2485 n
= find_root_element(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2490 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2491 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2499 g_strfreev(src_orig
);
2506 * Creates a "target" attribute. When other commands encounter an element with
2507 * this attribute, the element path is modified to the target value. If the
2508 * source element path doesn't exist when using 'ATTR SET target', it is
2509 * created, but the destination element path must exist.
2511 * req[0] - source element path
2512 * req[1] - destination element path
2514 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2516 gchar
**src
, **dst
, *line
= NULL
, **odst
= NULL
;
2520 if (!req
|| !req
[0] || !req
[1])
2521 return GPG_ERR_SYNTAX
;
2523 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2525 * The first argument may be only a root element.
2527 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2528 return GPG_ERR_SYNTAX
;
2531 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2533 * The first argument may be only a root element.
2535 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2536 rc
= GPG_ERR_SYNTAX
;
2541 odst
= g_strdupv(dst
);
2544 rc
= GPG_ERR_ENOMEM
;
2548 n
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
2551 * Make sure the destination element path exists.
2557 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2558 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2564 n
= create_element_path(client
, &src
, &rc
);
2569 line
= g_strjoinv("\t", odst
);
2572 rc
= GPG_ERR_ENOMEM
;
2573 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2577 rc
= add_attribute(n
, "target", line
);
2591 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2597 tmp
= g_strdupv(req
);
2600 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2601 return GPG_ERR_ENOMEM
;
2604 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2610 if (g_utf8_collate(req
[0], req
[1]) == 0)
2614 * Will not overwrite an existing root.
2616 tmp
= g_strdupv(req
+1);
2619 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2620 return GPG_ERR_ENOMEM
;
2623 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2626 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
2630 return GPG_ERR_AMBIGUOUS_NAME
;
2632 if (!valid_xml_element((xmlChar
*)req
[1]))
2633 return GPG_ERR_SYNTAX
;
2635 tmp
= g_strdupv(req
);
2638 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2639 return GPG_ERR_ENOMEM
;
2642 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2646 return GPG_ERR_ELEMENT_NOT_FOUND
;
2648 return add_attribute(n
, "_name", req
[1]);
2652 * req[0] - attribute
2653 * req[1] - element path
2655 static gpg_error_t
attribute_get(assuan_context_t ctx
, gchar
**req
)
2657 struct client_s
*client
= assuan_get_pointer(ctx
);
2663 if (!req
|| !req
[0] || !req
[1])
2664 return GPG_ERR_SYNTAX
;
2666 if (strchr(req
[1], '\t')) {
2667 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2668 return GPG_ERR_SYNTAX
;
2671 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2672 return GPG_ERR_SYNTAX
;
2675 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2681 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2682 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2690 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2691 return GPG_ERR_NOT_FOUND
;
2693 pth_cleanup_push(xmlFree
, a
);
2696 rc
= xfer_data(ctx
, (gchar
*)a
, xmlStrlen(a
));
2698 rc
= GPG_ERR_NO_VALUE
;
2709 * req[0] - attribute
2710 * req[1] - element path
2713 static gpg_error_t
attribute_set(struct client_s
*client
, gchar
**req
)
2715 gchar
**path
= NULL
;
2719 if (!req
|| !req
[0] || !req
[1])
2720 return GPG_ERR_SYNTAX
;
2723 * Reserved attribute names.
2725 if (!strcmp(req
[0], "_name")) {
2727 * Only reserved for the root element. Not the rest of the
2730 if (strchr(req
[1], '\t') == NULL
)
2731 return name_attribute(client
, req
+ 1);
2733 else if (!strcmp(req
[0], "target"))
2734 return target_attribute(client
, req
+ 1);
2736 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2738 * The first argument may be only a root element.
2740 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2741 return GPG_ERR_SYNTAX
;
2744 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2750 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2751 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2757 rc
= add_attribute(n
, req
[0], req
[2]);
2766 * req[1] - attribute name or element path if command is LIST
2767 * req[2] - element path
2768 * req[2] - element path or value
2770 static gint
attr_command(assuan_context_t ctx
, gchar
*line
)
2772 struct client_s
*client
= assuan_get_pointer(ctx
);
2776 log_write2("ARGS=\"%s\"", line
);
2777 req
= split_input_line(line
, " ", 4);
2779 if (!req
|| !req
[0] || !req
[1]) {
2781 return send_error(ctx
, GPG_ERR_SYNTAX
);
2784 pth_cleanup_push(req_cleanup
, req
);
2786 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2787 rc
= attribute_set(client
, req
+1);
2788 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2789 rc
= attribute_get(ctx
, req
+1);
2790 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2791 rc
= attribute_delete(client
, req
+1);
2792 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2793 rc
= attribute_list(ctx
, req
+1);
2795 rc
= GPG_ERR_SYNTAX
;
2798 return send_error(ctx
, rc
);
2801 static gint
iscached_command(assuan_context_t ctx
, gchar
*line
)
2803 gchar
**req
= split_input_line(line
, " ", 0);
2807 if (!req
|| !*req
) {
2809 return send_error(ctx
, GPG_ERR_SYNTAX
);
2812 log_write2("ARGS=\"%s\"", line
);
2814 if (!valid_filename(req
[0])) {
2816 return GPG_ERR_INV_VALUE
;
2819 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2822 if (cache_iscached(md5file
)) {
2825 return send_error(ctx
, 0);
2829 tmp
= get_key_file_string("global", "data_directory");
2833 return GPG_ERR_ENOMEM
;
2836 path
= expand_homedir(tmp
);
2841 return GPG_ERR_ENOMEM
;
2846 path
= g_strdup_printf("%s/%s", tmp
, req
[0]);
2851 return GPG_ERR_ENOMEM
;
2854 if (access(path
, R_OK
) == -1) {
2855 gpg_error_t rc
= gpg_error_from_syserror();
2859 return send_error(ctx
, rc
);
2863 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2866 static gint
clearcache_command(assuan_context_t ctx
, gchar
*line
)
2868 gchar
**req
= split_input_line(line
, " ", 0);
2871 log_write2("ARGS=\"%s\"", line
);
2874 if (!req
|| !*req
) {
2876 cache_clear(NULL
, 2);
2878 return send_error(ctx
, 0);
2881 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2883 (void)cache_clear(md5file
, 1);
2885 return send_error(ctx
, 0);
2888 static gint
cachetimeout_command(assuan_context_t ctx
, gchar
*line
)
2892 gchar
**req
= split_input_line(line
, " ", 0);
2895 if (!req
|| !*req
|| !req
[1]) {
2897 return send_error(ctx
, GPG_ERR_SYNTAX
);
2901 timeout
= strtol(req
[1], &p
, 10);
2903 if (errno
!= 0 || *p
!= 0 || timeout
< -1) {
2905 return send_error(ctx
, GPG_ERR_SYNTAX
);
2908 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2909 CACHE_LOCK(client
->ctx
);
2911 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2913 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
2917 return send_error(ctx
, 0);
2920 static gint
dump_command(assuan_context_t ctx
, gchar
*line
)
2924 struct client_s
*client
= assuan_get_pointer(ctx
);
2927 if (disable_list_and_dump
== TRUE
)
2928 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2930 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2933 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2934 return send_error(ctx
, GPG_ERR_ENOMEM
);
2937 pth_cleanup_push(xmlFree
, xml
);
2938 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
2940 return send_error(ctx
, rc
);
2943 static gint
getconfig_command(assuan_context_t ctx
, gchar
*line
)
2945 struct client_s
*client
= assuan_get_pointer(ctx
);
2947 gchar filename
[255]={0}, param
[747]={0};
2948 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2950 log_write2("ARGS=\"%s\"", line
);
2952 if (!line
|| !*line
)
2953 return send_error(ctx
, GPG_ERR_SYNTAX
);
2955 if (strchr(line
, ' ')) {
2956 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2961 if (fp
&& !valid_filename(fp
))
2962 return send_error(ctx
, GPG_ERR_INV_VALUE
);
2964 paramp
= g_ascii_strdown(paramp
, -1);
2967 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2968 return send_error(ctx
, GPG_ERR_ENOMEM
);
2971 if (fp
&& !g_ascii_strcasecmp(paramp
, "iterations")) {
2972 if (!(client
->opts
& OPT_ITERATIONS
) || fp
!= client
->filename
) {
2973 file_header_internal_t
*fh
= read_file_header(fp
, FALSE
, &rc
);
2975 if (!fh
&& rc
!= GPG_ERR_ENOENT
)
2976 return send_error(ctx
, rc
);
2980 p
= g_strdup_printf("%llu", fh
->ver
.fh2
.iter
);
2981 close_file_header(fh
);
2984 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2985 pwmd_strerror(GPG_ERR_ENOMEM
));
2986 return send_error(ctx
, GPG_ERR_ENOMEM
);
2993 else if (!g_ascii_strcasecmp(paramp
, "enable_pinentry")) {
2994 #ifdef WITH_PINENTRY
2997 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY
))
2998 n
= client
->pinentry
->enable
;
3000 n
= get_key_file_boolean(fp
, "enable_pinentry");
3002 p
= g_strdup_printf("%s", n
? "true" : "false");
3005 log_write("%s(%i): %s", __FILE__
, __LINE__
,
3006 pwmd_strerror(GPG_ERR_ENOMEM
));
3007 return send_error(ctx
, GPG_ERR_ENOMEM
);
3012 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3015 else if (!g_ascii_strcasecmp(paramp
, "pinentry_timeout")) {
3016 #ifdef WITH_PINENTRY
3017 p
= g_strdup_printf("%i", get_key_file_integer(fp
, "pinentry_timeout"));
3020 log_write("%s(%i): %s", __FILE__
, __LINE__
,
3021 pwmd_strerror(GPG_ERR_ENOMEM
));
3022 return send_error(ctx
, GPG_ERR_ENOMEM
);
3027 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3031 p
= get_key_file_string(fp
? fp
: "global", paramp
);
3035 return send_error(ctx
, GPG_ERR_UNKNOWN_OPTION
);
3037 tmp
= expand_homedir(p
);
3041 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3042 return send_error(ctx
, GPG_ERR_ENOMEM
);
3047 pth_cleanup_push(g_free
, p
);
3048 rc
= xfer_data(ctx
, p
, strlen(p
));
3050 return send_error(ctx
, rc
);
3054 xmlXPathContextPtr xp
;
3055 xmlXPathObjectPtr result
;
3060 static void xpath_command_cleanup(void *arg
)
3062 struct xpath_s
*xpath
= arg
;
3064 req_cleanup(xpath
->req
);
3067 xmlBufferFree(xpath
->buf
);
3070 xmlXPathFreeObject(xpath
->result
);
3073 xmlXPathFreeContext(xpath
->xp
);
3076 static gint
xpath_command(assuan_context_t ctx
, gchar
*line
)
3078 struct client_s
*client
= assuan_get_pointer(ctx
);
3080 struct xpath_s xpath
;
3082 log_write2("ARGS=\"%s\"", line
);
3084 if (disable_list_and_dump
== TRUE
)
3085 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3087 if (!line
|| !*line
)
3088 return send_error(ctx
, GPG_ERR_SYNTAX
);
3090 memset(&xpath
, 0, sizeof(struct xpath_s
));
3092 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
3093 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
3094 return send_error(ctx
, GPG_ERR_ENOMEM
);
3097 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3100 xpath_command_cleanup(&xpath
);
3101 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3104 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3106 if (!xpath
.result
) {
3107 xpath_command_cleanup(&xpath
);
3108 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3111 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3112 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3116 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3117 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, 0, NULL
);
3121 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
3122 rc
= GPG_ERR_NO_VALUE
;
3125 else if (xpath
.req
[1])
3128 pth_cleanup_push(xpath_command_cleanup
, &xpath
);
3129 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
.buf
),
3130 xmlBufferLength(xpath
.buf
));
3134 xpath_command_cleanup(&xpath
);
3135 return send_error(ctx
, rc
);
3138 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3139 static gint
xpathattr_command(assuan_context_t ctx
, gchar
*line
)
3141 struct client_s
*client
= assuan_get_pointer(ctx
);
3143 struct xpath_s xpath
;
3145 gboolean cmd
= FALSE
; //SET
3147 log_write2("ARGS=\"%s\"", line
);
3149 if (disable_list_and_dump
== TRUE
)
3150 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3152 if (!line
|| !*line
)
3153 return send_error(ctx
, GPG_ERR_SYNTAX
);
3155 memset(&xpath
, 0, sizeof(struct xpath_s
));
3157 if ((req
= split_input_line(line
, " ", 3)) == NULL
)
3158 return send_error(ctx
, GPG_ERR_ENOMEM
);
3161 rc
= GPG_ERR_SYNTAX
;
3165 if (!g_ascii_strcasecmp(req
[0], "SET"))
3167 else if (!g_ascii_strcasecmp(req
[0], "DELETE"))
3170 rc
= GPG_ERR_SYNTAX
;
3174 if (!req
[1] || !req
[2]) {
3175 rc
= GPG_ERR_SYNTAX
;
3179 if ((xpath
.req
= split_input_line(req
[2], "\t", 3)) == NULL
) {
3180 rc
= GPG_ERR_ENOMEM
;
3184 if (!xpath
.req
[0] || (!xpath
.req
[1] && !cmd
) || (xpath
.req
[1] && cmd
)) {
3185 rc
= GPG_ERR_SYNTAX
;
3189 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3192 rc
= EPWMD_LIBXML_ERROR
;
3196 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3198 if (!xpath
.result
) {
3199 rc
= EPWMD_LIBXML_ERROR
;
3203 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3204 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3208 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3209 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, cmd
, (xmlChar
*)req
[1]);
3213 xpath_command_cleanup(&xpath
);
3214 return send_error(ctx
, rc
);
3217 static gint
import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
3220 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
3221 gpg_error_t rc
= file_modified(client
);
3222 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
3223 xmlDocPtr doc
= NULL
;
3224 xmlNodePtr n
, root
, copy
;
3226 if (assuan_rc
|| rc
) {
3229 return assuan_rc
? assuan_rc
: rc
;
3232 req
= split_input_line((gchar
*)line
, "\t", 2);
3236 return GPG_ERR_SYNTAX
;
3239 path
= split_input_line(req
[1], "\t", 0);
3241 if (!content
|| !*content
) {
3242 rc
= GPG_ERR_SYNTAX
;
3246 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
3249 rc
= EPWMD_LIBXML_ERROR
;
3253 root
= xmlDocGetRootElement(doc
);
3254 rc
= validate_import(root
);
3260 path_orig
= g_strdupv(path
);
3263 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3264 rc
= GPG_ERR_ENOMEM
;
3268 xmlChar
*a
= xmlGetProp(root
, (xmlChar
*)"_name");
3271 g_strfreev(path_orig
);
3272 rc
= GPG_ERR_ENOMEM
;
3276 if (strv_printf(&path
, "%s", (gchar
*)a
) == FALSE
) {
3278 g_strfreev(path_orig
);
3279 rc
= GPG_ERR_ENOMEM
;
3284 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
3286 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3287 g_strfreev(path_orig
);
3292 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, TRUE
);
3294 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3295 g_strfreev(path_orig
);
3299 xmlNodePtr parent
= n
->parent
;
3310 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
3311 n
= create_element_path(client
, &path
, &rc
);
3317 copy
= xmlCopyNodeList(root
);
3318 n
= xmlAddChildList(n
, copy
);
3321 rc
= EPWMD_LIBXML_ERROR
;
3324 /* Check if the content root element can create a DTD root element. */
3325 if (!xmlStrEqual((xmlChar
*)"element", root
->name
)) {
3326 rc
= GPG_ERR_SYNTAX
;
3332 if ((a
= xmlGetProp(root
, (xmlChar
*)"_name")) == NULL
) {
3333 rc
= GPG_ERR_SYNTAX
;
3337 gchar
*tmp
= g_strdup((gchar
*)a
);
3339 gboolean literal
= is_literal_element(&tmp
);
3341 if (!valid_xml_element((xmlChar
*)tmp
) || literal
) {
3343 rc
= GPG_ERR_INV_VALUE
;
3347 if (strv_printf(&path
, "%s", tmp
) == FALSE
) {
3349 rc
= GPG_ERR_ENOMEM
;
3354 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, TRUE
);
3356 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3357 rc
= EPWMD_LIBXML_ERROR
;
3361 /* Overwriting the existing tree. */
3368 xmlSetProp(root
, (xmlChar
*)"_name", (xmlChar
*)path
[0]);
3369 n
= xmlCopyNode(root
, 1);
3370 n
= xmlAddChildList(xmlDocGetRootElement(client
->doc
), n
);
3374 rc
= update_element_mtime(n
->parent
);
3384 client
->inquire_status
= INQUIRE_DONE
;
3388 static gint
import_command(assuan_context_t ctx
, gchar
*line
)
3391 struct client_s
*client
= assuan_get_pointer(ctx
);
3393 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
3396 return send_error(ctx
, rc
);
3398 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3399 client
->inquire_status
= INQUIRE_BUSY
;
3403 static gpg_error_t
do_lock_command(struct client_s
*client
)
3405 gpg_error_t rc
= lock_file_mutex(client
);
3408 client
->is_lock_cmd
= TRUE
;
3410 return client
->opts
& OPT_INQUIRE
? rc
: send_error(client
->ctx
, rc
);
3413 static gint
lock_command(assuan_context_t ctx
, gchar
*line
)
3415 struct client_s
*client
= assuan_get_pointer(ctx
);
3417 return do_lock_command(client
);
3420 static gint
unlock_command(assuan_context_t ctx
, gchar
*line
)
3422 struct client_s
*client
= assuan_get_pointer(ctx
);
3424 unlock_file_mutex(client
);
3425 return send_error(ctx
, 0);
3428 static gint
getpid_command(assuan_context_t ctx
, gchar
*line
)
3432 pid_t pid
= getpid();
3434 print_fmt(buf
, sizeof(buf
), "%i", pid
);
3435 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3436 return send_error(ctx
, rc
);
3439 static gint
version_command(assuan_context_t ctx
, gchar
*line
)
3444 buf
= g_strdup_printf("0x%X %s", VERSION_HEX
,
3445 #ifdef WITH_PINENTRY
3455 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3457 return send_error(ctx
, rc
);
3460 #ifdef WITH_PINENTRY
3461 static void set_option_value(gchar
**opt
, const gchar
*value
)
3469 *opt
= g_strdup(value
);
3473 static gint
set_unset_common(assuan_context_t ctx
, const gchar
*name
,
3476 struct client_s
*client
= assuan_get_pointer(ctx
);
3479 if (g_ascii_strcasecmp(name
, (gchar
*)"log_level") == 0) {
3486 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3489 MUTEX_LOCK(&rcfile_mutex
);
3490 g_key_file_set_integer(keyfileh
, "global", "log_level", n
);
3491 MUTEX_UNLOCK(&rcfile_mutex
);
3494 else if (g_ascii_strcasecmp(name
, (gchar
*)"rc_on_locked") == 0) {
3501 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3504 client
->rc_on_locked
= n
? TRUE
: FALSE
;
3507 else if (g_ascii_strcasecmp(name
, (gchar
*)"lock_on_open") == 0) {
3508 rc
= parse_open_opt_lock(client
, (gpointer
)value
);
3513 client
->opts
|= OPT_LOCK
;
3515 else if (g_ascii_strcasecmp(name
, (gchar
*)"cipher") == 0) {
3517 client
->opts
&= ~(OPT_CIPHER
);
3521 rc
= parse_save_opt_cipher(client
, (gpointer
)value
);
3526 client
->opts
|= OPT_CIPHER
;
3529 else if (g_ascii_strcasecmp(name
, (gchar
*)"iterations") == 0) {
3530 rc
= parse_save_opt_iterations(client
, (gpointer
)value
);
3537 else if (g_ascii_strcasecmp(name
, (gchar
*)"NAME") == 0) {
3538 pth_attr_t attr
= pth_attr_of(pth_self());
3542 pth_attr_destroy(attr
);
3546 print_fmt(buf
, sizeof(buf
), "%s", value
);
3547 pth_attr_set(attr
, PTH_ATTR_NAME
, buf
);
3548 pth_attr_destroy(attr
);
3549 #ifdef WITH_PINENTRY
3550 if (client
->pinentry
->name
)
3551 g_free(client
->pinentry
->name
);
3553 client
->pinentry
->name
= g_strdup(buf
);
3555 if (!client
->pinentry
->name
)
3556 return GPG_ERR_ENOMEM
;
3561 #ifdef WITH_PINENTRY
3562 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3563 set_option_value(&client
->pinentry
->lcmessages
, value
);
3564 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3565 set_option_value(&client
->pinentry
->lcctype
, value
);
3566 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3567 set_option_value(&client
->pinentry
->ttyname
, value
);
3568 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3569 set_option_value(&client
->pinentry
->ttytype
, value
);
3570 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3571 set_option_value(&client
->pinentry
->display
, value
);
3572 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3573 set_option_value(&client
->pinentry
->path
, value
);
3574 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3575 set_option_value(&client
->pinentry
->title
, value
);
3576 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3577 set_option_value(&client
->pinentry
->prompt
, value
);
3578 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3579 set_option_value(&client
->pinentry
->desc
, value
);
3580 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0) {
3590 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3592 MUTEX_LOCK(&rcfile_mutex
);
3593 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
:
3594 "global", "pinentry_timeout", n
);
3595 MUTEX_UNLOCK(&rcfile_mutex
);
3598 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0) {
3599 rc
= parse_opt_pinentry(client
, (gpointer
)value
);
3607 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3608 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3609 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3610 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3611 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3612 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3613 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3614 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3615 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3616 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3617 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3618 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3619 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3620 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3621 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3622 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3623 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3624 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3625 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0)
3626 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3627 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0)
3628 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3631 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
3637 static gint
unset_command(assuan_context_t ctx
, gchar
*line
)
3639 log_write2("ARGS=\"%s\"", line
);
3640 return send_error(ctx
, set_unset_common(ctx
, line
, NULL
));
3643 static gint
set_command(assuan_context_t ctx
, gchar
*line
)
3645 gchar name
[64] = {0}, value
[256] = {0};
3647 log_write2("ARGS=\"%s\"", line
);
3649 if (sscanf(line
, " %63[_a-zA-Z] = %255c", name
, value
) != 2)
3650 return send_error(ctx
, gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
));
3652 return send_error(ctx
, set_unset_common(ctx
, name
, value
));
3655 static gint
rename_command(assuan_context_t ctx
, gchar
*line
)
3657 struct client_s
*client
= assuan_get_pointer(ctx
);
3659 gchar
**req
, **src
, *dst
;
3662 log_write2("ARGS=\"%s\"", line
);
3663 req
= split_input_line(line
, " ", -1);
3665 if (!req
|| !req
[0] || !req
[1]) {
3667 return send_error(ctx
, GPG_ERR_SYNTAX
);
3671 is_literal_element(&dst
);
3673 if (!valid_xml_element((xmlChar
*)dst
)) {
3675 return GPG_ERR_INV_VALUE
;
3678 if (strchr(req
[0], '\t'))
3679 src
= split_input_line(req
[0], "\t", -1);
3681 src
= split_input_line(req
[0], " ", -1);
3683 if (!src
|| !*src
) {
3684 rc
= GPG_ERR_SYNTAX
;
3688 n
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3691 n
= find_elements(client
->doc
, n
->children
, src
+1, &rc
, NULL
, NULL
,
3692 NULL
, FALSE
, 0, NULL
, FALSE
);
3698 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
3701 rc
= GPG_ERR_ENOMEM
;
3705 /* To prevent unwanted effects:
3707 * <root name="a"><b/></root>
3711 if (xmlStrEqual(a
, (xmlChar
*)dst
)) {
3713 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3723 for (p
= src
; *p
; p
++) {
3727 strv_printf(&tmp
, "%s", *p
);
3731 strv_printf(&tmp
, "!%s", dst
);
3732 ndst
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
3734 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3740 ndst
= find_elements(client
->doc
, ndst
->children
, tmp
+1, &rc
, NULL
,
3741 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3745 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3750 /* Target may exist:
3753 * <root name="b" target="a"/>
3761 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3767 xmlFreeNodeList(ndst
);
3770 rc
= add_attribute(n
, "_name", dst
);
3775 return send_error(ctx
, rc
);
3778 static gint
copy_command(assuan_context_t ctx
, gchar
*line
)
3780 struct client_s
*client
= assuan_get_pointer(ctx
);
3782 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3783 xmlNodePtr nsrc
, ndst
, new;
3785 log_write2("ARGS=\"%s\"", line
);
3786 req
= split_input_line(line
, " ", -1);
3788 if (!req
|| !req
[0] || !req
[1]) {
3790 return send_error(ctx
, GPG_ERR_SYNTAX
);
3793 if (strchr(req
[0], '\t'))
3794 src
= split_input_line(req
[0], "\t", -1);
3796 src
= split_input_line(req
[0], " ", -1);
3798 if (!src
|| !*src
) {
3799 rc
= GPG_ERR_SYNTAX
;
3803 if (strchr(req
[1], '\t'))
3804 dst
= split_input_line(req
[1], "\t", -1);
3806 dst
= split_input_line(req
[1], " ", -1);
3808 if (!dst
|| !*dst
) {
3809 rc
= GPG_ERR_SYNTAX
;
3813 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3816 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3817 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3822 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3825 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3826 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3828 if (!ndst
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3831 new = xmlCopyNodeList(nsrc
);
3834 rc
= GPG_ERR_ENOMEM
;
3839 ndst
= create_element_path(client
, &dst
, &rc
);
3843 xmlFreeNodeList(new);
3847 /* Merge any attributes from the src node to the initial dst node. */
3848 for (xmlAttrPtr attr
= new->properties
; attr
; attr
= attr
->next
) {
3849 if (xmlStrEqual(attr
->name
, (xmlChar
*)"_name"))
3852 xmlAttrPtr a
= xmlHasProp(ndst
, attr
->name
);
3857 xmlChar
*tmp
= xmlNodeGetContent(attr
->children
);
3858 xmlNewProp(ndst
, attr
->name
, tmp
);
3860 rc
= add_attribute(ndst
, NULL
, NULL
);
3863 xmlNodePtr n
= ndst
->children
;
3866 ndst
->children
= NULL
;
3868 if (!new->children
) {
3870 xmlFreeNodeList(new);
3874 n
= xmlCopyNodeList(new->children
);
3877 rc
= GPG_ERR_ENOMEM
;
3882 xmlFreeNodeList(new);
3883 n
= xmlAddChildList(ndst
, n
);
3886 rc
= GPG_ERR_ENOMEM
;
3890 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
) == ndst
->parent
? ndst
: ndst
->parent
);
3902 return send_error(ctx
, rc
);
3905 static gint
move_command(assuan_context_t ctx
, gchar
*line
)
3907 struct client_s
*client
= assuan_get_pointer(ctx
);
3909 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3910 xmlNodePtr nsrc
, ndst
= NULL
;
3912 log_write2("ARGS=\"%s\"", line
);
3913 req
= split_input_line(line
, " ", -1);
3915 if (!req
|| !req
[0] || !req
[1]) {
3917 return send_error(ctx
, GPG_ERR_SYNTAX
);
3920 if (strchr(req
[0], '\t'))
3921 src
= split_input_line(req
[0], "\t", -1);
3923 src
= split_input_line(req
[0], " ", -1);
3925 if (!src
|| !*src
) {
3926 rc
= GPG_ERR_SYNTAX
;
3930 if (strchr(req
[1], '\t'))
3931 dst
= split_input_line(req
[1], "\t", -1);
3933 dst
= split_input_line(req
[1], " ", -1);
3935 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3938 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3939 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3945 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3948 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3949 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3952 ndst
= xmlDocGetRootElement(client
->doc
);
3954 for (xmlNodePtr n
= ndst
; n
; n
= n
->parent
) {
3956 rc
= GPG_ERR_CONFLICT
;
3961 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3967 xmlChar
*a
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
3968 xmlNodePtr dup
= find_element(ndst
->children
, (gchar
*)a
, NULL
);
3976 if (ndst
== xmlDocGetRootElement(client
->doc
)) {
3977 xmlNodePtr n
= nsrc
;
3978 gboolean match
= FALSE
;
3980 while (n
->parent
&& n
->parent
!= ndst
)
3983 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
3984 xmlChar
*b
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
3986 if (xmlStrEqual(a
, b
)) {
3988 xmlUnlinkNode(nsrc
);
3998 xmlFreeNodeList(dup
);
4007 ndst
= create_element_path(client
, &dst
, &rc
);
4012 update_element_mtime(nsrc
->parent
);
4013 xmlUnlinkNode(nsrc
);
4014 ndst
= xmlAddChildList(ndst
, nsrc
);
4017 rc
= GPG_ERR_ENOMEM
;
4019 update_element_mtime(ndst
->parent
);
4031 return send_error(ctx
, rc
);
4034 static int ls_command(assuan_context_t ctx
, gchar
*line
)
4036 log_write2("ARGS=\"%s\"", line
);
4038 gchar
*tmp
= g_key_file_get_string(keyfileh
, "global", "data_directory", NULL
);
4039 gchar
*dir
= expand_homedir(tmp
);
4040 DIR *d
= opendir(dir
);
4042 rc
= gpg_error_from_syserror();
4047 return send_error(ctx
, rc
);
4050 size_t len
= offsetof(struct dirent
, d_name
)+pathconf(dir
, _PC_NAME_MAX
)+1;
4051 struct dirent
*p
= g_malloc(len
), *cur
= NULL
;
4057 while (!readdir_r(d
, p
, &cur
) && cur
) {
4058 if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '\0')
4060 else if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '.' && cur
->d_name
[2] == '\0')
4063 tmp
= g_strdup_printf("%s%s\n", list
? list
: "", cur
->d_name
);
4069 rc
= GPG_ERR_ENOMEM
;
4081 return send_error(ctx
, rc
);
4084 return send_error(ctx
, GPG_ERR_NO_VALUE
);
4086 list
[strlen(list
)-1] = 0;
4087 rc
= xfer_data(ctx
, list
, strlen(list
));
4089 return send_error(ctx
, rc
);
4092 static void bye_notify(assuan_context_t ctx
)
4094 struct client_s
*cl
= assuan_get_pointer(ctx
);
4096 /* This will let assuan_process_next() return. */
4097 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
4098 cl
->last_rc
= 0; // BYE command result
4101 static void reset_notify(assuan_context_t ctx
)
4103 struct client_s
*cl
= assuan_get_pointer(ctx
);
4110 * This is called before every Assuan command.
4112 gint
command_startup(assuan_context_t ctx
, const gchar
*name
)
4114 struct client_s
*cl
= assuan_get_pointer(ctx
);
4117 log_write1("%s", name
);
4119 for (int i
= 0; command_table
[i
]; i
++) {
4120 if (!g_ascii_strcasecmp(name
, command_table
[i
]->name
) &&
4121 command_table
[i
]->ignore_startup
)
4125 #ifdef WITH_PINENTRY
4126 if (!(cl
->opts
& OPT_PINENTRY
))
4127 reset_pin_defaults(cl
->pinentry
);
4130 cl
->last_rc
= rc
= file_modified(cl
);
4133 if ((rc
== EPWMD_NO_FILE
|| rc
== EPWMD_FILE_MODIFIED
) &&
4134 !g_ascii_strcasecmp(name
, "OPEN"))
4142 * This is called after every Assuan command.
4144 void command_finalize(assuan_context_t ctx
, gint rc
)
4146 struct client_s
*client
= assuan_get_pointer(ctx
);
4148 if (!client
->is_lock_cmd
)
4149 unlock_file_mutex(client
);
4151 log_write1(N_("command completed (rc=%u)"), client
->last_rc
);
4152 client
->opts
&= ~(OPT_INQUIRE
);
4153 client
->opts
&= ~(OPT_BASE64
);
4156 static gint
help_command(assuan_context_t ctx
, gchar
*line
)
4161 if (!line
|| !*line
) {
4163 gchar
*buf
= g_strdup(N_(
4164 "Usage: HELP [<COMMAND>]\n"
4165 " For commands that take an element path as an argument, each element is\n"
4166 " separated with an ASCII tab character (ASCII 0x09).\n"
4168 " Each element may contain a \"target\" attribute whose value is also an\n"
4169 " element path. Think of a \"target\" attribute like a symbolic link on a\n"
4170 " filesystem. When found, the element path of the \"target\" attribute will\n"
4171 " be used as a prefix for further elements in the current element path. To\n"
4172 " ignore any \"target\" attribute for the current element, prefix the element\n"
4173 " with an ! (ASCII 0x21).\n"
4175 " See pwmd(1) for configuration file options which may also set default\n"
4176 " options for specific data files.\n"
4180 for (i
= 0; command_table
[i
]; i
++) {
4181 gchar
*p
= strrchr(buf
, '\n');
4182 gboolean newline
= FALSE
;
4184 if (!command_table
[i
]->help
)
4187 if (p
&& strlen(p
)+strlen(command_table
[i
]->name
) > 79) {
4188 tmp
= g_strdup_printf("%s\n", buf
);
4194 tmp
= g_strdup_printf("%s%s%s", buf
, !newline
? " " : "",
4195 command_table
[i
]->name
);
4200 tmp
= g_strdup_printf("%s\n", buf
);
4203 rc
= xfer_data(ctx
, buf
, strlen(buf
));
4205 return send_error(ctx
, rc
);
4208 for (i
= 0; command_table
[i
]; i
++) {
4209 if (!g_strcasecmp(line
, command_table
[i
]->name
)) {
4210 if (!command_table
[i
]->help
)
4213 gchar
*tmp
= g_strdup_printf(N_("Usage: %s"), command_table
[i
]->help
);
4214 rc
= xfer_data(ctx
, tmp
, strlen(tmp
));
4216 return send_error(ctx
, rc
);
4220 return send_error(ctx
, GPG_ERR_INV_NAME
);
4223 void new_command(const gchar
*name
, gboolean ignore
,
4224 gint (*handler
)(assuan_context_t
, gchar
*), const gchar
*help
)
4229 for (i
= 0; command_table
[i
]; i
++);
4231 command_table
= g_realloc(command_table
, (i
+2)*sizeof(struct command_table_s
*));
4232 command_table
[i
] = g_malloc0(sizeof(struct command_table_s
));
4233 command_table
[i
]->name
= name
;
4234 command_table
[i
]->handler
= handler
;
4235 command_table
[i
]->ignore_startup
= ignore
;
4236 command_table
[i
++]->help
= help
;
4237 command_table
[i
] = NULL
;
4240 void deinit_commands()
4244 for (i
= 0; command_table
[i
]; i
++)
4245 g_free(command_table
[i
]);
4247 g_free(command_table
);
4250 static gint
sort_commands(const void *arg1
, const void *arg2
)
4252 struct command_table_s
* const *a
= arg1
;
4253 struct command_table_s
* const *b
= arg2
;
4262 return strcmp((*a
)->name
, (*b
)->name
);
4265 void init_commands()
4267 /* !BEGIN-HELP-TEXT!
4269 * This comment is used as a marker to generate the offline documentation
4270 * for commands found in doc/COMMANDS.
4272 new_command("HELP", TRUE
, help_command
, N_(
4273 "HELP [<COMMAND>]\n"
4274 " Show available commands or command specific help text.\n"
4277 new_command("OPEN", FALSE
, open_command
, N_(
4278 "OPEN [--lock] [--inquire | --pinentry=[0|1]] [--base64] <filename> [<key>]\n"
4279 " Opens <filename> using <key>. When the filename is not found on the\n"
4280 " file-system a new document will be created. If the file is found, it is\n"
4281 " looked for in the file cache for an existing key. When found and no key\n"
4282 " was specified, the cached key will be used for decryption (if encrypted).\n"
4283 " When not found, pinentry(1) will be used to retrieve the key (see the\n"
4284 " OPTIONS documentation).\n"
4286 " When the --lock option is passed then the file mutex will be locked as if\n"
4287 " the LOCK command had been sent after the file had been opened.\n"
4289 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4290 " retrieve the filename and key arguments.\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. If\n"
4295 " the passphrase is invalid then it is up to the client whether to retry or\n"
4296 " not. To decrypt an encrypted file with an empty passphrase and avoid the\n"
4297 " pinentry dialog, use --pinentry=0.\n"
4299 " When a \"key_file\" configuration parameter has been set for the current\n"
4300 " file and there is no cache entry, then an --inquire must be used to\n"
4301 " retrieve the key.\n"
4303 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4304 " decoded before doing decryption. This allows for binary keys and may also\n"
4305 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4308 new_command("SAVE", FALSE
, save_command
, N_(
4309 "SAVE [--reset] [--inquire | --pinentry=[0|1]] [--cipher=[<string>]]\n"
4310 " [--iterations=[N]] [--base64] [<key>]\n"
4311 " Writes the XML document to disk. The file written to is the file that was\n"
4312 " opened using the OPEN command. If <key> is not specified then the\n"
4313 " currently cached key will be used. If the file is a new file or the file\n"
4314 " is not found in the file cache then <key> will be used. If both <key> is\n"
4315 " not specified and the file is not cached then pinentry(1) will be used to\n"
4316 " retrieve the key (see below) unless the configured number of iterations is\n"
4317 " 0 in which case the file will be saved unencrypted.\n"
4319 " Note that when both <key> is specified and the configured number of\n"
4320 " iterations is 0 the iterations for the current filename will be reset to\n"
4321 " 1. This is to be on the safe side and prevent misuse.\n"
4323 " The --iterations option can be used to change the number of encryption\n"
4324 " iterations for the opened file. When 0 no encryption will be performed.\n"
4325 " When this option is either not passed or is specified without a value then\n"
4326 " the previous setting obtained from the file header will be used.\n"
4328 " You can specify an alternate cipher to encrypt with by specifying a cipher\n"
4329 " string with the --cipher option. Omitting the string uses the current\n"
4330 " cipher of the opened file or the default if the file is a new one. The\n"
4331 " default is specified in the configuration file. See pwmd(1) for available\n"
4334 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4335 " specifying the --pinentry option with the value 1 or 0, respectively. When\n"
4336 " no value is specified then the configuration file value will be used.\n"
4337 " When enabled and the passphrase confirmation fails, the pinentry process\n"
4338 " is started over again until either the passphrases match or until the\n"
4339 " input is canceled by the user. To save with encryption and with an empty\n"
4340 " passphrase, use --pinentry=0.\n"
4342 " When --reset is specified then the cached passphrase for the opened file\n"
4343 " will be cleared before doing the actual SAVE as if the CLEARCACHE command\n"
4346 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4347 " retrieve the key.\n"
4349 " When a \"key_file\" configuration parameter has been set for the current\n"
4350 " file and there is no cache entry, then an --inquire must be used to\n"
4351 " retrieve the key.\n"
4353 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4354 " decoded before doing encryption. This allows for binary keys and may also\n"
4355 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4358 new_command("ISCACHED", TRUE
, iscached_command
, N_(
4359 "ISCACHED <filename>\n"
4360 " An OK response is returned if the specified file is found in the file\n"
4361 " cache. If not found in the cache but exists on the filesystem,\n"
4362 " GPG_ERR_NOT_FOUND is returned. Otherwise a filesystem error is returned.\n"
4365 new_command("CLEARCACHE", TRUE
, clearcache_command
, N_(
4366 "CLEARCACHE [<filename>]\n"
4367 " Clears a file cache entry. This will forget the timeout and key for all or\n"
4368 " the specified file. Always returns an OK response.\n"
4371 new_command("CACHETIMEOUT", TRUE
, cachetimeout_command
, N_(
4372 "CACHETIMEOUT <filename> <seconds>\n"
4373 " Specify the number of seconds the specified file will be cached. -1 will\n"
4374 " keep the cache entry forever, 0 will require the key each time the OPEN or\n"
4375 " SAVE commands are used. Also see the \"cache_timeout\" configuration\n"
4376 " parameter. Returns ERR if the filename is not cached or if the timeout is\n"
4377 " invalid. OK otherwise.\n"
4380 new_command("LIST", FALSE
, list_command
, N_(
4381 "LIST [--no-recurse] [--verbose] [[!]element[<TAB>[!]element[...]]]\n"
4382 " If no element path is given then a newline separated list of root elements\n"
4383 " is returned with the data response. If given, then all reachable elements\n"
4384 " for the specified element path are returned unless the --no-recurse option\n"
4385 " is specified. If specified, only the child elements of the element path\n"
4386 " are returned without recursing into grandchildren. Each element in the\n"
4387 " path is prefixed with the literal '!' character when the element contains\n"
4388 " no \"target\" attribute. Refer to THE TARGET ATTRIBUTE for more information.\n"
4390 " When the --verbose option is passed then each element path returned in the\n"
4391 " list will have a single space character followed by either a 0 or 1\n"
4392 " appended to it. When 0, the element path has no children, otherwise it\n"
4393 " does have children. When used with the --no-recurse option this may be\n"
4394 " useful to limit the amount of data transferred to the client.\n"
4397 new_command("REALPATH", FALSE
, realpath_command
, N_(
4398 "REALPATH [!]element[<TAB>[!]element[...]]\n"
4399 " Resolves all \"target\" attributes of the specified element path and returns\n"
4400 " the result with a data response.\n"
4403 new_command("STORE", FALSE
, store_command
, N_(
4404 "STORE [!]element[[<TAB>[!]element[...]]<TAB>[content]]\n"
4405 " Creates a new element path or modifies the content of an existing element\n"
4406 " path. If only a single element is specified, a new root element is\n"
4407 " created. Otherwise, elements are TAB delimited and the content will be set\n"
4408 " to the last TAB delimited argument. If no content is specified after the\n"
4409 " last TAB then the content for the last specified element will be removed,\n"
4410 " or empty when creating a new element.\n"
4412 " The only restriction of an element name is that it not contain whitespace\n"
4413 " or begin with the literal element character '!' unless specifying a\n"
4414 " literal element. There is no whitespace between the TAB delimited\n"
4415 " elements. It is recommended that the value or content be base 64 encoded\n"
4416 " when it contains control or TAB characters to prevent XML and pwmd parsing\n"
4419 " This command uses a server INQUIRE to retrieve the data from the client.\n"
4422 new_command("RENAME", FALSE
, rename_command
, N_(
4423 "RENAME [!]element[<TAB>[!]element[...]] <value>\n"
4424 " Renames the specified element to the new value. If an element of the same\n"
4425 " name as the value exists then it will be overwritten.\n"
4428 new_command("COPY", FALSE
, copy_command
, N_(
4429 "COPY [!]element[<TAB>[!]element[...]] [!]element[<TAB>[!]element[...]]\n"
4430 " Copies the entire element tree starting from the child node of the source\n"
4431 " element path, to the destination element path. If the destination element\n"
4432 " path does not exist then it will be created; otherwise it is overwritten.\n"
4434 " Note that attributes from the source element path are merged into the\n"
4435 " destination element path when the destination element path exists. When an\n"
4436 " attribute of the same name exists in both the source and destination\n"
4437 " element paths then the destination attribute will be updated to the source\n"
4438 " attribute value.\n"
4441 new_command("MOVE", FALSE
, move_command
, N_(
4442 "MOVE [!]element[<TAB>[!]element[...]] [[!]element[<TAB>[!]element[...]]]\n"
4443 " Moves the source element path to the destination element path. If the\n"
4444 " destination is not specified then it will be moved to the root of the\n"
4445 " document. If the destination is specified and exists then it will be\n"
4446 " overwritten; otherwise it will be created.\n"
4449 new_command("DELETE", FALSE
, delete_command
, N_(
4450 "DELETE [!]element[<TAB>[!]element[...]]\n"
4451 " Removes the specified element path and any children from the XML document.\n"
4454 new_command("GET", FALSE
, get_command
, N_(
4455 "GET [!]element[<TAB>[!]element[...]]\n"
4456 " Retrieves the content or XML text node of the specified element path. The\n"
4457 " content is returned with a data response.\n"
4460 new_command("ATTR", FALSE
, attr_command
, N_(
4461 "ATTR SET|GET|DELETE|LIST [<attribute>] [!]<arg1> [!][arg2]\n"
4462 " ATTR SET attribute [!]element[<TAB>[!]element[...]] [attribute_value]\n"
4463 " Stores or updates an attribute name and optional value of an element\n"
4466 " ATTR DELETE attribute [!]element[<TAB>[!]element[...]]\n"
4467 " Removes an attribute from an element path.\n"
4469 " ATTR LIST [!]element[<TAB>[!]element[...]]\n"
4470 " Retrieves a newline separated list of attributes names and values from\n"
4471 " the specified element path. The attribute names and values are space\n"
4474 " ATTR GET attribute [!]element[<TAB>[!]element[...]]\n"
4475 " Retrieves the value of an attribute from an element path.\n"
4477 " The \"_name\" attribute (case sensitive) cannot be removed with ATTR DELETE\n"
4478 " if the element path is the root element. Although it can be SET to change\n"
4479 " the element name but only if the destination element name doesn't exist.\n"
4480 " Use the RENAME command for that instead.\n"
4482 " The \"_mtime\" attribute is updated each time an element is modified by\n"
4483 " either storing content, editing attributes or by deleting a child element.\n"
4485 " Also see THE TARGET ATTRIBUTE.\n"
4488 new_command("XPATH", FALSE
, xpath_command
, N_(
4489 "XPATH <expression>[<TAB>[value]]\n"
4490 " Evaluates an XPath expression. If no value argument is specified, it is\n"
4491 " assumed the expression is a request to return a result. Otherwise, the\n"
4492 " result is set to the value argument and the document is updated. If there\n"
4493 " is no value after the <TAB> character, the value is assumed to be empty\n"
4494 " and the document is updated.\n"
4497 new_command("XPATHATTR", FALSE
, xpathattr_command
, N_(
4498 "XPATHATTR SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
4499 " Like the XPATH command but operates on element attributes and won't return\n"
4500 " a result. For the SET operation the <value> is optional but the field is\n"
4501 " required in which case the value will be empty.\n"
4504 new_command("IMPORT", FALSE
, import_command
, N_(
4505 "IMPORT <content>[<TAB>[!]element[<TAB>[!]element[...]]]\n"
4506 " Like the STORE command (an INQUIRE), but the content argument is raw XML\n"
4507 " data. The content is created as a child of the specified element path. If\n"
4508 " an element of the element path does not exist then it is created. If no\n"
4509 " element path is specified then the content must begin with an pwmd DTD\n"
4512 " Note that the new content must begin with an XML element node. Also note\n"
4513 " that an existing child node of the same element name as the root node of\n"
4514 " the imported content will be overwritten.\n"
4517 new_command("DUMP", FALSE
, dump_command
, N_(
4519 " Shows the in memory XML document with indenting. To dump a specific\n"
4520 " element tree, use the XPATH command.\n"
4523 new_command("LOCK", FALSE
, lock_command
, N_(
4525 " Locks the mutex associated with the opened file. This prevents other\n"
4526 " clients from sending commands to the same opened file until the client\n"
4527 " that sent this command either disconnects or sends the UNLOCK command.\n"
4530 new_command("UNLOCK", FALSE
, unlock_command
, N_(
4532 " Unlocks the file mutex which was locked with the LOCK command.\n"
4535 new_command("GETPID", TRUE
, getpid_command
, N_(
4537 " Retrieves the process id of the server.\n"
4540 new_command("GETCONFIG", TRUE
, getconfig_command
, N_(
4541 "GETCONFIG [filename] <parameter>\n"
4542 " Returns the value of a pwmd configuration variable with a data response.\n"
4543 " If no file has been opened then the value for the specified file or the\n"
4544 " default from the \"global\" section will be returned. If a file has been\n"
4545 " opened and no filename is specified, the value previously set with the SET\n"
4546 " command, if any, will be returned.\n"
4548 " If there is no such configuration parameter defined, GPG_ERR_UNKNOWN_OPTION\n"
4552 new_command("VERSION", TRUE
, version_command
, N_(
4554 " Returns the server version number and compile-time features with a data\n"
4555 " response with each being space delimited.\n"
4558 new_command("SET", TRUE
, set_command
, N_(
4559 "SET <NAME>=<VALUE>\n"
4560 " Sets a client option NAME to VALUE. Use the UNSET command to reset an\n"
4561 " option to its default value.\n"
4563 " NAME |VALUE |Description\n"
4564 " -----------------|----------|----------------------------------------------\n"
4565 " ENABLE_PINENTRY 0|1 When 0, disable use of pinentry. The default\n"
4568 " * Deprecated. Pass --pinentry to the OPEN and\n"
4569 " SAVE commands instead.\n"
4571 " PINENTRY_TIMEOUT <integer> The number of seconds before the pinentry\n"
4572 " process will terminate while waiting for a\n"
4573 " passphrase. The default is 20, 0 disables.\n"
4575 " PINENTRTY_PATH <string> Full path to the pinentry binary. The default\n"
4576 " is specified at compile time.\n"
4578 " TTYNAME <string> Same as the --ttyname option to pinentry(1).\n"
4580 " TTYTYPE <string> Same as the --ttytype option to pinentry(1).\n"
4582 " DISPLAY <string> Same as the --display option to pinentry(1).\n"
4584 " TITLE <string> Sets the title string of the pinentry dialog.\n"
4586 " PROMPT <string> Sets the prompt string of the pinentry dialog.\n"
4588 " DESC <string> Sets the error or description string of the\n"
4589 " pinentry dialog.\n"
4591 " LC_CTYPE <string> Same as the --lc-ctype option to pinentry(1).\n"
4593 " LC_MESSAGES <string> Same as the --lc-messages option to\n"
4596 " NAME <string> Associates the thread ID of the connection\n"
4597 " with the specified textual representation.\n"
4598 " Useful for debugging log messages.\n"
4600 " CIPHER <string> The cipher to use for the next SAVE.\n"
4602 " * Deprecated. Use --cipher instead.\n"
4604 " ITERATIONS <integer> The number of encryption iterations to do\n"
4605 " when the SAVE command is sent. An opened file\n"
4606 " is needed when setting this option. The\n"
4607 " CONFIG status message is sent after receiving\n"
4610 " * Deprecated. Use --iterations instead.\n"
4612 " LOCK_ON_OPEN 0|1 If enabled then the file mutex will be locked\n"
4613 " after a successful OPEN as if the LOCK\n"
4614 " command had been sent.\n"
4616 " * Deprecated. Use --lock instead.\n"
4618 " RC_ON_LOCKED 0|1 If enabled then return an error code instead\n"
4619 " of a status message when the file mutex is\n"
4620 " locked by another client.\n"
4623 new_command("UNSET", TRUE
, unset_command
, N_(
4625 " Resets option NAME to the value specified in the server configuration\n"
4626 " file. Some options have no default and will be reset to NULL or 0\n"
4627 " depending on the value type. See the SET command for available options.\n"
4630 new_command("LS", TRUE
, ls_command
, N_(
4632 " Lists the contents of the configured data_directory. The result is a\n"
4633 " newline separated list of filenames.\n"
4636 new_command("RESET", TRUE
, NULL
, N_(
4638 " Closes the currently opened file but keeps any previously set client\n"
4642 new_command("BYE", TRUE
, NULL
, N_(
4644 " Closes the connection discarding any unsaved changes.\n"
4647 new_command("NOP", TRUE
, NULL
, N_(
4649 " Does nothing. Always returns successfully.\n"
4652 /* !END-HELP-TEXT! */
4653 new_command("CANCEL", TRUE
, NULL
, NULL
);
4654 new_command("END", TRUE
, NULL
, NULL
);
4657 for (i
= 0; command_table
[i
]; i
++);
4658 qsort(command_table
, i
-1, sizeof(struct command_table_s
*), sort_commands
);
4661 gpg_error_t
register_commands(assuan_context_t ctx
)
4665 for (; command_table
[i
]; i
++) {
4666 if (!command_table
[i
]->handler
)
4669 rc
= assuan_register_command (ctx
, command_table
[i
]->name
,
4670 command_table
[i
]->handler
);
4676 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
4681 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
4686 rc
= assuan_register_pre_cmd_notify(ctx
, command_startup
);
4691 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
4694 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
,
4695 struct crypto_s
*crypto
, gpointer
*dst
, goffset
*dst_len
)
4697 goffset insize
, len
;
4698 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
4699 guint64 iter
= 0, n_iter
= 0, iter_progress
= 0;
4702 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->ver
.fh1
) : sizeof(crypto
->fh
->ver
.fh2
);
4703 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->ver
.fh1
.iter
: crypto
->fh
->ver
.fh2
.iter
;
4704 gsize hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
4706 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
4707 insize
= crypto
->fh
->st
.st_size
- fh_size
;
4708 crypto
->iv
= gcry_malloc(crypto
->blocksize
);
4711 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4712 return GPG_ERR_ENOMEM
;
4716 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh1
.iv
, crypto
->blocksize
);
4718 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
4720 crypto
->inbuf
= gcry_malloc(insize
);
4722 if (!crypto
->inbuf
) {
4723 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4724 return GPG_ERR_ENOMEM
;
4727 crypto
->insize
= insize
;
4728 len
= pth_read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
4730 if (len
!= crypto
->insize
)
4731 return GPG_ERR_INV_LENGTH
;
4733 /* No encryption iterations. This is a plain (gzipped) file. */
4734 if ((crypto
->fh
->v1
&& (long)fh_iter
< 0L) ||
4735 (!crypto
->fh
->v1
&& fh_iter
<= 0L)) {
4737 * cache_file_count() needs both .used == TRUE and a valid key in
4738 * order for it to count as a used cache entry. Fixes CACHE status
4741 memset(crypto
->key
, '!', hashlen
);
4745 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4746 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4750 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
4751 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4755 iter_progress
= get_key_file_uint64(client
&& client
->filename
?
4756 client
->filename
: "global", "iteration_progress");
4758 if (iter_progress
> 0 && fh_iter
>= iter_progress
) {
4759 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
4765 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4770 crypto
->tkey
= gcry_malloc(hashlen
);
4772 if (!crypto
->tkey
) {
4773 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4774 return GPG_ERR_ENOMEM
;
4777 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
4778 guchar
*tkey
= crypto
->tkey
;
4781 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
4782 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4786 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
4787 if (iter_progress
> 0ULL && iter
>= iter_progress
) {
4788 if (!(iter
% iter_progress
)) {
4789 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
4790 ++n_iter
* iter_progress
, fh_iter
);
4797 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4798 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4802 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4805 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4812 if (iter_progress
&& fh_iter
>= iter_progress
) {
4813 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
4820 if (!crypto
->fh
->v1
&& crypto
->fh
->ver
.fh2
.version
>= 0x218) {
4823 if (crypto
->fh
->ver
.fh2
.iter
> 0ULL) {
4824 if (memcmp(crypto
->inbuf
, crypto_magic
, sizeof(crypto_magic
)))
4825 return GPG_ERR_INV_PASSPHRASE
;
4827 len
= sizeof(crypto_magic
);
4830 rc
= do_decompress(ctx
, (guchar
*)crypto
->inbuf
+len
, crypto
->insize
-len
,
4831 (gpointer
*)&crypto
->outbuf
, &outsize
);
4837 rc
= do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
4838 (gpointer
*)&crypto
->outbuf
, &outsize
);
4840 if (rc
== GPG_ERR_ENOMEM
)
4843 return GPG_ERR_INV_PASSPHRASE
; // Not a valid gzip header. Must be a bad key.
4845 if (g_strncasecmp(crypto
->outbuf
, "<?xml ", 6) != 0) {
4846 gcry_free(crypto
->outbuf
);
4847 crypto
->outbuf
= NULL
;
4848 return GPG_ERR_INV_PASSPHRASE
;
4853 client
->xml
= crypto
->outbuf
;
4854 client
->len
= outsize
;
4855 crypto
->outbuf
= NULL
;
4858 *dst
= crypto
->outbuf
;
4860 crypto
->outbuf
= NULL
;
4863 /* The calling function should free the crypto struct. */