* gpgkeys_hkp.c (send_key), gpgkeys_ldap.c (send_key,
[gnupg.git] / keyserver / gpgkeys_hkp.c
1 /* gpgkeys_hkp.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 #include <config.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #ifdef HAVE_GETOPT_H
29 #include <getopt.h>
30 #endif
31 #ifdef HAVE_LIBCURL
32 #include <curl/curl.h>
33 #else
34 #include "curl-shim.h"
35 #endif
36 #include "keyserver.h"
37 #include "ksutil.h"
38
39 extern char *optarg;
40 extern int optind;
41
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)
49 {
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;
63     }
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);
81 }
82
83 int
84 send_key(int *eof)
85 {
86   CURLcode res;
87   char request[MAX_URL+15];
88   int begin=0,end=0,ret=KEYSERVER_INTERNAL_ERROR;
89   char keyid[17],state[6];
90   char line[MAX_LINE];
91   char *key=NULL,*encoded_key=NULL;
92   size_t keylen=0,keymax=0;
93
94   /* Read and throw away input until we see the BEGIN */
95
96   while(fgets(line,MAX_LINE,input)!=NULL)
97     if(sscanf(line,"KEY%*[ ]%16s%*[ ]%5s\n",keyid,state)==2
98        && strcmp(state,"BEGIN")==0)
99       {
100         begin=1;
101         break;
102       }
103
104   if(!begin)
105     {
106       /* i.e. eof before the KEY BEGIN was found.  This isn't an
107          error. */
108       *eof=1;
109       ret=KEYSERVER_OK;
110       goto fail;
111     }
112
113   /* Now slurp up everything until we see the END */
114
115   while(fgets(line,MAX_LINE,input))
116     if(sscanf(line,"KEY%*[ ]%16s%*[ ]%3s\n",keyid,state)==2
117        && strcmp(state,"END")==0)
118       {
119         end=1;
120         break;
121       }
122     else
123       {
124         if(strlen(line)+keylen>keymax)
125           {
126             char *tmp;
127
128             keymax+=200;
129             tmp=realloc(key,keymax+1);
130             if(!tmp)
131               {
132                 free(key);
133                 fprintf(console,"gpgkeys: out of memory\n");
134                 ret=KEYSERVER_NO_MEMORY;
135                 goto fail;
136               }
137
138             key=tmp;
139           }
140
141         strcpy(&key[keylen],line);
142         keylen+=strlen(line);
143       }
144
145   if(!end)
146     {
147       fprintf(console,"gpgkeys: no KEY %s END found\n",keyid);
148       *eof=1;
149       ret=KEYSERVER_KEY_INCOMPLETE;
150       goto fail;
151     }
152
153   encoded_key=curl_escape(key,keylen);
154   if(!encoded_key)
155     {
156       fprintf(console,"gpgkeys: out of memory\n");
157       ret=KEYSERVER_NO_MEMORY;
158       goto fail;
159     }
160
161   free(key);
162
163   key=malloc(8+strlen(encoded_key)+1);
164   if(!key)
165     {
166       fprintf(console,"gpgkeys: out of memory\n");
167       ret=KEYSERVER_NO_MEMORY;
168       goto fail;
169     }
170
171   strcpy(key,"keytext=");
172   strcat(key,encoded_key);
173
174   strcpy(request,"http://");
175   strcat(request,opt->host);
176   strcat(request,":");
177   if(opt->port)
178     strcat(request,opt->port);
179   else
180     strcat(request,"11371");
181   strcat(request,opt->path);
182   /* request is MAX_URL+15 bytes long - MAX_URL covers the whole URL,
183      including any supplied path.  The 15 covers /pks/add. */
184   append_path(request,"/pks/add");
185
186   if(opt->verbose>2)
187     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
188
189   curl_easy_setopt(curl,CURLOPT_URL,request);
190   curl_easy_setopt(curl,CURLOPT_POST,1);
191   curl_easy_setopt(curl,CURLOPT_POSTFIELDS,key);
192   curl_easy_setopt(curl,CURLOPT_FAILONERROR,1);
193
194   res=curl_easy_perform(curl);
195   if(res!=0)
196     {
197       fprintf(console,"gpgkeys: HTTP post error %d: %s\n",res,errorbuffer);
198       ret=curl_err_to_gpg_err(res);
199       goto fail;
200     }
201   else
202     fprintf(output,"\nKEY %s SENT\n",keyid);
203
204   ret=KEYSERVER_OK;
205
206  fail:
207   free(key);
208   curl_free(encoded_key);
209
210   if(ret!=0 && begin)
211     fprintf(output,"KEY %s FAILED %d\n",keyid,ret);
212
213   return ret;
214 }
215
216 static int
217 get_key(char *getkey)
218 {
219   CURLcode res;
220   char request[MAX_URL+60];
221   char *offset;
222   struct curl_writer_ctx ctx;
223
224   memset(&ctx,0,sizeof(ctx));
225
226   /* Build the search string.  HKP only uses the short key IDs. */
227
228   if(strncmp(getkey,"0x",2)==0)
229     getkey+=2;
230
231   fprintf(output,"KEY 0x%s BEGIN\n",getkey);
232
233   if(strlen(getkey)==32)
234     {
235       fprintf(console,
236               "gpgkeys: HKP keyservers do not support v3 fingerprints\n");
237       fprintf(output,"KEY 0x%s FAILED %d\n",getkey,KEYSERVER_NOT_SUPPORTED);
238       return KEYSERVER_NOT_SUPPORTED;
239     }
240
241   strcpy(request,"http://");
242   strcat(request,opt->host);
243   strcat(request,":");
244   if(opt->port)
245     strcat(request,opt->port);
246   else
247     strcat(request,"11371");
248   strcat(request,opt->path);
249   /* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
250      including any supplied path.  The 60 overcovers this /pks/... etc
251      string plus the 8 bytes of key id */
252   append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
253
254   /* fingerprint or long key id.  Take the last 8 characters and treat
255      it like a short key id */
256   if(strlen(getkey)>8)
257     offset=&getkey[strlen(getkey)-8];
258   else
259     offset=getkey;
260
261   strcat(request,offset);
262
263   if(opt->verbose>2)
264     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
265
266   curl_easy_setopt(curl,CURLOPT_URL,request);
267   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
268   ctx.stream=output;
269   curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
270
271   res=curl_easy_perform(curl);
272   if(res!=CURLE_OK)
273     {
274       fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
275       fprintf(output,"\nKEY 0x%s FAILED %d\n",getkey,curl_err_to_gpg_err(res));
276     }
277   else
278     {
279       curl_writer_finalize(&ctx);
280       if(!ctx.flags.done)
281         {
282           fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
283           fprintf(output,"\nKEY 0x%s FAILED %d\n",
284                   getkey,KEYSERVER_KEY_NOT_FOUND);
285         }
286       else
287         fprintf(output,"\nKEY 0x%s END\n",getkey);
288     }
289
290   return KEYSERVER_OK;
291 }
292
293 static int
294 get_name(const char *getkey)
295 {
296   CURLcode res;
297   char *request=NULL;
298   char *searchkey_encoded;
299   int ret=KEYSERVER_INTERNAL_ERROR;
300   struct curl_writer_ctx ctx;
301
302   memset(&ctx,0,sizeof(ctx));
303
304   searchkey_encoded=curl_escape((char *)getkey,0);
305   if(!searchkey_encoded)
306     {
307       fprintf(console,"gpgkeys: out of memory\n");
308       ret=KEYSERVER_NO_MEMORY;
309       goto fail;
310     }
311
312   request=malloc(MAX_URL+60+strlen(searchkey_encoded));
313   if(!request)
314     {
315       fprintf(console,"gpgkeys: out of memory\n");
316       ret=KEYSERVER_NO_MEMORY;
317       goto fail;
318     }
319
320   fprintf(output,"NAME %s BEGIN\n",getkey);
321
322   strcpy(request,"http://");
323   strcat(request,opt->host);
324   strcat(request,":");
325   if(opt->port)
326     strcat(request,opt->port);
327   else
328     strcat(request,"11371");
329   strcat(request,opt->path);
330   append_path(request,"/pks/lookup?op=get&options=mr&search=");
331   strcat(request,searchkey_encoded);
332
333   if(opt->action==KS_GETNAME)
334     strcat(request,"&exact=on");
335
336   if(opt->verbose>2)
337     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
338
339   curl_easy_setopt(curl,CURLOPT_URL,request);
340   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_writer);
341   ctx.stream=output;
342   curl_easy_setopt(curl,CURLOPT_FILE,&ctx);
343
344   res=curl_easy_perform(curl);
345   if(res!=CURLE_OK)
346     {
347       fprintf(console,"gpgkeys: HTTP fetch error %d: %s\n",res,errorbuffer);
348       ret=curl_err_to_gpg_err(res);
349     }
350   else
351     {
352       curl_writer_finalize(&ctx);
353       if(!ctx.flags.done)
354         {
355           fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey);
356           ret=KEYSERVER_KEY_NOT_FOUND;
357         }
358       else
359         {
360           fprintf(output,"\nNAME %s END\n",getkey);
361           ret=KEYSERVER_OK;
362         }
363     }
364
365  fail:
366   curl_free(searchkey_encoded);
367   free(request);
368
369   if(ret!=KEYSERVER_OK)
370     fprintf(output,"\nNAME %s FAILED %d\n",getkey,ret);
371
372   return ret;
373 }
374
375 static int
376 search_key(const char *searchkey)
377 {
378   CURLcode res;
379   char *request=NULL;
380   char *searchkey_encoded;
381   int ret=KEYSERVER_INTERNAL_ERROR;
382   enum ks_search_type search_type;
383
384   search_type=classify_ks_search(&searchkey);
385
386   if(opt->debug)
387     fprintf(console,"gpgkeys: search type is %d, and key is \"%s\"\n",
388             search_type,searchkey);
389
390   searchkey_encoded=curl_escape((char *)searchkey,0);
391   if(!searchkey_encoded)
392     {
393       fprintf(console,"gpgkeys: out of memory\n");
394       ret=KEYSERVER_NO_MEMORY;
395       goto fail;
396     }
397
398   request=malloc(MAX_URL+60+strlen(searchkey_encoded));
399   if(!request)
400     {
401       fprintf(console,"gpgkeys: out of memory\n");
402       ret=KEYSERVER_NO_MEMORY;
403       goto fail;
404     }
405
406   fprintf(output,"SEARCH %s BEGIN\n",searchkey);
407
408   strcpy(request,"http://");
409   strcat(request,opt->host);
410   strcat(request,":");
411   if(opt->port)
412     strcat(request,opt->port);
413   else
414     strcat(request,"11371");
415   strcat(request,opt->path);
416   append_path(request,"/pks/lookup?op=index&options=mr&search=");
417   strcat(request,searchkey_encoded);
418
419   if(search_type!=KS_SEARCH_SUBSTR)
420     strcat(request,"&exact=on");
421
422   if(opt->verbose>2)
423     fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request);
424
425   curl_easy_setopt(curl,CURLOPT_URL,request);
426   curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,curl_mrindex_writer);
427   curl_easy_setopt(curl,CURLOPT_FILE,output);
428
429   res=curl_easy_perform(curl);
430   if(res!=0)
431     {
432       fprintf(console,"gpgkeys: HTTP search error %d: %s\n",res,errorbuffer);
433       ret=curl_err_to_gpg_err(res);
434     }
435   else
436     {
437       fprintf(output,"\nSEARCH %s END\n",searchkey);
438       ret=KEYSERVER_OK;
439     }
440
441  fail:
442
443   curl_free(searchkey_encoded);
444   free(request);
445
446   if(ret!=KEYSERVER_OK)
447     fprintf(output,"\nSEARCH %s FAILED %d\n",searchkey,ret);
448
449   return ret;
450 }
451
452 void
453 fail_all(struct keylist *keylist,int err)
454 {
455   if(!keylist)
456     return;
457
458   if(opt->action==KS_SEARCH)
459     {
460       fprintf(output,"SEARCH ");
461       while(keylist)
462         {
463           fprintf(output,"%s ",keylist->str);
464           keylist=keylist->next;
465         }
466       fprintf(output,"FAILED %d\n",err);
467     }
468   else
469     while(keylist)
470       {
471         fprintf(output,"KEY %s FAILED %d\n",keylist->str,err);
472         keylist=keylist->next;
473       }
474 }
475
476 static void 
477 show_help (FILE *fp)
478 {
479   fprintf (fp,"-h\thelp\n");
480   fprintf (fp,"-V\tversion\n");
481   fprintf (fp,"-o\toutput to this file\n");
482 }
483
484 int
485 main(int argc,char *argv[])
486 {
487   int arg,ret=KEYSERVER_INTERNAL_ERROR;
488   char line[MAX_LINE];
489   int failed=0;
490   struct keylist *keylist=NULL,*keyptr=NULL;
491   char *proxy=NULL;
492
493   console=stderr;
494
495   /* Kludge to implement standard GNU options.  */
496   if (argc > 1 && !strcmp (argv[1], "--version"))
497     {
498       fputs ("gpgkeys_hkp (GnuPG) " VERSION"\n", stdout);
499       return 0;
500     }
501   else if (argc > 1 && !strcmp (argv[1], "--help"))
502     {
503       show_help (stdout);
504       return 0;
505     }
506
507   while((arg=getopt(argc,argv,"hVo:"))!=-1)
508     switch(arg)
509       {
510       default:
511       case 'h':
512         show_help (console);
513         return KEYSERVER_OK;
514
515       case 'V':
516         fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
517         return KEYSERVER_OK;
518
519       case 'o':
520         output=fopen(optarg,"w");
521         if(output==NULL)
522           {
523             fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
524                     optarg,strerror(errno));
525             return KEYSERVER_INTERNAL_ERROR;
526           }
527
528         break;
529       }
530
531   if(argc>optind)
532     {
533       input=fopen(argv[optind],"r");
534       if(input==NULL)
535         {
536           fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
537                   argv[optind],strerror(errno));
538           return KEYSERVER_INTERNAL_ERROR;
539         }
540     }
541
542   if(input==NULL)
543     input=stdin;
544
545   if(output==NULL)
546     output=stdout;
547
548   opt=init_ks_options();
549   if(!opt)
550     return KEYSERVER_NO_MEMORY;
551
552   /* Get the command and info block */
553
554   while(fgets(line,MAX_LINE,input)!=NULL)
555     {
556       int err;
557       char option[MAX_OPTION+1];
558
559       if(line[0]=='\n')
560         break;
561
562       err=parse_ks_options(line,opt);
563       if(err>0)
564         {
565           ret=err;
566           goto fail;
567         }
568       else if(err==0)
569         continue;
570
571       if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
572         {
573           int no=0;
574           char *start=&option[0];
575
576           option[MAX_OPTION]='\0';
577
578           if(strncasecmp(option,"no-",3)==0)
579             {
580               no=1;
581               start=&option[3];
582             }
583
584           if(strncasecmp(start,"http-proxy",10)==0)
585             {
586               if(no)
587                 {
588                   free(proxy);
589                   proxy=strdup("");
590                 }
591               else if(start[10]=='=')
592                 {
593                   if(strlen(&start[11])<MAX_PROXY)
594                     {
595                       free(proxy);
596                       proxy=strdup(&start[11]);
597                     }
598                 }
599             }
600 #if 0
601           else if(strcasecmp(start,"try-dns-srv")==0)
602             {
603               if(no)
604                 http_flags&=~HTTP_FLAG_TRY_SRV;
605               else
606                 http_flags|=HTTP_FLAG_TRY_SRV;
607             }
608 #endif
609           continue;
610         }
611     }
612
613   if(!opt->host)
614     {
615       fprintf(console,"gpgkeys: no keyserver host provided\n");
616       goto fail;
617     }
618
619   if(opt->timeout && register_timeout()==-1)
620     {
621       fprintf(console,"gpgkeys: unable to register timeout handler\n");
622       return KEYSERVER_INTERNAL_ERROR;
623     }
624
625   curl_global_init(CURL_GLOBAL_DEFAULT);
626   curl=curl_easy_init();
627   if(!curl)
628     {
629       fprintf(console,"gpgkeys: unable to initialize curl\n");
630       ret=KEYSERVER_INTERNAL_ERROR;
631       goto fail;
632     }
633
634   curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
635
636   if(opt->auth)
637     curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);
638
639   if(opt->debug)
640     {
641       fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
642       curl_easy_setopt(curl,CURLOPT_STDERR,console);
643       curl_easy_setopt(curl,CURLOPT_VERBOSE,1);
644     }
645
646   if(proxy)
647     curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
648
649 #if 0
650   /* By suggested convention, if the user gives a :port, then disable
651      SRV. */
652   if(opt->port)
653     http_flags&=~HTTP_FLAG_TRY_SRV;
654 #endif
655
656   /* If it's a GET or a SEARCH, the next thing to come in is the
657      keyids.  If it's a SEND, then there are no keyids. */
658
659   if(opt->action==KS_SEND)
660     while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
661   else if(opt->action==KS_GET
662           || opt->action==KS_GETNAME || opt->action==KS_SEARCH)
663     {
664       for(;;)
665         {
666           struct keylist *work;
667
668           if(fgets(line,MAX_LINE,input)==NULL)
669             break;
670           else
671             {
672               if(line[0]=='\n' || line[0]=='\0')
673                 break;
674
675               work=malloc(sizeof(struct keylist));
676               if(work==NULL)
677                 {
678                   fprintf(console,"gpgkeys: out of memory while "
679                           "building key list\n");
680                   ret=KEYSERVER_NO_MEMORY;
681                   goto fail;
682                 }
683
684               strcpy(work->str,line);
685
686               /* Trim the trailing \n */
687               work->str[strlen(line)-1]='\0';
688
689               work->next=NULL;
690
691               /* Always attach at the end to keep the list in proper
692                  order for searching */
693               if(keylist==NULL)
694                 keylist=work;
695               else
696                 keyptr->next=work;
697
698               keyptr=work;
699             }
700         }
701     }
702   else
703     {
704       fprintf(console,"gpgkeys: no keyserver command specified\n");
705       goto fail;
706     }
707
708   /* Send the response */
709
710   fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
711   fprintf(output,"PROGRAM %s\n\n",VERSION);
712
713   if(opt->verbose>1)
714     {
715       fprintf(console,"Host:\t\t%s\n",opt->host);
716       if(opt->port)
717         fprintf(console,"Port:\t\t%s\n",opt->port);
718       if(strcmp(opt->path,"/")!=0)
719         fprintf(console,"Path:\t\t%s\n",opt->path);
720       fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action));
721     }
722
723   if(opt->action==KS_GET)
724     {
725       keyptr=keylist;
726
727       while(keyptr!=NULL)
728         {
729           set_timeout(opt->timeout);
730
731           if(get_key(keyptr->str)!=KEYSERVER_OK)
732             failed++;
733
734           keyptr=keyptr->next;
735         }
736     }
737   else if(opt->action==KS_GETNAME)
738     {
739       keyptr=keylist;
740
741       while(keyptr!=NULL)
742         {
743           set_timeout(opt->timeout);
744
745           if(get_name(keyptr->str)!=KEYSERVER_OK)
746             failed++;
747
748           keyptr=keyptr->next;
749         }
750     }
751   else if(opt->action==KS_SEND)
752     {
753       int eof=0;
754
755       do
756         {
757           set_timeout(opt->timeout);
758
759           if(send_key(&eof)!=KEYSERVER_OK)
760             failed++;
761         }
762       while(!eof);
763     }
764   else if(opt->action==KS_SEARCH)
765     {
766       char *searchkey=NULL;
767       int len=0;
768
769       set_timeout(opt->timeout);
770
771       /* To search, we stick a space in between each key to search
772          for. */
773
774       keyptr=keylist;
775       while(keyptr!=NULL)
776         {
777           len+=strlen(keyptr->str)+1;
778           keyptr=keyptr->next;
779         }
780
781       searchkey=malloc(len+1);
782       if(searchkey==NULL)
783         {
784           ret=KEYSERVER_NO_MEMORY;
785           fail_all(keylist,KEYSERVER_NO_MEMORY);
786           goto fail;
787         }
788
789       searchkey[0]='\0';
790
791       keyptr=keylist;
792       while(keyptr!=NULL)
793         {
794           strcat(searchkey,keyptr->str);
795           strcat(searchkey," ");
796           keyptr=keyptr->next;
797         }
798
799       /* Nail that last space */
800       if(*searchkey)
801         searchkey[strlen(searchkey)-1]='\0';
802
803       if(search_key(searchkey)!=KEYSERVER_OK)
804         failed++;
805
806       free(searchkey);
807     }
808   else
809     abort();
810
811   if(!failed)
812     ret=KEYSERVER_OK;
813
814  fail:
815   while(keylist!=NULL)
816     {
817       struct keylist *current=keylist;
818       keylist=keylist->next;
819       free(current);
820     }
821
822   if(input!=stdin)
823     fclose(input);
824
825   if(output!=stdout)
826     fclose(output);
827
828   free_ks_options(opt);
829
830   if(curl)
831     curl_easy_cleanup(curl);
832
833   free(proxy);
834
835   return ret;
836 }