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"
60 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
62 return gcry_calloc(items
, size
);
65 static void z_free(void *data
, void *p
)
70 static gpg_error_t
file_modified(struct client_s
*client
)
75 if (client
->state
!= STATE_OPEN
)
78 rc
= lock_file_mutex(client
);
83 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
84 if (client
->mtime
!= st
.st_mtime
)
85 return EPWMD_FILE_MODIFIED
;
92 static gpg_error_t
parse_xml(assuan_context_t ctx
)
94 struct client_s
*client
= assuan_get_pointer(ctx
);
96 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
99 return EPWMD_LIBXML_ERROR
;
104 void unlock_file_mutex(struct client_s
*client
)
106 struct file_mutex_s
*m
;
109 if (client
->has_lock
== FALSE
|| client
->pinentry
->status
!= PINENTRY_NONE
)
111 if (client
->has_lock
== FALSE
)
115 CACHE_LOCK(client
->ctx
);
117 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
123 MUTEX_UNLOCK(&m
->mutex
);
124 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
127 gpg_error_t
lock_file_mutex(struct client_s
*client
)
129 struct file_mutex_s
*m
;
131 if (client
->has_lock
== TRUE
)
134 CACHE_LOCK(client
->ctx
);
136 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
143 if (pthread_mutex_trylock(&m
->mutex
) == EBUSY
) {
146 * If a client disconnects unexpectedly while waiting for a
147 * lock, this lets the thread terminate because send_status()
148 * will return an error.
150 while (pthread_mutex_trylock(&m
->mutex
) == EBUSY
) {
151 gpg_error_t rc
= send_status(client
->ctx
, STATUS_LOCKED
, NULL
);
160 MUTEX_LOCK(&m
->mutex
);
167 client
->has_lock
= TRUE
;
171 void free_client(struct client_s
*client
)
174 xmlFreeDoc(client
->doc
);
177 gcry_free(client
->xml
);
179 if (client
->filename
)
180 g_free(client
->filename
);
183 cleanup_crypto(&client
->crypto
);
185 if (client
->xml_error
)
186 xmlResetError(client
->xml_error
);
189 void cleanup_client(struct client_s
*client
)
191 assuan_context_t ctx
= client
->ctx
;
192 struct client_thread_s
*thd
= client
->thd
;
193 gboolean has_lock
= client
->has_lock
;
195 struct pinentry_s
*pin
= client
->pinentry
;
198 unlock_file_mutex(client
);
199 CACHE_LOCK(client
->ctx
);
200 cache_decr_refcount(client
->md5file
);
203 * This may be a new file so don't use a cache slot. save_command() will
204 * set this to FALSE on success.
206 if (client
->new == TRUE
)
207 cache_clear(client
->md5file
, 1);
211 memset(client
, 0, sizeof(struct client_s
));
212 client
->state
= STATE_CONNECTED
;
215 client
->freed
= TRUE
;
217 client
->pinentry
= pin
;
219 client
->has_lock
= has_lock
;
222 static void gz_cleanup(void *arg
)
224 struct gz_s
**gz
= (struct gz_s
**)arg
;
229 if (!(*gz
)->done
&& (*gz
)->out
)
230 gcry_free((*gz
)->out
);
233 if ((*gz
)->which
== STATUS_COMPRESS
) {
235 deflateEnd(&(*gz
)->z
);
239 inflateEnd(&(*gz
)->z
);
246 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
247 gpointer
*out
, gulong
*outsize
, gint
*rc
)
253 gz
= g_malloc0(sizeof(struct gz_s
));
256 *rc
= gpg_error_from_errno(ENOMEM
);
260 gz
->which
= STATUS_DECOMPRESS
;
261 pthread_cleanup_push(gz_cleanup
, &gz
);
262 gz
->z
.zalloc
= z_alloc
;
263 gz
->z
.zfree
= z_free
;
265 gz
->z
.avail_in
= (uInt
)insize
;
266 gz
->z
.avail_out
= zlib_bufsize
;
267 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
270 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
276 *rc
= inflateInit2(&gz
->z
, 47);
279 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
284 memset(&h
, 0, sizeof(gz_header
));
285 h
.comment
= (guchar
*)buf
;
286 h
.comm_max
= sizeof(buf
);
287 *rc
= inflateGetHeader(&gz
->z
, &h
);
290 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
295 *rc
= inflate(&gz
->z
, Z_BLOCK
);
298 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
304 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
309 *rc
= inflate(&gz
->z
, Z_FINISH
);
315 if (!gz
->z
.avail_out
) {
316 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
319 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
325 gz
->z
.next_out
= gz
->out
+ gz
->z
.total_out
;
326 gz
->z
.avail_out
= zlib_bufsize
;
327 pthread_cleanup_push(gz_cleanup
, &gz
);
328 pthread_testcancel();
329 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
330 gz
->z
.total_out
, insize
);
331 pthread_testcancel();
332 pthread_cleanup_pop(0);
344 } while (*rc
!= Z_STREAM_END
);
346 pthread_testcancel();
347 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
349 pthread_testcancel();
355 *outsize
= gz
->z
.total_out
;
362 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
363 pthread_cleanup_pop(1);
367 static void read_file_header_handler(void *arg
)
372 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
377 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
383 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
384 *rc
= gpg_error_from_errno(ENOMEM
);
388 fh_size
= v1
? sizeof(fh
->fh1
) : sizeof(fh
->fh2
);
390 if (lstat(filename
, &fh
->st
) == -1) {
391 *rc
= gpg_error_from_syserror();
396 if (!S_ISREG(fh
->st
.st_mode
)) {
397 *rc
= GPG_ERR_ENOANO
;
402 fd
= open(filename
, O_RDONLY
);
405 *rc
= gpg_error_from_errno(errno
);
411 len
= read(fd
, &fh
->fh1
, fh_size
);
413 len
= read(fd
, &fh
->fh2
, fh_size
);
415 if (len
!= fh_size
) {
417 pthread_cleanup_push(read_file_header_handler
, (void *)fd
);
419 pthread_cleanup_pop(1);
420 *rc
= gpg_error_from_errno(n
);
429 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*key
,
432 struct client_s
*client
= assuan_get_pointer(ctx
);
437 if (!client
->crypto
->fh
) {
444 rc
= try_xml_decrypt(ctx
, key
, client
->crypto
, NULL
, NULL
);
447 cleanup_client(client
);
448 return send_error(ctx
, rc
);
452 CACHE_LOCK(client
->ctx
);
454 if (cached
== FALSE
) {
455 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
456 cleanup_client(client
);
458 return send_syserror(ctx
, ENOMEM
);
461 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
462 cache_reset_timeout(client
->md5file
, timeout
);
465 cache_set_timeout(client
->md5file
, -2);
473 gcry_free(client
->xml
);
478 if (client
->new == FALSE
)
479 send_status_all(STATUS_CACHE
);
481 client
->state
= STATE_OPEN
;
484 if (!rc
&& client
->new == FALSE
&&
485 client
->crypto
->fh
->fh2
.iter
!= (guint
)get_key_file_integer(client
->filename
, "iterations")) {
486 g_key_file_set_integer(keyfileh
, client
->filename
, "iterations",
487 client
->crypto
->fh
->fh2
.iter
);
488 send_status_all(STATUS_CONFIG
);
492 log_write("OPEN '%s'", client
->filename
);
494 cleanup_crypto(&client
->crypto
);
495 return send_error(ctx
, rc
);
499 static gboolean
validate_access(struct client_s
*cl
, const gchar
*filename
)
501 gchar
*access
= get_key_file_string(filename
, "tcp_access");
507 list
= g_strsplit(access
, ",", -1);
511 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
515 for (p
= list
; *p
; p
++) {
516 gboolean
not = FALSE
;
527 if (strcasecmp(cl
->thd
->tls
->fp
, fp
) == 0) {
542 static void req_cleanup(void *arg
)
547 g_strfreev((gchar
**)arg
);
550 static int open_command(assuan_context_t ctx
, char *line
)
552 gboolean cached
= FALSE
;
554 struct client_s
*client
= assuan_get_pointer(ctx
);
556 gchar
*filename
= NULL
;
558 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
561 pthread_cleanup_push(req_cleanup
, req
);
563 if (!filename
|| !*filename
) {
565 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
568 if (valid_filename(filename
) == FALSE
) {
570 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
573 if (client
->state
== STATE_OPEN
)
574 cleanup_client(client
);
577 if (client
->thd
->remote
== TRUE
) {
578 if (validate_access(client
, filename
) == FALSE
) {
579 log_write(N_("client validation failed for file '%s'"), filename
);
581 return send_error(ctx
, EPWMD_FILE_ACCESS
);
586 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
587 CACHE_LOCK(client
->ctx
);
589 if (cache_has_file(client
->md5file
) == FALSE
) {
590 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
593 return send_syserror(ctx
, ENOMEM
);
597 cache_incr_refcount(client
->md5file
);
599 rc
= lock_file_mutex(client
);
603 return send_error(ctx
, rc
);
606 client
->freed
= FALSE
;
607 client
->crypto
= init_client_crypto();
609 if (!client
->crypto
) {
611 cleanup_client(client
);
612 return send_syserror(ctx
, ENOMEM
);
615 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
617 if (!client
->crypto
->key
) {
619 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
620 gpg_error_from_errno(ENOMEM
));
621 cleanup_client(client
);
622 return send_syserror(ctx
, ENOMEM
);
625 memset(client
->crypto
->key
, 0, gcrykeysize
);
626 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
627 pthread_testcancel();
629 if (!client
->crypto
->fh
) {
630 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
631 log_write("%s: %s", filename
, pwmd_strerror(rc
));
633 cleanup_client(client
);
634 return send_error(ctx
, rc
);
638 * New files don't need a key.
640 if ((client
->xml
= new_document()) == NULL
) {
641 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
643 cleanup_client(client
);
644 return send_syserror(ctx
, ENOMEM
);
647 client
->len
= xmlStrlen(client
->xml
);
649 client
->filename
= g_strdup(filename
);
651 if (!client
->filename
) {
653 cleanup_client(client
);
654 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
655 return send_syserror(ctx
, ENOMEM
);
658 if (req
[1] && *req
[1])
659 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
664 client
->pinentry
->filename
= g_strdup(client
->filename
);
666 if (!client
->pinentry
->filename
) {
667 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
668 cleanup_client(client
);
669 return send_syserror(ctx
, ENOMEM
);
672 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
675 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
677 client
->filename
= g_strdup(filename
);
679 if (!client
->filename
) {
680 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
682 cleanup_client(client
);
683 return send_syserror(ctx
, ENOMEM
);
687 client
->pinentry
->filename
= g_strdup(client
->filename
);
689 if (!client
->pinentry
->filename
) {
690 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
692 cleanup_client(client
);
693 return send_syserror(ctx
, ENOMEM
);
697 if (client
->crypto
->fh
->fh2
.iter
<= 0)
701 if (client
->thd
->remote
== FALSE
||
702 get_key_file_boolean(client
->filename
, "tcp_require_key") == FALSE
)
705 CACHE_LOCK(client
->ctx
);
706 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
714 if (cached
== FALSE
) {
715 gchar
*tmp
= get_key_file_string(filename
, "key_file");
719 cleanup_client(client
);
720 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
724 * No key specified and no matching filename found in the cache. Use
725 * pinentry to retrieve the key. Cannot return assuan_process_done()
726 * here otherwise the command will be interrupted. The event loop in
727 * client_thread() will poll the file descriptor waiting for it to
728 * become ready to read a pinentry_key_s which will contain the
729 * entered key or an error code. It will then call
730 * open_command_finalize() to to finish the command.
732 if (!req
[1] || !*req
[1]) {
734 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
736 /* From set_pinentry_defaults(). */
737 if (client
->pinentry
->enable
== FALSE
||
738 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
739 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
744 rc
= lock_pin_mutex(client
);
747 unlock_pin_mutex(client
->pinentry
);
748 cleanup_client(client
);
749 return send_error(ctx
, rc
);
752 client
->pinentry
->which
= PINENTRY_OPEN
;
753 rc
= pinentry_fork(ctx
);
756 unlock_pin_mutex(client
->pinentry
);
757 cleanup_client(client
);
758 return send_error(ctx
, rc
);
761 // Called from pinentry iterate.
762 client
->pinentry
->cb
= open_command_finalize
;
763 client
->pinentry
->status
= PINENTRY_INIT
;
766 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
771 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
777 pthread_cleanup_pop(1);
778 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
781 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
782 gulong size
, gpointer
*out
, gulong
*outsize
, gint
*rc
)
787 gint cmd
= Z_NO_FLUSH
;
789 gz
= g_malloc0(sizeof(struct gz_s
));
792 *rc
= gpg_error_from_errno(ENOMEM
);
796 gz
->which
= STATUS_COMPRESS
;
797 pthread_cleanup_push(gz_cleanup
, &gz
);
798 gz
->z
.zalloc
= z_alloc
;
799 gz
->z
.zfree
= z_free
;
800 gz
->z
.next_in
= data
;
801 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
802 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
803 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
806 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
812 *rc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
815 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
820 /* Rather than store the size of the uncompressed data in the file header,
821 * store it in the comment field of the gzip header. Don't give anyone too
822 * much information. Not sure why really, but it seems the right way. :)
824 memset(&h
, 0, sizeof(gz_header
));
825 g_snprintf(buf
, sizeof(buf
), "%li", size
);
826 h
.comment
= (guchar
*)buf
;
827 *rc
= deflateSetHeader(&gz
->z
, &h
);
830 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
838 *rc
= deflate(&gz
->z
, cmd
);
844 if (!gz
->z
.avail_out
) {
845 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
848 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
854 gz
->z
.next_out
= gz
->out
+ gz
->z
.total_out
;
855 gz
->z
.avail_out
= zlib_bufsize
;
858 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
859 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
860 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
862 gz
->z
.avail_in
= zlib_bufsize
;
864 pthread_cleanup_push(gz_cleanup
, &gz
);
865 pthread_testcancel();
866 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li",
867 gz
->z
.total_in
, size
);
868 pthread_testcancel();
869 pthread_cleanup_pop(0);
875 if (gz
->z
.total_in
>= size
)
884 } while (*rc
!= Z_STREAM_END
);
886 pthread_testcancel();
887 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li", gz
->z
.total_in
, size
);
888 pthread_testcancel();
894 *outsize
= gz
->z
.total_out
;
901 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
902 pthread_cleanup_pop(1);
906 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
908 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
909 struct client_crypto_s
*crypto
, status_msg_t which
)
912 gsize len
= CRYPTO_BLOCKSIZE
;
913 gpointer p
= gcry_malloc(len
);
918 return gpg_err_code_from_errno(ENOMEM
);
920 pthread_cleanup_push(gcry_free
, p
);
922 if (crypto
->insize
< CRYPTO_BLOCKSIZE
)
923 len
= crypto
->insize
;
926 inbuf
= crypto
->inbuf
+ total
;
929 if (len
+ total
> crypto
->insize
)
932 if (which
== STATUS_ENCRYPT
)
933 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
935 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
940 tmp
= crypto
->inbuf
+total
;
941 memmove(tmp
, p
, len
);
944 if (total
>= crypto
->insize
)
947 pthread_testcancel();
952 pthread_cleanup_pop(1);
956 /* The crypto struct must be setup for iterations and .key. */
957 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
958 struct client_crypto_s
*crypto
, const gchar
*filename
)
960 gsize len
= crypto
->insize
;
964 guint iter_progress
= 0, n_iter
= 0, xiter
= 0;
965 gchar tmp
[FILENAME_MAX
];
969 if (!crypto
->fh
->fh2
.iter
) {
971 * cache_file_count() needs both .used == TRUE and a valid key in
972 * order for it to count as a used cache entry. Fixes CACHE status
975 memset(crypto
->key
, '!', gcrykeysize
);
980 * Resize the existing xml buffer to the block size required by gcrypt
981 * rather than duplicating it and wasting memory.
983 if (crypto
->insize
/ gcryblocksize
) {
984 len
= (crypto
->insize
/ gcryblocksize
) * gcryblocksize
;
986 if (crypto
->insize
% gcryblocksize
)
987 len
+= gcryblocksize
;
990 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
993 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
994 return gpg_error_from_errno(ENOMEM
);
997 crypto
->inbuf
= inbuf
;
998 crypto
->insize
= len
;
999 gcry_create_nonce(crypto
->fh
->fh2
.iv
, sizeof(crypto
->fh
->fh2
.iv
));
1000 crypto
->tkey
= gcry_malloc(gcrykeysize
);
1002 if (!crypto
->tkey
) {
1003 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1004 return gpg_error_from_errno(ENOMEM
);
1007 memcpy(crypto
->tkey
, crypto
->key
, gcrykeysize
);
1008 guchar
*tkey
= crypto
->tkey
;
1011 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
1012 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1016 iter_progress
= get_key_file_integer(client
? client
->filename
: "global",
1017 "iteration_progress");
1019 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
1020 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1021 "%u %u", 0, crypto
->fh
->fh2
.iter
);
1027 while (xiter
< crypto
->fh
->fh2
.iter
-1) {
1028 if (iter_progress
> 0 && xiter
>= iter_progress
) {
1029 if (!(xiter
% iter_progress
)) {
1030 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1031 "%u %u", ++n_iter
* iter_progress
, crypto
->fh
->fh2
.iter
);
1038 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
1039 sizeof(crypto
->fh
->fh2
.iv
)))) {
1040 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1044 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1047 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1054 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
1055 sizeof(crypto
->fh
->fh2
.iv
)))) {
1056 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1060 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, gcrykeysize
))) {
1061 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1065 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1070 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
1071 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1072 "%u %u", crypto
->fh
->fh2
.iter
, crypto
->fh
->fh2
.iter
);
1080 if (!client
&& !strcmp(filename
, "-")) {
1081 crypto
->fh
->fd
= STDOUT_FILENO
;
1085 if (lstat(filename
, &st
) == 0) {
1086 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1089 * FIXME What if the file has an ACL?
1091 if (!(mode
& S_IWUSR
))
1092 return gpg_error_from_errno(EACCES
);
1095 if (errno
!= ENOENT
)
1096 return gpg_error_from_errno(errno
);
1099 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1100 crypto
->fh
->fd
= mkstemp(tmp
);
1102 if (crypto
->fh
->fd
== -1) {
1104 p
= strrchr(tmp
, '/');
1106 log_write("%s: %s", p
, strerror(rc
));
1107 return gpg_error_from_errno(rc
);
1112 * xml_import() or convert_file() from command line.
1114 crypto
->fh
->fd
= STDOUT_FILENO
;
1117 crypto
->fh
->fh2
.version
= VERSION_HEX
;
1118 len
= write(crypto
->fh
->fd
, &crypto
->fh
->fh2
, sizeof(crypto
->fh
->fh2
));
1120 if (len
!= sizeof(crypto
->fh
->fh2
)) {
1123 if (filename
&& strcmp(filename
, "-"))
1126 return gpg_error_from_errno(len
);
1129 len
= write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1131 if (len
!= crypto
->insize
) {
1134 if (filename
&& strcmp(filename
, "-"))
1137 return gpg_error_from_errno(len
);
1140 if (fsync(crypto
->fh
->fd
) == -1) {
1143 if (filename
&& strcmp(filename
, "-"))
1146 return gpg_error_from_errno(len
);
1149 if (filename
&& strcmp(filename
, "-")) {
1150 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1151 gchar tmp2
[FILENAME_MAX
];
1153 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1155 if (rename(filename
, tmp2
) == -1) {
1158 return gpg_error_from_errno(len
);
1162 if (rename(tmp
, filename
) == -1) {
1165 return gpg_error_from_errno(len
);
1169 chmod(filename
, mode
);
1172 if (client
&& lstat(filename
, &st
) == 0)
1173 client
->mtime
= st
.st_mtime
;
1178 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1181 struct client_s
*client
= assuan_get_pointer(ctx
);
1183 gulong len
, outsize
= 0;
1190 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1191 gcry_free(client
->crypto
->key
);
1193 client
->crypto
->key
= key
;
1194 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1195 iter
= (guint
)get_key_file_integer(client
->filename
, "compression_level");
1200 if (do_compress(ctx
, (gint
)iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
)
1203 cleanup_crypto(&client
->crypto
);
1205 if (zrc
== Z_MEM_ERROR
)
1206 return send_syserror(ctx
, ENOMEM
);
1208 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1216 client
->crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1218 if (!client
->crypto
->fh
) {
1219 cleanup_crypto(&client
->crypto
);
1221 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1222 return send_syserror(ctx
, ENOMEM
);
1225 iter
= get_key_file_integer(client
->filename
, "iterations");
1226 client
->crypto
->fh
->fh2
.iter
= iter
< 0 ? 0 : iter
;
1227 client
->crypto
->inbuf
= xmlbuf
;
1228 client
->crypto
->insize
= len
;
1229 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1232 cleanup_crypto(&client
->crypto
);
1233 return send_error(ctx
, rc
);
1236 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1237 CACHE_LOCK(client
->ctx
);
1240 cache_reset_timeout(client
->md5file
, timeout
);
1243 if (client
->new == TRUE
)
1244 send_status_all(STATUS_CACHE
);
1246 client
->new = FALSE
;
1247 cleanup_crypto(&client
->crypto
);
1248 return send_error(ctx
, 0);
1251 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1253 cleanup_crypto(&client
->crypto
);
1254 return send_syserror(ctx
, ENOMEM
);
1257 client
->new = FALSE
;
1258 cache_reset_timeout(client
->md5file
, timeout
);
1260 send_status_all(STATUS_CACHE
);
1261 cleanup_crypto(&client
->crypto
);
1262 return send_error(ctx
, 0);
1265 static int save_command(assuan_context_t ctx
, char *line
)
1267 gboolean cached
= FALSE
;
1269 struct client_s
*client
= assuan_get_pointer(ctx
);
1272 rc
= lock_file_mutex(client
);
1275 return send_error(ctx
, rc
);
1277 rc
= file_modified(client
);
1280 return send_error(ctx
, rc
);
1282 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1283 return send_syserror(ctx
, errno
);
1285 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1286 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1287 return send_error(ctx
, GPG_ERR_ENOANO
);
1291 cached
= cache_iscached(client
->md5file
);
1295 * If a cache entry doesn't exist for this file and the file has a
1296 * "key_file" or "key" parameter, then it's an error. The reason is that
1297 * cache expiration would be useless.
1299 if (cached
== FALSE
) {
1300 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1304 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1309 client
->crypto
= init_client_crypto();
1311 if (!client
->crypto
) {
1312 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1313 return send_syserror(ctx
, ENOMEM
);
1316 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
1318 if (!client
->crypto
->key
) {
1319 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1320 cleanup_crypto(&client
->crypto
);
1321 return send_syserror(ctx
, ENOMEM
);
1324 memset(client
->crypto
->key
, '!', gcrykeysize
);
1326 if (get_key_file_integer(client
->filename
, "iterations") <= 0)
1329 if (!line
|| !*line
) {
1330 client
->crypto
->tkey
= gcry_malloc(gcrykeysize
);
1332 if (!client
->crypto
->tkey
) {
1333 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1334 cleanup_crypto(&client
->crypto
);
1335 return send_syserror(ctx
, ENOMEM
);
1338 memset(client
->crypto
->tkey
, '!', gcrykeysize
);
1341 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1342 memcmp(client
->crypto
->key
, client
->crypto
->tkey
,
1343 gcrykeysize
) == 0) {
1346 #ifdef WITH_PINENTRY
1347 if (client
->pinentry
->enable
== FALSE
||
1348 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1349 /* Empty keys are allowed. */
1350 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1354 lock_pin_mutex(client
);
1355 client
->pinentry
->which
= PINENTRY_SAVE
;
1356 rc
= pinentry_fork(ctx
);
1359 unlock_pin_mutex(client
->pinentry
);
1360 return send_error(ctx
, rc
);
1363 client
->pinentry
->cb
= save_command_finalize
;
1364 client
->pinentry
->status
= PINENTRY_INIT
;
1367 /* Empty keys are allowed. */
1368 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1378 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, line
,
1380 memset(line
, 0, strlen(line
));
1384 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1387 static int delete_command(assuan_context_t ctx
, char *line
)
1389 struct client_s
*client
= assuan_get_pointer(ctx
);
1394 rc
= file_modified(client
);
1397 return send_error(ctx
, rc
);
1399 if (strchr(line
, '\t'))
1400 req
= split_input_line(line
, "\t", -1);
1402 req
= split_input_line(line
, " ", -1);
1405 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1407 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1411 return send_error(ctx
, rc
);
1415 * No sub-node defined. Remove the entire node (account).
1424 return send_error(ctx
, 0);
1427 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1431 return send_error(ctx
, rc
);
1438 return send_error(ctx
, 0);
1442 * Don't return with assuan_process_done() here. This has been called from
1443 * assuan_process_next() and the command should be finished in
1446 static int store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1449 assuan_context_t ctx
= data
;
1450 struct client_s
*client
= assuan_get_pointer(ctx
);
1453 gpg_error_t rc
= file_modified(client
);
1455 if (assuan_rc
|| rc
) {
1458 return assuan_rc
? assuan_rc
: rc
;
1461 req
= split_input_line((gchar
*)line
, "\t", 0);
1465 return EPWMD_COMMAND_SYNTAX
;
1467 if (valid_xml_element((xmlChar
*)*req
) == FALSE
) {
1469 return EPWMD_INVALID_ELEMENT
;
1472 if (valid_element_path(req
+1, TRUE
) == FALSE
) {
1474 return EPWMD_INVALID_ELEMENT
;
1478 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1480 if (rc
&& rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1481 rc
= new_account(client
->doc
, *req
);
1498 create_elements_cb(n
, req
+1, &rc
, NULL
);
1500 find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1501 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
);
1505 client
->inquire_status
= INQUIRE_DONE
;
1509 static int store_command(assuan_context_t ctx
, char *line
)
1511 struct client_s
*client
= assuan_get_pointer(ctx
);
1512 gpg_error_t rc
= file_modified(client
);
1515 return send_error(ctx
, rc
);
1517 pthread_testcancel();
1518 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1519 pthread_testcancel();
1522 return send_error(ctx
, rc
);
1524 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1525 client
->inquire_status
= INQUIRE_BUSY
;
1529 static int get_command(assuan_context_t ctx
, char *line
)
1531 struct client_s
*client
= assuan_get_pointer(ctx
);
1536 rc
= file_modified(client
);
1539 return send_error(ctx
, rc
);
1541 req
= split_input_line(line
, "\t", -1);
1543 if (!req
|| !*req
) {
1545 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1548 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1552 return send_error(ctx
, rc
);
1556 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1561 return send_error(ctx
, rc
);
1563 if (!n
|| !n
->children
)
1564 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1566 n
= find_text_node(n
->children
);
1568 if (!n
|| !n
->content
|| !*n
->content
)
1569 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1571 pthread_testcancel();
1572 rc
= assuan_send_data(ctx
, n
->content
, xmlStrlen(n
->content
));
1573 pthread_testcancel();
1574 return send_error(ctx
, rc
);
1577 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
1578 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
1580 gchar
*path
= *(gchar
**)data
;
1581 gchar
*tmp
= NULL
, *result
;
1585 *(gchar
**)data
= NULL
;
1588 path
= g_strjoinv("\t", target
);
1591 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1592 *rc
= gpg_error_from_errno(ENOMEM
);
1597 tmp
= g_strjoinv("\t", req_orig
);
1601 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1602 *rc
= gpg_error_from_errno(ENOMEM
);
1608 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1610 result
= g_strdup(path
);
1613 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1614 *rc
= gpg_error_from_errno(ENOMEM
);
1622 *(gchar
**)data
= result
;
1626 static void list_command_cleanup1(void *arg
);
1627 static int realpath_command(assuan_context_t ctx
, char *line
)
1630 struct client_s
*client
= assuan_get_pointer(ctx
);
1638 rc
= file_modified(client
);
1641 return send_error(ctx
, rc
);
1643 if (strchr(line
, '\t') != NULL
) {
1644 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1645 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1648 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1649 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1652 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1656 return send_error(ctx
, rc
);
1659 rp
= g_strjoinv("\t", req
);
1663 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1664 return send_syserror(ctx
, ENOMEM
);
1668 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1669 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
);
1674 return send_error(ctx
, rc
);
1678 string
= g_string_new(rp
);
1683 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1684 return send_syserror(ctx
, ENOMEM
);
1688 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
1689 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
1690 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1695 pthread_cleanup_push(list_command_cleanup1
, string
);
1696 pthread_testcancel();
1697 rc
= assuan_send_data(ctx
, string
->str
, string
->len
);
1698 pthread_testcancel();
1699 pthread_cleanup_pop(1);
1700 return send_error(ctx
, rc
);
1703 static void list_command_cleanup1(void *arg
)
1705 g_string_free((GString
*)arg
, TRUE
);
1708 static void list_command_cleanup2(void *arg
)
1710 struct element_list_s
*elements
= arg
;
1713 gint total
= g_slist_length(elements
->list
);
1716 for (i
= 0; i
< total
; i
++) {
1717 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
1721 g_slist_free(elements
->list
);
1723 if (elements
->prefix
)
1724 g_free(elements
->prefix
);
1730 static int list_command(assuan_context_t ctx
, char *line
)
1732 struct client_s
*client
= assuan_get_pointer(ctx
);
1734 struct element_list_s
*elements
= NULL
;
1737 if (disable_list_and_dump
== TRUE
)
1738 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1740 rc
= file_modified(client
);
1743 return send_error(ctx
, rc
);
1748 rc
= list_accounts(client
->doc
, &str
);
1749 pthread_cleanup_push(list_command_cleanup1
, str
);
1752 return send_error(ctx
, rc
);
1754 pthread_testcancel();
1755 rc
= assuan_send_data(ctx
, str
->str
, str
->len
);
1756 pthread_testcancel();
1757 pthread_cleanup_pop(1);
1758 return send_error(ctx
, rc
);
1761 elements
= g_malloc0(sizeof(struct element_list_s
));
1764 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1765 rc
= gpg_err_code_from_errno(ENOMEM
);
1769 pthread_cleanup_push(list_command_cleanup2
, elements
);
1770 pthread_testcancel();
1771 rc
= create_path_list(client
->doc
, elements
, line
);
1772 pthread_testcancel();
1778 gint total
= g_slist_length(elements
->list
);
1783 rc
= EPWMD_EMPTY_ELEMENT
;
1787 str
= g_string_new(NULL
);
1790 rc
= gpg_err_code_from_errno(ENOMEM
);
1791 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1795 pthread_cleanup_push(list_command_cleanup1
, str
);
1797 for (i
= 0; i
< total
; i
++) {
1798 tmp
= g_slist_nth_data(elements
->list
, i
);
1799 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
1802 pthread_testcancel();
1803 rc
= assuan_send_data(ctx
, str
->str
, str
->len
);
1804 pthread_testcancel();
1805 pthread_cleanup_pop(1);
1808 rc
= EPWMD_EMPTY_ELEMENT
;
1812 pthread_cleanup_pop(1);
1813 return send_error(ctx
, rc
);
1816 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1821 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1822 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1825 return EPWMD_LIBXML_ERROR
;
1828 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1834 * req[0] - element path
1836 static int attribute_list(assuan_context_t ctx
, gchar
**req
)
1838 struct client_s
*client
= assuan_get_pointer(ctx
);
1839 gchar
**attrlist
= NULL
;
1841 gchar
**path
= NULL
;
1847 if (!req
|| !req
[0])
1848 return EPWMD_COMMAND_SYNTAX
;
1850 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1852 * The first argument may be only an account.
1854 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1855 return EPWMD_COMMAND_SYNTAX
;
1858 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1866 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1867 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1877 for (a
= n
->properties
; a
; a
= a
->next
) {
1880 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1882 g_strfreev(attrlist
);
1884 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1885 return gpg_error_from_errno(ENOMEM
);
1890 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1893 g_strfreev(attrlist
);
1894 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1895 return gpg_error_from_errno(ENOMEM
);
1898 attrlist
[++i
] = NULL
;
1902 return EPWMD_EMPTY_ELEMENT
;
1904 line
= g_strjoinv("\n", attrlist
);
1907 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1908 g_strfreev(attrlist
);
1909 return gpg_error_from_errno(ENOMEM
);
1912 pthread_cleanup_push(g_free
, line
);
1913 pthread_cleanup_push(req_cleanup
, attrlist
);
1914 pthread_testcancel();
1915 rc
= assuan_send_data(ctx
, line
, strlen(line
));
1916 pthread_testcancel();
1917 pthread_cleanup_pop(1);
1918 pthread_cleanup_pop(1);
1923 * req[0] - attribute
1924 * req[1] - element path
1926 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1930 gchar
**path
= NULL
;
1933 if (!req
|| !req
[0] || !req
[1])
1934 return EPWMD_COMMAND_SYNTAX
;
1936 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1938 * The first argument may be only an account.
1940 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1941 return EPWMD_COMMAND_SYNTAX
;
1945 * Don't remove the "name" attribute for the account element. To remove an
1946 * account use DELETE <account>.
1948 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
1949 rc
= EPWMD_ATTR_SYNTAX
;
1953 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1959 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1960 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1968 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
1969 return EPWMD_ATTR_NOT_FOUND
;
1971 if (xmlRemoveProp(a
) == -1)
1972 return EPWMD_LIBXML_ERROR
;
1981 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
1984 gchar
**src
= *path
;
1985 gchar
**src_orig
= g_strdupv(src
);
1986 xmlNodePtr n
= NULL
;
1991 *rc
= gpg_error_from_errno(ENOMEM
);
1992 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1997 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
2000 if (*rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2001 *rc
= new_account(client
->doc
, src
[0]);
2014 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
2016 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2017 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
);
2023 * Reset the position of the element tree now that the elements
2024 * have been created.
2029 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
2034 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2035 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2043 g_strfreev(src_orig
);
2050 * Creates a "target" attribute. When other commands encounter an element with
2051 * this attribute, the element path is modified to the target value. If the
2052 * source element path doesn't exist when using 'ATTR SET target', it is
2053 * created, but the destination element path must exist.
2055 * req[0] - source element path
2056 * req[1] - destination element path
2058 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2060 gchar
**src
, **dst
, *line
= NULL
;
2064 if (!req
|| !req
[0] || !req
[1])
2065 return EPWMD_COMMAND_SYNTAX
;
2067 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2069 * The first argument may be only an account.
2071 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2072 return EPWMD_COMMAND_SYNTAX
;
2075 if (valid_element_path(src
, FALSE
) == FALSE
) {
2077 return EPWMD_INVALID_ELEMENT
;
2080 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2082 * The first argument may be only an account.
2084 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2085 rc
= EPWMD_COMMAND_SYNTAX
;
2090 n
= find_account(client
->doc
, &dst
, &rc
, NULL
, 0);
2093 * Make sure the destination element path exists.
2099 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2100 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2106 n
= create_element_path(client
, &src
, &rc
);
2111 line
= g_strjoinv("\t", dst
);
2114 rc
= gpg_error_from_errno(ENOMEM
);
2115 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2119 rc
= add_attribute(n
, "target", line
);
2129 * req[0] - account name
2132 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2138 tmp
= g_strdupv(req
);
2141 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2142 return gpg_error_from_errno(ENOMEM
);
2145 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2151 if (g_utf8_collate(req
[0], req
[1]) == 0)
2155 * Will not overwrite an existing account.
2157 tmp
= g_strdupv(req
+1);
2160 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2161 return gpg_error_from_errno(ENOMEM
);
2164 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2167 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
2171 return EPWMD_ACCOUNT_EXISTS
;
2174 * Whitespace not allowed in account names.
2176 if (contains_whitespace(req
[1]) == TRUE
)
2177 return EPWMD_ATTR_SYNTAX
;
2179 tmp
= g_strdupv(req
);
2182 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2183 return gpg_error_from_errno(ENOMEM
);
2186 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2190 return EPWMD_ELEMENT_NOT_FOUND
;
2192 return add_attribute(n
, "name", req
[1]);
2196 * req[0] - attribute
2197 * req[1] - element path
2199 static int attribute_get(assuan_context_t ctx
, gchar
**req
)
2201 struct client_s
*client
= assuan_get_pointer(ctx
);
2207 if (!req
|| !req
[0] || !req
[1])
2208 return EPWMD_COMMAND_SYNTAX
;
2210 if (strchr(req
[1], '\t')) {
2211 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2212 return EPWMD_COMMAND_SYNTAX
;
2215 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2216 return EPWMD_COMMAND_SYNTAX
;
2219 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2225 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2226 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2234 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2235 return EPWMD_ATTR_NOT_FOUND
;
2237 pthread_cleanup_push(xmlFree
, a
);
2238 pthread_testcancel();
2239 rc
= assuan_send_data(ctx
, a
, xmlStrlen(a
));
2240 pthread_testcancel();
2241 pthread_cleanup_pop(1);
2250 * req[0] - attribute
2251 * req[1] - element path
2254 static int attribute_set(struct client_s
*client
, gchar
**req
)
2256 gchar
**path
= NULL
;
2260 if (!req
|| !req
[0] || !req
[1] || !req
[2])
2261 return EPWMD_COMMAND_SYNTAX
;
2264 * Reserved attribute names.
2266 if (g_utf8_collate(req
[0], "name") == 0) {
2268 * Only reserved for the account element. Not the rest of the
2271 if (strchr(req
[1], '\t') == NULL
)
2272 return name_attribute(client
, req
+ 1);
2274 else if (g_utf8_collate(req
[0], "target") == 0)
2275 return target_attribute(client
, req
+ 1);
2277 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2279 * The first argument may be only an account.
2281 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2282 return EPWMD_COMMAND_SYNTAX
;
2285 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2291 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2292 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2299 return add_attribute(n
, req
[0], req
[2]);
2308 * req[1] - attribute name or element path if command is LIST
2309 * req[2] - element path
2310 * req[2] - element path or value
2312 static int attr_command(assuan_context_t ctx
, char *line
)
2314 struct client_s
*client
= assuan_get_pointer(ctx
);
2318 rc
= file_modified(client
);
2321 return send_error(ctx
, rc
);
2323 req
= split_input_line(line
, " ", 4);
2325 if (!req
|| !req
[0] || !req
[1]) {
2327 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2330 pthread_cleanup_push(req_cleanup
, req
);
2332 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2333 rc
= attribute_set(client
, req
+1);
2334 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2335 rc
= attribute_get(ctx
, req
+1);
2336 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2337 rc
= attribute_delete(client
, req
+1);
2338 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2339 rc
= attribute_list(ctx
, req
+1);
2341 rc
= EPWMD_COMMAND_SYNTAX
;
2343 pthread_cleanup_pop(1);
2344 return send_error(ctx
, rc
);
2347 static int iscached_command(assuan_context_t ctx
, char *line
)
2349 gchar
**req
= split_input_line(line
, " ", 0);
2352 if (!req
|| !*req
) {
2354 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2357 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2359 pthread_cleanup_push(pthread_mutex_unlock
, (void *)&cache_mutex
);
2362 if (cache_iscached(md5file
) == FALSE
) {
2364 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2368 pthread_cleanup_pop(0);
2369 return send_error(ctx
, 0);
2372 static int clearcache_command(assuan_context_t ctx
, char *line
)
2374 struct client_s
*client
= assuan_get_pointer(ctx
);
2375 gchar
**req
= split_input_line(line
, " ", 0);
2378 pthread_cleanup_push(pthread_mutex_unlock
, (void *)&cache_mutex
);
2381 if (!req
|| !*req
) {
2383 cache_clear(client
->md5file
, 2);
2385 return send_error(ctx
, 0);
2388 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2391 if (cache_clear(md5file
, 1) == FALSE
) {
2393 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2397 pthread_cleanup_pop(0);
2398 return send_error(ctx
, 0);
2401 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2405 gchar
**req
= split_input_line(line
, " ", 0);
2407 struct client_s
*client
= assuan_get_pointer(ctx
);
2409 pthread_cleanup_push(req_cleanup
, req
);
2411 if (!req
|| !*req
|| !req
[1]) {
2413 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2417 timeout
= strtol(req
[0], &p
, 10);
2419 if (errno
!= 0 || *p
!= 0) {
2421 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2424 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2425 pthread_cleanup_pop(1);
2426 pthread_cleanup_push(pthread_mutex_unlock
, (void *)&cache_mutex
);
2427 CACHE_LOCK(client
->ctx
);
2429 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2431 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2435 pthread_cleanup_pop(0);
2436 return send_error(ctx
, 0);
2439 static int dump_command(assuan_context_t ctx
, char *line
)
2443 struct client_s
*client
= assuan_get_pointer(ctx
);
2446 if (disable_list_and_dump
== TRUE
)
2447 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2449 rc
= file_modified(client
);
2452 return send_error(ctx
, rc
);
2454 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2457 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2458 return send_syserror(ctx
, ENOMEM
);
2461 pthread_cleanup_push(xmlFree
, xml
);
2462 pthread_testcancel();
2463 rc
= assuan_send_data(ctx
, xml
, len
);
2464 pthread_testcancel();
2465 pthread_cleanup_pop(1);
2466 return send_error(ctx
, rc
);
2469 static int getconfig_command(assuan_context_t ctx
, gchar
*line
)
2471 struct client_s
*client
= assuan_get_pointer(ctx
);
2473 gchar filename
[255]={0}, param
[747]={0};
2474 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2476 if (strchr(line
, ' ')) {
2477 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2482 if (fp
&& !valid_filename(fp
))
2483 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
2485 paramp
= g_ascii_strdown(paramp
, -1);
2488 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2489 return send_syserror(ctx
, ENOMEM
);
2492 p
= get_key_file_string(fp
? fp
: "global", paramp
);
2496 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2498 tmp
= expand_homedir(p
);
2502 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2503 return send_syserror(ctx
, ENOMEM
);
2507 pthread_cleanup_push(g_free
, p
);
2508 pthread_testcancel();
2509 rc
= assuan_send_data(ctx
, p
, strlen(p
));
2510 pthread_testcancel();
2511 pthread_cleanup_pop(1);
2512 return send_error(ctx
, rc
);
2516 xmlXPathContextPtr xp
;
2517 xmlXPathObjectPtr result
;
2522 static void xpath_command_cleanup(void *arg
)
2524 struct xpath_s
*xpath
= arg
;
2526 req_cleanup(xpath
->req
);
2529 xmlBufferFree(xpath
->buf
);
2532 xmlXPathFreeObject(xpath
->result
);
2535 xmlXPathFreeContext(xpath
->xp
);
2538 static int xpath_command(assuan_context_t ctx
, gchar
*line
)
2540 struct client_s
*client
= assuan_get_pointer(ctx
);
2542 struct xpath_s xpath
;
2544 if (disable_list_and_dump
== TRUE
)
2545 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2547 rc
= file_modified(client
);
2550 return send_error(ctx
, rc
);
2552 if (!line
|| !*line
)
2553 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2555 memset(&xpath
, 0, sizeof(struct xpath_s
));
2556 pthread_cleanup_push(xpath_command_cleanup
, &xpath
);
2558 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
2559 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
2560 return send_syserror(ctx
, ENOMEM
);
2563 xpath
.xp
= xmlXPathNewContext(client
->doc
);
2566 xpath_command_cleanup(&xpath
);
2567 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2570 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
2572 if (!xpath
.result
) {
2573 xpath_command_cleanup(&xpath
);
2574 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2577 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
2578 rc
= EPWMD_EMPTY_ELEMENT
;
2582 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
2583 (xmlChar
*)xpath
.req
[1], &xpath
.buf
);
2587 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
2588 rc
= EPWMD_EMPTY_ELEMENT
;
2591 else if (xpath
.req
[1])
2594 pthread_testcancel();
2595 rc
= assuan_send_data(ctx
, xmlBufferContent(xpath
.buf
),
2596 xmlBufferLength(xpath
.buf
));
2597 pthread_testcancel();
2601 pthread_cleanup_pop(1);
2602 return send_error(ctx
, rc
);
2605 static int import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
2608 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
2609 gpg_error_t rc
= file_modified(client
);
2610 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
2612 xmlNodePtr n
, root
, copy
;
2614 if (assuan_rc
|| rc
) {
2617 return assuan_rc
? assuan_rc
: rc
;
2620 req
= split_input_line((gchar
*)line
, " ", 2);
2624 return EPWMD_COMMAND_SYNTAX
;
2626 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2627 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2628 return EPWMD_COMMAND_SYNTAX
;
2633 if (!content
|| !*content
) {
2634 rc
= EPWMD_COMMAND_SYNTAX
;
2638 if (valid_xml_element((xmlChar
*)*path
) == FALSE
) {
2639 rc
= EPWMD_INVALID_ELEMENT
;
2643 if (valid_element_path(path
+1, FALSE
) == FALSE
) {
2644 rc
= EPWMD_INVALID_ELEMENT
;
2648 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2651 rc
= EPWMD_LIBXML_ERROR
;
2655 root
= xmlDocGetRootElement(doc
);
2656 path_orig
= g_strdupv(path
);
2660 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2661 rc
= gpg_error_from_errno(ENOMEM
);
2665 if (strv_printf(&path
, "%s", (gchar
*)root
->name
) == FALSE
) {
2666 g_strfreev(path_orig
);
2668 rc
= gpg_error_from_errno(ENOMEM
);
2672 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2674 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2675 g_strfreev(path_orig
);
2680 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2682 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2683 g_strfreev(path_orig
);
2688 xmlNodePtr parent
= n
->parent
;
2699 if (rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2700 n
= create_element_path(client
, &path
, &rc
);
2708 copy
= xmlCopyNode(root
, 1);
2709 n
= xmlAddChild(n
, copy
);
2713 rc
= EPWMD_LIBXML_ERROR
;
2718 client
->inquire_status
= INQUIRE_DONE
;
2722 static int import_command(assuan_context_t ctx
, gchar
*line
)
2725 struct client_s
*client
= assuan_get_pointer(ctx
);
2727 rc
= file_modified(client
);
2730 return send_error(ctx
, rc
);
2732 pthread_testcancel();
2733 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
2734 pthread_testcancel();
2737 return send_error(ctx
, rc
);
2739 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2740 client
->inquire_status
= INQUIRE_BUSY
;
2744 static int lock_command(assuan_context_t ctx
, gchar
*line
)
2747 struct client_s
*client
= assuan_get_pointer(ctx
);
2749 rc
= file_modified(client
);
2752 return send_error(ctx
, rc
);
2754 rc
= lock_file_mutex(client
);
2757 client
->is_lock_cmd
= TRUE
;
2759 return send_error(ctx
, rc
);
2762 static int unlock_command(assuan_context_t ctx
, gchar
*line
)
2764 struct client_s
*client
= assuan_get_pointer(ctx
);
2765 gpg_error_t rc
= file_modified(client
);
2768 return send_error(ctx
, rc
);
2770 unlock_file_mutex(client
);
2771 return send_error(ctx
, 0);
2774 static int getpid_command(assuan_context_t ctx
, gchar
*line
)
2778 pid_t pid
= getpid();
2780 print_fmt(buf
, sizeof(buf
), "%i", pid
);
2781 pthread_testcancel();
2782 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2783 pthread_testcancel();
2784 return send_error(ctx
, rc
);
2787 static int version_command(assuan_context_t ctx
, gchar
*line
)
2792 print_fmt(buf
, sizeof(buf
), "%s", PACKAGE_VERSION
);
2793 pthread_testcancel();
2794 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2795 pthread_testcancel();
2796 return send_error(ctx
, rc
);
2799 static void bye_notify(assuan_context_t ctx
)
2801 struct client_s
*cl
= assuan_get_pointer(ctx
);
2805 if (!cl
->thd
->remote
)
2809 rc
= gnutls_bye(cl
->thd
->tls
->ses
, GNUTLS_SHUT_RDWR
);
2810 } while (rc
== GNUTLS_E_AGAIN
);
2813 /* This will let assuan_process_next() return. */
2814 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
2817 static void reset_notify(assuan_context_t ctx
)
2819 struct client_s
*cl
= assuan_get_pointer(ctx
);
2825 static gpg_error_t
parse_client_option(assuan_context_t ctx
, const gchar
*line
)
2827 gchar name
[32] = {0}, value
[256] = {0};
2829 if (sscanf(line
, " %31[a-zA-Z] = %255c", name
, value
) != 2)
2830 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
);
2832 if (g_strcasecmp(name
, (gchar
*)"NAME") == 0) {
2833 struct client_s
*cl
= assuan_get_pointer(ctx
);
2836 g_free(cl
->thd
->name
);
2838 cl
->thd
->name
= g_strdup(value
);
2839 log_write("OPTION CLIENT %s", line
);
2842 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2847 static int option_handler(assuan_context_t ctx
, const gchar
*name
,
2850 struct client_s
*client
= assuan_get_pointer(ctx
);
2852 if (!value
|| !*value
)
2853 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2855 if (g_strcasecmp(name
, (gchar
*)"client") == 0)
2856 return parse_client_option(ctx
, value
);
2858 if (g_strcasecmp(name
, (gchar
*)"iterations") == 0) {
2863 n
= strtol(value
, &p
, 10);
2865 if (errno
|| (p
&& *p
) || n
< 0)
2866 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2868 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
: "global", "iterations", (guint
)n
);
2869 send_status_all(STATUS_CONFIG
);
2871 #ifdef WITH_PINENTRY
2872 else if (g_strcasecmp(name
, (gchar
*)"ttyname") == 0) {
2873 g_free(client
->pinentry
->ttyname
);
2874 client
->pinentry
->ttyname
= g_strdup(value
);
2876 else if (g_strcasecmp(name
, (gchar
*)"ttytype") == 0) {
2877 g_free(client
->pinentry
->ttytype
);
2878 client
->pinentry
->ttytype
= g_strdup(value
);
2880 else if (g_strcasecmp(name
, (gchar
*)"display") == 0) {
2881 g_free(client
->pinentry
->display
);
2882 client
->pinentry
->display
= g_strdup(value
);
2884 else if (g_strcasecmp(name
, (gchar
*)"path") == 0) {
2885 g_free(client
->pinentry
->path
);
2886 client
->pinentry
->path
= g_strdup(value
);
2888 else if (g_strcasecmp(name
, (gchar
*)"title") == 0) {
2889 g_free(client
->pinentry
->title
);
2890 client
->pinentry
->title
= g_strdup(value
);
2892 else if (g_strcasecmp(name
, (gchar
*)"prompt") == 0) {
2893 g_free(client
->pinentry
->prompt
);
2894 client
->pinentry
->prompt
= g_strdup(value
);
2896 else if (g_strcasecmp(name
, (gchar
*)"desc") == 0) {
2897 g_free(client
->pinentry
->desc
);
2898 client
->pinentry
->desc
= g_strdup(value
);
2901 * Look at client_thread() to see how this works.
2903 else if (g_strcasecmp(name
, (gchar
*)"timeout") == 0) {
2905 gint n
= strtol(value
, &p
, 10);
2908 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2910 client
->pinentry
->timeout
= n
;
2912 else if (g_strcasecmp(name
, (gchar
*)"pinentry") == 0) {
2914 gint n
= strtol(value
, &p
, 10);
2916 if (*p
|| n
< 0 || n
> 1)
2917 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2919 client
->pinentry
->enable
= n
== 0 ? FALSE
: TRUE
;
2923 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2925 log_write("OPTION %s=%s", name
, value
);
2929 gpg_error_t
register_commands(assuan_context_t ctx
)
2933 gint (*handler
)(assuan_context_t
, gchar
*line
);
2935 { "OPEN", open_command
},
2936 { "SAVE", save_command
},
2937 { "LIST", list_command
},
2938 { "REALPATH", realpath_command
},
2939 { "STORE", store_command
},
2940 { "DELETE", delete_command
},
2941 { "GET", get_command
},
2942 { "ATTR", attr_command
},
2943 { "ISCACHED", iscached_command
},
2944 { "CLEARCACHE", clearcache_command
},
2945 { "CACHETIMEOUT", cachetimeout_command
},
2946 { "GETCONFIG", getconfig_command
},
2947 { "DUMP", dump_command
},
2948 { "XPATH", xpath_command
},
2949 { "IMPORT", import_command
},
2950 { "LOCK", lock_command
},
2951 { "UNLOCK", unlock_command
},
2952 { "GETPID", getpid_command
},
2953 { "VERSION", version_command
},
2960 for (i
=0; table
[i
].name
; i
++) {
2961 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
2967 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
2972 rc
= assuan_register_option_handler(ctx
, option_handler
);
2977 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
2982 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
2985 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, guchar
*key
,
2986 struct client_crypto_s
*crypto
, gpointer
*dst
, gsize
*dst_len
)
2989 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
2990 guint iter
= 0, n_iter
= 0, iter_progress
= 0;
2994 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->fh1
) : sizeof(crypto
->fh
->fh2
);
2995 glong fh_iter
= crypto
->fh
->v1
? crypto
->fh
->fh1
.iter
: crypto
->fh
->fh2
.iter
;
2997 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
2998 insize
= crypto
->fh
->st
.st_size
- fh_size
;
2999 crypto
->iv
= gcry_malloc(gcryblocksize
);
3002 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3003 return gpg_error_from_errno(ENOMEM
);
3006 /* No encryption iterations. This is a plain (gzipped) file. */
3007 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0)) {
3009 * cache_file_count() needs both .used == TRUE and a valid key in
3010 * order for it to count as a used cache entry. Fixes CACHE status
3013 memset(key
, '!', gcrykeysize
);
3017 memcpy(crypto
->iv
, crypto
->fh
->fh1
.iv
, gcryblocksize
);
3019 memcpy(crypto
->iv
, crypto
->fh
->fh2
.iv
, gcryblocksize
);
3021 crypto
->inbuf
= gcry_malloc(insize
);
3023 if (!crypto
->inbuf
) {
3024 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3025 return gpg_error_from_errno(ENOMEM
);
3028 crypto
->insize
= insize
;
3029 len
= read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
3031 if (len
!= crypto
->insize
)
3032 return GPG_ERR_INV_LENGTH
;
3034 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0))
3037 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
3038 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3042 if ((rc
= gcry_cipher_setkey(crypto
->gh
, key
, gcrykeysize
))) {
3043 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3047 iter_progress
= (guint
)get_key_file_integer(client
&& client
->filename
?
3048 client
->filename
: "global", "iteration_progress");
3050 if (iter_progress
> 0 && fh_iter
>= iter_progress
) {
3051 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u", 0, fh_iter
);
3057 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3062 crypto
->tkey
= gcry_malloc(gcrykeysize
);
3064 if (!crypto
->tkey
) {
3065 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
3066 return gpg_error_from_errno(ENOMEM
);
3069 memcpy(crypto
->tkey
, key
, gcrykeysize
);
3070 guchar
*tkey
= crypto
->tkey
;
3073 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
3074 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3078 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
3079 if (iter_progress
> 0 && iter
>= iter_progress
) {
3080 if (!(iter
% iter_progress
)) {
3081 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u",
3082 ++n_iter
* iter_progress
, fh_iter
);
3089 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
3090 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3094 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3097 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3104 if (iter_progress
&& fh_iter
>= iter_progress
) {
3105 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u", fh_iter
, fh_iter
);
3112 if (do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
3113 (gpointer
*)&crypto
->outbuf
, &outsize
, &zrc
) == FALSE
) {
3114 if (zrc
== Z_MEM_ERROR
)
3115 return gpg_error_from_errno(ENOMEM
);
3117 return EPWMD_BADKEY
; // Not a valid gzip header. Must be a bad key.
3120 if (g_strncasecmp(crypto
->outbuf
, "<?xml version=\"1.0\"?>", 21) != 0) {
3121 gcry_free(crypto
->outbuf
);
3122 crypto
->outbuf
= NULL
;
3123 return EPWMD_BADKEY
;
3127 client
->xml
= crypto
->outbuf
;
3128 client
->len
= outsize
;
3129 crypto
->outbuf
= NULL
;
3132 *dst
= crypto
->outbuf
;
3134 crypto
->outbuf
= NULL
;
3137 /* The calling function should free the crypto struct. */
3142 * This is called after every Assuan command.
3144 void command_finalize(assuan_context_t ctx
, gint rc
)
3146 struct client_s
*client
= assuan_get_pointer(ctx
);
3148 if (!client
->is_lock_cmd
)
3149 unlock_file_mutex(client
);