1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
30 #include <sys/types.h>
35 #include <glib/gstdio.h>
43 #include "pwmd-error.h"
55 /* These are flags that are set by commands. */
56 #define OPT_INQUIRE 0x0001
57 #define OPT_NO_PASSPHRASE 0x0002
58 #define OPT_RESET 0x0004
59 #define OPT_LIST_RECURSE 0x0008
60 #define OPT_LIST_VERBOSE 0x0010
61 #define OPT_LOCK 0x0020
62 #define OPT_LOCK_ON_OPEN 0x0040
63 #define OPT_SIGN 0x0080
64 #define OPT_LIST_ALL 0x0100
66 struct command_table_s
{
68 gpg_error_t (*handler
)(assuan_context_t
, gchar
*line
);
70 gboolean ignore_startup
;
71 gboolean unlock
; // unlock the file mutex after validating the checksum
74 static struct command_table_s
**command_table
;
76 static gpg_error_t
do_lock(struct client_s
*client
, gboolean add
);
78 gpg_error_t
unlock_file_mutex(struct client_s
*client
, gboolean remove
)
82 // OPEN: keep the lock for the same file being reopened.
83 if (client
->flags
&FLAG_KEEP_LOCK
&& client
->flags
&FLAG_HAS_LOCK
)
86 if (!(client
->flags
&FLAG_HAS_LOCK
))
87 return GPG_ERR_NOT_LOCKED
;
89 rc
= cache_unlock_mutex(client
->md5file
, remove
);
91 rc
= GPG_ERR_INV_STATE
;
93 client
->flags
&= ~(FLAG_HAS_LOCK
|FLAG_LOCK_CMD
);
98 gpg_error_t
lock_file_mutex(struct client_s
*client
, gboolean add
)
101 gint timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
103 if (client
->flags
&FLAG_HAS_LOCK
)
106 rc
= cache_lock_mutex(client
->ctx
, client
->md5file
,
107 client
->flags
&FLAG_RC_ON_LOCKED
, add
, timeout
);
109 client
->flags
|= FLAG_HAS_LOCK
;
114 static gpg_error_t
file_modified(struct client_s
*client
,
115 struct command_table_s
*cmd
)
119 if (!(client
->flags
&FLAG_OPEN
))
120 return GPG_ERR_INV_STATE
;
122 rc
= lock_file_mutex(client
, FALSE
);
123 if (!rc
|| rc
== GPG_ERR_NO_DATA
) {
127 if (g_lstat(client
->filename
, &st
) && errno
!= ENOENT
)
128 rc
= gpg_error_from_syserror();
129 else if (client
->ctime
&& client
->ctime
!= st
.st_ctime
)
130 rc
= GPG_ERR_CHECKSUM
;
133 if ((cmd
->unlock
&& !(client
->flags
&FLAG_HAS_LOCK
)) || rc
)
134 unlock_file_mutex(client
, FALSE
);
139 static gpg_error_t
parse_xml(assuan_context_t ctx
, gboolean
new)
141 struct client_s
*client
= assuan_get_pointer(ctx
);
142 gboolean cached
= client
->doc
!= NULL
;
145 client
->doc
= new_document();
147 client
->doc
= parse_doc((gchar
*)client
->crypto
->plaintext
,
148 client
->crypto
->plaintext_len
);
151 client
->dupdoc
= xmlCopyDoc(client
->doc
, 1);
152 if (!client
->dupdoc
) {
154 xmlFreeDoc(client
->doc
);
159 return !client
->doc
? GPG_ERR_ENOMEM
: 0;
162 static void free_client(struct client_s
*client
)
164 /* client->doc is a pointer to the xml and is held in the cache. */
166 xmlFreeDoc(client
->dupdoc
);
168 g_free(client
->filename
);
169 g_free(client
->last_error
);
171 if (client
->crypto
) {
172 cleanup_crypto_stage2(client
->crypto
);
173 if (client
->crypto
->pkey_sexp
)
174 gcry_sexp_release(client
->crypto
->pkey_sexp
);
176 client
->crypto
->pkey_sexp
= NULL
;
177 memset(client
->crypto
->sign_grip
, 0, sizeof(client
->crypto
->sign_grip
));
180 if (client
->xml_error
)
181 xmlResetError(client
->xml_error
);
184 void cleanup_client(struct client_s
*client
)
186 assuan_context_t ctx
= client
->ctx
;
187 struct client_thread_s
*thd
= client
->thd
;
188 struct crypto_s
*crypto
= client
->crypto
;
190 unlock_file_mutex(client
, client
->flags
&FLAG_NEW
);
192 memset(client
, 0, sizeof(struct client_s
));
193 client
->crypto
= crypto
;
198 static gpg_error_t
open_finalize(assuan_context_t ctx
)
200 struct client_s
*client
= assuan_get_pointer(ctx
);
202 struct cache_data_s
*cdata
= cache_get_data(client
->md5file
);
203 gboolean cached
= FALSE
;
205 client
->crypto
->filename
= g_strdup(client
->filename
);
206 if (cdata
|| client
->flags
&FLAG_NEW
) {
207 cached
= cdata
!= NULL
;
211 rc
= send_status(ctx
, STATUS_DECRYPT
, NULL
);
215 rc
= decrypt_data(client
->crypto
);
219 rc
= parse_xml(ctx
, client
->flags
&FLAG_NEW
);
221 gint timeout
= get_key_file_integer(client
->filename
,
225 cdata
= g_malloc0(sizeof(struct cache_data_s
));
226 cdata
->doc
= client
->doc
;
228 if (!(client
->flags
&FLAG_NEW
)) {
229 rc
= gcry_sexp_build((gcry_sexp_t
*)&cdata
->pubkey
, NULL
,
230 "%S", client
->crypto
->pkey_sexp
);
235 gcry_sexp_release(cdata
->sigkey
);
237 rc
= gcry_sexp_build((gcry_sexp_t
*)&cdata
->sigkey
, NULL
,
238 "%S", client
->crypto
->sigpkey_sexp
);
239 cdata
->ctime
= client
->crypto
->st
.st_ctime
;
241 if (!cache_add_file(client
->md5file
, (client
->flags
&FLAG_NEW
)
242 ? NULL
: client
->crypto
->grip
, cdata
, timeout
)) {
245 xmlFreeDoc(client
->doc
);
252 client
->flags
|= FLAG_OPEN
;
253 client
->doc
= client
->dupdoc
;
258 if (!rc
&& (client
->opts
&OPT_LOCK_ON_OPEN
))
259 rc
= do_lock(client
, FALSE
);
264 static void req_cleanup(void *arg
)
269 g_strfreev((gchar
**)arg
);
272 static gpg_error_t
parse_open_opt_lock(gpointer data
, gpointer value
)
274 struct client_s
*client
= data
;
276 client
->opts
|= OPT_LOCK_ON_OPEN
;
280 static gpg_error_t
parse_opt_pinentry(gpointer data
, gpointer value
)
282 struct client_s
*client
= data
;
284 client
->flags
|= FLAG_NO_PINENTRY
;
288 static gpg_error_t
parse_opt_inquire(gpointer data
, gpointer value
)
290 struct client_s
*client
= data
;
293 client
->opts
|= OPT_INQUIRE
;
297 static void update_checksum(struct client_s
*client
)
299 client
->ctime
= client
->crypto
->st
.st_ctime
;
302 static gpg_error_t
validate_checksum(struct client_s
*client
, time_t ctime
)
304 if (!g_lstat(client
->filename
, &client
->crypto
->st
))
305 return ctime
!= client
->crypto
->st
.st_ctime
? GPG_ERR_CHECKSUM
: 0;
307 return gpg_error_from_syserror();
310 static gpg_error_t
do_open(assuan_context_t ctx
, const gchar
*filename
,
311 const gchar
*password
)
313 struct client_s
*client
= assuan_get_pointer(ctx
);
314 struct cache_data_s
*cdata
;
316 gboolean done
= FALSE
;
318 if (!valid_filename(filename
))
319 return GPG_ERR_INV_VALUE
;
321 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
322 client
->filename
= g_strdup(filename
);
323 if (!client
->filename
)
324 return GPG_ERR_ENOMEM
;
328 pthread_cleanup_push(cleanup_cache_mutex
, NULL
);
329 cdata
= cache_get_data(client
->md5file
);
330 if (cdata
&& cdata
->doc
) {
331 rc
= validate_checksum(client
, cdata
->ctime
);
332 /* This will check that the key is cached in the agent which needs to
333 * be determined for files that share a keygrip. */
335 rc
= cache_iscached(client
->filename
);
337 if (!rc
&& !password
) {
338 rc
= read_data_header(client
->filename
, &client
->crypto
->hdr
,
341 client
->doc
= cdata
->doc
;
342 gcry_sexp_build(&client
->crypto
->pkey_sexp
, NULL
, "%S",
344 gcry_pk_get_keygrip(client
->crypto
->pkey_sexp
, client
->crypto
->grip
);
345 gcry_sexp_build(&client
->crypto
->sigpkey_sexp
, NULL
, "%S",
347 gcry_pk_get_keygrip(client
->crypto
->sigpkey_sexp
, client
->crypto
->sign_grip
);
348 rc
= open_finalize(ctx
);
353 /* There was an error accessing the file so clear the cache entry. The
354 * real error will be returned from read_data_file() since the file
355 * may have only disappeared. */
357 rc
= cache_clear(client
->md5file
);
360 pthread_cleanup_pop(1);
364 rc
= read_data_file(client
->filename
, client
->crypto
);
366 if (gpg_err_code(rc
) != GPG_ERR_ENOENT
) {
367 log_write("%s: %s", client
->filename
, pwmd_strerror(rc
));
371 client
->flags
|= FLAG_NEW
;
372 memset(client
->crypto
->grip
, 0, sizeof(client
->crypto
->grip
));
373 memset(client
->crypto
->sign_grip
, 0, sizeof(client
->crypto
->sign_grip
));
375 pthread_cleanup_push(cleanup_cache_mutex
, NULL
);
376 rc
= open_finalize(ctx
);
377 pthread_cleanup_pop(1);
381 update_checksum(client
);
384 rc
= set_agent_passphrase(client
->crypto
, password
, strlen(password
));
390 pthread_cleanup_push(cleanup_cache_mutex
, NULL
);
391 rc
= open_finalize(ctx
);
392 pthread_cleanup_pop(1);
396 gpg_error_t
kill_scd(struct agent_s
*agent
)
400 if (get_key_file_boolean(NULL
, "kill_scd"))
401 rc
= send_to_agent(agent
, NULL
, NULL
, "SCD KILLSCD");
406 static gpg_error_t
open_command(assuan_context_t ctx
, gchar
*line
)
409 struct client_s
*client
= assuan_get_pointer(ctx
);
410 gchar
**req
, *password
= NULL
, *filename
;
412 gboolean same_file
= FALSE
;
413 struct argv_s
*args
[] = {
414 &(struct argv_s
) { "lock", OPTION_TYPE_NOARG
, parse_open_opt_lock
},
415 &(struct argv_s
) { "no-pinentry", OPTION_TYPE_NOARG
,
416 parse_opt_pinentry
},
420 client
->flags
&= ~(FLAG_NO_PINENTRY
);
421 rc
= parse_options(&line
, args
, client
);
423 return send_error(ctx
, rc
);
425 req
= split_input_line(line
, " ", 2);
427 return send_error(ctx
, GPG_ERR_SYNTAX
);
429 pthread_cleanup_push(req_cleanup
, req
);
431 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, filename
, strlen(filename
));
432 /* This client may have locked a different file with ISCACHED --lock than
433 * the current filename. This will remove that lock. */
434 same_file
= !memcmp(md5file
, client
->md5file
, 16) ? TRUE
: FALSE
;
435 if (client
->flags
&FLAG_OPEN
||
436 (client
->flags
&FLAG_HAS_LOCK
&& !same_file
)) {
437 typeof(client
->opts
) opts
= client
->opts
;
438 typeof(client
->flags
) flags
= client
->flags
;
441 client
->flags
|= FLAG_KEEP_LOCK
;
443 cleanup_client(client
);
445 client
->flags
|= flags
;
446 client
->flags
&= ~(FLAG_LOCK_CMD
|FLAG_NEW
);
448 client
->flags
&= ~(FLAG_HAS_LOCK
);
451 /* Need to lock the mutex here because file_modified() cannot without
452 * knowing the filename. */
453 memcpy(client
->md5file
, md5file
, 16);
454 rc
= lock_file_mutex(client
, TRUE
);
456 password
= req
[1] && *req
[1] ? req
[1] : NULL
;
457 rc
= set_pinentry_mode(client
->crypto
->agent
,
458 (client
->flags
&FLAG_NO_PINENTRY
) ? "loopback" : "ask");
460 rc
= do_open(ctx
, filename
, password
);
462 cleanup_client(client
);
464 cleanup_crypto_stage1(client
->crypto
);
468 pthread_cleanup_pop(1);
470 if (!rc
&& client
->flags
& FLAG_NEW
)
471 rc
= send_status(ctx
, STATUS_NEWFILE
, NULL
);
473 (void)kill_scd(client
->crypto
->agent
);
474 return send_error(ctx
, rc
);
477 static gpg_error_t
parse_save_opt_no_passphrase(gpointer data
, gpointer value
)
479 struct client_s
*client
= data
;
482 client
->opts
|= OPT_NO_PASSPHRASE
;
486 static gpg_error_t
parse_save_opt_cipher(gpointer data
, gpointer value
)
488 struct client_s
*client
= data
;
489 gint algo
= cipher_string_to_gcrypt((gchar
*)value
);
490 file_header_t
*hdr
= &client
->crypto
->save
.hdr
;
493 return GPG_ERR_INV_VALUE
;
495 hdr
->flags
= set_cipher_flag(hdr
->flags
, algo
);
499 static gpg_error_t
parse_save_opt_keygrip(gpointer data
, gpointer value
)
501 struct client_s
*client
= data
;
503 if (client
->crypto
->save
.pkey
)
504 gcry_sexp_release(client
->crypto
->save
.pkey
);
506 client
->crypto
->save
.pkey
= NULL
;
507 return get_pubkey(client
->crypto
, value
, &client
->crypto
->save
.pkey
);
510 static gpg_error_t
parse_save_opt_sign_keygrip(gpointer data
, gpointer value
)
512 struct client_s
*client
= data
;
514 if (client
->crypto
->save
.sigpkey
)
515 gcry_sexp_release(client
->crypto
->save
.sigpkey
);
517 client
->crypto
->save
.sigpkey
= NULL
;
518 return get_pubkey(client
->crypto
, value
, &client
->crypto
->save
.sigpkey
);
521 static gpg_error_t
parse_opt_s2k_count(gpointer data
, gpointer value
)
523 struct client_s
*client
= data
;
527 return GPG_ERR_INV_VALUE
;
529 client
->crypto
->save
.s2k_count
= strtoul(v
, NULL
, 10);
533 static gpg_error_t
save_finalize(assuan_context_t ctx
)
535 struct client_s
*client
= assuan_get_pointer(ctx
);
539 gcry_sexp_t pubkey
= client
->crypto
->save
.pkey
;
540 gcry_sexp_t sigkey
= client
->crypto
->save
.sigpkey
;
541 struct cache_data_s
*cdata
;
543 xmlDocDumpFormatMemory(client
->doc
, &buf
, &buflen
, 0);
545 return GPG_ERR_ENOMEM
;
548 pubkey
= client
->crypto
->pkey_sexp
;
551 sigkey
= client
->crypto
->sigpkey_sexp
;
553 gcry_sexp_build(&client
->crypto
->save
.sigpkey
, 0, "%S", pubkey
);
554 sigkey
= client
->crypto
->save
.sigpkey
;
558 rc
= send_status(ctx
, STATUS_ENCRYPT
, NULL
);
564 pthread_cleanup_push(xmlFree
, buf
);
565 rc
= encrypt_data_file(client
->crypto
, pubkey
, sigkey
, client
->filename
,
567 pthread_cleanup_pop(1);
568 if (pubkey
== client
->crypto
->save
.pkey
) {
570 gcry_sexp_release(client
->crypto
->pkey_sexp
);
571 client
->crypto
->pkey_sexp
= client
->crypto
->save
.pkey
;
572 gcry_pk_get_keygrip(client
->crypto
->pkey_sexp
, client
->crypto
->grip
);
575 gcry_sexp_release(pubkey
);
577 client
->crypto
->save
.pkey
= NULL
;
581 gcry_pk_get_keygrip(sigkey
, client
->crypto
->sign_grip
);
583 if (sigkey
== client
->crypto
->save
.sigpkey
) {
585 if (client
->crypto
->sigpkey_sexp
)
586 gcry_sexp_release(client
->crypto
->sigpkey_sexp
);
588 client
->crypto
->sigpkey_sexp
= client
->crypto
->save
.sigpkey
;
589 gcry_pk_get_keygrip(client
->crypto
->sigpkey_sexp
, client
->crypto
->sign_grip
);
592 gcry_sexp_release(sigkey
);
594 client
->crypto
->save
.sigpkey
= NULL
;
598 update_checksum(client
);
600 pthread_cleanup_push(cleanup_cache_mutex
, NULL
);
601 cdata
= cache_get_data(client
->md5file
);
602 gboolean cached
= cdata
!= NULL
;
605 cdata
= g_malloc0(sizeof(struct cache_data_s
));
607 /* Update in case of any --keygrip argument */
609 gcry_sexp_release(cdata
->pubkey
);
611 gcry_sexp_build((gcry_sexp_t
*)&cdata
->pubkey
, NULL
, "%S",
612 client
->crypto
->pkey_sexp
);
615 gcry_sexp_release(cdata
->sigkey
);
617 gcry_sexp_build((gcry_sexp_t
*)&cdata
->sigkey
, NULL
, "%S",
618 client
->crypto
->sigpkey_sexp
);
620 xmlDocPtr doc
= xmlCopyDoc(client
->doc
, 1);
623 xmlFreeDoc(cdata
->doc
);
625 client
->dupdoc
= doc
;
626 cdata
->doc
= client
->doc
;
627 client
->doc
= client
->dupdoc
;
628 cdata
->ctime
= client
->ctime
;
629 rc
= cache_set_data(client
->md5file
, cdata
, client
->crypto
->grip
);
631 if (!rc
&& (!cached
|| (client
->flags
&FLAG_NEW
)))
632 send_status_all(STATUS_CACHE
, NULL
);
635 client
->flags
&= ~(FLAG_NEW
);
640 pthread_cleanup_pop(1);
646 static gpg_error_t
parse_opt_reset(gpointer data
, gpointer value
)
648 struct client_s
*client
= data
;
651 client
->opts
|= OPT_RESET
;
655 static gpg_error_t
save_command(assuan_context_t ctx
, gchar
*line
)
657 struct client_s
*client
= assuan_get_pointer(ctx
);
660 struct argv_s
*args
[] = {
661 &(struct argv_s
) { "no-passphrase", OPTION_TYPE_NOARG
,
662 parse_save_opt_no_passphrase
},
663 &(struct argv_s
) { "cipher", OPTION_TYPE_ARG
, parse_save_opt_cipher
},
664 &(struct argv_s
) { "inquire-keyparam", OPTION_TYPE_NOARG
, parse_opt_inquire
},
665 &(struct argv_s
) { "keygrip", OPTION_TYPE_ARG
, parse_save_opt_keygrip
},
666 &(struct argv_s
) { "sign-keygrip", OPTION_TYPE_ARG
,
667 parse_save_opt_sign_keygrip
},
668 &(struct argv_s
) { "s2k-count", OPTION_TYPE_ARG
, parse_opt_s2k_count
},
669 &(struct argv_s
) { "reset", OPTION_TYPE_NOARG
, parse_opt_reset
},
673 cleanup_save(&client
->crypto
->save
);
674 memcpy(&client
->crypto
->save
.hdr
, &client
->crypto
->hdr
, sizeof(file_header_t
));
675 client
->crypto
->save
.s2k_count
= get_key_file_ulong(client
->filename
, "s2k_count");
676 rc
= parse_options(&line
, args
, client
);
678 return send_error(ctx
, rc
);
680 if ((client
->opts
&OPT_NO_PASSPHRASE
) && !(client
->flags
&FLAG_NEW
)
681 && !(client
->opts
&OPT_INQUIRE
))
682 return send_error(ctx
, GPG_ERR_WRONG_KEY_USAGE
);
684 if (g_lstat(client
->filename
, &st
) == -1 && errno
!= ENOENT
)
685 return send_error(ctx
, gpg_error_from_syserror());
687 if (errno
!= ENOENT
&& !S_ISREG(st
.st_mode
)) {
688 log_write("%s: %s", client
->filename
, pwmd_strerror(GPG_ERR_ENOANO
));
689 return send_error(ctx
, GPG_ERR_ENOANO
);
692 if (client
->opts
&OPT_RESET
) {
693 rc
= cache_clear(client
->md5file
);
695 return send_error(ctx
, rc
);
698 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
));
700 return send_error(ctx
, rc
);
702 if (!rc
&& !client
->crypto
->save
.pkey
&&
703 (client
->flags
&FLAG_NEW
|| client
->opts
&OPT_INQUIRE
)) {
704 rc
= send_status(client
->ctx
, STATUS_GENKEY
, NULL
);
706 struct inquire_data_s idata
= {0};
707 gchar
*params
= client
->opts
&OPT_INQUIRE
? NULL
708 : default_key_params(client
->crypto
);
710 pthread_cleanup_push(g_free
, params
);
711 idata
.crypto
= client
->crypto
;
715 idata
.len
= strlen(params
);
720 client
->crypto
->agent
->inquire_data
= &idata
;
721 client
->crypto
->agent
->inquire_cb
= NULL
;
722 rc
= generate_key(client
->crypto
, params
,
723 (client
->opts
&OPT_NO_PASSPHRASE
), TRUE
);
724 pthread_cleanup_pop(1);
729 rc
= save_finalize(ctx
);
731 cleanup_crypto_stage1(client
->crypto
);
732 (void)kill_scd(client
->crypto
->agent
);
733 return send_error(ctx
, rc
);
736 static gpg_error_t
do_delete(assuan_context_t ctx
, gchar
*line
)
738 struct client_s
*client
= assuan_get_pointer(ctx
);
743 if (strchr(line
, '\t'))
744 req
= split_input_line(line
, "\t", -1);
746 req
= split_input_line(line
, " ", -1);
749 return GPG_ERR_SYNTAX
;
751 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
758 * No sub-node defined. Remove the entire node (root element).
770 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
783 static gpg_error_t
delete_command(assuan_context_t ctx
, gchar
*line
)
785 struct client_s
*client
= assuan_get_pointer(ctx
);
787 struct argv_s
*args
[] = {
788 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
792 rc
= parse_options(&line
, args
, client
);
794 return send_error(ctx
, rc
);
796 if (client
->opts
&OPT_INQUIRE
) {
800 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
802 return send_error(ctx
, rc
);
804 line
= (gchar
*)result
;
807 rc
= do_delete(ctx
, line
);
809 if (client
->opts
&OPT_INQUIRE
)
812 return send_error(ctx
, rc
);
815 /* FIXME: storing an element content with the same value as a child element
817 static gpg_error_t
store_command(assuan_context_t ctx
, gchar
*line
)
819 struct client_s
*client
= assuan_get_pointer(ctx
);
824 xmlNodePtr n
, parent
;
825 gboolean has_content
;
826 gchar
*content
= NULL
;
828 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
830 return send_error(ctx
, rc
);
832 req
= split_input_line((gchar
*)result
, "\t", 0);
836 return send_error(ctx
, GPG_ERR_SYNTAX
);
838 len
= g_strv_length(req
);
839 has_content
= line
[strlen(line
)-1] != '\t' && len
> 1;
840 if (*(req
+1) && !valid_element_path(req
, has_content
)) {
842 return send_error(ctx
, GPG_ERR_INV_VALUE
);
846 content
= req
[len
-1];
851 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
852 if (rc
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
853 rc
= new_root_element(client
->doc
, *req
);
856 return send_error(ctx
, GPG_ERR_SYNTAX
);
864 return send_error(ctx
, rc
);
869 if (req
[1] && *req
[1]) {
871 parent
= create_elements_cb(n
, req
+1, &rc
, NULL
);
873 parent
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
874 NULL
, NULL
, create_elements_cb
, FALSE
, 0, NULL
, FALSE
);
877 if (!rc
&& len
> 1) {
878 n
= find_text_node(parent
->children
);
880 xmlNodeSetContent(n
, (xmlChar
*)content
);
882 xmlNodeAddContent(parent
, (xmlChar
*)content
);
884 update_element_mtime(parent
);
888 req
[len
-1] = content
;
891 return send_error(ctx
, rc
);
894 static gpg_error_t
xfer_data(assuan_context_t ctx
, const gchar
*line
,
900 gint progress
= get_key_file_integer("global", "xfer_progress");
903 progress
= progress
>0 ? (progress
/ASSUAN_LINELENGTH
)*ASSUAN_LINELENGTH
: 0;
904 to_send
= total
< ASSUAN_LINELENGTH
? total
: ASSUAN_LINELENGTH
;
905 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
912 if (sent
+ to_send
> total
)
913 to_send
= total
- sent
;
915 rc
= assuan_send_data(ctx
, flush
? NULL
: (gchar
*)line
+sent
,
916 flush
? 0 : to_send
);
918 sent
+= flush
? 0 : to_send
;
920 if ((progress
&& !(sent
% progress
) && sent
!= total
) ||
921 (sent
== total
&& flush
))
922 rc
= send_status(ctx
, STATUS_XFER
, "%li %li", sent
, total
);
924 if (!flush
&& !rc
&& sent
== total
) {
929 } while (!rc
&& sent
< total
);
934 static gpg_error_t
do_get(assuan_context_t ctx
, gchar
*line
)
936 struct client_s
*client
= assuan_get_pointer(ctx
);
941 req
= split_input_line(line
, "\t", -1);
945 return GPG_ERR_SYNTAX
;
948 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
955 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
961 if (!n
|| !n
->children
)
962 return GPG_ERR_NO_DATA
;
964 n
= find_text_node(n
->children
);
965 if (!n
|| !n
->content
|| !*n
->content
)
966 return GPG_ERR_NO_DATA
;
968 rc
= xfer_data(ctx
, (gchar
*)n
->content
, xmlStrlen(n
->content
));
972 static gpg_error_t
get_command(assuan_context_t ctx
, gchar
*line
)
974 struct client_s
*client
= assuan_get_pointer(ctx
);
976 struct argv_s
*args
[] = {
977 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
981 rc
= parse_options(&line
, args
, client
);
983 return send_error(ctx
, rc
);
985 if (client
->opts
&OPT_INQUIRE
) {
989 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
991 return send_error(ctx
, rc
);
993 line
= (gchar
*)result
;
996 rc
= do_get(ctx
, line
);
998 if (client
->opts
&OPT_INQUIRE
)
1001 return send_error(ctx
, rc
);
1004 static xmlNodePtr
realpath_elements_cb(xmlNodePtr node
, gchar
**target
,
1005 gpg_error_t
*rc
, gchar
**req_orig
, void *data
)
1007 gchar
*path
= *(gchar
**)data
;
1008 gchar
*tmp
= NULL
, *result
;
1012 *(gchar
**)data
= NULL
;
1015 path
= g_strjoinv("\t", target
);
1018 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1019 *rc
= GPG_ERR_ENOMEM
;
1024 tmp
= g_strjoinv("\t", req_orig
);
1028 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1029 *rc
= GPG_ERR_ENOMEM
;
1035 result
= g_strdup_printf("%s\t%s", path
, tmp
);
1037 result
= g_strdup(path
);
1040 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1041 *rc
= GPG_ERR_ENOMEM
;
1049 *(gchar
**)data
= result
;
1053 static void list_command_cleanup1(void *arg
);
1054 static gpg_error_t
do_realpath(assuan_context_t ctx
, gchar
*line
)
1056 struct client_s
*client
= assuan_get_pointer(ctx
);
1065 if (strchr(line
, '\t') != NULL
) {
1066 if ((req
= split_input_line(line
, "\t", 0)) == NULL
)
1067 return GPG_ERR_SYNTAX
;
1070 if ((req
= split_input_line(line
, " ", 0)) == NULL
)
1071 return GPG_ERR_SYNTAX
;
1074 n
= find_root_element(client
->doc
, &req
, &rc
, NULL
, 0, FALSE
);
1080 rp
= g_strjoinv("\t", req
);
1083 return GPG_ERR_ENOMEM
;
1087 n
= find_elements(client
->doc
, n
->children
, req
+1, &rc
,
1088 NULL
, realpath_elements_cb
, NULL
, FALSE
, 0, &rp
, FALSE
);
1096 string
= g_string_new(rp
);
1100 return GPG_ERR_ENOMEM
;
1103 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++) {
1104 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+1) && *(t
+1) != '!')) {
1105 string
= g_string_insert_c(string
, !i
? i
++ : ++i
, '!');
1110 pthread_cleanup_push(list_command_cleanup1
, string
);
1111 rc
= xfer_data(ctx
, string
->str
, string
->len
);
1112 pthread_cleanup_pop(1);
1116 static gpg_error_t
realpath_command(assuan_context_t ctx
, gchar
*line
)
1119 struct client_s
*client
= assuan_get_pointer(ctx
);
1120 struct argv_s
*args
[] = {
1121 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
1125 rc
= parse_options(&line
, args
, client
);
1127 return send_error(ctx
, rc
);
1129 if (client
->opts
&OPT_INQUIRE
) {
1133 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
1135 return send_error(ctx
, rc
);
1137 line
= (gchar
*)result
;
1140 rc
= do_realpath(ctx
, line
);
1142 if (client
->opts
&OPT_INQUIRE
)
1145 return send_error(ctx
, rc
);
1148 static void list_command_cleanup1(void *arg
)
1150 g_string_free((GString
*)arg
, TRUE
);
1153 static void list_command_cleanup2(void *arg
)
1155 struct element_list_s
*elements
= arg
;
1158 if (elements
->list
) {
1159 gint total
= g_slist_length(elements
->list
);
1162 for (i
= 0; i
< total
; i
++) {
1163 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
1167 g_slist_free(elements
->list
);
1170 if (elements
->prefix
)
1171 g_free(elements
->prefix
);
1174 g_strfreev(elements
->req
);
1180 static gpg_error_t
parse_list_opt_norecurse(gpointer data
, gpointer value
)
1182 struct client_s
*client
= data
;
1184 client
->opts
&= ~(OPT_LIST_RECURSE
);
1188 static gpg_error_t
parse_list_opt_verbose(gpointer data
, gpointer value
)
1190 struct client_s
*client
= data
;
1192 client
->opts
|= OPT_LIST_VERBOSE
;
1196 static gpg_error_t
parse_list_opt_all(gpointer data
, gpointer value
)
1198 struct client_s
*client
= data
;
1200 client
->opts
|= OPT_LIST_ALL
;
1204 static gpg_error_t
list_path_once(struct client_s
*client
, gchar
*line
,
1205 struct element_list_s
*elements
, GString
*result
)
1209 elements
->req
= split_input_line(line
, " ", 0);
1211 strv_printf(&elements
->req
, "%s", line
);
1213 rc
= create_path_list(client
->doc
, elements
, *elements
->req
);
1216 gint total
= g_slist_length(elements
->list
);
1220 rc
= GPG_ERR_NO_DATA
;
1224 for (i
= 0; i
< total
; i
++) {
1225 gchar
*tmp
= g_slist_nth_data(elements
->list
, i
);
1227 g_string_append_printf(result
, "%s%s", tmp
,
1228 i
+1 == total
? "" : "\n");
1234 rc
= GPG_ERR_NO_DATA
;
1240 static gpg_error_t
do_list(assuan_context_t ctx
, gchar
*line
)
1242 struct client_s
*client
= assuan_get_pointer(ctx
);
1244 struct element_list_s
*elements
= NULL
;
1246 elements
= g_malloc0(sizeof(struct element_list_s
));
1248 return GPG_ERR_ENOMEM
;
1250 elements
->recurse
= client
->opts
&OPT_LIST_RECURSE
;
1251 elements
->verbose
= client
->opts
&OPT_LIST_VERBOSE
;
1253 if (!line
|| !*line
) {
1256 pthread_cleanup_push(list_command_cleanup2
, elements
);
1257 rc
= list_root_elements(client
->doc
, &str
, elements
->verbose
);
1258 pthread_cleanup_pop(1);
1259 pthread_cleanup_push(list_command_cleanup1
, str
);
1262 if (client
->opts
&OPT_LIST_ALL
) {
1263 gchar
**roots
= split_input_line(str
->str
, "\n", 0);
1266 pthread_cleanup_push(req_cleanup
, roots
);
1267 g_string_truncate(str
, 0);
1269 for (p
= roots
; *p
; p
++) {
1270 elements
= g_malloc0(sizeof(struct element_list_s
));
1272 rc
= GPG_ERR_ENOMEM
;
1276 elements
->recurse
= client
->opts
&OPT_LIST_RECURSE
;
1277 elements
->verbose
= client
->opts
&OPT_LIST_VERBOSE
;
1278 pthread_cleanup_push(list_command_cleanup2
, elements
);
1279 rc
= list_path_once(client
, *p
, elements
, str
);
1280 pthread_cleanup_pop(1);
1285 g_string_append(str
, "\n");
1288 pthread_cleanup_pop(1);
1292 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1295 pthread_cleanup_pop(1);
1299 pthread_cleanup_push(list_command_cleanup2
, elements
);
1300 GString
*str
= g_string_new(NULL
);
1301 pthread_cleanup_push(list_command_cleanup1
, str
);
1302 rc
= list_path_once(client
, line
, elements
, str
);
1304 rc
= xfer_data(ctx
, str
->str
, str
->len
);
1306 pthread_cleanup_pop(1);
1307 pthread_cleanup_pop(1);
1311 static gpg_error_t
list_command(assuan_context_t ctx
, gchar
*line
)
1313 struct client_s
*client
= assuan_get_pointer(ctx
);
1315 struct argv_s
*args
[] = {
1316 &(struct argv_s
) { "no-recurse", OPTION_TYPE_NOARG
, parse_list_opt_norecurse
},
1317 &(struct argv_s
) { "verbose", OPTION_TYPE_NOARG
, parse_list_opt_verbose
},
1318 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
1319 &(struct argv_s
) { "all", OPTION_TYPE_NOARG
, parse_list_opt_all
},
1323 if (disable_list_and_dump
== TRUE
)
1324 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1326 client
->opts
|= OPT_LIST_RECURSE
;
1327 rc
= parse_options(&line
, args
, client
);
1329 return send_error(ctx
, rc
);
1331 if (client
->opts
&OPT_INQUIRE
) {
1335 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
1337 return send_error(ctx
, rc
);
1339 line
= (gchar
*)result
;
1342 rc
= do_list(ctx
, line
);
1344 if (client
->opts
&OPT_INQUIRE
)
1347 return send_error(ctx
, rc
);
1351 * req[0] - element path
1353 static gpg_error_t
attribute_list(assuan_context_t ctx
, gchar
**req
)
1355 struct client_s
*client
= assuan_get_pointer(ctx
);
1356 gchar
**attrlist
= NULL
;
1358 gchar
**path
= NULL
;
1364 if (!req
|| !req
[0])
1365 return GPG_ERR_SYNTAX
;
1367 if ((path
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1369 * The first argument may be only a root element.
1371 if ((path
= split_input_line(req
[0], " ", 0)) == NULL
)
1372 return GPG_ERR_SYNTAX
;
1375 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
1383 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1384 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1394 for (a
= n
->properties
; a
; a
= a
->next
) {
1397 if ((pa
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1399 g_strfreev(attrlist
);
1401 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1402 return GPG_ERR_ENOMEM
;
1407 attrlist
[i
] = g_strdup_printf("%s %s", (gchar
*)a
->name
,
1408 an
&& an
->content
? (gchar
*)an
->content
: "");
1411 g_strfreev(attrlist
);
1412 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1413 return GPG_ERR_ENOMEM
;
1416 attrlist
[++i
] = NULL
;
1420 return GPG_ERR_NO_DATA
;
1422 line
= g_strjoinv("\n", attrlist
);
1425 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1426 g_strfreev(attrlist
);
1427 return GPG_ERR_ENOMEM
;
1430 pthread_cleanup_push(g_free
, line
);
1431 pthread_cleanup_push(req_cleanup
, attrlist
);
1432 rc
= xfer_data(ctx
, line
, strlen(line
));
1433 pthread_cleanup_pop(1);
1434 pthread_cleanup_pop(1);
1439 * req[0] - attribute
1440 * req[1] - element path
1442 static gpg_error_t
attribute_delete(struct client_s
*client
, gchar
**req
)
1445 gchar
**path
= NULL
;
1448 if (!req
|| !req
[0] || !req
[1])
1449 return GPG_ERR_SYNTAX
;
1451 if (!g_strcmp0(req
[0], "_name"))
1452 return GPG_ERR_INV_ATTR
;
1454 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1456 * The first argument may be only a root element.
1458 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1459 return GPG_ERR_SYNTAX
;
1462 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
1467 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1468 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1473 rc
= delete_attribute(n
, (xmlChar
*)req
[0]);
1480 static xmlNodePtr
create_element_path(struct client_s
*client
,
1481 gchar
***elements
, gpg_error_t
*rc
, xmlNodePtr parent
)
1483 gchar
**req
= *elements
;
1484 gchar
**req_orig
= g_strdupv(req
);
1485 xmlNodePtr n
= NULL
;
1490 *rc
= GPG_ERR_ENOMEM
;
1491 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1496 n
= find_root_element(client
->doc
, &req
, rc
, NULL
, 0, FALSE
);
1498 if (*rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
1501 *rc
= new_root_element(client
->doc
, req
[0]);
1507 else if (n
== parent
) {
1508 *rc
= GPG_ERR_CONFLICT
;
1514 n
= create_target_elements_cb(n
, req
+1, rc
, NULL
);
1516 n
= find_elements(client
->doc
, n
->children
, req
+1, rc
, NULL
, NULL
,
1517 create_target_elements_cb
, FALSE
, 0, parent
, FALSE
);
1523 * Reset the position of the element tree now that the elements
1524 * have been created.
1529 n
= find_root_element(client
->doc
, &req
, rc
, NULL
, 0, FALSE
);
1533 n
= find_elements(client
->doc
, n
->children
, req
+1, rc
,
1534 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1541 g_strfreev(req_orig
);
1548 * Creates a "target" attribute. When other commands encounter an element with
1549 * this attribute, the element path is modified to the target value. If the
1550 * source element path doesn't exist when using 'ATTR SET target', it is
1551 * created, but the destination element path must exist.
1553 * req[0] - source element path
1554 * req[1] - destination element path
1556 static gpg_error_t
target_attribute(struct client_s
*client
, gchar
**req
)
1558 gchar
**src
, **dst
, *line
= NULL
, **odst
= NULL
;
1562 if (!req
|| !req
[0] || !req
[1])
1563 return GPG_ERR_SYNTAX
;
1565 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1567 * The first argument may be only a root element.
1569 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
)
1570 return GPG_ERR_SYNTAX
;
1573 if (!valid_element_path(src
, FALSE
))
1574 return GPG_ERR_INV_VALUE
;
1576 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1578 * The first argument may be only a root element.
1580 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
1581 rc
= GPG_ERR_SYNTAX
;
1586 odst
= g_strdupv(dst
);
1589 rc
= GPG_ERR_ENOMEM
;
1593 n
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
1596 * Make sure the destination element path exists.
1602 n
= find_elements(client
->doc
, n
->children
, dst
+1, &rc
,
1603 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1609 n
= create_element_path(client
, &src
, &rc
, NULL
);
1614 line
= g_strjoinv("\t", odst
);
1617 rc
= GPG_ERR_ENOMEM
;
1618 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1622 rc
= add_attribute(n
, "target", line
);
1633 * req[0] - attribute
1634 * req[1] - element path
1636 static gpg_error_t
attribute_get(assuan_context_t ctx
, gchar
**req
)
1638 struct client_s
*client
= assuan_get_pointer(ctx
);
1644 if (!req
|| !req
[0] || !req
[1])
1645 return GPG_ERR_SYNTAX
;
1647 if (strchr(req
[1], '\t')) {
1648 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
)
1649 return GPG_ERR_SYNTAX
;
1652 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1653 return GPG_ERR_SYNTAX
;
1656 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
1662 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1663 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1671 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
)
1672 return GPG_ERR_NOT_FOUND
;
1674 pthread_cleanup_push(xmlFree
, a
);
1677 rc
= xfer_data(ctx
, (gchar
*)a
, xmlStrlen(a
));
1679 rc
= GPG_ERR_NO_DATA
;
1681 pthread_cleanup_pop(1);
1690 * req[0] - attribute
1691 * req[1] - element path
1694 static gpg_error_t
attribute_set(struct client_s
*client
, gchar
**req
)
1696 gchar
**path
= NULL
;
1700 if (!req
|| !req
[0] || !req
[1])
1701 return GPG_ERR_SYNTAX
;
1704 * Reserved attribute names.
1706 if (!g_strcmp0(req
[0], "_name"))
1707 return GPG_ERR_INV_ATTR
;
1708 else if (!g_strcmp0(req
[0], "target"))
1709 return target_attribute(client
, req
+ 1);
1711 if ((path
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1713 * The first argument may be only a root element.
1715 if ((path
= split_input_line(req
[1], " ", 0)) == NULL
)
1716 return GPG_ERR_SYNTAX
;
1719 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
1725 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
,
1726 NULL
, NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
1732 rc
= add_attribute(n
, req
[0], req
[2]);
1741 * req[1] - attribute name or element path if command is LIST
1742 * req[2] - element path
1743 * req[2] - element path or value
1746 static gpg_error_t
do_attr(assuan_context_t ctx
, gchar
*line
)
1748 struct client_s
*client
= assuan_get_pointer(ctx
);
1752 req
= split_input_line(line
, " ", 4);
1753 if (!req
|| !req
[0] || !req
[1]) {
1755 return GPG_ERR_SYNTAX
;
1758 pthread_cleanup_push(req_cleanup
, req
);
1760 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
1761 rc
= attribute_set(client
, req
+1);
1762 else if (g_ascii_strcasecmp(req
[0], "GET") == 0)
1763 rc
= attribute_get(ctx
, req
+1);
1764 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
1765 rc
= attribute_delete(client
, req
+1);
1766 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
1767 rc
= attribute_list(ctx
, req
+1);
1769 rc
= GPG_ERR_SYNTAX
;
1771 pthread_cleanup_pop(1);
1775 static gpg_error_t
attr_command(assuan_context_t ctx
, gchar
*line
)
1777 struct client_s
*client
= assuan_get_pointer(ctx
);
1779 struct argv_s
*args
[] = {
1780 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
1784 rc
= parse_options(&line
, args
, client
);
1786 return send_error(ctx
, rc
);
1788 if (client
->opts
&OPT_INQUIRE
) {
1792 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
1794 return send_error(ctx
, rc
);
1796 line
= (gchar
*)result
;
1799 rc
= do_attr(ctx
, line
);
1801 if (client
->opts
&OPT_INQUIRE
)
1804 return send_error(ctx
, rc
);
1807 static gpg_error_t
parse_iscached_opt_lock(gpointer data
, gpointer value
)
1809 struct client_s
*client
= data
;
1812 client
->opts
|= OPT_LOCK
;
1816 static gpg_error_t
iscached_command(assuan_context_t ctx
, gchar
*line
)
1818 struct client_s
*client
= assuan_get_pointer(ctx
);
1821 struct argv_s
*args
[] = {
1822 &(struct argv_s
) { "lock", OPTION_TYPE_NOARG
, parse_iscached_opt_lock
},
1826 if (!line
|| !*line
)
1827 return send_error(ctx
, GPG_ERR_SYNTAX
);
1829 rc
= parse_options(&line
, args
, client
);
1831 return send_error(ctx
, rc
);
1832 else if (!valid_filename(line
))
1833 return send_error(ctx
, GPG_ERR_INV_VALUE
);
1835 rc
= cache_iscached(line
);
1836 if (client
->opts
&OPT_LOCK
&& (!rc
|| gpg_err_code(rc
) == GPG_ERR_NO_DATA
)) {
1837 gpg_error_t trc
= rc
;
1838 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, line
, strlen(line
));
1839 if (memcmp(md5file
, client
->md5file
, 16))
1840 cleanup_client(client
);
1842 memcpy(client
->md5file
, md5file
, 16);
1843 rc
= do_lock(client
, TRUE
);
1848 return send_error(ctx
, rc
);
1851 static gpg_error_t
clearcache_command(assuan_context_t ctx
, gchar
*line
)
1856 if (!line
|| !*line
)
1857 rc
= cache_clear(NULL
);
1859 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, line
, strlen(line
));
1860 rc
= cache_clear(md5file
);
1863 return send_error(ctx
, rc
);
1866 static gpg_error_t
cachetimeout_command(assuan_context_t ctx
, gchar
*line
)
1870 gchar
**req
= split_input_line(line
, " ", 0);
1874 if (!req
|| !*req
|| !req
[1]) {
1876 return send_error(ctx
, GPG_ERR_SYNTAX
);
1880 timeout
= g_ascii_strtoll(req
[1], &p
, 10);
1881 if (errno
!= 0 || *p
!= 0 || timeout
< -1) {
1883 return send_error(ctx
, GPG_ERR_SYNTAX
);
1886 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[0], strlen(req
[0]));
1888 if (cache_set_timeout(md5file
, timeout
)) {
1889 MUTEX_LOCK(&rcfile_mutex
);
1890 g_key_file_set_integer(keyfileh
, req
[0], "cache_timeout", timeout
);
1891 MUTEX_UNLOCK(&rcfile_mutex
);
1894 rc
= GPG_ERR_NOT_FOUND
;
1897 return send_error(ctx
, rc
);
1900 static gpg_error_t
dump_command(assuan_context_t ctx
, gchar
*line
)
1904 struct client_s
*client
= assuan_get_pointer(ctx
);
1907 if (disable_list_and_dump
== TRUE
)
1908 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
1910 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
1913 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1914 return send_error(ctx
, GPG_ERR_ENOMEM
);
1917 pthread_cleanup_push(xmlFree
, xml
);
1918 rc
= xfer_data(ctx
, (gchar
*)xml
, len
);
1919 pthread_cleanup_pop(1);
1920 return send_error(ctx
, rc
);
1923 static gpg_error_t
getconfig_command(assuan_context_t ctx
, gchar
*line
)
1925 struct client_s
*client
= assuan_get_pointer(ctx
);
1927 gchar filename
[255]={0}, param
[747]={0};
1928 gchar
*p
, *tmp
= NULL
, *fp
= client
->filename
, *paramp
= line
;
1930 if (!line
|| !*line
)
1931 return send_error(ctx
, GPG_ERR_SYNTAX
);
1933 if (strchr(line
, ' ')) {
1934 sscanf(line
, " %254[^ ] %746c", filename
, param
);
1939 if (fp
&& !valid_filename(fp
))
1940 return send_error(ctx
, GPG_ERR_INV_VALUE
);
1942 paramp
= g_ascii_strdown(paramp
, -1);
1944 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1945 return send_error(ctx
, GPG_ERR_ENOMEM
);
1948 if (!g_strcmp0(paramp
, "cipher") && fp
) {
1949 struct crypto_s
*crypto
;
1951 rc
= init_client_crypto(&crypto
);
1953 rc
= read_data_header(fp
, &crypto
->hdr
, NULL
, NULL
);
1955 const char *t
= gcry_cipher_algo_name(cipher_to_gcrypt(crypto
->hdr
.flags
));
1961 cleanup_crypto(&crypto
);
1962 if (rc
&& gpg_err_code(rc
) != GPG_ERR_ENOENT
)
1963 return send_error(ctx
, rc
);
1969 p
= get_key_file_string(fp
? fp
: "global", paramp
);
1972 return send_error(ctx
, GPG_ERR_UNKNOWN_OPTION
);
1974 tmp
= expand_homedir(p
);
1977 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
1978 return send_error(ctx
, GPG_ERR_ENOMEM
);
1983 pthread_cleanup_push(g_free
, p
);
1984 rc
= xfer_data(ctx
, p
, strlen(p
));
1985 pthread_cleanup_pop(1);
1986 return send_error(ctx
, rc
);
1990 xmlXPathContextPtr xp
;
1991 xmlXPathObjectPtr result
;
1996 static void xpath_command_cleanup(void *arg
)
1998 struct xpath_s
*xpath
= arg
;
2003 req_cleanup(xpath
->req
);
2006 xmlBufferFree(xpath
->buf
);
2009 xmlXPathFreeObject(xpath
->result
);
2012 xmlXPathFreeContext(xpath
->xp
);
2015 static gpg_error_t
do_xpath(assuan_context_t ctx
, gchar
*line
)
2018 struct client_s
*client
= assuan_get_pointer(ctx
);
2019 struct xpath_s _x
= {0};
2020 struct xpath_s
*xpath
= &_x
;
2022 if ((xpath
->req
= split_input_line(line
, "\t", 2)) == NULL
) {
2023 if (strv_printf(&xpath
->req
, "%s", line
) == FALSE
)
2024 return GPG_ERR_ENOMEM
;
2027 xpath
->xp
= xmlXPathNewContext(client
->doc
);
2029 rc
= GPG_ERR_BAD_DATA
;
2033 xpath
->result
= xmlXPathEvalExpression((xmlChar
*)xpath
->req
[0], xpath
->xp
);
2034 if (!xpath
->result
) {
2035 rc
= GPG_ERR_BAD_DATA
;
2039 if (xmlXPathNodeSetIsEmpty(xpath
->result
->nodesetval
)) {
2040 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
2044 rc
= recurse_xpath_nodeset(client
->doc
, xpath
->result
->nodesetval
,
2045 (xmlChar
*)xpath
->req
[1], &xpath
->buf
, 0, NULL
);
2048 else if (!xpath
->req
[1] && !xmlBufferLength(xpath
->buf
)) {
2049 rc
= GPG_ERR_NO_DATA
;
2052 else if (xpath
->req
[1]) {
2057 pthread_cleanup_push(xpath_command_cleanup
, &xpath
);
2058 rc
= xfer_data(ctx
, (gchar
*)xmlBufferContent(xpath
->buf
),
2059 xmlBufferLength(xpath
->buf
));
2060 pthread_cleanup_pop(0);
2062 xpath_command_cleanup(xpath
);
2066 static gpg_error_t
xpath_command(assuan_context_t ctx
, gchar
*line
)
2068 struct client_s
*client
= assuan_get_pointer(ctx
);
2070 struct argv_s
*args
[] = {
2071 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
2075 if (disable_list_and_dump
== TRUE
)
2076 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2078 rc
= parse_options(&line
, args
, client
);
2080 return send_error(ctx
, rc
);
2082 if (client
->opts
&OPT_INQUIRE
) {
2086 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
2088 return send_error(ctx
, rc
);
2090 line
= (gchar
*)result
;
2093 if (!line
|| !*line
)
2094 rc
= GPG_ERR_SYNTAX
;
2097 rc
= do_xpath(ctx
, line
);
2099 if (client
->opts
&OPT_INQUIRE
)
2102 return send_error(ctx
, rc
);
2105 static gpg_error_t
do_xpathattr(assuan_context_t ctx
, gchar
*line
)
2107 struct client_s
*client
= assuan_get_pointer(ctx
);
2110 gboolean cmd
= FALSE
; //SET
2111 struct xpath_s _x
= {0};
2112 struct xpath_s
*xpath
= &_x
;
2114 if ((req
= split_input_line(line
, " ", 3)) == NULL
)
2115 return GPG_ERR_ENOMEM
;
2118 rc
= GPG_ERR_SYNTAX
;
2122 if (!g_ascii_strcasecmp(req
[0], "SET"))
2124 else if (!g_ascii_strcasecmp(req
[0], "DELETE"))
2127 rc
= GPG_ERR_SYNTAX
;
2131 if (!req
[1] || !req
[2]) {
2132 rc
= GPG_ERR_SYNTAX
;
2136 if ((xpath
->req
= split_input_line(req
[2], "\t", 3)) == NULL
) {
2137 rc
= GPG_ERR_ENOMEM
;
2141 if (!xpath
->req
[0] || (!xpath
->req
[1] && !cmd
) || (xpath
->req
[1] && cmd
)) {
2142 rc
= GPG_ERR_SYNTAX
;
2146 xpath
->xp
= xmlXPathNewContext(client
->doc
);
2148 rc
= GPG_ERR_BAD_DATA
;
2152 xpath
->result
= xmlXPathEvalExpression((xmlChar
*)xpath
->req
[0], xpath
->xp
);
2153 if (!xpath
->result
) {
2154 rc
= GPG_ERR_BAD_DATA
;
2158 if (xmlXPathNodeSetIsEmpty(xpath
->result
->nodesetval
)) {
2159 rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
2163 rc
= recurse_xpath_nodeset(client
->doc
, xpath
->result
->nodesetval
,
2164 (xmlChar
*)xpath
->req
[1], &xpath
->buf
, cmd
, (xmlChar
*)req
[1]);
2167 xpath_command_cleanup(xpath
);
2172 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
2173 static gpg_error_t
xpathattr_command(assuan_context_t ctx
, gchar
*line
)
2175 struct client_s
*client
= assuan_get_pointer(ctx
);
2177 struct argv_s
*args
[] = {
2178 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
2182 if (disable_list_and_dump
== TRUE
)
2183 return send_error(ctx
, GPG_ERR_NOT_IMPLEMENTED
);
2185 rc
= parse_options(&line
, args
, client
);
2187 return send_error(ctx
, rc
);
2189 if (client
->opts
&OPT_INQUIRE
) {
2193 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
2195 return send_error(ctx
, rc
);
2197 line
= (gchar
*)result
;
2200 if (!line
|| !*line
)
2201 rc
= GPG_ERR_SYNTAX
;
2204 rc
= do_xpathattr(ctx
, line
);
2206 if (client
->opts
&OPT_INQUIRE
)
2209 return send_error(ctx
, rc
);
2212 static gpg_error_t
do_import(struct client_s
*client
, guchar
*line
)
2214 gchar
**req
, **path
= NULL
, **path_orig
= NULL
, *content
;
2215 xmlDocPtr doc
= NULL
;
2216 xmlNodePtr n
, root
, copy
;
2219 req
= split_input_line((gchar
*)line
, "\t", 2);
2222 return GPG_ERR_SYNTAX
;
2225 path
= split_input_line(req
[1], "\t", 0);
2226 if (!content
|| !*content
) {
2227 rc
= GPG_ERR_SYNTAX
;
2231 if (path
&& !valid_element_path(path
, FALSE
)) {
2232 rc
= GPG_ERR_INV_VALUE
;
2236 doc
= xmlReadDoc((xmlChar
*)content
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2238 rc
= GPG_ERR_BAD_DATA
;
2242 root
= xmlDocGetRootElement(doc
);
2243 rc
= validate_import(root
);
2248 path_orig
= g_strdupv(path
);
2250 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(GPG_ERR_ENOMEM
));
2251 rc
= GPG_ERR_ENOMEM
;
2255 xmlChar
*a
= xmlGetProp(root
, (xmlChar
*)"_name");
2257 g_strfreev(path_orig
);
2258 rc
= GPG_ERR_ENOMEM
;
2262 if (strv_printf(&path
, "%s", (gchar
*)a
) == FALSE
) {
2264 g_strfreev(path_orig
);
2265 rc
= GPG_ERR_ENOMEM
;
2270 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, FALSE
);
2272 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
2273 g_strfreev(path_orig
);
2278 n
= find_elements(client
->doc
, n
->children
, path
+1, &rc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, TRUE
);
2280 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
2281 g_strfreev(path_orig
);
2285 xmlNodePtr parent
= n
->parent
;
2296 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
) {
2297 n
= create_element_path(client
, &path
, &rc
, NULL
);
2303 copy
= xmlCopyNodeList(root
);
2304 n
= xmlAddChildList(n
, copy
);
2306 rc
= GPG_ERR_BAD_DATA
;
2309 /* Check if the content root element can create a DTD root element. */
2310 if (!xmlStrEqual((xmlChar
*)"element", root
->name
)) {
2311 rc
= GPG_ERR_SYNTAX
;
2317 if ((a
= xmlGetProp(root
, (xmlChar
*)"_name")) == NULL
) {
2318 rc
= GPG_ERR_SYNTAX
;
2322 gchar
*tmp
= g_strdup((gchar
*)a
);
2324 gboolean literal
= is_literal_element(&tmp
);
2326 if (!valid_xml_element((xmlChar
*)tmp
) || literal
) {
2328 rc
= GPG_ERR_INV_VALUE
;
2332 if (strv_printf(&path
, "%s", tmp
) == FALSE
) {
2334 rc
= GPG_ERR_ENOMEM
;
2339 n
= find_root_element(client
->doc
, &path
, &rc
, NULL
, 0, TRUE
);
2341 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
2342 rc
= GPG_ERR_BAD_DATA
;
2346 /* Overwriting the existing tree. */
2353 xmlSetProp(root
, (xmlChar
*)"_name", (xmlChar
*)path
[0]);
2354 n
= xmlCopyNode(root
, 1);
2355 n
= xmlAddChildList(xmlDocGetRootElement(client
->doc
), n
);
2359 rc
= update_element_mtime(n
->parent
);
2372 static gpg_error_t
import_command(assuan_context_t ctx
, gchar
*line
)
2375 struct client_s
*client
= assuan_get_pointer(ctx
);
2379 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
2381 return send_error(ctx
, rc
);
2383 rc
= do_import(client
, result
);
2384 return send_error(ctx
, rc
);
2387 static gpg_error_t
do_lock(struct client_s
*client
, gboolean add
)
2389 gpg_error_t rc
= lock_file_mutex(client
, add
);
2392 client
->flags
|= FLAG_LOCK_CMD
;
2397 static gpg_error_t
lock_command(assuan_context_t ctx
, gchar
*line
)
2399 struct client_s
*client
= assuan_get_pointer(ctx
);
2400 gpg_error_t rc
= do_lock(client
, FALSE
);
2402 return send_error(ctx
, rc
);
2405 static gpg_error_t
unlock_command(assuan_context_t ctx
, gchar
*line
)
2407 struct client_s
*client
= assuan_get_pointer(ctx
);
2410 rc
= unlock_file_mutex(client
, FALSE
);
2411 return send_error(ctx
, rc
);
2414 static gpg_error_t
option_command(assuan_context_t ctx
, const gchar
*name
,
2417 struct client_s
*client
= assuan_get_pointer(ctx
);
2418 struct agent_s
*agent
= client
->crypto
->agent
;
2421 log_write1("OPTION name='%s' value='%s'", name
, value
);
2423 if (g_ascii_strcasecmp(name
, (gchar
*)"log_level") == 0) {
2427 l
= strtol(value
, NULL
, 10);
2430 return gpg_error(GPG_ERR_INV_VALUE
);
2433 MUTEX_LOCK(&rcfile_mutex
);
2434 g_key_file_set_integer(keyfileh
, "global", "log_level", (gint
)l
);
2435 MUTEX_UNLOCK(&rcfile_mutex
);
2438 else if (g_ascii_strcasecmp(name
, (gchar
*)"rc_on_locked") == 0) {
2442 l
= strtol(value
, NULL
, 10);
2445 return gpg_error(GPG_ERR_INV_VALUE
);
2449 client
->flags
|= FLAG_RC_ON_LOCKED
;
2451 client
->flags
&= ~(FLAG_RC_ON_LOCKED
);
2454 else if (g_ascii_strcasecmp(name
, (gchar
*)"NAME") == 0) {
2455 gchar
*tmp
= pthread_getspecific(thread_name_key
);
2460 if (!value
|| !*value
) {
2461 pthread_setspecific(thread_name_key
, g_strdup(""));
2465 pthread_setspecific(thread_name_key
, g_strdup(value
));
2468 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc-messages") == 0) {
2469 rc
= set_agent_option(client
->crypto
->agent
, "lc-messages", value
);
2471 g_free(agent
->lc_messages
);
2472 agent
->lc_messages
= g_strdup(value
);
2475 else if (g_ascii_strcasecmp(name
, (gchar
*)"lc-ctype") == 0) {
2476 rc
= set_agent_option(client
->crypto
->agent
, "lc-ctype", value
);
2478 g_free(agent
->lc_ctype
);
2479 agent
->lc_ctype
= g_strdup(value
);
2482 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttyname") == 0) {
2483 rc
= set_agent_option(client
->crypto
->agent
, "ttyname", value
);
2485 g_free(agent
->ttyname
);
2486 agent
->ttyname
= g_strdup(value
);
2489 else if (g_ascii_strcasecmp(name
, (gchar
*)"ttytype") == 0) {
2490 rc
= set_agent_option(client
->crypto
->agent
, "ttytype", value
);
2492 g_free(agent
->ttytype
);
2493 agent
->ttytype
= g_strdup(value
);
2496 else if (g_ascii_strcasecmp(name
, (gchar
*)"display") == 0) {
2497 rc
= set_agent_option(client
->crypto
->agent
, "display", value
);
2499 g_free(agent
->display
);
2500 agent
->display
= g_strdup(value
);
2503 else if (g_ascii_strcasecmp(name
, (gchar
*)"desc") == 0) {
2504 if (client
->crypto
->agent
->desc
)
2505 g_free(client
->crypto
->agent
->desc
);
2507 client
->crypto
->agent
->desc
= g_strdup(value
);
2508 if (!client
->crypto
->agent
->desc
)
2509 rc
= GPG_ERR_ENOMEM
;
2512 else if (g_ascii_strcasecmp(name
, "pinentry_timeout") == 0) {
2519 n
= strtol(value
, &p
, 10);
2522 return gpg_error(GPG_ERR_INV_VALUE
);
2524 MUTEX_LOCK(&rcfile_mutex
);
2525 g_key_file_set_integer(keyfileh
, client
->filename
? client
->filename
:
2526 "global", "pinentry_timeout", n
);
2527 MUTEX_UNLOCK(&rcfile_mutex
);
2532 return gpg_error(GPG_ERR_UNKNOWN_OPTION
);
2538 static gpg_error_t
do_rename(assuan_context_t ctx
, gchar
*line
)
2540 struct client_s
*client
= assuan_get_pointer(ctx
);
2542 gchar
**req
, **src
, *dst
;
2545 req
= split_input_line(line
, " ", -1);
2547 if (!req
|| !req
[0] || !req
[1]) {
2549 return GPG_ERR_SYNTAX
;
2553 is_literal_element(&dst
);
2555 if (!valid_xml_element((xmlChar
*)dst
)) {
2557 return GPG_ERR_INV_VALUE
;
2560 if (strchr(req
[0], '\t'))
2561 src
= split_input_line(req
[0], "\t", -1);
2563 src
= split_input_line(req
[0], " ", -1);
2565 if (!src
|| !*src
) {
2566 rc
= GPG_ERR_SYNTAX
;
2570 n
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
2572 n
= find_elements(client
->doc
, n
->children
, src
+1, &rc
, NULL
, NULL
,
2573 NULL
, FALSE
, 0, NULL
, FALSE
);
2578 xmlChar
*a
= xmlGetProp(n
, (xmlChar
*)"_name");
2580 rc
= GPG_ERR_ENOMEM
;
2584 /* To prevent unwanted effects:
2586 * <root name="a"><b/></root>
2590 if (xmlStrEqual(a
, (xmlChar
*)dst
)) {
2592 rc
= GPG_ERR_AMBIGUOUS_NAME
;
2601 for (p
= src
; *p
; p
++) {
2604 strv_printf(&tmp
, "%s", *p
);
2608 strv_printf(&tmp
, "!%s", dst
);
2609 ndst
= find_root_element(client
->doc
, &tmp
, &rc
, NULL
, 0, FALSE
);
2610 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
) {
2616 ndst
= find_elements(client
->doc
, ndst
->children
, tmp
+1, &rc
, NULL
,
2617 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2620 if (!ndst
&& rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
2625 /* Target may exist:
2628 * <root name="b" target="a"/>
2636 rc
= GPG_ERR_AMBIGUOUS_NAME
;
2642 xmlFreeNodeList(ndst
);
2645 rc
= add_attribute(n
, "_name", dst
);
2653 static gpg_error_t
rename_command(assuan_context_t ctx
, gchar
*line
)
2655 struct client_s
*client
= assuan_get_pointer(ctx
);
2657 struct argv_s
*args
[] = {
2658 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
2662 rc
= parse_options(&line
, args
, client
);
2664 return send_error(ctx
, rc
);
2666 if (client
->opts
&OPT_INQUIRE
) {
2670 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
2672 return send_error(ctx
, rc
);
2674 line
= (gchar
*)result
;
2677 rc
= do_rename(ctx
, line
);
2679 if (client
->opts
&OPT_INQUIRE
)
2682 return send_error(ctx
, rc
);
2685 static gpg_error_t
do_copy(assuan_context_t ctx
, gchar
*line
)
2687 struct client_s
*client
= assuan_get_pointer(ctx
);
2689 gchar
**req
, **src
= NULL
, **dst
= NULL
;
2690 xmlNodePtr nsrc
, ndst
, new = NULL
;
2692 req
= split_input_line(line
, " ", -1);
2693 if (!req
|| !req
[0] || !req
[1]) {
2695 return GPG_ERR_SYNTAX
;
2698 if (strchr(req
[0], '\t'))
2699 src
= split_input_line(req
[0], "\t", -1);
2701 src
= split_input_line(req
[0], " ", -1);
2703 if (!src
|| !*src
) {
2704 rc
= GPG_ERR_SYNTAX
;
2708 if (strchr(req
[1], '\t'))
2709 dst
= split_input_line(req
[1], "\t", -1);
2711 dst
= split_input_line(req
[1], " ", -1);
2713 if (!dst
|| !*dst
) {
2714 rc
= GPG_ERR_SYNTAX
;
2718 if (!valid_element_path(dst
, FALSE
)) {
2719 rc
= GPG_ERR_INV_VALUE
;
2723 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
2725 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
2726 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2731 new = xmlCopyNodeList(nsrc
);
2733 rc
= GPG_ERR_ENOMEM
;
2737 gboolean create
= FALSE
;
2738 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
2739 if (ndst
&& dst
[1]) {
2741 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
2742 NULL
, create_target_elements_cb
, FALSE
, 0, NULL
, FALSE
);
2749 if (!ndst
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
2752 ndst
= create_element_path(client
, &dst
, &rc
, NULL
);
2757 /* Merge any attributes from the src node to the initial dst node. */
2758 for (xmlAttrPtr attr
= new->properties
; attr
; attr
= attr
->next
) {
2759 if (xmlStrEqual(attr
->name
, (xmlChar
*)"_name"))
2762 xmlAttrPtr a
= xmlHasProp(ndst
, attr
->name
);
2766 xmlChar
*tmp
= xmlNodeGetContent(attr
->children
);
2767 xmlNewProp(ndst
, attr
->name
, tmp
);
2769 rc
= add_attribute(ndst
, NULL
, NULL
);
2772 xmlNodePtr n
= ndst
->children
;
2775 ndst
->children
= NULL
;
2777 if (new->children
) {
2778 n
= xmlCopyNodeList(new->children
);
2780 rc
= GPG_ERR_ENOMEM
;
2784 n
= xmlAddChildList(ndst
, n
);
2786 rc
= GPG_ERR_ENOMEM
;
2790 rc
= update_element_mtime(xmlDocGetRootElement(client
->doc
) ==
2791 ndst
->parent
? ndst
: ndst
->parent
);
2797 xmlFreeNodeList(new);
2812 static gpg_error_t
copy_command(assuan_context_t ctx
, gchar
*line
)
2814 struct client_s
*client
= assuan_get_pointer(ctx
);
2816 struct argv_s
*args
[] = {
2817 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
2821 rc
= parse_options(&line
, args
, client
);
2823 return send_error(ctx
, rc
);
2825 if (client
->opts
&OPT_INQUIRE
) {
2829 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
2831 return send_error(ctx
, rc
);
2833 line
= (gchar
*)result
;
2836 rc
= do_copy(ctx
, line
);
2838 if (client
->opts
&OPT_INQUIRE
)
2841 return send_error(ctx
, rc
);
2844 static gpg_error_t
do_move(assuan_context_t ctx
, gchar
*line
)
2846 struct client_s
*client
= assuan_get_pointer(ctx
);
2848 gchar
**req
, **src
= NULL
, **dst
= NULL
;
2849 xmlNodePtr nsrc
, ndst
= NULL
;
2851 req
= split_input_line(line
, " ", -1);
2853 if (!req
|| !req
[0] || !req
[1]) {
2855 return GPG_ERR_SYNTAX
;
2858 if (strchr(req
[0], '\t'))
2859 src
= split_input_line(req
[0], "\t", -1);
2861 src
= split_input_line(req
[0], " ", -1);
2863 if (!src
|| !*src
) {
2864 rc
= GPG_ERR_SYNTAX
;
2868 if (strchr(req
[1], '\t'))
2869 dst
= split_input_line(req
[1], "\t", -1);
2871 dst
= split_input_line(req
[1], " ", -1);
2873 nsrc
= find_root_element(client
->doc
, &src
, &rc
, NULL
, 0, FALSE
);
2875 nsrc
= find_elements(client
->doc
, nsrc
->children
, src
+1, &rc
, NULL
,
2876 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2882 if (!valid_element_path(dst
, FALSE
)) {
2883 rc
= GPG_ERR_INV_VALUE
;
2887 ndst
= find_root_element(client
->doc
, &dst
, &rc
, NULL
, 0, FALSE
);
2889 ndst
= find_elements(client
->doc
, ndst
->children
, dst
+1, &rc
, NULL
,
2890 NULL
, NULL
, FALSE
, 0, NULL
, FALSE
);
2893 ndst
= xmlDocGetRootElement(client
->doc
);
2895 for (xmlNodePtr n
= ndst
; n
; n
= n
->parent
) {
2897 rc
= GPG_ERR_CONFLICT
;
2902 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
2908 xmlChar
*a
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
2909 xmlNodePtr dup
= find_element(ndst
->children
, (gchar
*)a
, NULL
);
2916 if (ndst
== xmlDocGetRootElement(client
->doc
)) {
2917 xmlNodePtr n
= nsrc
;
2918 gboolean match
= FALSE
;
2920 while (n
->parent
&& n
->parent
!= ndst
)
2923 xmlChar
*a
= node_has_attribute(n
, (xmlChar
*)"_name");
2924 xmlChar
*b
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
2926 if (xmlStrEqual(a
, b
)) {
2928 xmlUnlinkNode(nsrc
);
2938 xmlFreeNodeList(dup
);
2947 xmlChar
*name
= node_has_attribute(nsrc
, (xmlChar
*)"_name");
2949 if (nsrc
->parent
== xmlDocGetRootElement(client
->doc
)
2950 && !g_strcmp0((gchar
*)name
, *dst
)) {
2952 rc
= GPG_ERR_CONFLICT
;
2957 ndst
= create_element_path(client
, &dst
, &rc
, nsrc
);
2963 update_element_mtime(nsrc
->parent
);
2964 xmlUnlinkNode(nsrc
);
2965 ndst
= xmlAddChildList(ndst
, nsrc
);
2968 rc
= GPG_ERR_ENOMEM
;
2970 update_element_mtime(ndst
->parent
);
2985 static gpg_error_t
move_command(assuan_context_t ctx
, gchar
*line
)
2987 struct client_s
*client
= assuan_get_pointer(ctx
);
2989 struct argv_s
*args
[] = {
2990 &(struct argv_s
) { "inquire", OPTION_TYPE_NOARG
, parse_opt_inquire
},
2994 rc
= parse_options(&line
, args
, client
);
2996 return send_error(ctx
, rc
);
2998 if (client
->opts
&OPT_INQUIRE
) {
3002 rc
= assuan_inquire(ctx
, "DATA", &result
, &len
, 0);
3004 return send_error(ctx
, rc
);
3006 line
= (gchar
*)result
;
3009 rc
= do_move(ctx
, line
);
3011 if (client
->opts
&OPT_INQUIRE
)
3014 return send_error(ctx
, rc
);
3017 static gpg_error_t
ls_command(assuan_context_t ctx
, gchar
*line
)
3020 gchar
*tmp
= g_key_file_get_string(keyfileh
, "global", "data_directory", NULL
);
3021 gchar
*dir
= expand_homedir(tmp
);
3022 DIR *d
= opendir(dir
);
3024 rc
= gpg_error_from_syserror();
3029 return send_error(ctx
, rc
);
3032 size_t len
= offsetof(struct dirent
, d_name
)+pathconf(dir
, _PC_NAME_MAX
)+1;
3033 struct dirent
*p
= g_malloc(len
), *cur
= NULL
;
3039 while (!readdir_r(d
, p
, &cur
) && cur
) {
3040 if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '\0')
3042 else if (cur
->d_name
[0] == '.' && cur
->d_name
[1] == '.' && cur
->d_name
[2] == '\0')
3045 tmp
= g_strdup_printf("%s%s\n", list
? list
: "", cur
->d_name
);
3051 rc
= GPG_ERR_ENOMEM
;
3063 return send_error(ctx
, rc
);
3066 return send_error(ctx
, GPG_ERR_NO_DATA
);
3068 list
[strlen(list
)-1] = 0;
3069 rc
= xfer_data(ctx
, list
, strlen(list
));
3071 return send_error(ctx
, rc
);
3074 static gpg_error_t
bye_notify(assuan_context_t ctx
, gchar
*line
)
3076 struct client_s
*cl
= assuan_get_pointer(ctx
);
3078 /* This will let assuan_process_next() return. */
3079 fcntl(cl
->thd
->fd
, F_SETFL
, O_NONBLOCK
);
3080 cl
->last_rc
= 0; // BYE command result
3084 static gpg_error_t
reset_notify(assuan_context_t ctx
, gchar
*line
)
3086 struct client_s
*client
= assuan_get_pointer(ctx
);
3089 cleanup_client(client
);
3095 * This is called before every Assuan command.
3097 static gpg_error_t
command_startup(assuan_context_t ctx
, const gchar
*name
)
3099 struct client_s
*client
= assuan_get_pointer(ctx
);
3101 struct command_table_s
*cmd
= NULL
;
3103 log_write1("command='%s'", name
);
3104 client
->last_rc
= client
->opts
= 0;
3106 for (int i
= 0; command_table
[i
]; i
++) {
3107 if (!g_ascii_strcasecmp(name
, command_table
[i
]->name
)) {
3108 if (command_table
[i
]->ignore_startup
)
3110 cmd
= command_table
[i
];
3115 client
->last_rc
= rc
= gpg_error(file_modified(client
, cmd
));
3120 * This is called after every Assuan command.
3122 static void command_finalize(assuan_context_t ctx
, gpg_error_t rc
)
3124 struct client_s
*client
= assuan_get_pointer(ctx
);
3126 if (!(client
->flags
&FLAG_LOCK_CMD
))
3127 unlock_file_mutex(client
, FALSE
);
3129 log_write1(_("command completed: rc=%u"), client
->last_rc
);
3130 client
->last_rc
= gpg_error(GPG_ERR_UNKNOWN_COMMAND
);
3133 static gpg_error_t
help_command(assuan_context_t ctx
, gchar
*line
)
3138 if (!line
|| !*line
) {
3140 gchar
*help
= g_strdup(_(
3141 "Usage: HELP [<COMMAND>]\n"
3142 "For commands that take an element path as an argument, each element is "
3143 "separated with an ASCII @key{TAB} character (ASCII 0x09)."
3147 for (i
= 0; command_table
[i
]; i
++) {
3148 if (!command_table
[i
]->help
)
3151 tmp
= g_strdup_printf("%s %s", help
, command_table
[i
]->name
);
3156 tmp
= strip_texi_and_wrap(help
);
3158 rc
= xfer_data(ctx
, tmp
, strlen(tmp
));
3160 return send_error(ctx
, rc
);
3163 for (i
= 0; command_table
[i
]; i
++) {
3164 if (!g_strcasecmp(line
, command_table
[i
]->name
)) {
3167 if (!command_table
[i
]->help
)
3170 help
= strip_texi_and_wrap(command_table
[i
]->help
);
3171 tmp
= g_strdup_printf(_("Usage: %s"), help
);
3173 rc
= xfer_data(ctx
, tmp
, strlen(tmp
));
3175 return send_error(ctx
, rc
);
3179 return send_error(ctx
, GPG_ERR_INV_NAME
);
3182 static void new_command(const gchar
*name
, gboolean ignore
, gboolean unlock
,
3183 gpg_error_t (*handler
)(assuan_context_t
, gchar
*), const gchar
*help
)
3188 for (i
= 0; command_table
[i
]; i
++);
3190 command_table
= g_realloc(command_table
, (i
+2)*sizeof(struct command_table_s
*));
3191 command_table
[i
] = g_malloc0(sizeof(struct command_table_s
));
3192 command_table
[i
]->name
= name
;
3193 command_table
[i
]->handler
= handler
;
3194 command_table
[i
]->ignore_startup
= ignore
;
3195 command_table
[i
]->unlock
= unlock
;
3196 command_table
[i
++]->help
= help
;
3197 command_table
[i
] = NULL
;
3200 void deinit_commands()
3204 for (i
= 0; command_table
[i
]; i
++)
3205 g_free(command_table
[i
]);
3207 g_free(command_table
);
3210 static gint
sort_commands(const void *arg1
, const void *arg2
)
3212 struct command_table_s
* const *a
= arg1
;
3213 struct command_table_s
* const *b
= arg2
;
3222 return g_strcmp0((*a
)->name
, (*b
)->name
);
3225 static gpg_error_t
passwd_command(assuan_context_t ctx
, gchar
*line
)
3227 struct client_s
*client
= assuan_get_pointer(ctx
);
3229 struct argv_s
*args
[] = {
3230 &(struct argv_s
) { "reset", OPTION_TYPE_NOARG
, parse_opt_reset
},
3231 &(struct argv_s
) { "s2k-count", OPTION_TYPE_ARG
, parse_opt_s2k_count
},
3235 if (client
->flags
&FLAG_NEW
)
3236 return send_error(ctx
, GPG_ERR_INV_STATE
);
3238 client
->crypto
->save
.s2k_count
= get_key_file_ulong(client
->filename
, "s2k_count");
3239 rc
= parse_options(&line
, args
, client
);
3241 return send_error(ctx
, rc
);
3243 if (!rc
&& client
->opts
&OPT_RESET
)
3244 rc
= cache_clear(client
->md5file
);
3247 if (client
->crypto
->save
.s2k_count
)
3248 rc
= send_to_agent(client
->crypto
->agent
, NULL
, NULL
,
3249 "OPTION s2k-count=%lu", client
->crypto
->save
.s2k_count
);
3252 rc
= agent_passwd(client
->crypto
);
3255 return send_error(ctx
, rc
);
3258 static gpg_error_t
parse_keygrip_opt_sign(gpointer data
, gpointer value
)
3260 struct client_s
*client
= data
;
3263 client
->opts
|= OPT_SIGN
;
3267 static gpg_error_t
keygrip_command(assuan_context_t ctx
, gchar
*line
)
3269 struct client_s
*client
= assuan_get_pointer(ctx
);
3271 struct crypto_s
*crypto
;
3272 struct argv_s
*args
[] = {
3273 &(struct argv_s
) { "sign", OPTION_TYPE_NOARG
, parse_keygrip_opt_sign
},
3277 if (!line
|| !*line
)
3278 return send_error(ctx
, GPG_ERR_SYNTAX
);
3280 rc
= parse_options(&line
, args
, client
);
3282 return send_error(ctx
, rc
);
3284 if (!valid_filename(line
))
3285 return send_error(ctx
, GPG_ERR_INV_VALUE
);
3287 rc
= init_client_crypto(&crypto
);
3289 return send_error(ctx
, rc
);
3291 rc
= read_data_file(line
, crypto
);
3293 gchar
*hexgrip
= NULL
;
3295 if (client
->opts
&OPT_SIGN
) {
3296 if (valid_keygrip(crypto
->sign_grip
, sizeof(crypto
->sign_grip
)))
3297 hexgrip
= bin2hex(crypto
->sign_grip
, sizeof(crypto
->sign_grip
));
3301 hexgrip
= bin2hex(crypto
->grip
, sizeof(crypto
->grip
));
3304 rc
= GPG_ERR_ENOMEM
;
3306 rc
= xfer_data(ctx
, hexgrip
, strlen(hexgrip
));
3311 cleanup_crypto(&crypto
);
3312 return send_error(ctx
, rc
);
3315 static gpg_error_t
getinfo_command(assuan_context_t ctx
, gchar
*line
)
3317 struct client_s
*client
= assuan_get_pointer(ctx
);
3320 if (!g_ascii_strcasecmp(line
, "clients"))
3321 rc
= send_status(ctx
, STATUS_CLIENTS
, NULL
);
3322 else if (!g_ascii_strcasecmp(line
, "cache"))
3323 rc
= send_status(ctx
, STATUS_CACHE
, NULL
);
3324 else if (!g_ascii_strcasecmp(line
, "pid")) {
3326 pid_t pid
= getpid();
3328 print_fmt(buf
, sizeof(buf
), "%i", pid
);
3329 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3331 else if (!g_ascii_strcasecmp(line
, "version")) {
3332 gchar
*buf
= g_strdup_printf("0x%X %s", VERSION_HEX
,
3337 rc
= xfer_data(ctx
, buf
, strlen(buf
));
3340 else if (!g_ascii_strcasecmp(line
, "last_error")) {
3341 if (client
->last_error
)
3342 rc
= xfer_data(ctx
, client
->last_error
, strlen(client
->last_error
));
3344 rc
= GPG_ERR_NO_DATA
;
3347 rc
= gpg_error(GPG_ERR_SYNTAX
);
3349 return send_error(ctx
, rc
);
3352 static gpg_error_t
send_data_cb(gpointer user
, const void *buf
, size_t len
)
3354 assuan_context_t ctx
= user
;
3356 return assuan_send_data(ctx
, buf
, len
);
3359 static gpg_error_t
send_status_cb(gpointer user
, const gchar
*line
)
3361 assuan_context_t ctx
= user
;
3362 gchar keyword
[200], *k
;
3365 for (p
= line
, k
= keyword
; *p
; p
++) {
3366 if (g_ascii_isspace(*p
))
3376 while (*p
&& g_ascii_isspace(*p
))
3379 return assuan_write_status(ctx
, keyword
, *p
? p
: NULL
);
3382 static gpg_error_t
agent_command(assuan_context_t ctx
, gchar
*line
)
3385 struct client_s
*client
= assuan_get_pointer(ctx
);
3387 if (!line
|| !*line
)
3388 return send_error(ctx
, GPG_ERR_SYNTAX
);
3390 assuan_set_flag(client
->crypto
->agent
->ctx
, ASSUAN_CONVEY_COMMENTS
, 1);
3391 rc
= assuan_transact(client
->crypto
->agent
->ctx
, line
, send_data_cb
,
3392 client
->ctx
, agent_loopback_cb
, client
->crypto
, send_status_cb
,
3394 if (gpg_err_code(rc
) == GPG_ERR_ASS_CANCELED
) {
3398 rc
= assuan_write_line(client
->crypto
->agent
->ctx
, "CAN");
3400 rc
= assuan_read_line(client
->crypto
->agent
->ctx
, &line
, &len
);
3402 rc
= gpg_error(GPG_ERR_ASS_CANCELED
);
3406 assuan_set_flag(client
->crypto
->agent
->ctx
, ASSUAN_CONVEY_COMMENTS
, 0);
3407 return send_error(ctx
, rc
);
3410 void init_commands()
3412 /* !BEGIN-HELP-TEXT!
3414 * This comment is used as a marker to generate the offline documentation
3415 * for commands found in doc/COMMANDS.
3417 new_command("HELP", TRUE
, TRUE
, help_command
, _(
3418 "HELP [<COMMAND>]\n"
3419 " Show available commands or command specific help text."
3422 new_command("AGENT", TRUE
, TRUE
, agent_command
, _(
3424 "Send a @command{gpg-agent} protocol @var{command} directly to the "
3425 "@command{gpg-agent}."
3427 new_command("GETINFO", TRUE
, TRUE
, getinfo_command
, _(
3428 "GETINFO CACHE | CLIENTS | PID | LAST_ERROR | VERSION\n"
3429 "Get server and other information: @var{cache} returns the number of cached "
3430 "documents via a status message. @var{clients} returns the number of "
3431 "connected clients via a status message. @var{pid} returns the process ID "
3432 "number of the server via a data response. @var{VERSION} returns the server "
3433 "version number and compile-time features with a data response with each "
3434 "being space delimited. @var{LAST_ERROR} returns a detailed description of "
3435 "the last failed command when available. @xref{Status Messages}."
3438 new_command("PASSWD", FALSE
, FALSE
, passwd_command
, _(
3439 "PASSWD [--reset] [--s2k-count=N]\n"
3440 "Changes the passphrase of the secret key required to open the current "
3441 "file. When the @option{--reset} option is passed then the cache entry for "
3442 "the current file will be reset and the passphrase, if any, will be required "
3443 "during the next @code{OPEN}. @xref{OPEN}."
3445 "The @option{--s2k-count} option sets number of hash iterations for a "
3446 "passphrase and must be either @code{0} to use the calibrated count of the "
3447 "machine (the default), or a value greater than or equal to @code{65536}. "
3451 new_command("KEYGRIP", TRUE
, TRUE
, keygrip_command
, _(
3452 "KEYGRIP [--sign] <filename>\n"
3453 "Returns the hex encoded keygrip of the specified @var{filename} with a "
3456 "When the @option{--sign} option is specified then the key used for signing "
3457 "of the specified @var{filename} will be returned."
3460 new_command("OPEN", TRUE
, TRUE
, open_command
, _(
3461 "OPEN [--lock] [--no-pinentry] <filename> [<passphrase>]\n"
3462 "Opens @var{filename} using @var{passphrase}. When the filename is not "
3463 "found on the file-system then a new document will be created. If the file "
3464 "is found, it is looked for in the file cache. If cached and no "
3465 "@var{passphrase} was specified then the cached document is opened. When not "
3466 "cached, @cite{pinentry(1)} will be used to retrieve the passphrase to use "
3467 "for decryption unless @option{--no-pinentry} was specified (see below)."
3469 "When the @option{--lock} option is passed then the file mutex will be "
3470 "locked as if the @code{LOCK} command (@pxref{LOCK}) had been sent after the "
3471 "file has been opened."
3473 "By default, a pinentry is used to retrieve a passphrase when required. "
3474 "Passing @option{--no-pinentry} will disable pinentry use for the rest of "
3475 "the session. When pinentry use is disabled but required for some operation"
3476 "then a server @emph{INQUIRE} will be send to the client to retrieve the "
3477 "passphrase. See the @code{OPTION} command (@pxref{OPTION}), for pinentry "
3481 new_command("SAVE", FALSE
, FALSE
, save_command
, _(
3482 "SAVE [--no-passphrase] [--reset] [--s2k-count=N] [--cipher=<algo>] [--inquire-keyparam] [--keygrip=hexstring [--sign-keygrip=hexstring]]\n"
3483 "Writes the @abbr{XML} document to disk. The file written to is the file that "
3484 "was opened using the @code{OPEN} command (@pxref{OPEN}). If the file is a "
3485 "new one or the option @option{--inquire-keyparam} was passed, then a new "
3486 "keypair will be generated and a pinentry will be used to prompt for the "
3487 "passphrase to encrypt with unless the @option{--no-passphrase} option was "
3488 "passed, in which case the data file will not be passphrase protected."
3490 "The @option{--reset} option will clear the cache entry for the current file "
3493 "The @option{--cipher} option can be used to encrypt the @abbr{XML} data to "
3494 "an alternate cipher. The default is @code{aes256}. See the Configuration "
3495 "(@pxref{Configuration}) for available ciphers."
3497 "The @option{--inquire-keyparam} option will send a server @emph{INQUIRE} to "
3498 "the client to obtain the key paramaters to use when generating a new "
3499 "keypair. The inquired data is expected to be an S-expression. If not "
3500 "specified then an @samp{RSA} key of @samp{2048} bits will be generated "
3501 "unless otherwise set in the configuration file (@pxref{Configuration}). Note "
3502 "that when this option is specified a new keypair will be generated "
3503 "reguardless if the file is a new one or not."
3505 "You can encrypt the data file to a public key other than the one that it "
3506 "was originally encrypted with by passing the @option{--keygrip} option with "
3507 "the hex encoded keygrip of the public key as its argument. The keygrip may "
3508 "be of any key that @command{gpg-agent} knows about. The "
3509 "@option{--sign-keygrip} option may also be used to sign with an alternate "
3510 "secret key. This option may be needed when using a smartcard."
3512 "The @option{--s2k-count} option sets number of hash iterations for a "
3513 "passphrase. A value less-than @code{65536} will use the machine calibrated "
3514 "value which is the default. This setting only affects new files. To change "
3515 "the setting, use the @code{PASSWD} command (@pxref{PASSWD})."
3518 new_command("ISCACHED", TRUE
, FALSE
, iscached_command
, _(
3519 "ISCACHED [--lock] <filename>\n"
3520 "An @emph{OK} response is returned if the specified @var{filename} is found "
3521 "in the file cache. If not found in the cache but exists on the filesystem "
3522 "then @var{GPG_ERR_NO_DATA} is returned. Otherwise a filesystem error is "
3525 "The @option{lock} option will lock the file mutex of @var{filename} when the "
3526 "file exists; it does not need to be opened nor cached."
3529 new_command("CLEARCACHE", TRUE
, TRUE
, clearcache_command
, _(
3530 "CLEARCACHE [<filename>]\n"
3531 "Clears a file cache entry or all or the specified @var{filename}. Always "
3532 "returns an @emph{OK} response."
3535 new_command("CACHETIMEOUT", TRUE
, TRUE
, cachetimeout_command
, _(
3536 "CACHETIMEOUT <filename> <seconds>\n"
3537 "The time in @var{seconds} until @var{filename} will be removed from the "
3538 "cache. @code{-1} will keep the cache entry forever, @code{0} will require "
3539 "the passphrase for each @code{OPEN} command (@pxref{OPEN}). "
3540 "@xref{Configuration}, and the @code{cache_timeout} parameter."
3543 new_command("LIST", FALSE
, TRUE
, list_command
, _(
3544 "LIST [--inquire] [--no-recurse] [--verbose] [--all] [[!]element[<TAB>[!]child[..]]]\n"
3545 "If no element path is given then a newline separated list of root elements "
3546 "is returned with a data response. If given, then all reachable elements "
3547 "of the specified element path are returned unless the @option{--no-recurse} "
3548 "option is specified. If specified, only the child elements of the element "
3549 "path are returned without recursing into grandchildren. Each resulting "
3550 "element is prefixed with the literal @code{!} character when the element "
3551 "contains no @code{target} attribute. @xref{Target Attribute}, for details."
3553 "When the @option{--verbose} option is passed then each element path "
3554 "returned will have a single space character followed by either a "
3555 "@code{0} or @code{1} appended to it. When @code{0}, the element path has no "
3556 "child elements, otherwise it does. When used with the @option{--no-recurse} "
3557 "option this may be useful to limit the amount of data transferred to the "
3560 "The @option{--all} option lists the entire element tree for all root "
3563 "When the @option{--inquire} option is passed then all remaining non-option "
3564 "arguments are retrieved via a server @emph{INQUIRE}."
3567 new_command("REALPATH", FALSE
, TRUE
, realpath_command
, _(
3568 "REALPATH [--inquire] [!]element[<TAB>[!]child[..]]\n"
3569 "Resolves all @code{target} attributes of the specified element path and "
3570 "returns the result with a data response. @xref{Target Attribute}, for details."
3572 "When the @option{--inquire} option is passed then all remaining non-option "
3573 "arguments are retrieved via a server @emph{INQUIRE}."
3576 new_command("STORE", FALSE
, TRUE
, store_command
, _(
3577 "STORE [!]element[<TAB>[!]child[..]]<TAB>[content]\n"
3578 "This command uses a server @emph{INQUIRE} to retrieve data from the client."
3580 "Creates a new element path or modifies the @var{content} of an existing "
3581 "element. If only a single element is specified then a new root element is "
3582 "created. Otherwise, elements are @key{TAB} delimited and the content will be "
3583 "set to the final @key{TAB} delimited element. If no @var{content} is "
3584 "specified after the final @key{TAB}, then the content of the element will "
3585 "be removed, or empty when creating a new element."
3587 "The only restriction of an element name is that it not contain whitespace "
3588 "or begin with the literal element character @code{!} unless specifying a "
3589 "literal element (@pxref{Target Attribute}). There is no whitespace between "
3590 "the @key{TAB} delimited elements. It is recommended that the content of an "
3591 "element be base64 encoded when it contains control or @key{TAB} characters "
3592 "to prevent @abbr{XML} and @command{pwmd} parsing errors."
3595 new_command("RENAME", FALSE
, TRUE
, rename_command
, _(
3596 "RENAME [--inquire] [!]element[<TAB>[!]child[..]] <value>\n"
3597 "Renames the specified @var{element} to the new @var{value}. If an element of "
3598 "the same name as the @var{value} already exists it will be overwritten."
3600 "When the @option{--inquire} option is passed then all remaining non-option "
3601 "arguments are retrieved via a server @emph{INQUIRE}."
3604 new_command("COPY", FALSE
, TRUE
, copy_command
, _(
3605 "COPY [--inquire] [!]source[<TAB>[!]child[..]] [!]dest[<TAB>[!]child[..]]\n"
3606 "Copies the entire element tree starting from the child node of the source "
3607 "element, to the destination element path. If the destination element path "
3608 "does not exist then it will be created; otherwise it is overwritten."
3610 "Note that attributes from the source element are merged into the "
3611 "destination element when the destination element path exists. When an "
3612 "attribute of the same name exists in both the source and destination "
3613 "elements then the destination attribute will be updated to the source "
3616 "When the @option{--inquire} option is passed then all remaining non-option "
3617 "arguments are retrieved via a server @emph{INQUIRE}."
3620 new_command("MOVE", FALSE
, TRUE
, move_command
, _(
3621 "MOVE [--inquire] [!]source[<TAB>[!]child[..]] [[!]dest[<TAB>[!]child[..]]]\n"
3622 "Moves the source element path to the destination element path. If the "
3623 "destination is not specified then it will be moved to the root node of the "
3624 "document. If the destination is specified and exists then it will be "
3625 "overwritten; otherwise it will be created."
3627 "When the @option{--inquire} option is passed then all remaining non-option "
3628 "arguments are retrieved via a server @emph{INQUIRE}."
3631 new_command("DELETE", FALSE
, TRUE
, delete_command
, _(
3632 "DELETE [--inquire] [!]element[<TAB>[!]child[..]]\n"
3633 "Removes the specified element path and all of its children. This may break "
3634 "an element with a @code{target} attribute (@pxref{Target Attribute}) that "
3635 "refers to this element or any of its children."
3637 "When the @option{--inquire} option is passed then all remaining non-option "
3638 "arguments are retrieved via a server @emph{INQUIRE}."
3641 new_command("GET", FALSE
, TRUE
, get_command
, _(
3642 "GET [--inquire] [!]element[<TAB>[!]child[..]]\n"
3643 "Retrieves the content of the specified element. The content is returned "
3644 "with a data response."
3646 "When the @option{--inquire} option is passed then all remaining non-option "
3647 "arguments are retrieved via a server @emph{INQUIRE}."
3650 new_command("ATTR", FALSE
, TRUE
, attr_command
, _(
3651 "ATTR [--inquire] SET|GET|DELETE|LIST [<attribute>] [!]element[<TAB>[!]child[..]] ..\n"
3653 "@item ATTR SET attribute [!]element[<TAB>[!]child[..]] [value]\n"
3655 " Stores or updates an @var{attribute} name and optional @var{value} of an "
3656 "element. When no @var{value} is specified any existing value will be removed."
3658 "@item ATTR DELETE attribute [!]element[<TAB>[!]child[..]]\n"
3660 " Removes an @var{attribute} from an element."
3662 "@item ATTR LIST [!]element[<TAB>[!]child[..]]\n"
3664 " Retrieves a newline separated list of attributes names and values "
3665 "from the specified element. Each attribute name and value is space delimited."
3667 "@item ATTR GET attribute [!]element[<TAB>[!]child[..]]\n"
3669 " Retrieves the value of an @var{attribute} from an element."
3672 "The @code{_name} attribute (case sensitive) cannot be removed nor modified. "
3673 "Use the @code{DELETE} (@pxref{DELETE}) or @code{RENAME} (@pxref{RENAME}) "
3674 "commands instead.\n"
3676 "The @code{_mtime} attribute is updated each time an element is modified by "
3677 "either storing content, editing attributes or by deleting a child element. "
3678 "The @code{_ctime} attribute is created for each new element in an element "
3681 "When the @option{--inquire} option is passed then all remaining non-option "
3682 "arguments are retrieved via a server @emph{INQUIRE}."
3684 "@xref{Target Attribute}, for details about this special attribute."
3687 new_command("XPATH", FALSE
, TRUE
, xpath_command
, _(
3688 "XPATH [--inquire] <expression>[<TAB>[value]]\n"
3689 "Evaluates an XPath @var{expression}. If no @var{value} argument is "
3690 "specified, it is assumed the expression is a request to return a result. "
3691 "Otherwise, the result is set to the @var{value} argument and the document is "
3692 "updated. If there is no @var{value} after the @key{TAB} character, the value "
3693 "is assumed to be empty and the document is updated."
3695 "When the @option{--inquire} option is passed then all remaining non-option "
3696 "arguments are retrieved via a server @emph{INQUIRE}."
3699 new_command("XPATHATTR", FALSE
, TRUE
, xpathattr_command
, _(
3700 "XPATHATTR [--inquire] SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
3701 "Like the @code{XPATH} command (@pxref{XPATH}) but operates on element "
3702 "attributes and does not return a result. For the @var{SET} operation the "
3703 "@var{value} is optional but the field is required. If not specified then "
3704 "the attribute value will be empty."
3706 "When the @option{--inquire} option is passed then all remaining non-option "
3707 "arguments are retrieved via a server @emph{INQUIRE}."
3710 new_command("IMPORT", FALSE
, TRUE
, import_command
, _(
3711 "IMPORT <content>[<TAB>[!]element[<TAB>[!]child[..]]]\n"
3712 "This command uses a server @emph{INQUIRE} to retrieve data from the client."
3714 "Like the @code{STORE} command (@pxref{STORE}), but the @var{content} "
3715 "argument is raw @abbr{XML} data. The content is created as a child of the "
3716 "specified element path and will overwrite an existing element of the same "
3717 "name. If an element of the element path does not exist then it will be "
3720 "The content must begin with an @abbr{XML} element node. @xref{Introduction}, "
3724 new_command("DUMP", FALSE
, TRUE
, dump_command
, _(
3726 "Shows the in memory @abbr{XML} document with indenting. @xref{XPATH}, for "
3727 "dumping a specific node."
3730 new_command("LOCK", FALSE
, FALSE
, lock_command
, _(
3732 "Locks the mutex associated with the opened file. This prevents other clients "
3733 "from sending commands to the same opened file until the client "
3734 "that sent this command either disconnects or sends the @code{UNLOCK} "
3735 "command. @xref{UNLOCK}."
3738 new_command("UNLOCK", TRUE
, FALSE
, unlock_command
, _(
3740 "Unlocks the file mutex which was locked with the @code{LOCK} command or "
3741 "a commands' @option{lock} option. @xref{LOCK}."
3744 new_command("GETCONFIG", TRUE
, TRUE
, getconfig_command
, _(
3745 "GETCONFIG [filename] <parameter>\n"
3746 "Returns the value of a @command{pwmd} configuration @var{parameter} with a "
3747 "data response. If no file has been opened then the value for @var{filename} "
3748 "or the default from the @samp{global} section will be returned. If a file "
3749 "has been opened and no @var{filename} is specified, a value previously "
3750 "set with the @code{OPTION} command (@pxref{OPTION}) will be returned."
3753 new_command("OPTION", TRUE
, TRUE
, NULL
, _(
3754 "OPTION <NAME>=<VALUE>\n"
3755 "Sets a client option @var{name} to @var{value}. The value for an option is "
3756 "kept for the duration of the connection."
3760 " Passed to the @command{gpg-agent} and used for the @command{pinentry} dialog."
3763 " Passed to the @command{gpg-agent} and used for the @command{pinentry} dialog."
3766 " Passed to the @command{gpg-agent} and used for the @command{pinentry} dialog."
3769 " Sets the description string of the @command{gpg-agent} and @command{pinentry} dialog."
3772 " Passed to the @command{gpg-agent} and used for the @command{pinentry} dialog."
3774 "@item LC-MESSAGES\n"
3775 " Passed to the @command{gpg-agent} and used for the @command{pinentry} dialog."
3778 " Associates the thread ID of the connection with the specified textual "
3779 "representation. Useful for debugging log messages."
3781 "@item RC_ON_LOCKED\n"
3782 " When @code{1}, a command will return an error code rather than a status "
3783 "message when a file mutex is locked by another thread.\n"
3787 new_command("LS", TRUE
, TRUE
, ls_command
, _(
3789 "Lists the contents of @code{data_directory}. @xref{Configuration}, for "
3790 "details. The result is a newline separated list of filenames."
3793 new_command("RESET", TRUE
, TRUE
, NULL
, _(
3795 "Closes the currently opened file but keeps any previously set client options."
3798 new_command("NOP", TRUE
, TRUE
, NULL
, _(
3800 "Does nothing. Always returns successfully."
3803 /* !END-HELP-TEXT! */
3804 new_command("CANCEL", TRUE
, TRUE
, NULL
, NULL
);
3805 new_command("END", TRUE
, TRUE
, NULL
, NULL
);
3806 new_command("BYE", TRUE
, TRUE
, NULL
, NULL
);
3809 for (i
= 0; command_table
[i
]; i
++);
3810 qsort(command_table
, i
-1, sizeof(struct command_table_s
*), sort_commands
);
3813 gpg_error_t
register_commands(assuan_context_t ctx
)
3817 for (; command_table
[i
]; i
++) {
3818 if (!command_table
[i
]->handler
)
3821 rc
= assuan_register_command (ctx
, command_table
[i
]->name
,
3822 command_table
[i
]->handler
, command_table
[i
]->help
);
3828 rc
= assuan_register_option_handler(ctx
, option_command
);
3832 rc
= assuan_register_bye_notify(ctx
, bye_notify
);
3836 rc
= assuan_register_reset_notify(ctx
, reset_notify
);
3840 rc
= assuan_register_pre_cmd_notify(ctx
, command_startup
);
3844 return assuan_register_post_cmd_notify(ctx
, command_finalize
);