~ubuntu-branches/ubuntu/hardy/gnupg/hardy-updates

« back to all changes in this revision

Viewing changes to keyserver/gpgkeys_hkp.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2005-12-16 16:57:39 UTC
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20051216165739-v0m2d1you6hd8jho
Tags: upstream-1.4.2
ImportĀ upstreamĀ versionĀ 1.4.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 *
16
16
 * You should have received a copy of the GNU General Public License
17
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
 
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
 
19
 * USA.
19
20
 */
20
21
 
21
22
#include <config.h>
22
23
#include <stdio.h>
23
24
#include <string.h>
24
 
#include <ctype.h>
25
25
#include <stdlib.h>
26
26
#include <errno.h>
27
27
#include <unistd.h>
28
28
#ifdef HAVE_GETOPT_H
29
29
#include <getopt.h>
30
30
#endif
31
 
#define INCLUDED_BY_MAIN_MODULE 1
32
 
#include "util.h"
33
 
#include "http.h"
 
31
#ifdef FAKE_CURL
 
32
#include "curl-shim.h"
 
33
#else
 
34
#include <curl/curl.h>
 
35
#endif
34
36
#include "keyserver.h"
35
37
#include "ksutil.h"
36
38
 
37
39
extern char *optarg;
38
40
extern int optind;
39
41
 
40
 
static int verbose=0,include_revoked=0,include_disabled=0;
41
 
static unsigned int http_flags=0;
42
 
static char host[MAX_HOST+1]={'\0'},proxy[MAX_PROXY+1]={'\0'},port[MAX_PORT+1]={'\0'};
43
 
static FILE *input=NULL,*output=NULL,*console=NULL;
44
 
 
45
 
#ifdef __riscos__
46
 
#define HTTP_PROXY_ENV           "GnuPG$HttpProxy"
47
 
#else
48
 
#define HTTP_PROXY_ENV           "http_proxy"
49
 
#endif
50
 
 
51
 
int
52
 
urlencode_filter( void *opaque, int control,
53
 
                  IOBUF a, byte *buf, size_t *ret_len)
 
42
static FILE *input,*output,*console;
 
43
static CURL *curl;
 
44
static struct ks_options *opt;
 
45
static char errorbuffer[CURL_ERROR_SIZE];
 
46
 
 
47
static size_t
 
48
curl_mrindex_writer(const void *ptr,size_t size,size_t nmemb,void *stream)
54
49
{
55
 
    size_t size = *ret_len;
56
 
    int rc=0;
57
 
 
58
 
    if( control == IOBUFCTRL_FLUSH ) {
59
 
        const byte *p;
60
 
        for(p=buf; size; p++, size-- ) {
61
 
            if( isalnum(*p) || *p == '-' )
62
 
                iobuf_put( a, *p );
63
 
            else if( *p == ' ' )
64
 
                iobuf_put( a, '+' );
65
 
            else {
66
 
                char numbuf[5];
67
 
                sprintf(numbuf, "%%%02X", *p );
68
 
                iobuf_writestr(a, numbuf );
69
 
            }
70
 
        }
 
50
  static int checked=0,swallow=0;
 
51
 
 
52
  if(!checked)
 
53
    {
 
54
      /* If the document begins with a '<', assume it's a HTML
 
55
         response, which we don't support.  Discard the whole message
 
56
         body.  GPG can handle it, but this is an optimization to deal
 
57
         with it on this side of the pipe.  */
 
58
      const char *buf=ptr;
 
59
      if(buf[0]=='<')
 
60
        swallow=1;
 
61
 
 
62
      checked=1;
71
63
    }
72
 
    else if( control == IOBUFCTRL_DESC )
73
 
        *(char**)buf = "urlencode_filter";
74
 
    return rc;
 
64
 
 
65
  if(swallow || fwrite(ptr,size,nmemb,stream)==nmemb)
 
66
    return size*nmemb;
 
67
  else
 
68
    return 0;
 
69
}
 
70
 
 
71
/* Append but avoid creating a double slash // in the path. */
 
72
static char *
 
73
append_path(char *dest,const char *src)
 
74
{
 
75
  size_t n=strlen(dest);
 
76
 
 
77
  if(src[0]=='/' && n>0 && dest[n-1]=='/')
 
78
    dest[n-1]='\0';
 
79
 
 
80
  return strcat(dest,src);
75
81
}
76
82
 
77
83
int
78
84
send_key(int *eof)
79
85
{
80
 
  int rc,begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
 
86
  CURLcode res;
 
87
  char request[MAX_URL+15];
 
88
  int begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
81
89
  char keyid[17];
82
 
  char *request;
83
 
  struct http_context hd;
84
 
  unsigned int status;
85
 
  IOBUF temp = iobuf_temp();
86
90
  char line[MAX_LINE];
87
 
 
88
 
  memset(&hd,0,sizeof(hd));
89
 
 
90
 
  request=malloc(strlen(host)+100);
91
 
  if(!request)
 
91
  char *key,*encoded_key=NULL;
 
92
  size_t keylen=8,keymax=8;
 
93
 
 
94
  key=malloc(9);
 
95
  if(!key)
92
96
    {
93
97
      fprintf(console,"gpgkeys: out of memory\n");
94
 
      return KEYSERVER_NO_MEMORY;
 
98
      ret=KEYSERVER_NO_MEMORY;
 
99
      goto fail;
95
100
    }
96
101
 
97
 
  iobuf_push_filter(temp,urlencode_filter,NULL);
 
102
  strcpy(key,"keytext=");
98
103
 
99
104
  /* Read and throw away input until we see the BEGIN */
100
105
 
123
128
        break;
124
129
      }
125
130
    else
126
 
      if(iobuf_writestr(temp,line))
127
 
        {
128
 
          fprintf(console,"gpgkeys: internal iobuf error\n");
129
 
          goto fail;
130
 
        }
 
131
      {
 
132
        if(strlen(line)+keylen>keymax)
 
133
          {
 
134
            char *tmp;
 
135
 
 
136
            keymax+=200;
 
137
            tmp=realloc(key,keymax+1);
 
138
            if(!tmp)
 
139
              {
 
140
                free(key);
 
141
                fprintf(console,"gpgkeys: out of memory\n");
 
142
                ret=KEYSERVER_NO_MEMORY;
 
143
                goto fail;
 
144
              }
 
145
 
 
146
            key=tmp;
 
147
          }
 
148
 
 
149
        strcpy(&key[keylen],line);
 
150
        keylen+=strlen(line);
 
151
      }
131
152
 
132
153
  if(!end)
133
154
    {
137
158
      goto fail;
138
159
    }
139
160
 
140
 
  iobuf_flush_temp(temp);
141
 
 
142
 
  sprintf(request,"hkp://%s%s%s/pks/add",host,port[0]?":":"",port[0]?port:"");
143
 
 
144
 
  if(verbose>2)
 
161
  encoded_key=curl_escape(key,keylen);
 
162
  if(!encoded_key)
 
163
    {
 
164
      fprintf(console,"gpgkeys: out of memory\n");
 
165
      ret=KEYSERVER_NO_MEMORY;
 
166
      goto fail;
 
167
    }
 
168
 
 
169
  strcpy(request,"http://");
 
170
  strcat(request,opt->host);
 
171
  strcat(request,":");
 
172
  if(opt->port)
 
173
    strcat(request,opt->port);
 
174
  else
 
175
    strcat(request,"11371");
 
176
  strcat(request,opt->path);
 
177
  /* request is MAX_URL+15 bytes long - MAX_URL covers the whole URL,
 
178
     including any supplied path.  The 15 covers /pks/add. */
 
179
  append_path(request,"/pks/add");
 
180
 
 
181
  if(opt->verbose>2)
145
182
    fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
146
183
 
147
 
  rc=http_open(&hd,HTTP_REQ_POST,request,http_flags,proxy[0]?proxy:NULL);
148
 
  if(rc)
149
 
    {
150
 
      fprintf(console,"gpgkeys: unable to connect to `%s'\n",host);
151
 
      goto fail;
152
 
    }
153
 
 
154
 
  /* Some keyservers require this Content-Type (e.g. CryptoEx). */
155
 
  iobuf_writestr(hd.fp_write,
156
 
                 "Content-Type: application/x-www-form-urlencoded\r\n");
157
 
 
158
 
  sprintf(request,"Content-Length: %u\r\n",
159
 
          (unsigned)iobuf_get_temp_length(temp)+9);
160
 
  iobuf_writestr(hd.fp_write,request);
161
 
 
162
 
  http_start_data(&hd);
163
 
 
164
 
  iobuf_writestr(hd.fp_write,"keytext=");
165
 
  iobuf_write(hd.fp_write,
166
 
              iobuf_get_temp_buffer(temp),iobuf_get_temp_length(temp));
167
 
  iobuf_put(hd.fp_write,'\n');
168
 
 
169
 
  rc=http_wait_response(&hd,&status);
170
 
  if(rc)
171
 
    {
172
 
      fprintf(console,"gpgkeys: error sending to `%s': %s\n",
173
 
              host,g10_errstr(rc));
174
 
      goto fail;
175
 
    }
176
 
 
177
 
  if((status/100)!=2)
178
 
    {
179
 
      fprintf(console,"gpgkeys: remote server returned error %d\n",status);
180
 
      goto fail;
181
 
    }
182
 
 
183
 
  fprintf(output,"KEY %s SENT\n",keyid);
 
184
  curl_easy_setopt(curl,CURLOPT_URL,request);
 
185
  curl_easy_setopt(curl,CURLOPT_POST,1);
 
186
  curl_easy_setopt(curl,CURLOPT_POSTFIELDS,encoded_key);
 
187
  curl_easy_setopt(curl,CURLOPT_FAILONERROR,1);
 
188
 
 
189
  res=curl_easy_perform(curl);
 
190
  if(res!=0)
 
191
    {
 
192
      fprintf(console,"gpgkeys: HTTP post error %d: %s\n",res,errorbuffer);
 
193
      ret=curl_err_to_gpg_err(res);
 
194
    }
 
195
  else
 
196
    fprintf(output,"\nKEY %s SENT\n",keyid);
184
197
 
185
198
  ret=KEYSERVER_OK;
186
199
 
187
200
 fail:
188
 
  free(request);
189
 
  iobuf_close(temp);
190
 
  http_close(&hd);
 
201
  free(key);
 
202
  curl_free(encoded_key);
191
203
 
192
204
  if(ret!=0 && begin)
193
205
    fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
195
207
  return ret;
196
208
}
197
209
 
198
 
int
 
210
static int
199
211
get_key(char *getkey)
200
212
{
201
 
  int rc,gotit=0;
202
 
  char search[29];
203
 
  char *request;
204
 
  struct http_context hd;
 
213
  CURLcode res;
 
214
  char request[MAX_URL+60];
 
215
  char *offset;
 
216
  struct curl_writer_ctx ctx;
 
217
 
 
218
  memset(&ctx,0,sizeof(ctx));
205
219
 
206
220
  /* Build the search string.  HKP only uses the short key IDs. */
207
221
 
208
222
  if(strncmp(getkey,"0x",2)==0)
209
223
    getkey+=2;
210
224
 
 
225
  fprintf(output,"KEY 0x%s BEGIN\n",getkey);
 
226
 
211
227
  if(strlen(getkey)==32)
212
228
    {
213
229
      fprintf(console,
214
230
              "gpgkeys: HKP keyservers do not support v3 fingerprints\n");
215
 
      fprintf(output,"KEY 0x%s BEGIN\n",getkey);
216
231
      fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
217
232
      return KEYSERVER_NOT_SUPPORTED;
218
233
    }
219
234
 
220
 
 if(strlen(getkey)>8)
221
 
    {
222
 
      char *offset=&getkey[strlen(getkey)-8];
223
 
 
224
 
      /* fingerprint or long key id.  Take the last 8 characters and
225
 
         treat it like a short key id */
226
 
 
227
 
      sprintf(search,"0x%.8s",offset);
228
 
    }
229
 
 else
230
 
   {
231
 
      /* short key id */
232
 
 
233
 
      sprintf(search,"0x%.8s",getkey);
234
 
    }
235
 
 
236
 
  fprintf(output,"KEY 0x%s BEGIN\n",getkey);
237
 
 
238
 
  request=malloc(strlen(host)+100);
239
 
  if(!request)
240
 
    {
241
 
      fprintf(console,"gpgkeys: out of memory\n");
242
 
      return KEYSERVER_NO_MEMORY;
243
 
    }
244
 
 
245
 
  sprintf(request,"hkp://%s%s%s/pks/lookup?op=get&options=mr&search=%s",
246
 
          host,port[0]?":":"",port[0]?port:"", search);
247
 
 
248
 
  if(verbose>2)
 
235
  strcpy(request,"http://");
 
236
  strcat(request,opt->host);
 
237
  strcat(request,":");
 
238
  if(opt->port)
 
239
    strcat(request,opt->port);
 
240
  else
 
241
    strcat(request,"11371");
 
242
  strcat(request,opt->path);
 
243
  /* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
 
244
     including any supplied path.  The 60 overcovers this /pks/... etc
 
245
     string plus the 8 bytes of key id */
 
246
  append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
 
247
 
 
248
  /* fingerprint or long key id.  Take the last 8 characters and treat
 
249
     it like a short key id */
 
250
  if(strlen(getkey)>8)
 
251
    offset=&getkey[strlen(getkey)-8];
 
252
  else
 
253
    offset=getkey;
 
254
 
 
255
  strcat(request,offset);
 
256
 
 
257
  if(opt->verbose>2)
249
258
    fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
250
259
 
251
 
  rc=http_open_document(&hd,request,http_flags,proxy[0]?proxy:NULL);
252
 
  if(rc!=0)
 
260
  curl_easy_setopt(curl,CURLOPT_URL,request);
 
261
  curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
 
262
  ctx.stream=output;
 
263
  curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
 
264
 
 
265
  res=curl_easy_perform(curl);
 
266
  if(res!=0)
253
267
    {
254
 
      fprintf(console,"gpgkeys: HKP fetch error: %s\n",
255
 
              rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
256
 
      fprintf(output,"KEY 0x%s FAILED %d\n",getkey,
257
 
            rc==G10ERR_NETWORK?KEYSERVER_UNREACHABLE:KEYSERVER_INTERNAL_ERROR);
 
268
      fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
 
269
      fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res));
258
270
    }
259
271
  else
260
272
    {
261
 
      unsigned int maxlen=1024,buflen;
262
 
      byte *line=NULL;
263
 
 
264
 
      while(iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen))
265
 
        {
266
 
          maxlen=1024;
267
 
 
268
 
          if(gotit)
269
 
            {
270
 
              fputs (line, output);
271
 
              if(strncmp(line,END,strlen(END))==0)
272
 
                break;
273
 
            }
274
 
          else
275
 
            if(strncmp(line,BEGIN,strlen(BEGIN))==0)
276
 
              {
277
 
                fputs (line,output);
278
 
                gotit=1;
279
 
              }
280
 
        }
281
 
 
282
 
      if(gotit)
283
 
        fprintf(output,"KEY 0x%s END\n",getkey);
 
273
      if(ctx.done)
 
274
        fprintf(output,"\nKEY 0x%s END\n",getkey);
284
275
      else
285
276
        {
286
277
          fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
287
278
          fprintf(output,"KEY 0x%s FAILED %d\n",
288
279
                  getkey,KEYSERVER_KEY_NOT_FOUND);
289
280
        }
290
 
 
291
 
      m_free(line);
292
 
      http_close(&hd);
293
281
    }
294
282
 
295
 
  free(request);
296
 
 
297
283
  return KEYSERVER_OK;
298
284
}
299
285
 
300
 
/* Remove anything <between brackets> and de-urlencode in place.  Note
301
 
   that this requires all brackets to be closed on the same line.  It
302
 
   also means that the result is never larger than the input. */
303
 
void
304
 
dehtmlize(char *line)
305
 
{
306
 
  int parsedindex=0;
307
 
  char *parsed=line;
308
 
 
309
 
  while(*line!='\0')
310
 
    {
311
 
      switch(*line)
312
 
        {
313
 
        case '<':
314
 
          while(*line!='>' && *line!='\0')
315
 
            line++;
316
 
 
317
 
          if(*line!='\0')
318
 
            line++;
319
 
          break;
320
 
 
321
 
        case '&':
322
 
          if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='l') &&
323
 
             (*(line+2)!='\0' && ascii_tolower(*(line+2))=='t') &&
324
 
             (*(line+3)!='\0' && *(line+3)==';'))
325
 
            {
326
 
              parsed[parsedindex++]='<';
327
 
              line+=4;
328
 
              break;
329
 
            }
330
 
          else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='g') &&
331
 
                  (*(line+2)!='\0' && ascii_tolower(*(line+2))=='t') &&
332
 
                  (*(line+3)!='\0' && *(line+3)==';'))
333
 
            {
334
 
              parsed[parsedindex++]='>';
335
 
              line+=4;
336
 
              break;
337
 
            }
338
 
          else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='a') &&
339
 
                  (*(line+2)!='\0' && ascii_tolower(*(line+2))=='m') &&
340
 
                  (*(line+3)!='\0' && ascii_tolower(*(line+3))=='p') &&
341
 
                  (*(line+4)!='\0' && *(line+4)==';'))
342
 
            {
343
 
              parsed[parsedindex++]='&';
344
 
              line+=5;
345
 
              break;
346
 
            }
347
 
          else if((*(line+1)!='\0' && ascii_tolower(*(line+1))=='q') &&
348
 
                  (*(line+2)!='\0' && ascii_tolower(*(line+2))=='u') &&
349
 
                  (*(line+3)!='\0' && ascii_tolower(*(line+3))=='o') &&
350
 
                  (*(line+4)!='\0' && ascii_tolower(*(line+4))=='t') &&
351
 
                  (*(line+5)!='\0' && *(line+5)==';'))
352
 
            {
353
 
              parsed[parsedindex++]='"';
354
 
              line+=6;
355
 
              break;
356
 
            }
357
 
 
358
 
        default:
359
 
          parsed[parsedindex++]=*line;
360
 
          line++;
361
 
          break;
362
 
        }
363
 
    }
364
 
 
365
 
  parsed[parsedindex]='\0';
366
 
 
367
 
  /* Chop off any trailing whitespace.  Note that the HKP servers have
368
 
     \r\n as line endings, and the NAI HKP servers have just \n. */
369
 
 
370
 
  if(parsedindex>0)
371
 
    {
372
 
      parsedindex--;
373
 
      while(isspace(((unsigned char *)parsed)[parsedindex]))
374
 
        {
375
 
          parsed[parsedindex]='\0';
376
 
          if(parsedindex==0)
377
 
            break;
378
 
          parsedindex--;
379
 
        }
380
 
    }
381
 
}
382
 
 
383
 
int
384
 
write_quoted(IOBUF a, const char *buf, char delim)
385
 
{
386
 
  while(*buf)
387
 
    {
388
 
      if(*buf==delim)
389
 
        {
390
 
          char quoted[5];
391
 
          sprintf(quoted,"%%%02X",delim);
392
 
          if(iobuf_writestr(a,quoted))
393
 
            return -1;
394
 
        }
395
 
      else if(*buf=='%')
396
 
        {
397
 
          if(iobuf_writestr(a,"%25"))
398
 
            return -1;
399
 
        }
400
 
      else
401
 
        {
402
 
          if(iobuf_writebyte(a,*buf))
403
 
            return -1;
404
 
        }
405
 
 
406
 
      buf++;
407
 
    }
408
 
 
409
 
  return 0;
410
 
}
411
 
 
412
 
/* pub  2048/<a href="/pks/lookup?op=get&search=0x3CB3B415">3CB3B415</a> 1998/04/03 David M. Shaw &lt;<a href="/pks/lookup?op=get&search=0x3CB3B415">dshaw@jabberwocky.com</a>&gt; */
413
 
 
414
 
/* Luckily enough, both the HKP server and NAI HKP interface to their
415
 
   LDAP server are close enough in output so the same function can
416
 
   parse them both. */
417
 
 
418
 
int
419
 
parse_hkp_index(IOBUF buffer,char *line)
420
 
{
421
 
  int ret=0;
422
 
 
423
 
  /* printf("Open %d, LINE: `%s'\n",open,line); */
424
 
 
425
 
  dehtmlize(line);
426
 
 
427
 
  /* printf("Now open %d, LINE: `%s'\n",open,line); */
428
 
 
429
 
  if(line[0]=='\0')
430
 
    return 0;
431
 
  else if(ascii_strncasecmp(line,"pub",3)==0)
432
 
    {
433
 
      char *tok,*keyid,*uid=NULL,number[15];
434
 
      int bits=0,type=0,disabled=0,revoked=0;
435
 
      u32 createtime=0;
436
 
 
437
 
      line+=3;
438
 
 
439
 
      if(*line=='-')
440
 
        {
441
 
          disabled=1;
442
 
          if(!include_disabled)
443
 
            return 0;
444
 
        }
445
 
 
446
 
      line++;
447
 
 
448
 
      tok=strsep(&line,"/");
449
 
      if(tok==NULL || strlen(tok)==0)
450
 
        return ret;
451
 
 
452
 
      if(tok[strlen(tok)-1]=='R')
453
 
        type=1;
454
 
      else if(tok[strlen(tok)-1]=='D')
455
 
        type=17;
456
 
 
457
 
      bits=atoi(tok);
458
 
 
459
 
      keyid=strsep(&line," ");
460
 
 
461
 
      tok=strsep(&line," ");
462
 
      if(tok!=NULL)
463
 
        {
464
 
          char *temp=tok;
465
 
 
466
 
          /* The date parser wants '-' instead of '/', so... */
467
 
          while(*temp!='\0')
468
 
            {
469
 
              if(*temp=='/')
470
 
                *temp='-';
471
 
 
472
 
              temp++;
473
 
            }
474
 
 
475
 
          createtime=scan_isodatestr(tok);
476
 
        }
477
 
 
478
 
      if(line!=NULL)
479
 
        {
480
 
          while(*line==' ' && *line!='\0')
481
 
            line++;
482
 
 
483
 
          if(*line!='\0')
484
 
            {
485
 
              if(strncmp(line,"*** KEY REVOKED ***",19)==0)
486
 
                {
487
 
                  revoked=1;
488
 
                  if(!include_revoked)
489
 
                    return 0;
490
 
                }
491
 
              else
492
 
                uid=line;
493
 
            }
494
 
        }
495
 
 
496
 
      if(keyid)
497
 
        {
498
 
          iobuf_writestr(buffer,"pub:");
499
 
 
500
 
          write_quoted(buffer,keyid,':');
501
 
 
502
 
          iobuf_writestr(buffer,":");
503
 
 
504
 
          if(type)
505
 
            {
506
 
              sprintf(number,"%d",type);
507
 
              write_quoted(buffer,number,':');
508
 
            }
509
 
 
510
 
          iobuf_writestr(buffer,":");
511
 
 
512
 
          if(bits)
513
 
            {
514
 
              sprintf(number,"%d",bits);
515
 
              write_quoted(buffer,number,':');
516
 
            }
517
 
 
518
 
          iobuf_writestr(buffer,":");
519
 
 
520
 
          if(createtime)
521
 
            {
522
 
              sprintf(number,"%d",createtime);
523
 
              write_quoted(buffer,number,':');
524
 
            }
525
 
 
526
 
          iobuf_writestr(buffer,"::");
527
 
 
528
 
          if(revoked)
529
 
            write_quoted(buffer,"r",':');
530
 
 
531
 
          if(disabled)
532
 
            write_quoted(buffer,"d",':');
533
 
 
534
 
          if(uid)
535
 
            {
536
 
              iobuf_writestr(buffer,"\nuid:");
537
 
              write_quoted(buffer,uid,':');
538
 
            }
539
 
 
540
 
          iobuf_writestr(buffer,"\n");
541
 
 
542
 
          ret=1;
543
 
        }
544
 
    }
545
 
  else if(ascii_strncasecmp(line,"   ",3)==0)
546
 
    {
547
 
      while(*line==' ' && *line!='\0')
548
 
        line++;
549
 
 
550
 
      if(*line!='\0')
551
 
        {
552
 
          iobuf_writestr(buffer,"uid:");
553
 
          write_quoted(buffer,line,':');
554
 
          iobuf_writestr(buffer,"\n");
555
 
        }
556
 
    }
557
 
 
558
 
#if 0
559
 
  else if(open)
560
 
    {
561
 
      /* Try and catch some bastardization of HKP.  If we don't have
562
 
         certain unchanging landmarks, we can't reliably parse the
563
 
         response.  This only complains about problems within the key
564
 
         section itself.  Headers and footers should not matter. */
565
 
 
566
 
      fprintf(console,"gpgkeys: this keyserver does not support searching\n");
567
 
      ret=-1;
568
 
    }
569
 
#endif
570
 
 
571
 
  return ret;
572
 
}
573
 
 
574
 
void
575
 
handle_old_hkp_index(IOBUF inp)
576
 
{
577
 
  int ret,rc,count=0;
578
 
  unsigned int buflen;
579
 
  byte *line=NULL;
580
 
  IOBUF buffer=iobuf_temp();
581
 
 
582
 
  do
583
 
    {
584
 
      unsigned int maxlen=1024;
585
 
 
586
 
      /* This is a judgement call.  Is it better to slurp up all the
587
 
         results before prompting the user?  On the one hand, it
588
 
         probably makes the keyserver happier to not be blocked on
589
 
         sending for a long time while the user picks a key.  On the
590
 
         other hand, it might be nice for the server to be able to
591
 
         stop sending before a large search result page is
592
 
         complete. */
593
 
 
594
 
      rc=iobuf_read_line(inp,&line,&buflen,&maxlen);
595
 
 
596
 
      ret=parse_hkp_index(buffer,line);
597
 
      if(ret==-1)
598
 
        break;
599
 
 
600
 
      if(rc!=0)
601
 
        count+=ret;
602
 
    }
603
 
  while(rc!=0);
604
 
 
605
 
  m_free(line);
606
 
 
607
 
  if(ret>-1)
608
 
    fprintf(output,"info:1:%d\n%s",count,iobuf_get_temp_buffer(buffer));
609
 
 
610
 
  iobuf_close(buffer);
611
 
}
612
 
 
613
286
int
614
287
search_key(char *searchkey)
615
288
{
616
 
  int max=0,len=0,ret=KEYSERVER_INTERNAL_ERROR,rc;
617
 
  struct http_context hd;
618
 
  char *search=NULL,*request=NULL;
619
 
  unsigned char *skey=(unsigned char*) searchkey;
 
289
  CURLcode res;
 
290
  char *request;
 
291
  char *searchkey_encoded;
 
292
  int ret=KEYSERVER_INTERNAL_ERROR;
 
293
 
 
294
  searchkey_encoded=curl_escape(searchkey,0);
 
295
 
 
296
  request=malloc(MAX_URL+50+strlen(searchkey_encoded));
 
297
  if(!request)
 
298
    {
 
299
      fprintf(console,"gpgkeys: out of memory\n");
 
300
      ret=KEYSERVER_NO_MEMORY;
 
301
      goto fail;
 
302
    }
620
303
 
621
304
  fprintf(output,"SEARCH %s BEGIN\n",searchkey);
622
305
 
623
 
  /* Build the search string.  It's going to need url-encoding. */
624
 
 
625
 
  while(*skey!='\0')
626
 
    {
627
 
      if(max-len<3)
628
 
        {
629
 
          max+=100;
630
 
          search=realloc(search,max+1); /* Note +1 for \0 */
631
 
          if (!search)
632
 
            {
633
 
              fprintf(console,"gpgkeys: out of memory\n");
634
 
              ret=KEYSERVER_NO_MEMORY;
635
 
              goto fail;
636
 
            }
637
 
        }
638
 
 
639
 
      if(isalnum(*skey) || *skey=='-')
640
 
        search[len++]=*skey;
641
 
      else if(*skey==' ')
642
 
        search[len++]='+';
643
 
      else
644
 
        {
645
 
          sprintf(&search[len],"%%%02X",*skey);
646
 
          len+=3;
647
 
        }
648
 
 
649
 
      skey++;
650
 
    }
651
 
 
652
 
  if(!search)
653
 
    {
654
 
      fprintf(console,"gpgkeys: corrupt input?\n");
655
 
      return -1;
656
 
    }
657
 
 
658
 
  search[len]='\0';
659
 
 
660
 
  request=malloc(strlen(host)+100+strlen(search));
661
 
  if(!request)
662
 
    {
663
 
      fprintf(console,"gpgkeys: out of memory\n");
664
 
      ret=KEYSERVER_NO_MEMORY;
665
 
      goto fail;
666
 
    }
667
 
 
668
 
  sprintf(request,"hkp://%s%s%s/pks/lookup?op=index&options=mr&search=%s",
669
 
          host,port[0]?":":"",port[0]?port:"",search);
670
 
 
671
 
  if(verbose>2)
 
306
  strcpy(request,"http://");
 
307
  strcat(request,opt->host);
 
308
  strcat(request,":");
 
309
  if(opt->port)
 
310
    strcat(request,opt->port);
 
311
  else
 
312
    strcat(request,"11371");
 
313
  strcat(request,opt->path);
 
314
  append_path(request,"/pks/lookup?op=index&options=mr&search=");
 
315
  strcat(request,searchkey_encoded);
 
316
 
 
317
  if(opt->verbose>2)
672
318
    fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
673
319
 
674
 
  rc=http_open_document(&hd,request,http_flags,proxy[0]?proxy:NULL);
675
 
  if(rc)
 
320
  curl_easy_setopt(curl,CURLOPT_URL,request);
 
321
  curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_mrindex_writer);
 
322
  curl_easy_setopt(curl,CURLOPT_FILE,output);
 
323
 
 
324
  res=curl_easy_perform(curl);
 
325
  if(res!=0)
676
326
    {
677
 
      fprintf(console,"gpgkeys: can't search keyserver `%s': %s\n",
678
 
              host,rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
 
327
      fprintf(console,"gpgkeys: HTTP search error %d: %s\n",res,errorbuffer);
 
328
      ret=curl_err_to_gpg_err(res);
679
329
    }
680
330
  else
681
331
    {
682
 
      unsigned int maxlen=1024,buflen;
683
 
      byte *line=NULL;
684
 
 
685
 
      /* Is it a pksd that knows how to handle machine-readable
686
 
         format? */
687
 
 
688
 
      rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
689
 
      if(line[0]=='<')
690
 
        handle_old_hkp_index(hd.fp_read);
691
 
      else
692
 
        do
693
 
          {
694
 
            fprintf(output,"%s",line);
695
 
            maxlen=1024;
696
 
            rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
697
 
          }
698
 
        while(rc!=0);
699
 
 
700
 
      m_free(line);
701
 
 
702
 
      http_close(&hd);
703
 
 
704
 
      fprintf(output,"SEARCH %s END\n",searchkey);
705
 
 
 
332
      fprintf(output,"\nSEARCH %s END\n",searchkey);
706
333
      ret=KEYSERVER_OK;
707
334
    }
708
335
 
709
336
 fail:
710
337
 
 
338
  curl_free(searchkey_encoded);
711
339
  free(request);
712
 
  free(search);
713
340
 
714
341
  if(ret!=KEYSERVER_OK)
715
 
    fprintf(output,"SEARCH %s FAILED %d\n",searchkey,ret);
 
342
    fprintf(output,"\nSEARCH %s FAILED %d\n",searchkey,ret);
716
343
 
717
344
  return ret;
718
345
}
719
346
 
720
347
void
721
 
fail_all(struct keylist *keylist,int action,int err)
 
348
fail_all(struct keylist *keylist,int err)
722
349
{
723
350
  if(!keylist)
724
351
    return;
725
352
 
726
 
  if(action==SEARCH)
 
353
  if(opt->action==KS_SEARCH)
727
354
    {
728
355
      fprintf(output,"SEARCH ");
729
356
      while(keylist)
752
379
int
753
380
main(int argc,char *argv[])
754
381
{
755
 
  int arg,action=-1,ret=KEYSERVER_INTERNAL_ERROR;
 
382
  int arg,ret=KEYSERVER_INTERNAL_ERROR;
756
383
  char line[MAX_LINE];
757
384
  int failed=0;
758
385
  struct keylist *keylist=NULL,*keyptr=NULL;
759
 
  unsigned int timeout=DEFAULT_KEYSERVER_TIMEOUT;
 
386
  char *proxy=NULL;
760
387
 
761
388
  console=stderr;
762
389
 
813
440
  if(output==NULL)
814
441
    output=stdout;
815
442
 
 
443
  opt=init_ks_options();
 
444
  if(!opt)
 
445
    return KEYSERVER_NO_MEMORY;
 
446
 
816
447
  /* Get the command and info block */
817
448
 
818
449
  while(fgets(line,MAX_LINE,input)!=NULL)
819
450
    {
820
 
      int version;
821
 
      char command[MAX_COMMAND+1];
 
451
      int err;
822
452
      char option[MAX_OPTION+1];
823
 
      char hash;
824
453
 
825
454
      if(line[0]=='\n')
826
455
        break;
827
456
 
828
 
      if(sscanf(line,"%c",&hash)==1 && hash=='#')
 
457
      err=parse_ks_options(line,opt);
 
458
      if(err>0)
 
459
        {
 
460
          ret=err;
 
461
          goto fail;
 
462
        }
 
463
      else if(err==0)
829
464
        continue;
830
465
 
831
 
      if(sscanf(line,"COMMAND %" MKSTRING(MAX_COMMAND) "s\n",command)==1)
832
 
        {
833
 
          command[MAX_COMMAND]='\0';
834
 
 
835
 
          if(strcasecmp(command,"get")==0)
836
 
            action=GET;
837
 
          else if(strcasecmp(command,"send")==0)
838
 
            action=SEND;
839
 
          else if(strcasecmp(command,"search")==0)
840
 
            action=SEARCH;
841
 
 
842
 
          continue;
843
 
        }
844
 
 
845
 
      if(sscanf(line,"HOST %" MKSTRING(MAX_HOST) "s\n",host)==1)
846
 
        {
847
 
          host[MAX_HOST]='\0';
848
 
          continue;
849
 
        }
850
 
 
851
 
      if(sscanf(line,"PORT %" MKSTRING(MAX_PORT) "s\n",port)==1)
852
 
        {
853
 
          port[MAX_PORT]='\0';
854
 
          continue;
855
 
        }
856
 
 
857
 
      if(sscanf(line,"VERSION %d\n",&version)==1)
858
 
        {
859
 
          if(version!=KEYSERVER_PROTO_VERSION)
860
 
            {
861
 
              ret=KEYSERVER_VERSION_ERROR;
862
 
              goto fail;
863
 
            }
864
 
 
865
 
          continue;
866
 
        }
867
 
 
868
466
      if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
869
467
        {
870
468
          int no=0;
878
476
              start=&option[3];
879
477
            }
880
478
 
881
 
          if(strcasecmp(start,"verbose")==0)
882
 
            {
883
 
              if(no)
884
 
                verbose--;
885
 
              else
886
 
                verbose++;
887
 
            }
888
 
          else if(strcasecmp(start,"include-revoked")==0)
889
 
            {
890
 
              if(no)
891
 
                include_revoked=0;
892
 
              else
893
 
                include_revoked=1;
894
 
            }
895
 
          else if(strcasecmp(start,"include-disabled")==0)
896
 
            {
897
 
              if(no)
898
 
                include_disabled=0;
899
 
              else
900
 
                include_disabled=1;
901
 
            }
902
 
          else if(strncasecmp(start,"http-proxy",10)==0)
903
 
            {
904
 
              if(no)
905
 
                proxy[0]='\0';
 
479
          if(strncasecmp(start,"http-proxy",10)==0)
 
480
            {
 
481
              if(no)
 
482
                {
 
483
                  free(proxy);
 
484
                  proxy=strdup("");
 
485
                }
906
486
              else if(start[10]=='=')
907
487
                {
908
 
                  strncpy(proxy,&start[11],MAX_PROXY);
909
 
                  proxy[MAX_PROXY]='\0';
910
 
                }
911
 
              else if(start[10]=='\0')
912
 
                {
913
 
                  char *http_proxy=getenv(HTTP_PROXY_ENV);
914
 
                  if(http_proxy)
 
488
                  if(strlen(&start[11])<MAX_PROXY)
915
489
                    {
916
 
                      strncpy(proxy,http_proxy,MAX_PROXY);
917
 
                      proxy[MAX_PROXY]='\0';
 
490
                      free(proxy);
 
491
                      proxy=strdup(&start[11]);
918
492
                    }
919
493
                }
920
494
            }
921
 
          else if(strcasecmp(start,"broken-http-proxy")==0)
922
 
            {
923
 
              if(no)
924
 
                http_flags&=~HTTP_FLAG_NO_SHUTDOWN;
925
 
              else
926
 
                http_flags|=HTTP_FLAG_NO_SHUTDOWN;
927
 
            }
 
495
#if 0
928
496
          else if(strcasecmp(start,"try-dns-srv")==0)
929
497
            {
930
498
              if(no)
932
500
              else
933
501
                http_flags|=HTTP_FLAG_TRY_SRV;
934
502
            }
935
 
          else if(strncasecmp(start,"timeout",7)==0)
936
 
            {
937
 
              if(no)
938
 
                timeout=0;
939
 
              else if(start[7]=='=')
940
 
                timeout=atoi(&start[8]);
941
 
              else if(start[7]=='\0')
942
 
                timeout=DEFAULT_KEYSERVER_TIMEOUT;
943
 
            }
944
 
 
 
503
#endif
945
504
          continue;
946
505
        }
947
506
    }
948
507
 
949
 
  if(timeout && register_timeout()==-1)
 
508
  if(!opt->host)
 
509
    {
 
510
      fprintf(console,"gpgkeys: no keyserver host provided\n");
 
511
      goto fail;
 
512
    }
 
513
 
 
514
  if(opt->timeout && register_timeout()==-1)
950
515
    {
951
516
      fprintf(console,"gpgkeys: unable to register timeout handler\n");
952
517
      return KEYSERVER_INTERNAL_ERROR;
953
518
    }
954
519
 
 
520
  curl_global_init(CURL_GLOBAL_DEFAULT);
 
521
  curl=curl_easy_init();
 
522
  if(!curl)
 
523
    {
 
524
      fprintf(console,"gpgkeys: unable to initialize curl\n");
 
525
      ret=KEYSERVER_INTERNAL_ERROR;
 
526
      goto fail;
 
527
    }
 
528
 
 
529
  curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
 
530
 
 
531
  if(opt->auth)
 
532
    curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);
 
533
 
 
534
  if(opt->debug)
 
535
    {
 
536
      curl_easy_setopt(curl,CURLOPT_STDERR,console);
 
537
      curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
 
538
    }
 
539
 
 
540
  if(proxy)
 
541
    curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
 
542
 
 
543
#if 0
955
544
  /* By suggested convention, if the user gives a :port, then disable
956
545
     SRV. */
957
 
  if(port[0])
 
546
  if(opt->port)
958
547
    http_flags&=~HTTP_FLAG_TRY_SRV;
 
548
#endif
959
549
 
960
550
  /* If it's a GET or a SEARCH, the next thing to come in is the
961
551
     keyids.  If it's a SEND, then there are no keyids. */
962
552
 
963
 
  if(action==SEND)
 
553
  if(opt->action==KS_SEND)
964
554
    while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
965
 
  else if(action==GET || action==SEARCH)
 
555
  else if(opt->action==KS_GET || opt->action==KS_SEARCH)
966
556
    {
967
557
      for(;;)
968
558
        {
1013
603
  fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
1014
604
  fprintf(output,"PROGRAM %s\n\n",VERSION);
1015
605
 
1016
 
  if(verbose>1)
1017
 
    {
1018
 
      fprintf(console,"Host:\t\t%s\n",host);
1019
 
      if(port[0])
1020
 
        fprintf(console,"Port:\t\t%s\n",port);
1021
 
      fprintf(console,"Command:\t%s\n",action==GET?"GET":
1022
 
              action==SEND?"SEND":"SEARCH");
1023
 
    }
1024
 
 
1025
 
#if 0
1026
 
  if(verbose>1)
1027
 
    {
1028
 
      vals=ldap_get_values(ldap,res,"software");
1029
 
      if(vals!=NULL)
1030
 
        {
1031
 
          fprintf(console,"Server: \t%s\n",vals[0]);
1032
 
          ldap_value_free(vals);
1033
 
        }
1034
 
 
1035
 
      vals=ldap_get_values(ldap,res,"version");
1036
 
      if(vals!=NULL)
1037
 
        {
1038
 
          fprintf(console,"Version:\t%s\n",vals[0]);
1039
 
          ldap_value_free(vals);
1040
 
        }
1041
 
    }
1042
 
#endif
1043
 
 
1044
 
  switch(action)
1045
 
    {
1046
 
    case GET:
 
606
  if(opt->verbose>1)
 
607
    {
 
608
      fprintf(console,"Host:\t\t%s\n",opt->host);
 
609
      if(opt->port)
 
610
        fprintf(console,"Port:\t\t%s\n",opt->port);
 
611
      if(strcmp(opt->path,"/")!=0)
 
612
        fprintf(console,"Path:\t\t%s\n",opt->path);
 
613
      fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action));
 
614
    }
 
615
 
 
616
  if(opt->action==KS_GET)
 
617
    {
1047
618
      keyptr=keylist;
1048
619
 
1049
620
      while(keyptr!=NULL)
1050
621
        {
1051
 
          set_timeout(timeout);
 
622
          set_timeout(opt->timeout);
1052
623
 
1053
624
          if(get_key(keyptr->str)!=KEYSERVER_OK)
1054
625
            failed++;
1055
626
 
1056
627
          keyptr=keyptr->next;
1057
628
        }
1058
 
      break;
1059
 
 
1060
 
    case SEND:
1061
 
      {
1062
 
        int eof=0;
1063
 
 
1064
 
        do
1065
 
          {
1066
 
            set_timeout(timeout);
1067
 
 
1068
 
            if(send_key(&eof)!=KEYSERVER_OK)
1069
 
              failed++;
1070
 
          }
1071
 
        while(!eof);
1072
 
      }
1073
 
      break;
1074
 
 
1075
 
    case SEARCH:
1076
 
      {
1077
 
        char *searchkey=NULL;
1078
 
        int len=0;
1079
 
 
1080
 
        set_timeout(timeout);
1081
 
 
1082
 
        /* To search, we stick a space in between each key to search
1083
 
           for. */
1084
 
 
1085
 
        keyptr=keylist;
1086
 
        while(keyptr!=NULL)
1087
 
          {
1088
 
            len+=strlen(keyptr->str)+1;
1089
 
            keyptr=keyptr->next;
1090
 
          }
1091
 
 
1092
 
        searchkey=malloc(len+1);
1093
 
        if(searchkey==NULL)
1094
 
          {
1095
 
            ret=KEYSERVER_NO_MEMORY;
1096
 
            fail_all(keylist,action,KEYSERVER_NO_MEMORY);
1097
 
            goto fail;
1098
 
          }
1099
 
 
1100
 
        searchkey[0]='\0';
1101
 
 
1102
 
        keyptr=keylist;
1103
 
        while(keyptr!=NULL)
1104
 
          {
1105
 
            strcat(searchkey,keyptr->str);
1106
 
            strcat(searchkey," ");
1107
 
            keyptr=keyptr->next;
1108
 
          }
1109
 
 
1110
 
        /* Nail that last space */
1111
 
        if(*searchkey)
1112
 
          searchkey[strlen(searchkey)-1]='\0';
1113
 
 
1114
 
        if(search_key(searchkey)!=KEYSERVER_OK)
1115
 
          failed++;
1116
 
 
1117
 
        free(searchkey);
1118
 
      }
1119
 
 
1120
 
      break;
1121
 
    }
 
629
    }
 
630
  else if(opt->action==KS_SEND)
 
631
    {
 
632
      int eof=0;
 
633
 
 
634
      do
 
635
        {
 
636
          set_timeout(opt->timeout);
 
637
 
 
638
          if(send_key(&eof)!=KEYSERVER_OK)
 
639
            failed++;
 
640
        }
 
641
      while(!eof);
 
642
    }
 
643
  else if(opt->action==KS_SEARCH)
 
644
    {
 
645
      char *searchkey=NULL;
 
646
      int len=0;
 
647
 
 
648
      set_timeout(opt->timeout);
 
649
 
 
650
      /* To search, we stick a space in between each key to search
 
651
         for. */
 
652
 
 
653
      keyptr=keylist;
 
654
      while(keyptr!=NULL)
 
655
        {
 
656
          len+=strlen(keyptr->str)+1;
 
657
          keyptr=keyptr->next;
 
658
        }
 
659
 
 
660
      searchkey=malloc(len+1);
 
661
      if(searchkey==NULL)
 
662
        {
 
663
          ret=KEYSERVER_NO_MEMORY;
 
664
          fail_all(keylist,KEYSERVER_NO_MEMORY);
 
665
          goto fail;
 
666
        }
 
667
 
 
668
      searchkey[0]='\0';
 
669
 
 
670
      keyptr=keylist;
 
671
      while(keyptr!=NULL)
 
672
        {
 
673
          strcat(searchkey,keyptr->str);
 
674
          strcat(searchkey," ");
 
675
          keyptr=keyptr->next;
 
676
        }
 
677
 
 
678
      /* Nail that last space */
 
679
      if(*searchkey)
 
680
        searchkey[strlen(searchkey)-1]='\0';
 
681
 
 
682
      if(search_key(searchkey)!=KEYSERVER_OK)
 
683
        failed++;
 
684
 
 
685
      free(searchkey);
 
686
    }
 
687
  else
 
688
    abort();
1122
689
 
1123
690
  if(!failed)
1124
691
    ret=KEYSERVER_OK;
1137
704
  if(output!=stdout)
1138
705
    fclose(output);
1139
706
 
 
707
  free_ks_options(opt);
 
708
 
 
709
  if(curl)
 
710
    curl_easy_cleanup(curl);
 
711
 
 
712
  free(proxy);
 
713
 
1140
714
  return ret;
1141
715
}