bd1fb94022f95d1f470613b75e64219044fe3bd0
[tinc] / src / invitation.c
1 /*
2     invitation.c -- Create and accept invitations
3     Copyright (C) 2013 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include "control_common.h"
23 #include "crypto.h"
24 #include "ecdsa.h"
25 #include "ecdsagen.h"
26 #include "invitation.h"
27 #include "names.h"
28 #include "netutl.h"
29 #include "rsagen.h"
30 #include "sptps.h"
31 #include "tincctl.h"
32 #include "utils.h"
33 #include "xalloc.h"
34
35 #ifdef HAVE_MINGW
36 #define SCRIPTEXTENSION ".bat"
37 #else
38 #define SCRIPTEXTENSION ""
39 #endif
40
41 int addressfamily = AF_UNSPEC;
42
43 char *get_my_hostname() {
44         char *hostname = NULL;
45         char *port = NULL;
46         char *hostport = NULL;
47         char *name = get_my_name(false);
48         char *filename = NULL;
49
50         // Use first Address statement in own host config file
51         if(check_id(name)) {
52                 xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
53                 FILE *f = fopen(filename, "r");
54                 if(f) {
55                         while(fgets(line, sizeof line, f)) {
56                                 if(!rstrip(line))
57                                         continue;
58                                 char *p = line, *q;
59                                 p += strcspn(p, "\t =");
60                                 if(!*p)
61                                         continue;
62                                 q = p + strspn(p, "\t ");
63                                 if(*q == '=')
64                                         q += 1 + strspn(q + 1, "\t ");
65                                 *p = 0;
66                                 p = q + strcspn(q, "\t ");
67                                 if(*p)
68                                         *p++ = 0;
69                                 p += strspn(p, "\t ");
70                                 p[strcspn(p, "\t ")] = 0;
71                                 if(!port && !strcasecmp(line, "Port")) {
72                                         port = xstrdup(q);
73                                         continue;
74                                 }
75                                 if(strcasecmp(line, "Address"))
76                                         continue;
77                                 hostname = xstrdup(q);
78                                 if(*p) {
79                                         free(port);
80                                         port = xstrdup(p);
81                                 }
82                                 break;
83                         }
84                         fclose(f);
85                 }
86         }
87
88         if(hostname)
89                 goto done;
90
91         // If that doesn't work, guess externally visible hostname
92         fprintf(stderr, "Trying to discover externally visible hostname...\n");
93         struct addrinfo *ai = str2addrinfo("ifconfig.me", "80", SOCK_STREAM);
94         static const char request[] = "GET /host HTTP/1.0\r\n\r\n";
95         if(ai) {
96                 int s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
97                 if(s >= 0) {
98                         if(connect(s, ai->ai_addr, ai->ai_addrlen)) {
99                                 closesocket(s);
100                                 s = -1;
101                         }
102                 }
103                 if(s >= 0) {
104                         send(s, request, sizeof request - 1, 0);
105                         int len = recv(s, line, sizeof line - 1, MSG_WAITALL);
106                         if(len > 0) {
107                                 line[len] = 0;
108                                 if(line[len - 1] == '\n')
109                                         line[--len] = 0;
110                                 char *p = strrchr(line, '\n');
111                                 if(p && p[1])
112                                         hostname = xstrdup(p + 1);
113                         }
114                         closesocket(s);
115                 }
116                 freeaddrinfo(ai);
117         }
118
119         // Check that the hostname is reasonable
120         if(hostname) {
121                 for(char *p = hostname; *p; p++) {
122                         if(isalnum(*p) || *p == '-' || *p == '.')
123                                 continue;
124                         // If not, forget it.
125                         free(hostname);
126                         hostname = NULL;
127                         break;
128                 }
129         }
130
131 again:
132         printf("Please enter your host's external address or hostname");
133         if(hostname)
134                 printf(" [%s]", hostname);
135         printf(": ");
136         fflush(stdout);
137
138         if(!fgets(line, sizeof line, stdin)) {
139                 fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
140                 free(hostname);
141                 return NULL;
142         }
143
144         if(!rstrip(line)) {
145                 if(hostname)
146                         goto save;
147                 else
148                         goto again;
149         }
150
151         for(char *p = line; *p; p++) {
152                 if(isalnum(*p) || *p == '-' || *p == '.')
153                         continue;
154                 fprintf(stderr, "Invalid address or hostname.\n");
155                 goto again;
156         }
157
158         free(hostname);
159         hostname = xstrdup(line);
160
161 save:
162         if(filename) {
163                 FILE *f = fopen(filename, "a");
164                 if(f) {
165                         fprintf(f, "\nAddress = %s\n", hostname);
166                         fclose(f);
167                 } else {
168                         fprintf(stderr, "Could not append Address to %s: %s\n", filename, strerror(errno));
169                 }
170         }
171
172 done:
173         if(port) {
174                 if(strchr(hostname, ':'))
175                         xasprintf(&hostport, "[%s]:%s", hostname, port);
176                 else
177                         xasprintf(&hostport, "%s:%s", hostname, port);
178         } else {
179                 hostport = hostname;
180                 hostname = NULL;
181         }
182
183         free(hostname);
184         free(port);
185         free(filename);
186         return hostport;
187 }
188
189 static bool fcopy(FILE *out, const char *filename) {
190         FILE *in = fopen(filename, "r");
191         if(!in) {
192                 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
193                 return false;
194         }
195
196         char buf[1024];
197         size_t len;
198         while((len = fread(buf, 1, sizeof buf, in)))
199                 fwrite(buf, len, 1, out);
200         fclose(in);
201         return true;
202 }
203
204 int cmd_invite(int argc, char *argv[]) {
205         if(argc < 2) {
206                 fprintf(stderr, "Not enough arguments!\n");
207                 return 1;
208         }
209
210         // Check validity of the new node's name
211         if(!check_id(argv[1])) {
212                 fprintf(stderr, "Invalid name for node.\n");
213                 return 1;
214         }
215
216         char *myname = get_my_name(true);
217         if(!myname)
218                 return 1;
219
220         // Ensure no host configuration file with that name exists
221         char *filename = NULL;
222         xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, argv[1]);
223         if(!access(filename, F_OK)) {
224                 free(filename);
225                 fprintf(stderr, "A host config file for %s already exists!\n", argv[1]);
226                 return 1;
227         }
228         free(filename);
229
230         // If a daemon is running, ensure no other nodes now about this name
231         bool found = false;
232         if(connect_tincd(false)) {
233                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
234
235                 while(recvline(fd, line, sizeof line)) {
236                         char node[4096];
237                         int code, req;
238                         if(sscanf(line, "%d %d %s", &code, &req, node) != 3)
239                                 break;
240                         if(!strcmp(node, argv[1]))
241                                 found = true;
242                 }
243
244                 if(found) {
245                         fprintf(stderr, "A node with name %s is already known!\n", argv[1]);
246                         return 1;
247                 }
248         }
249
250         char hash[25];
251
252         xasprintf(&filename, "%s" SLASH "invitations", confbase);
253         if(mkdir(filename, 0700) && errno != EEXIST) {
254                 fprintf(stderr, "Could not create directory %s: %s\n", filename, strerror(errno));
255                 free(filename);
256                 return 1;
257         }
258
259         // Count the number of valid invitations, clean up old ones
260         DIR *dir = opendir(filename);
261         if(!dir) {
262                 fprintf(stderr, "Could not read directory %s: %s\n", filename, strerror(errno));
263                 free(filename);
264                 return 1;
265         }
266
267         errno = 0;
268         int count = 0;
269         struct dirent *ent;
270         time_t deadline = time(NULL) - 604800; // 1 week in the past
271
272         while((ent = readdir(dir))) {
273                 if(strlen(ent->d_name) != 24)
274                         continue;
275                 char *invname;
276                 struct stat st;
277                 xasprintf(&invname, "%s" SLASH "%s", filename, ent->d_name);
278                 if(!stat(invname, &st)) {
279                         if(deadline < st.st_mtime)
280                                 count++;
281                         else
282                                 unlink(invname);
283                 } else {
284                         fprintf(stderr, "Could not stat %s: %s\n", invname, strerror(errno));
285                         errno = 0;
286                 }
287                 free(invname);
288         }
289
290         if(errno) {
291                 fprintf(stderr, "Error while reading directory %s: %s\n", filename, strerror(errno));
292                 closedir(dir);
293                 free(filename);
294                 return 1;
295         }
296                 
297         closedir(dir);
298         free(filename);
299
300         ecdsa_t *key;
301         xasprintf(&filename, "%s" SLASH "invitations" SLASH "ecdsa_key.priv", confbase);
302
303         // Remove the key if there are no outstanding invitations.
304         if(!count)
305                 unlink(filename);
306
307         // Create a new key if necessary.
308         FILE *f = fopen(filename, "r");
309         if(!f) {
310                 if(errno != ENOENT) {
311                         fprintf(stderr, "Could not read %s: %s\n", filename, strerror(errno));
312                         free(filename);
313                         return 1;
314                 }
315
316                 key = ecdsa_generate();
317                 if(!key) {
318                         free(filename);
319                         return 1;
320                 }
321                 f = fopen(filename, "w");
322                 if(!f) {
323                         fprintf(stderr, "Could not write %s: %s\n", filename, strerror(errno));
324                         free(filename);
325                         return 1;
326                 }
327                 chmod(filename, 0600);
328                 ecdsa_write_pem_private_key(key, f);
329         } else {
330                 key = ecdsa_read_pem_private_key(f);
331                 if(!key)
332                         fprintf(stderr, "Could not read private key from %s\n", filename);
333         }
334         fclose(f);
335         free(filename);
336         if(!key)
337                 return 1;
338
339         // Create a hash of the key.
340         char *fingerprint = ecdsa_get_base64_public_key(key);
341         digest_t *digest = digest_open_by_name("sha256", 18);
342         if(!digest)
343                 abort();
344         digest_create(digest, fingerprint, strlen(fingerprint), hash);
345         b64encode_urlsafe(hash, hash, 18);
346
347         // Create a random cookie for this invitation.
348         char cookie[25];
349         randomize(cookie, 18);
350         b64encode_urlsafe(cookie, cookie, 18);
351
352         // Create a file containing the details of the invitation.
353         xasprintf(&filename, "%s" SLASH "invitations" SLASH "%s", confbase, cookie);
354         int ifd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
355         if(!ifd) {
356                 fprintf(stderr, "Could not create invitation file %s: %s\n", filename, strerror(errno));
357                 free(filename);
358                 return 1;
359         }
360         free(filename);
361         f = fdopen(ifd, "w");
362         if(!f)
363                 abort();
364
365         // Fill in the details.
366         fprintf(f, "Name = %s\n", argv[1]);
367         if(netname)
368                 fprintf(f, "NetName = %s\n", netname);
369         fprintf(f, "ConnectTo = %s\n", myname);
370         // TODO: copy Broadcast and Mode
371         fprintf(f, "#---------------------------------------------------------------#\n");
372         fprintf(f, "Name = %s\n", myname);
373
374         xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, myname);
375         fcopy(f, filename);
376         fclose(f);
377
378         // Create an URL from the local address, key hash and cookie
379         char *address = get_my_hostname();
380         printf("%s/%s%s\n", address, hash, cookie);
381         free(filename);
382         free(address);
383
384         return 0;
385 }
386
387 static int sock;
388 static char cookie[18];
389 static sptps_t sptps;
390 static char *data;
391 static size_t datalen;
392 static bool success = false;
393
394 static char cookie[18], hash[18];
395
396 static char *get_line(const char **data) {
397         if(!data || !*data)
398                 return NULL;
399
400         if(!**data) {
401                 *data = NULL;
402                 return NULL;
403         }
404
405         static char line[1024];
406         const char *end = strchr(*data, '\n');
407         size_t len = end ? end - *data : strlen(*data);
408         if(len >= sizeof line) {
409                 fprintf(stderr, "Maximum line length exceeded!\n");
410                 return NULL;
411         }
412         if(len && !isprint(**data))
413                 abort();
414
415         memcpy(line, *data, len);
416         line[len] = 0;
417
418         if(end)
419                 *data = end + 1;
420         else
421                 *data = NULL;
422
423         return line;
424 }
425
426 static char *get_value(const char *data, const char *var) {
427         char *line = get_line(&data);
428         if(!line)
429                 return NULL;
430
431         char *sep = line + strcspn(line, " \t=");
432         char *val = sep + strspn(sep, " \t");
433         if(*val == '=')
434                 val += 1 + strspn(val + 1, " \t");
435         *sep = 0;
436         if(strcasecmp(line, var))
437                 return NULL;
438         return val;
439 }
440
441 static char *grep(const char *data, const char *var) {
442         static char value[1024];
443
444         const char *p = data;
445         int varlen = strlen(var);
446
447         // Skip all lines not starting with var
448         while(strncasecmp(p, var, varlen) || !strchr(" \t=", p[varlen])) {
449                 p = strchr(p, '\n');
450                 if(!p)
451                         break;
452                 else
453                         p++;
454         }
455
456         if(!p)
457                 return NULL;
458
459         p += varlen;
460         p += strspn(p, " \t");
461         if(*p == '=')
462                 p += 1 + strspn(p + 1, " \t");
463
464         const char *e = strchr(p, '\n');
465         if(!e)
466                 return xstrdup(p);
467
468         if(e - p >= sizeof value) {
469                 fprintf(stderr, "Maximum line length exceeded!\n");
470                 return NULL;
471         }
472
473         memcpy(value, p, e - p);
474         value[e - p] = 0;
475         return value;
476 }
477
478 static bool finalize_join(void) {
479         char *name = xstrdup(get_value(data, "Name"));
480         if(!name) {
481                 fprintf(stderr, "No Name found in invitation!\n");
482                 return false;
483         }
484
485         if(!check_id(name)) {
486                 fprintf(stderr, "Invalid Name found in invitation: %s!\n", name);
487                 return false;
488         }
489
490         if(!netname)
491                 netname = grep(data, "NetName");
492
493 make_names:
494         if(!confbasegiven) {
495                 free(confbase);
496                 confbase = NULL;
497         }
498
499         make_names();
500
501         free(tinc_conf);
502         free(hosts_dir);
503
504         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
505         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
506
507         if(!access(tinc_conf, F_OK)) {
508                 fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
509                 if(!tty || confbasegiven)
510                         return false;
511 ask_netname:
512                 fprintf(stderr, "Enter a new netname: ");
513                 if(!fgets(line, sizeof line, stdin)) {
514                         fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
515                         return false;
516                 }
517                 if(!*line || *line == '\n')
518                         goto ask_netname;
519
520                 line[strlen(line) - 1] = 0;
521                 netname = line;
522                 goto make_names;
523         }       
524
525         if(mkdir(confbase, 0755) && errno != EEXIST) {
526                 fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno));
527                 return false;
528         }
529
530         if(mkdir(hosts_dir, 0755) && errno != EEXIST) {
531                 fprintf(stderr, "Could not create directory %s: %s\n", hosts_dir, strerror(errno));
532                 return false;
533         }
534
535         FILE *f = fopen(tinc_conf, "w");
536         if(!f) {
537                 fprintf(stderr, "Could not create file %s: %s\n", tinc_conf, strerror(errno));
538                 return false;
539         }
540
541         fprintf(f, "Name = %s\n", name);
542
543         char *filename;
544         xasprintf(&filename, "%s" SLASH "%s", hosts_dir, name);
545         FILE *fh = fopen(filename, "w");
546         if(!fh) {
547                 fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
548                 return false;
549         }
550
551         // Filter first chunk on approved keywords, split between tinc.conf and hosts/Name
552         // Other chunks go unfiltered to their respective host config files
553         const char *p = data;
554         char *l, *value;
555
556         while((l = get_line(&p))) {
557                 // Ignore comments
558                 if(*l == '#')
559                         continue;
560
561                 // Split line into variable and value
562                 int len = strcspn(l, "\t =");
563                 value = l + len;
564                 value += strspn(value, "\t ");
565                 if(*value == '=') {
566                         value++;
567                         value += strspn(value, "\t ");
568                 }
569                 l[len] = 0;
570
571                 // Is it a Name?
572                 if(!strcasecmp(l, "Name"))
573                         if(strcmp(value, name))
574                                 break;
575                         else
576                                 continue;
577                 else if(!strcasecmp(l, "NetName"))
578                         continue;
579
580                 // Check the list of known variables
581                 bool found = false;
582                 int i;
583                 for(i = 0; variables[i].name; i++) {
584                         if(strcasecmp(l, variables[i].name))
585                                 continue;
586                         found = true;
587                         break;
588                 }
589
590                 // Ignore unknown and unsafe variables
591                 if(!found) {
592                         fprintf(stderr, "Ignoring unknown variable '%s' in invitation.\n", l);
593                         continue;
594                 } else if(!(variables[i].type & VAR_SAFE)) {
595                         fprintf(stderr, "Ignoring unsafe variable '%s' in invitation.\n", l);
596                         continue;
597                 }
598
599                 // Copy the safe variable to the right config file
600                 fprintf(variables[i].type & VAR_HOST ? fh : f, "%s = %s\n", l, value);
601         }
602
603         fclose(f);
604         free(filename);
605
606         while(l && !strcasecmp(l, "Name")) {
607                 if(!check_id(value)) {
608                         fprintf(stderr, "Invalid Name found in invitation.\n");
609                         return false;
610                 }
611
612                 if(!strcmp(value, name)) {
613                         fprintf(stderr, "Secondary chunk would overwrite our own host config file.\n");
614                         return false;
615                 }
616
617                 xasprintf(&filename, "%s" SLASH "%s", hosts_dir, value);
618                 f = fopen(filename, "w");
619
620                 if(!f) {
621                         fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
622                         return false;
623                 }
624
625                 while((l = get_line(&p))) {
626                         if(!strcmp(l, "#---------------------------------------------------------------#"))
627                                 continue;
628                         int len = strcspn(l, "\t =");
629                         if(len == 4 && !strncasecmp(l, "Name", 4)) {
630                                 value = l + len;
631                                 value += strspn(value, "\t ");
632                                 if(*value == '=') {
633                                         value++;
634                                         value += strspn(value, "\t ");
635                                 }
636                                 l[len] = 0;
637                                 break;
638                         }
639
640                         fputs(l, f);
641                         fputc('\n', f);
642                 }
643
644                 fclose(f);
645                 free(filename);
646         }
647
648         // Generate our key and send a copy to the server
649         ecdsa_t *key = ecdsa_generate();
650         if(!key)
651                 return false;
652
653         char *b64key = ecdsa_get_base64_public_key(key);
654         if(!b64key)
655                 return false;
656
657         xasprintf(&filename, "%s" SLASH "ecdsa_key.priv", confbase);
658         f = fopen(filename, "w");
659
660 #ifdef HAVE_FCHMOD
661         /* Make it unreadable for others. */
662         fchmod(fileno(f), 0600);
663 #endif
664
665         if(!ecdsa_write_pem_private_key(key, f)) {
666                 fprintf(stderr, "Error writing private key!\n");
667                 ecdsa_free(key);
668                 fclose(f);
669                 return false;
670         }
671
672         fclose(f);
673
674         fprintf(fh, "ECDSAPublicKey = %s\n", b64key);
675
676         sptps_send_record(&sptps, 1, b64key, strlen(b64key));
677         free(b64key);
678
679
680         rsa_t *rsa = rsa_generate(2048, 0x1001);
681         xasprintf(&filename, "%s" SLASH "rsa_key.priv", confbase);
682         f = fopen(filename, "w");
683
684 #ifdef HAVE_FCHMOD
685         /* Make it unreadable for others. */
686         fchmod(fileno(f), 0600);
687 #endif
688
689         rsa_write_pem_private_key(rsa, f);
690         fclose(f);
691
692         rsa_write_pem_public_key(rsa, fh);
693         fclose(fh);
694
695         ecdsa_free(key);
696         rsa_free(rsa);
697
698         fprintf(stderr, "Invitation succesfully accepted.\n");
699         shutdown(sock, SHUT_RDWR);
700         success = true;
701
702         return true;
703 }
704
705 static bool invitation_send(void *handle, uint8_t type, const char *data, size_t len) {
706         while(len) {
707                 int result = send(sock, data, len, 0);
708                 if(result == -1 && errno == EINTR)
709                         continue;
710                 else if(result <= 0)
711                         return false;
712                 data += result;
713                 len -= result;
714         }
715         return true;
716 }
717
718 static bool invitation_receive(void *handle, uint8_t type, const char *msg, uint16_t len) {
719         switch(type) {
720                 case SPTPS_HANDSHAKE:
721                         return sptps_send_record(&sptps, 0, cookie, sizeof cookie);
722
723                 case 0:
724                         data = xrealloc(data, datalen + len + 1);
725                         memcpy(data + datalen, msg, len);
726                         datalen += len;
727                         data[datalen] = 0;
728                         break;
729
730                 case 1:
731                         return finalize_join();
732
733                 default:
734                         return false;
735         }
736
737         return true;
738 }
739
740 int cmd_join(int argc, char *argv[]) {
741         free(data);
742         data = NULL;
743         datalen = 0;
744
745         if(argc > 2) {
746                 fprintf(stderr, "Too many arguments!\n");
747                 return 1;
748         }
749
750         // Make sure confdir exists.
751         if(mkdir(confdir, 0755) && errno != EEXIST) {
752                 fprintf(stderr, "Could not create directory %s: %s\n", CONFDIR, strerror(errno));
753                 return 1;
754         }
755
756         // Either read the invitation from the command line or from stdin.
757         char *invitation;
758
759         if(argc > 1) {
760                 invitation = argv[1];
761         } else {
762                 if(tty) {
763                         printf("Enter invitation URL: ");
764                         fflush(stdout);
765                 }
766                 errno = EPIPE;
767                 if(!fgets(line, sizeof line, stdin)) {
768                         fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
769                         return false;
770                 }
771                 invitation = line;
772         }
773
774         // Parse the invitation URL.
775         rstrip(line);
776
777         char *slash = strchr(invitation, '/');
778         if(!slash)
779                 goto invalid;
780
781         *slash++ = 0;
782
783         if(strlen(slash) != 48)
784                 goto invalid;
785
786         char *address = invitation;
787         char *port = NULL;
788         if(*address == '[') {
789                 address++;
790                 char *bracket = strchr(address, ']');
791                 if(!bracket)
792                         goto invalid;
793                 *bracket = 0;
794                 if(bracket[1] == ':')
795                         port = bracket + 2;
796         } else {
797                 port = strchr(address, ':');
798                 if(port)
799                         *port++ = 0;
800         }
801
802         if(!port || !*port)
803                 port = "655";
804
805         if(!b64decode(slash, hash, 18) || !b64decode(slash + 24, cookie, 18))
806                 goto invalid;
807
808         // Generate a throw-away key for the invitation.
809         ecdsa_t *key = ecdsa_generate();
810         if(!key)
811                 return 1;
812
813         char *b64key = ecdsa_get_base64_public_key(key);
814
815         // Connect to the tinc daemon mentioned in the URL.
816         struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
817         if(!ai)
818                 return 1;
819
820         sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
821         if(sock <= 0) {
822                 fprintf(stderr, "Could not open socket: %s\n", strerror(errno));
823                 return 1;
824         }
825
826         if(connect(sock, ai->ai_addr, ai->ai_addrlen)) {
827                 fprintf(stderr, "Could not connect to %s port %s: %s\n", address, port, strerror(errno));
828                 closesocket(sock);
829                 return 1;
830         }
831
832         fprintf(stderr, "Connected to %s port %s...\n", address, port);
833
834         // Tell him we have an invitation, and give him our throw-away key.
835         int len = snprintf(line, sizeof line, "0 ?%s %d.%d\n", b64key, PROT_MAJOR, PROT_MINOR);
836         if(len <= 0 || len >= sizeof line)
837                 abort();
838
839         if(!sendline(sock, "0 ?%s %d.%d", b64key, PROT_MAJOR, 1)) {
840                 fprintf(stderr, "Error sending request to %s port %s: %s\n", address, port, strerror(errno));
841                 closesocket(sock);
842                 return 1;
843         }
844
845         char hisname[4096] = "";
846         int code, hismajor, hisminor = 0;
847
848         if(!recvline(sock, line, sizeof line) || sscanf(line, "%d %s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(sock, line, sizeof line) || !rstrip(line) || sscanf(line, "%d ", &code) != 1 || code != ACK || strlen(line) < 3) {
849                 fprintf(stderr, "Cannot read greeting from peer\n");
850                 closesocket(sock);
851                 return 1;
852         }
853
854         // Check if the hash of the key he have us matches the hash in the URL.
855         char *fingerprint = line + 2;
856         digest_t *digest = digest_open_by_name("sha256", 18);
857         if(!digest)
858                 abort();
859         char hishash[18];
860         if(!digest_create(digest, fingerprint, strlen(fingerprint), hishash)) {
861                 fprintf(stderr, "Could not create digest\n%s\n", line + 2);
862                 return 1;
863         }
864         if(memcmp(hishash, hash, 18)) {
865                 fprintf(stderr, "Peer has an invalid key!\n%s\n", line + 2);
866                 return 1;
867
868         }
869         
870         ecdsa_t *hiskey = ecdsa_set_base64_public_key(fingerprint);
871         if(!hiskey)
872                 return 1;
873
874         // Start an SPTPS session
875         if(!sptps_start(&sptps, NULL, true, false, key, hiskey, "tinc invitation", 15, invitation_send, invitation_receive))
876                 return 1;
877
878         // Feed rest of input buffer to SPTPS
879         if(!sptps_receive_data(&sptps, buffer, blen))
880                 return 1;
881
882         while((len = recv(sock, line, sizeof line, 0))) {
883                 if(len < 0) {
884                         if(errno == EINTR)
885                                 continue;
886                         fprintf(stderr, "Error reading data from %s port %s: %s\n", address, port, strerror(errno));
887                         return 1;
888                 }
889
890                 if(!sptps_receive_data(&sptps, line, len))
891                         return 1;
892         }
893         
894         sptps_stop(&sptps);
895         ecdsa_free(hiskey);
896         ecdsa_free(key);
897         closesocket(sock);
898
899         if(!success) {
900                 fprintf(stderr, "Connection closed by peer, invitation cancelled.\n");
901                 return 1;
902         }
903
904         return 0;
905
906 invalid:
907         fprintf(stderr, "Invalid invitation URL.\n");
908         return 1;
909 }