* call-agent.c (start_agent): Make copies of old locales and check
[gnupg.git] / g10 / hkp.c
1 /* hkp.c  -  Horrowitz Keyserver Protocol
2  *      Copyright (C) 1999 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 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <assert.h>
28
29 #include "errors.h"
30 #include "util.h"
31 #include "ttyio.h"
32 #include "i18n.h"
33 #include "options.h"
34 #include "filter.h"
35 #include "http.h"
36 #include "main.h"
37
38 static int urlencode_filter( void *opaque, int control,
39                              IOBUF a, byte *buf, size_t *ret_len);
40
41 /****************
42  * Try to import the key with KEYID from a keyserver but ask the user
43  * before doing so.
44  * Returns: 0 the key was successfully imported
45  *          -1 key not found on server or user does not want to
46  *             import the key
47  *          or other error codes.
48  */
49 int
50 hkp_ask_import( u32 *keyid )
51 {
52   #ifdef HAVE_DOSISH_SYSTEM
53     return -1;
54   #else
55     struct http_context hd;
56     char *request;
57     int rc;
58     unsigned int hflags = opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0;
59
60     if( !opt.keyserver_name )
61         return -1;
62     log_info(_("requesting key %08lX from %s ...\n"), (ulong)keyid[1],
63                                                    opt.keyserver_name );
64     request = gcry_xmalloc( strlen( opt.keyserver_name ) + 100 );
65     /* hkp does not accept the long keyid - we should really write a
66      * nicer one :-)
67      * FIXME: request binary mode - need to pass no_armor mode
68      * down to the import function.  Marc told that there is such a
69      * binary mode ... how?
70      */
71     sprintf( request, "x-hkp://%s:11371/pks/lookup?op=get&search=0x%08lX",
72                         opt.keyserver_name, (ulong)keyid[1] );
73     rc = http_open_document( &hd, request, hflags );
74     if( rc ) {
75         log_info(_("can't get key from keyserver: %s\n"),
76                         rc == GPGERR_NETWORK? strerror(errno)
77                                             : gpg_errstr(rc) );
78     }
79     else {
80         rc = import_keys_stream( hd.fp_read , 0 );
81         http_close( &hd );
82     }
83
84     gcry_free( request );
85     return rc;
86   #endif
87 }
88
89
90
91 int
92 hkp_import( STRLIST users )
93 {
94   #ifdef HAVE_DOSISH_SYSTEM
95     return -1;
96   #else
97     if( !opt.keyserver_name ) {
98         log_error(_("no keyserver known (use option --keyserver)\n"));
99         return -1;
100     }
101
102     for( ; users; users = users->next ) {
103         u32 kid[2];
104         int type = classify_user_id( users->d, kid, NULL, NULL, NULL );
105         if( type != 10 && type != 11 ) {
106             log_info(_("%s: not a valid key ID\n"), users->d );
107             continue;
108         }
109         /* because the function may use log_info in some situations, the
110          * errorcounter ist not increaed and the program will return
111          * with success - which is not good when this function is used.
112          */
113         if( hkp_ask_import( kid ) )
114             log_inc_errorcount();
115     }
116     return 0;
117   #endif
118 }
119
120
121 int
122 hkp_export( STRLIST users )
123 {
124   #ifdef HAVE_DOSISH_SYSTEM
125     return -1;
126   #else
127     int rc;
128     armor_filter_context_t afx;
129     IOBUF temp = iobuf_temp();
130     struct http_context hd;
131     char *request;
132     unsigned int status;
133     unsigned int hflags = opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0;
134
135     if( !opt.keyserver_name ) {
136         log_error(_("no keyserver known (use option --keyserver)\n"));
137         return -1;
138     }
139
140     iobuf_push_filter( temp, urlencode_filter, NULL );
141
142     memset( &afx, 0, sizeof afx);
143     afx.what = 1;
144     iobuf_push_filter( temp, armor_filter, &afx );
145
146     rc = export_pubkeys_stream( temp, users, 1 );
147     if( rc == -1 ) {
148         iobuf_close(temp);
149         return 0;
150     }
151
152     iobuf_flush_temp( temp );
153
154     request = gcry_xmalloc( strlen( opt.keyserver_name ) + 100 );
155     sprintf( request, "x-hkp://%s:11371/pks/add", opt.keyserver_name );
156     rc = http_open( &hd, HTTP_REQ_POST, request , hflags );
157     if( rc ) {
158         log_error(_("can't connect to `%s': %s\n"),
159                    opt.keyserver_name,
160                         rc == GPGERR_NETWORK? strerror(errno)
161                                             : gpg_errstr(rc) );
162         iobuf_close(temp);
163         gcry_free( request );
164         return rc;
165     }
166
167     sprintf( request, "Content-Length: %u\n",
168                       (unsigned)iobuf_get_temp_length(temp) + 9 );
169     iobuf_writestr( hd.fp_write, request );
170     gcry_free( request );
171     http_start_data( &hd );
172
173     iobuf_writestr( hd.fp_write, "keytext=" );
174     iobuf_write( hd.fp_write, iobuf_get_temp_buffer(temp),
175                               iobuf_get_temp_length(temp) );
176     iobuf_put( hd.fp_write, '\n' );
177     iobuf_flush_temp( temp );
178     iobuf_close(temp);
179
180     rc = http_wait_response( &hd, &status );
181     if( rc ) {
182         log_error(_("error sending to `%s': %s\n"),
183                    opt.keyserver_name, gpg_errstr(rc) );
184     }
185     else {
186       #if 1
187         if( opt.verbose ) {
188             int c;
189             while( (c=iobuf_get(hd.fp_read)) != EOF )
190                 putchar( c );
191         }
192       #endif
193         if( (status/100) == 2 )
194             log_info(_("success sending to `%s' (status=%u)\n"),
195                                         opt.keyserver_name, status  );
196         else
197             log_error(_("failed sending to `%s': status=%u\n"),
198                                         opt.keyserver_name, status  );
199     }
200     http_close( &hd );
201     return rc;
202   #endif
203 }
204
205 static int
206 urlencode_filter( void *opaque, int control,
207                   IOBUF a, byte *buf, size_t *ret_len)
208 {
209     size_t size = *ret_len;
210     int rc=0;
211
212     if( control == IOBUFCTRL_FLUSH ) {
213         const byte *p;
214         for(p=buf; size; p++, size-- ) {
215             if( isalnum(*p) || *p == '-' )
216                 iobuf_put( a, *p );
217             else if( *p == ' ' )
218                 iobuf_put( a, '+' );
219             else {
220                 char numbuf[5];
221                 sprintf(numbuf, "%%%02X", *p );
222                 iobuf_writestr(a, numbuf );
223             }
224         }
225     }
226     else if( control == IOBUFCTRL_DESC )
227         *(char**)buf = "urlencode_filter";
228     return rc;
229 }
230