1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2010 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>
48 #include "pwmd_error.h"
61 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
63 return gcry_calloc(items
, size
);
66 static void z_free(void *data
, void *p
)
71 static gpg_error_t
file_modified(struct client_s
*client
)
76 if (client
->state
!= STATE_OPEN
)
79 rc
= lock_file_mutex(client
);
84 if (lstat(client
->filename
, &st
) == 0 && client
->mtime
) {
85 if (client
->mtime
!= st
.st_mtime
)
86 return EPWMD_FILE_MODIFIED
;
93 static gpg_error_t
parse_xml(assuan_context_t ctx
)
95 struct client_s
*client
= assuan_get_pointer(ctx
);
97 client
->doc
= xmlReadMemory(client
->xml
, client
->len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
100 return EPWMD_LIBXML_ERROR
;
105 void unlock_file_mutex(struct client_s
*client
)
110 if (client
->has_lock
== FALSE
|| client
->pinentry
->status
!= PINENTRY_NONE
)
112 if (client
->has_lock
== FALSE
)
116 CACHE_LOCK(client
->ctx
);
118 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
125 client
->has_lock
= client
->is_lock_cmd
= FALSE
;
128 gpg_error_t
lock_file_mutex(struct client_s
*client
)
133 if (client
->has_lock
== TRUE
)
136 CACHE_LOCK(client
->ctx
);
138 if (cache_get_mutex(client
->md5file
, &m
) == FALSE
) {
144 MUTEX_TRYLOCK(client
->ctx
, m
, rc
);
147 client
->has_lock
= TRUE
;
152 void free_client(struct client_s
*client
)
155 xmlFreeDoc(client
->doc
);
158 gcry_free(client
->xml
);
160 if (client
->filename
)
161 g_free(client
->filename
);
164 cleanup_crypto(&client
->crypto
);
166 if (client
->xml_error
)
167 xmlResetError(client
->xml_error
);
170 void cleanup_client(struct client_s
*client
)
172 assuan_context_t ctx
= client
->ctx
;
173 struct client_thread_s
*thd
= client
->thd
;
174 gboolean has_lock
= client
->has_lock
;
176 struct pinentry_s
*pin
= client
->pinentry
;
179 unlock_file_mutex(client
);
180 CACHE_LOCK(client
->ctx
);
181 cache_decr_refcount(client
->md5file
);
184 * This may be a new file so don't use a cache slot. save_command() will
185 * set this to FALSE on success.
187 if (client
->new == TRUE
)
188 cache_clear(client
->md5file
, 1);
192 memset(client
, 0, sizeof(struct client_s
));
193 client
->state
= STATE_CONNECTED
;
196 client
->freed
= TRUE
;
198 client
->pinentry
= pin
;
200 client
->has_lock
= has_lock
;
203 static void gz_cleanup(void *arg
)
205 struct gz_s
**gz
= (struct gz_s
**)arg
;
210 if (!(*gz
)->done
&& (*gz
)->out
)
211 gcry_free((*gz
)->out
);
213 if ((*gz
)->which
== STATUS_COMPRESS
) {
215 deflateEnd(&(*gz
)->z
);
219 inflateEnd(&(*gz
)->z
);
226 gboolean
do_decompress(assuan_context_t ctx
, gpointer in
, gulong insize
,
227 gpointer
*out
, gulong
*outsize
, gint
*rc
)
233 gz
= g_malloc0(sizeof(struct gz_s
));
236 *rc
= gpg_error_from_errno(ENOMEM
);
240 pth_cleanup_push(gz_cleanup
, &gz
);
241 gz
->which
= STATUS_DECOMPRESS
;
242 gz
->z
.zalloc
= z_alloc
;
243 gz
->z
.zfree
= z_free
;
245 gz
->z
.avail_in
= (uInt
)insize
;
246 gz
->z
.avail_out
= zlib_bufsize
;
247 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
250 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
256 *rc
= inflateInit2(&gz
->z
, 47);
259 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
264 memset(&h
, 0, sizeof(gz_header
));
265 h
.comment
= (guchar
*)buf
;
266 h
.comm_max
= sizeof(buf
);
267 *rc
= inflateGetHeader(&gz
->z
, &h
);
270 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
275 *rc
= inflate(&gz
->z
, Z_BLOCK
);
278 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
284 insize
= (gulong
)strtol((gchar
*)h
.comment
, NULL
, 10);
289 *rc
= inflate(&gz
->z
, Z_FINISH
);
295 if (!gz
->z
.avail_out
) {
296 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
299 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
305 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
306 gz
->z
.avail_out
= zlib_bufsize
;
307 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li",
308 gz
->z
.total_out
, insize
);
320 } while (*rc
!= Z_STREAM_END
);
322 *rc
= send_status(ctx
, STATUS_DECOMPRESS
, "%li %li", gz
->z
.total_out
,
329 *outsize
= gz
->z
.total_out
;
336 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
341 file_header_internal_t
*read_file_header(const gchar
*filename
, gboolean v1
,
346 file_header_internal_t
*fh
= g_malloc0(sizeof(file_header_internal_t
));
353 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
354 *rc
= gpg_error_from_errno(ENOMEM
);
358 pth_cleanup_push(g_free
, fh
);
359 fh_size
= v1
? sizeof(fh
->ver
.fh1
) : sizeof(fh
->ver
.fh2
);
361 if (lstat(filename
, &fh
->st
) == -1) {
362 *rc
= gpg_error_from_syserror();
367 if (!S_ISREG(fh
->st
.st_mode
)) {
368 *rc
= GPG_ERR_ENOANO
;
373 fd
= open(filename
, O_RDONLY
);
376 *rc
= gpg_error_from_errno(errno
);
381 pth_cleanup_push(cleanup_fd_cb
, &fd
);
382 p
= v1
? (void *)&fh
->ver
.fh1
: (void *)&fh
->ver
.fh2
;
383 len
= pth_read(fd
, p
, fh_size
);
385 if (len
!= fh_size
) {
389 *rc
= gpg_error_from_errno(n
);
401 * This is called before every Assuan command.
403 gpg_error_t
command_startup(assuan_context_t ctx
)
405 struct client_s
*cl
= assuan_get_pointer(ctx
);
407 const gchar
*name
= assuan_get_command_name(ctx
);
412 log_write1("%s", name
);
414 if (!g_ascii_strcasecmp(name
, "ISCACHED") ||
415 !g_ascii_strcasecmp(name
, "CLEARCACHE") ||
416 !g_ascii_strcasecmp(name
, "CACHETIMEOUT") ||
417 !g_ascii_strcasecmp(name
, "GETCONFIG") ||
418 !g_ascii_strcasecmp(name
, "GETPID") ||
419 !g_ascii_strcasecmp(name
, "VERSION") ||
420 !g_ascii_strcasecmp(name
, "SET") ||
421 !g_ascii_strcasecmp(name
, "BYE") ||
422 !g_ascii_strcasecmp(name
, "NOP") ||
423 !g_ascii_strcasecmp(name
, "CANCEL") ||
424 !g_ascii_strcasecmp(name
, "RESET") ||
425 !g_ascii_strcasecmp(name
, "END") ||
426 !g_ascii_strcasecmp(name
, "HELP") ||
427 !g_ascii_strcasecmp(name
, "OPTION") ||
428 !g_ascii_strcasecmp(name
, "INPUT") ||
429 !g_ascii_strcasecmp(name
, "OUTPUT") ||
430 !g_ascii_strcasecmp(name
, "UNSET"))
433 cl
->last_rc
= rc
= file_modified(cl
);
436 if ((rc
== EPWMD_NO_FILE
|| rc
== EPWMD_FILE_MODIFIED
) &&
437 !g_ascii_strcasecmp(name
, "OPEN"))
444 static gpg_error_t
open_command_finalize(assuan_context_t ctx
, guchar
*key
,
447 struct client_s
*client
= assuan_get_pointer(ctx
);
452 if (!client
->crypto
->fh
) {
459 rc
= init_client_crypto2(client
->filename
, client
->crypto
);
462 cleanup_client(client
);
463 return send_error(ctx
, rc
);
466 rc
= try_xml_decrypt(ctx
, key
, client
->crypto
, NULL
, NULL
);
469 cleanup_client(client
);
470 return send_error(ctx
, rc
);
474 CACHE_LOCK(client
->ctx
);
476 if (cached
== FALSE
) {
477 if (cache_update_key(client
->md5file
, key
) == FALSE
) {
478 cleanup_client(client
);
480 return send_syserror(ctx
, ENOMEM
);
483 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
484 cache_reset_timeout(client
->md5file
, timeout
);
487 cache_set_timeout(client
->md5file
, -2);
495 gcry_free(client
->xml
);
500 if (client
->new == FALSE
)
501 send_status_all(STATUS_CACHE
);
503 client
->state
= STATE_OPEN
;
506 if (!rc
&& client
->new == FALSE
&&
507 client
->crypto
->fh
->ver
.fh2
.iter
!= (guint64
)get_key_file_double(client
->filename
, "iterations")) {
508 MUTEX_LOCK(&rcfile_mutex
);
509 g_key_file_set_double(keyfileh
, client
->filename
, "iterations",
510 client
->crypto
->fh
->ver
.fh2
.iter
);
511 MUTEX_UNLOCK(&rcfile_mutex
);
512 send_status_all(STATUS_CONFIG
);
515 cleanup_crypto(&client
->crypto
);
516 return send_error(ctx
, rc
);
519 static void req_cleanup(void *arg
)
524 g_strfreev((gchar
**)arg
);
527 static gpg_error_t
open_command(assuan_context_t ctx
, gchar
*line
)
529 gboolean cached
= FALSE
;
531 struct client_s
*client
= assuan_get_pointer(ctx
);
533 gchar
*filename
= NULL
;
534 guint hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
536 rc
= command_startup(ctx
);
539 return send_error(ctx
, rc
);
541 if ((req
= split_input_line(line
, " ", 2)) != NULL
)
544 pth_cleanup_push(req_cleanup
, req
);
546 if (!filename
|| !*filename
) {
548 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
551 log_write2("ARGS=\"%s\" %s", filename
, req
[1] ? "<passphrase>" : "");
553 if (valid_filename(filename
) == FALSE
) {
555 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
558 if (client
->state
== STATE_OPEN
)
559 cleanup_client(client
);
561 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
562 CACHE_LOCK(client
->ctx
);
564 if (cache_has_file(client
->md5file
) == FALSE
) {
565 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
568 return send_syserror(ctx
, ENOMEM
);
572 cache_incr_refcount(client
->md5file
);
574 rc
= lock_file_mutex(client
);
578 return send_error(ctx
, rc
);
581 client
->freed
= FALSE
;
582 client
->crypto
= init_client_crypto();
584 if (!client
->crypto
) {
586 cleanup_client(client
);
587 return send_syserror(ctx
, ENOMEM
);
590 client
->crypto
->key
= gcry_malloc(hashlen
);
592 if (!client
->crypto
->key
) {
594 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
,
595 gpg_error_from_errno(ENOMEM
));
596 cleanup_client(client
);
597 return send_syserror(ctx
, ENOMEM
);
600 memset(client
->crypto
->key
, 0, hashlen
);
601 client
->crypto
->fh
= read_file_header(filename
, FALSE
, &rc
);
603 if (!client
->crypto
->fh
) {
604 if (gpg_err_code_to_errno(rc
) != ENOENT
) {
605 log_write("%s: %s", filename
, pwmd_strerror(rc
));
607 cleanup_client(client
);
608 return send_error(ctx
, rc
);
612 * New files don't need a key.
614 if ((client
->xml
= new_document()) == NULL
) {
615 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
617 cleanup_client(client
);
618 return send_syserror(ctx
, ENOMEM
);
621 client
->len
= xmlStrlen(client
->xml
);
623 client
->filename
= g_strdup(filename
);
625 if (!client
->filename
) {
627 cleanup_client(client
);
628 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
629 return send_syserror(ctx
, ENOMEM
);
632 if (req
[1] && *req
[1])
633 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
638 client
->pinentry
->filename
= g_strdup(client
->filename
);
640 if (!client
->pinentry
->filename
) {
641 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
642 cleanup_client(client
);
643 return send_syserror(ctx
, ENOMEM
);
646 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
649 client
->mtime
= client
->crypto
->fh
->st
.st_mtime
;
651 client
->filename
= g_strdup(filename
);
653 if (!client
->filename
) {
654 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
656 cleanup_client(client
);
657 return send_syserror(ctx
, ENOMEM
);
661 client
->pinentry
->filename
= g_strdup(client
->filename
);
663 if (!client
->pinentry
->filename
) {
664 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
666 cleanup_client(client
);
667 return send_syserror(ctx
, ENOMEM
);
671 if (client
->crypto
->fh
->ver
.fh2
.iter
<= 0ULL)
674 CACHE_LOCK(client
->ctx
);
675 cached
= cache_get_key(client
->md5file
, client
->crypto
->key
);
678 if (cached
== FALSE
) {
679 gchar
*tmp
= get_key_file_string(filename
, "key_file");
684 cleanup_client(client
);
685 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
689 * No key specified and no matching filename found in the cache. Use
690 * pinentry to retrieve the key. Cannot return assuan_process_done()
691 * here otherwise the command will be interrupted. The event loop in
692 * client_thread() will poll the file descriptor waiting for it to
693 * become ready to read a pinentry_key_s which will contain the
694 * entered key or an error code. It will then call
695 * open_command_finalize() to to finish the command.
697 if (!req
[1] || !*req
[1]) {
699 gboolean b
= get_key_file_boolean(filename
, "enable_pinentry");
701 /* From set_pinentry_defaults(). */
702 if (client
->pinentry
->enable
== FALSE
||
703 (client
->pinentry
->enable
== -1 && b
== FALSE
)) {
704 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
709 rc
= lock_pin_mutex(client
);
712 unlock_pin_mutex(client
->pinentry
);
713 cleanup_client(client
);
714 return send_error(ctx
, rc
);
717 client
->pinentry
->which
= PINENTRY_OPEN
;
718 rc
= pinentry_fork(ctx
);
721 unlock_pin_mutex(client
->pinentry
);
722 cleanup_client(client
);
723 return send_error(ctx
, rc
);
726 // Called from pinentry iterate.
727 client
->pinentry
->cb
= open_command_finalize
;
728 client
->pinentry
->status
= PINENTRY_INIT
;
731 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
736 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
739 else if (req
&& req
[1] && *req
[1]) {
740 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, req
[1],
741 strlen(req
[1]) ? strlen(req
[1]) : 1);
746 return open_command_finalize(ctx
, client
->crypto
->key
, cached
);
749 gboolean
do_compress(assuan_context_t ctx
, gint level
, gpointer data
,
750 guint size
, gpointer
*out
, gulong
*outsize
, gint
*rc
)
755 gint cmd
= Z_NO_FLUSH
;
757 gz
= g_malloc0(sizeof(struct gz_s
));
760 *rc
= gpg_error_from_errno(ENOMEM
);
764 pth_cleanup_push(gz_cleanup
, &gz
);
765 gz
->which
= STATUS_COMPRESS
;
766 gz
->z
.zalloc
= z_alloc
;
767 gz
->z
.zfree
= z_free
;
768 gz
->z
.next_in
= data
;
769 gz
->z
.avail_in
= size
< zlib_bufsize
? (uInt
)size
: (uInt
)zlib_bufsize
;
770 gz
->z
.avail_out
= (uInt
)zlib_bufsize
;
771 gz
->z
.next_out
= gz
->out
= gcry_malloc(zlib_bufsize
);
774 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
780 *rc
= deflateInit2(&gz
->z
, level
, Z_DEFLATED
, 31, 8, Z_DEFAULT_STRATEGY
);
783 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
788 /* Rather than store the size of the uncompressed data in the file header,
789 * store it in the comment field of the gzip header. Don't give anyone too
790 * much information. Not sure why really, but it seems the right way. :)
792 memset(&h
, 0, sizeof(gz_header
));
793 g_snprintf(buf
, sizeof(buf
), "%u", size
);
794 h
.comment
= (guchar
*)buf
;
795 *rc
= deflateSetHeader(&gz
->z
, &h
);
798 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
806 *rc
= deflate(&gz
->z
, cmd
);
812 if (!gz
->z
.avail_out
) {
813 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ zlib_bufsize
);
816 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
822 gz
->z
.next_out
= (guchar
*)gz
->out
+ gz
->z
.total_out
;
823 gz
->z
.avail_out
= zlib_bufsize
;
826 if (!gz
->z
.avail_in
&& gz
->z
.total_in
< size
) {
827 if (gz
->z
.total_in
+ zlib_bufsize
> size
)
828 gz
->z
.avail_in
= size
- gz
->z
.total_in
;
830 gz
->z
.avail_in
= zlib_bufsize
;
832 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u",
833 gz
->z
.total_in
, size
);
839 if (gz
->z
.total_in
>= size
)
848 } while (*rc
!= Z_STREAM_END
);
850 *rc
= send_status(ctx
, STATUS_COMPRESS
, "%li %u", gz
->z
.total_in
, size
);
856 *outsize
= gz
->z
.total_out
;
863 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gz
->z
.msg
);
868 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
870 static gpg_error_t
iterate_crypto_once(struct client_s
*client
,
871 struct client_crypto_s
*crypto
, status_msg_t which
)
874 goffset len
= CRYPTO_BLOCKSIZE(crypto
);
875 gpointer p
= gcry_malloc(len
);
880 return gpg_err_code_from_errno(ENOMEM
);
882 if (crypto
->insize
< CRYPTO_BLOCKSIZE(crypto
))
883 len
= crypto
->insize
;
885 pth_cleanup_push(gcry_free
, p
);
888 inbuf
= (guchar
*)crypto
->inbuf
+ total
;
891 if (len
+ total
> crypto
->insize
)
892 len
= crypto
->blocksize
;
894 if (which
== STATUS_ENCRYPT
)
895 rc
= gcry_cipher_encrypt(crypto
->gh
, p
, len
, inbuf
, len
);
897 rc
= gcry_cipher_decrypt(crypto
->gh
, p
, len
, inbuf
, len
);
902 tmp
= (guchar
*)crypto
->inbuf
+ total
;
903 memmove(tmp
, p
, len
);
906 if (total
>= crypto
->insize
)
917 /* The crypto struct must be setup for iterations and .key. */
918 gpg_error_t
do_xml_encrypt(struct client_s
*client
,
919 struct client_crypto_s
*crypto
, const gchar
*filename
)
921 goffset len
= crypto
->insize
;
925 guint64 iter_progress
= 0ULL, n_iter
= 0ULL, xiter
= 0ULL;
926 gchar tmp
[FILENAME_MAX
];
929 guint hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
931 if (!crypto
->fh
->ver
.fh2
.iter
) {
933 * cache_file_count() needs both .used == TRUE and a valid key in
934 * order for it to count as a used cache entry. Fixes CACHE status
937 memset(crypto
->key
, '!', hashlen
);
942 * Resize the existing xml buffer to the block size required by gcrypt
943 * rather than duplicating it and wasting memory.
945 len
= (crypto
->insize
/ crypto
->blocksize
) * crypto
->blocksize
;
947 if (crypto
->insize
% crypto
->blocksize
)
948 len
+= crypto
->blocksize
;
950 inbuf
= gcry_realloc(crypto
->inbuf
, len
);
953 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
954 return gpg_error_from_errno(ENOMEM
);
957 crypto
->inbuf
= inbuf
;
958 crypto
->insize
= len
;
959 gcry_create_nonce(crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
960 crypto
->tkey
= gcry_malloc(hashlen
);
963 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
964 return gpg_error_from_errno(ENOMEM
);
967 memcpy(crypto
->tkey
, crypto
->key
, hashlen
);
968 guchar
*tkey
= crypto
->tkey
;
971 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
972 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
976 iter_progress
= (guint64
)get_key_file_double(
977 client
? client
->filename
: "global", "iteration_progress");
979 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
980 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
981 "0 %llu", crypto
->fh
->ver
.fh2
.iter
);
987 while (xiter
< crypto
->fh
->ver
.fh2
.iter
-1) {
988 if (iter_progress
> 0ULL && xiter
>= iter_progress
) {
989 if (!(xiter
% iter_progress
)) {
990 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
991 "%llu %llu", ++n_iter
* iter_progress
,
992 crypto
->fh
->ver
.fh2
.iter
);
999 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1000 crypto
->blocksize
))) {
1001 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
1005 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1008 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
1015 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->fh
->ver
.fh2
.iv
,
1016 crypto
->blocksize
))) {
1017 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
1021 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->key
, crypto
->keysize
))) {
1022 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
1026 rc
= iterate_crypto_once(client
, crypto
, STATUS_ENCRYPT
);
1031 if (iter_progress
&& crypto
->fh
->ver
.fh2
.iter
>= iter_progress
) {
1032 rc
= send_status(client
? client
->ctx
: NULL
, STATUS_ENCRYPT
,
1033 "%llu %llu", crypto
->fh
->ver
.fh2
.iter
, crypto
->fh
->ver
.fh2
.iter
);
1043 if (!client
&& !g_ascii_strcasecmp(filename
, "-")) {
1044 crypto
->fh
->fd
= STDOUT_FILENO
;
1048 if (lstat(filename
, &st
) == 0) {
1049 mode
= st
.st_mode
& (S_IRWXU
|S_IRWXG
|S_IRWXO
);
1051 if (!(mode
& S_IWUSR
))
1052 return gpg_error_from_errno(EACCES
);
1054 else if (errno
!= ENOENT
)
1055 return gpg_error_from_errno(errno
);
1057 g_snprintf(tmp
, sizeof(tmp
), "%s.XXXXXX", filename
);
1058 crypto
->fh
->fd
= mkstemp(tmp
);
1060 if (crypto
->fh
->fd
== -1) {
1062 p
= strrchr(tmp
, '/');
1064 log_write("%s: %s", p
, strerror(rc
));
1065 return gpg_error_from_errno(rc
);
1068 pth_cleanup_push(cleanup_unlink_cb
, tmp
);
1072 * xml_import() or convert_file() from command line.
1074 crypto
->fh
->fd
= STDOUT_FILENO
;
1077 crypto
->fh
->ver
.fh2
.magic
[0] = '\177';
1078 crypto
->fh
->ver
.fh2
.magic
[1] = 'P';
1079 crypto
->fh
->ver
.fh2
.magic
[2] = 'W';
1080 crypto
->fh
->ver
.fh2
.magic
[3] = 'M';
1081 crypto
->fh
->ver
.fh2
.magic
[4] = 'D';
1082 crypto
->fh
->ver
.fh2
.version
= VERSION_HEX
;
1083 len
= pth_write(crypto
->fh
->fd
, &crypto
->fh
->ver
.fh2
, sizeof(crypto
->fh
->ver
.fh2
));
1085 if (len
!= sizeof(crypto
->fh
->ver
.fh2
)) {
1091 return gpg_error_from_errno(len
);
1094 len
= pth_write(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
1096 if (len
!= crypto
->insize
) {
1102 return gpg_error_from_errno(len
);
1105 if (fsync(crypto
->fh
->fd
) == -1) {
1111 return gpg_error_from_errno(len
);
1118 if (mode
&& get_key_file_boolean(filename
, "backup") == TRUE
) {
1119 gchar tmp2
[FILENAME_MAX
];
1121 g_snprintf(tmp2
, sizeof(tmp2
), "%s.backup", filename
);
1123 acl
= acl_get_file(filename
, ACL_TYPE_ACCESS
);
1126 log_write("ACL: %s: %s", filename
, strerror(errno
));
1129 if (rename(filename
, tmp2
) == -1) {
1136 return gpg_error_from_errno(len
);
1141 acl
= acl_get_file(".", ACL_TYPE_DEFAULT
);
1144 log_write("ACL: %s: %s", filename
, strerror(errno
));
1148 if (rename(tmp
, filename
) == -1) {
1155 return gpg_error_from_errno(len
);
1161 chmod(filename
, mode
);
1164 if (acl
&& acl_set_file(filename
, ACL_TYPE_ACCESS
, acl
))
1165 log_write("ACL: %s: %s", filename
, strerror(errno
));
1172 if (client
&& lstat(filename
, &st
) == 0)
1173 client
->mtime
= st
.st_mtime
;
1178 gpg_error_t
update_save_flags(const gchar
*filename
,
1179 struct client_crypto_s
*crypto
)
1186 crypto
->fh
= g_malloc0(sizeof(file_header_internal_t
));
1189 return GPG_ERR_ENOMEM
;
1192 rc
= init_client_crypto2(filename
, crypto
);
1197 if (filename
&& !crypto
->fh
->v1
) {
1198 iter
= (guint64
)get_key_file_double(filename
, "iterations");
1199 crypto
->fh
->ver
.fh2
.iter
= iter
< 0L ? 0UL : iter
;
1205 static gpg_error_t
save_command_finalize(assuan_context_t ctx
, guchar
*key
,
1208 struct client_s
*client
= assuan_get_pointer(ctx
);
1218 if (client
->crypto
->key
&& client
->crypto
->key
!= key
)
1219 gcry_free(client
->crypto
->key
);
1221 client
->crypto
->key
= key
;
1222 rc
= update_timestamp(client
->doc
);
1225 return send_error(ctx
, rc
);
1227 xmlDocDumpFormatMemory(client
->doc
, (xmlChar
**)&xmlbuf
, (gint
*)&len
, 0);
1228 pth_cleanup_push(xmlFree
, xmlbuf
);
1229 clevel
= get_key_file_integer(client
->filename
, "compression_level");
1234 if (do_compress(ctx
, clevel
, xmlbuf
, len
, &outbuf
, &outsize
, &zrc
) == FALSE
) {
1236 cleanup_crypto(&client
->crypto
);
1238 if (zrc
== Z_MEM_ERROR
)
1239 return send_syserror(ctx
, ENOMEM
);
1241 return send_error(ctx
, GPG_ERR_COMPR_ALGO
);
1249 client
->crypto
->inbuf
= xmlbuf
;
1250 client
->crypto
->insize
= len
;
1251 rc
= update_save_flags(client
->filename
, client
->crypto
);
1254 cleanup_crypto(&client
->crypto
);
1255 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
1256 return send_error(ctx
, rc
);
1259 rc
= do_xml_encrypt(client
, client
->crypto
, client
->filename
);
1262 cleanup_crypto(&client
->crypto
);
1263 return send_error(ctx
, rc
);
1266 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
1267 CACHE_LOCK(client
->ctx
);
1270 cache_reset_timeout(client
->md5file
, timeout
);
1273 if (client
->new == TRUE
)
1274 send_status_all(STATUS_CACHE
);
1276 client
->new = FALSE
;
1277 cleanup_crypto(&client
->crypto
);
1278 return send_error(ctx
, 0);
1281 if (cache_update_key(client
->md5file
, client
->crypto
->key
) == FALSE
) {
1283 cleanup_crypto(&client
->crypto
);
1284 return send_syserror(ctx
, ENOMEM
);
1287 client
->new = FALSE
;
1288 cache_reset_timeout(client
->md5file
, timeout
);
1290 send_status_all(STATUS_CACHE
);
1291 cleanup_crypto(&client
->crypto
);
1292 return send_error(ctx
, 0);
1295 static gpg_error_t
save_command(assuan_context_t ctx
, gchar
*line
)
1297 gboolean cached
= FALSE
;
1299 struct client_s
*client
= assuan_get_pointer(ctx
);
1300 guint hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
1303 rc
= command_startup(ctx
);
1306 return send_error(ctx
, rc
);
1309 log_write2("ARGS=%s", "<passphrase>");
1311 if (lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
1312 return send_syserror(ctx
, errno
);
1314 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
1315 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
1316 return send_error(ctx
, GPG_ERR_ENOANO
);
1320 cached
= cache_iscached(client
->md5file
);
1324 * If a cache entry doesn't exist for this file and the file has a
1325 * "key_file" or "key" parameter, then it's an error. The reason is that
1326 * cache expiration would be useless.
1328 if (cached
== FALSE
) {
1329 gchar
*tmp
= get_key_file_string(client
->filename
, "key_file");
1333 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
1340 if (!client
->crypto
) {
1341 client
->crypto
= init_client_crypto();
1343 if (!client
->crypto
) {
1344 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1345 return send_syserror(ctx
, ENOMEM
);
1349 client
->crypto
->key
= gcry_malloc(hashlen
);
1351 if (!client
->crypto
->key
) {
1352 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1353 cleanup_crypto(&client
->crypto
);
1354 return send_syserror(ctx
, ENOMEM
);
1357 memset(client
->crypto
->key
, '!', hashlen
);
1359 if (get_key_file_double(client
->filename
, "iterations") <= 0L)
1362 if (!line
|| !*line
) {
1363 client
->crypto
->tkey
= gcry_malloc(hashlen
);
1365 if (!client
->crypto
->tkey
) {
1366 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1367 cleanup_crypto(&client
->crypto
);
1368 return send_syserror(ctx
, ENOMEM
);
1371 memset(client
->crypto
->tkey
, '!', hashlen
);
1374 if (cache_get_key(client
->md5file
, client
->crypto
->key
) == FALSE
||
1375 !memcmp(client
->crypto
->key
, client
->crypto
->tkey
, hashlen
)) {
1378 #ifdef WITH_PINENTRY
1381 if (client
->pinentry
->enable
== FALSE
||
1382 get_key_file_boolean(client
->filename
, "enable_pinentry") == FALSE
) {
1383 /* Empty keys are allowed. */
1384 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1388 lock_pin_mutex(client
);
1389 client
->pinentry
->which
= PINENTRY_SAVE
;
1390 rc
= pinentry_fork(ctx
);
1393 unlock_pin_mutex(client
->pinentry
);
1394 return send_error(ctx
, rc
);
1397 client
->pinentry
->cb
= save_command_finalize
;
1398 client
->pinentry
->status
= PINENTRY_INIT
;
1401 /* Empty keys are allowed. */
1402 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, "", 1);
1412 gcry_md_hash_buffer(GCRY_MD_SHA256
, client
->crypto
->key
, line
,
1416 return save_command_finalize(ctx
, client
->crypto
->key
, cached
);
1419 static gpg_error_t
delete_command(assuan_context_t ctx
, gchar
*line
)
1421 struct client_s
*client
= assuan_get_pointer(ctx
);
1426 rc
= command_startup(ctx
);
1429 return send_error(ctx
, rc
);
1431 log_write2("ARGS=\"%s\"", line
);
1433 if (strchr(line
, '\t'))
1434 req
= split_input_line(line
, "\t", -1);
1436 req
= split_input_line(line
, " ", -1);
1439 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1441 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1445 return send_error(ctx
, rc
);
1449 * No sub-node defined. Remove the entire node (account).
1458 return send_error(ctx
, 0);
1461 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1465 return send_error(ctx
, rc
);
1472 return send_error(ctx
, 0);
1476 * Don't return with assuan_process_done() here. This has been called from
1477 * assuan_process_next() and the command should be finished in
1480 static gpg_error_t
store_command_finalize(gpointer data
, gpg_error_t assuan_rc
,
1481 guchar
*line
, gsize len
)
1483 assuan_context_t ctx
= data
;
1484 struct client_s
*client
= assuan_get_pointer(ctx
);
1487 gpg_error_t rc
= file_modified(client
);
1489 if (assuan_rc
|| rc
) {
1492 return assuan_rc
? assuan_rc
: rc
;
1495 req
= split_input_line((gchar
*)line
, "\t", 0);
1499 return EPWMD_COMMAND_SYNTAX
;
1502 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1504 if (rc
&& rc
== EPWMD_ELEMENT_NOT_FOUND
) {
1505 rc
= new_account(client
->doc
, *req
);
1522 create_elements_cb(n
, req
+1, &rc
, NULL
);
1524 find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1525 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
);
1529 client
->inquire_status
= INQUIRE_DONE
;
1533 static gpg_error_t
store_command(assuan_context_t ctx
, gchar
*line
)
1535 struct client_s
*client
= assuan_get_pointer(ctx
);
1538 rc
= command_startup(ctx
);
1541 return send_error(ctx
, rc
);
1543 rc
= assuan_inquire_ext(ctx
, "STORE", 0, store_command_finalize
, ctx
);
1546 return send_error(ctx
, rc
);
1548 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1549 client
->inquire_status
= INQUIRE_BUSY
;
1553 static void *send_data_cb(void *arg
)
1555 struct assuan_cmd_s
*data
= arg
;
1559 pth_cancel_state(PTH_CANCEL_ENABLE
|PTH_CANCEL_ASYNCHRONOUS
, &old
);
1560 rc
= assuan_send_data(data
->ctx
, data
->line
, data
->line_len
);
1561 pth_cancel_state(old
, NULL
);
1562 pth_exit((void *)rc
);
1566 /* For every assuan command that needs to be sent to the client, a timeout is
1567 * needed to determine if the client lost the connection. The timeout is the
1568 * same as the "keepalive" configuration parameter or a default if unset.
1570 gpg_error_t
do_assuan_command(assuan_context_t ctx
,
1571 void *(*cb
)(void *data
), void *data
)
1573 pth_attr_t attr
= pth_attr_new();
1576 gint to
= get_key_file_integer("global", "keepalive");
1577 pth_event_t ev
, tev
;
1581 pth_attr_init(attr
);
1582 pth_attr_set(attr
, PTH_ATTR_JOINABLE
, TRUE
);
1583 tid
= pth_spawn(attr
, cb
, data
);
1585 pth_attr_destroy(attr
);
1588 log_write("%s(%i): pth_spawn(): %s", __FILE__
, __LINE__
,
1589 _gpg_strerror(gpg_error_from_errno(n
)));
1590 return gpg_error_from_errno(n
);
1593 pth_cleanup_push(cleanup_cancel_cb
, tid
);
1594 to
= to
<= 0 ? DEFAULT_KEEPALIVE_TO
: to
;
1595 ev
= pth_event(PTH_EVENT_TID
|PTH_UNTIL_TID_DEAD
, tid
);
1596 tev
= pth_event(PTH_EVENT_TIME
, pth_timeout(to
, 0));
1597 ev
= pth_event_concat(ev
, tev
, NULL
);
1598 pth_cleanup_push(cleanup_ev_cb
, ev
);
1601 st
= pth_event_status(ev
);
1603 if (st
== PTH_STATUS_FAILED
) {
1605 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1607 else if (st
== PTH_STATUS_OCCURRED
)
1608 pth_join(tid
, (void **)&rc
);
1610 st
= pth_event_status(tev
);
1612 if (st
== PTH_STATUS_OCCURRED
) {
1614 rc
= GPG_ERR_ASS_WRITE_ERROR
;
1623 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
1629 struct assuan_cmd_s data
;
1630 gint progress
= get_key_file_integer("global", "xfer_progress");
1633 progress
= progress
>0 ? (progress
/ASSUAN_LINELENGTH
)*ASSUAN_LINELENGTH
: 0;
1634 to_send
= total
< ASSUAN_LINELENGTH
? total
: ASSUAN_LINELENGTH
;
1636 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1643 if (sent
+ to_send
> total
)
1644 to_send
= total
- sent
;
1646 data
.line
= flush
? NULL
: (gchar
*)line
+sent
;
1647 data
.line_len
= flush
? 0 : to_send
;
1648 rc
= do_assuan_command(ctx
, send_data_cb
, &data
);
1651 sent
+= flush
? 0 : to_send
;
1653 if ((progress
&& !(sent
% progress
) && sent
!= total
) ||
1654 (sent
== total
&& flush
))
1655 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
1657 if (!flush
&& !rc
&& sent
== total
) {
1662 } while (!rc
&& sent
< total
);
1667 static gpg_error_t
get_command(assuan_context_t ctx
, gchar
*line
)
1669 struct client_s
*client
= assuan_get_pointer(ctx
);
1674 rc
= command_startup(ctx
);
1677 return send_error(ctx
, rc
);
1679 log_write2("ARGS=\"%s\"", line
);
1680 req
= split_input_line(line
, "\t", -1);
1682 if (!req
|| !*req
) {
1684 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1687 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1691 return send_error(ctx
, rc
);
1695 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1700 return send_error(ctx
, rc
);
1702 if (!n
|| !n
->children
)
1703 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1705 n
= find_text_node(n
->children
);
1707 if (!n
|| !n
->content
|| !*n
->content
)
1708 return send_error(ctx
, EPWMD_EMPTY_ELEMENT
);
1710 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
1711 return send_error(ctx
, rc
);
1714 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
1715 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
1717 gchar
*path
= *(gchar
**)data
;
1718 gchar
*tmp
= NULL
, *result
;
1722 *(gchar
**)data
= NULL
;
1725 path
= g_strjoinv("\t", target
);
1728 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1729 *rc
= gpg_error_from_errno(ENOMEM
);
1734 tmp
= g_strjoinv("\t", req_orig
);
1738 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1739 *rc
= gpg_error_from_errno(ENOMEM
);
1745 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1747 result
= g_strdup(path
);
1750 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1751 *rc
= gpg_error_from_errno(ENOMEM
);
1759 *(gchar
**)data
= result
;
1763 static void list_command_cleanup1(void *arg
);
1764 static gpg_error_t
realpath_command(assuan_context_t ctx
, gchar
*line
)
1767 struct client_s
*client
= assuan_get_pointer(ctx
);
1775 rc
= command_startup(ctx
);
1778 return send_error(ctx
, rc
);
1780 log_write2("ARGS=\"%s\"", line
);
1782 if (strchr(line
, '\t') != NULL
) {
1783 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1784 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1787 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1788 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
1791 n
= find_account(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1795 return send_error(ctx
, rc
);
1798 rp
= g_strjoinv("\t", req
);
1802 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1803 return send_syserror(ctx
, ENOMEM
);
1807 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1808 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
);
1813 return send_error(ctx
, rc
);
1817 string
= g_string_new(rp
);
1822 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1823 return send_syserror(ctx
, ENOMEM
);
1827 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
1828 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
1829 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1834 pth_cleanup_push(list_command_cleanup1
, string
);
1835 rc
= xfer_data(ctx
, string
->str
, string
->len
);
1837 return send_error(ctx
, rc
);
1840 static void list_command_cleanup1(void *arg
)
1842 g_string_free((GString
*)arg
, TRUE
);
1845 static void list_command_cleanup2(void *arg
)
1847 struct element_list_s
*elements
= arg
;
1850 gint total
= g_slist_length(elements
->list
);
1853 for (i
= 0; i
< total
; i
++) {
1854 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
1858 g_slist_free(elements
->list
);
1860 if (elements
->prefix
)
1861 g_free(elements
->prefix
);
1867 static gpg_error_t
list_command(assuan_context_t ctx
, gchar
*line
)
1869 struct client_s
*client
= assuan_get_pointer(ctx
);
1871 struct element_list_s
*elements
= NULL
;
1874 rc
= command_startup(ctx
);
1877 return send_error(ctx
, rc
);
1879 if (disable_list_and_dump
== TRUE
)
1880 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1882 log_write2("ARGS=\"%s\"", line
);
1887 rc
= list_accounts(client
->doc
, &str
);
1890 return send_error(ctx
, rc
);
1892 pth_cleanup_push(list_command_cleanup1
, str
);
1893 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1895 return send_error(ctx
, rc
);
1898 elements
= g_malloc0(sizeof(struct element_list_s
));
1901 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1902 rc
= gpg_err_code_from_errno(ENOMEM
);
1906 pth_cleanup_push(list_command_cleanup2
, elements
);
1907 rc
= create_path_list(client
->doc
, elements
, line
);
1913 gint total
= g_slist_length(elements
->list
);
1918 rc
= EPWMD_EMPTY_ELEMENT
;
1922 str
= g_string_new(NULL
);
1925 rc
= gpg_err_code_from_errno(ENOMEM
);
1926 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1930 for (i
= 0; i
< total
; i
++) {
1931 tmp
= g_slist_nth_data(elements
->list
, i
);
1932 g_string_append_printf(str
, "%s%s", tmp
, i
+1 == total
? "" : "\n");
1935 pth_cleanup_push(list_command_cleanup1
, str
);
1936 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1940 rc
= EPWMD_EMPTY_ELEMENT
;
1944 return send_error(ctx
, rc
);
1948 * req[0] - element path
1950 static gint
attribute_list(assuan_context_t ctx
, gchar
**req
)
1952 struct client_s
*client
= assuan_get_pointer(ctx
);
1953 gchar
**attrlist
= NULL
;
1955 gchar
**path
= NULL
;
1961 if (!req
|| !req
[0])
1962 return EPWMD_COMMAND_SYNTAX
;
1964 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1966 * The first argument may be only an account.
1968 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1969 return EPWMD_COMMAND_SYNTAX
;
1972 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
1980 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1981 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
1991 for (a
= n
->properties
; a
; a
= a
->next
) {
1994 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1996 g_strfreev(attrlist
);
1998 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
1999 return gpg_error_from_errno(ENOMEM
);
2004 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
, (gchar
*)an
->content
);
2007 g_strfreev(attrlist
);
2008 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2009 return gpg_error_from_errno(ENOMEM
);
2012 attrlist
[++i
] = NULL
;
2016 return EPWMD_EMPTY_ELEMENT
;
2018 line
= g_strjoinv("\n", attrlist
);
2021 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2022 g_strfreev(attrlist
);
2023 return gpg_error_from_errno(ENOMEM
);
2026 pth_cleanup_push(g_free
, line
);
2027 pth_cleanup_push(req_cleanup
, attrlist
);
2028 rc
= xfer_data(ctx
, line
, strlen(line
));
2035 * req[0] - attribute
2036 * req[1] - element path
2038 static gint
attribute_delete(struct client_s
*client
, gchar
**req
)
2042 gchar
**path
= NULL
;
2045 if (!req
|| !req
[0] || !req
[1])
2046 return EPWMD_COMMAND_SYNTAX
;
2048 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2050 * The first argument may be only an account.
2052 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2053 return EPWMD_COMMAND_SYNTAX
;
2057 * Don't remove the "name" attribute for the account element. To remove an
2058 * account use DELETE <account>.
2060 if (!path
[1] && xmlStrEqual((xmlChar
*)req
[0], (xmlChar
*)"name")) {
2061 rc
= EPWMD_ATTR_SYNTAX
;
2065 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2071 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2072 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2080 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
)
2081 return EPWMD_ATTR_NOT_FOUND
;
2083 if (xmlRemoveProp(a
) == -1)
2084 return EPWMD_LIBXML_ERROR
;
2093 static xmlNodePtr
create_element_path(struct client_s
*client
, gchar
***path
,
2096 gchar
**src
= *path
;
2097 gchar
**src_orig
= g_strdupv(src
);
2098 xmlNodePtr n
= NULL
;
2103 *rc
= gpg_error_from_errno(ENOMEM
);
2104 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2109 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2112 if (*rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2113 *rc
= new_account(client
->doc
, src
[0]);
2126 n
= create_target_elements_cb(n
, src
+1, rc
, NULL
);
2128 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2129 NULL
, NULL
, create_target_elements_cb
, FALSE
, 0, NULL
);
2135 * Reset the position of the element tree now that the elements
2136 * have been created.
2141 n
= find_account(client
->doc
, &src
, rc
, NULL
, 0, FALSE
);
2146 n
= find_elements(client
->doc
, n
->children
, src
+1, rc
,
2147 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2155 g_strfreev(src_orig
);
2162 * Creates a "target" attribute. When other commands encounter an element with
2163 * this attribute, the element path is modified to the target value. If the
2164 * source element path doesn't exist when using 'ATTR SET target', it is
2165 * created, but the destination element path must exist.
2167 * req[0] - source element path
2168 * req[1] - destination element path
2170 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
2172 gchar
**src
, **dst
, *line
= NULL
, **odst
= NULL
;
2176 if (!req
|| !req
[0] || !req
[1])
2177 return EPWMD_COMMAND_SYNTAX
;
2179 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
2181 * The first argument may be only an account.
2183 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
2184 return EPWMD_COMMAND_SYNTAX
;
2187 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2189 * The first argument may be only an account.
2191 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
2192 rc
= EPWMD_COMMAND_SYNTAX
;
2197 odst
= g_strdupv(dst
);
2200 rc
= gpg_error_from_errno(ENOMEM
);
2204 n
= find_account(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
2207 * Make sure the destination element path exists.
2213 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
2214 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2220 n
= create_element_path(client
, &src
, &rc
);
2225 line
= g_strjoinv("\t", odst
);
2228 rc
= gpg_error_from_errno(ENOMEM
);
2229 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2233 rc
= add_attribute(n
, "target", line
);
2244 * req[0] - account name
2247 static gpg_error_t
name_attribute(struct client_s
*client
, gchar
**req
)
2253 tmp
= g_strdupv(req
);
2256 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2257 return gpg_error_from_errno(ENOMEM
);
2260 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2266 if (g_utf8_collate(req
[0], req
[1]) == 0)
2270 * Will not overwrite an existing account.
2272 tmp
= g_strdupv(req
+1);
2275 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2276 return gpg_error_from_errno(ENOMEM
);
2279 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2282 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
2286 return EPWMD_ACCOUNT_EXISTS
;
2289 * Whitespace not allowed in account names.
2291 if (contains_whitespace(req
[1]) == TRUE
)
2292 return EPWMD_ATTR_SYNTAX
;
2294 tmp
= g_strdupv(req
);
2297 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2298 return gpg_error_from_errno(ENOMEM
);
2301 n
= find_account(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2305 return EPWMD_ELEMENT_NOT_FOUND
;
2307 return add_attribute(n
, "name", req
[1]);
2311 * req[0] - attribute
2312 * req[1] - element path
2314 static gint
attribute_get(assuan_context_t ctx
, gchar
**req
)
2316 struct client_s
*client
= assuan_get_pointer(ctx
);
2322 if (!req
|| !req
[0] || !req
[1])
2323 return EPWMD_COMMAND_SYNTAX
;
2325 if (strchr(req
[1], '\t')) {
2326 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
2327 return EPWMD_COMMAND_SYNTAX
;
2330 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2331 return EPWMD_COMMAND_SYNTAX
;
2334 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2340 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2341 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2349 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
2350 return EPWMD_ATTR_NOT_FOUND
;
2352 pth_cleanup_push(xmlFree
, a
);
2353 rc
= xfer_data(ctx
, (gchar
*)a
, xmlStrlen(a
));
2363 * req[0] - attribute
2364 * req[1] - element path
2367 static gint
attribute_set(struct client_s
*client
, gchar
**req
)
2369 gchar
**path
= NULL
;
2373 if (!req
|| !req
[0] || !req
[1] || !req
[2])
2374 return EPWMD_COMMAND_SYNTAX
;
2377 * Reserved attribute names.
2379 if (g_utf8_collate(req
[0], "name") == 0) {
2381 * Only reserved for the account element. Not the rest of the
2384 if (strchr(req
[1], '\t') == NULL
)
2385 return name_attribute(client
, req
+ 1);
2387 else if (g_utf8_collate(req
[0], "target") == 0)
2388 return target_attribute(client
, req
+ 1);
2390 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
2392 * The first argument may be only an account.
2394 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
2395 return EPWMD_COMMAND_SYNTAX
;
2398 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2404 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
2405 NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2412 return add_attribute(n
, req
[0], req
[2]);
2421 * req[1] - attribute name or element path if command is LIST
2422 * req[2] - element path
2423 * req[2] - element path or value
2425 static gpg_error_t
attr_command(assuan_context_t ctx
, gchar
*line
)
2427 struct client_s
*client
= assuan_get_pointer(ctx
);
2431 rc
= command_startup(ctx
);
2434 return send_error(ctx
, rc
);
2436 log_write2("ARGS=\"%s\"", line
);
2437 req
= split_input_line(line
, " ", 4);
2439 if (!req
|| !req
[0] || !req
[1]) {
2441 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2444 pth_cleanup_push(req_cleanup
, req
);
2446 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
2447 rc
= attribute_set(client
, req
+1);
2448 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
2449 rc
= attribute_get(ctx
, req
+1);
2450 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
2451 rc
= attribute_delete(client
, req
+1);
2452 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
2453 rc
= attribute_list(ctx
, req
+1);
2455 rc
= EPWMD_COMMAND_SYNTAX
;
2458 return send_error(ctx
, rc
);
2461 static gpg_error_t
iscached_command(assuan_context_t ctx
, gchar
*line
)
2463 gpg_error_t rc
= command_startup(ctx
);
2466 return send_error(ctx
, rc
);
2468 gchar
**req
= split_input_line(line
, " ", 0);
2472 if (!req
|| !*req
) {
2474 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2477 log_write2("ARGS=\"%s\"", line
);
2479 if (!valid_filename(req
[0])) {
2481 return EPWMD_INVALID_FILENAME
;
2484 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2487 if (cache_iscached(md5file
)) {
2490 return send_error(ctx
, 0);
2494 tmp
= get_key_file_string("global", "data_directory");
2498 return gpg_error_from_errno(ENOMEM
);
2501 path
= expand_homedir(tmp
);
2506 return gpg_error_from_errno(ENOMEM
);
2511 path
= g_strdup_printf("%s/%s", tmp
, req
[0]);
2516 return gpg_error_from_errno(ENOMEM
);
2519 if (access(path
, R_OK
) == -1) {
2520 gpg_error_t rc
= gpg_error_from_syserror();
2524 return send_error(ctx
, rc
);
2528 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2531 static gpg_error_t
clearcache_command(assuan_context_t ctx
, gchar
*line
)
2533 gpg_error_t rc
= command_startup(ctx
);
2536 return send_error(ctx
, rc
);
2538 struct client_s
*client
= assuan_get_pointer(ctx
);
2539 gchar
**req
= split_input_line(line
, " ", 0);
2542 log_write2("ARGS=\"%s\"", line
);
2545 if (!req
|| !*req
) {
2547 cache_clear(client
->md5file
, 2);
2549 return send_error(ctx
, 0);
2552 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2555 if (cache_clear(md5file
, 1) == FALSE
) {
2557 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2561 return send_error(ctx
, 0);
2564 static gpg_error_t
cachetimeout_command(assuan_context_t ctx
, gchar
*line
)
2566 gpg_error_t rc
= command_startup(ctx
);
2569 return send_error(ctx
, rc
);
2573 gchar
**req
= split_input_line(line
, " ", 0);
2576 if (!req
|| !*req
|| !req
[1]) {
2578 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2582 timeout
= strtol(req
[1], &p
, 10);
2584 if (errno
!= 0 || *p
!= 0 || timeout
< -1) {
2586 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2589 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
2590 CACHE_LOCK(client
->ctx
);
2592 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2594 return send_error(ctx
, EPWMD_CACHE_NOT_FOUND
);
2598 return send_error(ctx
, 0);
2601 static gpg_error_t
dump_command(assuan_context_t ctx
, gchar
*line
)
2605 struct client_s
*client
= assuan_get_pointer(ctx
);
2608 rc
= command_startup(ctx
);
2611 return send_error(ctx
, rc
);
2613 if (disable_list_and_dump
== TRUE
)
2614 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2616 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2619 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2620 return send_syserror(ctx
, ENOMEM
);
2623 pth_cleanup_push(xmlFree
, xml
);
2624 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
2626 return send_error(ctx
, rc
);
2629 static gpg_error_t
getconfig_command(assuan_context_t ctx
, gchar
*line
)
2631 struct client_s
*client
= assuan_get_pointer(ctx
);
2633 gchar filename
[255]={0}, param
[747]={0};
2634 gchar
*p
, *tmp
, *fp
= client
->filename
, *paramp
= line
;
2636 rc
= command_startup(ctx
);
2639 return send_error(ctx
, rc
);
2641 log_write2("ARGS=\"%s\"", line
);
2643 if (strchr(line
, ' ')) {
2644 sscanf(line
, " %254[^ ] %746c", filename
, param
);
2649 if (fp
&& !valid_filename(fp
))
2650 return send_error(ctx
, EPWMD_INVALID_FILENAME
);
2652 paramp
= g_ascii_strdown(paramp
, -1);
2655 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2656 return send_syserror(ctx
, ENOMEM
);
2659 if (fp
&& !g_ascii_strcasecmp(paramp
, "iterations")) {
2660 if (!(client
->opts
& OPT_ITERATIONS
) || fp
!= client
->filename
) {
2661 file_header_internal_t
*fh
= read_file_header(fp
, FALSE
, &rc
);
2663 if (!fh
&& rc
!= GPG_ERR_ENOENT
)
2664 return send_error(ctx
, rc
);
2668 p
= g_strdup_printf("%lu", (unsigned long)fh
->ver
.fh2
.iter
);
2669 close_file_header(fh
);
2672 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2674 return send_syserror(ctx
, ENOMEM
);
2681 else if (!g_ascii_strcasecmp(paramp
, "enable_pinentry")) {
2682 #ifdef WITH_PINENTRY
2685 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY
))
2686 n
= client
->pinentry
->enable
;
2688 n
= get_key_file_boolean(fp
, "enable_pinentry");
2690 p
= g_strdup_printf("%s", n
? "true" : "false");
2693 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2695 return send_syserror(ctx
, ENOMEM
);
2700 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2703 else if (!g_ascii_strcasecmp(paramp
, "pinentry_timeout")) {
2704 #ifdef WITH_PINENTRY
2705 if (fp
== client
->filename
&& (client
->opts
& OPT_PINENTRY_TO
))
2706 p
= g_strdup_printf("%i", client
->pinentry
->timeout
);
2708 p
= g_strdup_printf("%i",
2709 get_key_file_integer(fp
, "pinentry_timeout"));
2712 log_write("%s(%i): %s", __FILE__
, __LINE__
,
2714 return send_syserror(ctx
, ENOMEM
);
2719 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2723 p
= get_key_file_string(fp
? fp
: "global", paramp
);
2727 return send_error(ctx
, GPG_ERR_NO_VALUE
);
2729 tmp
= expand_homedir(p
);
2733 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2734 return send_syserror(ctx
, ENOMEM
);
2739 pth_cleanup_push(g_free
, p
);
2740 rc
= xfer_data(ctx
, p
, strlen(p
));
2742 return send_error(ctx
, rc
);
2746 xmlXPathContextPtr xp
;
2747 xmlXPathObjectPtr result
;
2752 static void xpath_command_cleanup(void *arg
)
2754 struct xpath_s
*xpath
= arg
;
2756 req_cleanup(xpath
->req
);
2759 xmlBufferFree(xpath
->buf
);
2762 xmlXPathFreeObject(xpath
->result
);
2765 xmlXPathFreeContext(xpath
->xp
);
2768 static gpg_error_t
xpath_command(assuan_context_t ctx
, gchar
*line
)
2770 struct client_s
*client
= assuan_get_pointer(ctx
);
2772 struct xpath_s xpath
;
2773 rc
= command_startup(ctx
);
2776 return send_error(ctx
, rc
);
2779 log_write2("ARGS=\"%s\"", line
);
2781 if (disable_list_and_dump
== TRUE
)
2782 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2784 if (!line
|| !*line
)
2785 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
2787 memset(&xpath
, 0, sizeof(struct xpath_s
));
2789 if ((xpath
.req
= split_input_line(line
, "\t", 2)) == NULL
) {
2790 if (strv_printf(&xpath
.req
, "%s", line
) == FALSE
)
2791 return send_syserror(ctx
, ENOMEM
);
2794 xpath
.xp
= xmlXPathNewContext(client
->doc
);
2797 xpath_command_cleanup(&xpath
);
2798 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2801 xpath
.result
= xmlXPathEvalExpression((xmlChar
*)xpath
.req
[0], xpath
.xp
);
2803 if (!xpath
.result
) {
2804 xpath_command_cleanup(&xpath
);
2805 return send_error(ctx
, EPWMD_LIBXML_ERROR
);
2808 if (xmlXPathNodeSetIsEmpty(xpath
.result
->nodesetval
)) {
2809 rc
= EPWMD_EMPTY_ELEMENT
;
2813 rc
= recurse_xpath_nodeset(client
->doc
, xpath
.result
->nodesetval
,
2814 (xmlChar
*)xpath
.req
[1], &xpath
.buf
);
2818 else if (!xpath
.req
[1] && !xmlBufferLength(xpath
.buf
)) {
2819 rc
= EPWMD_EMPTY_ELEMENT
;
2822 else if (xpath
.req
[1])
2825 pth_cleanup_push(xpath_command_cleanup
, &xpath
);
2826 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
.buf
),
2827 xmlBufferLength(xpath
.buf
));
2831 xpath_command_cleanup(&xpath
);
2832 return send_error(ctx
, rc
);
2835 static gpg_error_t
import_command_finalize(gpointer data
,
2836 gpg_error_t assuan_rc
, guchar
*line
, gsize len
)
2838 struct client_s
*client
= assuan_get_pointer((assuan_context_t
)data
);
2839 gpg_error_t rc
= file_modified(client
);
2840 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
2841 xmlDocPtr doc
= NULL
;
2842 xmlNodePtr n
, root
, copy
;
2844 if (assuan_rc
|| rc
) {
2847 return assuan_rc
? assuan_rc
: rc
;
2850 req
= split_input_line((gchar
*)line
, "\t", 2);
2854 return EPWMD_COMMAND_SYNTAX
;
2857 path
= split_input_line(req
[1], "\t", 0);
2859 if (!content
|| !*content
) {
2860 rc
= EPWMD_COMMAND_SYNTAX
;
2864 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2867 rc
= EPWMD_LIBXML_ERROR
;
2871 root
= xmlDocGetRootElement(doc
);
2874 path_orig
= g_strdupv(path
);
2877 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
2878 rc
= gpg_error_from_errno(ENOMEM
);
2882 if (strv_printf(&path
, "%s", (gchar
*)root
->name
) == FALSE
) {
2883 g_strfreev(path_orig
);
2884 rc
= gpg_error_from_errno(ENOMEM
);
2888 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2890 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2891 g_strfreev(path_orig
);
2896 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
);
2898 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2899 g_strfreev(path_orig
);
2903 xmlNodePtr parent
= n
->parent
;
2914 if (rc
== EPWMD_ELEMENT_NOT_FOUND
) {
2915 n
= create_element_path(client
, &path
, &rc
);
2921 copy
= xmlCopyNode(root
, 1);
2922 n
= xmlAddChild(n
, copy
);
2925 rc
= EPWMD_LIBXML_ERROR
;
2928 /* Check if the content root element can create a DTD root element. */
2929 if (xmlStrcmp((xmlChar
*)"root", root
->name
)) {
2930 rc
= EPWMD_COMMAND_SYNTAX
;
2936 if ((a
= xmlGetProp(root
, (xmlChar
*)"name")) == NULL
) {
2937 rc
= EPWMD_COMMAND_SYNTAX
;
2941 gchar
*tmp
= g_strdup((gchar
*)a
);
2943 gboolean literal
= is_literal_element(&tmp
);
2945 if (!valid_xml_element((xmlChar
*)tmp
) || literal
) {
2947 rc
= EPWMD_INVALID_ELEMENT
;
2951 if (strv_printf(&path
, "%s", tmp
) == FALSE
) {
2953 rc
= gpg_error_from_errno(ENOMEM
);
2958 n
= find_account(client
->doc
, &path
, &rc
, NULL
, 0, TRUE
);
2960 if (rc
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
) {
2961 rc
= EPWMD_LIBXML_ERROR
;
2965 /* Overwriting the existing tree. */
2972 xmlSetProp(root
, (xmlChar
*)"name", (xmlChar
*)path
[0]);
2973 n
= xmlCopyNode(root
, 1);
2974 n
= xmlAddChild(xmlDocGetRootElement(client
->doc
), n
);
2985 client
->inquire_status
= INQUIRE_DONE
;
2989 static gpg_error_t
import_command(assuan_context_t ctx
, gchar
*line
)
2992 struct client_s
*client
= assuan_get_pointer(ctx
);
2994 rc
= command_startup(ctx
);
2997 return send_error(ctx
, rc
);
2999 rc
= assuan_inquire_ext(ctx
, "IMPORT", 0, import_command_finalize
, ctx
);
3002 return send_error(ctx
, rc
);
3004 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3005 client
->inquire_status
= INQUIRE_BUSY
;
3009 static gpg_error_t
lock_command(assuan_context_t ctx
, gchar
*line
)
3012 struct client_s
*client
= assuan_get_pointer(ctx
);
3014 rc
= command_startup(ctx
);
3017 return send_error(ctx
, rc
);
3019 rc
= lock_file_mutex(client
);
3022 client
->is_lock_cmd
= TRUE
;
3024 return send_error(ctx
, rc
);
3027 static gpg_error_t
unlock_command(assuan_context_t ctx
, gchar
*line
)
3029 struct client_s
*client
= assuan_get_pointer(ctx
);
3031 gpg_error_t rc
= command_startup(ctx
);
3034 return send_error(ctx
, rc
);
3036 unlock_file_mutex(client
);
3037 return send_error(ctx
, 0);
3040 static gpg_error_t
getpid_command(assuan_context_t ctx
, gchar
*line
)
3044 pid_t pid
= getpid();
3046 rc
= command_startup(ctx
);
3049 return send_error(ctx
, rc
);
3051 print_fmt(buf
, sizeof(buf
), "%i", pid
);
3052 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3053 return send_error(ctx
, rc
);
3056 static gpg_error_t
version_command(assuan_context_t ctx
, gchar
*line
)
3061 rc
= command_startup(ctx
);
3064 return send_error(ctx
, rc
);
3066 print_fmt(buf
, sizeof(buf
), "0x%X", VERSION_HEX
);
3067 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3068 return send_error(ctx
, rc
);
3071 #ifdef WITH_PINENTRY
3072 static void set_option_value(gchar
**opt
, const gchar
*value
)
3080 *opt
= g_strdup(value
);
3084 static gint
set_unset_common(assuan_context_t ctx
, const gchar
*name
,
3087 struct client_s
*client
= assuan_get_pointer(ctx
);
3089 if (g_ascii_strcasecmp(name
, (gchar
*)"log_level") == 0) {
3093 l
= strtol(value
, NULL
, 10);
3096 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3099 log_write1("log_level=%li", l
);
3100 MUTEX_LOCK(&rcfile_mutex
);
3101 g_key_file_set_integer(keyfileh
, "global", "log_level", (gint
)l
);
3102 MUTEX_UNLOCK(&rcfile_mutex
);
3105 else if (g_ascii_strcasecmp(name
, (gchar
*)"cipher") == 0) {
3107 const gchar
*p
= value
;
3109 if (!client
->filename
)
3110 return EPWMD_NO_FILE
;
3113 flags
= pwmd_cipher_str_to_cipher(value
);
3116 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3119 p
= get_key_file_string("global", "cipher");
3121 MUTEX_LOCK(&rcfile_mutex
);
3122 g_key_file_set_string(keyfileh
, client
->filename
, "cipher", p
);
3123 MUTEX_UNLOCK(&rcfile_mutex
);
3124 log_write1("cipher=%s", p
);
3131 else if (g_ascii_strcasecmp(name
, (gchar
*)"iterations") == 0) {
3135 if (!client
->filename
)
3136 return EPWMD_NO_FILE
;
3139 MUTEX_LOCK(&rcfile_mutex
);
3140 g_key_file_set_double(keyfileh
, client
->filename
, "iterations",
3141 get_key_file_double("global", "iterations"));
3142 MUTEX_UNLOCK(&rcfile_mutex
);
3143 log_write1("iterations=%lu",
3144 (guint64
)get_key_file_double(client
->filename
, "iterations"));
3149 n
= strtoul(value
, &p
, 10);
3151 if (errno
|| (p
&& *p
) || n
== G_MAXULONG
)
3152 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3154 MUTEX_LOCK(&rcfile_mutex
);
3155 g_key_file_set_double(keyfileh
,
3156 client
->filename
? client
->filename
: "global", "iterations", n
);
3157 MUTEX_UNLOCK(&rcfile_mutex
);
3159 if (client
->filename
)
3160 client
->opts
|= OPT_ITERATIONS
;
3162 log_write1("iterations=%lu", n
);
3165 else if (g_ascii_strcasecmp(name
, (gchar
*)"NAME") == 0) {
3166 pth_attr_t attr
= pth_attr_of(pth_self());
3170 pth_attr_destroy(attr
);
3174 print_fmt(buf
, sizeof(buf
), "%s", value
);
3175 pth_attr_set(attr
, PTH_ATTR_NAME
, buf
);
3176 pth_attr_destroy(attr
);
3177 log_write1("name=%s", buf
);
3178 #ifdef WITH_PINENTRY
3179 if (client
->pinentry
->name
)
3180 g_free(client
->pinentry
->name
);
3182 client
->pinentry
->name
= g_strdup(buf
);
3184 if (!client
->pinentry
->name
)
3185 return gpg_error_from_errno(ENOMEM
);
3190 #ifdef WITH_PINENTRY
3191 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_messages") == 0)
3192 set_option_value(&client
->pinentry
->lcmessages
, value
);
3193 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc_ctype") == 0)
3194 set_option_value(&client
->pinentry
->lcctype
, value
);
3195 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0)
3196 set_option_value(&client
->pinentry
->ttyname
, value
);
3197 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0)
3198 set_option_value(&client
->pinentry
->ttytype
, value
);
3199 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0)
3200 set_option_value(&client
->pinentry
->display
, value
);
3201 else if (g_ascii_strcasecmp(name
, (gchar
*)"pinentry_path") == 0)
3202 set_option_value(&client
->pinentry
->path
, value
);
3203 else if (g_ascii_strcasecmp(name
, (gchar
*)"title") == 0)
3204 set_option_value(&client
->pinentry
->title
, value
);
3205 else if (g_ascii_strcasecmp(name
, (gchar
*)"prompt") == 0)
3206 set_option_value(&client
->pinentry
->prompt
, value
);
3207 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0)
3208 set_option_value(&client
->pinentry
->desc
, value
);
3209 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0) {
3214 client
->pinentry
->timeout
=
3215 get_key_file_integer(client
->filename
, "pinentry_timeout");
3216 client
->opts
&= ~(OPT_PINENTRY_TO
);
3217 log_write1("pinentry_timeout=%i",
3218 get_key_file_integer(client
->filename
, "pinentry_timeout"));
3222 n
= strtol(value
, &p
, 10);
3225 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3227 client
->pinentry
->timeout
= n
;
3228 client
->opts
|= OPT_PINENTRY_TO
;
3229 log_write1("pinentry_timeout=%i", n
);
3232 else if (g_ascii_strcasecmp(name
, "enable_pinentry") == 0) {
3237 client
->pinentry
->enable
= -1;
3238 client
->opts
&= ~(OPT_PINENTRY
);
3242 n
= strtol(value
, &p
, 10);
3244 if (*p
|| n
< 0 || n
> 1)
3245 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_INV_VALUE
);
3247 client
->pinentry
->enable
= n
== 0 ? FALSE
: TRUE
;
3248 client
->opts
|= OPT_PINENTRY
;
3249 log_write1("enable_pinentry=%i", n
);
3254 return gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_UNKNOWN_OPTION
);
3256 log_write1("%s=%s", name
, value
? value
: "");
3262 static gpg_error_t
unset_command(assuan_context_t ctx
, gchar
*line
)
3264 gpg_error_t rc
= command_startup(ctx
);
3267 return send_error(ctx
, rc
);
3269 log_write2("ARGS=\"%s\"", line
);
3270 return send_error(ctx
, set_unset_common(ctx
, line
, NULL
));
3273 static gpg_error_t
set_command(assuan_context_t ctx
, gchar
*line
)
3275 gchar name
[64] = {0}, value
[256] = {0};
3277 gpg_error_t rc
= command_startup(ctx
);
3280 return send_error(ctx
, rc
);
3282 log_write2("ARGS=\"%s\"", line
);
3284 if (sscanf(line
, " %63[_a-zA-Z] = %255c", name
, value
) != 2)
3285 return send_error(ctx
, gpg_err_make(PWMD_ERR_SOURCE
, GPG_ERR_SYNTAX
));
3287 return send_error(ctx
, set_unset_common(ctx
, name
, value
));
3290 static gpg_error_t
rename_command(assuan_context_t ctx
, gchar
*line
)
3292 struct client_s
*client
= assuan_get_pointer(ctx
);
3294 gchar
**req
, **src
, *dst
;
3297 rc
= command_startup(ctx
);
3300 return send_error(ctx
, rc
);
3302 log_write2("ARGS=\"%s\"", line
);
3303 req
= split_input_line(line
, " ", -1);
3305 if (!req
|| !req
[0] || !req
[1]) {
3307 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
3312 if (!valid_xml_element((xmlChar
*)dst
)) {
3314 return EPWMD_INVALID_ELEMENT
;
3317 if (strchr(req
[0], '\t'))
3318 src
= split_input_line(req
[0], "\t", -1);
3320 src
= split_input_line(req
[0], " ", -1);
3322 if (!src
|| !*src
) {
3323 rc
= EPWMD_COMMAND_SYNTAX
;
3327 n
= find_account(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3330 n
= find_elements(client
->doc
, n
->children
, src
+1, &rc
, NULL
, NULL
,
3331 NULL
, FALSE
, 0, NULL
);
3337 xmlNodeSetName(n
, (xmlChar
*)dst
);
3339 rc
= add_attribute(n
, "name", dst
);
3344 return send_error(ctx
, rc
);
3347 static gpg_error_t
copy_command(assuan_context_t ctx
, gchar
*line
)
3349 struct client_s
*client
= assuan_get_pointer(ctx
);
3351 gchar
**req
, **src
= NULL
, **dst
= NULL
;
3352 xmlNodePtr nsrc
, ndst
, new, n
;
3354 rc
= command_startup(ctx
);
3357 return send_error(ctx
, rc
);
3359 log_write2("ARGS=\"%s\"", line
);
3360 req
= split_input_line(line
, " ", -1);
3362 if (!req
|| !req
[0] || !req
[1]) {
3364 return send_error(ctx
, EPWMD_COMMAND_SYNTAX
);
3367 if (strchr(req
[0], '\t'))
3368 src
= split_input_line(req
[0], "\t", -1);
3370 src
= split_input_line(req
[0], " ", -1);
3372 if (!src
|| !*src
) {
3373 rc
= EPWMD_COMMAND_SYNTAX
;
3377 if (strchr(req
[1], '\t'))
3378 dst
= split_input_line(req
[1], "\t", -1);
3380 dst
= split_input_line(req
[1], " ", -1);
3382 if (!dst
|| !*dst
) {
3383 rc
= EPWMD_COMMAND_SYNTAX
;
3387 nsrc
= find_account(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
3390 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
3391 NULL
, NULL
, FALSE
, 0, NULL
);
3396 ndst
= find_account(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
3399 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
3400 NULL
, NULL
, FALSE
, 0, NULL
);
3402 if (!ndst
&& rc
!= EPWMD_ELEMENT_NOT_FOUND
)
3405 new = xmlCopyNodeList(nsrc
->children
);
3408 rc
= GPG_ERR_ENOMEM
;
3413 ndst
= create_element_path(client
, &dst
, &rc
);
3420 xmlUnlinkNode(ndst
->children
);
3422 xmlAddChild(ndst
, new);
3434 return send_error(ctx
, rc
);
3437 static gpg_error_t
bye_notify(assuan_context_t ctx
, gchar
*data
)
3439 struct client_s
*cl
= assuan_get_pointer(ctx
);
3441 /* This will let assuan_process_next() return. */
3442 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
3446 static gpg_error_t
reset_notify(assuan_context_t ctx
, gchar
*data
)
3448 struct client_s
*cl
= assuan_get_pointer(ctx
);
3457 * This is called after every Assuan command.
3459 void command_finalize(assuan_context_t ctx
, gpg_error_t rc
)
3461 struct client_s
*client
= assuan_get_pointer(ctx
);
3463 if (!client
->is_lock_cmd
)
3464 unlock_file_mutex(client
);
3466 log_write1(N_("command completed (rc=%u)"), client
->last_rc
);
3469 gpg_error_t
register_commands(assuan_context_t ctx
)
3473 gpg_error_t (*handler
)(assuan_context_t
, gchar
*line
);
3475 { "OPEN", open_command
},
3476 { "SAVE", save_command
},
3477 { "LIST", list_command
},
3478 { "REALPATH", realpath_command
},
3479 { "STORE", store_command
},
3480 { "DELETE", delete_command
},
3481 { "GET", get_command
},
3482 { "ATTR", attr_command
},
3483 { "ISCACHED", iscached_command
},
3484 { "CLEARCACHE", clearcache_command
},
3485 { "CACHETIMEOUT", cachetimeout_command
},
3486 { "GETCONFIG", getconfig_command
},
3487 { "DUMP", dump_command
},
3488 { "XPATH", xpath_command
},
3489 { "IMPORT", import_command
},
3490 { "LOCK", lock_command
},
3491 { "UNLOCK", unlock_command
},
3492 { "GETPID", getpid_command
},
3493 { "VERSION", version_command
},
3494 { "SET", set_command
},
3495 { "UNSET", unset_command
},
3496 { "RENAME", rename_command
},
3497 { "COPY", copy_command
},
3504 for (i
=0; table
[i
].name
; i
++) {
3505 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
, NULL
);
3511 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
3516 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
3521 return assuan_register_post_cmd_notify(ctx
, command_finalize
);
3524 gpg_error_t
try_xml_decrypt(assuan_context_t ctx
, guchar
*key
,
3525 struct client_crypto_s
*crypto
, gpointer
*dst
, goffset
*dst_len
)
3527 goffset insize
, len
;
3528 struct client_s
*client
= ctx
? assuan_get_pointer(ctx
) : NULL
;
3529 guint64 iter
= 0ULL, n_iter
= 0ULL, iter_progress
= 0ULL;
3533 gsize fh_size
= crypto
->fh
->v1
? sizeof(crypto
->fh
->ver
.fh1
) : sizeof(crypto
->fh
->ver
.fh2
);
3534 guint64 fh_iter
= crypto
->fh
->v1
? crypto
->fh
->ver
.fh1
.iter
: crypto
->fh
->ver
.fh2
.iter
;
3535 guint hashlen
= gcry_md_get_algo_dlen(GCRY_MD_SHA256
);
3537 lseek(crypto
->fh
->fd
, fh_size
, SEEK_SET
);
3538 insize
= crypto
->fh
->st
.st_size
- fh_size
;
3539 crypto
->iv
= gcry_malloc(crypto
->blocksize
);
3542 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3543 return gpg_error_from_errno(ENOMEM
);
3547 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh1
.iv
, crypto
->blocksize
);
3549 memcpy(crypto
->iv
, crypto
->fh
->ver
.fh2
.iv
, crypto
->blocksize
);
3551 crypto
->inbuf
= gcry_malloc(insize
);
3553 if (!crypto
->inbuf
) {
3554 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
3555 return gpg_error_from_errno(ENOMEM
);
3558 crypto
->insize
= insize
;
3559 len
= pth_read(crypto
->fh
->fd
, crypto
->inbuf
, crypto
->insize
);
3561 if (len
!= crypto
->insize
)
3562 return GPG_ERR_INV_LENGTH
;
3564 /* No encryption iterations. This is a plain (gzipped) file. */
3565 if ((crypto
->fh
->v1
&& (long)fh_iter
< 0L) ||
3566 (!crypto
->fh
->v1
&& fh_iter
<= 0L)) {
3568 * cache_file_count() needs both .used == TRUE and a valid key in
3569 * order for it to count as a used cache entry. Fixes CACHE status
3572 memset(key
, '!', hashlen
);
3576 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
3577 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3581 if ((rc
= gcry_cipher_setkey(crypto
->gh
, key
, crypto
->keysize
))) {
3582 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3586 iter_progress
= (guint64
)get_key_file_double(client
&& client
->filename
?
3587 client
->filename
: "global", "iteration_progress");
3589 if (iter_progress
> 0ULL && fh_iter
>= iter_progress
) {
3590 rc
= send_status(ctx
, STATUS_DECRYPT
, "0 %llu", fh_iter
);
3596 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3601 crypto
->tkey
= gcry_malloc(hashlen
);
3603 if (!crypto
->tkey
) {
3604 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, strerror(ENOMEM
));
3605 return gpg_error_from_errno(ENOMEM
);
3608 memcpy(crypto
->tkey
, key
, hashlen
);
3609 guchar
*tkey
= crypto
->tkey
;
3612 if ((rc
= gcry_cipher_setkey(crypto
->gh
, crypto
->tkey
, crypto
->keysize
))) {
3613 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3617 while (iter
< (crypto
->fh
->v1
? fh_iter
: fh_iter
-1)) {
3618 if (iter_progress
> 0ULL && iter
>= iter_progress
) {
3619 if (!(iter
% iter_progress
)) {
3620 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu",
3621 ++n_iter
* iter_progress
, fh_iter
);
3628 if ((rc
= gcry_cipher_setiv(crypto
->gh
, crypto
->iv
, crypto
->blocksize
))) {
3629 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3633 rc
= iterate_crypto_once(client
, crypto
, STATUS_DECRYPT
);
3636 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, _gpg_strerror(rc
));
3643 if (iter_progress
&& fh_iter
>= iter_progress
) {
3644 rc
= send_status(ctx
, STATUS_DECRYPT
, "%llu %llu", fh_iter
, fh_iter
);
3651 if (do_decompress(ctx
, crypto
->inbuf
, crypto
->insize
,
3652 (gpointer
*)&crypto
->outbuf
, &outsize
, &zrc
) == FALSE
) {
3653 if (zrc
== Z_MEM_ERROR
)
3654 return gpg_error_from_errno(ENOMEM
);
3656 return EPWMD_BADKEY
; // Not a valid gzip header. Must be a bad key.
3659 if (g_strncasecmp(crypto
->outbuf
, "<?xml ", 6) != 0) {
3660 gcry_free(crypto
->outbuf
);
3661 crypto
->outbuf
= NULL
;
3662 return EPWMD_BADKEY
;
3666 client
->xml
= crypto
->outbuf
;
3667 client
->len
= outsize
;
3668 crypto
->outbuf
= NULL
;
3671 *dst
= crypto
->outbuf
;
3673 crypto
->outbuf
= NULL
;
3676 /* The calling function should free the crypto struct. */