1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

Enhanced gpg-conect-agent scripting.

Typo fixes in comments.
This commit is contained in:
Werner Koch 2007-10-19 14:51:39 +00:00
parent bea6c580f2
commit 259a40c830
8 changed files with 620 additions and 86 deletions

4
NEWS
View File

@ -5,6 +5,10 @@ Noteworthy changes in version 2.0.8
taken into account. This required a change of our the socket taken into account. This required a change of our the socket
emulation code; thus old GnuPG modules can't be used anymore. 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) Noteworthy changes in version 2.0.7 (2007-09-10)
------------------------------------------------ ------------------------------------------------

View File

@ -33,7 +33,7 @@
maximum allowed allocation. maximum allowed allocation.
Returns the length of the line. EOF is indicated by a line of 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 MAX_LENGTH to 0. If the returned value is less then 0 not enough
memory was enable and ERRNO is set accordingly. memory was enable and ERRNO is set accordingly.

View File

@ -1,3 +1,7 @@
2007-10-19 Werner Koch <wk@g10code.com>
* tools.texi (Controlling gpg-connect-agent): Updated.
2007-08-29 Werner Koch <wk@g10code.com> 2007-08-29 Werner Koch <wk@g10code.com>
* tools.texi (Checking programs): New. * tools.texi (Checking programs): New.

View File

@ -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 connects to the assuan server in extended mode to allow descriptor
passing. This option makes it use the old mode. 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 @item --hex
@opindex hex @opindex hex
Print data lines in a hex format and the ASCII representation of 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 commands to control its operation. These control commands all start
with a slash (@code{/}). with a slash (@code{/}).
@table @code @table @code
@item /echo @var{args} @item /echo @var{args}
Just print @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}. 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} @item /definqprog @var{name} @var{prog}
Run @var{prog} for inquiries matching @var{name} and pass the 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 @item /showdef
Print all definitions Print all definitions
@ -1095,6 +1170,21 @@ input source for other commands.
@item /recvfd @item /recvfd
Not yet implemented. 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 @item /hex
@itemx /nohex @itemx /nohex
Same as the command line option @option{--hex}. Same as the command line option @option{--hex}.
@ -1103,6 +1193,17 @@ Same as the command line option @option{--hex}.
@itemx /nodecode @itemx /nodecode
Same as the command line option @option{--decode}. 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 @item /help
Print a list of available control commands. Print a list of available control commands.

View File

@ -1,5 +1,18 @@
2007-10-19 Werner Koch <wk@g10code.com> 2007-10-19 Werner Koch <wk@g10code.com>
* 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 * gpgconf-comp.c (retrieve_options_from_file): Don't call fclose
with NULL. Fixes bug 842. with NULL. Fixes bug 842.

View File

@ -80,7 +80,9 @@ watchgnupg_LDADD = $(NETLIBS)
gpg_connect_agent_SOURCES = gpg-connect-agent.c no-libgcrypt.c gpg_connect_agent_SOURCES = gpg-connect-agent.c no-libgcrypt.c
# FIXME: remove PTH_LIBS (why do we need them at all?) # FIXME: remove PTH_LIBS (why do we need them at all?)
gpg_connect_agent_LDADD = $(common_libs) $(LIBASSUAN_LIBS) $(PTH_LIBS) \ 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_SOURCES = gpgkey2ssh.c
gpgkey2ssh_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS) 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 # Make sure that all libs are build before we use them. This is
# important for things like make -j2. # important for things like make -j2.
$(PROGRAMS): $(common_libs) $(pwquery_libs) $(PROGRAMS): $(common_libs) $(pwquery_libs) ../common/libgpgrl.a

View File

@ -25,12 +25,17 @@
#include <errno.h> #include <errno.h>
#include <ctype.h> #include <ctype.h>
#include <assuan.h> #include <assuan.h>
#include <unistd.h>
#include "i18n.h" #include "i18n.h"
#include "../common/util.h" #include "../common/util.h"
#include "../common/asshelp.h" #include "../common/asshelp.h"
#include "../common/sysutils.h" #include "../common/sysutils.h"
#include "../common/membuf.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. */ /* Constants to identify the commands and options. */
enum cmd_and_opt_values enum cmd_and_opt_values
@ -41,6 +46,7 @@ enum cmd_and_opt_values
oRawSocket = 'S', oRawSocket = 'S',
oExec = 'E', oExec = 'E',
oRun = 'r', oRun = 'r',
oSubst = 's',
oNoVerbose = 500, oNoVerbose = 500,
oHomedir, oHomedir,
@ -65,6 +71,7 @@ static ARGPARSE_OPTS opts[] =
{ oNoExtConnect, "no-ext-connect", { oNoExtConnect, "no-ext-connect",
0, N_("do not use extended connect mode")}, 0, N_("do not use extended connect mode")},
{ oRun, "run", 2, N_("|FILE|run commands from FILE on startup")}, { oRun, "run", 2, N_("|FILE|run commands from FILE on startup")},
{ oSubst, "subst", 0, N_("run /subst on startup")},
/* hidden options */ /* hidden options */
{ oNoVerbose, "no-verbose", 0, "@"}, { oNoVerbose, "no-verbose", 0, "@"},
{ oHomedir, "homedir", 2, "@" }, { oHomedir, "homedir", 2, "@" },
@ -94,7 +101,8 @@ struct definq_s
{ {
struct definq_s *next; struct definq_s *next;
char *name; /* Name of inquiry or NULL for any name. */ 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. */ char file[1]; /* Name of file or program. */
}; };
typedef struct definq_s *definq_t; typedef struct definq_s *definq_t;
@ -129,6 +137,7 @@ static struct
/*-- local prototypes --*/ /*-- local prototypes --*/
static char *substitute_line_copy (const char *buffer);
static int read_and_print_response (assuan_context_t ctx, int *r_goterr); static int read_and_print_response (assuan_context_t ctx, int *r_goterr);
static assuan_context_t start_agent (void); 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 * static const char *
set_var (const char *name, const char *value) 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 /* Substitute variables in LINE and return a new allocated buffer if
required. The function might modify LINE if the expanded version required. The function might modify LINE if the expanded version
@ -253,6 +540,7 @@ substitute_line (char *buffer)
const char *value; const char *value;
size_t valuelen, n; size_t valuelen, n;
char *result = NULL; char *result = NULL;
char *freeme = NULL;
while (*line) while (*line)
{ {
@ -268,8 +556,18 @@ substitute_line (char *buffer)
} }
if (p[1] == '{') 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) if (!*pend)
return result; /* Unclosed - don't substitute. */ return result; /* Unclosed - don't substitute. */
} }
@ -281,7 +579,8 @@ substitute_line (char *buffer)
if (p[1] == '{' && *pend == '}') if (p[1] == '{' && *pend == '}')
{ {
*pend++ = 0; *pend++ = 0;
value = get_var (p+2); freeme = get_var_ext (p+2);
value = freeme;
} }
else if (*pend) else if (*pend)
{ {
@ -319,16 +618,32 @@ substitute_line (char *buffer)
free (result); free (result);
result = dst; result = dst;
} }
xfree (freeme);
freeme = NULL;
} }
return result; 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 static void
assign_variable (char *line, int syslet) assign_variable (char *line, int syslet)
{ {
char *name, *p, *tmp, *free_me; char *name, *p, *tmp, *free_me, *buffer;
/* Get the name. */ /* Get the name. */
name = line; name = line;
@ -343,42 +658,20 @@ assign_variable (char *line, int syslet)
set_var (name, NULL); /* Remove variable. */ set_var (name, NULL); /* Remove variable. */
else if (syslet) 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) if (free_me)
p = free_me; p = free_me;
if (!strcmp (p, "cwd")) buffer = xmalloc (4 + strlen (p) + 1);
{ strcpy (stpcpy (buffer, "get "), p);
tmp = gnu_getcwd (); tmp = get_var_ext (buffer);
if (!tmp) xfree (buffer);
log_error ("getcwd failed: %s\n", strerror (errno)); set_var (name, tmp);
set_var (name, tmp); xfree (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");
}
xfree (free_me); xfree (free_me);
} }
else else
{ {
tmp = opt.enable_varsubst? substitute_line (p) : NULL; tmp = opt.enable_varsubst? substitute_line_copy (p) : NULL;
if (tmp) if (tmp)
{ {
set_var (name, tmp); set_var (name, tmp);
@ -405,7 +698,7 @@ show_variables (void)
change the content of LINE. We assume that leading white spaces change the content of LINE. We assume that leading white spaces
are already removed. */ are already removed. */
static void static void
add_definq (char *line, int is_prog) add_definq (char *line, int is_var, int is_prog)
{ {
definq_t d; definq_t d;
char *name, *p; char *name, *p;
@ -421,6 +714,7 @@ add_definq (char *line, int is_prog)
d = xmalloc (sizeof *d + strlen (p) ); d = xmalloc (sizeof *d + strlen (p) );
strcpy (d->file, p); strcpy (d->file, p);
d->is_var = is_var;
d->is_prog = is_prog; d->is_prog = is_prog;
if ( !strcmp (name, "*")) if ( !strcmp (name, "*"))
d->name = NULL; d->name = NULL;
@ -441,10 +735,12 @@ show_definq (void)
for (d=definq_list; d; d = d->next) for (d=definq_list; d; d = d->next)
if (d->name) 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) for (d=definq_list; d; d = d->next)
if (!d->name) 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; int cmderr;
const char *opt_run = NULL; const char *opt_run = NULL;
FILE *script_fp = NULL; FILE *script_fp = NULL;
int use_tty, last_was_tty;
gnupg_rl_initialize ();
set_strusage (my_strusage); set_strusage (my_strusage);
log_set_prefix ("gpg-connect-agent", 1); log_set_prefix ("gpg-connect-agent", 1);
@ -759,6 +1058,7 @@ main (int argc, char **argv)
case oExec: opt.exec = 1; break; case oExec: opt.exec = 1; break;
case oNoExtConnect: opt.connect_flags &= ~(1); break; case oNoExtConnect: opt.connect_flags &= ~(1); break;
case oRun: opt_run = pargs.r.ret_str; break; case oRun: opt_run = pargs.r.ret_str; break;
case oSubst: opt.enable_varsubst = 1; break;
default: pargs.err = 2; break; default: pargs.err = 2; break;
} }
@ -767,6 +1067,8 @@ main (int argc, char **argv)
if (log_get_errorcount (0)) if (log_get_errorcount (0))
exit (2); exit (2);
use_tty = (isatty ( fileno (stdin)) && isatty (fileno (stdout)));
if (opt.exec) if (opt.exec)
{ {
if (!argc) if (!argc)
@ -841,13 +1143,35 @@ main (int argc, char **argv)
line = NULL; line = NULL;
linesize = 0; linesize = 0;
last_was_tty = 0;
for (;;) for (;;)
{ {
int n; int n;
size_t maxlength; size_t maxlength;
maxlength = 2048; 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) if (n < 0)
{ {
log_error (_("error reading input: %s\n"), strerror (errno)); log_error (_("error reading input: %s\n"), strerror (errno));
@ -899,19 +1223,45 @@ main (int argc, char **argv)
} }
else if (!strcmp (cmd, "slet")) else if (!strcmp (cmd, "slet"))
{ {
/* Deprecated - never used in a released version. */
assign_variable (p, 1); assign_variable (p, 1);
} }
else if (!strcmp (cmd, "showvar")) else if (!strcmp (cmd, "showvar"))
{ {
show_variables (); 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")) 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")) 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")) else if (!strcmp (cmd, "showdef"))
{ {
@ -934,21 +1284,49 @@ main (int argc, char **argv)
} }
else if (!strcmp (cmd, "sendfd")) 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; continue;
} }
else if (!strcmp (cmd, "recvfd")) 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; continue;
} }
else if (!strcmp (cmd, "open")) 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")) 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")) else if (!strcmp (cmd, "showopen"))
{ {
@ -1012,19 +1390,15 @@ main (int argc, char **argv)
"Available commands:\n" "Available commands:\n"
"/echo ARGS Echo ARGS.\n" "/echo ARGS Echo ARGS.\n"
"/let NAME VALUE Set variable NAME to VALUE.\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" "/showvar Show all variables.\n"
"/definqfile NAME FILE\n" "/definq NAME VAR Use content of VAR for inquiries with NAME.\n"
" Use content of FILE for inquiries with NAME.\n" "/definqfile NAME FILE Use content of FILE for inquiries with NAME.\n"
" NAME may be \"*\" to match any inquiry.\n" "/definqprog NAME PGM Run PGM for inquiries with NAME.\n"
"/definqprog NAME PGM\n"
" Run PGM for inquiries matching NAME and pass the\n"
" entire line to it as arguments.\n"
"/showdef Print all definitions.\n" "/showdef Print all definitions.\n"
"/cleardef Delete all definitions.\n" "/cleardef Delete all definitions.\n"
"/sendfd FILE MODE Open FILE and pass descriptor to server.\n" "/sendfd FILE MODE Open FILE and pass descriptor to server.\n"
"/recvfd Receive FD from server and print.\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" "/close FD Close file with descriptor FD.\n"
"/showopen Show descriptors of all open files.\n" "/showopen Show descriptors of all open files.\n"
"/serverpid Retrieve the pid of the server.\n" "/serverpid Retrieve the pid of the server.\n"
@ -1094,7 +1468,7 @@ handle_inquire (assuan_context_t ctx, char *line)
{ {
const char *name; const char *name;
definq_t d; definq_t d;
FILE *fp; FILE *fp = NULL;
char buffer[1024]; char buffer[1024];
int rc, n; int rc, n;
@ -1126,43 +1500,58 @@ handle_inquire (assuan_context_t ctx, char *line)
return 0; return 0;
} }
if (d->is_prog) if (d->is_var)
{ {
fp = popen (d->file, "r"); char *tmpvalue = get_var_ext (d->file);
if (!fp) rc = assuan_send_data (ctx, tmpvalue, strlen (tmpvalue));
log_error ("error executing `%s': %s\n", d->file, strerror (errno)); xfree (tmpvalue);
else if (opt.verbose) if (rc)
log_error ("handling inquiry `%s' by running `%s'\n", name, d->file); log_error ("sending data back failed: %s\n", gpg_strerror (rc) );
} }
else else
{ {
fp = fopen (d->file, "rb"); if (d->is_prog)
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) ); fp = popen (d->file, "r");
break; 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); rc = assuan_send_data (ctx, NULL, 0);
if (rc) if (rc)
log_error ("sending data back failed: %s\n", gpg_strerror (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)) if (pclose (fp))
log_error ("error running `%s': %s\n", d->file, strerror (errno)); log_error ("error running `%s': %s\n", d->file, strerror (errno));

View File

@ -117,3 +117,24 @@ gcry_control (enum gcry_ctl_cmds CMD, ...)
{ {
return 0; 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;
}