* parse-packet.c (dump_sig_subpkt, parse_signature), build-packet.c
[gnupg.git] / util / assuan-client.c
1 /* assuan-client.c - client functions
2  *      Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3  *      Copyright (C) 2005 Free Software Foundation, Inc.
4  *
5  * This file is part of Assuan.
6  *
7  * Assuan is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Assuan is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20  * USA. 
21  */
22
23 /* Please note that this is a stripped down and modified version of
24    the orginal Assuan code from libassuan. */
25
26 #include <config.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <assert.h>
32 #include <string.h>
33
34 #include "assuan-defs.h"
35
36 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
37                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
38 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
39
40
41 assuan_error_t
42 _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off)
43 {
44   char *line;
45   int linelen;
46   assuan_error_t rc;
47
48   *okay = 0;
49   *off = 0;
50   do 
51     {
52       rc = _assuan_read_line (ctx);
53       if (rc)
54         return rc;
55       line = ctx->inbound.line;
56       linelen = ctx->inbound.linelen;
57     }    
58   while (*line == '#' || !linelen);
59
60   if (linelen >= 1
61       && line[0] == 'D' && line[1] == ' ')
62     {
63       *okay = 2; /* data line */
64       *off = 2;
65     }
66   else if (linelen >= 1
67            && line[0] == 'S' 
68            && (line[1] == '\0' || line[1] == ' '))
69     {
70       *okay = 4;
71       *off = 1;
72       while (line[*off] == ' ')
73         ++*off;
74     }  
75   else if (linelen >= 2
76            && line[0] == 'O' && line[1] == 'K'
77            && (line[2] == '\0' || line[2] == ' '))
78     {
79       *okay = 1;
80       *off = 2;
81       while (line[*off] == ' ')
82         ++*off;
83     }
84   else if (linelen >= 3
85            && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
86            && (line[3] == '\0' || line[3] == ' '))
87     {
88       *okay = 0;
89       *off = 3;
90       while (line[*off] == ' ')
91         ++*off;
92     }  
93   else if (linelen >= 7
94            && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
95            && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
96            && line[6] == 'E' 
97            && (line[7] == '\0' || line[7] == ' '))
98     {
99       *okay = 3;
100       *off = 7;
101       while (line[*off] == ' ')
102         ++*off;
103     }
104   else if (linelen >= 3
105            && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
106            && (line[3] == '\0' || line[3] == ' '))
107     {
108       *okay = 5; /* end line */
109       *off = 3;
110     }
111   else
112     rc = ASSUAN_Invalid_Response;
113   return rc;
114 }
115
116
117 \f
118 assuan_error_t
119 assuan_transact (assuan_context_t ctx,
120                  const char *command,
121                  assuan_error_t (*data_cb)(void *, const void *, size_t),
122                  void *data_cb_arg,
123                  assuan_error_t (*inquire_cb)(void*, const char *),
124                  void *inquire_cb_arg,
125                  assuan_error_t (*status_cb)(void*, const char *),
126                  void *status_cb_arg)
127 {
128   return assuan_transact2 (ctx, command,
129                            data_cb, data_cb_arg,
130                            inquire_cb, inquire_cb_arg,
131                            status_cb, status_cb_arg,
132                            NULL, NULL);
133 }
134
135
136 /**
137  * assuan_transact2:
138  * @ctx: The Assuan context
139  * @command: Coimmand line to be send to server
140  * @data_cb: Callback function for data lines
141  * @data_cb_arg: first argument passed to @data_cb
142  * @inquire_cb: Callback function for a inquire response
143  * @inquire_cb_arg: first argument passed to @inquire_cb
144  * @status_cb: Callback function for a status response
145  * @status_cb_arg: first argument passed to @status_cb
146  * @okay_cb: Callback function for the final  OK response
147  * @okay_cb_arg: first argument passed to @okay_cb
148  * 
149  * FIXME: Write documentation
150  * 
151  * Return value: 0 on success or error code.  The error code may be
152  * the one one returned by the server in error lines or from the
153  * callback functions.
154  **/
155 assuan_error_t
156 assuan_transact2 (assuan_context_t ctx,
157                   const char *command,
158                   assuan_error_t (*data_cb)(void *, const void *, size_t),
159                   void *data_cb_arg,
160                   assuan_error_t (*inquire_cb)(void*, const char *),
161                   void *inquire_cb_arg,
162                   assuan_error_t (*status_cb)(void*, const char *),
163                   void *status_cb_arg,
164                   assuan_error_t (*okay_cb)(void*, const char *),
165                   void *okay_cb_arg)
166 {
167   int rc, okay, off;
168   unsigned char *line;
169   int linelen;
170
171   rc = assuan_write_line (ctx, command);
172   if (rc)
173     return rc;
174
175   if (*command == '#' || !*command)
176     return 0; /* Don't expect a response for a comment line.  */
177
178  again:
179   rc = _assuan_read_from_server (ctx, &okay, &off);
180   if (rc)
181     return rc; /* error reading from server */
182
183   line = ctx->inbound.line + off;
184   linelen = ctx->inbound.linelen - off;
185
186   if (!okay)
187     {
188       rc = atoi (line);
189       if (rc < 100)
190         rc = ASSUAN_Server_Fault;
191     }
192   else if (okay == 1) /* Received OK. */
193     {
194       if (okay_cb)
195         {
196           rc = okay_cb (okay_cb_arg, line);
197           /* We better wipe out the buffer after processing it.  This
198              is no real guarantee that it won't get swapped out but at
199              least for the standard cases we can make sure that a
200              passphrase returned with the OK line is rendered
201              unreadable.  In fact the current Assuan interface suffers
202              from the problem that it is not possible to do assuan I/O
203              through secure memory.  There is no easy solution given
204              the current implementation but we need to address it
205              sooner or later.  The problem was introduced with
206              gpg-agent's GET_PASPHRASE command but it might also make
207              sense to have a way to convey sessions keys through
208              secured memory.  Note that the old implementation in gpg
209              for accessing the passphrase in fact used secure memory
210              but had the drawback of using a limited and not fully
211              conforming Assuan implementation - given that pinentry
212              and gpg-agent neither use secured memory for Assuan I/O,
213              it is negligible to drop the old implementation in gpg's
214              passphrase.c and use the wipememory workaround here.  */
215           memset (line, 0, strlen (line));
216         }
217     }
218   else if (okay == 2)
219     {
220       if (!data_cb)
221         rc = ASSUAN_No_Data_Callback;
222       else 
223         {
224           unsigned char *s, *d;
225
226           for (s=d=line; linelen; linelen--)
227             {
228               if (*s == '%' && linelen > 2)
229                 { /* handle escaping */
230                   s++;
231                   *d++ = xtoi_2 (s);
232                   s += 2;
233                   linelen -= 2;
234                 }
235               else
236                 *d++ = *s++;
237             }
238           *d = 0; /* add a hidden string terminator */
239           rc = data_cb (data_cb_arg, line, d - line);
240           if (!rc)
241             goto again;
242         }
243     }
244   else if (okay == 3)
245     {
246       if (!inquire_cb)
247         {
248           assuan_write_line (ctx, "END"); /* get out of inquire mode */
249           _assuan_read_from_server (ctx, &okay, &off); /* dummy read */
250           rc = ASSUAN_No_Inquire_Callback;
251         }
252       else
253         {
254           rc = inquire_cb (inquire_cb_arg, line);
255           if (!rc)
256             rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
257           if (!rc)
258             goto again;
259         }
260     }
261   else if (okay == 4)
262     {
263       if (status_cb)
264         rc = status_cb (status_cb_arg, line);
265       if (!rc)
266         goto again;
267     }
268   else if (okay == 5)
269     {
270       if (!data_cb)
271         rc = ASSUAN_No_Data_Callback;
272       else 
273         {
274           rc = data_cb (data_cb_arg, NULL, 0);
275           if (!rc)
276             goto again;
277         }
278     }
279
280   return rc;
281 }
282