See ChangeLog: Wed May 19 16:04:30 CEST 1999 Werner Koch
[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     struct http_context hd;
53     char *request;
54     int rc;
55
56     if( !opt.keyserver_name )
57         return -1;
58     log_info("requesting key %08lX from %s ...\n", (ulong)keyid[1],
59                                                    opt.keyserver_name );
60     request = m_alloc( strlen( opt.keyserver_name ) + 100 );
61     /* hkp does not accept the long keyid - we should really write a
62      * nicer one */
63     sprintf( request, "x-hkp://%s:11371/pks/lookup?op=get&search=0x%08lX",
64                         opt.keyserver_name, (ulong)keyid[1] );
65     rc = http_open_document( &hd, request, 0 );
66     if( rc ) {
67         log_info("can't get key from keyserver: %s\n",
68                         rc == G10ERR_NETWORK? strerror(errno)
69                                             : g10_errstr(rc) );
70     }
71     else {
72         rc = import_keys_stream( hd.fp_read , 0 );
73         http_close( &hd );
74     }
75
76     m_free( request );
77     return rc;
78 }
79
80
81
82 int
83 hkp_import( STRLIST users )
84 {
85     if( !opt.keyserver_name ) {
86         log_error("no keyserver known (use option --keyserver)\n");
87         return -1;
88     }
89
90     for( ; users; users = users->next ) {
91         u32 kid[2];
92         int type = classify_user_id( users->d, kid, NULL, NULL, NULL );
93         if( type != 10 && type != 11 ) {
94             log_info("%s: not a valid key ID\n", users->d );
95             continue;
96         }
97         hkp_ask_import( kid );
98     }
99     return 0;
100 }
101
102
103 int
104 hkp_export( STRLIST users )
105 {
106     int rc;
107     armor_filter_context_t afx;
108     IOBUF temp = iobuf_temp();
109     struct http_context hd;
110     char *request;
111     unsigned int status;
112
113     if( !opt.keyserver_name ) {
114         log_error("no keyserver known (use option --keyserver)\n");
115         return -1;
116     }
117
118     iobuf_push_filter( temp, urlencode_filter, NULL );
119
120     memset( &afx, 0, sizeof afx);
121     afx.what = 1;
122     iobuf_push_filter( temp, armor_filter, &afx );
123
124     rc = export_pubkeys_stream( temp, users, 1 );
125     if( rc == -1 ) {
126         iobuf_close(temp);
127         return 0;
128     }
129
130     iobuf_flush_temp( temp );
131
132     request = m_alloc( strlen( opt.keyserver_name ) + 100 );
133     sprintf( request, "x-hkp://%s:11371/pks/add", opt.keyserver_name );
134     rc = http_open( &hd, HTTP_REQ_POST, request , 0 );
135     if( rc ) {
136         log_error("can't connect to `%s': %s\n",
137                    opt.keyserver_name,
138                         rc == G10ERR_NETWORK? strerror(errno)
139                                             : g10_errstr(rc) );
140         iobuf_close(temp);
141         m_free( request );
142         return rc;
143     }
144
145     sprintf( request, "Content-Length: %u\n",
146                       (unsigned)iobuf_get_temp_length(temp) + 9 );
147     iobuf_writestr( hd.fp_write, request );
148     m_free( request );
149     http_start_data( &hd );
150
151     iobuf_writestr( hd.fp_write, "keytext=" );
152     iobuf_write( hd.fp_write, iobuf_get_temp_buffer(temp),
153                               iobuf_get_temp_length(temp) );
154     iobuf_put( hd.fp_write, '\n' );
155     iobuf_flush_temp( temp );
156     iobuf_close(temp);
157
158     rc = http_wait_response( &hd, &status );
159     if( rc ) {
160         log_error("error sending to `%s': %s\n",
161                    opt.keyserver_name, g10_errstr(rc) );
162     }
163     else {
164       #if 1
165         if( opt.verbose ) {
166             int c;
167             while( (c=iobuf_get(hd.fp_read)) != EOF )
168                 putchar( c );
169         }
170       #endif
171         if( (status/100) == 2 )
172             log_info("success sending to `%s' (status=%u)\n",
173                                         opt.keyserver_name, status  );
174         else
175             log_error("failed sending to `%s': status=%u\n",
176                                         opt.keyserver_name, status  );
177     }
178     http_close( &hd );
179     return rc;
180 }
181
182 static int
183 urlencode_filter( void *opaque, int control,
184                   IOBUF a, byte *buf, size_t *ret_len)
185 {
186     size_t size = *ret_len;
187     int rc=0;
188
189     if( control == IOBUFCTRL_FLUSH ) {
190         const byte *p;
191         for(p=buf; size; p++, size-- ) {
192             if( isalnum(*p) || *p == '-' )
193                 iobuf_put( a, *p );
194             else if( *p == ' ' )
195                 iobuf_put( a, '+' );
196             else {
197                 char numbuf[5];
198                 sprintf(numbuf, "%%%02X", *p );
199                 iobuf_writestr(a, numbuf );
200             }
201         }
202     }
203     else if( control == IOBUFCTRL_DESC )
204         *(char**)buf = "urlencode_filter";
205     return rc;
206 }
207