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"
53 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
55 return gcry_calloc(items
, size
);
58 static void z_free(void *data
, void *p
)
63 static gpg_error_t
file_modified(struct client_s
*client
)
68 if (client
->state
!= STATE_OPEN
)
71 rc
= lock_file_mutex(client
);
76 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
77 if (client
->mtime
!= st
.st_mtime
)
78 return EPWMD_FILE_MODIFIED
;
85 static gpg_error_t
parse_xml(assuan_context_t ctx
)
87 struct client_s
*client
= assuan_get_pointer(ctx
);
89 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
92 return EPWMD_LIBXML_ERROR
;
97 void unlock_file_mutex(struct client_s
*client
)
99 struct file_mutex_s
*m
;
102 if (client
->has_lock
== FALSE
|| client
->pinentry
->status
!= PINENTRY_NONE
)
104 if (client
->has_lock
== FALSE
)
108 CACHE_LOCK(client
->ctx
);
110 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
116 MUTEX_UNLOCK(&m
->mutex
);
117 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
120 gpg_error_t
lock_file_mutex(struct client_s
*client
)
122 struct file_mutex_s
*m
;
124 if (client
->has_lock
== TRUE
)
127 CACHE_LOCK(client
->ctx
);
129 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
136 if (pthread_mutex_trylock(&m
->mutex
) == EBUSY
) {
139 * If a client disconnects unexpectedly while waiting for a
140 * lock, this lets the thread terminate because send_status()
141 * will return an error.
143 while (pthread_mutex_trylock(&m
->mutex
) == EBUSY
) {
144 gpg_error_t rc
= send_status(client
->ctx
, STATUS_LOCKED
, NULL
);
153 MUTEX_LOCK(&m
->mutex
);
160 client
->has_lock
= TRUE
;
164 void free_client(struct client_s
*client
)
167 xmlFreeDoc(client
->doc
);
170 gcry_free(client
->xml
);
172 if (client
->filename
)
173 g_free(client
->filename
);
176 cleanup_crypto(&client
->crypto
);
178 if (client
->xml_error
)
179 xmlResetError(client
->xml_error
);
182 void cleanup_client(struct client_s
*client
)
184 assuan_context_t ctx
= client
->ctx
;
185 struct client_thread_s
*thd
= client
->thd
;
186 gboolean has_lock
= client
->has_lock
;
188 struct pinentry_s
*pin
= client
->pinentry
;
191 unlock_file_mutex(client
);
192 CACHE_LOCK(client
->ctx
);
193 cache_decr_refcount(client
->md5file
);
196 * This may be a new file so don't use a cache slot. save_command() will
197 * set this to FALSE on success.
199 if (client
->new == TRUE
)
200 cache_clear(client
->md5file
, 1);
203 memset(client
, 0, sizeof(struct client_s
));
204 client
->state
= STATE_CONNECTED
;
207 client
->freed
= TRUE
;
209 client
->pinentry
= pin
;
211 client
->has_lock
= has_lock
;
215 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
216 gpointer
*out
, gulong
*outsize
, gint
*rc
)
226 z
.avail_in
= (uInt
)insize
;
227 z
.avail_out
= zlib_bufsize
;
228 z
.next_out
= pout
= gcry_malloc(zlib_bufsize
);
231 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
236 *rc
= inflateInit2(&z
, 47);
239 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
244 memset(&h
, 0, sizeof(gz_header
));
245 h
.comment
= (guchar
*)buf
;
246 h
.comm_max
= sizeof(buf
);
247 *rc
= inflateGetHeader(&z
, &h
);
250 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
256 *rc
= inflate(&z
, Z_BLOCK
);
259 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
266 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
271 *rc
= inflate(&z
, Z_FINISH
);
278 p
= gcry_realloc(pout
, z
.total_out
+ zlib_bufsize
);
281 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
287 z
.next_out
= pout
+ z
.total_out
;
288 z
.avail_out
= zlib_bufsize
;
289 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
290 z
.total_out
, insize
);
301 } while (*rc
!= Z_STREAM_END
);
303 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", z
.total_out
,
310 *outsize
= z
.total_out
;
316 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
322 static void read_file_header_handler(void *arg
)
327 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
332 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
338 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
339 *rc
= gpg_error_from_errno(ENOMEM
);
343 fh_size
= v1
? sizeof(fh
->fh1
) : sizeof(fh
->fh2
);
345 if (lstat(filename
, &fh
->st
) == -1) {
346 *rc
= gpg_error_from_syserror();
351 if (!S_ISREG(fh
->st
.st_mode
)) {
352 *rc
= GPG_ERR_ENOANO
;
357 fd
= open(filename
, O_RDONLY
);
360 *rc
= gpg_error_from_errno(errno
);
366 len
= read(fd
, &fh
->fh1
, fh_size
);
368 len
= read(fd
, &fh
->fh2
, fh_size
);
370 if (len
!= fh_size
) {
372 pthread_cleanup_push(read_file_header_handler
, (void *)fd
);
374 pthread_cleanup_pop(1);
375 *rc
= gpg_error_from_errno(n
);
384 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*key
,
387 struct client_s
*client
= assuan_get_pointer(ctx
);
392 if (!client
->crypto
->fh
) {
399 rc
= try_xml_decrypt(ctx
, key
, client
->crypto
, NULL
, NULL
);
402 cleanup_client(client
);
403 return send_error(ctx
, rc
);
407 CACHE_LOCK(client
->ctx
);
409 if (cached
== FALSE
) {
410 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
411 cleanup_client(client
);
413 return send_syserror(ctx
, ENOMEM
);
416 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
417 cache_reset_timeout(client
->md5file
, timeout
);
420 cache_set_timeout(client
->md5file
, -2);
428 gcry_free(client
->xml
);
433 if (client
->new == FALSE
)
434 send_status_all(STATUS_CACHE
);
436 client
->state
= STATE_OPEN
;
439 if (!rc
&& client
->new == FALSE
&&
440 client
->crypto
->fh
->fh2
.iter
!= (guint
)get_key_file_integer(client
->filename
, "iterations")) {
441 g_key_file_set_integer(keyfileh
, client
->filename
, "iterations",
442 client
->crypto
->fh
->fh2
.iter
);
443 send_status_all(STATUS_CONFIG
);
447 log_write("OPEN '%s'", client
->filename
);
449 cleanup_crypto(&client
->crypto
);
450 return send_error(ctx
, rc
);
454 static gboolean
validate_access(struct client_s
*cl
, const gchar
*filename
)
456 gchar
*access
= get_key_file_string(filename
, "tcp_access");
462 list
= g_strsplit(access
, ",", -1);
466 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
470 for (p
= list
; *p
; p
++) {
471 gboolean
not = FALSE
;
482 if (strcasecmp(cl
->thd
->tls
->fp
, fp
) == 0) {
497 static void req_cleanup(void *arg
)
502 g_strfreev((gchar
**)arg
);
505 static int open_command(assuan_context_t ctx
, char *line
)
507 gboolean cached
= FALSE
;
509 struct client_s
*client
= assuan_get_pointer(ctx
);
511 gchar
*filename
= NULL
;
513 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
516 pthread_cleanup_push(req_cleanup
, req
);
518 if (!filename
|| !*filename
) {
520 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
523 if (valid_filename(filename
) == FALSE
) {
525 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
528 if (client
->state
== STATE_OPEN
)
529 cleanup_client(client
);
532 if (client
->thd
->remote
== TRUE
) {
533 if (validate_access(client
, filename
) == FALSE
) {
534 log_write(N_("client validation failed for file '%s'"), filename
);
536 return send_error(ctx
, EPWMD_FILE_ACCESS
);
541 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
542 CACHE_LOCK(client
->ctx
);
544 if (cache_has_file(client
->md5file
) == FALSE
) {
545 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
548 return send_syserror(ctx
, ENOMEM
);
552 cache_incr_refcount(client
->md5file
);
554 rc
= lock_file_mutex(client
);
558 return send_error(ctx
, rc
);
561 client
->freed
= FALSE
;
562 client
->crypto
= init_client_crypto();
564 if (!client
->crypto
) {
566 cleanup_client(client
);
567 return send_syserror(ctx
, ENOMEM
);
570 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
572 if (!client
->crypto
->key
) {
574 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
575 gpg_error_from_errno(ENOMEM
));
576 cleanup_client(client
);
577 return send_syserror(ctx
, ENOMEM
);
580 memset(client
->crypto
->key
, 0, gcrykeysize
);
581 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
582 pthread_testcancel();
584 if (!client
->crypto
->fh
) {
585 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
586 log_write("%s: %s", filename
, pwmd_strerror(rc
));
588 cleanup_client(client
);
589 return send_error(ctx
, rc
);
593 * New files don't need a key.
595 if ((client
->xml
= new_document()) == NULL
) {
596 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
598 cleanup_client(client
);
599 return send_syserror(ctx
, ENOMEM
);
602 client
->len
= xmlStrlen(client
->xml
);
604 client
->filename
= g_strdup(filename
);
606 if (!client
->filename
) {
608 cleanup_client(client
);
609 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
610 return send_syserror(ctx
, ENOMEM
);
613 if (req
[1] && *req
[1])
614 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
619 client
->pinentry
->filename
= g_strdup(client
->filename
);
621 if (!client
->pinentry
->filename
) {
622 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
623 cleanup_client(client
);
624 return send_syserror(ctx
, ENOMEM
);
627 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
630 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
632 client
->filename
= g_strdup(filename
);
634 if (!client
->filename
) {
635 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
637 cleanup_client(client
);
638 return send_syserror(ctx
, ENOMEM
);
642 client
->pinentry
->filename
= g_strdup(client
->filename
);
644 if (!client
->pinentry
->filename
) {
645 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
647 cleanup_client(client
);
648 return send_syserror(ctx
, ENOMEM
);
652 if (client
->crypto
->fh
->fh2
.iter
<= 0)
656 if (client
->thd
->remote
== FALSE
||
657 get_key_file_boolean(client
->filename
, "tcp_require_key") == FALSE
)
660 CACHE_LOCK(client
->ctx
);
661 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
669 if (cached
== FALSE
) {
670 gchar
*tmp
= get_key_file_string(filename
, "key_file");
674 cleanup_client(client
);
675 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
679 * No key specified and no matching filename found in the cache. Use
680 * pinentry to retrieve the key. Cannot return assuan_process_done()
681 * here otherwise the command will be interrupted. The event loop in
682 * client_thread() will poll the file descriptor waiting for it to
683 * become ready to read a pinentry_key_s which will contain the
684 * entered key or an error code. It will then call
685 * open_command_finalize() to to finish the command.
687 if (!req
[1] || !*req
[1]) {
689 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
691 /* From set_pinentry_defaults(). */
692 if (client
->pinentry
->enable
== FALSE
||
693 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
694 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
699 rc
= lock_pin_mutex(client
);
702 unlock_pin_mutex(client
->pinentry
);
703 cleanup_client(client
);
704 return send_error(ctx
, rc
);
707 client
->pinentry
->which
= PINENTRY_OPEN
;
708 rc
= pinentry_fork(ctx
);
711 unlock_pin_mutex(client
->pinentry
);
712 cleanup_client(client
);
713 return send_error(ctx
, rc
);
716 // Called from pinentry iterate.
717 client
->pinentry
->cb
= open_command_finalize
;
718 client
->pinentry
->status
= PINENTRY_INIT
;
721 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
726 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
732 pthread_cleanup_pop(1);
733 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
736 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
737 gulong size
, gpointer
*out
, gulong
*outsize
, gint
*rc
)
743 gint cmd
= Z_NO_FLUSH
;
747 z
.next_in
= pin
= data
;
748 z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
749 z
.avail_out
= (uInt
)zlib_bufsize
;
750 z
.next_out
= pout
= gcry_malloc(zlib_bufsize
);
753 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
758 *rc
= deflateInit2(&z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
761 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
766 /* Rather than store the size of the uncompressed data in the file header,
767 * store it in the comment field of the gzip header. Don't give anyone too
768 * much information. Not sure why really, but it seems the right way. :)
770 memset(&h
, 0, sizeof(gz_header
));
771 g_snprintf(buf
, sizeof(buf
), "%li", size
);
772 h
.comment
= (guchar
*)buf
;
773 *rc
= deflateSetHeader(&z
, &h
);
776 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
785 *rc
= deflate(&z
, cmd
);
792 p
= gcry_realloc(pout
, z
.total_out
+ zlib_bufsize
);
795 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
801 z
.next_out
= pout
+ z
.total_out
;
802 z
.avail_out
= zlib_bufsize
;
805 if (!z
.avail_in
&& z
.total_in
< size
) {
806 if (z
.total_in
+ zlib_bufsize
> size
)
807 z
.avail_in
= size
- z
.total_in
;
809 z
.avail_in
= zlib_bufsize
;
811 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li",
818 if (z
.total_in
>= size
)
827 } while (*rc
!= Z_STREAM_END
);
829 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %li", z
.total_in
, size
);
835 *outsize
= z
.total_out
;
841 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, z
.msg
);
847 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
849 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
850 struct client_crypto_s
*crypto
, status_msg_t which
)
853 gsize len
= CRYPTO_BLOCKSIZE
;
854 gpointer p
= gcry_malloc(len
);
859 return gpg_err_code_from_errno(ENOMEM
);
861 pthread_cleanup_push(gcry_free
, p
);
863 if (crypto
->insize
< CRYPTO_BLOCKSIZE
)
864 len
= crypto
->insize
;
867 inbuf
= crypto
->inbuf
+ total
;
870 if (len
+ total
> crypto
->insize
)
873 if (which
== STATUS_ENCRYPT
)
874 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
876 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
881 tmp
= crypto
->inbuf
+total
;
882 memmove(tmp
, p
, len
);
885 if (total
>= crypto
->insize
)
888 pthread_testcancel();
893 pthread_cleanup_pop(1);
897 /* The crypto struct must be setup for iterations and .key. */
898 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
899 struct client_crypto_s
*crypto
, const gchar
*filename
)
901 gsize len
= crypto
->insize
;
905 guint iter_progress
= 0, n_iter
= 0, xiter
= 0;
906 gchar tmp
[FILENAME_MAX
];
910 if (!crypto
->fh
->fh2
.iter
) {
912 * cache_file_count() needs both .used == TRUE and a valid key in
913 * order for it to count as a used cache entry. Fixes CACHE status
916 memset(crypto
->key
, '!', gcrykeysize
);
921 * Resize the existing xml buffer to the block size required by gcrypt
922 * rather than duplicating it and wasting memory.
924 if (crypto
->insize
/ gcryblocksize
) {
925 len
= (crypto
->insize
/ gcryblocksize
) * gcryblocksize
;
927 if (crypto
->insize
% gcryblocksize
)
928 len
+= gcryblocksize
;
931 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
934 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
935 return gpg_error_from_errno(ENOMEM
);
938 crypto
->inbuf
= inbuf
;
939 crypto
->insize
= len
;
940 gcry_create_nonce(crypto
->fh
->fh2
.iv
, sizeof(crypto
->fh
->fh2
.iv
));
941 crypto
->tkey
= gcry_malloc(gcrykeysize
);
944 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
945 return gpg_error_from_errno(ENOMEM
);
948 memcpy(crypto
->tkey
, crypto
->key
, gcrykeysize
);
949 guchar
*tkey
= crypto
->tkey
;
952 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
953 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
957 iter_progress
= get_key_file_integer(client
? client
->filename
: "global",
958 "iteration_progress");
960 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
961 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
962 "%u %u", 0, crypto
->fh
->fh2
.iter
);
968 while (xiter
< crypto
->fh
->fh2
.iter
-1) {
969 if (iter_progress
> 0 && xiter
>= iter_progress
) {
970 if (!(xiter
% iter_progress
)) {
971 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
972 "%u %u", ++n_iter
* iter_progress
, crypto
->fh
->fh2
.iter
);
979 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
980 sizeof(crypto
->fh
->fh2
.iv
)))) {
981 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
985 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
988 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
995 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->fh2
.iv
,
996 sizeof(crypto
->fh
->fh2
.iv
)))) {
997 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1001 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, gcrykeysize
))) {
1002 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
1006 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1011 if (iter_progress
&& crypto
->fh
->fh2
.iter
>= iter_progress
) {
1012 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1013 "%u %u", crypto
->fh
->fh2
.iter
, crypto
->fh
->fh2
.iter
);
1021 if (!client
&& !strcmp(filename
, "-")) {
1022 crypto
->fh
->fd
= STDOUT_FILENO
;
1026 if (lstat(filename
, &st
) == 0) {
1027 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1030 * FIXME What if the file has an ACL?
1032 if (!(mode
& S_IWUSR
))
1033 return gpg_error_from_errno(EACCES
);
1036 if (errno
!= ENOENT
)
1037 return gpg_error_from_errno(errno
);
1040 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1041 crypto
->fh
->fd
= mkstemp(tmp
);
1043 if (crypto
->fh
->fd
== -1) {
1045 p
= strrchr(tmp
, '/');
1047 log_write("%s: %s", p
, strerror(rc
));
1048 return gpg_error_from_errno(rc
);
1053 * xml_import() or convert_file() from command line.
1055 crypto
->fh
->fd
= STDOUT_FILENO
;
1058 crypto
->fh
->fh2
.version
= VERSION_HEX
;
1059 len
= write(crypto
->fh
->fd
, &crypto
->fh
->fh2
, sizeof(crypto
->fh
->fh2
));
1061 if (len
!= sizeof(crypto
->fh
->fh2
)) {
1064 if (filename
&& strcmp(filename
, "-"))
1067 return gpg_error_from_errno(len
);
1070 len
= write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1072 if (len
!= crypto
->insize
) {
1075 if (filename
&& strcmp(filename
, "-"))
1078 return gpg_error_from_errno(len
);
1081 if (fsync(crypto
->fh
->fd
) == -1) {
1084 if (filename
&& strcmp(filename
, "-"))
1087 return gpg_error_from_errno(len
);
1090 if (filename
&& strcmp(filename
, "-")) {
1091 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1092 gchar tmp2
[FILENAME_MAX
];
1094 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1096 if (rename(filename
, tmp2
) == -1) {
1099 return gpg_error_from_errno(len
);
1103 if (rename(tmp
, filename
) == -1) {
1106 return gpg_error_from_errno(len
);
1110 chmod(filename
, mode
);
1113 if (client
&& lstat(filename
, &st
) == 0)
1114 client
->mtime
= st
.st_mtime
;
1119 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1122 struct client_s
*client
= assuan_get_pointer(ctx
);
1124 gulong len
, outsize
= 0;
1131 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1132 gcry_free(client
->crypto
->key
);
1134 client
->crypto
->key
= key
;
1135 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1136 iter
= (guint
)get_key_file_integer(client
->filename
, "compression_level");
1141 if (do_compress(ctx
, (gint
)iter
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
)
1143 if (key
!= client
->crypto
->key
)
1147 cleanup_crypto(&client
->crypto
);
1149 if (zrc
== Z_MEM_ERROR
)
1150 return send_syserror(ctx
, ENOMEM
);
1152 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1160 client
->crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1162 if (!client
->crypto
->fh
) {
1163 cleanup_crypto(&client
->crypto
);
1165 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1166 return send_syserror(ctx
, ENOMEM
);
1169 iter
= get_key_file_integer(client
->filename
, "iterations");
1170 client
->crypto
->fh
->fh2
.iter
= iter
< 0 ? 0 : iter
;
1171 client
->crypto
->inbuf
= xmlbuf
;
1172 client
->crypto
->insize
= len
;
1173 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1176 cleanup_crypto(&client
->crypto
);
1177 return send_error(ctx
, rc
);
1180 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1181 CACHE_LOCK(client
->ctx
);
1184 cache_reset_timeout(client
->md5file
, timeout
);
1187 if (client
->new == TRUE
)
1188 send_status_all(STATUS_CACHE
);
1190 client
->new = FALSE
;
1191 cleanup_crypto(&client
->crypto
);
1192 return send_error(ctx
, 0);
1195 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1197 cleanup_crypto(&client
->crypto
);
1198 return send_syserror(ctx
, ENOMEM
);
1201 client
->new = FALSE
;
1202 cache_reset_timeout(client
->md5file
, timeout
);
1204 send_status_all(STATUS_CACHE
);
1205 cleanup_crypto(&client
->crypto
);
1206 return send_error(ctx
, 0);
1209 static int save_command(assuan_context_t ctx
, char *line
)
1211 gboolean cached
= FALSE
;
1213 struct client_s
*client
= assuan_get_pointer(ctx
);
1216 rc
= lock_file_mutex(client
);
1219 return send_error(ctx
, rc
);
1221 rc
= file_modified(client
);
1224 return send_error(ctx
, rc
);
1226 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1227 return send_syserror(ctx
, errno
);
1229 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1230 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1231 return send_error(ctx
, GPG_ERR_ENOANO
);
1235 cached
= cache_iscached(client
->md5file
);
1239 * If a cache entry doesn't exist for this file and the file has a
1240 * "key_file" or "key" parameter, then it's an error. The reason is that
1241 * cache expiration would be useless.
1243 if (cached
== FALSE
) {
1244 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1248 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1253 client
->crypto
= init_client_crypto();
1255 if (!client
->crypto
) {
1256 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1257 return send_syserror(ctx
, ENOMEM
);
1260 client
->crypto
->key
= gcry_malloc(gcrykeysize
);
1262 if (!client
->crypto
->key
) {
1263 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1264 cleanup_crypto(&client
->crypto
);
1265 return send_syserror(ctx
, ENOMEM
);
1268 memset(client
->crypto
->key
, '!', gcrykeysize
);
1270 if (get_key_file_integer(client
->filename
, "iterations") <= 0)
1273 if (!line
|| !*line
) {
1274 client
->crypto
->tkey
= gcry_malloc(gcrykeysize
);
1276 if (!client
->crypto
->tkey
) {
1277 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1278 cleanup_crypto(&client
->crypto
);
1279 return send_syserror(ctx
, ENOMEM
);
1282 memset(client
->crypto
->tkey
, '!', gcrykeysize
);
1285 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1286 memcmp(client
->crypto
->key
, client
->crypto
->tkey
,
1287 gcrykeysize
) == 0) {
1290 #ifdef WITH_PINENTRY
1291 if (client
->pinentry
->enable
== FALSE
||
1292 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1293 /* Empty keys are allowed. */
1294 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1298 lock_pin_mutex(client
);
1299 client
->pinentry
->which
= PINENTRY_SAVE
;
1300 rc
= pinentry_fork(ctx
);
1303 unlock_pin_mutex(client
->pinentry
);
1304 return send_error(ctx
, rc
);
1307 client
->pinentry
->cb
= save_command_finalize
;
1308 client
->pinentry
->status
= PINENTRY_INIT
;
1311 /* Empty keys are allowed. */
1312 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1322 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, line
,
1324 memset(line
, 0, strlen(line
));
1328 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1331 static int delete_command(assuan_context_t ctx
, char *line
)
1333 struct client_s
*client
= assuan_get_pointer(ctx
);
1338 rc
= file_modified(client
);
1341 return send_error(ctx
, rc
);
1343 if (strchr(line
, '\t'))
1344 req
= split_input_line(line
, "\t", -1);
1346 req
= split_input_line(line
, " ", -1);
1349 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1351 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1355 return send_error(ctx
, rc
);
1359 * No sub-node defined. Remove the entire node (account).
1368 return send_error(ctx
, 0);
1371 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1375 return send_error(ctx
, rc
);
1382 return send_error(ctx
, 0);
1386 * Don't return with assuan_process_done() here. This has been called from
1387 * assuan_process_next() and the command should be finished in
1390 static int store_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
1393 assuan_context_t ctx
= data
;
1394 struct client_s
*client
= assuan_get_pointer(ctx
);
1397 gpg_error_t rc
= file_modified(client
);
1399 if (assuan_rc
|| rc
) {
1402 return assuan_rc
? assuan_rc
: rc
;
1405 req
= split_input_line((gchar
*)line
, "\t", 0);
1409 return EPWMD_COMMAND_SYNTAX
;
1411 if (valid_xml_element((xmlChar
*)*req
) == FALSE
) {
1413 return EPWMD_INVALID_ELEMENT
;
1416 if (valid_element_path(req
+1, TRUE
) == FALSE
) {
1418 return EPWMD_INVALID_ELEMENT
;
1422 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1424 if (rc
&& rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1425 rc
= new_account(client
->doc
, *req
);
1442 create_elements_cb(n
, req
+1, &rc
, NULL
);
1444 find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1445 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
);
1449 client
->inquire_status
= INQUIRE_DONE
;
1453 static int store_command(assuan_context_t ctx
, char *line
)
1455 struct client_s
*client
= assuan_get_pointer(ctx
);
1456 gpg_error_t rc
= file_modified(client
);
1459 return send_error(ctx
, rc
);
1461 pthread_testcancel();
1462 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1463 pthread_testcancel();
1466 return send_error(ctx
, rc
);
1468 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1469 client
->inquire_status
= INQUIRE_BUSY
;
1473 static int get_command(assuan_context_t ctx
, char *line
)
1475 struct client_s
*client
= assuan_get_pointer(ctx
);
1480 rc
= file_modified(client
);
1483 return send_error(ctx
, rc
);
1485 req
= split_input_line(line
, "\t", -1);
1487 if (!req
|| !*req
) {
1489 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1492 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1496 return send_error(ctx
, rc
);
1500 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1505 return send_error(ctx
, rc
);
1507 if (!n
|| !n
->children
)
1508 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1510 n
= find_text_node(n
->children
);
1512 if (!n
|| !n
->content
|| !*n
->content
)
1513 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1515 pthread_testcancel();
1516 rc
= assuan_send_data(ctx
, n
->content
, xmlStrlen(n
->content
));
1517 pthread_testcancel();
1518 return send_error(ctx
, rc
);
1521 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
1522 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
1524 gchar
*path
= *(gchar
**)data
;
1525 gchar
*tmp
= NULL
, *result
;
1529 *(gchar
**)data
= NULL
;
1532 path
= g_strjoinv("\t", target
);
1535 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1536 *rc
= gpg_error_from_errno(ENOMEM
);
1541 tmp
= g_strjoinv("\t", req_orig
);
1545 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1546 *rc
= gpg_error_from_errno(ENOMEM
);
1552 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1554 result
= g_strdup(path
);
1557 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1558 *rc
= gpg_error_from_errno(ENOMEM
);
1566 *(gchar
**)data
= result
;
1570 static void list_command_cleanup1(void *arg
);
1571 static int realpath_command(assuan_context_t ctx
, char *line
)
1574 struct client_s
*client
= assuan_get_pointer(ctx
);
1582 rc
= file_modified(client
);
1585 return send_error(ctx
, rc
);
1587 if (strchr(line
, '\t') != NULL
) {
1588 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1589 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1592 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1593 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1596 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0);
1600 return send_error(ctx
, rc
);
1603 rp
= g_strjoinv("\t", req
);
1607 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1608 return send_syserror(ctx
, ENOMEM
);
1612 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1613 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
);
1618 return send_error(ctx
, rc
);
1622 string
= g_string_new(rp
);
1627 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1628 return send_syserror(ctx
, ENOMEM
);
1632 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
1633 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
1634 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1639 pthread_cleanup_push(list_command_cleanup1
, string
);
1640 pthread_testcancel();
1641 rc
= assuan_send_data(ctx
, string
->str
, string
->len
);
1642 pthread_testcancel();
1643 pthread_cleanup_pop(1);
1644 return send_error(ctx
, rc
);
1647 static void list_command_cleanup1(void *arg
)
1649 g_string_free((GString
*)arg
, TRUE
);
1652 static void list_command_cleanup2(void *arg
)
1654 struct element_list_s
*elements
= arg
;
1657 gint total
= g_slist_length(elements
->list
);
1660 for (i
= 0; i
< total
; i
++) {
1661 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
1665 g_slist_free(elements
->list
);
1667 if (elements
->prefix
)
1668 g_free(elements
->prefix
);
1674 static int list_command(assuan_context_t ctx
, char *line
)
1676 struct client_s
*client
= assuan_get_pointer(ctx
);
1678 struct element_list_s
*elements
= NULL
;
1681 if (disable_list_and_dump
== TRUE
)
1682 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1684 rc
= file_modified(client
);
1687 return send_error(ctx
, rc
);
1692 rc
= list_accounts(client
->doc
, &str
);
1693 pthread_cleanup_push(list_command_cleanup1
, str
);
1696 return send_error(ctx
, rc
);
1698 pthread_testcancel();
1699 rc
= assuan_send_data(ctx
, str
->str
, str
->len
);
1700 pthread_testcancel();
1701 pthread_cleanup_pop(1);
1702 return send_error(ctx
, rc
);
1705 elements
= g_malloc0(sizeof(struct element_list_s
));
1708 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1709 rc
= gpg_err_code_from_errno(ENOMEM
);
1713 pthread_cleanup_push(list_command_cleanup2
, elements
);
1714 pthread_testcancel();
1715 rc
= create_path_list(client
->doc
, elements
, line
);
1716 pthread_testcancel();
1722 gint total
= g_slist_length(elements
->list
);
1727 rc
= EPWMD_EMPTY_ELEMENT
;
1731 str
= g_string_new(NULL
);
1734 rc
= gpg_err_code_from_errno(ENOMEM
);
1735 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1739 pthread_cleanup_push(list_command_cleanup1
, str
);
1741 for (i
= 0; i
< total
; i
++) {
1742 tmp
= g_slist_nth_data(elements
->list
, i
);
1743 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
1746 pthread_testcancel();
1747 rc
= assuan_send_data(ctx
, str
->str
, str
->len
);
1748 pthread_testcancel();
1749 pthread_cleanup_pop(1);
1752 rc
= EPWMD_EMPTY_ELEMENT
;
1756 pthread_cleanup_pop(1);
1757 return send_error(ctx
, rc
);
1760 static gpg_error_t
add_attribute(xmlNodePtr node
, const gchar
*name
,
1765 if ((a
= xmlHasProp(node
, (xmlChar
*)name
)) == NULL
) {
1766 a
= xmlNewProp(node
, (xmlChar
*)name
, (xmlChar
*)value
);
1769 return EPWMD_LIBXML_ERROR
;
1772 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1778 * req[0] - element path
1780 static int attribute_list(assuan_context_t ctx
, gchar
**req
)
1782 struct client_s
*client
= assuan_get_pointer(ctx
);
1783 gchar
**attrlist
= NULL
;
1785 gchar
**path
= NULL
;
1791 if (!req
|| !req
[0])
1792 return EPWMD_COMMAND_SYNTAX
;
1794 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1796 * The first argument may be only an account.
1798 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1799 return EPWMD_COMMAND_SYNTAX
;
1802 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1810 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1811 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1821 for (a
= n
->properties
; a
; a
= a
->next
) {
1824 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1826 g_strfreev(attrlist
);
1828 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1829 return gpg_error_from_errno(ENOMEM
);
1834 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1837 g_strfreev(attrlist
);
1838 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1839 return gpg_error_from_errno(ENOMEM
);
1842 attrlist
[++i
] = NULL
;
1846 return EPWMD_EMPTY_ELEMENT
;
1848 line
= g_strjoinv("\n", attrlist
);
1851 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1852 g_strfreev(attrlist
);
1853 return gpg_error_from_errno(ENOMEM
);
1856 pthread_cleanup_push(g_free
, line
);
1857 pthread_cleanup_push(req_cleanup
, attrlist
);
1858 pthread_testcancel();
1859 rc
= assuan_send_data(ctx
, line
, strlen(line
));
1860 pthread_testcancel();
1861 pthread_cleanup_pop(1);
1862 pthread_cleanup_pop(1);
1867 * req[0] - attribute
1868 * req[1] - element path
1870 static int attribute_delete(struct client_s
*client
, gchar
**req
)
1874 gchar
**path
= NULL
;
1877 if (!req
|| !req
[0] || !req
[1])
1878 return EPWMD_COMMAND_SYNTAX
;
1880 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1882 * The first argument may be only an account.
1884 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1885 return EPWMD_COMMAND_SYNTAX
;
1889 * Don't remove the "name" attribute for the account element. To remove an
1890 * account use DELETE <account>.
1892 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
1893 rc
= EPWMD_ATTR_SYNTAX
;
1897 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
1903 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1904 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1912 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
1913 return EPWMD_ATTR_NOT_FOUND
;
1915 if (xmlRemoveProp(a
) == -1)
1916 return EPWMD_LIBXML_ERROR
;
1925 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
1928 gchar
**src
= *path
;
1929 gchar
**src_orig
= g_strdupv(src
);
1930 xmlNodePtr n
= NULL
;
1935 *rc
= gpg_error_from_errno(ENOMEM
);
1936 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1941 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
1944 if (*rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1945 *rc
= new_account(client
->doc
, src
[0]);
1958 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
1960 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
1961 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
);
1967 * Reset the position of the element tree now that the elements
1968 * have been created.
1973 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0);
1978 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
1979 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1987 g_strfreev(src_orig
);
1994 * Creates a "target" attribute. When other commands encounter an element with
1995 * this attribute, the element path is modified to the target value. If the
1996 * source element path doesn't exist when using 'ATTR SET target', it is
1997 * created, but the destination element path must exist.
1999 * req[0] - source element path
2000 * req[1] - destination element path
2002 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2004 gchar
**src
, **dst
, *line
= NULL
;
2008 if (!req
|| !req
[0] || !req
[1])
2009 return EPWMD_COMMAND_SYNTAX
;
2011 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2013 * The first argument may be only an account.
2015 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2016 return EPWMD_COMMAND_SYNTAX
;
2019 if (valid_element_path(src
, FALSE
) == FALSE
) {
2021 return EPWMD_INVALID_ELEMENT
;
2024 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2026 * The first argument may be only an account.
2028 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2029 rc
= EPWMD_COMMAND_SYNTAX
;
2034 n
= find_account(client
->doc
, &dst
, &rc
, NULL
, 0);
2037 * Make sure the destination element path exists.
2043 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2044 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2050 n
= create_element_path(client
, &src
, &rc
);
2055 line
= g_strjoinv("\t", dst
);
2058 rc
= gpg_error_from_errno(ENOMEM
);
2059 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2063 rc
= add_attribute(n
, "target", line
);
2073 * req[0] - account name
2076 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2082 tmp
= g_strdupv(req
);
2085 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2086 return gpg_error_from_errno(ENOMEM
);
2089 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2095 if (g_utf8_collate(req
[0], req
[1]) == 0)
2099 * Will not overwrite an existing account.
2101 tmp
= g_strdupv(req
+1);
2104 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2105 return gpg_error_from_errno(ENOMEM
);
2108 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2111 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
2115 return EPWMD_ACCOUNT_EXISTS
;
2118 * Whitespace not allowed in account names.
2120 if (contains_whitespace(req
[1]) == TRUE
)
2121 return EPWMD_ATTR_SYNTAX
;
2123 tmp
= g_strdupv(req
);
2126 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2127 return gpg_error_from_errno(ENOMEM
);
2130 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0);
2134 return EPWMD_ELEMENT_NOT_FOUND
;
2136 return add_attribute(n
, "name", req
[1]);
2140 * req[0] - attribute
2141 * req[1] - element path
2143 static int attribute_get(assuan_context_t ctx
, gchar
**req
)
2145 struct client_s
*client
= assuan_get_pointer(ctx
);
2151 if (!req
|| !req
[0] || !req
[1])
2152 return EPWMD_COMMAND_SYNTAX
;
2154 if (strchr(req
[1], '\t')) {
2155 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2156 return EPWMD_COMMAND_SYNTAX
;
2159 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2160 return EPWMD_COMMAND_SYNTAX
;
2163 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2169 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2170 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2178 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2179 return EPWMD_ATTR_NOT_FOUND
;
2181 pthread_cleanup_push(xmlFree
, a
);
2182 pthread_testcancel();
2183 rc
= assuan_send_data(ctx
, a
, xmlStrlen(a
));
2184 pthread_testcancel();
2185 pthread_cleanup_pop(1);
2194 * req[0] - attribute
2195 * req[1] - element path
2198 static int attribute_set(struct client_s
*client
, gchar
**req
)
2200 gchar
**path
= NULL
;
2204 if (!req
|| !req
[0] || !req
[1] || !req
[2])
2205 return EPWMD_COMMAND_SYNTAX
;
2208 * Reserved attribute names.
2210 if (g_utf8_collate(req
[0], "name") == 0) {
2212 * Only reserved for the account element. Not the rest of the
2215 if (strchr(req
[1], '\t') == NULL
)
2216 return name_attribute(client
, req
+ 1);
2218 else if (g_utf8_collate(req
[0], "target") == 0)
2219 return target_attribute(client
, req
+ 1);
2221 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2223 * The first argument may be only an account.
2225 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2226 return EPWMD_COMMAND_SYNTAX
;
2229 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2235 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2236 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2243 return add_attribute(n
, req
[0], req
[2]);
2252 * req[1] - attribute name or element path if command is LIST
2253 * req[2] - element path
2254 * req[2] - element path or value
2256 static int attr_command(assuan_context_t ctx
, char *line
)
2258 struct client_s
*client
= assuan_get_pointer(ctx
);
2262 rc
= file_modified(client
);
2265 return send_error(ctx
, rc
);
2267 req
= split_input_line(line
, " ", 4);
2269 if (!req
|| !req
[0] || !req
[1]) {
2271 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2274 pthread_cleanup_push(req_cleanup
, req
);
2276 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2277 rc
= attribute_set(client
, req
+1);
2278 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2279 rc
= attribute_get(ctx
, req
+1);
2280 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2281 rc
= attribute_delete(client
, req
+1);
2282 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2283 rc
= attribute_list(ctx
, req
+1);
2285 rc
= EPWMD_COMMAND_SYNTAX
;
2287 pthread_cleanup_pop(1);
2288 return send_error(ctx
, rc
);
2291 static int iscached_command(assuan_context_t ctx
, char *line
)
2293 gchar
**req
= split_input_line(line
, " ", 0);
2296 if (!req
|| !*req
) {
2298 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2301 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2303 pthread_cleanup_push(pthread_mutex_unlock
, (void *)&cache_mutex
);
2306 if (cache_iscached(md5file
) == FALSE
) {
2308 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2312 pthread_cleanup_pop(0);
2313 return send_error(ctx
, 0);
2316 static int clearcache_command(assuan_context_t ctx
, char *line
)
2318 struct client_s
*client
= assuan_get_pointer(ctx
);
2319 gchar
**req
= split_input_line(line
, " ", 0);
2322 pthread_cleanup_push(pthread_mutex_unlock
, (void *)&cache_mutex
);
2325 if (!req
|| !*req
) {
2327 cache_clear(client
->md5file
, 2);
2329 return send_error(ctx
, 0);
2332 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2335 if (cache_clear(md5file
, 1) == FALSE
) {
2337 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2341 pthread_cleanup_pop(0);
2342 return send_error(ctx
, 0);
2345 static int cachetimeout_command(assuan_context_t ctx
, char *line
)
2349 gchar
**req
= split_input_line(line
, " ", 0);
2351 struct client_s
*client
= assuan_get_pointer(ctx
);
2353 pthread_cleanup_push(req_cleanup
, req
);
2355 if (!req
|| !*req
|| !req
[1]) {
2357 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2361 timeout
= strtol(req
[0], &p
, 10);
2363 if (errno
!= 0 || *p
!= 0) {
2365 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2368 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2369 pthread_cleanup_pop(1);
2370 pthread_cleanup_push(pthread_mutex_unlock
, (void *)&cache_mutex
);
2371 CACHE_LOCK(client
->ctx
);
2373 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2375 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2379 pthread_cleanup_pop(0);
2380 return send_error(ctx
, 0);
2383 static int dump_command(assuan_context_t ctx
, char *line
)
2387 struct client_s
*client
= assuan_get_pointer(ctx
);
2390 if (disable_list_and_dump
== TRUE
)
2391 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2393 rc
= file_modified(client
);
2396 return send_error(ctx
, rc
);
2398 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2401 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2402 return send_syserror(ctx
, ENOMEM
);
2405 pthread_cleanup_push(xmlFree
, xml
);
2406 pthread_testcancel();
2407 rc
= assuan_send_data(ctx
, xml
, len
);
2408 pthread_testcancel();
2409 pthread_cleanup_pop(1);
2410 return send_error(ctx
, rc
);
2413 static int getconfig_command(assuan_context_t ctx
, gchar
*line
)
2415 struct client_s
*client
= assuan_get_pointer(ctx
);
2417 gchar filename
[255]={0}, param
[747]={0};
2418 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2420 if (strchr(line
, ' ')) {
2421 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2426 if (fp
&& !valid_filename(fp
))
2427 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
2429 paramp
= g_ascii_strdown(paramp
, -1);
2432 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2433 return send_syserror(ctx
, ENOMEM
);
2436 p
= get_key_file_string(fp
? fp
: "global", paramp
);
2440 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2442 tmp
= expand_homedir(p
);
2446 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2447 return send_syserror(ctx
, ENOMEM
);
2451 pthread_cleanup_push(g_free
, p
);
2452 pthread_testcancel();
2453 rc
= assuan_send_data(ctx
, p
, strlen(p
));
2454 pthread_testcancel();
2455 pthread_cleanup_pop(1);
2456 return send_error(ctx
, rc
);
2460 xmlXPathContextPtr xp
;
2461 xmlXPathObjectPtr result
;
2466 static void xpath_command_cleanup(void *arg
)
2468 struct xpath_s
*xpath
= arg
;
2470 req_cleanup(xpath
->req
);
2473 xmlBufferFree(xpath
->buf
);
2476 xmlXPathFreeObject(xpath
->result
);
2479 xmlXPathFreeContext(xpath
->xp
);
2482 static int xpath_command(assuan_context_t ctx
, gchar
*line
)
2484 struct client_s
*client
= assuan_get_pointer(ctx
);
2486 struct xpath_s xpath
;
2488 if (disable_list_and_dump
== TRUE
)
2489 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2491 rc
= file_modified(client
);
2494 return send_error(ctx
, rc
);
2496 if (!line
|| !*line
)
2497 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2499 memset(&xpath
, 0, sizeof(struct xpath_s
));
2500 pthread_cleanup_push(xpath_command_cleanup
, &xpath
);
2502 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
2503 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
2504 return send_syserror(ctx
, ENOMEM
);
2507 xpath
.xp
= xmlXPathNewContext(client
->doc
);
2510 xpath_command_cleanup(&xpath
);
2511 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2514 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
2516 if (!xpath
.result
) {
2517 xpath_command_cleanup(&xpath
);
2518 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2521 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
2522 rc
= EPWMD_EMPTY_ELEMENT
;
2526 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
2527 (xmlChar
*)xpath
.req
[1], &xpath
.buf
);
2531 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
2532 rc
= EPWMD_EMPTY_ELEMENT
;
2535 else if (xpath
.req
[1])
2538 pthread_testcancel();
2539 rc
= assuan_send_data(ctx
, xmlBufferContent(xpath
.buf
),
2540 xmlBufferLength(xpath
.buf
));
2541 pthread_testcancel();
2545 pthread_cleanup_pop(1);
2546 return send_error(ctx
, rc
);
2549 static int import_command_finalize(gpointer data
, gint assuan_rc
, guchar
*line
,
2552 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
2553 gpg_error_t rc
= file_modified(client
);
2554 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
2556 xmlNodePtr n
, root
, copy
;
2558 if (assuan_rc
|| rc
) {
2561 return assuan_rc
? assuan_rc
: rc
;
2564 req
= split_input_line((gchar
*)line
, " ", 2);
2568 return EPWMD_COMMAND_SYNTAX
;
2570 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2571 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
2572 return EPWMD_COMMAND_SYNTAX
;
2577 if (!content
|| !*content
) {
2578 rc
= EPWMD_COMMAND_SYNTAX
;
2582 if (valid_xml_element((xmlChar
*)*path
) == FALSE
) {
2583 rc
= EPWMD_INVALID_ELEMENT
;
2587 if (valid_element_path(path
+1, FALSE
) == FALSE
) {
2588 rc
= EPWMD_INVALID_ELEMENT
;
2592 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2595 rc
= EPWMD_LIBXML_ERROR
;
2599 root
= xmlDocGetRootElement(doc
);
2600 path_orig
= g_strdupv(path
);
2604 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2605 rc
= gpg_error_from_errno(ENOMEM
);
2609 if (strv_printf(&path
, "%s", (gchar
*)root
->name
) == FALSE
) {
2610 g_strfreev(path_orig
);
2612 rc
= gpg_error_from_errno(ENOMEM
);
2616 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0);
2618 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2619 g_strfreev(path_orig
);
2624 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2626 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2627 g_strfreev(path_orig
);
2632 xmlNodePtr parent
= n
->parent
;
2643 if (rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2644 n
= create_element_path(client
, &path
, &rc
);
2652 copy
= xmlCopyNode(root
, 1);
2653 n
= xmlAddChild(n
, copy
);
2657 rc
= EPWMD_LIBXML_ERROR
;
2662 client
->inquire_status
= INQUIRE_DONE
;
2666 static int import_command(assuan_context_t ctx
, gchar
*line
)
2669 struct client_s
*client
= assuan_get_pointer(ctx
);
2671 rc
= file_modified(client
);
2674 return send_error(ctx
, rc
);
2676 pthread_testcancel();
2677 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
2678 pthread_testcancel();
2681 return send_error(ctx
, rc
);
2683 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2684 client
->inquire_status
= INQUIRE_BUSY
;
2688 static int lock_command(assuan_context_t ctx
, gchar
*line
)
2691 struct client_s
*client
= assuan_get_pointer(ctx
);
2693 rc
= file_modified(client
);
2696 return send_error(ctx
, rc
);
2698 rc
= lock_file_mutex(client
);
2701 client
->is_lock_cmd
= TRUE
;
2703 return send_error(ctx
, rc
);
2706 static int unlock_command(assuan_context_t ctx
, gchar
*line
)
2708 struct client_s
*client
= assuan_get_pointer(ctx
);
2709 gpg_error_t rc
= file_modified(client
);
2712 return send_error(ctx
, rc
);
2714 unlock_file_mutex(client
);
2715 return send_error(ctx
, 0);
2718 static int getpid_command(assuan_context_t ctx
, gchar
*line
)
2722 pid_t pid
= getpid();
2724 print_fmt(buf
, sizeof(buf
), "%i", pid
);
2725 pthread_testcancel();
2726 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2727 pthread_testcancel();
2728 return send_error(ctx
, rc
);
2731 static int version_command(assuan_context_t ctx
, gchar
*line
)
2736 print_fmt(buf
, sizeof(buf
), "%s", PACKAGE_VERSION
);
2737 pthread_testcancel();
2738 rc
= assuan_send_data(ctx
, buf
, strlen(buf
));
2739 pthread_testcancel();
2740 return send_error(ctx
, rc
);
2743 static void bye_notify(assuan_context_t ctx
)
2745 struct client_s
*cl
= assuan_get_pointer(ctx
);
2749 if (!cl
->thd
->remote
)
2753 rc
= gnutls_bye(cl
->thd
->tls
->ses
, GNUTLS_SHUT_RDWR
);
2754 } while (rc
== GNUTLS_E_AGAIN
);
2757 /* This will let assuan_process_next() return. */
2758 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
2761 static void reset_notify(assuan_context_t ctx
)
2763 struct client_s
*cl
= assuan_get_pointer(ctx
);
2769 static gpg_error_t
parse_client_option(assuan_context_t ctx
, const gchar
*line
)
2771 gchar name
[32] = {0}, value
[256] = {0};
2773 if (sscanf(line
, " %31[a-zA-Z] = %255c", name
, value
) != 2)
2774 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
);
2776 if (g_strcasecmp(name
, (gchar
*)"NAME") == 0) {
2777 struct client_s
*cl
= assuan_get_pointer(ctx
);
2780 g_free(cl
->thd
->name
);
2782 cl
->thd
->name
= g_strdup(value
);
2783 log_write("OPTION CLIENT %s", line
);
2786 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2791 static int option_handler(assuan_context_t ctx
, const gchar
*name
,
2794 struct client_s
*client
= assuan_get_pointer(ctx
);
2796 if (!value
|| !*value
)
2797 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2799 if (g_strcasecmp(name
, (gchar
*)"client") == 0)
2800 return parse_client_option(ctx
, value
);
2802 if (g_strcasecmp(name
, (gchar
*)"iterations") == 0) {
2807 n
= strtol(value
, &p
, 10);
2809 if (errno
|| (p
&& *p
) || n
< 0)
2810 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2812 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
: "global", "iterations", (guint
)n
);
2813 send_status_all(STATUS_CONFIG
);
2815 #ifdef WITH_PINENTRY
2816 else if (g_strcasecmp(name
, (gchar
*)"ttyname") == 0) {
2817 g_free(client
->pinentry
->ttyname
);
2818 client
->pinentry
->ttyname
= g_strdup(value
);
2820 else if (g_strcasecmp(name
, (gchar
*)"ttytype") == 0) {
2821 g_free(client
->pinentry
->ttytype
);
2822 client
->pinentry
->ttytype
= g_strdup(value
);
2824 else if (g_strcasecmp(name
, (gchar
*)"display") == 0) {
2825 g_free(client
->pinentry
->display
);
2826 client
->pinentry
->display
= g_strdup(value
);
2828 else if (g_strcasecmp(name
, (gchar
*)"path") == 0) {
2829 g_free(client
->pinentry
->path
);
2830 client
->pinentry
->path
= g_strdup(value
);
2832 else if (g_strcasecmp(name
, (gchar
*)"title") == 0) {
2833 g_free(client
->pinentry
->title
);
2834 client
->pinentry
->title
= g_strdup(value
);
2836 else if (g_strcasecmp(name
, (gchar
*)"prompt") == 0) {
2837 g_free(client
->pinentry
->prompt
);
2838 client
->pinentry
->prompt
= g_strdup(value
);
2840 else if (g_strcasecmp(name
, (gchar
*)"desc") == 0) {
2841 g_free(client
->pinentry
->desc
);
2842 client
->pinentry
->desc
= g_strdup(value
);
2845 * Look at client_thread() to see how this works.
2847 else if (g_strcasecmp(name
, (gchar
*)"timeout") == 0) {
2849 gint n
= strtol(value
, &p
, 10);
2852 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2854 client
->pinentry
->timeout
= n
;
2856 else if (g_strcasecmp(name
, (gchar
*)"pinentry") == 0) {
2858 gint n
= strtol(value
, &p
, 10);
2860 if (*p
|| n
< 0 || n
> 1)
2861 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
2863 client
->pinentry
->enable
= n
== 0 ? FALSE
: TRUE
;
2867 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
2869 log_write("OPTION %s=%s", name
, value
);
2873 gpg_error_t
register_commands(assuan_context_t ctx
)
2877 gint (*handler
)(assuan_context_t
, gchar
*line
);
2879 { "OPEN", open_command
},
2880 { "SAVE", save_command
},
2881 { "LIST", list_command
},
2882 { "REALPATH", realpath_command
},
2883 { "STORE", store_command
},
2884 { "DELETE", delete_command
},
2885 { "GET", get_command
},
2886 { "ATTR", attr_command
},
2887 { "ISCACHED", iscached_command
},
2888 { "CLEARCACHE", clearcache_command
},
2889 { "CACHETIMEOUT", cachetimeout_command
},
2890 { "GETCONFIG", getconfig_command
},
2891 { "DUMP", dump_command
},
2892 { "XPATH", xpath_command
},
2893 { "IMPORT", import_command
},
2894 { "LOCK", lock_command
},
2895 { "UNLOCK", unlock_command
},
2896 { "GETPID", getpid_command
},
2897 { "VERSION", version_command
},
2904 for (i
=0; table
[i
].name
; i
++) {
2905 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
2911 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
2916 rc
= assuan_register_option_handler(ctx
, option_handler
);
2921 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
2926 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
2929 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, guchar
*key
,
2930 struct client_crypto_s
*crypto
, gpointer
*dst
, gsize
*dst_len
)
2933 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
2934 guint iter
= 0, n_iter
= 0, iter_progress
= 0;
2938 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->fh1
) : sizeof(crypto
->fh
->fh2
);
2939 glong fh_iter
= crypto
->fh
->v1
? crypto
->fh
->fh1
.iter
: crypto
->fh
->fh2
.iter
;
2941 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
2942 insize
= crypto
->fh
->st
.st_size
- fh_size
;
2943 crypto
->iv
= gcry_malloc(gcryblocksize
);
2946 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2947 return gpg_error_from_errno(ENOMEM
);
2950 /* No encryption iterations. This is a plain (gzipped) file. */
2951 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0)) {
2953 * cache_file_count() needs both .used == TRUE and a valid key in
2954 * order for it to count as a used cache entry. Fixes CACHE status
2957 memset(key
, '!', gcrykeysize
);
2961 memcpy(crypto
->iv
, crypto
->fh
->fh1
.iv
, gcryblocksize
);
2963 memcpy(crypto
->iv
, crypto
->fh
->fh2
.iv
, gcryblocksize
);
2965 crypto
->inbuf
= gcry_malloc(insize
);
2967 if (!crypto
->inbuf
) {
2968 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2969 return gpg_error_from_errno(ENOMEM
);
2972 crypto
->insize
= insize
;
2973 len
= read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
2975 if (len
!= crypto
->insize
)
2976 return GPG_ERR_INV_LENGTH
;
2978 if ((crypto
->fh
->v1
&& fh_iter
< 0) || (!crypto
->fh
->v1
&& fh_iter
<= 0))
2981 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
2982 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2986 if ((rc
= gcry_cipher_setkey(crypto
->gh
, key
, gcrykeysize
))) {
2987 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
2991 iter_progress
= (guint
)get_key_file_integer(client
&& client
->filename
?
2992 client
->filename
: "global", "iteration_progress");
2994 if (iter_progress
> 0 && fh_iter
>= iter_progress
) {
2995 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u", 0, fh_iter
);
3001 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3006 crypto
->tkey
= gcry_malloc(gcrykeysize
);
3008 if (!crypto
->tkey
) {
3009 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
3010 return gpg_error_from_errno(ENOMEM
);
3013 memcpy(crypto
->tkey
, key
, gcrykeysize
);
3014 guchar
*tkey
= crypto
->tkey
;
3017 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, gcrykeysize
))) {
3018 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3022 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
3023 if (iter_progress
> 0 && iter
>= iter_progress
) {
3024 if (!(iter
% iter_progress
)) {
3025 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u",
3026 ++n_iter
* iter_progress
, fh_iter
);
3033 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, gcryblocksize
))) {
3034 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3038 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3041 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(rc
));
3048 if (iter_progress
&& fh_iter
>= iter_progress
) {
3049 rc
= send_status(ctx
, STATUS_DECRYPT
, "%u %u", fh_iter
, fh_iter
);
3056 if (do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
3057 (gpointer
*)&crypto
->outbuf
, &outsize
, &zrc
) == FALSE
) {
3058 if (zrc
== Z_MEM_ERROR
)
3059 return gpg_error_from_errno(ENOMEM
);
3061 return EPWMD_BADKEY
; // Not a valid gzip header. Must be a bad key.
3064 if (g_strncasecmp(crypto
->outbuf
, "<?xml version=\"1.0\"?>", 21) != 0) {
3065 gcry_free(crypto
->outbuf
);
3066 crypto
->outbuf
= NULL
;
3067 return EPWMD_BADKEY
;
3071 client
->xml
= crypto
->outbuf
;
3072 client
->len
= outsize
;
3073 crypto
->outbuf
= NULL
;
3076 *dst
= crypto
->outbuf
;
3078 crypto
->outbuf
= NULL
;
3081 /* The calling function should free the crypto struct. */
3086 * This is called after every Assuan command.
3088 void command_finalize(assuan_context_t ctx
, gint rc
)
3090 struct client_s
*client
= assuan_get_pointer(ctx
);
3092 if (!client
->is_lock_cmd
)
3093 unlock_file_mutex(client
);