2005-04-11 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / tools / gpg-connect-agent.c
blob19ff160f01910003ac9e6b60c1af838e8a337adb
1 /* gpg-connect-agent.c - Tool to connect to the agent.
2 * Copyright (C) 2005 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <assuan.h>
30 #include "i18n.h"
31 #include "../common/util.h"
32 #include "../common/asshelp.h"
36 /* Constants to identify the commands and options. */
37 enum cmd_and_opt_values
39 aNull = 0,
40 oQuiet = 'q',
41 oVerbose = 'v',
43 oNoVerbose = 500,
44 oHomedir,
45 oHex
50 /* The list of commands and options. */
51 static ARGPARSE_OPTS opts[] =
53 { 301, NULL, 0, N_("@\nOptions:\n ") },
55 { oVerbose, "verbose", 0, N_("verbose") },
56 { oQuiet, "quiet", 0, N_("quiet") },
57 { oHex, "hex", 0, N_("print data out hex encoded") },
59 /* hidden options */
60 { oNoVerbose, "no-verbose", 0, "@"},
61 { oHomedir, "homedir", 2, "@" },
62 {0}
66 /* We keep all global options in the structure OPT. */
67 struct
69 int verbose; /* Verbosity level. */
70 int quiet; /* Be extra quiet. */
71 const char *homedir; /* Configuration directory name */
72 int hex; /* Print data lines in hex format. */
73 } opt;
76 /*-- local prototypes --*/
77 static int read_and_print_response (assuan_context_t ctx);
78 static assuan_context_t start_agent (void);
83 /* Print usage information and and provide strings for help. */
84 static const char *
85 my_strusage( int level )
87 const char *p;
89 switch (level)
91 case 11: p = "gpg-connect-agent (GnuPG)";
92 break;
93 case 13: p = VERSION; break;
94 case 17: p = PRINTABLE_OS_NAME; break;
95 case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
96 break;
97 case 1:
98 case 40: p = _("Usage: gpg-connect-agent [options] (-h for help)");
99 break;
100 case 41:
101 p = _("Syntax: gpg-connect-agent [options]\n"
102 "Connect to a running agent and send commands\n");
103 break;
104 case 31: p = "\nHome: "; break;
105 case 32: p = opt.homedir; break;
106 case 33: p = "\n"; break;
108 default: p = NULL; break;
110 return p;
114 /* Initialize the gettext system. */
115 static void
116 i18n_init(void)
118 #ifdef USE_SIMPLE_GETTEXT
119 set_gettext_file (PACKAGE_GT);
120 #else
121 # ifdef ENABLE_NLS
122 setlocale (LC_ALL, "" );
123 bindtextdomain (PACKAGE_GT, LOCALEDIR);
124 textdomain (PACKAGE_GT);
125 # endif
126 #endif
130 /* gpg-connect-agent's entry point. */
132 main (int argc, char **argv)
134 ARGPARSE_ARGS pargs;
135 const char *fname;
136 int no_more_options = 0;
137 assuan_context_t ctx;
138 char *line;
139 size_t linesize;
140 int rc;
142 set_strusage (my_strusage);
143 log_set_prefix ("gpg-connect-agent", 1);
145 i18n_init();
147 opt.homedir = default_homedir ();
149 /* Parse the command line. */
150 pargs.argc = &argc;
151 pargs.argv = &argv;
152 pargs.flags = 1; /* Do not remove the args. */
153 while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
155 switch (pargs.r_opt)
157 case oQuiet: opt.quiet = 1; break;
158 case oVerbose: opt.verbose++; break;
159 case oNoVerbose: opt.verbose = 0; break;
160 case oHomedir: opt.homedir = pargs.r.ret_str; break;
161 case oHex: opt.hex = 1; break;
163 default: pargs.err = 2; break;
167 if (log_get_errorcount (0))
168 exit (2);
170 fname = argc ? *argv : NULL;
172 ctx = start_agent ();
173 line = NULL;
174 linesize = 0;
175 for (;;)
177 int n;
178 size_t maxlength;
180 maxlength = 2048;
181 n = read_line (stdin, &line, &linesize, &maxlength);
182 if (n < 0)
184 log_error (_("error reading input: %s\n"), strerror (errno));
185 exit (1);
187 if (!n)
188 break; /* EOF */
189 if (!maxlength)
191 log_error (_("line too long - skipped\n"));
192 continue;
194 if (memchr (line, 0, n))
195 log_info (_("line shortened due to embedded Nul character\n"));
196 if (line[n-1] == '\n')
197 line[n-1] = 0;
198 rc = assuan_write_line (ctx, line);
199 if (rc)
201 log_info (_("sending line failed: %s\n"), assuan_strerror (rc) );
202 continue;
204 if (*line == '#' || !*line)
205 continue; /* Don't expect a response for a coment line. */
207 rc = read_and_print_response (ctx);
208 if (rc)
209 log_info (_("receiving line failed: %s\n"), assuan_strerror (rc) );
212 if (opt.verbose)
213 log_info ("closing connection to agent\n");
215 return 0;
219 /* Read all response lines from server and print them. Returns 0 on
220 success or an assuan error code. */
221 static int
222 read_and_print_response (assuan_context_t ctx)
224 char *line;
225 int linelen;
226 assuan_error_t rc;
227 int i, j;
229 for (;;)
233 rc = assuan_read_line (ctx, &line, &linelen);
234 if (rc)
235 return rc;
237 while (*line == '#' || !linelen);
239 if (linelen >= 1
240 && line[0] == 'D' && line[1] == ' ')
242 if (opt.hex)
244 for (i=2; i < linelen; )
246 int save_i = i;
248 printf ("D[%04X] ", i-2);
249 for (j=0; j < 16 ; j++, i++)
251 if (j == 8)
252 putchar (' ');
253 if (i < linelen)
254 printf (" %02X", ((unsigned char*)line)[i]);
255 else
256 fputs (" ", stdout);
258 fputs (" ", stdout);
259 i= save_i;
260 for (j=0; j < 16; j++, i++)
262 unsigned int c = ((unsigned char*)line)[i];
263 if ( i >= linelen )
264 putchar (' ');
265 else if (isascii (c) && isprint (c) && !iscntrl (c))
266 putchar (c);
267 else
268 putchar ('.');
270 putchar ('\n');
273 else
275 fwrite (line, linelen, 1, stdout);
276 putchar ('\n');
279 else if (linelen >= 1
280 && line[0] == 'S'
281 && (line[1] == '\0' || line[1] == ' '))
283 fwrite (line, linelen, 1, stdout);
284 putchar ('\n');
286 else if (linelen >= 2
287 && line[0] == 'O' && line[1] == 'K'
288 && (line[2] == '\0' || line[2] == ' '))
290 fwrite (line, linelen, 1, stdout);
291 putchar ('\n');
292 return 0;
294 else if (linelen >= 3
295 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
296 && (line[3] == '\0' || line[3] == ' '))
298 fwrite (line, linelen, 1, stdout);
299 putchar ('\n');
300 return 0;
302 else if (linelen >= 7
303 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
304 && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
305 && line[6] == 'E'
306 && (line[7] == '\0' || line[7] == ' '))
308 fwrite (line, linelen, 1, stdout);
309 putchar ('\n');
310 return 0;
312 else if (linelen >= 3
313 && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
314 && (line[3] == '\0' || line[3] == ' '))
316 fwrite (line, linelen, 1, stdout);
317 putchar ('\n');
318 /* Received from server, thus more responses are expected. */
320 else
321 return ASSUAN_Invalid_Response;
328 /* Connect to teh agebnt and send the standard options. */
329 static assuan_context_t
330 start_agent (void)
332 int rc = 0;
333 char *infostr, *p;
334 assuan_context_t ctx;
336 infostr = getenv ("GPG_AGENT_INFO");
337 if (!infostr || !*infostr)
339 char *sockname;
341 /* Check whether we can connect at the standard socket. */
342 sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
343 rc = assuan_socket_connect (&ctx, sockname, 0);
344 xfree (sockname);
346 else
348 int prot;
349 int pid;
351 infostr = xstrdup (infostr);
352 if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
354 log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
355 xfree (infostr);
356 exit (1);
358 *p++ = 0;
359 pid = atoi (p);
360 while (*p && *p != ':')
361 p++;
362 prot = *p? atoi (p+1) : 0;
363 if (prot != 1)
365 log_error (_("gpg-agent protocol version %d is not supported\n"),
366 prot);
367 xfree (infostr);
368 exit (1);
371 rc = assuan_socket_connect (&ctx, infostr, pid);
372 xfree (infostr);
375 if (rc)
377 log_error ("can't connect to the agent: %s\n", assuan_strerror (rc));
378 exit (1);
381 if (opt.verbose)
382 log_info ("connection to agent established\n");
384 rc = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
385 if (rc)
387 log_error (_("error sending %s command: %s\n"), "RESET",
388 assuan_strerror (rc));
389 exit (1);
392 rc = send_pinentry_environment (ctx, GPG_ERR_SOURCE_DEFAULT,
393 NULL, NULL, NULL, NULL, NULL);
394 if (rc)
396 log_error (_("error sending standard options: %s\n"), gpg_strerror (rc));
397 exit (1);
400 return ctx;