From 259a40c830a89148d67cadbbabac77027c446af0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 19 Oct 2007 14:51:39 +0000 Subject: [PATCH] Enhanced gpg-conect-agent scripting. Typo fixes in comments. --- NEWS | 4 + common/xreadline.c | 2 +- doc/ChangeLog | 4 + doc/tools.texi | 109 +++++++- tools/ChangeLog | 13 + tools/Makefile.am | 6 +- tools/gpg-connect-agent.c | 547 ++++++++++++++++++++++++++++++++------ tools/no-libgcrypt.c | 21 ++ 8 files changed, 620 insertions(+), 86 deletions(-) diff --git a/NEWS b/NEWS index a729ff17b..a0a2c1011 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ Noteworthy changes in version 2.0.8 taken into account. This required a change of our the socket emulation code; thus old GnuPG modules can't be used anymore. + * Fixed a crash in gpgconf. + + * Enhanced gpg-connect-agent with a small scripting language. + Noteworthy changes in version 2.0.7 (2007-09-10) ------------------------------------------------ diff --git a/common/xreadline.c b/common/xreadline.c index 2b640b3ab..ab43c292a 100644 --- a/common/xreadline.c +++ b/common/xreadline.c @@ -33,7 +33,7 @@ maximum allowed allocation. Returns the length of the line. EOF is indicated by a line of - length zero. A truncated line is indicated my setting the value at + length zero. A truncated line is indicated by setting the value at MAX_LENGTH to 0. If the returned value is less then 0 not enough memory was enable and ERRNO is set accordingly. diff --git a/doc/ChangeLog b/doc/ChangeLog index d083158eb..096e8eb92 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2007-10-19 Werner Koch + + * tools.texi (Controlling gpg-connect-agent): Updated. + 2007-08-29 Werner Koch * tools.texi (Checking programs): New. diff --git a/doc/tools.texi b/doc/tools.texi index 902f080e2..d240aca35 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -1045,6 +1045,16 @@ When using @option{-S} or @option{--exec}, @command{gpg-connect-agent} connects to the assuan server in extended mode to allow descriptor passing. This option makes it use the old mode. +@item --run @var{file} +@opindex run +Run the commands from @var{file} at startup and then continue with the +regular input method. + +@item -s +@itemx --subst +@opindex subst +Run the command @code{/subst} at startup. + @item --hex @opindex hex Print data lines in a hex format and the ASCII representation of @@ -1065,20 +1075,85 @@ While reading Assuan commands, gpg-agent also allows a few special commands to control its operation. These control commands all start with a slash (@code{/}). - @table @code @item /echo @var{args} Just print @var{args}. -@item /definqfile @var{name} @var{file} +@item /let @var{name} @var{value} +Set the variable @var{name} to @var{value}. Variables are only +substituted on the input if the @command{/subst} has been used. +Variables are referenced by prefixing the name with a dollr sign and +optionally include the name in curly braces. The rules for a valid name +are idnetically to those of the standard bourne shell. This is not yet +enforced but may be in the future. When used with curly braces no +leading or trailing white space is allowed. +If a variable is not found, it is searched in the environment and if +found copied to the table of variables. + +Variable functions are available: The name of the function must be +followed by at least one space and the at least one argument. The +following functions are available: + +@table @code +@item get +Return a value described by the argument. Available arguments are: + +@table @code +@item cwd +The current working directory. +@item homedir +The gnupg homedir. +@item sysconfdir +GnuPG's system configuration directory. +@item bindir +GnuPG's binary directory. +@item libdir +GnuPG's library directory. +@item libexecdir +GnuPG's library directory for executable files. +@item datadir +GnuPG's data directory. +@item serverpid +The PID of the current server. Command @command{/serverpid} must +have been given to return a useful value. +@end table + +@item unescape @var{args} +Remove C-style escapes from @var{args}. Note that @code{\0} and +@code{\x00} terminate the returned string implictly. The string to be +converted are the entire arguments right behind the delimiting space of +the function name. + +@item unpercent @var{args} +@itemx unpercent+ @var{args} +Remove percent style ecaping from @var{args}. Note that @code{%00} +terminates the string implicitly. The string to be converted are the +entire arguments right behind the delimiting space of the function +name. @code{unpercent+} also maps plus signs to a spaces. + +@item percent @var{args} +@item percent+ @var{args} +Escape the @var{args} using percent style ecaping. Tabs, formfeeds, +linefeeds, carriage returns and colons are escaped. @code{percent+} also +maps spaces to plus signs. + +@end table + + +@item /definq @var{name} @var{var} +Use content of the variable @var{var} for inquiries with @var{name}. +@var{name} may be an asterisk (@code{*}) to match any inquiry. + + +@item /definqfile @var{name} @var{file} Use content of @var{file} for inquiries with @var{name}. -@var{name} may be an asterisk (@code{*} to match any inquiry. +@var{name} may be an asterisk (@code{*}) to match any inquiry. @item /definqprog @var{name} @var{prog} Run @var{prog} for inquiries matching @var{name} and pass the -entire line to it as command line arguments +entire line to it as command line arguments. @item /showdef Print all definitions @@ -1095,6 +1170,21 @@ input source for other commands. @item /recvfd Not yet implemented. +@item /open @var{var} @var{file} [@var{mode}] +Open @var{file} and assign the file descriptor to @var{var}. Warning: +This command is experimental and might change in future versions. + +@item /close @var{fd} +Close the file descriptor @var{fd}. Warning: This command is +experimental and might change in future versions. + +@item /showopen +Show a listy of open files. + +@item /serverpid +Send the Assuan command @command{GETINFO pid} to the server and store +the returned PID for internal purposes. + @item /hex @itemx /nohex Same as the command line option @option{--hex}. @@ -1103,6 +1193,17 @@ Same as the command line option @option{--hex}. @itemx /nodecode Same as the command line option @option{--decode}. +@item /subst +@itemx /nosubst +Enable and disable variable substitution. It defaults to disabled +unless the command line option @option{--subst} has been used. + +@item /run @var{file} +Run commands from @var{file}. + +@item /bye +Terminate the connection and the program + @item /help Print a list of available control commands. diff --git a/tools/ChangeLog b/tools/ChangeLog index c42e75c87..118a0fe12 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,5 +1,18 @@ 2007-10-19 Werner Koch + * gpg-connect-agent.c (get_var_ext): New. + (substitute_line): Use it. + (assign_variable): Implement /slet in terms of get_var_ext. + (main): New option -s/--subst. + (add_definq): Add arg IS_VAR. Change all callers. + (main): Add command /definq. + (handle_inquire): Implement new command. + (substitute_line_copy): New. + (unescape_string, unpercent_string): New. + * no-libgcrypt.c (gcry_set_outofcore_handler) + (gcry_set_fatalerror_handler, gcry_set_log_handler): New. + * Makefile.am (gpg_connect_agent_LDADD): Link to libreadline. + * gpgconf-comp.c (retrieve_options_from_file): Don't call fclose with NULL. Fixes bug 842. diff --git a/tools/Makefile.am b/tools/Makefile.am index a9004a757..e47392300 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -80,7 +80,9 @@ watchgnupg_LDADD = $(NETLIBS) gpg_connect_agent_SOURCES = gpg-connect-agent.c no-libgcrypt.c # FIXME: remove PTH_LIBS (why do we need them at all?) gpg_connect_agent_LDADD = $(common_libs) $(LIBASSUAN_LIBS) $(PTH_LIBS) \ - $(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) + $(GPG_ERROR_LIBS) \ + ../common/libgpgrl.a $(LIBREADLINE) \ + $(LIBINTL) $(NETLIBS) $(LIBICONV) gpgkey2ssh_SOURCES = gpgkey2ssh.c gpgkey2ssh_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS) @@ -99,5 +101,5 @@ endif # Make sure that all libs are build before we use them. This is # important for things like make -j2. -$(PROGRAMS): $(common_libs) $(pwquery_libs) +$(PROGRAMS): $(common_libs) $(pwquery_libs) ../common/libgpgrl.a diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index cb3f0639d..197172ee2 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -25,12 +25,17 @@ #include #include #include +#include #include "i18n.h" #include "../common/util.h" #include "../common/asshelp.h" #include "../common/sysutils.h" #include "../common/membuf.h" +#include "../common/ttyio.h" + +#define CONTROL_D ('D' - 'A' + 1) +#define octdigitp(p) (*(p) >= '0' && *(p) <= '7') /* Constants to identify the commands and options. */ enum cmd_and_opt_values @@ -41,6 +46,7 @@ enum cmd_and_opt_values oRawSocket = 'S', oExec = 'E', oRun = 'r', + oSubst = 's', oNoVerbose = 500, oHomedir, @@ -65,6 +71,7 @@ static ARGPARSE_OPTS opts[] = { oNoExtConnect, "no-ext-connect", 0, N_("do not use extended connect mode")}, { oRun, "run", 2, N_("|FILE|run commands from FILE on startup")}, + { oSubst, "subst", 0, N_("run /subst on startup")}, /* hidden options */ { oNoVerbose, "no-verbose", 0, "@"}, { oHomedir, "homedir", 2, "@" }, @@ -94,7 +101,8 @@ struct definq_s { struct definq_s *next; char *name; /* Name of inquiry or NULL for any name. */ - int is_prog; /* True if this is a program to run. */ + int is_var; /* True if FILE is a variable name. */ + int is_prog; /* True if FILE is a program to run. */ char file[1]; /* Name of file or program. */ }; typedef struct definq_s *definq_t; @@ -129,6 +137,7 @@ static struct /*-- local prototypes --*/ +static char *substitute_line_copy (const char *buffer); static int read_and_print_response (assuan_context_t ctx, int *r_goterr); static assuan_context_t start_agent (void); @@ -185,6 +194,145 @@ gnu_getcwd (void) } +/* Unescale STRING and returned the malloced result. The surrounding + quotes must already be removed from STRING. */ +static char * +unescape_string (const char *string) +{ + const unsigned char *s; + int esc; + size_t n; + char *buffer; + unsigned char *d; + + n = 0; + for (s = (const unsigned char*)string, esc=0; *s; s++) + { + if (esc) + { + switch (*s) + { + case 'b': + case 't': + case 'v': + case 'n': + case 'f': + case 'r': + case '"': + case '\'': + case '\\': n++; break; + case 'x': + if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2)) + n++; + break; + + default: + if (s[1] && s[2] + && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2)) + n++; + break; + } + esc = 0; + } + else if (*s == '\\') + esc = 1; + else + n++; + } + + buffer = xmalloc (n+1); + d = (unsigned char*)buffer; + for (s = (const unsigned char*)string, esc=0; *s; s++) + { + if (esc) + { + switch (*s) + { + case 'b': *d++ = '\b'; break; + case 't': *d++ = '\t'; break; + case 'v': *d++ = '\v'; break; + case 'n': *d++ = '\n'; break; + case 'f': *d++ = '\f'; break; + case 'r': *d++ = '\r'; break; + case '"': *d++ = '\"'; break; + case '\'': *d++ = '\''; break; + case '\\': *d++ = '\\'; break; + case 'x': + if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2)) + { + s++; + *d++ = xtoi_2 (s); + s++; + } + break; + + default: + if (s[1] && s[2] + && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2)) + { + *d++ = (atoi_1 (s)*64) + (atoi_1 (s+1)*8) + atoi_1 (s+2); + s += 2; + } + break; + } + esc = 0; + } + else if (*s == '\\') + esc = 1; + else + *d++ = *s; + } + *d = 0; + return buffer; +} + + +/* Do the percent unescaping and return a newly malloced string. + If WITH_PLUS is set '+' characters will be changed to space. */ +static char * +unpercent_string (const char *string, int with_plus) +{ + const unsigned char *s; + unsigned char *buffer, *p; + size_t n; + + n = 0; + for (s=(const unsigned char *)string; *s; s++) + { + if (*s == '%' && s[1] && s[2]) + { + s++; + n++; + s++; + } + else if (with_plus && *s == '+') + n++; + else + n++; + } + + buffer = xmalloc (n+1); + p = buffer; + for (s=(const unsigned char *)string; *s; s++) + { + if (*s == '%' && s[1] && s[2]) + { + s++; + *p++ = xtoi_2 (s); + s++; + } + else if (with_plus && *s == '+') + *p++ = ' '; + else + *p++ = *s; + } + *p = 0; + return (char*)buffer; +} + + + + static const char * set_var (const char *name, const char *value) @@ -241,6 +389,145 @@ get_var (const char *name) } +/* Extended version of get_var. This returns a malloced string and + understand the fucntion syntax: "func args". + + Defined functions are + + get - Return a value described by the next argument: + cwd - The current working directory. + homedir - The gnupg homedir. + sysconfdir - GnuPG's system configuration directory. + bindir - GnuPG's binary directory. + libdir - GnuPG's library directory. + libexecdir - GnuPG's library directory for executable files. + datadir - GnuPG's data directory. + serverpid - The PID of the current server. + + unescape ARGS + Remove C-style escapes from string. Note that "\0" and + "\x00" terminate the string implictly. Use "\x7d" to + represent the closing brace. The args start right after + the first space after the function name. + + unpercent ARGS + unpercent+ ARGS + Remove percent style ecaping from string. NOte that "%00 + terminates the string implicitly. Use "%7d" to represetn + the closing brace. The args start right after the first + space after the function name. "unpercent+" also maps '+' + to space. + + percent ARGS + percent+ ARGS + Escape the args using the percent style. Tabs, formfeeds, + linefeeds and carriage returns are also escaped. + "percent+" also maps spaces to plus characters. + + Example: get_var_ext ("get sysconfdir") -> "/etc/gnupg" + + */ +static char * +get_var_ext (const char *name) +{ + static int recursion_count; + const char *s; + char *result; + char *p; + char *free_me = NULL; + + if (recursion_count > 50) + { + log_error ("variables nested too deeply\n"); + return NULL; + } + + recursion_count++; + free_me = opt.enable_varsubst? substitute_line_copy (name) : NULL; + if (free_me) + name = free_me; + for (s=name; *s && !spacep (s); s++) + ; + if (!*s) + { + s = get_var (name); + result = s? xstrdup (s): NULL; + } + else if ( (s - name) == 3 && !strncmp (name, "get", 3)) + { + while ( spacep (s) ) + s++; + if (!strcmp (s, "cwd")) + { + result = gnu_getcwd (); + if (!result) + log_error ("getcwd failed: %s\n", strerror (errno)); + } + else if (!strcmp (s, "homedir")) + result = make_filename (opt.homedir, NULL); + else if (!strcmp (s, "sysconfdir")) + result = xstrdup (gnupg_sysconfdir ()); + else if (!strcmp (s, "bindir")) + result = xstrdup (gnupg_bindir ()); + else if (!strcmp (s, "libdir")) + result = xstrdup (gnupg_libdir ()); + else if (!strcmp (s, "libexecdir")) + result = xstrdup (gnupg_libexecdir ()); + else if (!strcmp (s, "datadir")) + result = xstrdup (gnupg_datadir ()); + else if (!strcmp (s, "serverpid")) + { + char numbuf[30]; + snprintf (numbuf, sizeof numbuf, "%d", (int)server_pid); + result = xstrdup (numbuf); + } + else + { + log_error ("invalid argument `%s' for variable function `get'\n", s); + log_info ("valid are: cwd, " + "{home,bin,lib,libexec,data}dir, serverpid\n"); + result = NULL; + } + } + else if ( (s - name) == 8 && !strncmp (name, "unescape", 8)) + { + s++; + result = unescape_string (s); + } + else if ( (s - name) == 9 && !strncmp (name, "unpercent", 9)) + { + s++; + result = unpercent_string (s, 0); + } + else if ( (s - name) == 10 && !strncmp (name, "unpercent+", 10)) + { + s++; + result = unpercent_string (s, 1); + } + else if ( (s - name) == 7 && !strncmp (name, "percent", 7)) + { + s++; + result = percent_escape (s, "\t\r\n\f\v"); + } + else if ( (s - name) == 8 && !strncmp (name, "percent+", 8)) + { + s++; + result = percent_escape (s, "\t\r\n\f\v"); + for (p=result; *p; p++) + if (*p == ' ') + *p = '+'; + } + else + { + log_error ("unknown variable function `%.*s'\n", (int)(s-name), name); + result = NULL; + } + + xfree (free_me); + recursion_count--; + return result; +} + /* Substitute variables in LINE and return a new allocated buffer if required. The function might modify LINE if the expanded version @@ -253,6 +540,7 @@ substitute_line (char *buffer) const char *value; size_t valuelen, n; char *result = NULL; + char *freeme = NULL; while (*line) { @@ -268,8 +556,18 @@ substitute_line (char *buffer) } if (p[1] == '{') { - for (pend=p+2; *pend && *pend != '}' ; pend++) - ; + int count = 0; + + for (pend=p+2; *pend; pend++) + { + if (*pend == '{') + count++; + else if (*pend == '}') + { + if (--count < 0) + break; + } + } if (!*pend) return result; /* Unclosed - don't substitute. */ } @@ -281,7 +579,8 @@ substitute_line (char *buffer) if (p[1] == '{' && *pend == '}') { *pend++ = 0; - value = get_var (p+2); + freeme = get_var_ext (p+2); + value = freeme; } else if (*pend) { @@ -319,16 +618,32 @@ substitute_line (char *buffer) free (result); result = dst; } + xfree (freeme); + freeme = NULL; } return result; } +/* Same as substitute_line but do not modify BUFFER. */ +static char * +substitute_line_copy (const char *buffer) +{ + char *result, *p; + + p = xstrdup (buffer?buffer:""); + result = substitute_line (p); + if (!result) + result = p; + else + xfree (p); + return result; +} static void assign_variable (char *line, int syslet) { - char *name, *p, *tmp, *free_me; + char *name, *p, *tmp, *free_me, *buffer; /* Get the name. */ name = line; @@ -343,42 +658,20 @@ assign_variable (char *line, int syslet) set_var (name, NULL); /* Remove variable. */ else if (syslet) { - free_me = opt.enable_varsubst? substitute_line (p) : NULL; + free_me = opt.enable_varsubst? substitute_line_copy (p) : NULL; if (free_me) p = free_me; - if (!strcmp (p, "cwd")) - { - tmp = gnu_getcwd (); - if (!tmp) - log_error ("getcwd failed: %s\n", strerror (errno)); - set_var (name, tmp); - xfree (tmp); - } - else if (!strcmp (p, "homedir")) - set_var (name, opt.homedir); - else if (!strcmp (p, "sysconfdir")) - set_var (name, gnupg_sysconfdir ()); - else if (!strcmp (p, "bindir")) - set_var (name, gnupg_bindir ()); - else if (!strcmp (p, "libdir")) - set_var (name, gnupg_libdir ()); - else if (!strcmp (p, "libexecdir")) - set_var (name, gnupg_libexecdir ()); - else if (!strcmp (p, "datadir")) - set_var (name, gnupg_datadir ()); - else if (!strcmp (p, "serverpid")) - set_int_var (name, (int)server_pid); - else - { - log_error ("undefined tag `%s'\n", p); - log_info ("valid tags are: cwd, {home,bin,lib,libexec,data}dir, " - "serverpid\n"); - } + buffer = xmalloc (4 + strlen (p) + 1); + strcpy (stpcpy (buffer, "get "), p); + tmp = get_var_ext (buffer); + xfree (buffer); + set_var (name, tmp); + xfree (tmp); xfree (free_me); } else { - tmp = opt.enable_varsubst? substitute_line (p) : NULL; + tmp = opt.enable_varsubst? substitute_line_copy (p) : NULL; if (tmp) { set_var (name, tmp); @@ -405,7 +698,7 @@ show_variables (void) change the content of LINE. We assume that leading white spaces are already removed. */ static void -add_definq (char *line, int is_prog) +add_definq (char *line, int is_var, int is_prog) { definq_t d; char *name, *p; @@ -421,6 +714,7 @@ add_definq (char *line, int is_prog) d = xmalloc (sizeof *d + strlen (p) ); strcpy (d->file, p); + d->is_var = is_var; d->is_prog = is_prog; if ( !strcmp (name, "*")) d->name = NULL; @@ -441,10 +735,12 @@ show_definq (void) for (d=definq_list; d; d = d->next) if (d->name) - printf ("%-20s %c %s\n", d->name, d->is_prog? 'p':'f', d->file); + printf ("%-20s %c %s\n", + d->name, d->is_var? 'v' : d->is_prog? 'p':'f', d->file); for (d=definq_list; d; d = d->next) if (!d->name) - printf ("%-20s %c %s\n", "*", d->is_prog? 'p':'f', d->file); + printf ("%-20s %c %s\n", "*", + d->is_var? 'v': d->is_prog? 'p':'f', d->file); } @@ -727,7 +1023,10 @@ main (int argc, char **argv) int cmderr; const char *opt_run = NULL; FILE *script_fp = NULL; + int use_tty, last_was_tty; + + gnupg_rl_initialize (); set_strusage (my_strusage); log_set_prefix ("gpg-connect-agent", 1); @@ -759,6 +1058,7 @@ main (int argc, char **argv) case oExec: opt.exec = 1; break; case oNoExtConnect: opt.connect_flags &= ~(1); break; case oRun: opt_run = pargs.r.ret_str; break; + case oSubst: opt.enable_varsubst = 1; break; default: pargs.err = 2; break; } @@ -767,6 +1067,8 @@ main (int argc, char **argv) if (log_get_errorcount (0)) exit (2); + use_tty = (isatty ( fileno (stdin)) && isatty (fileno (stdout))); + if (opt.exec) { if (!argc) @@ -841,13 +1143,35 @@ main (int argc, char **argv) line = NULL; linesize = 0; + last_was_tty = 0; for (;;) { int n; size_t maxlength; maxlength = 2048; - n = read_line (script_fp? script_fp:stdin, &line, &linesize, &maxlength); + if (use_tty && !script_fp) + { + last_was_tty = 1; + line = tty_get ("> "); + n = strlen (line); + if (n==1 && *line == CONTROL_D) + n = 0; + if (n >= maxlength) + maxlength = 0; + } + else + { + if (last_was_tty) + { + xfree (line); + line = NULL; + linesize = 0; + last_was_tty = 0; + } + n = read_line (script_fp? script_fp:stdin, + &line, &linesize, &maxlength); + } if (n < 0) { log_error (_("error reading input: %s\n"), strerror (errno)); @@ -899,19 +1223,45 @@ main (int argc, char **argv) } else if (!strcmp (cmd, "slet")) { + /* Deprecated - never used in a released version. */ assign_variable (p, 1); } else if (!strcmp (cmd, "showvar")) { show_variables (); } + else if (!strcmp (cmd, "definq")) + { + tmpline = opt.enable_varsubst? substitute_line (p) : NULL; + if (tmpline) + { + add_definq (tmpline, 1, 0); + xfree (tmpline); + } + else + add_definq (p, 1, 0); + } else if (!strcmp (cmd, "definqfile")) { - add_definq (p, 0); + tmpline = opt.enable_varsubst? substitute_line (p) : NULL; + if (tmpline) + { + add_definq (tmpline, 0, 0); + xfree (tmpline); + } + else + add_definq (p, 0, 0); } else if (!strcmp (cmd, "definqprog")) { - add_definq (p, 1); + tmpline = opt.enable_varsubst? substitute_line (p) : NULL; + if (tmpline) + { + add_definq (tmpline, 0, 1); + xfree (tmpline); + } + else + add_definq (p, 0, 1); } else if (!strcmp (cmd, "showdef")) { @@ -934,21 +1284,49 @@ main (int argc, char **argv) } else if (!strcmp (cmd, "sendfd")) { - do_sendfd (ctx, p); + tmpline = opt.enable_varsubst? substitute_line (p) : NULL; + if (tmpline) + { + do_sendfd (ctx, tmpline); + xfree (tmpline); + } + else + do_sendfd (ctx, p); continue; } else if (!strcmp (cmd, "recvfd")) { - do_recvfd (ctx, p); + tmpline = opt.enable_varsubst? substitute_line (p) : NULL; + if (tmpline) + { + do_recvfd (ctx, tmpline); + xfree (tmpline); + } + else + do_recvfd (ctx, p); continue; } else if (!strcmp (cmd, "open")) { - do_open (p); + tmpline = opt.enable_varsubst? substitute_line (p) : NULL; + if (tmpline) + { + do_open (tmpline); + xfree (tmpline); + } + else + do_open (p); } else if (!strcmp (cmd, "close")) { - do_close (p); + tmpline = opt.enable_varsubst? substitute_line (p) : NULL; + if (tmpline) + { + do_close (tmpline); + xfree (tmpline); + } + else + do_close (p); } else if (!strcmp (cmd, "showopen")) { @@ -1012,19 +1390,15 @@ main (int argc, char **argv) "Available commands:\n" "/echo ARGS Echo ARGS.\n" "/let NAME VALUE Set variable NAME to VALUE.\n" -"/slet NAME TAG Set variable NAME to the value described by TAG.\n" "/showvar Show all variables.\n" -"/definqfile NAME FILE\n" -" Use content of FILE for inquiries with NAME.\n" -" NAME may be \"*\" to match any inquiry.\n" -"/definqprog NAME PGM\n" -" Run PGM for inquiries matching NAME and pass the\n" -" entire line to it as arguments.\n" +"/definq NAME VAR Use content of VAR for inquiries with NAME.\n" +"/definqfile NAME FILE Use content of FILE for inquiries with NAME.\n" +"/definqprog NAME PGM Run PGM for inquiries with NAME.\n" "/showdef Print all definitions.\n" "/cleardef Delete all definitions.\n" "/sendfd FILE MODE Open FILE and pass descriptor to server.\n" "/recvfd Receive FD from server and print.\n" -"/open VAR FILE MODE Open FILE and assign the descrptor to VAR.\n" +"/open VAR FILE MODE Open FILE and assign the file descriptor to VAR.\n" "/close FD Close file with descriptor FD.\n" "/showopen Show descriptors of all open files.\n" "/serverpid Retrieve the pid of the server.\n" @@ -1094,7 +1468,7 @@ handle_inquire (assuan_context_t ctx, char *line) { const char *name; definq_t d; - FILE *fp; + FILE *fp = NULL; char buffer[1024]; int rc, n; @@ -1126,43 +1500,58 @@ handle_inquire (assuan_context_t ctx, char *line) return 0; } - if (d->is_prog) + if (d->is_var) { - fp = popen (d->file, "r"); - if (!fp) - log_error ("error executing `%s': %s\n", d->file, strerror (errno)); - else if (opt.verbose) - log_error ("handling inquiry `%s' by running `%s'\n", name, d->file); + char *tmpvalue = get_var_ext (d->file); + rc = assuan_send_data (ctx, tmpvalue, strlen (tmpvalue)); + xfree (tmpvalue); + if (rc) + log_error ("sending data back failed: %s\n", gpg_strerror (rc) ); } else { - fp = fopen (d->file, "rb"); - if (!fp) - log_error ("error opening `%s': %s\n", d->file, strerror (errno)); - else if (opt.verbose) - log_error ("handling inquiry `%s' by returning content of `%s'\n", - name, d->file); - } - if (!fp) - return 0; - - while ( (n = fread (buffer, 1, sizeof buffer, fp)) ) - { - rc = assuan_send_data (ctx, buffer, n); - if (rc) + if (d->is_prog) { - log_error ("sending data back failed: %s\n", gpg_strerror (rc) ); - break; + fp = popen (d->file, "r"); + if (!fp) + log_error ("error executing `%s': %s\n", + d->file, strerror (errno)); + else if (opt.verbose) + log_error ("handling inquiry `%s' by running `%s'\n", + name, d->file); } + else + { + fp = fopen (d->file, "rb"); + if (!fp) + log_error ("error opening `%s': %s\n", d->file, strerror (errno)); + else if (opt.verbose) + log_error ("handling inquiry `%s' by returning content of `%s'\n", + name, d->file); + } + if (!fp) + return 0; + + while ( (n = fread (buffer, 1, sizeof buffer, fp)) ) + { + rc = assuan_send_data (ctx, buffer, n); + if (rc) + { + log_error ("sending data back failed: %s\n", gpg_strerror (rc) ); + break; + } + } + if (ferror (fp)) + log_error ("error reading from `%s': %s\n", d->file, strerror (errno)); } - if (ferror (fp)) - log_error ("error reading from `%s': %s\n", d->file, strerror (errno)); rc = assuan_send_data (ctx, NULL, 0); if (rc) log_error ("sending data back failed: %s\n", gpg_strerror (rc) ); - if (d->is_prog) + if (d->is_var) + ; + else if (d->is_prog) { if (pclose (fp)) log_error ("error running `%s': %s\n", d->file, strerror (errno)); diff --git a/tools/no-libgcrypt.c b/tools/no-libgcrypt.c index a21ccdb76..009fd95a5 100644 --- a/tools/no-libgcrypt.c +++ b/tools/no-libgcrypt.c @@ -117,3 +117,24 @@ gcry_control (enum gcry_ctl_cmds CMD, ...) { return 0; } + +void +gcry_set_outofcore_handler (gcry_handler_no_mem_t h, void *opaque) +{ + (void)h; + (void)opaque; +} + +void +gcry_set_fatalerror_handler (gcry_handler_error_t fnc, void *opaque) +{ + (void)fnc; + (void)opaque; +} + +void +gcry_set_log_handler (gcry_handler_log_t f, void *opaque) +{ + (void)f; + (void)opaque; +}