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
);
152 pthread_testcancel();
161 MUTEX_LOCK(&m
->mutex
);
168 client
->has_lock
= TRUE
;
172 void free_client(struct client_s
*client
)
175 xmlFreeDoc(client
->doc
);
178 gcry_free(client
->xml
);
180 if (client
->filename
)
181 g_free(client
->filename
);
184 cleanup_crypto(&client
->crypto
);
186 if (client
->xml_error
)
187 xmlResetError(client
->xml_error
);
190 void cleanup_client(struct client_s
*client
)
192 assuan_context_t ctx
= client
->ctx
;
193 struct client_thread_s
*thd
= client
->thd
;
194 gboolean has_lock
= client
->has_lock
;
196 struct pinentry_s
*pin
= client
->pinentry
;
199 unlock_file_mutex(client
);
200 CACHE_LOCK(client
->ctx
);
201 cache_decr_refcount(client
->md5file
);
204 * This may be a new file so don't use a cache slot. save_command() will
205 * set this to FALSE on success.
207 if (client
->new == TRUE
)
208 cache_clear(client
->md5file
, 1);
212 memset(client
, 0, sizeof(struct client_s
));
213 client
->state
= STATE_CONNECTED
;
216 client
->freed
= TRUE
;
218 client
->pinentry
= pin
;
220 client
->has_lock
= has_lock
;
223 static void gz_cleanup(void *arg
)
225 struct gz_s
**gz
= (struct gz_s
**)arg
;
230 if (!(*gz
)->done
&& (*gz
)->out
)
231 gcry_free((*gz
)->out
);
234 if ((*gz
)->which
== STATUS_COMPRESS
) {
236 deflateEnd(&(*gz
)->z
);
240 inflateEnd(&(*gz
)->z
);
247 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
248 gpointer
*out
, gulong
*outsize
, gint
*rc
)
254 gz
= g_malloc0(sizeof(struct gz_s
));
257 *rc
= gpg_error_from_errno(ENOMEM
);
261 gz
->which
= STATUS_DECOMPRESS
;
262 pthread_cleanup_push(gz_cleanup
, &gz
);
263 gz
->z
.zalloc
= z_alloc
;
264 gz
->z
.zfree
= z_free
;
266 gz
->z
.avail_in
= (uInt
)insize
;
267 gz
->z
.avail_out
= zlib_bufsize
;
268 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
271 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
277 *rc
= inflateInit2(&gz
->z
, 47);
280 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
285 memset(&h
, 0, sizeof(gz_header
));
286 h
.comment
= (guchar
*)buf
;
287 h
.comm_max
= sizeof(buf
);
288 *rc
= inflateGetHeader(&gz
->z
, &h
);
291 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
296 *rc
= inflate(&gz
->z
, Z_BLOCK
);
299 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
305 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
310 *rc
= inflate(&gz
->z
, Z_FINISH
);
316 if (!gz
->z
.avail_out
) {
317 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
320 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
326 gz
->z
.next_out
= gz
->out
+ gz
->z
.total_out
;
327 gz
->z
.avail_out
= zlib_bufsize
;
328 pthread_cleanup_push(gz_cleanup
, &gz
);
329 pthread_testcancel();
330 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
331 gz
->z
.total_out
, insize
);
332 pthread_testcancel();
333 pthread_cleanup_pop(0);
345 } while (*rc
!= Z_STREAM_END
);
347 pthread_testcancel();
348 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
350 pthread_testcancel();
356 *outsize
= gz
->z
.total_out
;
363 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
364 pthread_cleanup_pop(1);
368 static void read_file_header_handler(void *arg
)
373 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
378 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
384 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
385 *rc
= gpg_error_from_errno(ENOMEM
);
389 fh_size
= v1
? sizeof(fh
->fh1
) : sizeof(fh
->fh2
);
391 if (lstat(filename
, &fh
->st
) == -1) {
392 *rc
= gpg_error_from_syserror();
397 if (!S_ISREG(fh
->st
.st_mode
)) {
398 *rc
= GPG_ERR_ENOANO
;
403 fd
= open(filename
, O_RDONLY
);
406 *rc
= gpg_error_from_errno(errno
);
412 len
= read(fd
, &fh
->fh1
, fh_size
);
414 len
= read(fd
, &fh
->fh2
, fh_size
);
416 if (len
!= fh_size
) {
418 pthread_cleanup_push(read_file_header_handler
, (void *)fd
);
420 pthread_cleanup_pop(1);
421 *rc
= gpg_error_from_errno(n
);
430 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*key
,
433 struct client_s
*client
= assuan_get_pointer(ctx
);
438 if (!client
->crypto
->fh
) {
445 rc
= try_xml_decrypt(ctx
, key
, client
->crypto
, NULL
, NULL
);
448 cleanup_client(client
);
449 return send_error(ctx
, rc
);
453 CACHE_LOCK(client
->ctx
);
455 if (cached
== FALSE
) {
456 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
457 cleanup_client(client
);
459 return send_syserror(ctx
, ENOMEM
);
462 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
463 cache_reset_timeout(client
->md5file
, timeout
);
466 cache_set_timeout(client
->md5file
, -2);
474 gcry_free(client
->xml
);
479 if (client
->new == FALSE
)
480 send_status_all(STATUS_CACHE
);
482 client
->state
= STATE_OPEN
;
485 if (!rc
&& client
->new == FALSE
&&
486 client
->crypto
->fh
->fh2
.iter
!= (guint64
)get_key_file_integer(client
->filename
, "iterations")) {
487 g_key_file_set_integer(keyfileh
, client
->filename
, "iterations",
488 client
->crypto
->fh
->fh2
.iter
);
489 send_status_all(STATUS_CONFIG
);
493 log_write("OPEN '%s'", client
->filename
);
495 cleanup_crypto(&client
->crypto
);
496 return send_error(ctx
, rc
);
500 static gboolean
validate_access(struct client_s
*cl
, const gchar
*filename
)
502 gchar
*access
= get_key_file_string(filename
, "tcp_access");
508 list
= g_strsplit(access
, ",", -1);
512 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
516 for (p
= list
; *p
; p
++) {
517 gboolean
not = FALSE
;
528 if (strcasecmp(cl
->thd
->tls
->fp
, fp
) == 0) {
543 static void req_cleanup(void *arg
)
548 g_strfreev((gchar
**)arg
);
551 static int open_command(assuan_context_t ctx
, char *line
)
553 gboolean cached
= FALSE
;
555 struct client_s
*client
= assuan_get_pointer(ctx
);
557 gchar
*filename
= NULL
;
559 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
562 pthread_cleanup_push(req_cleanup
, req
);
564 if (!filename
|| !*filename
) {
566 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
569 if (valid_filename(filename
) == FALSE
) {
571 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
574 if (client
->state
== STATE_OPEN
)
575 cleanup_client(client
);
578 if (client
->thd
->remote
== TRUE
) {
579 if (validate_access(client
, filename
) == FALSE
) {
580 log_write(N_("client validation failed for file '%s'"), filename
);
582 return send_error(ctx
, EPWMD_FILE_ACCESS
);
587 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
588 CACHE_LOCK(client
->ctx
);
590 if (cache_has_file(client
->md5file
) == FALSE
) {
591 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
594 return send_syserror(ctx
, ENOMEM
);
598 cache_incr_refcount(client
->md5file
);
600 rc
= lock_file_mutex(client
);
604 return send_error(ctx
, rc
);
607 client
->freed
= FALSE
;
608 client
->crypto
= init_client_crypto();
610 if (!client
->crypto
) {
612 cleanup_client(client
);
613 return send_syserror(ctx
, ENOMEM
);
616 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
618 if (!client
->crypto
->key
) {
620 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
621 gpg_error_from_errno(ENOMEM
));
622 cleanup_client(client
);
623 return send_syserror(ctx
, ENOMEM
);
626 memset(client
->crypto
->key
, 0, gcrykeysize
);
627 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
628 pthread_testcancel();
630 if (!client
->crypto
->fh
) {
631 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
632 log_write("%s: %s", filename
, pwmd_strerror(rc
));
634 cleanup_client(client
);
635 return send_error(ctx
, rc
);
639 * New files don't need a key.
641 if ((client
->xml
= new_document()) == NULL
) {
642 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
644 cleanup_client(client
);
645 return send_syserror(ctx
, ENOMEM
);
648 client
->len
= xmlStrlen(client
->xml
);
650 client
->filename
= g_strdup(filename
);
652 if (!client
->filename
) {
654 cleanup_client(client
);
655 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
656 return send_syserror(ctx
, ENOMEM
);
659 if (req
[1] && *req
[1])
660 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
665 client
->pinentry
->filename
= g_strdup(client
->filename
);
667 if (!client
->pinentry
->filename
) {
668 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
669 cleanup_client(client
);
670 return send_syserror(ctx
, ENOMEM
);
673 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
676 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
678 client
->filename
= g_strdup(filename
);
680 if (!client
->filename
) {
681 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
683 cleanup_client(client
);
684 return send_syserror(ctx
, ENOMEM
);
688 client
->pinentry
->filename
= g_strdup(client
->filename
);
690 if (!client
->pinentry
->filename
) {
691 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
693 cleanup_client(client
);
694 return send_syserror(ctx
, ENOMEM
);
698 if (client
->crypto
->fh
->fh2
.iter
<= 0)
702 if (client
->thd
->remote
== FALSE
||
703 get_key_file_boolean(client
->filename
, "tcp_require_key") == FALSE
)
706 CACHE_LOCK(client
->ctx
);
707 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
715 if (cached
== FALSE
) {
716 gchar
*tmp
= get_key_file_string(filename
, "key_file");
720 cleanup_client(client
);
721 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
725 * No key specified and no matching filename found in the cache. Use
726 * pinentry to retrieve the key. Cannot return assuan_process_done()
727 * here otherwise the command will be interrupted. The event loop in
728 * client_thread() will poll the file descriptor waiting for it to
729 * become ready to read a pinentry_key_s which will contain the
730 * entered key or an error code. It will then call
731 * open_command_finalize() to to finish the command.
733 if (!req
[1] || !*req
[1]) {
735 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
737 /* From set_pinentry_defaults(). */
738 if (client
->pinentry
->enable
== FALSE
||
739 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
740 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
745 rc
= lock_pin_mutex(client
);
748 unlock_pin_mutex(client
->pinentry
);
749 cleanup_client(client
);
750 return send_error(ctx
, rc
);
753 client
->pinentry
->which
= PINENTRY_OPEN
;
754 rc
= pinentry_fork(ctx
);
757 unlock_pin_mutex(client
->pinentry
);
758 cleanup_client(client
);
759 return send_error(ctx
, rc
);
762 // Called from pinentry iterate.
763 client
->pinentry
->cb
= open_command_finalize
;
764 client
->pinentry
->status
= PINENTRY_INIT
;
767 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
772 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
778 pthread_cleanup_pop(1);
779 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
782 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
783 gulong size
, gpointer
*out
, gulong
*outsize
, gint
*rc
)
788 gint cmd
= Z_NO_FLUSH
;
790 gz
= g_malloc0(sizeof(struct gz_s
));
793 *rc
= gpg_error_from_errno(ENOMEM
);
797 gz
->which
= STATUS_COMPRESS
;
798 pthread_cleanup_push(gz_cleanup
, &gz
);
799 gz
->z
.zalloc
= z_alloc
;
800 gz
->z
.zfree
= z_free
;
801 gz
->z
.next_in
= data
;
802 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
803 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
804 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
807 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
813 *rc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
816 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
821 /* Rather than store the size of the uncompressed data in the file header,
822 * store it in the comment field of the gzip header. Don't give anyone too
823 * much information. Not sure why really, but it seems the right way. :)
825 memset(&h
, 0, sizeof(gz_header
));
826 g_snprintf(buf
, sizeof(buf
), "%li", size
);
827 h
.comment
= (guchar
*)buf
;
828 *rc
= deflateSetHeader(&gz
->z
, &h
);
831 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
839 *rc
= deflate(&gz
->z
, cmd
);
845 if (!gz
->z
.avail_out
) {
846 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
849 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
855 gz
->z
.next_out
= gz
->out
+ gz
->z
.total_out
;
856 gz
->z
.avail_out
= zlib_bufsize
;
859 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
860 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
861 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
863 gz
->z
.avail_in
= zlib_bufsize
;
865 pthread_cleanup_push(gz_cleanup
, &gz
);
866 pthread_testcancel();
867 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li",
868 gz
->z
.total_in
, size
);
869 pthread_testcancel();
870 pthread_cleanup_pop(0);
876 if (gz
->z
.total_in
>= size
)
885 } while (*rc
!= Z_STREAM_END
);
887 pthread_testcancel();
888 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li", gz
->z
.total_in
, size
);
889 pthread_testcancel();
895 *outsize
= gz
->z
.total_out
;
902 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
903 pthread_cleanup_pop(1);
907 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
909 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
910 struct client_crypto_s
*crypto
, status_msg_t which
)
913 gsize len
= CRYPTO_BLOCKSIZE
;
914 gpointer p
= gcry_malloc(len
);
919 return gpg_err_code_from_errno(ENOMEM
);
921 pthread_cleanup_push(gcry_free
, p
);
923 if (crypto
->insize
< CRYPTO_BLOCKSIZE
)
924 len
= crypto
->insize
;
927 inbuf
= crypto
->inbuf
+ total
;
930 if (len
+ total
> crypto
->insize
)
933 if (which
== STATUS_ENCRYPT
)
934 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
936 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
941 tmp
= crypto
->inbuf
+total
;
942 memmove(tmp
, p
, len
);
945 if (total
>= crypto
->insize
)
948 pthread_testcancel();
953 pthread_cleanup_pop(1);
957 /* The crypto struct must be setup for iterations and .key. */
958 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
959 struct client_crypto_s
*crypto
, const gchar
*filename
)
961 gsize len
= crypto
->insize
;
965 guint64 iter_progress
= 0, n_iter
= 0, xiter
= 0;
966 gchar tmp
[FILENAME_MAX
];
970 if (!crypto
->fh
->fh2
.iter
) {
972 * cache_file_count() needs both .used == TRUE and a valid key in
973 * order for it to count as a used cache entry. Fixes CACHE status
976 memset(crypto
->key
, '!', gcrykeysize
);
981 * Resize the existing xml buffer to the block size required by gcrypt
982 * rather than duplicating it and wasting memory.
984 if (crypto
->insize
/ gcryblocksize
) {
985 len
= (crypto
->insize
/ gcryblocksize
) * gcryblocksize
;
987 if (crypto
->insize
% gcryblocksize
)
988 len
+= gcryblocksize
;
991 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
994 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
995 return gpg_error_from_errno(ENOMEM
);
998 crypto
->inbuf
= inbuf
;
999 crypto
->insize
= len
;
1000 gcry_create_nonce(crypto
->fh
->fh2
.iv
, sizeof(crypto
->fh
->fh2
.iv
));
1001 crypto
->tkey
= gcry_malloc(gcrykeysize
);
1003 if (!crypto
->tkey
) {
1004 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1005 return gpg_error_from_errno(ENOMEM
);
1008 memcpy(crypto
->tkey
, crypto
->key
, gcrykeysize
);
1009 guchar
*tkey
= crypto
->tkey
;
1012 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
1013 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1017 iter_progress
= (guint64
)get_key_file_integer(
1018 client
? client
->filename
: "global", "iteration_progress");
1020 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
1021 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1022 "0 %llu", crypto
->fh
->fh2
.iter
);
1023 pthread_testcancel();
1029 while (xiter
< crypto
->fh
->fh2
.iter
-1) {
1030 if (iter_progress
> 0 && xiter
>= iter_progress
) {
1031 if (!(xiter
% iter_progress
)) {
1032 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1033 "%llu %llu", ++n_iter
* iter_progress
,
1034 crypto
->fh
->fh2
.iter
);
1035 pthread_testcancel();
1042 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
1043 sizeof(crypto
->fh
->fh2
.iv
)))) {
1044 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1048 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1051 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1058 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
1059 sizeof(crypto
->fh
->fh2
.iv
)))) {
1060 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1064 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, gcrykeysize
))) {
1065 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1069 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1074 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
1075 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1076 "%llu %llu", crypto
->fh
->fh2
.iter
, crypto
->fh
->fh2
.iter
);
1077 pthread_testcancel();
1085 if (!client
&& !strcmp(filename
, "-")) {
1086 crypto
->fh
->fd
= STDOUT_FILENO
;
1090 if (lstat(filename
, &st
) == 0) {
1091 pthread_testcancel();
1092 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1095 * FIXME What if the file has an ACL?
1097 if (!(mode
& S_IWUSR
))
1098 return gpg_error_from_errno(EACCES
);
1101 pthread_testcancel();
1102 if (errno
!= ENOENT
)
1103 return gpg_error_from_errno(errno
);
1106 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1107 crypto
->fh
->fd
= mkstemp(tmp
);
1109 if (crypto
->fh
->fd
== -1) {
1111 p
= strrchr(tmp
, '/');
1113 log_write("%s: %s", p
, strerror(rc
));
1114 return gpg_error_from_errno(rc
);
1119 * xml_import() or convert_file() from command line.
1121 crypto
->fh
->fd
= STDOUT_FILENO
;
1124 crypto
->fh
->fh2
.version
= VERSION_HEX
;
1125 len
= write(crypto
->fh
->fd
, &crypto
->fh
->fh2
, sizeof(crypto
->fh
->fh2
));
1126 pthread_testcancel();
1128 if (len
!= sizeof(crypto
->fh
->fh2
)) {
1131 if (filename
&& strcmp(filename
, "-"))
1134 return gpg_error_from_errno(len
);
1137 len
= write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1138 pthread_testcancel();
1140 if (len
!= crypto
->insize
) {
1141 pthread_testcancel();
1144 if (filename
&& strcmp(filename
, "-")) {
1146 pthread_testcancel();
1149 return gpg_error_from_errno(len
);
1152 if (fsync(crypto
->fh
->fd
) == -1) {
1153 pthread_testcancel();
1156 if (filename
&& strcmp(filename
, "-"))
1159 return gpg_error_from_errno(len
);
1162 if (filename
&& strcmp(filename
, "-")) {
1163 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1164 gchar tmp2
[FILENAME_MAX
];
1166 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1168 if (rename(filename
, tmp2
) == -1) {
1169 pthread_testcancel();
1172 return gpg_error_from_errno(len
);
1176 if (rename(tmp
, filename
) == -1) {
1177 pthread_testcancel();
1180 return gpg_error_from_errno(len
);
1184 chmod(filename
, mode
);
1185 pthread_testcancel();
1189 if (client
&& lstat(filename
, &st
) == 0)
1190 client
->mtime
= st
.st_mtime
;
1192 pthread_testcancel();
1196 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1199 struct client_s
*client
= assuan_get_pointer(ctx
);
1201 gulong len
, outsize
= 0;
1208 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1209 gcry_free(client
->crypto
->key
);
1211 client
->crypto
->key
= key
;
1212 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1213 iter
= (guint
)get_key_file_integer(client
->filename
, "compression_level");
1218 if (do_compress(ctx
, (gint
)iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
)
1221 cleanup_crypto(&client
->crypto
);
1223 if (zrc
== Z_MEM_ERROR
)
1224 return send_syserror(ctx
, ENOMEM
);
1226 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1234 client
->crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1236 if (!client
->crypto
->fh
) {
1237 cleanup_crypto(&client
->crypto
);
1239 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1240 return send_syserror(ctx
, ENOMEM
);
1243 iter
= get_key_file_integer(client
->filename
, "iterations");
1244 client
->crypto
->fh
->fh2
.iter
= iter
< 0 ? 0 : iter
;
1245 client
->crypto
->inbuf
= xmlbuf
;
1246 client
->crypto
->insize
= len
;
1247 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1250 cleanup_crypto(&client
->crypto
);
1251 return send_error(ctx
, rc
);
1254 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1255 CACHE_LOCK(client
->ctx
);
1258 cache_reset_timeout(client
->md5file
, timeout
);
1261 if (client
->new == TRUE
)
1262 send_status_all(STATUS_CACHE
);
1264 client
->new = FALSE
;
1265 cleanup_crypto(&client
->crypto
);
1266 return send_error(ctx
, 0);
1269 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1271 cleanup_crypto(&client
->crypto
);
1272 return send_syserror(ctx
, ENOMEM
);
1275 client
->new = FALSE
;
1276 cache_reset_timeout(client
->md5file
, timeout
);
1278 send_status_all(STATUS_CACHE
);
1279 cleanup_crypto(&client
->crypto
);
1280 return send_error(ctx
, 0);
1283 static int save_command(assuan_context_t ctx
, char *line
)
1285 gboolean cached
= FALSE
;
1287 struct client_s
*client
= assuan_get_pointer(ctx
);
1290 rc
= lock_file_mutex(client
);
1293 return send_error(ctx
, rc
);
1295 rc
= file_modified(client
);
1298 return send_error(ctx
, rc
);
1300 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1301 return send_syserror(ctx
, errno
);
1303 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1304 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1305 return send_error(ctx
, GPG_ERR_ENOANO
);
1309 cached
= cache_iscached(client
->md5file
);
1313 * If a cache entry doesn't exist for this file and the file has a
1314 * "key_file" or "key" parameter, then it's an error. The reason is that
1315 * cache expiration would be useless.
1317 if (cached
== FALSE
) {
1318 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1322 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1327 client
->crypto
= init_client_crypto();
1329 if (!client
->crypto
) {
1330 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1331 return send_syserror(ctx
, ENOMEM
);
1334 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
1336 if (!client
->crypto
->key
) {
1337 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1338 cleanup_crypto(&client
->crypto
);
1339 return send_syserror(ctx
, ENOMEM
);
1342 memset(client
->crypto
->key
, '!', gcrykeysize
);
1344 if (get_key_file_integer(client
->filename
, "iterations") <= 0)
1347 if (!line
|| !*line
) {
1348 client
->crypto
->tkey
= gcry_malloc(gcrykeysize
);
1350 if (!client
->crypto
->tkey
) {
1351 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1352 cleanup_crypto(&client
->crypto
);
1353 return send_syserror(ctx
, ENOMEM
);
1356 memset(client
->crypto
->tkey
, '!', gcrykeysize
);
1359 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1360 memcmp(client
->crypto
->key
, client
->crypto
->tkey
,
1361 gcrykeysize
) == 0) {
1364 #ifdef WITH_PINENTRY
1365 if (client
->pinentry
->enable
== FALSE
||
1366 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1367 /* Empty keys are allowed. */
1368 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1372 lock_pin_mutex(client
);
1373 client
->pinentry
->which
= PINENTRY_SAVE
;
1374 rc
= pinentry_fork(ctx
);
1377 unlock_pin_mutex(client
->pinentry
);
1378 return send_error(ctx
, rc
);
1381 client
->pinentry
->cb
= save_command_finalize
;
1382 client
->pinentry
->status
= PINENTRY_INIT
;
1385 /* Empty keys are allowed. */
1386 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1396 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, line
,
1398 memset(line
, 0, strlen(line
));
1402 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1405 static int delete_command(assuan_context_t ctx
, char *line
)
1407 struct client_s
*client
= assuan_get_pointer(ctx
);
1412 rc
= file_modified(client
);
1415 return send_error(ctx
, rc
);
1417 if (strchr(line
, '\t'))
1418 req
= split_input_line(line
, "\t", -1);
1420 req
= split_input_line(line
, " ", -1);
1423 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1425 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1429 return send_error(ctx
, rc
);
1433 * No sub-node defined. Remove the entire node (account).
1442 return send_error(ctx
, 0);
1445 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1449 return send_error(ctx
, rc
);
1456 return send_error(ctx
, 0);
1460 * Don't return with assuan_process_done() here. This has been called from
1461 * assuan_process_next() and the command should be finished in
1464 static int store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1467 assuan_context_t ctx
= data
;
1468 struct client_s
*client
= assuan_get_pointer(ctx
);
1471 gpg_error_t rc
= file_modified(client
);
1473 if (assuan_rc
|| rc
) {
1476 return assuan_rc
? assuan_rc
: rc
;
1479 req
= split_input_line((gchar
*)line
, "\t", 0);
1483 return EPWMD_COMMAND_SYNTAX
;
1485 if (valid_xml_element((xmlChar
*)*req
) == FALSE
) {
1487 return EPWMD_INVALID_ELEMENT
;
1490 if (valid_element_path(req
+1, TRUE
) == FALSE
) {
1492 return EPWMD_INVALID_ELEMENT
;
1496 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1498 if (rc
&& rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1499 rc
= new_account(client
->doc
, *req
);
1516 create_elements_cb(n
, req
+1, &rc
, NULL
);
1518 find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1519 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
);
1523 client
->inquire_status
= INQUIRE_DONE
;
1527 static int store_command(assuan_context_t ctx
, char *line
)
1529 struct client_s
*client
= assuan_get_pointer(ctx
);
1530 gpg_error_t rc
= file_modified(client
);
1533 return send_error(ctx
, rc
);
1535 pthread_testcancel();
1536 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1537 pthread_testcancel();
1540 return send_error(ctx
, rc
);
1542 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1543 client
->inquire_status
= INQUIRE_BUSY
;
1547 static int get_command(assuan_context_t ctx
, char *line
)
1549 struct client_s
*client
= assuan_get_pointer(ctx
);
1554 rc
= file_modified(client
);
1557 return send_error(ctx
, rc
);
1559 req
= split_input_line(line
, "\t", -1);
1561 if (!req
|| !*req
) {
1563 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1566 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1570 return send_error(ctx
, rc
);
1574 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1579 return send_error(ctx
, rc
);
1581 if (!n
|| !n
->children
)
1582 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1584 n
= find_text_node(n
->children
);
1586 if (!n
|| !n
->content
|| !*n
->content
)
1587 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1589 pthread_testcancel();
1590 rc
= assuan_send_data(ctx
, n
->content
, xmlStrlen(n
->content
));
1591 pthread_testcancel();
1592 return send_error(ctx
, rc
);
1595 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
1596 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
1598 gchar
*path
= *(gchar
**)data
;
1599 gchar
*tmp
= NULL
, *result
;
1603 *(gchar
**)data
= NULL
;
1606 path
= g_strjoinv("\t", target
);
1609 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1610 *rc
= gpg_error_from_errno(ENOMEM
);
1615 tmp
= g_strjoinv("\t", req_orig
);
1619 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1620 *rc
= gpg_error_from_errno(ENOMEM
);
1626 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1628 result
= g_strdup(path
);
1631 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1632 *rc
= gpg_error_from_errno(ENOMEM
);
1640 *(gchar
**)data
= result
;
1644 static void list_command_cleanup1(void *arg
);
1645 static int realpath_command(assuan_context_t ctx
, char *line
)
1648 struct client_s
*client
= assuan_get_pointer(ctx
);
1656 rc
= file_modified(client
);
1659 return send_error(ctx
, rc
);
1661 if (strchr(line
, '\t') != NULL
) {
1662 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1663 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1666 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1667 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1670 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1674 return send_error(ctx
, rc
);
1677 rp
= g_strjoinv("\t", req
);
1681 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1682 return send_syserror(ctx
, ENOMEM
);
1686 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1687 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
);
1692 return send_error(ctx
, rc
);
1696 string
= g_string_new(rp
);
1701 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1702 return send_syserror(ctx
, ENOMEM
);
1706 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
1707 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
1708 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1713 pthread_cleanup_push(list_command_cleanup1
, string
);
1714 pthread_testcancel();
1715 rc
= assuan_send_data(ctx
, string
->str
, string
->len
);
1716 pthread_testcancel();
1717 pthread_cleanup_pop(1);
1718 return send_error(ctx
, rc
);
1721 static void list_command_cleanup1(void *arg
)
1723 g_string_free((GString
*)arg
, TRUE
);
1726 static void list_command_cleanup2(void *arg
)
1728 struct element_list_s
*elements
= arg
;
1731 gint total
= g_slist_length(elements
->list
);
1734 for (i
= 0; i
< total
; i
++) {
1735 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
1739 g_slist_free(elements
->list
);
1741 if (elements
->prefix
)
1742 g_free(elements
->prefix
);
1748 static int list_command(assuan_context_t ctx
, char *line
)
1750 struct client_s
*client
= assuan_get_pointer(ctx
);
1752 struct element_list_s
*elements
= NULL
;
1755 if (disable_list_and_dump
== TRUE
)
1756 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1758 rc
= file_modified(client
);
1761 return send_error(ctx
, rc
);
1766 rc
= list_accounts(client
->doc
, &str
);
1767 pthread_cleanup_push(list_command_cleanup1
, str
);
1770 return send_error(ctx
, rc
);
1772 pthread_testcancel();
1773 rc
= assuan_send_data(ctx
, str
->str
, str
->len
);
1774 pthread_testcancel();
1775 pthread_cleanup_pop(1);
1776 return send_error(ctx
, rc
);
1779 elements
= g_malloc0(sizeof(struct element_list_s
));
1782 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1783 rc
= gpg_err_code_from_errno(ENOMEM
);
1787 pthread_cleanup_push(list_command_cleanup2
, elements
);
1788 pthread_testcancel();
1789 rc
= create_path_list(client
->doc
, elements
, line
);
1790 pthread_testcancel();
1796 gint total
= g_slist_length(elements
->list
);
1801 rc
= EPWMD_EMPTY_ELEMENT
;
1805 str
= g_string_new(NULL
);
1808 rc
= gpg_err_code_from_errno(ENOMEM
);
1809 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1813 pthread_cleanup_push(list_command_cleanup1
, str
);
1815 for (i
= 0; i
< total
; i
++) {
1816 tmp
= g_slist_nth_data(elements
->list
, i
);
1817 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
1820 pthread_testcancel();
1821 rc
= assuan_send_data(ctx
, str
->str
, str
->len
);
1822 pthread_testcancel();
1823 pthread_cleanup_pop(1);
1826 rc
= EPWMD_EMPTY_ELEMENT
;
1830 pthread_cleanup_pop(1);
1831 return send_error(ctx
, rc
);
1834 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1839 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1840 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1843 return EPWMD_LIBXML_ERROR
;
1846 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1852 * req[0] - element path
1854 static int attribute_list(assuan_context_t ctx
, gchar
**req
)
1856 struct client_s
*client
= assuan_get_pointer(ctx
);
1857 gchar
**attrlist
= NULL
;
1859 gchar
**path
= NULL
;
1865 if (!req
|| !req
[0])
1866 return EPWMD_COMMAND_SYNTAX
;
1868 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1870 * The first argument may be only an account.
1872 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1873 return EPWMD_COMMAND_SYNTAX
;
1876 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1884 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1885 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1895 for (a
= n
->properties
; a
; a
= a
->next
) {
1898 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1900 g_strfreev(attrlist
);
1902 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1903 return gpg_error_from_errno(ENOMEM
);
1908 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1911 g_strfreev(attrlist
);
1912 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1913 return gpg_error_from_errno(ENOMEM
);
1916 attrlist
[++i
] = NULL
;
1920 return EPWMD_EMPTY_ELEMENT
;
1922 line
= g_strjoinv("\n", attrlist
);
1925 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1926 g_strfreev(attrlist
);
1927 return gpg_error_from_errno(ENOMEM
);
1930 pthread_cleanup_push(g_free
, line
);
1931 pthread_cleanup_push(req_cleanup
, attrlist
);
1932 pthread_testcancel();
1933 rc
= assuan_send_data(ctx
, line
, strlen(line
));
1934 pthread_testcancel();
1935 pthread_cleanup_pop(1);
1936 pthread_cleanup_pop(1);
1941 * req[0] - attribute
1942 * req[1] - element path
1944 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1948 gchar
**path
= NULL
;
1951 if (!req
|| !req
[0] || !req
[1])
1952 return EPWMD_COMMAND_SYNTAX
;
1954 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1956 * The first argument may be only an account.
1958 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1959 return EPWMD_COMMAND_SYNTAX
;
1963 * Don't remove the "name" attribute for the account element. To remove an
1964 * account use DELETE <account>.
1966 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
1967 rc
= EPWMD_ATTR_SYNTAX
;
1971 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1977 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1978 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1986 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
1987 return EPWMD_ATTR_NOT_FOUND
;
1989 if (xmlRemoveProp(a
) == -1)
1990 return EPWMD_LIBXML_ERROR
;
1999 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
2002 gchar
**src
= *path
;
2003 gchar
**src_orig
= g_strdupv(src
);
2004 xmlNodePtr n
= NULL
;
2009 *rc
= gpg_error_from_errno(ENOMEM
);
2010 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2015 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
2018 if (*rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2019 *rc
= new_account(client
->doc
, src
[0]);
2032 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
2034 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2035 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
);
2041 * Reset the position of the element tree now that the elements
2042 * have been created.
2047 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
2052 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2053 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2061 g_strfreev(src_orig
);
2068 * Creates a "target" attribute. When other commands encounter an element with
2069 * this attribute, the element path is modified to the target value. If the
2070 * source element path doesn't exist when using 'ATTR SET target', it is
2071 * created, but the destination element path must exist.
2073 * req[0] - source element path
2074 * req[1] - destination element path
2076 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2078 gchar
**src
, **dst
, *line
= NULL
;
2082 if (!req
|| !req
[0] || !req
[1])
2083 return EPWMD_COMMAND_SYNTAX
;
2085 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2087 * The first argument may be only an account.
2089 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2090 return EPWMD_COMMAND_SYNTAX
;
2093 if (valid_element_path(src
, FALSE
) == FALSE
) {
2095 return EPWMD_INVALID_ELEMENT
;
2098 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2100 * The first argument may be only an account.
2102 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2103 rc
= EPWMD_COMMAND_SYNTAX
;
2108 n
= find_account(client
->doc
, &dst
, &rc
, NULL
, 0);
2111 * Make sure the destination element path exists.
2117 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2118 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2124 n
= create_element_path(client
, &src
, &rc
);
2129 line
= g_strjoinv("\t", dst
);
2132 rc
= gpg_error_from_errno(ENOMEM
);
2133 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2137 rc
= add_attribute(n
, "target", line
);
2147 * req[0] - account name
2150 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2156 tmp
= g_strdupv(req
);
2159 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2160 return gpg_error_from_errno(ENOMEM
);
2163 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2169 if (g_utf8_collate(req
[0], req
[1]) == 0)
2173 * Will not overwrite an existing account.
2175 tmp
= g_strdupv(req
+1);
2178 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2179 return gpg_error_from_errno(ENOMEM
);
2182 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2185 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
2189 return EPWMD_ACCOUNT_EXISTS
;
2192 * Whitespace not allowed in account names.
2194 if (contains_whitespace(req
[1]) == TRUE
)
2195 return EPWMD_ATTR_SYNTAX
;
2197 tmp
= g_strdupv(req
);
2200 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2201 return gpg_error_from_errno(ENOMEM
);
2204 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2208 return EPWMD_ELEMENT_NOT_FOUND
;
2210 return add_attribute(n
, "name", req
[1]);
2214 * req[0] - attribute
2215 * req[1] - element path
2217 static int attribute_get(assuan_context_t ctx
, gchar
**req
)
2219 struct client_s
*client
= assuan_get_pointer(ctx
);
2225 if (!req
|| !req
[0] || !req
[1])
2226 return EPWMD_COMMAND_SYNTAX
;
2228 if (strchr(req
[1], '\t')) {
2229 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2230 return EPWMD_COMMAND_SYNTAX
;
2233 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2234 return EPWMD_COMMAND_SYNTAX
;
2237 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2243 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2244 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2252 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2253 return EPWMD_ATTR_NOT_FOUND
;
2255 pthread_cleanup_push(xmlFree
, a
);
2256 pthread_testcancel();
2257 rc
= assuan_send_data(ctx
, a
, xmlStrlen(a
));
2258 pthread_testcancel();
2259 pthread_cleanup_pop(1);
2268 * req[0] - attribute
2269 * req[1] - element path
2272 static int attribute_set(struct client_s
*client
, gchar
**req
)
2274 gchar
**path
= NULL
;
2278 if (!req
|| !req
[0] || !req
[1] || !req
[2])
2279 return EPWMD_COMMAND_SYNTAX
;
2282 * Reserved attribute names.
2284 if (g_utf8_collate(req
[0], "name") == 0) {
2286 * Only reserved for the account element. Not the rest of the
2289 if (strchr(req
[1], '\t') == NULL
)
2290 return name_attribute(client
, req
+ 1);
2292 else if (g_utf8_collate(req
[0], "target") == 0)
2293 return target_attribute(client
, req
+ 1);
2295 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2297 * The first argument may be only an account.
2299 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2300 return EPWMD_COMMAND_SYNTAX
;
2303 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2309 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2310 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2317 return add_attribute(n
, req
[0], req
[2]);
2326 * req[1] - attribute name or element path if command is LIST
2327 * req[2] - element path
2328 * req[2] - element path or value
2330 static int attr_command(assuan_context_t ctx
, char *line
)
2332 struct client_s
*client
= assuan_get_pointer(ctx
);
2336 rc
= file_modified(client
);
2339 return send_error(ctx
, rc
);
2341 req
= split_input_line(line
, " ", 4);
2343 if (!req
|| !req
[0] || !req
[1]) {
2345 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2348 pthread_cleanup_push(req_cleanup
, req
);
2350 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2351 rc
= attribute_set(client
, req
+1);
2352 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2353 rc
= attribute_get(ctx
, req
+1);
2354 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2355 rc
= attribute_delete(client
, req
+1);
2356 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2357 rc
= attribute_list(ctx
, req
+1);
2359 rc
= EPWMD_COMMAND_SYNTAX
;
2361 pthread_cleanup_pop(1);
2362 return send_error(ctx
, rc
);
2365 static int iscached_command(assuan_context_t ctx
, char *line
)
2367 gchar
**req
= split_input_line(line
, " ", 0);
2370 if (!req
|| !*req
) {
2372 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2375 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2377 pthread_cleanup_push(pthread_mutex_unlock
, (void *)&cache_mutex
);
2380 if (cache_iscached(md5file
) == FALSE
) {
2382 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2386 pthread_cleanup_pop(0);
2387 return send_error(ctx
, 0);
2390 static int clearcache_command(assuan_context_t ctx
, char *line
)
2392 struct client_s
*client
= assuan_get_pointer(ctx
);
2393 gchar
**req
= split_input_line(line
, " ", 0);
2396 pthread_cleanup_push(pthread_mutex_unlock
, (void *)&cache_mutex
);
2399 if (!req
|| !*req
) {
2401 cache_clear(client
->md5file
, 2);
2403 return send_error(ctx
, 0);
2406 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2409 if (cache_clear(md5file
, 1) == FALSE
) {
2411 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2415 pthread_cleanup_pop(0);
2416 return send_error(ctx
, 0);
2419 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2423 gchar
**req
= split_input_line(line
, " ", 0);
2425 struct client_s
*client
= assuan_get_pointer(ctx
);
2427 pthread_cleanup_push(req_cleanup
, req
);
2429 if (!req
|| !*req
|| !req
[1]) {
2431 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2435 timeout
= strtol(req
[0], &p
, 10);
2437 if (errno
!= 0 || *p
!= 0) {
2439 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2442 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2443 pthread_cleanup_pop(1);
2444 pthread_cleanup_push(pthread_mutex_unlock
, (void *)&cache_mutex
);
2445 CACHE_LOCK(client
->ctx
);
2447 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2449 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2453 pthread_cleanup_pop(0);
2454 return send_error(ctx
, 0);
2457 static int dump_command(assuan_context_t ctx
, char *line
)
2461 struct client_s
*client
= assuan_get_pointer(ctx
);
2464 if (disable_list_and_dump
== TRUE
)
2465 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2467 rc
= file_modified(client
);
2470 return send_error(ctx
, rc
);
2472 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2475 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2476 return send_syserror(ctx
, ENOMEM
);
2479 pthread_cleanup_push(xmlFree
, xml
);
2480 pthread_testcancel();
2481 rc
= assuan_send_data(ctx
, xml
, len
);
2482 pthread_testcancel();
2483 pthread_cleanup_pop(1);
2484 return send_error(ctx
, rc
);
2487 static int getconfig_command(assuan_context_t ctx
, gchar
*line
)
2489 struct client_s
*client
= assuan_get_pointer(ctx
);
2491 gchar filename
[255]={0}, param
[747]={0};
2492 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2494 if (strchr(line
, ' ')) {
2495 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2500 if (fp
&& !valid_filename(fp
))
2501 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
2503 paramp
= g_ascii_strdown(paramp
, -1);
2506 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2507 return send_syserror(ctx
, ENOMEM
);
2510 p
= get_key_file_string(fp
? fp
: "global", paramp
);
2514 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2516 tmp
= expand_homedir(p
);
2520 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2521 return send_syserror(ctx
, ENOMEM
);
2525 pthread_cleanup_push(g_free
, p
);
2526 pthread_testcancel();
2527 rc
= assuan_send_data(ctx
, p
, strlen(p
));
2528 pthread_testcancel();
2529 pthread_cleanup_pop(1);
2530 return send_error(ctx
, rc
);
2534 xmlXPathContextPtr xp
;
2535 xmlXPathObjectPtr result
;
2540 static void xpath_command_cleanup(void *arg
)
2542 struct xpath_s
*xpath
= arg
;
2544 req_cleanup(xpath
->req
);
2547 xmlBufferFree(xpath
->buf
);
2550 xmlXPathFreeObject(xpath
->result
);
2553 xmlXPathFreeContext(xpath
->xp
);
2556 static int xpath_command(assuan_context_t ctx
, gchar
*line
)
2558 struct client_s
*client
= assuan_get_pointer(ctx
);
2560 struct xpath_s xpath
;
2562 if (disable_list_and_dump
== TRUE
)
2563 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2565 rc
= file_modified(client
);
2568 return send_error(ctx
, rc
);
2570 if (!line
|| !*line
)
2571 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2573 memset(&xpath
, 0, sizeof(struct xpath_s
));
2574 pthread_cleanup_push(xpath_command_cleanup
, &xpath
);
2576 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
2577 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
2578 return send_syserror(ctx
, ENOMEM
);
2581 xpath
.xp
= xmlXPathNewContext(client
->doc
);
2584 xpath_command_cleanup(&xpath
);
2585 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2588 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
2590 if (!xpath
.result
) {
2591 xpath_command_cleanup(&xpath
);
2592 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2595 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
2596 rc
= EPWMD_EMPTY_ELEMENT
;
2600 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
2601 (xmlChar
*)xpath
.req
[1], &xpath
.buf
);
2605 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
2606 rc
= EPWMD_EMPTY_ELEMENT
;
2609 else if (xpath
.req
[1])
2612 pthread_testcancel();
2613 rc
= assuan_send_data(ctx
, xmlBufferContent(xpath
.buf
),
2614 xmlBufferLength(xpath
.buf
));
2615 pthread_testcancel();
2619 pthread_cleanup_pop(1);
2620 return send_error(ctx
, rc
);
2623 static int import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
2626 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
2627 gpg_error_t rc
= file_modified(client
);
2628 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
2630 xmlNodePtr n
, root
, copy
;
2632 if (assuan_rc
|| rc
) {
2635 return assuan_rc
? assuan_rc
: rc
;
2638 req
= split_input_line((gchar
*)line
, " ", 2);
2642 return EPWMD_COMMAND_SYNTAX
;
2644 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2645 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2646 return EPWMD_COMMAND_SYNTAX
;
2651 if (!content
|| !*content
) {
2652 rc
= EPWMD_COMMAND_SYNTAX
;
2656 if (valid_xml_element((xmlChar
*)*path
) == FALSE
) {
2657 rc
= EPWMD_INVALID_ELEMENT
;
2661 if (valid_element_path(path
+1, FALSE
) == FALSE
) {
2662 rc
= EPWMD_INVALID_ELEMENT
;
2666 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2669 rc
= EPWMD_LIBXML_ERROR
;
2673 root
= xmlDocGetRootElement(doc
);
2674 path_orig
= g_strdupv(path
);
2678 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2679 rc
= gpg_error_from_errno(ENOMEM
);
2683 if (strv_printf(&path
, "%s", (gchar
*)root
->name
) == FALSE
) {
2684 g_strfreev(path_orig
);
2686 rc
= gpg_error_from_errno(ENOMEM
);
2690 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2692 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2693 g_strfreev(path_orig
);
2698 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2700 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2701 g_strfreev(path_orig
);
2706 xmlNodePtr parent
= n
->parent
;
2717 if (rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2718 n
= create_element_path(client
, &path
, &rc
);
2726 copy
= xmlCopyNode(root
, 1);
2727 n
= xmlAddChild(n
, copy
);
2731 rc
= EPWMD_LIBXML_ERROR
;
2736 client
->inquire_status
= INQUIRE_DONE
;
2740 static int import_command(assuan_context_t ctx
, gchar
*line
)
2743 struct client_s
*client
= assuan_get_pointer(ctx
);
2745 rc
= file_modified(client
);
2748 return send_error(ctx
, rc
);
2750 pthread_testcancel();
2751 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
2752 pthread_testcancel();
2755 return send_error(ctx
, rc
);
2757 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2758 client
->inquire_status
= INQUIRE_BUSY
;
2762 static int lock_command(assuan_context_t ctx
, gchar
*line
)
2765 struct client_s
*client
= assuan_get_pointer(ctx
);
2767 rc
= file_modified(client
);
2770 return send_error(ctx
, rc
);
2772 rc
= lock_file_mutex(client
);
2775 client
->is_lock_cmd
= TRUE
;
2777 return send_error(ctx
, rc
);
2780 static int unlock_command(assuan_context_t ctx
, gchar
*line
)
2782 struct client_s
*client
= assuan_get_pointer(ctx
);
2783 gpg_error_t rc
= file_modified(client
);
2786 return send_error(ctx
, rc
);
2788 unlock_file_mutex(client
);
2789 return send_error(ctx
, 0);
2792 static int getpid_command(assuan_context_t ctx
, gchar
*line
)
2796 pid_t pid
= getpid();
2798 print_fmt(buf
, sizeof(buf
), "%i", pid
);
2799 pthread_testcancel();
2800 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2801 pthread_testcancel();
2802 return send_error(ctx
, rc
);
2805 static int version_command(assuan_context_t ctx
, gchar
*line
)
2810 print_fmt(buf
, sizeof(buf
), "%s", PACKAGE_VERSION
);
2811 pthread_testcancel();
2812 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2813 pthread_testcancel();
2814 return send_error(ctx
, rc
);
2817 static void bye_notify(assuan_context_t ctx
)
2819 struct client_s
*cl
= assuan_get_pointer(ctx
);
2823 if (!cl
->thd
->remote
)
2827 rc
= gnutls_bye(cl
->thd
->tls
->ses
, GNUTLS_SHUT_RDWR
);
2828 } while (rc
== GNUTLS_E_AGAIN
);
2831 /* This will let assuan_process_next() return. */
2832 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
2835 static void reset_notify(assuan_context_t ctx
)
2837 struct client_s
*cl
= assuan_get_pointer(ctx
);
2843 static gpg_error_t
parse_client_option(assuan_context_t ctx
, const gchar
*line
)
2845 gchar name
[32] = {0}, value
[256] = {0};
2847 if (sscanf(line
, " %31[a-zA-Z] = %255c", name
, value
) != 2)
2848 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
);
2850 if (g_strcasecmp(name
, (gchar
*)"NAME") == 0) {
2851 struct client_s
*cl
= assuan_get_pointer(ctx
);
2854 g_free(cl
->thd
->name
);
2856 cl
->thd
->name
= g_strdup(value
);
2857 log_write("OPTION CLIENT %s", line
);
2860 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2865 static int option_handler(assuan_context_t ctx
, const gchar
*name
,
2868 struct client_s
*client
= assuan_get_pointer(ctx
);
2870 if (!value
|| !*value
)
2871 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2873 if (g_strcasecmp(name
, (gchar
*)"client") == 0)
2874 return parse_client_option(ctx
, value
);
2876 if (g_strcasecmp(name
, (gchar
*)"iterations") == 0) {
2881 n
= strtol(value
, &p
, 10);
2883 if (errno
|| (p
&& *p
) || n
< 0)
2884 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2886 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
: "global", "iterations", (guint
)n
);
2887 send_status_all(STATUS_CONFIG
);
2889 #ifdef WITH_PINENTRY
2890 else if (g_strcasecmp(name
, (gchar
*)"ttyname") == 0) {
2891 g_free(client
->pinentry
->ttyname
);
2892 client
->pinentry
->ttyname
= g_strdup(value
);
2894 else if (g_strcasecmp(name
, (gchar
*)"ttytype") == 0) {
2895 g_free(client
->pinentry
->ttytype
);
2896 client
->pinentry
->ttytype
= g_strdup(value
);
2898 else if (g_strcasecmp(name
, (gchar
*)"display") == 0) {
2899 g_free(client
->pinentry
->display
);
2900 client
->pinentry
->display
= g_strdup(value
);
2902 else if (g_strcasecmp(name
, (gchar
*)"path") == 0) {
2903 g_free(client
->pinentry
->path
);
2904 client
->pinentry
->path
= g_strdup(value
);
2906 else if (g_strcasecmp(name
, (gchar
*)"title") == 0) {
2907 g_free(client
->pinentry
->title
);
2908 client
->pinentry
->title
= g_strdup(value
);
2910 else if (g_strcasecmp(name
, (gchar
*)"prompt") == 0) {
2911 g_free(client
->pinentry
->prompt
);
2912 client
->pinentry
->prompt
= g_strdup(value
);
2914 else if (g_strcasecmp(name
, (gchar
*)"desc") == 0) {
2915 g_free(client
->pinentry
->desc
);
2916 client
->pinentry
->desc
= g_strdup(value
);
2919 * Look at client_thread() to see how this works.
2921 else if (g_strcasecmp(name
, (gchar
*)"timeout") == 0) {
2923 gint n
= strtol(value
, &p
, 10);
2926 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2928 client
->pinentry
->timeout
= n
;
2930 else if (g_strcasecmp(name
, (gchar
*)"pinentry") == 0) {
2932 gint n
= strtol(value
, &p
, 10);
2934 if (*p
|| n
< 0 || n
> 1)
2935 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2937 client
->pinentry
->enable
= n
== 0 ? FALSE
: TRUE
;
2941 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2943 log_write("OPTION %s=%s", name
, value
);
2947 gpg_error_t
register_commands(assuan_context_t ctx
)
2951 gint (*handler
)(assuan_context_t
, gchar
*line
);
2953 { "OPEN", open_command
},
2954 { "SAVE", save_command
},
2955 { "LIST", list_command
},
2956 { "REALPATH", realpath_command
},
2957 { "STORE", store_command
},
2958 { "DELETE", delete_command
},
2959 { "GET", get_command
},
2960 { "ATTR", attr_command
},
2961 { "ISCACHED", iscached_command
},
2962 { "CLEARCACHE", clearcache_command
},
2963 { "CACHETIMEOUT", cachetimeout_command
},
2964 { "GETCONFIG", getconfig_command
},
2965 { "DUMP", dump_command
},
2966 { "XPATH", xpath_command
},
2967 { "IMPORT", import_command
},
2968 { "LOCK", lock_command
},
2969 { "UNLOCK", unlock_command
},
2970 { "GETPID", getpid_command
},
2971 { "VERSION", version_command
},
2978 for (i
=0; table
[i
].name
; i
++) {
2979 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
2985 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
2990 rc
= assuan_register_option_handler(ctx
, option_handler
);
2995 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
3000 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
3003 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, guchar
*key
,
3004 struct client_crypto_s
*crypto
, gpointer
*dst
, gsize
*dst_len
)
3007 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
3008 guint64 iter
= 0, n_iter
= 0, iter_progress
= 0;
3012 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->fh1
) : sizeof(crypto
->fh
->fh2
);
3013 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->fh1
.iter
: crypto
->fh
->fh2
.iter
;
3015 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
3016 insize
= crypto
->fh
->st
.st_size
- fh_size
;
3017 crypto
->iv
= gcry_malloc(gcryblocksize
);
3020 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3021 return gpg_error_from_errno(ENOMEM
);
3024 /* No encryption iterations. This is a plain (gzipped) file. */
3025 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0)) {
3027 * cache_file_count() needs both .used == TRUE and a valid key in
3028 * order for it to count as a used cache entry. Fixes CACHE status
3031 memset(key
, '!', gcrykeysize
);
3035 memcpy(crypto
->iv
, crypto
->fh
->fh1
.iv
, gcryblocksize
);
3037 memcpy(crypto
->iv
, crypto
->fh
->fh2
.iv
, gcryblocksize
);
3039 crypto
->inbuf
= gcry_malloc(insize
);
3041 if (!crypto
->inbuf
) {
3042 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3043 return gpg_error_from_errno(ENOMEM
);
3046 crypto
->insize
= insize
;
3047 len
= read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
3048 pthread_testcancel();
3050 if (len
!= crypto
->insize
)
3051 return GPG_ERR_INV_LENGTH
;
3053 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0))
3056 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
3057 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3061 if ((rc
= gcry_cipher_setkey(crypto
->gh
, key
, gcrykeysize
))) {
3062 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3066 iter_progress
= (guint64
)get_key_file_integer(client
&& client
->filename
?
3067 client
->filename
: "global", "iteration_progress");
3069 if (iter_progress
> 0 && fh_iter
>= iter_progress
) {
3070 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
3071 pthread_testcancel();
3077 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3082 crypto
->tkey
= gcry_malloc(gcrykeysize
);
3084 if (!crypto
->tkey
) {
3085 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
3086 return gpg_error_from_errno(ENOMEM
);
3089 memcpy(crypto
->tkey
, key
, gcrykeysize
);
3090 guchar
*tkey
= crypto
->tkey
;
3093 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
3094 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3098 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
3099 if (iter_progress
> 0 && iter
>= iter_progress
) {
3100 if (!(iter
% iter_progress
)) {
3101 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
3102 ++n_iter
* iter_progress
, fh_iter
);
3103 pthread_testcancel();
3110 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
3111 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3115 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3118 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3125 if (iter_progress
&& fh_iter
>= iter_progress
) {
3126 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
3127 pthread_testcancel();
3134 if (do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
3135 (gpointer
*)&crypto
->outbuf
, &outsize
, &zrc
) == FALSE
) {
3136 if (zrc
== Z_MEM_ERROR
)
3137 return gpg_error_from_errno(ENOMEM
);
3139 return EPWMD_BADKEY
; // Not a valid gzip header. Must be a bad key.
3142 if (g_strncasecmp(crypto
->outbuf
, "<?xml version=\"1.0\"?>", 21) != 0) {
3143 gcry_free(crypto
->outbuf
);
3144 crypto
->outbuf
= NULL
;
3145 return EPWMD_BADKEY
;
3149 client
->xml
= crypto
->outbuf
;
3150 client
->len
= outsize
;
3151 crypto
->outbuf
= NULL
;
3154 *dst
= crypto
->outbuf
;
3156 crypto
->outbuf
= NULL
;
3159 /* The calling function should free the crypto struct. */
3164 * This is called after every Assuan command.
3166 void command_finalize(assuan_context_t ctx
, gint rc
)
3168 struct client_s
*client
= assuan_get_pointer(ctx
);
3170 if (!client
->is_lock_cmd
)
3171 unlock_file_mutex(client
);