aboutsummaryrefslogtreecommitdiffstats
path: root/agent/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/command.c')
-rw-r--r--agent/command.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/agent/command.c b/agent/command.c
new file mode 100644
index 000000000..62950b365
--- /dev/null
+++ b/agent/command.c
@@ -0,0 +1,229 @@
+/* command.c - gpg-agent command handler
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* FIXME: we should not use the default assuan buffering but setup
+ some buffering in secure mempory to protect session keys etc. */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "agent.h"
+#include "../assuan/assuan.h"
+
+#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
+#define digitp(a) ((a) >= '0' && (a) <= '9')
+#define hexdigitp(a) (digitp (a) \
+ || ((a) >= 'A' && (a) <= 'F') \
+ || ((a) >= 'a' && (a) <= 'f'))
+#define atoi_1(p) (*(p) - '0' )
+#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
+/* assumes ASCII and pre-checked values */
+#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
+ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+
+/* Data used to associate an Assuan context with local server data */
+struct server_local_s {
+ ASSUAN_CONTEXT assuan_ctx;
+ int message_fd;
+};
+
+/* SETHASH <hexstring>
+
+ The client can use this command to tell the server about the data
+ (which usually is a hash) to be signed. */
+static int
+cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
+{
+ int n;
+ char *p;
+ CTRL ctrl = assuan_get_pointer (ctx);
+ unsigned char *buf;
+
+ /* parse the hash value */
+ for (p=line,n=0; hexdigitp (*p); p++, n++)
+ ;
+ if (*p)
+ return set_error (Parameter_Error, "invalid hexstring");
+ if ((n&1))
+ return set_error (Parameter_Error, "odd number of digits");
+ n /= 2;
+ if (n != 16 && n != 20 && n != 24 && n != 32)
+ return set_error (Parameter_Error, "unsupported length of hash");
+ if (n > MAX_DIGEST_LEN)
+ return set_error (Parameter_Error, "hash value to long");
+
+ buf = ctrl->digest.value;
+ ctrl->digest.valuelen = n;
+ for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
+ buf[n] = xtoi_2 (p);
+ for (; n < ctrl->digest.valuelen; n++)
+ buf[n] = 0;
+ return 0;
+}
+
+
+/* PKSIGN <options>
+
+ Perform the actual sign operation. Neither input nor output are
+ sensitive to to eavesdropping */
+static int
+cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
+{
+ int rc;
+ CTRL ctrl = assuan_get_pointer (ctx);
+
+ /* fixme: check that all required data is available */
+ rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
+ /* fixme: return an error */
+ return 0;
+}
+
+
+/* MESSAGE FD=<n>
+
+ Set the file descriptor to read a message which is used with
+ detached signatures */
+static int
+cmd_message (ASSUAN_CONTEXT ctx, char *line)
+{
+#if 0
+ char *endp;
+ int fd;
+ CTRL ctrl = assuan_get_pointer (ctx);
+
+ if (strncmp (line, "FD=", 3))
+ return set_error (Syntax_Error, "FD=<n> expected");
+ line += 3;
+ if (!digitp (*line))
+ return set_error (Syntax_Error, "number required");
+ fd = strtoul (line, &endp, 10);
+ if (*endp)
+ return set_error (Syntax_Error, "garbage found");
+ if (fd == -1)
+ return set_error (No_Input, NULL);
+
+ ctrl->server_local->message_fd = fd;
+ return 0;
+#endif
+ return set_error (Not_Implemented, NULL);
+}
+
+
+
+/* Tell the assuan library about our commands */
+static int
+register_commands (ASSUAN_CONTEXT ctx)
+{
+ static struct {
+ const char *name;
+ int cmd_id;
+ int (*handler)(ASSUAN_CONTEXT, char *line);
+ } table[] = {
+ { "SETHASH", 0, cmd_sethash },
+ { "PKSIGN", 0, cmd_pksign },
+ { "", ASSUAN_CMD_INPUT, NULL },
+ { "", ASSUAN_CMD_OUTPUT, NULL },
+ { "MESSAGE", 0, cmd_message },
+ { NULL }
+ };
+ int i, j, rc;
+
+ for (i=j=0; table[i].name; i++)
+ {
+ rc = assuan_register_command (ctx,
+ table[i].cmd_id? table[i].cmd_id
+ : (ASSUAN_CMD_USER + j++),
+ table[i].name, table[i].handler);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+
+/* Startup the server */
+void
+start_command_handler (void)
+{
+ int rc;
+ int filedes[2];
+ ASSUAN_CONTEXT ctx;
+ struct server_control_s ctrl;
+
+ memset (&ctrl, 0, sizeof ctrl);
+
+ /* For now we use a simple pipe based server so that we can work
+ from scripts. We will later add options to run as a daemon and
+ wait for requests on a Unix domain socket */
+ filedes[0] = 0;
+ filedes[1] = 1;
+ rc = assuan_init_pipe_server (&ctx, filedes);
+ if (rc)
+ {
+ log_error ("failed to initialize the server: %s\n",
+ assuan_strerror(rc));
+ agent_exit (2);
+ }
+ rc = register_commands (ctx);
+ if (rc)
+ {
+ log_error ("failed to the register commands with Assuan: %s\n",
+ assuan_strerror(rc));
+ agent_exit (2);
+ }
+
+ assuan_set_pointer (ctx, &ctrl);
+ ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
+ ctrl.server_local->assuan_ctx = ctx;
+ ctrl.server_local->message_fd = -1;
+
+ log_info ("Assuan started\n");
+ for (;;)
+ {
+ rc = assuan_accept (ctx);
+ if (rc == -1)
+ {
+ log_info ("Assuan terminated\n");
+ break;
+ }
+ else if (rc)
+ {
+ log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
+ break;
+ }
+
+ rc = assuan_process (ctx);
+ if (rc)
+ {
+ log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
+ continue;
+ }
+ }
+
+
+ assuan_deinit_pipe_server (ctx);
+}
+