1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
24 #include <sys/types.h>
44 #include "pwmd_error.h"
57 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
59 return gcry_calloc(items
, size
);
62 static void z_free(void *data
, void *p
)
67 static gpg_error_t
file_modified(struct client_s
*client
)
72 if (client
->state
!= STATE_OPEN
)
75 rc
= lock_file_mutex(client
);
80 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
81 if (client
->mtime
!= st
.st_mtime
)
82 return EPWMD_FILE_MODIFIED
;
89 static gpg_error_t
parse_xml(assuan_context_t ctx
)
91 struct client_s
*client
= assuan_get_pointer(ctx
);
93 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
96 return EPWMD_LIBXML_ERROR
;
101 void unlock_file_mutex(struct client_s
*client
)
106 if (client
->has_lock
== FALSE
|| client
->pinentry
->status
!= PINENTRY_NONE
)
108 if (client
->has_lock
== FALSE
)
112 CACHE_LOCK(client
->ctx
);
114 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
121 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
124 gpg_error_t
lock_file_mutex(struct client_s
*client
)
129 if (client
->has_lock
== TRUE
)
132 CACHE_LOCK(client
->ctx
);
134 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
140 MUTEX_TRYLOCK(client
->ctx
, m
, rc
);
143 client
->has_lock
= TRUE
;
148 void free_client(struct client_s
*client
)
151 xmlFreeDoc(client
->doc
);
154 gcry_free(client
->xml
);
156 if (client
->filename
)
157 g_free(client
->filename
);
160 cleanup_crypto(&client
->crypto
);
162 if (client
->xml_error
)
163 xmlResetError(client
->xml_error
);
166 void cleanup_client(struct client_s
*client
)
168 assuan_context_t ctx
= client
->ctx
;
169 struct client_thread_s
*thd
= client
->thd
;
170 gboolean has_lock
= client
->has_lock
;
172 struct pinentry_s
*pin
= client
->pinentry
;
175 unlock_file_mutex(client
);
176 CACHE_LOCK(client
->ctx
);
177 cache_decr_refcount(client
->md5file
);
180 * This may be a new file so don't use a cache slot. save_command() will
181 * set this to FALSE on success.
183 if (client
->new == TRUE
)
184 cache_clear(client
->md5file
, 1);
188 memset(client
, 0, sizeof(struct client_s
));
189 client
->state
= STATE_CONNECTED
;
192 client
->freed
= TRUE
;
194 client
->pinentry
= pin
;
196 client
->has_lock
= has_lock
;
199 static void gz_cleanup(void *arg
)
201 struct gz_s
**gz
= (struct gz_s
**)arg
;
206 if (!(*gz
)->done
&& (*gz
)->out
)
207 gcry_free((*gz
)->out
);
209 if ((*gz
)->which
== STATUS_COMPRESS
) {
211 deflateEnd(&(*gz
)->z
);
215 inflateEnd(&(*gz
)->z
);
222 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
223 gpointer
*out
, gulong
*outsize
, gint
*rc
)
229 gz
= g_malloc0(sizeof(struct gz_s
));
232 *rc
= gpg_error_from_errno(ENOMEM
);
236 pth_cleanup_push(gz_cleanup
, &gz
);
237 gz
->which
= STATUS_DECOMPRESS
;
238 gz
->z
.zalloc
= z_alloc
;
239 gz
->z
.zfree
= z_free
;
241 gz
->z
.avail_in
= (uInt
)insize
;
242 gz
->z
.avail_out
= zlib_bufsize
;
243 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
246 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
252 *rc
= inflateInit2(&gz
->z
, 47);
255 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
260 memset(&h
, 0, sizeof(gz_header
));
261 h
.comment
= (guchar
*)buf
;
262 h
.comm_max
= sizeof(buf
);
263 *rc
= inflateGetHeader(&gz
->z
, &h
);
266 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
271 *rc
= inflate(&gz
->z
, Z_BLOCK
);
274 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
280 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
285 *rc
= inflate(&gz
->z
, Z_FINISH
);
291 if (!gz
->z
.avail_out
) {
292 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
295 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
301 gz
->z
.next_out
= gz
->out
+ gz
->z
.total_out
;
302 gz
->z
.avail_out
= zlib_bufsize
;
303 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
304 gz
->z
.total_out
, insize
);
316 } while (*rc
!= Z_STREAM_END
);
318 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
325 *outsize
= gz
->z
.total_out
;
332 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
337 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
342 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
349 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
350 *rc
= gpg_error_from_errno(ENOMEM
);
354 pth_cleanup_push(g_free
, fh
);
355 fh_size
= v1
? sizeof(fh
->fh1
) : sizeof(fh
->fh2
);
357 if (lstat(filename
, &fh
->st
) == -1) {
358 *rc
= gpg_error_from_syserror();
363 if (!S_ISREG(fh
->st
.st_mode
)) {
364 *rc
= GPG_ERR_ENOANO
;
369 fd
= open(filename
, O_RDONLY
);
372 *rc
= gpg_error_from_errno(errno
);
377 pth_cleanup_push(close
, (void *)fd
);
378 p
= v1
? (void *)&fh
->fh1
: (void *)&fh
->fh2
;
379 len
= pth_read(fd
, p
, fh_size
);
381 if (len
!= fh_size
) {
385 *rc
= gpg_error_from_errno(n
);
396 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*key
,
399 struct client_s
*client
= assuan_get_pointer(ctx
);
404 if (!client
->crypto
->fh
) {
411 rc
= try_xml_decrypt(ctx
, key
, client
->crypto
, NULL
, NULL
);
414 cleanup_client(client
);
415 return send_error(ctx
, rc
);
419 CACHE_LOCK(client
->ctx
);
421 if (cached
== FALSE
) {
422 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
423 cleanup_client(client
);
425 return send_syserror(ctx
, ENOMEM
);
428 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
429 cache_reset_timeout(client
->md5file
, timeout
);
432 cache_set_timeout(client
->md5file
, -2);
440 gcry_free(client
->xml
);
445 if (client
->new == FALSE
)
446 send_status_all(STATUS_CACHE
);
448 client
->state
= STATE_OPEN
;
451 if (!rc
&& client
->new == FALSE
&&
452 client
->crypto
->fh
->fh2
.iter
!= (guint64
)get_key_file_integer(client
->filename
, "iterations")) {
453 MUTEX_LOCK(&rcfile_mutex
);
454 g_key_file_set_integer(keyfileh
, client
->filename
, "iterations",
455 client
->crypto
->fh
->fh2
.iter
);
456 MUTEX_UNLOCK(&rcfile_mutex
);
457 send_status_all(STATUS_CONFIG
);
461 log_write("OPEN '%s'", client
->filename
);
463 cleanup_crypto(&client
->crypto
);
464 return send_error(ctx
, rc
);
467 static void req_cleanup(void *arg
)
472 g_strfreev((gchar
**)arg
);
475 static int open_command(assuan_context_t ctx
, char *line
)
477 gboolean cached
= FALSE
;
479 struct client_s
*client
= assuan_get_pointer(ctx
);
481 gchar
*filename
= NULL
;
483 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
486 pth_cleanup_push(req_cleanup
, req
);
488 if (!filename
|| !*filename
) {
490 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
493 if (valid_filename(filename
) == FALSE
) {
495 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
498 if (client
->state
== STATE_OPEN
)
499 cleanup_client(client
);
501 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
502 CACHE_LOCK(client
->ctx
);
504 if (cache_has_file(client
->md5file
) == FALSE
) {
505 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
508 return send_syserror(ctx
, ENOMEM
);
512 cache_incr_refcount(client
->md5file
);
514 rc
= lock_file_mutex(client
);
518 return send_error(ctx
, rc
);
521 client
->freed
= FALSE
;
522 client
->crypto
= init_client_crypto();
524 if (!client
->crypto
) {
526 cleanup_client(client
);
527 return send_syserror(ctx
, ENOMEM
);
530 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
532 if (!client
->crypto
->key
) {
534 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
535 gpg_error_from_errno(ENOMEM
));
536 cleanup_client(client
);
537 return send_syserror(ctx
, ENOMEM
);
540 memset(client
->crypto
->key
, 0, gcrykeysize
);
541 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
543 if (!client
->crypto
->fh
) {
544 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
545 log_write("%s: %s", filename
, pwmd_strerror(rc
));
547 cleanup_client(client
);
548 return send_error(ctx
, rc
);
552 * New files don't need a key.
554 if ((client
->xml
= new_document()) == NULL
) {
555 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
557 cleanup_client(client
);
558 return send_syserror(ctx
, ENOMEM
);
561 client
->len
= xmlStrlen(client
->xml
);
563 client
->filename
= g_strdup(filename
);
565 if (!client
->filename
) {
567 cleanup_client(client
);
568 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
569 return send_syserror(ctx
, ENOMEM
);
572 if (req
[1] && *req
[1])
573 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
578 client
->pinentry
->filename
= g_strdup(client
->filename
);
580 if (!client
->pinentry
->filename
) {
581 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
582 cleanup_client(client
);
583 return send_syserror(ctx
, ENOMEM
);
586 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
589 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
591 client
->filename
= g_strdup(filename
);
593 if (!client
->filename
) {
594 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
596 cleanup_client(client
);
597 return send_syserror(ctx
, ENOMEM
);
601 client
->pinentry
->filename
= g_strdup(client
->filename
);
603 if (!client
->pinentry
->filename
) {
604 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
606 cleanup_client(client
);
607 return send_syserror(ctx
, ENOMEM
);
611 if (client
->crypto
->fh
->fh2
.iter
<= 0)
614 CACHE_LOCK(client
->ctx
);
615 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
618 if (cached
== FALSE
) {
619 gchar
*tmp
= get_key_file_string(filename
, "key_file");
624 cleanup_client(client
);
625 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
629 * No key specified and no matching filename found in the cache. Use
630 * pinentry to retrieve the key. Cannot return assuan_process_done()
631 * here otherwise the command will be interrupted. The event loop in
632 * client_thread() will poll the file descriptor waiting for it to
633 * become ready to read a pinentry_key_s which will contain the
634 * entered key or an error code. It will then call
635 * open_command_finalize() to to finish the command.
637 if (!req
[1] || !*req
[1]) {
639 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
641 /* From set_pinentry_defaults(). */
642 if (client
->pinentry
->enable
== FALSE
||
643 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
644 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
649 rc
= lock_pin_mutex(client
);
652 unlock_pin_mutex(client
->pinentry
);
653 cleanup_client(client
);
654 return send_error(ctx
, rc
);
657 client
->pinentry
->which
= PINENTRY_OPEN
;
658 rc
= pinentry_fork(ctx
);
661 unlock_pin_mutex(client
->pinentry
);
662 cleanup_client(client
);
663 return send_error(ctx
, rc
);
666 // Called from pinentry iterate.
667 client
->pinentry
->cb
= open_command_finalize
;
668 client
->pinentry
->status
= PINENTRY_INIT
;
671 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
676 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
682 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
685 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
686 gulong size
, gpointer
*out
, gulong
*outsize
, gint
*rc
)
691 gint cmd
= Z_NO_FLUSH
;
693 gz
= g_malloc0(sizeof(struct gz_s
));
696 *rc
= gpg_error_from_errno(ENOMEM
);
700 pth_cleanup_push(gz_cleanup
, &gz
);
701 gz
->which
= STATUS_COMPRESS
;
702 gz
->z
.zalloc
= z_alloc
;
703 gz
->z
.zfree
= z_free
;
704 gz
->z
.next_in
= data
;
705 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
706 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
707 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
710 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
716 *rc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
719 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
724 /* Rather than store the size of the uncompressed data in the file header,
725 * store it in the comment field of the gzip header. Don't give anyone too
726 * much information. Not sure why really, but it seems the right way. :)
728 memset(&h
, 0, sizeof(gz_header
));
729 g_snprintf(buf
, sizeof(buf
), "%li", size
);
730 h
.comment
= (guchar
*)buf
;
731 *rc
= deflateSetHeader(&gz
->z
, &h
);
734 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
742 *rc
= deflate(&gz
->z
, cmd
);
748 if (!gz
->z
.avail_out
) {
749 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
752 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
758 gz
->z
.next_out
= gz
->out
+ gz
->z
.total_out
;
759 gz
->z
.avail_out
= zlib_bufsize
;
762 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
763 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
764 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
766 gz
->z
.avail_in
= zlib_bufsize
;
768 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li",
769 gz
->z
.total_in
, size
);
775 if (gz
->z
.total_in
>= size
)
784 } while (*rc
!= Z_STREAM_END
);
786 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li", gz
->z
.total_in
, size
);
792 *outsize
= gz
->z
.total_out
;
799 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
804 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
806 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
807 struct client_crypto_s
*crypto
, status_msg_t which
)
810 goffset len
= CRYPTO_BLOCKSIZE
;
811 gpointer p
= gcry_malloc(len
);
816 return gpg_err_code_from_errno(ENOMEM
);
818 if (crypto
->insize
< CRYPTO_BLOCKSIZE
)
819 len
= crypto
->insize
;
821 pth_cleanup_push(gcry_free
, p
);
824 inbuf
= crypto
->inbuf
+ total
;
827 if (len
+ total
> crypto
->insize
)
830 if (which
== STATUS_ENCRYPT
)
831 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
833 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
838 tmp
= crypto
->inbuf
+total
;
839 memmove(tmp
, p
, len
);
842 if (total
>= crypto
->insize
)
853 /* The crypto struct must be setup for iterations and .key. */
854 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
855 struct client_crypto_s
*crypto
, const gchar
*filename
)
857 goffset len
= crypto
->insize
;
861 guint64 iter_progress
= 0, n_iter
= 0, xiter
= 0;
862 gchar tmp
[FILENAME_MAX
];
866 if (!crypto
->fh
->fh2
.iter
) {
868 * cache_file_count() needs both .used == TRUE and a valid key in
869 * order for it to count as a used cache entry. Fixes CACHE status
872 memset(crypto
->key
, '!', gcrykeysize
);
877 * Resize the existing xml buffer to the block size required by gcrypt
878 * rather than duplicating it and wasting memory.
880 if (crypto
->insize
/ gcryblocksize
) {
881 len
= (crypto
->insize
/ gcryblocksize
) * gcryblocksize
;
883 if (crypto
->insize
% gcryblocksize
)
884 len
+= gcryblocksize
;
887 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
890 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
891 return gpg_error_from_errno(ENOMEM
);
894 crypto
->inbuf
= inbuf
;
895 crypto
->insize
= len
;
896 gcry_create_nonce(crypto
->fh
->fh2
.iv
, sizeof(crypto
->fh
->fh2
.iv
));
897 crypto
->tkey
= gcry_malloc(gcrykeysize
);
900 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
901 return gpg_error_from_errno(ENOMEM
);
904 memcpy(crypto
->tkey
, crypto
->key
, gcrykeysize
);
905 guchar
*tkey
= crypto
->tkey
;
908 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
909 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
913 iter_progress
= (guint64
)get_key_file_integer(
914 client
? client
->filename
: "global", "iteration_progress");
916 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
917 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
918 "0 %llu", crypto
->fh
->fh2
.iter
);
924 while (xiter
< crypto
->fh
->fh2
.iter
-1) {
925 if (iter_progress
> 0 && xiter
>= iter_progress
) {
926 if (!(xiter
% iter_progress
)) {
927 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
928 "%llu %llu", ++n_iter
* iter_progress
,
929 crypto
->fh
->fh2
.iter
);
936 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
937 sizeof(crypto
->fh
->fh2
.iv
)))) {
938 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
942 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
945 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
952 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
953 sizeof(crypto
->fh
->fh2
.iv
)))) {
954 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
958 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, gcrykeysize
))) {
959 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
963 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
968 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
969 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
970 "%llu %llu", crypto
->fh
->fh2
.iter
, crypto
->fh
->fh2
.iter
);
980 if (!client
&& !g_strcmp0(filename
, "-")) {
981 crypto
->fh
->fd
= STDOUT_FILENO
;
985 if (lstat(filename
, &st
) == 0) {
986 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
989 * FIXME What if the file has an ACL?
991 if (!(mode
& S_IWUSR
))
992 return gpg_error_from_errno(EACCES
);
994 else if (errno
!= ENOENT
)
995 return gpg_error_from_errno(errno
);
997 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
998 crypto
->fh
->fd
= mkstemp(tmp
);
1000 if (crypto
->fh
->fd
== -1) {
1002 p
= strrchr(tmp
, '/');
1004 log_write("%s: %s", p
, strerror(rc
));
1005 return gpg_error_from_errno(rc
);
1008 pth_cleanup_push(unlink
, tmp
);
1012 * xml_import() or convert_file() from command line.
1014 crypto
->fh
->fd
= STDOUT_FILENO
;
1017 crypto
->fh
->fh2
.magic
[0] = '\177';
1018 crypto
->fh
->fh2
.magic
[1] = 'P';
1019 crypto
->fh
->fh2
.magic
[2] = 'W';
1020 crypto
->fh
->fh2
.magic
[3] = 'M';
1021 crypto
->fh
->fh2
.magic
[4] = 'D';
1022 crypto
->fh
->fh2
.version
= VERSION_HEX
;
1023 len
= pth_write(crypto
->fh
->fd
, &crypto
->fh
->fh2
, sizeof(crypto
->fh
->fh2
));
1025 if (len
!= sizeof(crypto
->fh
->fh2
)) {
1031 return gpg_error_from_errno(len
);
1034 len
= pth_write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1036 if (len
!= crypto
->insize
) {
1042 return gpg_error_from_errno(len
);
1045 if (fsync(crypto
->fh
->fd
) == -1) {
1051 return gpg_error_from_errno(len
);
1055 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1056 gchar tmp2
[FILENAME_MAX
];
1058 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1060 if (rename(filename
, tmp2
) == -1) {
1063 return gpg_error_from_errno(len
);
1067 if (rename(tmp
, filename
) == -1) {
1070 return gpg_error_from_errno(len
);
1076 chmod(filename
, mode
);
1079 if (client
&& lstat(filename
, &st
) == 0)
1080 client
->mtime
= st
.st_mtime
;
1085 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1088 struct client_s
*client
= assuan_get_pointer(ctx
);
1090 gulong len
, outsize
= 0;
1097 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1098 gcry_free(client
->crypto
->key
);
1100 client
->crypto
->key
= key
;
1101 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1102 pth_cleanup_push(xmlFree
, xmlbuf
);
1103 iter
= (guint
)get_key_file_integer(client
->filename
, "compression_level");
1108 if (do_compress(ctx
, (gint
)iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
)
1111 cleanup_crypto(&client
->crypto
);
1113 if (zrc
== Z_MEM_ERROR
)
1114 return send_syserror(ctx
, ENOMEM
);
1116 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1124 client
->crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1126 if (!client
->crypto
->fh
) {
1127 cleanup_crypto(&client
->crypto
);
1129 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1130 return send_syserror(ctx
, ENOMEM
);
1133 iter
= get_key_file_integer(client
->filename
, "iterations");
1134 client
->crypto
->fh
->fh2
.iter
= iter
< 0 ? 0 : iter
;
1135 client
->crypto
->inbuf
= xmlbuf
;
1136 client
->crypto
->insize
= len
;
1137 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1140 cleanup_crypto(&client
->crypto
);
1141 return send_error(ctx
, rc
);
1144 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1145 CACHE_LOCK(client
->ctx
);
1148 cache_reset_timeout(client
->md5file
, timeout
);
1151 if (client
->new == TRUE
)
1152 send_status_all(STATUS_CACHE
);
1154 client
->new = FALSE
;
1155 cleanup_crypto(&client
->crypto
);
1156 return send_error(ctx
, 0);
1159 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1161 cleanup_crypto(&client
->crypto
);
1162 return send_syserror(ctx
, ENOMEM
);
1165 client
->new = FALSE
;
1166 cache_reset_timeout(client
->md5file
, timeout
);
1168 send_status_all(STATUS_CACHE
);
1169 cleanup_crypto(&client
->crypto
);
1170 return send_error(ctx
, 0);
1173 static int save_command(assuan_context_t ctx
, char *line
)
1175 gboolean cached
= FALSE
;
1177 struct client_s
*client
= assuan_get_pointer(ctx
);
1180 rc
= lock_file_mutex(client
);
1183 return send_error(ctx
, rc
);
1185 rc
= file_modified(client
);
1188 return send_error(ctx
, rc
);
1190 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1191 return send_syserror(ctx
, errno
);
1193 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1194 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1195 return send_error(ctx
, GPG_ERR_ENOANO
);
1199 cached
= cache_iscached(client
->md5file
);
1203 * If a cache entry doesn't exist for this file and the file has a
1204 * "key_file" or "key" parameter, then it's an error. The reason is that
1205 * cache expiration would be useless.
1207 if (cached
== FALSE
) {
1208 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1212 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1217 client
->crypto
= init_client_crypto();
1219 if (!client
->crypto
) {
1220 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1221 return send_syserror(ctx
, ENOMEM
);
1224 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
1226 if (!client
->crypto
->key
) {
1227 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1228 cleanup_crypto(&client
->crypto
);
1229 return send_syserror(ctx
, ENOMEM
);
1232 memset(client
->crypto
->key
, '!', gcrykeysize
);
1234 if (get_key_file_integer(client
->filename
, "iterations") <= 0)
1237 if (!line
|| !*line
) {
1238 client
->crypto
->tkey
= gcry_malloc(gcrykeysize
);
1240 if (!client
->crypto
->tkey
) {
1241 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1242 cleanup_crypto(&client
->crypto
);
1243 return send_syserror(ctx
, ENOMEM
);
1246 memset(client
->crypto
->tkey
, '!', gcrykeysize
);
1249 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1250 memcmp(client
->crypto
->key
, client
->crypto
->tkey
,
1251 gcrykeysize
) == 0) {
1254 #ifdef WITH_PINENTRY
1255 if (client
->pinentry
->enable
== FALSE
||
1256 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1257 /* Empty keys are allowed. */
1258 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1262 lock_pin_mutex(client
);
1263 client
->pinentry
->which
= PINENTRY_SAVE
;
1264 rc
= pinentry_fork(ctx
);
1267 unlock_pin_mutex(client
->pinentry
);
1268 return send_error(ctx
, rc
);
1271 client
->pinentry
->cb
= save_command_finalize
;
1272 client
->pinentry
->status
= PINENTRY_INIT
;
1275 /* Empty keys are allowed. */
1276 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1286 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, line
,
1290 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1293 static int delete_command(assuan_context_t ctx
, char *line
)
1295 struct client_s
*client
= assuan_get_pointer(ctx
);
1300 rc
= file_modified(client
);
1303 return send_error(ctx
, rc
);
1305 if (strchr(line
, '\t'))
1306 req
= split_input_line(line
, "\t", -1);
1308 req
= split_input_line(line
, " ", -1);
1311 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1313 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1317 return send_error(ctx
, rc
);
1321 * No sub-node defined. Remove the entire node (account).
1330 return send_error(ctx
, 0);
1333 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1337 return send_error(ctx
, rc
);
1344 return send_error(ctx
, 0);
1348 * Don't return with assuan_process_done() here. This has been called from
1349 * assuan_process_next() and the command should be finished in
1352 static int store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1355 assuan_context_t ctx
= data
;
1356 struct client_s
*client
= assuan_get_pointer(ctx
);
1359 gpg_error_t rc
= file_modified(client
);
1361 if (assuan_rc
|| rc
) {
1364 return assuan_rc
? assuan_rc
: rc
;
1367 req
= split_input_line((gchar
*)line
, "\t", 0);
1371 return EPWMD_COMMAND_SYNTAX
;
1373 if (valid_xml_element((xmlChar
*)*req
) == FALSE
) {
1375 return EPWMD_INVALID_ELEMENT
;
1378 if (valid_element_path(req
+1, TRUE
) == FALSE
) {
1380 return EPWMD_INVALID_ELEMENT
;
1384 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1386 if (rc
&& rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1387 rc
= new_account(client
->doc
, *req
);
1404 create_elements_cb(n
, req
+1, &rc
, NULL
);
1406 find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1407 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
);
1411 client
->inquire_status
= INQUIRE_DONE
;
1415 static int store_command(assuan_context_t ctx
, char *line
)
1417 struct client_s
*client
= assuan_get_pointer(ctx
);
1418 gpg_error_t rc
= file_modified(client
);
1421 return send_error(ctx
, rc
);
1423 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1426 return send_error(ctx
, rc
);
1428 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1429 client
->inquire_status
= INQUIRE_BUSY
;
1433 static void *send_data_cb(void *arg
)
1435 struct assuan_cmd_s
*data
= arg
;
1439 pth_cancel_state(PTH_CANCEL_ENABLE
|PTH_CANCEL_ASYNCHRONOUS
, &old
);
1440 rc
= assuan_send_data(data
->ctx
, data
->line
, data
->line_len
);
1441 pth_cancel_state(old
, NULL
);
1442 pth_exit((void *)rc
);
1446 /* For every assuan command that needs to be sent to the client, a timeout is
1447 * needed to determine if the client lost the connection. The timeout is the
1448 * same as the "keepalive" configuration parameter or a default if unset.
1450 gpg_error_t
do_assuan_command(assuan_context_t ctx
,
1451 void *(*cb
)(void *data
), void *data
)
1453 pth_attr_t attr
= pth_attr_new();
1456 gint to
= get_key_file_integer("global", "keepalive");
1457 pth_event_t ev
, tev
;
1461 pth_attr_init(attr
);
1462 pth_attr_set(attr
, PTH_ATTR_JOINABLE
, TRUE
);
1463 pth_cleanup_push(pth_attr_destroy
, attr
);
1464 tid
= pth_spawn(attr
, cb
, data
);
1469 log_write("%s(%i): pth_spawn(): %s", __FILE__
, __LINE__
,
1470 _gpg_strerror(gpg_error_from_errno(n
)));
1471 return gpg_error_from_errno(n
);
1474 pth_cleanup_push(pth_cancel
, tid
);
1475 to
= to
<= 0 ? DEFAULT_KEEPALIVE_TO
: to
;
1476 ev
= pth_event(PTH_EVENT_TID
|PTH_UNTIL_TID_DEAD
, tid
);
1477 tev
= pth_event(PTH_EVENT_TIME
, pth_timeout(to
, 0));
1478 ev
= pth_event_concat(ev
, tev
, NULL
);
1479 pth_cleanup_push(cleanup_ev_cb
, ev
);
1482 st
= pth_event_status(ev
);
1484 if (st
== PTH_STATUS_FAILED
) {
1486 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1488 else if (st
== PTH_STATUS_OCCURRED
)
1489 pth_join(tid
, (void **)&rc
);
1491 st
= pth_event_status(tev
);
1493 if (st
== PTH_STATUS_OCCURRED
) {
1495 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1504 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
1510 struct assuan_cmd_s data
;
1511 int progress
= get_key_file_integer("global", "xfer_progress");
1514 progress
= progress
>0 ? (progress
/ASSUAN_LINELENGTH
)*ASSUAN_LINELENGTH
: 0;
1515 to_send
= total
< ASSUAN_LINELENGTH
? total
: ASSUAN_LINELENGTH
;
1517 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1524 if (sent
+ to_send
> total
)
1525 to_send
= total
- sent
;
1527 data
.line
= flush
? NULL
: (gchar
*)line
+sent
;
1528 data
.line_len
= flush
? 0 : to_send
;
1529 rc
= do_assuan_command(ctx
, send_data_cb
, &data
);
1532 sent
+= flush
? 0 : to_send
;
1534 if ((progress
&& !(sent
% progress
) && sent
!= total
) ||
1535 (sent
== total
&& flush
))
1536 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1538 if (!flush
&& !rc
&& sent
== total
) {
1543 } while (!rc
&& sent
< total
);
1548 static int get_command(assuan_context_t ctx
, char *line
)
1550 struct client_s
*client
= assuan_get_pointer(ctx
);
1555 rc
= file_modified(client
);
1558 return send_error(ctx
, rc
);
1560 req
= split_input_line(line
, "\t", -1);
1562 if (!req
|| !*req
) {
1564 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1567 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1571 return send_error(ctx
, rc
);
1575 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1580 return send_error(ctx
, rc
);
1582 if (!n
|| !n
->children
)
1583 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1585 n
= find_text_node(n
->children
);
1587 if (!n
|| !n
->content
|| !*n
->content
)
1588 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1590 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
1591 return send_error(ctx
, rc
);
1594 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
1595 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
1597 gchar
*path
= *(gchar
**)data
;
1598 gchar
*tmp
= NULL
, *result
;
1602 *(gchar
**)data
= NULL
;
1605 path
= g_strjoinv("\t", target
);
1608 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1609 *rc
= gpg_error_from_errno(ENOMEM
);
1614 tmp
= g_strjoinv("\t", req_orig
);
1618 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1619 *rc
= gpg_error_from_errno(ENOMEM
);
1625 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1627 result
= g_strdup(path
);
1630 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1631 *rc
= gpg_error_from_errno(ENOMEM
);
1639 *(gchar
**)data
= result
;
1643 static void list_command_cleanup1(void *arg
);
1644 static int realpath_command(assuan_context_t ctx
, char *line
)
1647 struct client_s
*client
= assuan_get_pointer(ctx
);
1655 rc
= file_modified(client
);
1658 return send_error(ctx
, rc
);
1660 if (strchr(line
, '\t') != NULL
) {
1661 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1662 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1665 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1666 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1669 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1673 return send_error(ctx
, rc
);
1676 rp
= g_strjoinv("\t", req
);
1680 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1681 return send_syserror(ctx
, ENOMEM
);
1685 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1686 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
);
1691 return send_error(ctx
, rc
);
1695 string
= g_string_new(rp
);
1700 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1701 return send_syserror(ctx
, ENOMEM
);
1705 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
1706 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
1707 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1712 pth_cleanup_push(list_command_cleanup1
, string
);
1713 rc
= xfer_data(ctx
, string
->str
, string
->len
);
1715 return send_error(ctx
, rc
);
1718 static void list_command_cleanup1(void *arg
)
1720 g_string_free((GString
*)arg
, TRUE
);
1723 static void list_command_cleanup2(void *arg
)
1725 struct element_list_s
*elements
= arg
;
1728 gint total
= g_slist_length(elements
->list
);
1731 for (i
= 0; i
< total
; i
++) {
1732 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
1736 g_slist_free(elements
->list
);
1738 if (elements
->prefix
)
1739 g_free(elements
->prefix
);
1745 static int list_command(assuan_context_t ctx
, char *line
)
1747 struct client_s
*client
= assuan_get_pointer(ctx
);
1749 struct element_list_s
*elements
= NULL
;
1752 if (disable_list_and_dump
== TRUE
)
1753 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1755 rc
= file_modified(client
);
1758 return send_error(ctx
, rc
);
1763 rc
= list_accounts(client
->doc
, &str
);
1766 return send_error(ctx
, rc
);
1768 pth_cleanup_push(list_command_cleanup1
, str
);
1769 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1771 return send_error(ctx
, rc
);
1774 elements
= g_malloc0(sizeof(struct element_list_s
));
1777 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1778 rc
= gpg_err_code_from_errno(ENOMEM
);
1782 pth_cleanup_push(list_command_cleanup2
, elements
);
1783 rc
= create_path_list(client
->doc
, elements
, line
);
1789 gint total
= g_slist_length(elements
->list
);
1794 rc
= EPWMD_EMPTY_ELEMENT
;
1798 str
= g_string_new(NULL
);
1801 rc
= gpg_err_code_from_errno(ENOMEM
);
1802 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1806 for (i
= 0; i
< total
; i
++) {
1807 tmp
= g_slist_nth_data(elements
->list
, i
);
1808 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
1811 pth_cleanup_push(list_command_cleanup1
, str
);
1812 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1816 rc
= EPWMD_EMPTY_ELEMENT
;
1820 return send_error(ctx
, rc
);
1823 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1828 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1829 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1832 return EPWMD_LIBXML_ERROR
;
1835 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1841 * req[0] - element path
1843 static int attribute_list(assuan_context_t ctx
, gchar
**req
)
1845 struct client_s
*client
= assuan_get_pointer(ctx
);
1846 gchar
**attrlist
= NULL
;
1848 gchar
**path
= NULL
;
1854 if (!req
|| !req
[0])
1855 return EPWMD_COMMAND_SYNTAX
;
1857 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1859 * The first argument may be only an account.
1861 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1862 return EPWMD_COMMAND_SYNTAX
;
1865 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1873 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1874 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1884 for (a
= n
->properties
; a
; a
= a
->next
) {
1887 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1889 g_strfreev(attrlist
);
1891 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1892 return gpg_error_from_errno(ENOMEM
);
1897 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1900 g_strfreev(attrlist
);
1901 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1902 return gpg_error_from_errno(ENOMEM
);
1905 attrlist
[++i
] = NULL
;
1909 return EPWMD_EMPTY_ELEMENT
;
1911 line
= g_strjoinv("\n", attrlist
);
1914 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1915 g_strfreev(attrlist
);
1916 return gpg_error_from_errno(ENOMEM
);
1919 pth_cleanup_push(g_free
, line
);
1920 pth_cleanup_push(req_cleanup
, attrlist
);
1921 rc
= xfer_data(ctx
, line
, strlen(line
));
1928 * req[0] - attribute
1929 * req[1] - element path
1931 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1935 gchar
**path
= NULL
;
1938 if (!req
|| !req
[0] || !req
[1])
1939 return EPWMD_COMMAND_SYNTAX
;
1941 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1943 * The first argument may be only an account.
1945 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1946 return EPWMD_COMMAND_SYNTAX
;
1950 * Don't remove the "name" attribute for the account element. To remove an
1951 * account use DELETE <account>.
1953 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
1954 rc
= EPWMD_ATTR_SYNTAX
;
1958 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1964 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1965 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1973 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
1974 return EPWMD_ATTR_NOT_FOUND
;
1976 if (xmlRemoveProp(a
) == -1)
1977 return EPWMD_LIBXML_ERROR
;
1986 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
1989 gchar
**src
= *path
;
1990 gchar
**src_orig
= g_strdupv(src
);
1991 xmlNodePtr n
= NULL
;
1996 *rc
= gpg_error_from_errno(ENOMEM
);
1997 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2002 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
2005 if (*rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2006 *rc
= new_account(client
->doc
, src
[0]);
2019 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
2021 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2022 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
);
2028 * Reset the position of the element tree now that the elements
2029 * have been created.
2034 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
2039 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2040 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2048 g_strfreev(src_orig
);
2055 * Creates a "target" attribute. When other commands encounter an element with
2056 * this attribute, the element path is modified to the target value. If the
2057 * source element path doesn't exist when using 'ATTR SET target', it is
2058 * created, but the destination element path must exist.
2060 * req[0] - source element path
2061 * req[1] - destination element path
2063 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2065 gchar
**src
, **dst
, *line
= NULL
;
2069 if (!req
|| !req
[0] || !req
[1])
2070 return EPWMD_COMMAND_SYNTAX
;
2072 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2074 * The first argument may be only an account.
2076 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2077 return EPWMD_COMMAND_SYNTAX
;
2080 if (valid_element_path(src
, FALSE
) == FALSE
) {
2082 return EPWMD_INVALID_ELEMENT
;
2085 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2087 * The first argument may be only an account.
2089 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2090 rc
= EPWMD_COMMAND_SYNTAX
;
2095 n
= find_account(client
->doc
, &dst
, &rc
, NULL
, 0);
2098 * Make sure the destination element path exists.
2104 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2105 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2111 n
= create_element_path(client
, &src
, &rc
);
2116 line
= g_strjoinv("\t", dst
);
2119 rc
= gpg_error_from_errno(ENOMEM
);
2120 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2124 rc
= add_attribute(n
, "target", line
);
2134 * req[0] - account name
2137 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2143 tmp
= g_strdupv(req
);
2146 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2147 return gpg_error_from_errno(ENOMEM
);
2150 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2156 if (g_utf8_collate(req
[0], req
[1]) == 0)
2160 * Will not overwrite an existing account.
2162 tmp
= g_strdupv(req
+1);
2165 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2166 return gpg_error_from_errno(ENOMEM
);
2169 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2172 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
2176 return EPWMD_ACCOUNT_EXISTS
;
2179 * Whitespace not allowed in account names.
2181 if (contains_whitespace(req
[1]) == TRUE
)
2182 return EPWMD_ATTR_SYNTAX
;
2184 tmp
= g_strdupv(req
);
2187 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2188 return gpg_error_from_errno(ENOMEM
);
2191 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2195 return EPWMD_ELEMENT_NOT_FOUND
;
2197 return add_attribute(n
, "name", req
[1]);
2201 * req[0] - attribute
2202 * req[1] - element path
2204 static int attribute_get(assuan_context_t ctx
, gchar
**req
)
2206 struct client_s
*client
= assuan_get_pointer(ctx
);
2212 if (!req
|| !req
[0] || !req
[1])
2213 return EPWMD_COMMAND_SYNTAX
;
2215 if (strchr(req
[1], '\t')) {
2216 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2217 return EPWMD_COMMAND_SYNTAX
;
2220 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2221 return EPWMD_COMMAND_SYNTAX
;
2224 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2230 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2231 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2239 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2240 return EPWMD_ATTR_NOT_FOUND
;
2242 pth_cleanup_push(xmlFree
, a
);
2243 rc
= xfer_data(ctx
, (gchar
*)a
, xmlStrlen(a
));
2253 * req[0] - attribute
2254 * req[1] - element path
2257 static int attribute_set(struct client_s
*client
, gchar
**req
)
2259 gchar
**path
= NULL
;
2263 if (!req
|| !req
[0] || !req
[1] || !req
[2])
2264 return EPWMD_COMMAND_SYNTAX
;
2267 * Reserved attribute names.
2269 if (g_utf8_collate(req
[0], "name") == 0) {
2271 * Only reserved for the account element. Not the rest of the
2274 if (strchr(req
[1], '\t') == NULL
)
2275 return name_attribute(client
, req
+ 1);
2277 else if (g_utf8_collate(req
[0], "target") == 0)
2278 return target_attribute(client
, req
+ 1);
2280 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2282 * The first argument may be only an account.
2284 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2285 return EPWMD_COMMAND_SYNTAX
;
2288 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2294 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2295 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2302 return add_attribute(n
, req
[0], req
[2]);
2311 * req[1] - attribute name or element path if command is LIST
2312 * req[2] - element path
2313 * req[2] - element path or value
2315 static int attr_command(assuan_context_t ctx
, char *line
)
2317 struct client_s
*client
= assuan_get_pointer(ctx
);
2321 rc
= file_modified(client
);
2324 return send_error(ctx
, rc
);
2326 req
= split_input_line(line
, " ", 4);
2328 if (!req
|| !req
[0] || !req
[1]) {
2330 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2333 pth_cleanup_push(req_cleanup
, req
);
2335 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2336 rc
= attribute_set(client
, req
+1);
2337 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2338 rc
= attribute_get(ctx
, req
+1);
2339 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2340 rc
= attribute_delete(client
, req
+1);
2341 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2342 rc
= attribute_list(ctx
, req
+1);
2344 rc
= EPWMD_COMMAND_SYNTAX
;
2347 return send_error(ctx
, rc
);
2350 static int iscached_command(assuan_context_t ctx
, char *line
)
2352 gchar
**req
= split_input_line(line
, " ", 0);
2356 if (!req
|| !*req
) {
2358 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2361 if (!valid_filename(req
[0])) {
2363 return EPWMD_INVALID_FILENAME
;
2366 tmp
= get_key_file_string("global", "data_directory");
2370 return gpg_error_from_errno(ENOMEM
);
2373 path
= expand_homedir(tmp
);
2378 return gpg_error_from_errno(ENOMEM
);
2383 path
= g_strdup_printf("%s/%s", tmp
, req
[0]);
2388 return gpg_error_from_errno(ENOMEM
);
2391 if (access(path
, R_OK
) == -1) {
2392 gpg_error_t rc
= gpg_error_from_syserror();
2396 return send_error(ctx
, rc
);
2400 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2404 if (cache_iscached(md5file
) == FALSE
) {
2406 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2410 return send_error(ctx
, 0);
2413 static int clearcache_command(assuan_context_t ctx
, char *line
)
2415 struct client_s
*client
= assuan_get_pointer(ctx
);
2416 gchar
**req
= split_input_line(line
, " ", 0);
2421 if (!req
|| !*req
) {
2423 cache_clear(client
->md5file
, 2);
2425 return send_error(ctx
, 0);
2428 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2431 if (cache_clear(md5file
, 1) == FALSE
) {
2433 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2437 return send_error(ctx
, 0);
2440 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2444 gchar
**req
= split_input_line(line
, " ", 0);
2447 if (!req
|| !*req
|| !req
[1]) {
2449 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2453 timeout
= strtol(req
[0], &p
, 10);
2455 if (errno
!= 0 || *p
!= 0) {
2457 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2460 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2461 CACHE_LOCK(client
->ctx
);
2463 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2465 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2469 return send_error(ctx
, 0);
2472 static int dump_command(assuan_context_t ctx
, char *line
)
2476 struct client_s
*client
= assuan_get_pointer(ctx
);
2479 if (disable_list_and_dump
== TRUE
)
2480 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2482 rc
= file_modified(client
);
2485 return send_error(ctx
, rc
);
2487 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2490 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2491 return send_syserror(ctx
, ENOMEM
);
2494 pth_cleanup_push(xmlFree
, xml
);
2495 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
2497 return send_error(ctx
, rc
);
2500 static int getconfig_command(assuan_context_t ctx
, gchar
*line
)
2502 struct client_s
*client
= assuan_get_pointer(ctx
);
2504 gchar filename
[255]={0}, param
[747]={0};
2505 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2507 if (strchr(line
, ' ')) {
2508 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2513 if (fp
&& !valid_filename(fp
))
2514 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
2516 paramp
= g_ascii_strdown(paramp
, -1);
2519 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2520 return send_syserror(ctx
, ENOMEM
);
2523 if (fp
&& !g_ascii_strcasecmp(paramp
, "iterations")) {
2524 if (!(client
->opts
& OPT_ITERATIONS
) || fp
!= client
->filename
) {
2525 file_header_internal_t
*fh
= read_file_header(fp
, FALSE
, &rc
);
2527 if (!fh
&& rc
!= GPG_ERR_ENOENT
)
2528 return send_error(ctx
, rc
);
2532 p
= g_strdup_printf("%llu", fh
->fh2
.iter
);
2533 close_file_header(fh
);
2536 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2538 return send_syserror(ctx
, ENOMEM
);
2545 else if (!g_ascii_strcasecmp(paramp
, "enable_pinentry")) {
2548 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY
))
2549 n
= client
->pinentry
->enable
;
2551 n
= get_key_file_boolean(fp
, "enable_pinentry");
2553 p
= g_strdup_printf("%s", n
? "true" : "false");
2556 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2558 return send_syserror(ctx
, ENOMEM
);
2563 else if (!g_ascii_strcasecmp(paramp
, "pinentry_timeout")) {
2564 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY_TO
))
2565 p
= g_strdup_printf("%i", client
->pinentry
->timeout
);
2567 p
= g_strdup_printf("%i",
2568 get_key_file_integer(fp
, "pinentry_timeout"));
2571 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2573 return send_syserror(ctx
, ENOMEM
);
2579 p
= get_key_file_string(fp
? fp
: "global", paramp
);
2583 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2585 tmp
= expand_homedir(p
);
2589 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2590 return send_syserror(ctx
, ENOMEM
);
2595 pth_cleanup_push(g_free
, p
);
2596 rc
= xfer_data(ctx
, p
, strlen(p
));
2598 return send_error(ctx
, rc
);
2602 xmlXPathContextPtr xp
;
2603 xmlXPathObjectPtr result
;
2608 static void xpath_command_cleanup(void *arg
)
2610 struct xpath_s
*xpath
= arg
;
2612 req_cleanup(xpath
->req
);
2615 xmlBufferFree(xpath
->buf
);
2618 xmlXPathFreeObject(xpath
->result
);
2621 xmlXPathFreeContext(xpath
->xp
);
2624 static int xpath_command(assuan_context_t ctx
, gchar
*line
)
2626 struct client_s
*client
= assuan_get_pointer(ctx
);
2628 struct xpath_s xpath
;
2630 if (disable_list_and_dump
== TRUE
)
2631 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2633 rc
= file_modified(client
);
2636 return send_error(ctx
, rc
);
2638 if (!line
|| !*line
)
2639 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2641 memset(&xpath
, 0, sizeof(struct xpath_s
));
2643 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
2644 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
2645 return send_syserror(ctx
, ENOMEM
);
2648 xpath
.xp
= xmlXPathNewContext(client
->doc
);
2651 xpath_command_cleanup(&xpath
);
2652 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2655 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
2657 if (!xpath
.result
) {
2658 xpath_command_cleanup(&xpath
);
2659 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2662 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
2663 rc
= EPWMD_EMPTY_ELEMENT
;
2667 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
2668 (xmlChar
*)xpath
.req
[1], &xpath
.buf
);
2672 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
2673 rc
= EPWMD_EMPTY_ELEMENT
;
2676 else if (xpath
.req
[1])
2679 pth_cleanup_push(xpath_command_cleanup
, &xpath
);
2680 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
.buf
),
2681 xmlBufferLength(xpath
.buf
));
2685 xpath_command_cleanup(&xpath
);
2686 return send_error(ctx
, rc
);
2689 static int import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
2692 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
2693 gpg_error_t rc
= file_modified(client
);
2694 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
2696 xmlNodePtr n
, root
, copy
;
2698 if (assuan_rc
|| rc
) {
2701 return assuan_rc
? assuan_rc
: rc
;
2704 req
= split_input_line((gchar
*)line
, " ", 2);
2708 return EPWMD_COMMAND_SYNTAX
;
2710 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2711 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2712 return EPWMD_COMMAND_SYNTAX
;
2717 if (!content
|| !*content
) {
2718 rc
= EPWMD_COMMAND_SYNTAX
;
2722 if (valid_xml_element((xmlChar
*)*path
) == FALSE
) {
2723 rc
= EPWMD_INVALID_ELEMENT
;
2727 if (valid_element_path(path
+1, FALSE
) == FALSE
) {
2728 rc
= EPWMD_INVALID_ELEMENT
;
2732 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2735 rc
= EPWMD_LIBXML_ERROR
;
2739 root
= xmlDocGetRootElement(doc
);
2740 path_orig
= g_strdupv(path
);
2744 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2745 rc
= gpg_error_from_errno(ENOMEM
);
2749 if (strv_printf(&path
, "%s", (gchar
*)root
->name
) == FALSE
) {
2750 g_strfreev(path_orig
);
2752 rc
= gpg_error_from_errno(ENOMEM
);
2756 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2758 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2759 g_strfreev(path_orig
);
2764 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2766 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2767 g_strfreev(path_orig
);
2772 xmlNodePtr parent
= n
->parent
;
2783 if (rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2784 n
= create_element_path(client
, &path
, &rc
);
2792 copy
= xmlCopyNode(root
, 1);
2793 n
= xmlAddChild(n
, copy
);
2797 rc
= EPWMD_LIBXML_ERROR
;
2802 client
->inquire_status
= INQUIRE_DONE
;
2806 static int import_command(assuan_context_t ctx
, gchar
*line
)
2809 struct client_s
*client
= assuan_get_pointer(ctx
);
2811 rc
= file_modified(client
);
2814 return send_error(ctx
, rc
);
2816 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
2819 return send_error(ctx
, rc
);
2821 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2822 client
->inquire_status
= INQUIRE_BUSY
;
2826 static int lock_command(assuan_context_t ctx
, gchar
*line
)
2829 struct client_s
*client
= assuan_get_pointer(ctx
);
2831 rc
= file_modified(client
);
2834 return send_error(ctx
, rc
);
2836 rc
= lock_file_mutex(client
);
2839 client
->is_lock_cmd
= TRUE
;
2841 return send_error(ctx
, rc
);
2844 static int unlock_command(assuan_context_t ctx
, gchar
*line
)
2846 struct client_s
*client
= assuan_get_pointer(ctx
);
2847 gpg_error_t rc
= file_modified(client
);
2850 return send_error(ctx
, rc
);
2852 unlock_file_mutex(client
);
2853 return send_error(ctx
, 0);
2856 static int getpid_command(assuan_context_t ctx
, gchar
*line
)
2860 pid_t pid
= getpid();
2862 print_fmt(buf
, sizeof(buf
), "%i", pid
);
2863 rc
= xfer_data(ctx
, buf
, strlen(buf
));
2864 return send_error(ctx
, rc
);
2867 static int version_command(assuan_context_t ctx
, gchar
*line
)
2872 print_fmt(buf
, sizeof(buf
), "0x%X", VERSION_HEX
);
2873 rc
= xfer_data(ctx
, buf
, strlen(buf
));
2874 return send_error(ctx
, rc
);
2877 static void set_option_value(gchar
**opt
, const gchar
*value
)
2885 *opt
= g_strdup(value
);
2888 static int set_unset_common(assuan_context_t ctx
, const gchar
*name
,
2891 struct client_s
*client
= assuan_get_pointer(ctx
);
2893 if (g_ascii_strcasecmp(name
, (gchar
*)"iterations") == 0) {
2897 if (!client
->filename
)
2898 return EPWMD_NO_FILE
;
2901 MUTEX_LOCK(&rcfile_mutex
);
2902 g_key_file_set_integer(keyfileh
, client
->filename
, "iterations",
2903 get_key_file_integer("global", "iterations"));
2904 MUTEX_UNLOCK(&rcfile_mutex
);
2909 n
= strtol(value
, &p
, 10);
2911 if (errno
|| (p
&& *p
) || n
< 0)
2912 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2914 MUTEX_LOCK(&rcfile_mutex
);
2915 g_key_file_set_integer(keyfileh
,
2916 client
->filename
? client
->filename
: "global", "iterations",
2918 MUTEX_UNLOCK(&rcfile_mutex
);
2920 if (client
->filename
)
2921 client
->opts
|= OPT_ITERATIONS
;
2923 else if (g_ascii_strcasecmp(name
, (gchar
*)"NAME") == 0) {
2924 pth_attr_t attr
= pth_attr_of(pth_self());
2928 pth_attr_destroy(attr
);
2932 print_fmt(buf
, sizeof(buf
), "%s", value
);
2933 pth_attr_set(attr
, PTH_ATTR_NAME
, buf
);
2934 pth_attr_destroy(attr
);
2935 #ifdef WITH_PINENTRY
2936 if (client
->pinentry
->name
)
2937 g_free(client
->pinentry
->name
);
2939 client
->pinentry
->name
= g_strdup(buf
);
2941 if (!client
->pinentry
->name
)
2942 return gpg_error_from_errno(ENOMEM
);
2945 #ifdef WITH_PINENTRY
2946 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
2947 set_option_value(&client
->pinentry
->lcmessages
, value
);
2948 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
2949 set_option_value(&client
->pinentry
->lcctype
, value
);
2950 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
2951 set_option_value(&client
->pinentry
->ttyname
, value
);
2952 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
2953 set_option_value(&client
->pinentry
->ttytype
, value
);
2954 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
2955 set_option_value(&client
->pinentry
->display
, value
);
2956 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
2957 set_option_value(&client
->pinentry
->path
, value
);
2958 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
2959 set_option_value(&client
->pinentry
->title
, value
);
2960 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
2961 set_option_value(&client
->pinentry
->prompt
, value
);
2962 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
2963 set_option_value(&client
->pinentry
->desc
, value
);
2964 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0) {
2969 client
->pinentry
->timeout
=
2970 get_key_file_integer(client
->filename
, "pinentry_timeout");
2971 client
->opts
&= ~(OPT_PINENTRY_TO
);
2975 n
= strtol(value
, &p
, 10);
2978 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2980 client
->pinentry
->timeout
= n
;
2981 client
->opts
|= OPT_PINENTRY_TO
;
2983 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0) {
2988 client
->pinentry
->enable
= -1;
2989 client
->opts
&= ~(OPT_PINENTRY
);
2993 n
= strtol(value
, &p
, 10);
2995 if (*p
|| n
< 0 || n
> 1)
2996 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2998 client
->pinentry
->enable
= n
== 0 ? FALSE
: TRUE
;
2999 client
->opts
|= OPT_PINENTRY
;
3003 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
3006 log_write("%s %s%s%s", value
? "SET" : "UNSET", name
,
3007 value
? "=" : "", value
? value
: "");
3011 static int unset_command(assuan_context_t ctx
, gchar
*line
)
3013 return send_error(ctx
, set_unset_common(ctx
, line
, NULL
));
3016 static int set_command(assuan_context_t ctx
, gchar
*line
)
3018 gchar name
[64] = {0}, value
[256] = {0};
3020 if (sscanf(line
, " %63[_a-zA-Z] = %255c", name
, value
) != 2)
3021 return send_error(ctx
, gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
));
3023 return send_error(ctx
, set_unset_common(ctx
, name
, value
));
3026 static void bye_notify(assuan_context_t ctx
)
3028 struct client_s
*cl
= assuan_get_pointer(ctx
);
3030 /* This will let assuan_process_next() return. */
3031 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
3034 static void reset_notify(assuan_context_t ctx
)
3036 struct client_s
*cl
= assuan_get_pointer(ctx
);
3042 gpg_error_t
register_commands(assuan_context_t ctx
)
3046 gint (*handler
)(assuan_context_t
, gchar
*line
);
3048 { "OPEN", open_command
},
3049 { "SAVE", save_command
},
3050 { "LIST", list_command
},
3051 { "REALPATH", realpath_command
},
3052 { "STORE", store_command
},
3053 { "DELETE", delete_command
},
3054 { "GET", get_command
},
3055 { "ATTR", attr_command
},
3056 { "ISCACHED", iscached_command
},
3057 { "CLEARCACHE", clearcache_command
},
3058 { "CACHETIMEOUT", cachetimeout_command
},
3059 { "GETCONFIG", getconfig_command
},
3060 { "DUMP", dump_command
},
3061 { "XPATH", xpath_command
},
3062 { "IMPORT", import_command
},
3063 { "LOCK", lock_command
},
3064 { "UNLOCK", unlock_command
},
3065 { "GETPID", getpid_command
},
3066 { "VERSION", version_command
},
3067 { "SET", set_command
},
3068 { "UNSET", unset_command
},
3075 for (i
=0; table
[i
].name
; i
++) {
3076 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
3082 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
3087 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
3092 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
3095 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, guchar
*key
,
3096 struct client_crypto_s
*crypto
, gpointer
*dst
, goffset
*dst_len
)
3098 goffset insize
, len
;
3099 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
3100 guint64 iter
= 0, n_iter
= 0, iter_progress
= 0;
3104 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->fh1
) : sizeof(crypto
->fh
->fh2
);
3105 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->fh1
.iter
: crypto
->fh
->fh2
.iter
;
3107 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
3108 insize
= crypto
->fh
->st
.st_size
- fh_size
;
3109 crypto
->iv
= gcry_malloc(gcryblocksize
);
3112 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3113 return gpg_error_from_errno(ENOMEM
);
3116 /* No encryption iterations. This is a plain (gzipped) file. */
3117 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0)) {
3119 * cache_file_count() needs both .used == TRUE and a valid key in
3120 * order for it to count as a used cache entry. Fixes CACHE status
3123 memset(key
, '!', gcrykeysize
);
3127 memcpy(crypto
->iv
, crypto
->fh
->fh1
.iv
, gcryblocksize
);
3129 memcpy(crypto
->iv
, crypto
->fh
->fh2
.iv
, gcryblocksize
);
3131 crypto
->inbuf
= gcry_malloc(insize
);
3133 if (!crypto
->inbuf
) {
3134 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3135 return gpg_error_from_errno(ENOMEM
);
3138 crypto
->insize
= insize
;
3139 len
= pth_read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
3141 if (len
!= crypto
->insize
)
3142 return GPG_ERR_INV_LENGTH
;
3144 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0))
3147 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
3148 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3152 if ((rc
= gcry_cipher_setkey(crypto
->gh
, key
, gcrykeysize
))) {
3153 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3157 iter_progress
= (guint64
)get_key_file_integer(client
&& client
->filename
?
3158 client
->filename
: "global", "iteration_progress");
3160 if (iter_progress
> 0 && fh_iter
>= iter_progress
) {
3161 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
3167 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3172 crypto
->tkey
= gcry_malloc(gcrykeysize
);
3174 if (!crypto
->tkey
) {
3175 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
3176 return gpg_error_from_errno(ENOMEM
);
3179 memcpy(crypto
->tkey
, key
, gcrykeysize
);
3180 guchar
*tkey
= crypto
->tkey
;
3183 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
3184 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3188 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
3189 if (iter_progress
> 0 && iter
>= iter_progress
) {
3190 if (!(iter
% iter_progress
)) {
3191 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
3192 ++n_iter
* iter_progress
, fh_iter
);
3199 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
3200 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3204 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3207 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3214 if (iter_progress
&& fh_iter
>= iter_progress
) {
3215 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
3222 if (do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
3223 (gpointer
*)&crypto
->outbuf
, &outsize
, &zrc
) == FALSE
) {
3224 if (zrc
== Z_MEM_ERROR
)
3225 return gpg_error_from_errno(ENOMEM
);
3227 return EPWMD_BADKEY
; // Not a valid gzip header. Must be a bad key.
3230 if (g_strncasecmp(crypto
->outbuf
, "<?xml version=", 14) != 0) {
3231 gcry_free(crypto
->outbuf
);
3232 crypto
->outbuf
= NULL
;
3233 return EPWMD_BADKEY
;
3237 client
->xml
= crypto
->outbuf
;
3238 client
->len
= outsize
;
3239 crypto
->outbuf
= NULL
;
3242 *dst
= crypto
->outbuf
;
3244 crypto
->outbuf
= NULL
;
3247 /* The calling function should free the crypto struct. */
3252 * This is called after every Assuan command.
3254 void command_finalize(assuan_context_t ctx
, gint rc
)
3256 struct client_s
*client
= assuan_get_pointer(ctx
);
3258 if (!client
->is_lock_cmd
)
3259 unlock_file_mutex(client
);