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

« back to all changes in this revision

Viewing changes to keyserver/gpgkeys_oldhkp.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2006-11-03 09:18:26 UTC
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: james.westby@ubuntu.com-20061103091826-89kwl8tk1xypbmtk
Tags: upstream-1.4.5
ImportĀ upstreamĀ versionĀ 1.4.5

Show diffs side-by-side

added added

removed removed

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