* util.h (digitp, hexdigitp): New ctype like macros.
[gnupg.git] / agent / command.c
1 /* command.c - gpg-agent command handler
2  *      Copyright (C) 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
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
19  */
20
21 /* FIXME: we should not use the default assuan buffering but setup
22    some buffering in secure mempory to protect session keys etc. */
23
24 #include <config.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <unistd.h>
31
32 #include "agent.h"
33 #include "../assuan/assuan.h"
34
35 /* maximum allowed size of the inquired ciphertext */
36 #define MAXLEN_CIPHERTEXT 4096
37
38
39 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
40
41
42 #if MAX_DIGEST_LEN < 20
43 #error MAX_DIGEST_LEN shorter than keygrip
44 #endif
45
46 /* Data used to associate an Assuan context with local server data */
47 struct server_local_s {
48   ASSUAN_CONTEXT assuan_ctx;
49   int message_fd;
50 };
51
52
53 /* Map GNUPG_xxx error codes to Assuan status codes
54    FIXME: duplicated from ../sm/server.c */
55 static int
56 rc_to_assuan_status (int rc)
57 {
58   switch (rc)
59     {
60     case 0: break;
61     case GNUPG_Bad_Certificate:   rc = ASSUAN_Bad_Certificate; break;
62     case GNUPG_Bad_Certificate_Path: rc = ASSUAN_Bad_Certificate_Path; break;
63     case GNUPG_Missing_Certificate: rc = ASSUAN_Missing_Certificate; break;
64     case GNUPG_No_Data:           rc = ASSUAN_No_Data_Available; break;
65     case GNUPG_Bad_Signature:     rc = ASSUAN_Bad_Signature; break;
66     case GNUPG_Not_Implemented:   rc = ASSUAN_Not_Implemented; break;
67     case GNUPG_No_Agent:          rc = ASSUAN_No_Agent; break;
68     case GNUPG_Agent_Error:       rc = ASSUAN_Agent_Error; break;
69     case GNUPG_No_Public_Key:     rc = ASSUAN_No_Public_Key; break;
70     case GNUPG_No_Secret_Key:     rc = ASSUAN_No_Secret_Key; break;
71     case GNUPG_Invalid_Data:      rc = ASSUAN_Invalid_Data; break;
72
73     case GNUPG_Bad_PIN:
74     case GNUPG_Bad_Passphrase:
75       rc = ASSUAN_No_Secret_Key;
76       break;
77
78     case GNUPG_Read_Error: 
79     case GNUPG_Write_Error:
80     case GNUPG_IO_Error: 
81       rc = ASSUAN_Server_IO_Error;
82       break;
83     case GNUPG_Out_Of_Core:    
84     case GNUPG_Resource_Limit: 
85       rc = ASSUAN_Server_Resource_Problem;
86       break;
87     case GNUPG_Bug: 
88     case GNUPG_Internal_Error:   
89       rc = ASSUAN_Server_Bug;
90       break;
91     default: 
92       rc = ASSUAN_Server_Fault;
93       break;
94     }
95   return rc;
96 }
97
98
99 \f
100 static void
101 reset_notify (ASSUAN_CONTEXT ctx)
102 {
103   CTRL ctrl = assuan_get_pointer (ctx);
104
105   memset (ctrl->keygrip, 0, 20);
106   ctrl->have_keygrip = 0;
107   ctrl->digest.valuelen = 0;
108 }
109
110 /* SIGKEY <hexstring_with_keygrip>
111    SETKEY <hexstring_with_keygrip>
112   
113    Set the  key used for a sign or decrypt operation */
114 static int
115 cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
116 {
117   int n;
118   char *p;
119   CTRL ctrl = assuan_get_pointer (ctx);
120   unsigned char *buf;
121
122   /* parse the hash value */
123   for (p=line,n=0; hexdigitp (p); p++, n++)
124     ;
125   if (*p)
126     return set_error (Parameter_Error, "invalid hexstring");
127   if ((n&1))
128     return set_error (Parameter_Error, "odd number of digits");
129   n /= 2;
130   if (n != 20)
131     return set_error (Parameter_Error, "invalid length of keygrip");
132
133   buf = ctrl->keygrip;
134   for (p=line, n=0; n < 20; p += 2, n++)
135     buf[n] = xtoi_2 (p);
136   ctrl->have_keygrip = 1;
137   return 0;
138 }
139
140 /* SETHASH <algonumber> <hexstring> 
141
142   The client can use this command to tell the server about the data
143   (which usually is a hash) to be signed. */
144 static int
145 cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
146 {
147   int n;
148   char *p;
149   CTRL ctrl = assuan_get_pointer (ctx);
150   unsigned char *buf;
151   char *endp;
152   int algo;
153
154   /* parse the algo number and check it */
155   algo = (int)strtoul (line, &endp, 10);
156   for (line = endp; *line == ' ' || *line == '\t'; line++)
157     ;
158   if (!algo || gcry_md_test_algo (algo))
159     return set_error (Unsupported_Algorithm, NULL);
160   ctrl->digest.algo = algo;
161
162   /* parse the hash value */
163   for (p=line,n=0; hexdigitp (p); p++, n++)
164     ;
165   if (*p)
166     return set_error (Parameter_Error, "invalid hexstring");
167   if ((n&1))
168     return set_error (Parameter_Error, "odd number of digits");
169   n /= 2;
170   if (n != 16 && n != 20 && n != 24 && n != 32)
171     return set_error (Parameter_Error, "unsupported length of hash");
172   if (n > MAX_DIGEST_LEN)
173     return set_error (Parameter_Error, "hash value to long");
174
175   buf = ctrl->digest.value;
176   ctrl->digest.valuelen = n;
177   for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
178     buf[n] = xtoi_2 (p);
179   for (; n < ctrl->digest.valuelen; n++)
180     buf[n] = 0;
181   return 0;
182 }
183
184
185 /* PKSIGN <options>
186
187    Perform the actual sign operation. Neither input nor output are
188    sensitive to eavesdropping */
189 static int
190 cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
191 {
192   int rc;
193   CTRL ctrl = assuan_get_pointer (ctx);
194
195   rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
196   return rc_to_assuan_status (rc);
197 }
198
199 /* PKDECRYPT <options>
200
201    Perform the actual decrypt operation.  Input is not 
202    sensitive to eavesdropping */
203 static int
204 cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
205 {
206   int rc;
207   CTRL ctrl = assuan_get_pointer (ctx);
208   char *value;
209   size_t valuelen;
210
211   /* First inquire the data to decrypt */
212   rc = assuan_inquire (ctx, "CIPHERTEXT",
213                        &value, &valuelen, MAXLEN_CIPHERTEXT);
214   if (rc)
215     return rc;
216
217   rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
218   xfree (value);
219   return rc_to_assuan_status (rc);
220 }
221
222
223 \f
224 /* Tell the assuan library about our commands */
225 static int
226 register_commands (ASSUAN_CONTEXT ctx)
227 {
228   static struct {
229     const char *name;
230     int cmd_id;
231     int (*handler)(ASSUAN_CONTEXT, char *line);
232   } table[] = {
233     { "SIGKEY",     0,  cmd_sigkey },
234     { "SETKEY",     0,  cmd_sigkey },
235     { "SETHASH",    0,  cmd_sethash },
236     { "PKSIGN",     0,  cmd_pksign },
237     { "PKDECRYPT",  0,  cmd_pkdecrypt },
238     { "",     ASSUAN_CMD_INPUT, NULL }, 
239     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
240     { NULL }
241   };
242   int i, j, rc;
243
244   for (i=j=0; table[i].name; i++)
245     {
246       rc = assuan_register_command (ctx,
247                                     table[i].cmd_id? table[i].cmd_id
248                                                    : (ASSUAN_CMD_USER + j++),
249                                     table[i].name, table[i].handler);
250       if (rc)
251         return rc;
252     } 
253   assuan_register_reset_notify (ctx, reset_notify);
254   return 0;
255 }
256
257
258 /* Startup the server */
259 void
260 start_command_handler (void)
261 {
262   int rc;
263   int filedes[2];
264   ASSUAN_CONTEXT ctx;
265   struct server_control_s ctrl;
266
267   memset (&ctrl, 0, sizeof ctrl);
268
269   /* For now we use a simple pipe based server so that we can work
270      from scripts.  We will later add options to run as a daemon and
271      wait for requests on a Unix domain socket */
272   filedes[0] = 0;
273   filedes[1] = 1;
274   rc = assuan_init_pipe_server (&ctx, filedes);
275   if (rc)
276     {
277       log_error ("failed to initialize the server: %s\n",
278                  assuan_strerror(rc));
279       agent_exit (2);
280     }
281   rc = register_commands (ctx);
282   if (rc)
283     {
284       log_error ("failed to the register commands with Assuan: %s\n",
285                  assuan_strerror(rc));
286       agent_exit (2);
287     }
288
289   assuan_set_pointer (ctx, &ctrl);
290   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
291   ctrl.server_local->assuan_ctx = ctx;
292   ctrl.server_local->message_fd = -1;
293
294   for (;;)
295     {
296       rc = assuan_accept (ctx);
297       if (rc == -1)
298         {
299           break;
300         }
301       else if (rc)
302         {
303           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
304           break;
305         }
306       
307       rc = assuan_process (ctx);
308       if (rc)
309         {
310           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
311           continue;
312         }
313     }
314
315
316   assuan_deinit_pipe_server (ctx);
317 }
318