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