1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 Ben Kibbey <bjk@luxsci.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
29 #include <sys/types.h>
34 #include <glib/gstdio.h>
51 #include "pwmd_error.h"
65 struct command_table_s
{
67 gint (*handler
)(assuan_context_t
, gchar
*line
);
69 gboolean ignore_startup
;
72 static struct command_table_s
**command_table
;
73 static guchar crypto_magic
[5] = "\177PWMD";
75 static gpg_error_t
do_lock_command(struct client_s
*client
);
77 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
79 return gcry_calloc(items
, size
);
82 static void z_free(void *data
, void *p
)
87 static gpg_error_t
file_modified(struct client_s
*client
)
92 if (client
->state
!= STATE_OPEN
)
95 rc
= lock_file_mutex(client
);
100 if (g_lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
101 if (client
->mtime
!= st
.st_mtime
)
102 return EPWMD_FILE_MODIFIED
;
109 static gpg_error_t
parse_xml(assuan_context_t ctx
)
111 struct client_s
*client
= assuan_get_pointer(ctx
);
113 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
116 return EPWMD_LIBXML_ERROR
;
118 if (!client
->crypto
->fh
|| client
->crypto
->fh
->ver
.fh2
.version
>= 0x212)
121 return convert_elements(client
->doc
);
124 void unlock_file_mutex(struct client_s
*client
)
128 if (client
->has_lock
== FALSE
)
131 CACHE_LOCK(client
->ctx
);
133 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
140 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
143 gpg_error_t
lock_file_mutex(struct client_s
*client
)
148 if (client
->has_lock
== TRUE
)
151 CACHE_LOCK(client
->ctx
);
153 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
160 if (client
->rc_on_locked
) {
161 if (!pth_mutex_acquire(m
, TRUE
, NULL
))
162 return GPG_ERR_LOCKED
;
168 MUTEX_TRYLOCK(client
, m
, rc
);
171 client
->has_lock
= TRUE
;
176 void free_client(struct client_s
*client
)
179 xmlFreeDoc(client
->doc
);
182 gcry_free(client
->xml
);
184 if (client
->filename
)
185 g_free(client
->filename
);
188 cleanup_crypto(&client
->crypto
);
190 if (client
->xml_error
)
191 xmlResetError(client
->xml_error
);
194 void cleanup_client(struct client_s
*client
)
196 assuan_context_t ctx
= client
->ctx
;
197 struct client_thread_s
*thd
= client
->thd
;
198 gboolean rc_on_locked
= client
->rc_on_locked
;
199 gboolean lock_on_open
= client
->lock_on_open
;
201 struct pinentry_s
*pin
= client
->pinentry
;
204 unlock_file_mutex(client
);
205 CACHE_LOCK(client
->ctx
);
206 cache_decr_refcount(client
->md5file
);
209 * This may be a new file so don't use a cache slot. save_command() will
210 * set this to FALSE on success.
212 if (client
->new == TRUE
)
213 cache_clear(client
->md5file
, 1);
217 memset(client
, 0, sizeof(struct client_s
));
218 client
->state
= STATE_CONNECTED
;
221 client
->freed
= TRUE
;
223 client
->pinentry
= pin
;
225 client
->rc_on_locked
= rc_on_locked
;
226 client
->lock_on_open
= lock_on_open
;
229 static void gz_cleanup(void *arg
)
231 struct gz_s
**gz
= (struct gz_s
**)arg
;
236 if (!(*gz
)->done
&& (*gz
)->out
)
237 gcry_free((*gz
)->out
);
239 if ((*gz
)->which
== STATUS_COMPRESS
) {
241 deflateEnd(&(*gz
)->z
);
245 inflateEnd(&(*gz
)->z
);
252 gpg_error_t
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
253 gpointer
*out
, gulong
*outsize
)
261 gz
= g_malloc0(sizeof(struct gz_s
));
264 return GPG_ERR_ENOMEM
;
266 pth_cleanup_push(gz_cleanup
, &gz
);
267 gz
->which
= STATUS_DECOMPRESS
;
268 gz
->z
.zalloc
= z_alloc
;
269 gz
->z
.zfree
= z_free
;
271 gz
->z
.avail_in
= (uInt
)insize
;
272 gz
->z
.avail_out
= zlib_bufsize
;
273 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
276 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
278 return GPG_ERR_ENOMEM
;
281 zrc
= inflateInit2(&gz
->z
, 47);
284 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
286 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
289 memset(&h
, 0, sizeof(gz_header
));
290 h
.comment
= (guchar
*)buf
;
291 h
.comm_max
= sizeof(buf
);
292 zrc
= inflateGetHeader(&gz
->z
, &h
);
295 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
297 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
300 zrc
= inflate(&gz
->z
, Z_BLOCK
);
303 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
305 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
309 insize
= strtoul((gchar
*)h
.comment
, NULL
, 10);
314 zrc
= inflate(&gz
->z
, Z_FINISH
);
320 if (!gz
->z
.avail_out
) {
321 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
324 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
330 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
331 gz
->z
.avail_out
= zlib_bufsize
;
332 rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
333 gz
->z
.total_out
, insize
);
342 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
343 rc
= GPG_ERR_COMPR_ALGO
;
347 } while (zrc
!= Z_STREAM_END
);
349 rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
356 *outsize
= gz
->z
.total_out
;
366 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
371 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
378 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
379 *rc
= GPG_ERR_ENOMEM
;
383 pth_cleanup_push(g_free
, fh
);
384 fh_size
= v1
? sizeof(fh
->ver
.fh1
) : sizeof(fh
->ver
.fh2
)-8; // salt
386 if (g_lstat(filename
, &fh
->st
) == -1) {
387 *rc
= gpg_error_from_syserror();
392 if (!S_ISREG(fh
->st
.st_mode
)) {
393 *rc
= GPG_ERR_ENOANO
;
398 fd
= open(filename
, O_RDONLY
);
401 *rc
= gpg_error_from_syserror();
406 pth_cleanup_push(cleanup_fd_cb
, &fd
);
407 p
= v1
? (void *)&fh
->ver
.fh1
: (void *)&fh
->ver
.fh2
;
408 len
= pth_read(fd
, p
, fh_size
);
410 if (len
!= fh_size
) {
411 *rc
= gpg_error_from_syserror();
418 if (fh
->ver
.fh2
.version
>= 0x221) {
419 len
= pth_read(fd
, fh
->ver
.fh2
.salt
, sizeof(fh
->ver
.fh2
.salt
));
420 if (len
!= sizeof(fh
->ver
.fh2
.salt
)) {
421 *rc
= gpg_error_from_syserror();
436 gpg_error_t
hash_key(struct crypto_s
*crypto
, const guchar
*key
,
437 gsize keylen
, gboolean kdf
)
441 if (crypto
->key
!= key
) {
442 gcry_free(crypto
->key
);
443 crypto
->key
= gcry_malloc(KEYSIZE
);
445 return GPG_ERR_ENOMEM
;
448 if (!kdf
&& crypto
->fh
->ver
.fh2
.version
< 0x221) {
449 gcry_md_hash_buffer(GCRY_MD_SHA256
, crypto
->key
, key
, keylen
);
452 rc
= gcry_kdf_derive(key
, keylen
, GCRY_KDF_ITERSALTED_S2K
, GCRY_MD_SHA1
,
453 crypto
->fh
->ver
.fh2
.salt
, 8, 1000, KEYSIZE
, crypto
->key
);
459 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*key
,
460 gsize len
, gboolean cached
)
462 struct client_s
*client
= assuan_get_pointer(ctx
);
466 if (!client
->new && len
) {
467 rc
= hash_key(client
->crypto
, key
, len
, FALSE
);
469 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
473 if (!client
->crypto
->fh
) {
474 guchar
*tkey
= client
->crypto
->key
;
476 for (gsize i
= 0; i
< client
->crypto
->keysize
; i
++) {
484 rc
= init_client_crypto2(client
->filename
, client
->crypto
);
487 cleanup_client(client
);
488 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
491 rc
= try_xml_decrypt(ctx
, client
->crypto
, NULL
, NULL
);
494 cleanup_client(client
);
495 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
499 key
= client
->crypto
->key
;
500 CACHE_LOCK(client
->ctx
);
502 if (cached
== FALSE
) {
503 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
504 cleanup_client(client
);
506 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
509 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
510 cache_reset_timeout(client
->md5file
, timeout
);
513 cache_set_timeout(client
->md5file
, -2);
521 gcry_free(client
->xml
);
526 if (client
->new == FALSE
)
527 send_status_all(STATUS_CACHE
);
529 client
->state
= STATE_OPEN
;
532 if (!rc
&& client
->new == FALSE
&&
533 client
->crypto
->fh
->ver
.fh2
.iter
!= get_key_file_uint64(client
->filename
, "iterations")) {
534 gchar
*s
= g_strdup_printf("%llu", (unsigned long long)client
->crypto
->fh
->ver
.fh2
.iter
);
536 MUTEX_LOCK(&rcfile_mutex
);
537 g_key_file_set_value(keyfileh
, client
->filename
, "iterations", s
);
539 MUTEX_UNLOCK(&rcfile_mutex
);
540 send_status_all(STATUS_CONFIG
);
543 if (!rc
&& !client
->new && client
->crypto
->fh
->ver
.fh2
.version
< 0x221)
544 client
->rehash
= TRUE
; // For SAVE
546 cleanup_crypto(&client
->crypto
);
548 if (!rc
&& client
->new)
549 rc
= send_status(ctx
, STATUS_NEWFILE
, NULL
);
551 if (!rc
&& client
->lock_on_open
)
552 return do_lock_command(client
);
554 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
557 static void req_cleanup(void *arg
)
562 g_strfreev((gchar
**)arg
);
565 static gpg_error_t
parse_open_opt_lock(gpointer data
, gpointer value
)
567 struct client_s
*client
= data
;
568 const gchar
*p
= value
;
574 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
576 client
->lock_on_open
= n
? TRUE
: FALSE
;
578 else if ((!p
|| !*p
) && (client
->opts
& OPT_LOCK
))
579 client
->lock_on_open
= FALSE
;
581 client
->lock_on_open
= TRUE
;
586 static gpg_error_t
parse_opt_pinentry(gpointer data
, gpointer value
)
589 struct client_s
*client
= data
;
594 client
->pinentry
->enable
= -1;
595 client
->opts
&= ~(OPT_PINENTRY
);
602 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
604 client
->pinentry
->enable
= n
? TRUE
: FALSE
;
605 client
->opts
|= OPT_PINENTRY
;
608 return GPG_ERR_NOT_IMPLEMENTED
;
612 static gpg_error_t
parse_opt_inquire(gpointer data
, gpointer value
)
614 struct client_s
*client
= data
;
617 client
->opts
|= OPT_INQUIRE
;
621 static gpg_error_t
open_command_common(assuan_context_t ctx
, gchar
*line
)
623 gboolean cached
= FALSE
;
625 struct client_s
*client
= assuan_get_pointer(ctx
);
627 gchar
*filename
= NULL
;
629 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
632 pth_cleanup_push(req_cleanup
, req
);
634 if (!filename
|| !*filename
) {
636 return client
->opts
& OPT_INQUIRE
? GPG_ERR_SYNTAX
: send_error(ctx
, GPG_ERR_SYNTAX
);
639 log_write2("ARGS=\"%s\" %s", filename
, req
[1] ? "<passphrase>" : "");
641 if (valid_filename(filename
) == FALSE
) {
643 return client
->opts
& OPT_INQUIRE
? GPG_ERR_INV_VALUE
: send_error(ctx
, GPG_ERR_INV_VALUE
);
646 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
647 CACHE_LOCK(client
->ctx
);
649 if (cache_has_file(client
->md5file
) == FALSE
) {
650 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
653 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
658 rc
= lock_file_mutex(client
);
662 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
665 client
->freed
= FALSE
;
666 CACHE_LOCK(client
->ctx
);
667 cache_incr_refcount(client
->md5file
);
669 client
->crypto
= init_client_crypto();
671 if (!client
->crypto
) {
673 cleanup_client(client
);
674 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
677 client
->crypto
->key
= gcry_malloc(KEYSIZE
);
679 if (!client
->crypto
->key
) {
681 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
683 cleanup_client(client
);
684 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
687 memset(client
->crypto
->key
, 0, KEYSIZE
);
688 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
690 if (!client
->crypto
->fh
) {
691 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
692 log_write("%s: %s", filename
, pwmd_strerror(rc
));
694 cleanup_client(client
);
695 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
699 * New files don't need a key.
701 if ((client
->xml
= new_document()) == NULL
) {
702 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
704 cleanup_client(client
);
705 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
708 client
->len
= xmlStrlen(client
->xml
);
710 client
->filename
= g_strdup(filename
);
712 if (!client
->filename
) {
714 cleanup_client(client
);
715 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
716 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
721 client
->pinentry
->filename
= g_strdup(client
->filename
);
723 if (!client
->pinentry
->filename
) {
724 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
725 cleanup_client(client
);
726 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
729 return open_command_finalize(ctx
, (guchar
*)req
[1],
730 req
[1] ? strlen(req
[1]) : 0, cached
);
733 if (!(client
->opts
& OPT_CIPHER
))
734 g_key_file_set_string(keyfileh
, filename
, "cipher",
735 pwmd_cipher_to_str(client
->crypto
->fh
->ver
.fh2
.flags
));
737 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
740 client
->filename
= g_strdup(filename
);
742 if (!client
->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
->pinentry
->filename
)
751 g_free(client
->pinentry
->filename
);
753 client
->pinentry
->filename
= g_strdup(client
->filename
);
755 if (!client
->pinentry
->filename
) {
756 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
758 cleanup_client(client
);
759 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
763 if (client
->crypto
->fh
->ver
.fh2
.iter
<= 0ULL) {
767 CACHE_LOCK(client
->ctx
);
768 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
771 if (cached
== FALSE
) {
772 gchar
*tmp
= get_key_file_string(filename
, "key_file");
774 if (tmp
&& !(client
->opts
& OPT_INQUIRE
)) {
777 cleanup_client(client
);
778 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
785 * No key specified and no matching filename found in the cache. Use
786 * pinentry to retrieve the key. Cannot return assuan_process_done()
787 * here otherwise the command will be interrupted. The event loop in
788 * client_thread() will poll the file descriptor waiting for it to
789 * become ready to read a pinentry_key_s which will contain the
790 * entered key or an error code. It will then call
791 * open_command_finalize() to to finish the command.
793 if (!req
[1] || !*req
[1]) {
795 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
797 /* From set_pinentry_defaults(). */
798 if (client
->opts
& OPT_INQUIRE
||
799 client
->pinentry
->enable
== FALSE
||
800 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
801 rc
= hash_key(client
->crypto
, (guchar
*)"", 1, FALSE
);
803 cleanup_client(client
);
804 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
811 // To set the keysize.
812 rc
= init_client_crypto2(filename
, client
->crypto
);
814 cleanup_client(client
);
815 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
818 rc
= lock_pin_mutex(client
);
820 unlock_pin_mutex(client
->pinentry
);
821 cleanup_client(client
);
822 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
825 client
->pinentry
->which
= PINENTRY_OPEN
;
826 rc
= pinentry_fork(ctx
);
829 unlock_pin_mutex(client
->pinentry
);
830 cleanup_client(client
);
831 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
834 // Called from pinentry iterate.
835 client
->pinentry
->cb
= open_command_finalize
;
836 client
->pinentry
->status
= PINENTRY_INIT
;
839 rc
= hash_key(client
->crypto
, "" , 1, FALSE
);
841 cleanup_client(client
);
842 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
849 rc
= hash_key(client
->crypto
, (guchar
*)req
[1], strlen(req
[1]), FALSE
);
853 cleanup_client(client
);
854 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
857 else if (req
&& req
[1] && *req
[1]) {
858 rc
= hash_key(client
->crypto
, (guchar
*)req
[1], strlen(req
[1]), FALSE
);
862 cleanup_client(client
);
863 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
869 return open_command_finalize(ctx
, (guchar
*)req
[1],
870 req
[1] ? strlen(req
[1]) : 0, cached
);
873 static gint
open_command_inquire_finalize(gpointer data
, gint assuan_rc
,
874 guchar
*line
, gsize len
)
876 assuan_context_t ctx
= data
;
877 struct client_s
*client
= assuan_get_pointer(ctx
);
878 gpg_error_t rc
= file_modified(client
);
882 if (assuan_rc
|| (rc
&& rc
!= EPWMD_NO_FILE
)) {
886 return assuan_rc
? assuan_rc
: rc
;
889 while (*p
&& *++p
!= ' ')
892 if (*p
&& i
!= len
) {
895 has_null_byte(NULL
, p
, len
);
898 rc
= open_command_common(ctx
, (gchar
*)line
);
903 client
->inquire_status
= INQUIRE_DONE
;
907 static gint
open_command(assuan_context_t ctx
, gchar
*line
)
910 struct client_s
*client
= assuan_get_pointer(ctx
);
911 struct argv_s
*args
[] = {
912 &(struct argv_s
) { "lock", OPTION_TYPE_NOARG
, parse_open_opt_lock
},
913 &(struct argv_s
) { "pinentry", OPTION_TYPE_OPTARG
, parse_opt_pinentry
},
914 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
918 if (client
->state
== STATE_OPEN
)
919 cleanup_client(client
);
921 if (!(client
->opts
& OPT_LOCK
))
922 client
->lock_on_open
= FALSE
;
924 rc
= parse_options(&line
, args
, client
);
927 return send_error(ctx
, rc
);
929 if ((client
->opts
& OPT_INQUIRE
)) {
930 rc
= assuan_inquire_ext(ctx
, "OPEN", 0, open_command_inquire_finalize
,
934 return send_error(ctx
, rc
);
936 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
937 client
->inquire_status
= INQUIRE_BUSY
;
941 return open_command_common(ctx
, line
);
944 gpg_error_t
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
945 guint size
, gpointer
*out
, gulong
*outsize
)
950 gint cmd
= Z_NO_FLUSH
;
954 gz
= g_malloc0(sizeof(struct gz_s
));
957 return GPG_ERR_ENOMEM
;
959 pth_cleanup_push(gz_cleanup
, &gz
);
960 gz
->which
= STATUS_COMPRESS
;
961 gz
->z
.zalloc
= z_alloc
;
962 gz
->z
.zfree
= z_free
;
963 gz
->z
.next_in
= data
;
964 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
965 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
966 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
969 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
971 return GPG_ERR_ENOMEM
;
974 zrc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
977 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
979 return GPG_ERR_COMPR_ALGO
;
982 /* Rather than store the size of the uncompressed data in the file header,
983 * store it in the comment field of the gzip header. Don't give anyone too
984 * much information. Not sure why really, but it seems the right way. :)
986 memset(&h
, 0, sizeof(gz_header
));
987 g_snprintf(buf
, sizeof(buf
), "%u", size
);
988 h
.comment
= (guchar
*)buf
;
989 zrc
= deflateSetHeader(&gz
->z
, &h
);
992 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
994 return GPG_ERR_COMPR_ALGO
;
1000 zrc
= deflate(&gz
->z
, cmd
);
1006 if (!gz
->z
.avail_out
) {
1007 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
1010 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1011 rc
= GPG_ERR_ENOMEM
;
1016 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
1017 gz
->z
.avail_out
= zlib_bufsize
;
1020 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
1021 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
1022 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
1024 gz
->z
.avail_in
= zlib_bufsize
;
1026 rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u",
1027 gz
->z
.total_in
, size
);
1033 if (gz
->z
.total_in
>= size
)
1040 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
1041 rc
= GPG_ERR_COMPR_ALGO
;
1044 } while (zrc
!= Z_STREAM_END
);
1046 rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u", gz
->z
.total_in
, size
);
1052 *outsize
= gz
->z
.total_out
;
1062 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1065 * Useful for a large amount of data. Rather than doing all of the data in one
1066 * iteration do it in chunks. This lets the command be cancelable rather than
1067 * waiting for it to complete.
1069 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
1070 struct crypto_s
*crypto
, status_msg_t which
)
1073 goffset len
= CRYPTO_BLOCKSIZE(crypto
);
1074 gpointer p
= gcry_malloc(len
);
1079 return GPG_ERR_ENOMEM
;
1081 if (crypto
->insize
< CRYPTO_BLOCKSIZE(crypto
))
1082 len
= crypto
->insize
;
1084 pth_cleanup_push(gcry_free
, p
);
1087 inbuf
= (guchar
*)crypto
->inbuf
+ total
;
1090 if (len
+ total
> crypto
->insize
)
1091 len
= crypto
->blocksize
;
1093 if (which
== STATUS_ENCRYPT
)
1094 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1096 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
1101 tmp
= (guchar
*)crypto
->inbuf
+ total
;
1102 memmove(tmp
, p
, len
);
1105 if (total
>= crypto
->insize
)
1116 /* The crypto struct must be setup for iterations and .key. */
1117 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
1118 struct crypto_s
*crypto
, const gchar
*filename
)
1120 goffset len
= crypto
->insize
;
1124 guint64 iter_progress
= 0, n_iter
= 0, xiter
= 0;
1125 gchar tmp
[FILENAME_MAX
];
1129 if (!crypto
->fh
->ver
.fh2
.iter
) {
1131 * cache_file_count() needs both .used == TRUE and a valid key in
1132 * order for it to count as a used cache entry. Fixes CACHE status
1135 memset(crypto
->key
, '!', KEYSIZE
);
1140 * Resize the existing xml buffer to the block size required by gcrypt
1141 * rather than duplicating it and wasting memory.
1143 crypto
->insize
+= sizeof(crypto_magic
);
1144 len
= (crypto
->insize
/ crypto
->blocksize
) * crypto
->blocksize
;
1146 if (crypto
->insize
% crypto
->blocksize
)
1147 len
+= crypto
->blocksize
;
1149 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
1152 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1153 return GPG_ERR_ENOMEM
;
1156 guchar
*tmpbuf
= inbuf
;
1157 memmove(&tmpbuf
[sizeof(crypto_magic
)], tmpbuf
, len
-sizeof(crypto_magic
));
1158 memcpy(tmpbuf
, crypto_magic
, sizeof(crypto_magic
));
1159 crypto
->inbuf
= tmpbuf
;
1160 crypto
->insize
= len
;
1161 gcry_create_nonce(crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
1164 gcry_free(crypto
->tkey
);
1166 crypto
->tkey
= gcry_malloc(KEYSIZE
);
1168 if (!crypto
->tkey
) {
1169 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1170 return GPG_ERR_ENOMEM
;
1173 memcpy(crypto
->tkey
, crypto
->key
, KEYSIZE
);
1174 guchar
*tkey
= crypto
->tkey
;
1177 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
1178 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1182 iter_progress
= get_key_file_uint64(
1183 client
? client
->filename
: "global", "iteration_progress");
1185 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1186 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1187 "0 %llu", crypto
->fh
->ver
.fh2
.iter
);
1193 while (xiter
< crypto
->fh
->ver
.fh2
.iter
-1) {
1194 if (iter_progress
> 0ULL && xiter
>= iter_progress
) {
1195 if (!(xiter
% iter_progress
)) {
1196 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1197 "%llu %llu", ++n_iter
* iter_progress
,
1198 crypto
->fh
->ver
.fh2
.iter
);
1205 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1206 crypto
->blocksize
))) {
1207 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1211 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1214 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1221 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1222 crypto
->blocksize
))) {
1223 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1227 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
1228 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
1232 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1237 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1238 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1239 "%llu %llu", crypto
->fh
->ver
.fh2
.iter
, crypto
->fh
->ver
.fh2
.iter
);
1249 if (!client
&& !g_ascii_strcasecmp(filename
, "-")) {
1250 crypto
->fh
->fd
= STDOUT_FILENO
;
1254 if (g_lstat(filename
, &st
) == 0) {
1255 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1257 if (!(mode
& S_IWUSR
))
1258 return GPG_ERR_EACCES
;
1260 else if (errno
!= ENOENT
)
1261 return gpg_error_from_syserror();
1263 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1264 #if GLIB_CHECK_VERSION(2, 22, 0)
1265 crypto
->fh
->fd
= g_mkstemp_full(tmp
, O_WRONLY
, 0600);
1267 crypto
->fh
->fd
= mkstemp(tmp
);
1270 if (crypto
->fh
->fd
== -1) {
1271 rc
= gpg_error_from_syserror();
1272 p
= strrchr(tmp
, '/');
1274 log_write("%s: %s", p
, pwmd_strerror(rc
));
1278 pth_cleanup_push(cleanup_unlink_cb
, tmp
);
1282 * xml_import() or convert_file() from command line.
1284 crypto
->fh
->fd
= STDOUT_FILENO
;
1287 crypto
->fh
->ver
.fh2
.magic
[0] = '\177';
1288 crypto
->fh
->ver
.fh2
.magic
[1] = 'P';
1289 crypto
->fh
->ver
.fh2
.magic
[2] = 'W';
1290 crypto
->fh
->ver
.fh2
.magic
[3] = 'M';
1291 crypto
->fh
->ver
.fh2
.magic
[4] = 'D';
1292 crypto
->fh
->ver
.fh2
.version
= VERSION_HEX
;
1293 len
= pth_write(crypto
->fh
->fd
, &crypto
->fh
->ver
.fh2
, sizeof(crypto
->fh
->ver
.fh2
));
1295 if (len
!= sizeof(crypto
->fh
->ver
.fh2
)) {
1296 rc
= gpg_error_from_syserror();
1304 len
= pth_write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1306 if (len
!= crypto
->insize
) {
1307 rc
= gpg_error_from_syserror();
1315 if (fsync(crypto
->fh
->fd
) == -1) {
1316 rc
= gpg_error_from_syserror();
1328 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1329 gchar tmp2
[FILENAME_MAX
];
1331 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1333 acl
= acl_get_file(filename
, ACL_TYPE_ACCESS
);
1336 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1339 if (rename(filename
, tmp2
) == -1) {
1340 rc
= gpg_error_from_syserror();
1351 acl
= acl_get_file(".", ACL_TYPE_DEFAULT
);
1354 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1358 if (rename(tmp
, filename
) == -1) {
1359 rc
= gpg_error_from_syserror();
1371 chmod(filename
, mode
);
1374 if (acl
&& acl_set_file(filename
, ACL_TYPE_ACCESS
, acl
))
1375 log_write("ACL: %s: %s", filename
, pwmd_strerror(gpg_error_from_syserror()));
1381 /* Be sure the file entry has been written to disk. On FreeBSD I
1382 * noticed delays causing a following command to return
1383 * GPG_ERR_CHECKSUM. Recommended from fsync(2) (Linux).
1387 gchar
*s
= get_key_file_string("global", "data_directory");
1389 path
= expand_homedir(s
);
1391 dir
= opendir(path
);
1394 gint fd
= dirfd(dir
);
1398 rc
= gpg_error_from_syserror();
1403 rc
= gpg_error_from_syserror();
1406 if (client
&& g_lstat(filename
, &st
) == 0)
1407 client
->mtime
= st
.st_mtime
;
1412 gpg_error_t
update_save_flags(const gchar
*filename
,
1413 struct crypto_s
*crypto
)
1419 crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1422 return GPG_ERR_ENOMEM
;
1425 rc
= init_client_crypto2(filename
, crypto
);
1430 if (filename
&& !crypto
->fh
->v1
)
1431 crypto
->fh
->ver
.fh2
.iter
= get_key_file_uint64(filename
, "iterations");
1436 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1437 gsize keylen
, gboolean cached
)
1439 struct client_s
*client
= assuan_get_pointer(ctx
);
1448 rc
= update_save_flags(client
->filename
, client
->crypto
);
1450 cleanup_crypto(&client
->crypto
);
1451 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1452 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1456 gcry_create_nonce(client
->crypto
->fh
->ver
.fh2
.salt
, 8);
1457 rc
= hash_key(client
->crypto
, key
, keylen
, TRUE
);
1459 cleanup_crypto(&client
->crypto
);
1460 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1466 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
));
1469 cleanup_crypto(&client
->crypto
);
1470 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1473 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1474 pth_cleanup_push(xmlFree
, xmlbuf
);
1475 clevel
= get_key_file_integer(client
->filename
, "compression_level");
1480 rc
= do_compress(ctx
, clevel
, xmlbuf
, len
, &outbuf
, &outsize
);
1484 cleanup_crypto(&client
->crypto
);
1486 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1494 client
->crypto
->inbuf
= xmlbuf
;
1495 client
->crypto
->insize
= len
;
1496 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1499 cleanup_crypto(&client
->crypto
);
1500 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1503 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1504 CACHE_LOCK(client
->ctx
);
1507 cache_reset_timeout(client
->md5file
, timeout
);
1510 if (client
->new == TRUE
)
1511 send_status_all(STATUS_CACHE
);
1513 client
->new = FALSE
;
1514 cleanup_crypto(&client
->crypto
);
1515 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1518 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1520 cleanup_crypto(&client
->crypto
);
1521 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1524 client
->new = client
->rehash
= FALSE
;
1525 cache_reset_timeout(client
->md5file
, timeout
);
1527 send_status_all(STATUS_CACHE
);
1528 cleanup_crypto(&client
->crypto
);
1529 return client
->opts
& OPT_INQUIRE
? 0 : send_error(ctx
, 0);
1532 static gpg_error_t
parse_save_opt_iterations(gpointer data
, gpointer v
)
1534 struct client_s
*client
= data
;
1539 if (!client
->filename
)
1540 return EPWMD_NO_FILE
;
1542 if (!value
|| !*value
)
1546 n
= g_ascii_strtoull(value
, &p
, 10);
1548 if (errno
|| (p
&& *p
) || n
== G_MAXUINT64
)
1549 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_ERANGE
);
1551 MUTEX_LOCK(&rcfile_mutex
);
1552 g_key_file_set_value(keyfileh
,
1553 client
->filename
? client
->filename
: "global", "iterations", value
);
1554 MUTEX_UNLOCK(&rcfile_mutex
);
1556 if (client
->filename
)
1557 client
->opts
|= OPT_ITERATIONS
;
1562 static gpg_error_t
parse_save_opt_cipher(gpointer data
, gpointer value
)
1564 struct client_s
*client
= data
;
1565 const gchar
*p
= value
;
1568 if (!client
->filename
)
1569 return EPWMD_NO_FILE
;
1574 flags
= pwmd_cipher_str_to_cipher(p
);
1577 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
1579 MUTEX_LOCK(&rcfile_mutex
);
1580 g_key_file_set_string(keyfileh
, client
->filename
, "cipher", p
);
1581 MUTEX_UNLOCK(&rcfile_mutex
);
1589 static gpg_error_t
parse_save_opt_reset(gpointer data
, gpointer value
)
1591 struct client_s
*client
= data
;
1593 CACHE_LOCK(client
->ctx
);
1594 cache_clear(client
->md5file
, 1);
1599 static gpg_error_t
save_command_common(assuan_context_t ctx
, gchar
*line
,
1602 struct client_s
*client
= assuan_get_pointer(ctx
);
1603 gboolean cached
= FALSE
;
1605 gboolean keyfile_rehash
= FALSE
;
1608 // Force rehashing the passphrase to update to the salted header.
1610 cache_clear(client
->md5file
, 1);
1612 cached
= cache_iscached(client
->md5file
);
1616 * If a cache entry doesn't exist for this file and the file has a
1617 * "key_file" or "key" parameter, then it's an error. The reason is that
1618 * cache expiration would be useless. Unless this is an inquire, then its
1621 if (cached
== FALSE
&& !client
->rehash
) {
1622 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1624 if (tmp
&& !(client
->opts
& OPT_INQUIRE
)) {
1626 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1634 if (!client
->crypto
) {
1635 client
->crypto
= init_client_crypto();
1637 if (!client
->crypto
) {
1638 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1639 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1643 client
->crypto
->fh
= read_file_header(client
->filename
, FALSE
, &rc
);
1645 cleanup_crypto(&client
->crypto
);
1646 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, rc
);
1651 client
->crypto
->key
= gcry_malloc(KEYSIZE
);
1653 if (!client
->crypto
->key
) {
1654 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1655 cleanup_crypto(&client
->crypto
);
1656 return client
->opts
& OPT_INQUIRE
? GPG_ERR_ENOMEM
: send_error(ctx
, GPG_ERR_ENOMEM
);
1659 memset(client
->crypto
->key
, '!', KEYSIZE
);
1661 if (!get_key_file_uint64(client
->filename
, "iterations") &&
1665 if (!line
|| !*line
) {
1668 /* It doesn't make sense to use an --inquire with an empty
1669 * passphrase. This will prevent a pinentry dialog. */
1670 if (client
->opts
& OPT_INQUIRE
) {
1671 cleanup_crypto(&client
->crypto
);
1672 return GPG_ERR_WRONG_KEY_USAGE
;
1675 if (client
->rehash
) {
1676 tmp
= get_key_file_string(client
->filename
, "key_file");
1678 gchar
*file
= expand_homedir(tmp
);
1683 cleanup_crypto(&client
->crypto
);
1684 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1685 return GPG_ERR_ENOMEM
;
1688 if (stat(file
, &st
) == -1) {
1691 cleanup_crypto(&client
->crypto
);
1695 gint fd
= open(file
, O_RDONLY
);
1699 cleanup_crypto(&client
->crypto
);
1704 line
= gcry_malloc(st
.st_size
);
1706 cleanup_crypto(&client
->crypto
);
1707 return GPG_ERR_ENOMEM
;
1710 len
= pth_read(fd
, line
, st
.st_size
);
1713 if (len
!= st
.st_size
) {
1715 cleanup_crypto(&client
->crypto
);
1716 return GPG_ERR_INCOMPLETE_LINE
;
1719 keyfile_rehash
= TRUE
;
1724 client
->crypto
->tkey
= gcry_malloc(KEYSIZE
);
1726 if (!client
->crypto
->tkey
) {
1727 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1728 cleanup_crypto(&client
->crypto
);
1729 return send_error(ctx
, GPG_ERR_ENOMEM
);
1732 memset(client
->crypto
->tkey
, '!', KEYSIZE
);
1735 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1736 !memcmp(client
->crypto
->key
, client
->crypto
->tkey
, KEYSIZE
)) {
1739 #ifdef WITH_PINENTRY
1742 if (client
->pinentry
->enable
== FALSE
||
1743 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1744 /* Empty keys are allowed. */
1745 rc
= hash_key(client
->crypto
, (guchar
*)"" , 1, FALSE
);
1747 cleanup_crypto(&client
->crypto
);
1748 return send_error(ctx
, rc
);
1754 lock_pin_mutex(client
);
1755 client
->pinentry
->which
= PINENTRY_SAVE
;
1756 rc
= pinentry_fork(ctx
);
1759 unlock_pin_mutex(client
->pinentry
);
1760 cleanup_crypto(&client
->crypto
);
1761 return send_error(ctx
, rc
);
1764 client
->pinentry
->cb
= save_command_finalize
;
1765 client
->pinentry
->status
= PINENTRY_INIT
;
1768 /* Empty keys are allowed. */
1782 if (!get_key_file_uint64(client
->filename
, "iterations")) {
1783 guint64 iter
= get_key_file_uint64(NULL
, "iterations");
1787 iter
= 1; // default? what about the "global" section?
1789 MUTEX_LOCK(&rcfile_mutex
);
1790 p
= g_strdup_printf("%llu", (unsigned long long)iter
);
1791 g_key_file_set_value(keyfileh
, client
->filename
, "iterations", p
);
1793 MUTEX_UNLOCK(&rcfile_mutex
);
1794 client
->opts
|= OPT_ITERATIONS
;
1795 rc
= send_status(ctx
, STATUS_CONFIG
, NULL
);
1798 cleanup_crypto(&client
->crypto
);
1799 return client
->opts
& OPT_INQUIRE
? rc
: send_error(ctx
, rc
);
1805 rc
= save_command_finalize(ctx
, (guchar
*)line
, len
, cached
);
1812 static gint
save_command_inquire_finalize(gpointer data
, gint assuan_rc
,
1813 guchar
*line
, gsize len
)
1815 assuan_context_t ctx
= data
;
1816 struct client_s
*client
= assuan_get_pointer(ctx
);
1817 gpg_error_t rc
= file_modified(client
);
1819 if (assuan_rc
|| rc
) {
1823 return assuan_rc
? assuan_rc
: rc
;
1826 rc
= save_command_common(ctx
, (gchar
*)line
, len
);
1831 client
->inquire_status
= INQUIRE_DONE
;
1835 static gint
save_command(assuan_context_t ctx
, gchar
*line
)
1838 struct client_s
*client
= assuan_get_pointer(ctx
);
1840 struct argv_s
*args
[] = {
1841 &(struct argv_s
) { "iterations", OPTION_TYPE_OPTARG
, parse_save_opt_iterations
},
1842 &(struct argv_s
) { "cipher", OPTION_TYPE_OPTARG
, parse_save_opt_cipher
},
1843 &(struct argv_s
) { "pinentry", OPTION_TYPE_OPTARG
, parse_opt_pinentry
},
1844 &(struct argv_s
) { "reset", OPTION_TYPE_NOARG
, parse_save_opt_reset
},
1845 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
1849 rc
= parse_options(&line
, args
, client
);
1852 return send_error(ctx
, rc
);
1854 if (g_lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1855 return send_error(ctx
, gpg_error_from_syserror());
1857 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1858 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1859 return send_error(ctx
, GPG_ERR_ENOANO
);
1862 if ((client
->opts
& OPT_INQUIRE
)) {
1863 rc
= assuan_inquire_ext(ctx
, "SAVE", 0, save_command_inquire_finalize
,
1867 return send_error(ctx
, rc
);
1869 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1870 client
->inquire_status
= INQUIRE_BUSY
;
1875 log_write2("ARGS=%s", "<passphrase>");
1877 return save_command_common(ctx
, line
, line
? strlen(line
) : 0);
1880 static gint
delete_command(assuan_context_t ctx
, gchar
*line
)
1882 struct client_s
*client
= assuan_get_pointer(ctx
);
1887 log_write2("ARGS=\"%s\"", line
);
1889 if (strchr(line
, '\t'))
1890 req
= split_input_line(line
, "\t", -1);
1892 req
= split_input_line(line
, " ", -1);
1895 return send_error(ctx
, GPG_ERR_SYNTAX
);
1897 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1901 return send_error(ctx
, rc
);
1905 * No sub-node defined. Remove the entire node (root element).
1909 rc
= unlink_node(n
);
1914 return send_error(ctx
, rc
);
1917 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1921 return send_error(ctx
, rc
);
1924 rc
= unlink_node(n
);
1928 return send_error(ctx
, rc
);
1932 * Don't return with assuan_process_done() here. This has been called from
1933 * assuan_process_next() and the command should be finished in
1936 static gint
store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1939 assuan_context_t ctx
= data
;
1940 struct client_s
*client
= assuan_get_pointer(ctx
);
1942 xmlNodePtr n
, parent
;
1943 gboolean has_content
;
1944 gchar
*content
= NULL
;
1945 gpg_error_t rc
= file_modified(client
);
1947 if (assuan_rc
|| rc
) {
1950 return assuan_rc
? assuan_rc
: rc
;
1953 req
= split_input_line((gchar
*)line
, "\t", 0);
1957 return GPG_ERR_SYNTAX
;
1959 len
= g_strv_length(req
);
1960 has_content
= line
[strlen((gchar
*)line
)-1] != '\t' && len
> 1;
1961 if (*(req
+1) && !valid_element_path(req
, has_content
)) {
1963 return GPG_ERR_INV_VALUE
;
1967 content
= req
[len
-1];
1972 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1973 if (rc
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
1974 rc
= new_root_element(client
->doc
, *req
);
1990 if (req
[1] && *req
[1]) {
1992 parent
= create_elements_cb(n
, req
+1, &rc
, NULL
);
1994 parent
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1995 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
, FALSE
);
1998 if (!rc
&& len
> 1) {
1999 n
= find_text_node(parent
->children
);
2001 xmlNodeSetContent(n
, (xmlChar
*)content
);
2003 xmlNodeAddContent(parent
, (xmlChar
*)content
);
2005 update_element_mtime(parent
);
2009 req
[len
-1] = content
;
2012 client
->inquire_status
= INQUIRE_DONE
;
2016 static gint
store_command(assuan_context_t ctx
, gchar
*line
)
2018 struct client_s
*client
= assuan_get_pointer(ctx
);
2021 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
2024 return send_error(ctx
, rc
);
2026 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2027 client
->inquire_status
= INQUIRE_BUSY
;
2031 static void *send_data_cb(void *arg
)
2033 struct assuan_cmd_s
*data
= arg
;
2037 pth_cancel_state(PTH_CANCEL_ENABLE
|PTH_CANCEL_ASYNCHRONOUS
, &old
);
2038 rc
= g_malloc(sizeof(gpg_error_t
));
2039 *rc
= assuan_send_data(data
->ctx
, data
->line
, data
->line_len
);
2040 pth_cancel_state(old
, NULL
);
2045 /* For every assuan command that needs to be sent to the client, a timeout is
2046 * needed to determine if the client lost the connection. The timeout is the
2047 * same as the "keepalive" configuration parameter or a default if unset.
2049 gpg_error_t
do_assuan_command(assuan_context_t ctx
,
2050 void *(*cb
)(void *data
), void *data
)
2052 pth_attr_t attr
= pth_attr_new();
2059 pth_attr_init(attr
);
2060 pth_attr_set(attr
, PTH_ATTR_JOINABLE
, TRUE
);
2061 tid
= pth_spawn(attr
, cb
, data
);
2062 rc
= gpg_error_from_syserror();
2063 pth_attr_destroy(attr
);
2066 log_write("%s(%i): pth_spawn(): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
2070 pth_cleanup_push(cleanup_cancel_cb
, tid
);
2071 ev
= pth_event(PTH_EVENT_TID
|PTH_UNTIL_TID_DEAD
, tid
);
2072 pth_cleanup_push(cleanup_ev_cb
, ev
);
2076 st
= pth_event_status(ev
);
2078 if (st
== PTH_STATUS_FAILED
) {
2082 rc
= GPG_ERR_ASS_WRITE_ERROR
;
2084 else if (st
== PTH_STATUS_OCCURRED
) {
2086 rc
= *(gpg_error_t
*)p
;
2095 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
2101 struct assuan_cmd_s data
;
2102 gint progress
= get_key_file_integer("global", "xfer_progress");
2105 progress
= progress
>0 ? (progress
/ASSUAN_LINELENGTH
)*ASSUAN_LINELENGTH
: 0;
2106 to_send
= total
< ASSUAN_LINELENGTH
? total
: ASSUAN_LINELENGTH
;
2108 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
2115 if (sent
+ to_send
> total
)
2116 to_send
= total
- sent
;
2118 data
.line
= flush
? NULL
: (gchar
*)line
+sent
;
2119 data
.line_len
= flush
? 0 : to_send
;
2120 rc
= do_assuan_command(ctx
, send_data_cb
, &data
);
2123 sent
+= flush
? 0 : to_send
;
2125 if ((progress
&& !(sent
% progress
) && sent
!= total
) ||
2126 (sent
== total
&& flush
))
2127 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
2129 if (!flush
&& !rc
&& sent
== total
) {
2134 } while (!rc
&& sent
< total
);
2139 static gint
get_command(assuan_context_t ctx
, gchar
*line
)
2141 struct client_s
*client
= assuan_get_pointer(ctx
);
2146 log_write2("ARGS=\"%s\"", line
);
2147 req
= split_input_line(line
, "\t", -1);
2149 if (!req
|| !*req
) {
2151 return send_error(ctx
, GPG_ERR_SYNTAX
);
2154 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
2158 return send_error(ctx
, rc
);
2162 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2167 return send_error(ctx
, rc
);
2169 if (!n
|| !n
->children
)
2170 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2172 n
= find_text_node(n
->children
);
2174 if (!n
|| !n
->content
|| !*n
->content
)
2175 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2177 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
2178 return send_error(ctx
, rc
);
2181 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
2182 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
2184 gchar
*path
= *(gchar
**)data
;
2185 gchar
*tmp
= NULL
, *result
;
2189 *(gchar
**)data
= NULL
;
2192 path
= g_strjoinv("\t", target
);
2195 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2196 *rc
= GPG_ERR_ENOMEM
;
2201 tmp
= g_strjoinv("\t", req_orig
);
2205 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2206 *rc
= GPG_ERR_ENOMEM
;
2212 result
= g_strdup_printf("%s\t%s", path
, tmp
);
2214 result
= g_strdup(path
);
2217 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2218 *rc
= GPG_ERR_ENOMEM
;
2226 *(gchar
**)data
= result
;
2230 static void list_command_cleanup1(void *arg
);
2231 static gint
realpath_command(assuan_context_t ctx
, gchar
*line
)
2234 struct client_s
*client
= assuan_get_pointer(ctx
);
2242 log_write2("ARGS=\"%s\"", line
);
2244 if (strchr(line
, '\t') != NULL
) {
2245 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
2246 return send_error(ctx
, GPG_ERR_SYNTAX
);
2249 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
2250 return send_error(ctx
, GPG_ERR_SYNTAX
);
2253 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
2257 return send_error(ctx
, rc
);
2260 rp
= g_strjoinv("\t", req
);
2264 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2265 return send_error(ctx
, GPG_ERR_ENOMEM
);
2269 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
2270 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
, FALSE
);
2275 return send_error(ctx
, rc
);
2279 string
= g_string_new(rp
);
2284 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2285 return send_error(ctx
, GPG_ERR_ENOMEM
);
2289 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
2290 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
2291 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
2296 pth_cleanup_push(list_command_cleanup1
, string
);
2297 rc
= xfer_data(ctx
, string
->str
, string
->len
);
2299 return send_error(ctx
, rc
);
2302 static void list_command_cleanup1(void *arg
)
2304 g_string_free((GString
*)arg
, TRUE
);
2307 static void list_command_cleanup2(void *arg
)
2309 struct element_list_s
*elements
= arg
;
2312 if (elements
->list
) {
2313 gint total
= g_slist_length(elements
->list
);
2316 for (i
= 0; i
< total
; i
++) {
2317 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
2321 g_slist_free(elements
->list
);
2324 if (elements
->prefix
)
2325 g_free(elements
->prefix
);
2328 g_strfreev(elements
->req
);
2334 static gpg_error_t
parse_list_opt_norecurse(gpointer data
, gpointer value
)
2336 struct element_list_s
*elements
= data
;
2338 elements
->recurse
= FALSE
;
2342 static gpg_error_t
parse_list_opt_verbose(gpointer data
, gpointer value
)
2344 struct element_list_s
*elements
= data
;
2346 elements
->verbose
= TRUE
;
2350 static gint
list_command(assuan_context_t ctx
, gchar
*line
)
2352 struct client_s
*client
= assuan_get_pointer(ctx
);
2354 struct element_list_s
*elements
= NULL
;
2356 struct argv_s
*args
[] = {
2357 &(struct argv_s
) { "no-recurse", OPTION_TYPE_NOARG
, parse_list_opt_norecurse
},
2358 &(struct argv_s
) { "verbose", OPTION_TYPE_NOARG
, parse_list_opt_verbose
},
2362 if (disable_list_and_dump
== TRUE
)
2363 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2365 elements
= g_malloc0(sizeof(struct element_list_s
));
2368 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2369 return GPG_ERR_ENOMEM
;
2372 elements
->recurse
= TRUE
; // default
2373 pth_cleanup_push(list_command_cleanup2
, elements
);
2374 rc
= parse_options(&line
, args
, elements
);
2382 rc
= list_root_elements(client
->doc
, &str
, elements
->verbose
);
2386 return send_error(ctx
, rc
);
2389 pth_cleanup_push(list_command_cleanup1
, str
);
2390 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2393 return send_error(ctx
, rc
);
2396 elements
->req
= split_input_line(line
, " ", 0);
2399 strv_printf(&elements
->req
, "%s", line
);
2401 rc
= create_path_list(client
->doc
, elements
, *elements
->req
);
2407 gint total
= g_slist_length(elements
->list
);
2412 rc
= GPG_ERR_NO_VALUE
;
2416 str
= g_string_new(NULL
);
2419 rc
= GPG_ERR_ENOMEM
;
2420 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2424 for (i
= 0; i
< total
; i
++) {
2425 tmp
= g_slist_nth_data(elements
->list
, i
);
2426 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
2429 pth_cleanup_push(list_command_cleanup1
, str
);
2430 rc
= xfer_data(ctx
, str
->str
, str
->len
);
2434 rc
= GPG_ERR_NO_VALUE
;
2438 return send_error(ctx
, rc
);
2442 * req[0] - element path
2444 static gpg_error_t
attribute_list(assuan_context_t ctx
, gchar
**req
)
2446 struct client_s
*client
= assuan_get_pointer(ctx
);
2447 gchar
**attrlist
= NULL
;
2449 gchar
**path
= NULL
;
2455 if (!req
|| !req
[0])
2456 return GPG_ERR_SYNTAX
;
2458 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2460 * The first argument may be only a root element.
2462 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2463 return GPG_ERR_SYNTAX
;
2466 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2474 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2475 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2485 for (a
= n
->properties
; a
; a
= a
->next
) {
2488 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
2490 g_strfreev(attrlist
);
2492 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2493 return GPG_ERR_ENOMEM
;
2498 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
,
2499 an
&& an
->content
? (gchar
*)an
->content
: "");
2502 g_strfreev(attrlist
);
2503 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2504 return GPG_ERR_ENOMEM
;
2507 attrlist
[++i
] = NULL
;
2511 return GPG_ERR_NO_VALUE
;
2513 line
= g_strjoinv("\n", attrlist
);
2516 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2517 g_strfreev(attrlist
);
2518 return GPG_ERR_ENOMEM
;
2521 pth_cleanup_push(g_free
, line
);
2522 pth_cleanup_push(req_cleanup
, attrlist
);
2523 rc
= xfer_data(ctx
, line
, strlen(line
));
2530 * req[0] - attribute
2531 * req[1] - element path
2533 static gpg_error_t
attribute_delete(struct client_s
*client
, gchar
**req
)
2536 gchar
**path
= NULL
;
2539 if (!req
|| !req
[0] || !req
[1])
2540 return GPG_ERR_SYNTAX
;
2542 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2544 * The first argument may be only a root element.
2546 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2547 return GPG_ERR_SYNTAX
;
2551 * Don't remove the "_name" attribute for the root element. To remove an
2552 * root element use DELETE <name>.
2554 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"_name")) {
2555 rc
= GPG_ERR_SYNTAX
;
2559 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2565 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2566 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2572 rc
= delete_attribute(n
, (xmlChar
*)req
[0]);
2579 static xmlNodePtr
create_element_path(struct client_s
*client
,
2580 gchar
***elements
, gpg_error_t
*rc
, xmlNodePtr parent
)
2582 gchar
**req
= *elements
;
2583 gchar
**req_orig
= g_strdupv(req
);
2584 xmlNodePtr n
= NULL
;
2589 *rc
= GPG_ERR_ENOMEM
;
2590 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2595 n
= find_root_element(client
->doc
, &req
, rc
, NULL
, 0, FALSE
);
2597 if (*rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
2600 *rc
= new_root_element(client
->doc
, req
[0]);
2606 else if (n
== parent
) {
2607 *rc
= GPG_ERR_CONFLICT
;
2613 n
= create_target_elements_cb(n
, req
+1, rc
, NULL
);
2615 n
= find_elements(client
->doc
, n
->children
, req
+1, rc
, NULL
, NULL
,
2616 create_target_elements_cb
, FALSE
, 0, parent
, FALSE
);
2622 * Reset the position of the element tree now that the elements
2623 * have been created.
2628 n
= find_root_element(client
->doc
, &req
, rc
, NULL
, 0, FALSE
);
2632 n
= find_elements(client
->doc
, n
->children
, req
+1, rc
,
2633 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2640 g_strfreev(req_orig
);
2647 * Creates a "target" attribute. When other commands encounter an element with
2648 * this attribute, the element path is modified to the target value. If the
2649 * source element path doesn't exist when using 'ATTR SET target', it is
2650 * created, but the destination element path must exist.
2652 * req[0] - source element path
2653 * req[1] - destination element path
2655 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2657 gchar
**src
, **dst
, *line
= NULL
, **odst
= NULL
;
2661 if (!req
|| !req
[0] || !req
[1])
2662 return GPG_ERR_SYNTAX
;
2664 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2666 * The first argument may be only a root element.
2668 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2669 return GPG_ERR_SYNTAX
;
2672 if (!valid_element_path(src
, FALSE
))
2673 return GPG_ERR_INV_VALUE
;
2675 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2677 * The first argument may be only a root element.
2679 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2680 rc
= GPG_ERR_SYNTAX
;
2685 odst
= g_strdupv(dst
);
2688 rc
= GPG_ERR_ENOMEM
;
2692 n
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
2695 * Make sure the destination element path exists.
2701 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2702 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2708 n
= create_element_path(client
, &src
, &rc
, NULL
);
2713 line
= g_strjoinv("\t", odst
);
2716 rc
= GPG_ERR_ENOMEM
;
2717 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2721 rc
= add_attribute(n
, "target", line
);
2735 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2741 tmp
= g_strdupv(req
);
2744 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2745 return GPG_ERR_ENOMEM
;
2748 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2754 if (g_utf8_collate(req
[0], req
[1]) == 0)
2758 * Will not overwrite an existing root.
2760 tmp
= g_strdupv(req
+1);
2763 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2764 return GPG_ERR_ENOMEM
;
2767 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2770 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
2774 return GPG_ERR_AMBIGUOUS_NAME
;
2776 if (!valid_xml_element((xmlChar
*)req
[1]))
2777 return GPG_ERR_SYNTAX
;
2779 tmp
= g_strdupv(req
);
2782 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2783 return GPG_ERR_ENOMEM
;
2786 n
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2790 return GPG_ERR_ELEMENT_NOT_FOUND
;
2792 return add_attribute(n
, "_name", req
[1]);
2796 * req[0] - attribute
2797 * req[1] - element path
2799 static gpg_error_t
attribute_get(assuan_context_t ctx
, gchar
**req
)
2801 struct client_s
*client
= assuan_get_pointer(ctx
);
2807 if (!req
|| !req
[0] || !req
[1])
2808 return GPG_ERR_SYNTAX
;
2810 if (strchr(req
[1], '\t')) {
2811 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2812 return GPG_ERR_SYNTAX
;
2815 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2816 return GPG_ERR_SYNTAX
;
2819 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2825 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2826 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2834 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2835 return GPG_ERR_NOT_FOUND
;
2837 pth_cleanup_push(xmlFree
, a
);
2840 rc
= xfer_data(ctx
, (gchar
*)a
, xmlStrlen(a
));
2842 rc
= GPG_ERR_NO_VALUE
;
2853 * req[0] - attribute
2854 * req[1] - element path
2857 static gpg_error_t
attribute_set(struct client_s
*client
, gchar
**req
)
2859 gchar
**path
= NULL
;
2863 if (!req
|| !req
[0] || !req
[1])
2864 return GPG_ERR_SYNTAX
;
2867 * Reserved attribute names.
2869 if (!g_strcmp0(req
[0], "_name")) {
2871 * Only reserved for the root element. Not the rest of the
2874 if (strchr(req
[1], '\t') == NULL
)
2875 return name_attribute(client
, req
+ 1);
2877 else if (!g_strcmp0(req
[0], "target"))
2878 return target_attribute(client
, req
+ 1);
2880 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2882 * The first argument may be only a root element.
2884 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2885 return GPG_ERR_SYNTAX
;
2888 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2894 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2895 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2901 rc
= add_attribute(n
, req
[0], req
[2]);
2910 * req[1] - attribute name or element path if command is LIST
2911 * req[2] - element path
2912 * req[2] - element path or value
2914 static gint
attr_command(assuan_context_t ctx
, gchar
*line
)
2916 struct client_s
*client
= assuan_get_pointer(ctx
);
2920 log_write2("ARGS=\"%s\"", line
);
2921 req
= split_input_line(line
, " ", 4);
2923 if (!req
|| !req
[0] || !req
[1]) {
2925 return send_error(ctx
, GPG_ERR_SYNTAX
);
2928 pth_cleanup_push(req_cleanup
, req
);
2930 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2931 rc
= attribute_set(client
, req
+1);
2932 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2933 rc
= attribute_get(ctx
, req
+1);
2934 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2935 rc
= attribute_delete(client
, req
+1);
2936 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2937 rc
= attribute_list(ctx
, req
+1);
2939 rc
= GPG_ERR_SYNTAX
;
2942 return send_error(ctx
, rc
);
2945 static gint
iscached_command(assuan_context_t ctx
, gchar
*line
)
2947 gchar
**req
= split_input_line(line
, " ", 0);
2951 if (!req
|| !*req
) {
2953 return send_error(ctx
, GPG_ERR_SYNTAX
);
2956 log_write2("ARGS=\"%s\"", line
);
2958 if (!valid_filename(req
[0])) {
2960 return GPG_ERR_INV_VALUE
;
2963 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2966 if (cache_iscached(md5file
)) {
2969 return send_error(ctx
, 0);
2973 tmp
= get_key_file_string("global", "data_directory");
2977 return GPG_ERR_ENOMEM
;
2980 path
= expand_homedir(tmp
);
2985 return GPG_ERR_ENOMEM
;
2990 path
= g_strdup_printf("%s/%s", tmp
, req
[0]);
2995 return GPG_ERR_ENOMEM
;
2998 if (access(path
, R_OK
) == -1) {
2999 gpg_error_t rc
= gpg_error_from_syserror();
3003 return send_error(ctx
, rc
);
3007 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
3010 static gint
clearcache_command(assuan_context_t ctx
, gchar
*line
)
3012 gchar
**req
= split_input_line(line
, " ", 0);
3015 log_write2("ARGS=\"%s\"", line
);
3018 if (!req
|| !*req
) {
3020 cache_clear(NULL
, 2);
3022 return send_error(ctx
, 0);
3025 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
3027 (void)cache_clear(md5file
, 1);
3029 return send_error(ctx
, 0);
3032 static gint
cachetimeout_command(assuan_context_t ctx
, gchar
*line
)
3036 gchar
**req
= split_input_line(line
, " ", 0);
3039 if (!req
|| !*req
|| !req
[1]) {
3041 return send_error(ctx
, GPG_ERR_SYNTAX
);
3045 timeout
= strtol(req
[1], &p
, 10);
3047 if (errno
!= 0 || *p
!= 0 || timeout
< -1) {
3049 return send_error(ctx
, GPG_ERR_SYNTAX
);
3052 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
3053 CACHE_LOCK(client
->ctx
);
3055 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
3057 return send_error(ctx
, GPG_ERR_NOT_FOUND
);
3061 return send_error(ctx
, 0);
3064 static gint
dump_command(assuan_context_t ctx
, gchar
*line
)
3068 struct client_s
*client
= assuan_get_pointer(ctx
);
3071 if (disable_list_and_dump
== TRUE
)
3072 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3074 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
3077 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3078 return send_error(ctx
, GPG_ERR_ENOMEM
);
3081 pth_cleanup_push(xmlFree
, xml
);
3082 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
3084 return send_error(ctx
, rc
);
3087 static gint
getconfig_command(assuan_context_t ctx
, gchar
*line
)
3089 struct client_s
*client
= assuan_get_pointer(ctx
);
3091 gchar filename
[255]={0}, param
[747]={0};
3092 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
3094 log_write2("ARGS=\"%s\"", line
);
3096 if (!line
|| !*line
)
3097 return send_error(ctx
, GPG_ERR_SYNTAX
);
3099 if (strchr(line
, ' ')) {
3100 sscanf(line
, " %254[^ ] %746c", filename
, param
);
3105 if (fp
&& !valid_filename(fp
))
3106 return send_error(ctx
, GPG_ERR_INV_VALUE
);
3108 paramp
= g_ascii_strdown(paramp
, -1);
3111 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3112 return send_error(ctx
, GPG_ERR_ENOMEM
);
3115 if (fp
&& !g_ascii_strcasecmp(paramp
, "iterations")) {
3116 if (!(client
->opts
& OPT_ITERATIONS
) || fp
!= client
->filename
) {
3117 file_header_internal_t
*fh
= read_file_header(fp
, FALSE
, &rc
);
3119 if (!fh
&& rc
!= GPG_ERR_ENOENT
)
3120 return send_error(ctx
, rc
);
3124 p
= g_strdup_printf("%llu", (unsigned long long)fh
->ver
.fh2
.iter
);
3125 close_file_header(fh
);
3128 log_write("%s(%i): %s", __FILE__
, __LINE__
,
3129 pwmd_strerror(GPG_ERR_ENOMEM
));
3130 return send_error(ctx
, GPG_ERR_ENOMEM
);
3137 else if (!g_ascii_strcasecmp(paramp
, "enable_pinentry")) {
3138 #ifdef WITH_PINENTRY
3141 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY
))
3142 n
= client
->pinentry
->enable
;
3144 n
= get_key_file_boolean(fp
, "enable_pinentry");
3146 p
= g_strdup_printf("%s", n
? "true" : "false");
3149 log_write("%s(%i): %s", __FILE__
, __LINE__
,
3150 pwmd_strerror(GPG_ERR_ENOMEM
));
3151 return send_error(ctx
, GPG_ERR_ENOMEM
);
3156 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3159 else if (!g_ascii_strcasecmp(paramp
, "pinentry_timeout")) {
3160 #ifdef WITH_PINENTRY
3161 p
= g_strdup_printf("%i", get_key_file_integer(fp
, "pinentry_timeout"));
3164 log_write("%s(%i): %s", __FILE__
, __LINE__
,
3165 pwmd_strerror(GPG_ERR_ENOMEM
));
3166 return send_error(ctx
, GPG_ERR_ENOMEM
);
3171 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3175 p
= get_key_file_string(fp
? fp
: "global", paramp
);
3179 return send_error(ctx
, GPG_ERR_UNKNOWN_OPTION
);
3181 tmp
= expand_homedir(p
);
3185 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3186 return send_error(ctx
, GPG_ERR_ENOMEM
);
3191 pth_cleanup_push(g_free
, p
);
3192 rc
= xfer_data(ctx
, p
, strlen(p
));
3194 return send_error(ctx
, rc
);
3198 xmlXPathContextPtr xp
;
3199 xmlXPathObjectPtr result
;
3204 static void xpath_command_cleanup(void *arg
)
3206 struct xpath_s
*xpath
= arg
;
3208 req_cleanup(xpath
->req
);
3211 xmlBufferFree(xpath
->buf
);
3214 xmlXPathFreeObject(xpath
->result
);
3217 xmlXPathFreeContext(xpath
->xp
);
3220 static gint
xpath_command(assuan_context_t ctx
, gchar
*line
)
3222 struct client_s
*client
= assuan_get_pointer(ctx
);
3224 struct xpath_s xpath
;
3226 log_write2("ARGS=\"%s\"", line
);
3228 if (disable_list_and_dump
== TRUE
)
3229 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3231 if (!line
|| !*line
)
3232 return send_error(ctx
, GPG_ERR_SYNTAX
);
3234 memset(&xpath
, 0, sizeof(struct xpath_s
));
3236 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
3237 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
3238 return send_error(ctx
, GPG_ERR_ENOMEM
);
3241 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3244 xpath_command_cleanup(&xpath
);
3245 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3248 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3250 if (!xpath
.result
) {
3251 xpath_command_cleanup(&xpath
);
3252 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
3255 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3256 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3260 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3261 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, 0, NULL
);
3265 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
3266 rc
= GPG_ERR_NO_VALUE
;
3269 else if (xpath
.req
[1])
3272 pth_cleanup_push(xpath_command_cleanup
, &xpath
);
3273 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
.buf
),
3274 xmlBufferLength(xpath
.buf
));
3278 xpath_command_cleanup(&xpath
);
3279 return send_error(ctx
, rc
);
3282 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3283 static gint
xpathattr_command(assuan_context_t ctx
, gchar
*line
)
3285 struct client_s
*client
= assuan_get_pointer(ctx
);
3287 struct xpath_s xpath
;
3289 gboolean cmd
= FALSE
; //SET
3291 log_write2("ARGS=\"%s\"", line
);
3293 if (disable_list_and_dump
== TRUE
)
3294 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
3296 if (!line
|| !*line
)
3297 return send_error(ctx
, GPG_ERR_SYNTAX
);
3299 memset(&xpath
, 0, sizeof(struct xpath_s
));
3301 if ((req
= split_input_line(line
, " ", 3)) == NULL
)
3302 return send_error(ctx
, GPG_ERR_ENOMEM
);
3305 rc
= GPG_ERR_SYNTAX
;
3309 if (!g_ascii_strcasecmp(req
[0], "SET"))
3311 else if (!g_ascii_strcasecmp(req
[0], "DELETE"))
3314 rc
= GPG_ERR_SYNTAX
;
3318 if (!req
[1] || !req
[2]) {
3319 rc
= GPG_ERR_SYNTAX
;
3323 if ((xpath
.req
= split_input_line(req
[2], "\t", 3)) == NULL
) {
3324 rc
= GPG_ERR_ENOMEM
;
3328 if (!xpath
.req
[0] || (!xpath
.req
[1] && !cmd
) || (xpath
.req
[1] && cmd
)) {
3329 rc
= GPG_ERR_SYNTAX
;
3333 xpath
.xp
= xmlXPathNewContext(client
->doc
);
3336 rc
= EPWMD_LIBXML_ERROR
;
3340 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
3342 if (!xpath
.result
) {
3343 rc
= EPWMD_LIBXML_ERROR
;
3347 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
3348 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
3352 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
3353 (xmlChar
*)xpath
.req
[1], &xpath
.buf
, cmd
, (xmlChar
*)req
[1]);
3357 xpath_command_cleanup(&xpath
);
3358 return send_error(ctx
, rc
);
3361 static gint
import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
3364 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
3365 gpg_error_t rc
= file_modified(client
);
3366 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
3367 xmlDocPtr doc
= NULL
;
3368 xmlNodePtr n
, root
, copy
;
3370 if (assuan_rc
|| rc
) {
3373 return assuan_rc
? assuan_rc
: rc
;
3376 req
= split_input_line((gchar
*)line
, "\t", 2);
3380 return GPG_ERR_SYNTAX
;
3383 path
= split_input_line(req
[1], "\t", 0);
3385 if (!content
|| !*content
) {
3386 rc
= GPG_ERR_SYNTAX
;
3390 if (path
&& !valid_element_path(path
, FALSE
)) {
3391 rc
= GPG_ERR_INV_VALUE
;
3395 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
3398 rc
= EPWMD_LIBXML_ERROR
;
3402 root
= xmlDocGetRootElement(doc
);
3403 rc
= validate_import(root
);
3409 path_orig
= g_strdupv(path
);
3412 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
3413 rc
= GPG_ERR_ENOMEM
;
3417 xmlChar
*a
= xmlGetProp(root
, (xmlChar
*)"_name");
3420 g_strfreev(path_orig
);
3421 rc
= GPG_ERR_ENOMEM
;
3425 if (strv_printf(&path
, "%s", (gchar
*)a
) == FALSE
) {
3427 g_strfreev(path_orig
);
3428 rc
= GPG_ERR_ENOMEM
;
3433 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
3435 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3436 g_strfreev(path_orig
);
3441 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, TRUE
);
3443 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3444 g_strfreev(path_orig
);
3448 xmlNodePtr parent
= n
->parent
;
3459 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
3460 n
= create_element_path(client
, &path
, &rc
, NULL
);
3466 copy
= xmlCopyNodeList(root
);
3467 n
= xmlAddChildList(n
, copy
);
3470 rc
= EPWMD_LIBXML_ERROR
;
3473 /* Check if the content root element can create a DTD root element. */
3474 if (!xmlStrEqual((xmlChar
*)"element", root
->name
)) {
3475 rc
= GPG_ERR_SYNTAX
;
3481 if ((a
= xmlGetProp(root
, (xmlChar
*)"_name")) == NULL
) {
3482 rc
= GPG_ERR_SYNTAX
;
3486 gchar
*tmp
= g_strdup((gchar
*)a
);
3488 gboolean literal
= is_literal_element(&tmp
);
3490 if (!valid_xml_element((xmlChar
*)tmp
) || literal
) {
3492 rc
= GPG_ERR_INV_VALUE
;
3496 if (strv_printf(&path
, "%s", tmp
) == FALSE
) {
3498 rc
= GPG_ERR_ENOMEM
;
3503 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, TRUE
);
3505 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3506 rc
= EPWMD_LIBXML_ERROR
;
3510 /* Overwriting the existing tree. */
3517 xmlSetProp(root
, (xmlChar
*)"_name", (xmlChar
*)path
[0]);
3518 n
= xmlCopyNode(root
, 1);
3519 n
= xmlAddChildList(xmlDocGetRootElement(client
->doc
), n
);
3523 rc
= update_element_mtime(n
->parent
);
3533 client
->inquire_status
= INQUIRE_DONE
;
3537 static gint
import_command(assuan_context_t ctx
, gchar
*line
)
3540 struct client_s
*client
= assuan_get_pointer(ctx
);
3542 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
3545 return send_error(ctx
, rc
);
3547 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3548 client
->inquire_status
= INQUIRE_BUSY
;
3552 static gpg_error_t
do_lock_command(struct client_s
*client
)
3554 gpg_error_t rc
= lock_file_mutex(client
);
3557 client
->is_lock_cmd
= TRUE
;
3559 return client
->opts
& OPT_INQUIRE
? rc
: send_error(client
->ctx
, rc
);
3562 static gint
lock_command(assuan_context_t ctx
, gchar
*line
)
3564 struct client_s
*client
= assuan_get_pointer(ctx
);
3566 return do_lock_command(client
);
3569 static gint
unlock_command(assuan_context_t ctx
, gchar
*line
)
3571 struct client_s
*client
= assuan_get_pointer(ctx
);
3573 unlock_file_mutex(client
);
3574 return send_error(ctx
, 0);
3577 static gint
getpid_command(assuan_context_t ctx
, gchar
*line
)
3581 pid_t pid
= getpid();
3583 print_fmt(buf
, sizeof(buf
), "%i", pid
);
3584 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3585 return send_error(ctx
, rc
);
3588 static gint
version_command(assuan_context_t ctx
, gchar
*line
)
3593 buf
= g_strdup_printf("0x%X %s", VERSION_HEX
,
3594 #ifdef WITH_PINENTRY
3604 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3606 return send_error(ctx
, rc
);
3609 #ifdef WITH_PINENTRY
3610 static void set_option_value(gchar
**opt
, const gchar
*value
)
3618 *opt
= g_strdup(value
);
3622 static gint
set_unset_common(assuan_context_t ctx
, const gchar
*name
,
3625 struct client_s
*client
= assuan_get_pointer(ctx
);
3628 if (g_ascii_strcasecmp(name
, (gchar
*)"log_level") == 0) {
3635 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3638 MUTEX_LOCK(&rcfile_mutex
);
3639 g_key_file_set_integer(keyfileh
, "global", "log_level", n
);
3640 MUTEX_UNLOCK(&rcfile_mutex
);
3643 else if (g_ascii_strcasecmp(name
, (gchar
*)"rc_on_locked") == 0) {
3650 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3653 client
->rc_on_locked
= n
? TRUE
: FALSE
;
3656 else if (g_ascii_strcasecmp(name
, (gchar
*)"lock_on_open") == 0) {
3657 rc
= parse_open_opt_lock(client
, (gpointer
)value
);
3662 client
->opts
|= OPT_LOCK
;
3664 else if (g_ascii_strcasecmp(name
, (gchar
*)"cipher") == 0) {
3666 client
->opts
&= ~(OPT_CIPHER
);
3670 rc
= parse_save_opt_cipher(client
, (gpointer
)value
);
3675 client
->opts
|= OPT_CIPHER
;
3678 else if (g_ascii_strcasecmp(name
, (gchar
*)"iterations") == 0) {
3679 rc
= parse_save_opt_iterations(client
, (gpointer
)value
);
3686 else if (g_ascii_strcasecmp(name
, (gchar
*)"NAME") == 0) {
3687 pth_attr_t attr
= pth_attr_of(pth_self());
3691 pth_attr_destroy(attr
);
3695 print_fmt(buf
, sizeof(buf
), "%s", value
);
3696 pth_attr_set(attr
, PTH_ATTR_NAME
, buf
);
3697 pth_attr_destroy(attr
);
3698 #ifdef WITH_PINENTRY
3699 if (client
->pinentry
->name
)
3700 g_free(client
->pinentry
->name
);
3702 client
->pinentry
->name
= g_strdup(buf
);
3704 if (!client
->pinentry
->name
)
3705 return GPG_ERR_ENOMEM
;
3710 #ifdef WITH_PINENTRY
3711 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3712 set_option_value(&client
->pinentry
->lcmessages
, value
);
3713 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3714 set_option_value(&client
->pinentry
->lcctype
, value
);
3715 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3716 set_option_value(&client
->pinentry
->ttyname
, value
);
3717 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3718 set_option_value(&client
->pinentry
->ttytype
, value
);
3719 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3720 set_option_value(&client
->pinentry
->display
, value
);
3721 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3722 set_option_value(&client
->pinentry
->path
, value
);
3723 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3724 set_option_value(&client
->pinentry
->title
, value
);
3725 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3726 set_option_value(&client
->pinentry
->prompt
, value
);
3727 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3728 set_option_value(&client
->pinentry
->desc
, value
);
3729 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0) {
3739 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3741 MUTEX_LOCK(&rcfile_mutex
);
3742 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
:
3743 "global", "pinentry_timeout", n
);
3744 MUTEX_UNLOCK(&rcfile_mutex
);
3747 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0) {
3748 rc
= parse_opt_pinentry(client
, (gpointer
)value
);
3756 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3757 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3758 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3759 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3760 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3761 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3762 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3763 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3764 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3765 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3766 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3767 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3768 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3769 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3770 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3771 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3772 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3773 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3774 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0)
3775 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3776 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0)
3777 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_NOT_IMPLEMENTED
);
3780 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
3786 static gint
unset_command(assuan_context_t ctx
, gchar
*line
)
3788 log_write2("ARGS=\"%s\"", line
);
3789 return send_error(ctx
, set_unset_common(ctx
, line
, NULL
));
3792 static gint
set_command(assuan_context_t ctx
, gchar
*line
)
3794 gchar name
[64] = {0}, value
[256] = {0};
3796 log_write2("ARGS=\"%s\"", line
);
3798 if (sscanf(line
, " %63[_a-zA-Z] = %255c", name
, value
) != 2)
3799 return send_error(ctx
, gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
));
3801 return send_error(ctx
, set_unset_common(ctx
, name
, value
));
3804 static gint
rename_command(assuan_context_t ctx
, gchar
*line
)
3806 struct client_s
*client
= assuan_get_pointer(ctx
);
3808 gchar
**req
, **src
, *dst
;
3811 log_write2("ARGS=\"%s\"", line
);
3812 req
= split_input_line(line
, " ", -1);
3814 if (!req
|| !req
[0] || !req
[1]) {
3816 return send_error(ctx
, GPG_ERR_SYNTAX
);
3820 is_literal_element(&dst
);
3822 if (!valid_xml_element((xmlChar
*)dst
)) {
3824 return GPG_ERR_INV_VALUE
;
3827 if (strchr(req
[0], '\t'))
3828 src
= split_input_line(req
[0], "\t", -1);
3830 src
= split_input_line(req
[0], " ", -1);
3832 if (!src
|| !*src
) {
3833 rc
= GPG_ERR_SYNTAX
;
3837 n
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3840 n
= find_elements(client
->doc
, n
->children
, src
+1, &rc
, NULL
, NULL
,
3841 NULL
, FALSE
, 0, NULL
, FALSE
);
3847 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
3850 rc
= GPG_ERR_ENOMEM
;
3854 /* To prevent unwanted effects:
3856 * <root name="a"><b/></root>
3860 if (xmlStrEqual(a
, (xmlChar
*)dst
)) {
3862 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3872 for (p
= src
; *p
; p
++) {
3876 strv_printf(&tmp
, "%s", *p
);
3880 strv_printf(&tmp
, "!%s", dst
);
3881 ndst
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
3883 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
3889 ndst
= find_elements(client
->doc
, ndst
->children
, tmp
+1, &rc
, NULL
,
3890 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3894 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3899 /* Target may exist:
3902 * <root name="b" target="a"/>
3910 rc
= GPG_ERR_AMBIGUOUS_NAME
;
3916 xmlFreeNodeList(ndst
);
3919 rc
= add_attribute(n
, "_name", dst
);
3924 return send_error(ctx
, rc
);
3927 static gint
copy_command(assuan_context_t ctx
, gchar
*line
)
3929 struct client_s
*client
= assuan_get_pointer(ctx
);
3931 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3932 xmlNodePtr nsrc
, ndst
, new = NULL
;
3934 log_write2("ARGS=\"%s\"", line
);
3935 req
= split_input_line(line
, " ", -1);
3937 if (!req
|| !req
[0] || !req
[1]) {
3939 return send_error(ctx
, GPG_ERR_SYNTAX
);
3942 if (strchr(req
[0], '\t'))
3943 src
= split_input_line(req
[0], "\t", -1);
3945 src
= split_input_line(req
[0], " ", -1);
3947 if (!src
|| !*src
) {
3948 rc
= GPG_ERR_SYNTAX
;
3952 if (strchr(req
[1], '\t'))
3953 dst
= split_input_line(req
[1], "\t", -1);
3955 dst
= split_input_line(req
[1], " ", -1);
3957 if (!dst
|| !*dst
) {
3958 rc
= GPG_ERR_SYNTAX
;
3962 if (!valid_element_path(dst
, FALSE
)) {
3963 rc
= GPG_ERR_INV_VALUE
;
3967 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3969 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3970 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
3975 new = xmlCopyNodeList(nsrc
);
3977 rc
= GPG_ERR_ENOMEM
;
3981 gboolean create
= FALSE
;
3982 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3983 if (ndst
&& dst
[1]) {
3985 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3986 NULL
, create_target_elements_cb
, FALSE
, 0, NULL
, FALSE
);
3993 if (!ndst
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
3996 ndst
= create_element_path(client
, &dst
, &rc
, NULL
);
4001 /* Merge any attributes from the src node to the initial dst node. */
4002 for (xmlAttrPtr attr
= new->properties
; attr
; attr
= attr
->next
) {
4003 if (xmlStrEqual(attr
->name
, (xmlChar
*)"_name"))
4006 xmlAttrPtr a
= xmlHasProp(ndst
, attr
->name
);
4010 xmlChar
*tmp
= xmlNodeGetContent(attr
->children
);
4011 xmlNewProp(ndst
, attr
->name
, tmp
);
4013 rc
= add_attribute(ndst
, NULL
, NULL
);
4016 xmlNodePtr n
= ndst
->children
;
4019 ndst
->children
= NULL
;
4021 if (new->children
) {
4022 n
= xmlCopyNodeList(new->children
);
4024 rc
= GPG_ERR_ENOMEM
;
4028 n
= xmlAddChildList(ndst
, n
);
4030 rc
= GPG_ERR_ENOMEM
;
4034 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
) ==
4035 ndst
->parent
? ndst
: ndst
->parent
);
4041 xmlFreeNodeList(new);
4053 return send_error(ctx
, rc
);
4056 static gint
move_command(assuan_context_t ctx
, gchar
*line
)
4058 struct client_s
*client
= assuan_get_pointer(ctx
);
4060 gchar
**req
, **src
= NULL
, **dst
= NULL
;
4061 xmlNodePtr nsrc
, ndst
= NULL
;
4063 log_write2("ARGS=\"%s\"", line
);
4064 req
= split_input_line(line
, " ", -1);
4066 if (!req
|| !req
[0] || !req
[1]) {
4068 return send_error(ctx
, GPG_ERR_SYNTAX
);
4071 if (strchr(req
[0], '\t'))
4072 src
= split_input_line(req
[0], "\t", -1);
4074 src
= split_input_line(req
[0], " ", -1);
4076 if (!src
|| !*src
) {
4077 rc
= GPG_ERR_SYNTAX
;
4081 if (strchr(req
[1], '\t'))
4082 dst
= split_input_line(req
[1], "\t", -1);
4084 dst
= split_input_line(req
[1], " ", -1);
4086 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
4089 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
4090 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
4096 if (!valid_element_path(dst
, FALSE
)) {
4097 rc
= GPG_ERR_INV_VALUE
;
4101 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
4104 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
4105 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
4108 ndst
= xmlDocGetRootElement(client
->doc
);
4110 for (xmlNodePtr n
= ndst
; n
; n
= n
->parent
) {
4112 rc
= GPG_ERR_CONFLICT
;
4117 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
4123 xmlChar
*a
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
4124 xmlNodePtr dup
= find_element(ndst
->children
, (gchar
*)a
, NULL
);
4132 if (ndst
== xmlDocGetRootElement(client
->doc
)) {
4133 xmlNodePtr n
= nsrc
;
4134 gboolean match
= FALSE
;
4136 while (n
->parent
&& n
->parent
!= ndst
)
4139 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
4140 xmlChar
*b
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
4142 if (xmlStrEqual(a
, b
)) {
4144 xmlUnlinkNode(nsrc
);
4154 xmlFreeNodeList(dup
);
4163 xmlChar
*name
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
4165 if (nsrc
->parent
== xmlDocGetRootElement(client
->doc
)
4166 && !g_strcmp0((gchar
*)name
, *dst
)) {
4168 rc
= GPG_ERR_CONFLICT
;
4173 ndst
= create_element_path(client
, &dst
, &rc
, nsrc
);
4179 update_element_mtime(nsrc
->parent
);
4180 xmlUnlinkNode(nsrc
);
4181 ndst
= xmlAddChildList(ndst
, nsrc
);
4184 rc
= GPG_ERR_ENOMEM
;
4186 update_element_mtime(ndst
->parent
);
4198 return send_error(ctx
, rc
);
4201 static int ls_command(assuan_context_t ctx
, gchar
*line
)
4203 log_write2("ARGS=\"%s\"", line
);
4205 gchar
*tmp
= g_key_file_get_string(keyfileh
, "global", "data_directory", NULL
);
4206 gchar
*dir
= expand_homedir(tmp
);
4207 DIR *d
= opendir(dir
);
4209 rc
= gpg_error_from_syserror();
4214 return send_error(ctx
, rc
);
4217 size_t len
= offsetof(struct dirent
, d_name
)+pathconf(dir
, _PC_NAME_MAX
)+1;
4218 struct dirent
*p
= g_malloc(len
), *cur
= NULL
;
4224 while (!readdir_r(d
, p
, &cur
) && cur
) {
4225 if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '\0')
4227 else if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '.' && cur
->d_name
[2] == '\0')
4230 tmp
= g_strdup_printf("%s%s\n", list
? list
: "", cur
->d_name
);
4236 rc
= GPG_ERR_ENOMEM
;
4248 return send_error(ctx
, rc
);
4251 return send_error(ctx
, GPG_ERR_NO_VALUE
);
4253 list
[strlen(list
)-1] = 0;
4254 rc
= xfer_data(ctx
, list
, strlen(list
));
4256 return send_error(ctx
, rc
);
4259 static void bye_notify(assuan_context_t ctx
)
4261 struct client_s
*cl
= assuan_get_pointer(ctx
);
4263 /* This will let assuan_process_next() return. */
4264 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
4265 cl
->last_rc
= 0; // BYE command result
4268 static void reset_notify(assuan_context_t ctx
)
4270 struct client_s
*cl
= assuan_get_pointer(ctx
);
4277 * This is called before every Assuan command.
4279 gint
command_startup(assuan_context_t ctx
, const gchar
*name
)
4281 struct client_s
*cl
= assuan_get_pointer(ctx
);
4284 log_write1("%s", name
);
4286 for (int i
= 0; command_table
[i
]; i
++) {
4287 if (!g_ascii_strcasecmp(name
, command_table
[i
]->name
) &&
4288 command_table
[i
]->ignore_startup
)
4292 #ifdef WITH_PINENTRY
4293 if (!(cl
->opts
& OPT_PINENTRY
))
4294 reset_pin_defaults(cl
->pinentry
);
4297 cl
->last_rc
= rc
= file_modified(cl
);
4300 if ((rc
== EPWMD_NO_FILE
|| rc
== EPWMD_FILE_MODIFIED
) &&
4301 !g_ascii_strcasecmp(name
, "OPEN"))
4309 * This is called after every Assuan command.
4311 void command_finalize(assuan_context_t ctx
, gint rc
)
4313 struct client_s
*client
= assuan_get_pointer(ctx
);
4315 if (!client
->is_lock_cmd
)
4316 unlock_file_mutex(client
);
4318 log_write1(_("command completed (rc=%u)"), client
->last_rc
);
4319 client
->opts
&= ~(OPT_INQUIRE
);
4322 static gint
help_command(assuan_context_t ctx
, gchar
*line
)
4327 if (!line
|| !*line
) {
4329 gchar
*buf
= g_strdup(_(
4330 "Usage: HELP [<COMMAND>]\n"
4331 " For commands that take an element path as an argument, each element is\n"
4332 " separated with an ASCII tab character (ASCII 0x09).\n"
4334 " Each element may contain a \"target\" attribute whose value is also an\n"
4335 " element path. Think of a \"target\" attribute like a symbolic link on a\n"
4336 " filesystem. When found, the element path of the \"target\" attribute will\n"
4337 " be used as a prefix for further elements in the current element path. To\n"
4338 " ignore any \"target\" attribute for the current element, prefix the element\n"
4339 " with an ! (ASCII 0x21).\n"
4341 " See pwmd(1) for configuration file options which may also set default\n"
4342 " options for specific data files.\n"
4346 for (i
= 0; command_table
[i
]; i
++) {
4347 gchar
*p
= strrchr(buf
, '\n');
4348 gboolean newline
= FALSE
;
4350 if (!command_table
[i
]->help
)
4353 if (p
&& strlen(p
)+strlen(command_table
[i
]->name
) > 79) {
4354 tmp
= g_strdup_printf("%s\n", buf
);
4360 tmp
= g_strdup_printf("%s%s%s", buf
, !newline
? " " : "",
4361 command_table
[i
]->name
);
4366 tmp
= g_strdup_printf("%s\n", buf
);
4369 rc
= xfer_data(ctx
, buf
, strlen(buf
));
4371 return send_error(ctx
, rc
);
4374 for (i
= 0; command_table
[i
]; i
++) {
4375 if (!g_strcasecmp(line
, command_table
[i
]->name
)) {
4376 if (!command_table
[i
]->help
)
4379 gchar
*tmp
= g_strdup_printf(_("Usage: %s"), command_table
[i
]->help
);
4380 rc
= xfer_data(ctx
, tmp
, strlen(tmp
));
4382 return send_error(ctx
, rc
);
4386 return send_error(ctx
, GPG_ERR_INV_NAME
);
4389 void new_command(const gchar
*name
, gboolean ignore
,
4390 gint (*handler
)(assuan_context_t
, gchar
*), const gchar
*help
)
4395 for (i
= 0; command_table
[i
]; i
++);
4397 command_table
= g_realloc(command_table
, (i
+2)*sizeof(struct command_table_s
*));
4398 command_table
[i
] = g_malloc0(sizeof(struct command_table_s
));
4399 command_table
[i
]->name
= name
;
4400 command_table
[i
]->handler
= handler
;
4401 command_table
[i
]->ignore_startup
= ignore
;
4402 command_table
[i
++]->help
= help
;
4403 command_table
[i
] = NULL
;
4406 void deinit_commands()
4410 for (i
= 0; command_table
[i
]; i
++)
4411 g_free(command_table
[i
]);
4413 g_free(command_table
);
4416 static gint
sort_commands(const void *arg1
, const void *arg2
)
4418 struct command_table_s
* const *a
= arg1
;
4419 struct command_table_s
* const *b
= arg2
;
4428 return g_strcmp0((*a
)->name
, (*b
)->name
);
4431 void init_commands()
4433 /* !BEGIN-HELP-TEXT!
4435 * This comment is used as a marker to generate the offline documentation
4436 * for commands found in doc/COMMANDS.
4438 new_command("HELP", TRUE
, help_command
, _(
4439 "HELP [<COMMAND>]\n"
4440 " Show available commands or command specific help text.\n"
4443 new_command("OPEN", FALSE
, open_command
, _(
4444 "OPEN [--lock] [--inquire | --pinentry=[0|1]] <filename> [<key>]\n"
4445 " Opens <filename> using <key>. When the filename is not found on the\n"
4446 " file-system a new document will be created. If the file is found, it is\n"
4447 " looked for in the file cache for an existing key. When found and no key\n"
4448 " was specified, the cached key will be used for decryption (if encrypted).\n"
4449 " When not found, pinentry(1) will be used to retrieve the key (see the\n"
4450 " OPTIONS documentation).\n"
4452 " When the --lock option is passed then the file mutex will be locked as if\n"
4453 " the LOCK command had been sent after the file had been opened.\n"
4455 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4456 " retrieve the filename and key arguments.\n"
4458 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4459 " specifying the --pinentry option with the value 1 or 0 respectively. When\n"
4460 " no value is specified then the configuration file value will be used. If\n"
4461 " the passphrase is invalid then it is up to the client whether to retry or\n"
4462 " not. To decrypt an encrypted file with an empty passphrase and avoid the\n"
4463 " pinentry dialog, use --pinentry=0.\n"
4465 " When a \"key_file\" configuration parameter has been set for the current\n"
4466 " file and there is no cache entry, then an --inquire must be used to\n"
4467 " retrieve the key.\n"
4470 new_command("SAVE", FALSE
, save_command
, _(
4471 "SAVE [--reset] [--inquire | --pinentry=[0|1]] [--cipher=[<string>]]\n"
4472 " [--iterations=[N]] [<key>]\n"
4473 " Writes the XML document to disk. The file written to is the file that was\n"
4474 " opened using the OPEN command. If <key> is not specified then the\n"
4475 " currently cached key will be used. If the file is a new file or the file\n"
4476 " is not found in the file cache then <key> will be used. If both <key> is\n"
4477 " not specified and the file is not cached then pinentry(1) will be used to\n"
4478 " retrieve the key (see below) unless the configured number of iterations is\n"
4479 " 0 in which case the file will be saved unencrypted.\n"
4481 " Note that when both <key> is specified and the configured number of\n"
4482 " iterations is 0 the iterations for the current filename will be reset to\n"
4483 " 1. This is to be on the safe side and prevent misuse.\n"
4485 " The --iterations option can be used to change the number of encryption\n"
4486 " iterations for the opened file. When 0 no encryption will be performed.\n"
4487 " When this option is either not passed or is specified without a value then\n"
4488 " the previous setting obtained from the file header will be used.\n"
4490 " You can specify an alternate cipher to encrypt with by specifying a cipher\n"
4491 " string with the --cipher option. Omitting the string uses the current\n"
4492 " cipher of the opened file or the default if the file is a new one. The\n"
4493 " default is specified in the configuration file. See pwmd(1) for available\n"
4496 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4497 " specifying the --pinentry option with the value 1 or 0, respectively. When\n"
4498 " no value is specified then the configuration file value will be used.\n"
4499 " When enabled and the passphrase confirmation fails, the pinentry process\n"
4500 " is started over again until either the passphrases match or until the\n"
4501 " input is canceled by the user. To save with encryption and with an empty\n"
4502 " passphrase, use --pinentry=0.\n"
4504 " When --reset is specified then the cached passphrase for the opened file\n"
4505 " will be cleared before doing the actual SAVE as if the CLEARCACHE command\n"
4508 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4509 " retrieve the key.\n"
4511 " When a \"key_file\" configuration parameter has been set for the current\n"
4512 " file and there is no cache entry, then an --inquire must be used to\n"
4513 " retrieve the key.\n"
4516 new_command("ISCACHED", TRUE
, iscached_command
, _(
4517 "ISCACHED <filename>\n"
4518 " An OK response is returned if the specified file is found in the file\n"
4519 " cache. If not found in the cache but exists on the filesystem,\n"
4520 " GPG_ERR_NOT_FOUND is returned. Otherwise a filesystem error is returned.\n"
4523 new_command("CLEARCACHE", TRUE
, clearcache_command
, _(
4524 "CLEARCACHE [<filename>]\n"
4525 " Clears a file cache entry. This will forget the timeout and key for all or\n"
4526 " the specified file. Always returns an OK response.\n"
4529 new_command("CACHETIMEOUT", TRUE
, cachetimeout_command
, _(
4530 "CACHETIMEOUT <filename> <seconds>\n"
4531 " Specify the number of seconds the specified file will be cached. -1 will\n"
4532 " keep the cache entry forever, 0 will require the key each time the OPEN or\n"
4533 " SAVE commands are used. Also see the \"cache_timeout\" configuration\n"
4534 " parameter. Returns ERR if the filename is not cached or if the timeout is\n"
4535 " invalid. OK otherwise.\n"
4538 new_command("LIST", FALSE
, list_command
, _(
4539 "LIST [--no-recurse] [--verbose] [[!]element[<TAB>[!]element[...]]]\n"
4540 " If no element path is given then a newline separated list of root elements\n"
4541 " is returned with the data response. If given, then all reachable elements\n"
4542 " for the specified element path are returned unless the --no-recurse option\n"
4543 " is specified. If specified, only the child elements of the element path\n"
4544 " are returned without recursing into grandchildren. Each element in the\n"
4545 " path is prefixed with the literal '!' character when the element contains\n"
4546 " no \"target\" attribute. Refer to THE TARGET ATTRIBUTE for more information.\n"
4548 " When the --verbose option is passed then each element path returned in the\n"
4549 " list will have a single space character followed by either a 0 or 1\n"
4550 " appended to it. When 0, the element path has no children, otherwise it\n"
4551 " does have children. When used with the --no-recurse option this may be\n"
4552 " useful to limit the amount of data transferred to the client.\n"
4555 new_command("REALPATH", FALSE
, realpath_command
, _(
4556 "REALPATH [!]element[<TAB>[!]element[...]]\n"
4557 " Resolves all \"target\" attributes of the specified element path and returns\n"
4558 " the result with a data response.\n"
4561 new_command("STORE", FALSE
, store_command
, _(
4562 "STORE [!]element[[<TAB>[!]element[...]]<TAB>[content]]\n"
4563 " Creates a new element path or modifies the content of an existing element\n"
4564 " path. If only a single element is specified, a new root element is\n"
4565 " created. Otherwise, elements are TAB delimited and the content will be set\n"
4566 " to the last TAB delimited argument. If no content is specified after the\n"
4567 " last TAB then the content for the last specified element will be removed,\n"
4568 " or empty when creating a new element.\n"
4570 " The only restriction of an element name is that it not contain whitespace\n"
4571 " or begin with the literal element character '!' unless specifying a\n"
4572 " literal element. There is no whitespace between the TAB delimited\n"
4573 " elements. It is recommended that the value or content be base64 encoded\n"
4574 " when it contains control or TAB characters to prevent XML and pwmd parsing\n"
4577 " This command uses a server INQUIRE to retrieve the data from the client.\n"
4580 new_command("RENAME", FALSE
, rename_command
, _(
4581 "RENAME [!]element[<TAB>[!]element[...]] <value>\n"
4582 " Renames the specified element to the new value. If an element of the same\n"
4583 " name as the value exists then it will be overwritten.\n"
4586 new_command("COPY", FALSE
, copy_command
, _(
4587 "COPY [!]element[<TAB>[!]element[...]] [!]element[<TAB>[!]element[...]]\n"
4588 " Copies the entire element tree starting from the child node of the source\n"
4589 " element path, to the destination element path. If the destination element\n"
4590 " path does not exist then it will be created; otherwise it is overwritten.\n"
4592 " Note that attributes from the source element path are merged into the\n"
4593 " destination element path when the destination element path exists. When an\n"
4594 " attribute of the same name exists in both the source and destination\n"
4595 " element paths then the destination attribute will be updated to the source\n"
4596 " attribute value.\n"
4599 new_command("MOVE", FALSE
, move_command
, _(
4600 "MOVE [!]element[<TAB>[!]element[...]] [[!]element[<TAB>[!]element[...]]]\n"
4601 " Moves the source element path to the destination element path. If the\n"
4602 " destination is not specified then it will be moved to the root of the\n"
4603 " document. If the destination is specified and exists then it will be\n"
4604 " overwritten; otherwise it will be created.\n"
4607 new_command("DELETE", FALSE
, delete_command
, _(
4608 "DELETE [!]element[<TAB>[!]element[...]]\n"
4609 " Removes the specified element path and any children from the XML document.\n"
4612 new_command("GET", FALSE
, get_command
, _(
4613 "GET [!]element[<TAB>[!]element[...]]\n"
4614 " Retrieves the content or XML text node of the specified element path. The\n"
4615 " content is returned with a data response.\n"
4618 new_command("ATTR", FALSE
, attr_command
, _(
4619 "ATTR SET|GET|DELETE|LIST [<attribute>] [!]<arg1> [!][arg2]\n"
4620 " ATTR SET attribute [!]element[<TAB>[!]element[...]] [attribute_value]\n"
4621 " Stores or updates an attribute name and optional value of an element\n"
4624 " ATTR DELETE attribute [!]element[<TAB>[!]element[...]]\n"
4625 " Removes an attribute from an element path.\n"
4627 " ATTR LIST [!]element[<TAB>[!]element[...]]\n"
4628 " Retrieves a newline separated list of attributes names and values from\n"
4629 " the specified element path. The attribute names and values are space\n"
4632 " ATTR GET attribute [!]element[<TAB>[!]element[...]]\n"
4633 " Retrieves the value of an attribute from an element path.\n"
4635 " The \"_name\" attribute (case sensitive) cannot be removed with ATTR DELETE\n"
4636 " if the element path is the root element. Although it can be SET to change\n"
4637 " the element name but only if the destination element name doesn't exist.\n"
4638 " Use the RENAME command for that instead.\n"
4640 " The \"_mtime\" attribute is updated each time an element is modified by\n"
4641 " either storing content, editing attributes or by deleting a child element.\n"
4643 " Also see THE TARGET ATTRIBUTE.\n"
4646 new_command("XPATH", FALSE
, xpath_command
, _(
4647 "XPATH <expression>[<TAB>[value]]\n"
4648 " Evaluates an XPath expression. If no value argument is specified, it is\n"
4649 " assumed the expression is a request to return a result. Otherwise, the\n"
4650 " result is set to the value argument and the document is updated. If there\n"
4651 " is no value after the <TAB> character, the value is assumed to be empty\n"
4652 " and the document is updated.\n"
4655 new_command("XPATHATTR", FALSE
, xpathattr_command
, _(
4656 "XPATHATTR SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
4657 " Like the XPATH command but operates on element attributes and won't return\n"
4658 " a result. For the SET operation the <value> is optional but the field is\n"
4659 " required in which case the value will be empty.\n"
4662 new_command("IMPORT", FALSE
, import_command
, _(
4663 "IMPORT <content>[<TAB>[!]element[<TAB>[!]element[...]]]\n"
4664 " Like the STORE command (an INQUIRE), but the content argument is raw XML\n"
4665 " data. The content is created as a child of the specified element path. If\n"
4666 " an element of the element path does not exist then it is created. If no\n"
4667 " element path is specified then the content must begin with an pwmd DTD\n"
4670 " Note that the new content must begin with an XML element node. Also note\n"
4671 " that an existing child node of the same element name as the root node of\n"
4672 " the imported content will be overwritten.\n"
4675 new_command("DUMP", FALSE
, dump_command
, _(
4677 " Shows the in memory XML document with indenting. To dump a specific\n"
4678 " element tree, use the XPATH command.\n"
4681 new_command("LOCK", FALSE
, lock_command
, _(
4683 " Locks the mutex associated with the opened file. This prevents other\n"
4684 " clients from sending commands to the same opened file until the client\n"
4685 " that sent this command either disconnects or sends the UNLOCK command.\n"
4688 new_command("UNLOCK", FALSE
, unlock_command
, _(
4690 " Unlocks the file mutex which was locked with the LOCK command.\n"
4693 new_command("GETPID", TRUE
, getpid_command
, _(
4695 " Retrieves the process id of the server.\n"
4698 new_command("GETCONFIG", TRUE
, getconfig_command
, _(
4699 "GETCONFIG [filename] <parameter>\n"
4700 " Returns the value of a pwmd configuration variable with a data response.\n"
4701 " If no file has been opened then the value for the specified file or the\n"
4702 " default from the \"global\" section will be returned. If a file has been\n"
4703 " opened and no filename is specified, the value previously set with the SET\n"
4704 " command, if any, will be returned.\n"
4706 " If there is no such configuration parameter defined, GPG_ERR_UNKNOWN_OPTION\n"
4710 new_command("VERSION", TRUE
, version_command
, _(
4712 " Returns the server version number and compile-time features with a data\n"
4713 " response with each being space delimited.\n"
4716 new_command("SET", TRUE
, set_command
, _(
4717 "SET <NAME>=<VALUE>\n"
4718 " Sets a client option NAME to VALUE. Use the UNSET command to reset an\n"
4719 " option to its default value.\n"
4721 " NAME |VALUE |Description\n"
4722 " -----------------|----------|----------------------------------------------\n"
4723 " ENABLE_PINENTRY 0|1 When 0, disable use of pinentry. The default\n"
4726 " * Deprecated. Pass --pinentry to the OPEN and\n"
4727 " SAVE commands instead.\n"
4729 " PINENTRY_TIMEOUT <integer> The number of seconds before the pinentry\n"
4730 " process will terminate while waiting for a\n"
4731 " passphrase. The default is 20, 0 disables.\n"
4733 " PINENTRTY_PATH <string> Full path to the pinentry binary. The default\n"
4734 " is specified at compile time.\n"
4736 " TTYNAME <string> Same as the --ttyname option to pinentry(1).\n"
4738 " TTYTYPE <string> Same as the --ttytype option to pinentry(1).\n"
4740 " DISPLAY <string> Same as the --display option to pinentry(1).\n"
4742 " TITLE <string> Sets the title string of the pinentry dialog.\n"
4744 " PROMPT <string> Sets the prompt string of the pinentry dialog.\n"
4746 " DESC <string> Sets the error or description string of the\n"
4747 " pinentry dialog.\n"
4749 " LC_CTYPE <string> Same as the --lc-ctype option to pinentry(1).\n"
4751 " LC_MESSAGES <string> Same as the --lc-messages option to\n"
4754 " NAME <string> Associates the thread ID of the connection\n"
4755 " with the specified textual representation.\n"
4756 " Useful for debugging log messages.\n"
4758 " CIPHER <string> The cipher to use for the next SAVE.\n"
4760 " * Deprecated. Use --cipher instead.\n"
4762 " ITERATIONS <integer> The number of encryption iterations to do\n"
4763 " when the SAVE command is sent. An opened file\n"
4764 " is needed when setting this option. The\n"
4765 " CONFIG status message is sent after receiving\n"
4768 " * Deprecated. Use --iterations instead.\n"
4770 " LOCK_ON_OPEN 0|1 If enabled then the file mutex will be locked\n"
4771 " after a successful OPEN as if the LOCK\n"
4772 " command had been sent.\n"
4774 " * Deprecated. Use --lock instead.\n"
4776 " RC_ON_LOCKED 0|1 If enabled then return an error code instead\n"
4777 " of a status message when the file mutex is\n"
4778 " locked by another client.\n"
4781 new_command("UNSET", TRUE
, unset_command
, _(
4783 " Resets option NAME to the value specified in the server configuration\n"
4784 " file. Some options have no default and will be reset to NULL or 0\n"
4785 " depending on the value type. See the SET command for available options.\n"
4788 new_command("LS", TRUE
, ls_command
, _(
4790 " Lists the contents of the configured data_directory. The result is a\n"
4791 " newline separated list of filenames.\n"
4794 new_command("RESET", TRUE
, NULL
, _(
4796 " Closes the currently opened file but keeps any previously set client\n"
4800 new_command("BYE", TRUE
, NULL
, _(
4802 " Closes the connection discarding any unsaved changes.\n"
4805 new_command("NOP", TRUE
, NULL
, _(
4807 " Does nothing. Always returns successfully.\n"
4810 /* !END-HELP-TEXT! */
4811 new_command("CANCEL", TRUE
, NULL
, NULL
);
4812 new_command("END", TRUE
, NULL
, NULL
);
4815 for (i
= 0; command_table
[i
]; i
++);
4816 qsort(command_table
, i
-1, sizeof(struct command_table_s
*), sort_commands
);
4819 gpg_error_t
register_commands(assuan_context_t ctx
)
4823 for (; command_table
[i
]; i
++) {
4824 if (!command_table
[i
]->handler
)
4827 rc
= assuan_register_command (ctx
, command_table
[i
]->name
,
4828 command_table
[i
]->handler
);
4834 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
4839 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
4844 rc
= assuan_register_pre_cmd_notify(ctx
, command_startup
);
4849 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
4852 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
,
4853 struct crypto_s
*crypto
, gpointer
*dst
, goffset
*dst_len
)
4855 goffset insize
, len
;
4856 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
4857 guint64 iter
= 0, n_iter
= 0, iter_progress
= 0;
4860 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->ver
.fh1
) : sizeof(crypto
->fh
->ver
.fh2
);
4861 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->ver
.fh1
.iter
: crypto
->fh
->ver
.fh2
.iter
;
4863 if (!crypto
->fh
->v1
&& crypto
->fh
->ver
.fh2
.version
< 0x221)
4864 fh_size
-= sizeof(crypto
->fh
->ver
.fh2
.salt
);
4866 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
4867 insize
= crypto
->fh
->st
.st_size
- fh_size
;
4868 crypto
->iv
= gcry_malloc(crypto
->blocksize
);
4871 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4872 return GPG_ERR_ENOMEM
;
4876 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh1
.iv
, crypto
->blocksize
);
4878 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
4880 crypto
->inbuf
= gcry_malloc(insize
);
4882 if (!crypto
->inbuf
) {
4883 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4884 return GPG_ERR_ENOMEM
;
4887 crypto
->insize
= insize
;
4888 len
= pth_read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
4890 if (len
!= crypto
->insize
)
4891 return GPG_ERR_INV_LENGTH
;
4893 /* No encryption iterations. This is a plain (gzipped) file. */
4894 if ((crypto
->fh
->v1
&& (long)fh_iter
< 0L) ||
4895 (!crypto
->fh
->v1
&& fh_iter
<= 0L)) {
4897 * cache_file_count() needs both .used == TRUE and a valid key in
4898 * order for it to count as a used cache entry. Fixes CACHE status
4901 memset(crypto
->key
, '!', KEYSIZE
);
4905 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4906 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4910 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
4911 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4915 iter_progress
= get_key_file_uint64(client
&& client
->filename
?
4916 client
->filename
: "global", "iteration_progress");
4918 if (iter_progress
> 0 && fh_iter
>= iter_progress
) {
4919 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
4925 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4930 crypto
->tkey
= gcry_malloc(KEYSIZE
);
4932 if (!crypto
->tkey
) {
4933 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
4934 return GPG_ERR_ENOMEM
;
4937 memcpy(crypto
->tkey
, crypto
->key
, KEYSIZE
);
4938 guchar
*tkey
= crypto
->tkey
;
4941 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
4942 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4946 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
4947 if (iter_progress
> 0ULL && iter
>= iter_progress
) {
4948 if (!(iter
% iter_progress
)) {
4949 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
4950 ++n_iter
* iter_progress
, fh_iter
);
4957 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
4958 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4962 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
4965 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, pwmd_strerror(rc
));
4972 if (iter_progress
&& fh_iter
>= iter_progress
) {
4973 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
4980 if (!crypto
->fh
->v1
&& crypto
->fh
->ver
.fh2
.version
>= 0x218) {
4983 if (crypto
->fh
->ver
.fh2
.iter
> 0ULL) {
4984 if (memcmp(crypto
->inbuf
, crypto_magic
, sizeof(crypto_magic
)))
4985 return GPG_ERR_INV_PASSPHRASE
;
4987 len
= sizeof(crypto_magic
);
4990 rc
= do_decompress(ctx
, (guchar
*)crypto
->inbuf
+len
, crypto
->insize
-len
,
4991 (gpointer
*)&crypto
->outbuf
, &outsize
);
4997 rc
= do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
4998 (gpointer
*)&crypto
->outbuf
, &outsize
);
5000 if (rc
== GPG_ERR_ENOMEM
)
5003 return GPG_ERR_INV_PASSPHRASE
; // Not a valid gzip header. Must be a bad key.
5005 if (g_strncasecmp(crypto
->outbuf
, "<?xml ", 6) != 0) {
5006 gcry_free(crypto
->outbuf
);
5007 crypto
->outbuf
= NULL
;
5008 return GPG_ERR_INV_PASSPHRASE
;
5013 client
->xml
= crypto
->outbuf
;
5014 client
->len
= outsize
;
5015 crypto
->outbuf
= NULL
;
5018 *dst
= crypto
->outbuf
;
5020 crypto
->outbuf
= NULL
;
5023 /* The calling function should free the crypto struct. */