/[winpt]/trunk/Src/wptKeyserver.cpp
ViewVC logotype

Annotation of /trunk/Src/wptKeyserver.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 328 - (hide annotations)
Fri Sep 25 16:07:38 2009 UTC (15 years, 5 months ago) by twoaday
File size: 31151 byte(s)


1 werner 36 /* wptKeyserver.cpp - W32 Keyserver Access
2 twoaday 328 * Copyright (C) 2000-2009 Timo Schulz
3 werner 36 * Copyright (C) 2001 Marco Cunha
4     *
5     * This file is part of WinPT.
6     *
7     * WinPT is free software; you can redistribute it and/or
8     * modify it under the terms of the GNU General Public License
9     * as published by the Free Software Foundation; either version 2
10     * of the License, or (at your option) any later version.
11     *
12     * WinPT is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     * General Public License for more details.
16     */
17     #ifdef HAVE_CONFIG_H
18     #include <config.h>
19     #endif
20    
21     #include <windows.h>
22 twoaday 150 #include <shlobj.h>
23 werner 36 #include <stdio.h>
24     #include <sys/stat.h>
25     #include <ctype.h>
26    
27 twoaday 271 #include "wptGPG.h"
28 werner 36 #include "wptKeyserver.h"
29     #include "wptErrors.h"
30     #include "wptTypes.h"
31     #include "wptNLS.h"
32     #include "wptW32API.h"
33     #include "wptRegistry.h"
34 twoaday 225 #include "wptUTF8.h"
35 twoaday 273 #include "wptVersion.h"
36 twoaday 278 #include "StringBuffer.h"
37 werner 36
38 twoaday 273
39 twoaday 200 /* Map net_errno to a winsock error. */
40 twoaday 119 #define net_errno ((int)WSAGetLastError ())
41    
42 werner 36 keyserver server[MAX_KEYSERVERS] = {0};
43 twoaday 180 keyserver_proxy_s proxy = {0};
44 twoaday 119 static const char *server_list[] = {
45 twoaday 328 "hkp://pool.sks-keyservers.net",
46 werner 36 "hkp://subkeys.pgp.net",
47 twoaday 328 "http://minsky.surfnet.nl",
48 werner 36 NULL
49     };
50 twoaday 328 #define NUM_DEF_KEYSERVERS 3
51 werner 36
52 twoaday 328 static char hkp_err_msg[384]; /* Holds the error message from the server */
53     static int hkp_has_err = 0; /* != 0 indicates an error occurred. */
54 werner 36
55 twoaday 147 /* Default keyserver and port. */
56     char *default_keyserver = NULL;
57     WORD default_keyserver_port = 0;
58 twoaday 119
59 twoaday 273 /* Default socket timeout (secs). */
60     static size_t default_socket_timeout = 6;
61 twoaday 119
62 twoaday 214
63     /* Wrapper for safe memory allocation. */
64     static char*
65     safe_alloc (DWORD n)
66     {
67 twoaday 328 char *p = new char[n+1];
68 twoaday 214 if (!p)
69     BUG (0);
70     memset (p, 0, n);
71     return p;
72     }
73    
74 twoaday 328
75 twoaday 180 /* Basic64 encode the input @inbuf to @outbuf. */
76 werner 36 static void
77 twoaday 180 base64_encode (const char *inbuf, char *outbuf)
78 twoaday 181 {
79     char base64code[] =
80     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
81 twoaday 180 int index = 0, temp = 0, res = 0;
82 twoaday 328 int inputlen, len = 0;
83 werner 36
84 twoaday 180 inputlen = strlen (inbuf);
85 twoaday 328 for (int i = 0; i < inputlen; i++) {
86 werner 36 res = temp;
87 twoaday 180 res = (res << 8) | (inbuf[i] & 0xFF);
88 werner 36 switch (index++) {
89 twoaday 180 case 0:
90     outbuf[len++] = base64code[res >> 2 & 0x3F];
91     res &= 0x3;
92     break;
93     case 1:
94     outbuf[len++] = base64code[res >> 4 & 0x3F];
95 twoaday 328 res &= 0xF;
96 twoaday 180 break;
97     case 2:
98     outbuf[len++] = base64code[res >> 6 & 0x3F];
99     outbuf[len++] = base64code[res & 0x3F];
100     res = index = 0;
101     break;
102 werner 36 }
103     temp = res;
104     }
105    
106 twoaday 180 if (index == 2) {
107     outbuf[len++] = base64code[temp << 2 & 0x3F];
108     outbuf[len++] = '=';
109 werner 36 }
110 twoaday 180 else if (index == 1) {
111     outbuf[len++] = base64code[temp << 4 & 0x3F];
112     outbuf[len++] = '=';
113     outbuf[len++] = '=';
114     }
115    
116     outbuf[len] = '\0';
117 twoaday 119 }
118 werner 36
119    
120 twoaday 222 /* Check that the given buffer contains a valid keyserver URL
121     and return the prefix length, 0 in case of an error. */
122     static int
123     check_URL (const char *buf)
124     {
125 twoaday 328 if (strstr (buf, "hkp://"))
126     return 6;
127     if (strstr (buf, "http://"))
128     return 7;
129 twoaday 222 return 0;
130     }
131    
132    
133 werner 36 /* Skip the URL schema and return only the host part of it. */
134 twoaday 119 static const char*
135     skip_type_prefix (const char *hostname)
136 werner 36 {
137 twoaday 222 int pos;
138    
139     if (!hostname)
140     return hostname;
141    
142     pos = check_URL (hostname);
143     if (pos > 0)
144     hostname += pos;
145 werner 36 return hostname;
146     }
147    
148 twoaday 328
149 twoaday 229 /* Parse the keyserver response and extract the human
150     readable text passages. */
151     static int
152     parse_keyserver_error (const char *resp, char *txt, size_t txtlen)
153     {
154     char *p, *p2;
155 werner 36
156 twoaday 328 /* If we find no 'Error' substring we assume a success. */
157 twoaday 229 if (!stristr (resp, "Error"))
158 twoaday 231 return -1;
159 twoaday 229
160     memset (txt, 0, txtlen);
161     p = strstr (resp, "\r\n\r\n");
162     if (!p)
163     return -1;
164     resp += (p-resp);
165     p = strstr (resp, "<h1>");
166     if (!p)
167     return -1;
168     resp += (p-resp)+strlen ("<h1>");
169     p = strstr (resp, "</h1>");
170     if (!p)
171     return -1;
172     resp += (p-resp)+strlen ("</h1>");
173     p2 = strstr (resp, "</body>");
174     if (p2 != NULL)
175     memcpy (txt, resp, (p2-resp));
176     else {
177     if (!strnicmp (resp, "<p>", 3))
178     resp += 3;
179 twoaday 328 while (resp && (*resp == '\r' || *resp == '\n'))
180 twoaday 229 resp++;
181     memcpy (txt, resp, strlen (resp));
182     }
183     return 0;
184     }
185    
186    
187 werner 36 /* Check that the keyserver response indicates an OK.
188     Return 0 on success. */
189     static int
190     check_hkp_response (const char *resp, int recv)
191 twoaday 229 {
192     int ec;
193 werner 36
194     ec = recv ? WPTERR_WINSOCK_RECVKEY : WPTERR_WINSOCK_SENDKEY;
195 twoaday 328 if (!resp)
196     return ec;
197     log_debug ("check_hkp_response: '%s'\r\n", resp);
198 werner 36 if (!strstr (resp, "HTTP/1.0 200 OK") &&
199 twoaday 229 !strstr (resp, "HTTP/1.1 200 OK") &&
200     !strstr (resp, "HTTP/1.0 500 OK") &&
201     !strstr (resp, "HTTP/1.1 500 OK"))
202     return ec; /* http error */
203    
204 twoaday 328 if (!parse_keyserver_error (resp, hkp_err_msg, DIM (hkp_err_msg)-2)) {
205     if (!strlen (hkp_err_msg))
206     _snprintf (hkp_err_msg, DIM (hkp_err_msg)-1,
207 twoaday 229 "Unknown keyserver error");
208 twoaday 328 hkp_has_err = 1;
209 werner 36 return ec;
210     }
211     return 0;
212     }
213    
214    
215     /* Read a single line (\r\n) from a socket.
216     Return 0 on success. */
217     static int
218     sock_getline (int fd, char *buf, int buflen, int *nbytes)
219     {
220     char ch;
221 twoaday 328 int nread;
222 werner 36
223     if (nbytes)
224     *nbytes = 0;
225     *buf = 0;
226 twoaday 328 nread = 0;
227 werner 36 while (recv (fd, &ch, 1, 0) > 0) {
228     *buf++ = ch;
229 twoaday 180 nread++;
230     if (ch == '\r')
231     continue; /* remove this char. */
232     if (ch == '\n' || nread == (buflen - 1)) {
233 werner 36 *buf = 0;
234     if (nbytes)
235 twoaday 180 *nbytes = nread;
236 werner 36 return 0;
237     }
238     }
239    
240     return -1;
241     }
242    
243    
244     /* Perform a select() on the given fd to find out
245 twoaday 328 is there is data for reading. Wait at least @nsecs milli seconds. */
246 werner 36 static int
247 twoaday 328 sock_select (int fd, int nmsecs)
248 werner 36 {
249     FD_SET rfd;
250 twoaday 328 timeval tv = {0, nmsecs*1000};
251 werner 36
252     FD_ZERO (&rfd);
253     FD_SET (fd, &rfd);
254 twoaday 119 if (select (fd + 1, &rfd, NULL, NULL, &tv) == SOCKET_ERROR) {
255     log_debug ("sock_select: select() failed ec=%d.\r\n", net_errno);
256 werner 36 return SOCKET_ERROR;
257 twoaday 119 }
258 werner 36 if (FD_ISSET (fd, &rfd))
259     return 1;
260     return 0;
261     }
262    
263    
264 twoaday 119 /* Read from a socket @fd to buffer @buf with a fixed timeout
265     of 10 seconds. The amount of bytes which were read are
266     returned in @nbytes.
267 werner 36 Return value: 0 on success. */
268     static int
269 twoaday 273 sock_read (int fd, char *buf, size_t buflen, int *nbytes)
270 twoaday 328 {
271     size_t nleft = buflen;
272     size_t n;
273 twoaday 273 int nread;
274     int rc;
275 twoaday 195
276     if (nbytes)
277     *nbytes = 0;
278 twoaday 328 n = 0;
279 werner 36 while (nleft > 0) {
280 twoaday 181 if (n >= default_socket_timeout)
281 werner 36 return WPTERR_WINSOCK_TIMEOUT;
282 twoaday 328 rc = sock_select (fd, 400);
283 werner 36 if (rc == SOCKET_ERROR)
284 twoaday 119 return rc;
285     else if (!rc)
286 werner 36 n++;
287     else {
288     nread = recv (fd, buf, nleft, 0);
289 twoaday 119 if (nread == SOCKET_ERROR) {
290     log_debug ("sock_read: recv() failed ec=%d.\r\n", net_errno);
291 werner 36 return SOCKET_ERROR;
292 twoaday 119 }
293 werner 36 else if (!nread)
294     break;
295     nleft -= nread;
296     buf += nread;
297     }
298     }
299     if (nbytes)
300     *nbytes = buflen - nleft;
301    
302     return 0;
303     }
304    
305 twoaday 209
306     /* Helper to create a string from the gpgme data and
307     then release the gpgme data object. */
308     char*
309 twoaday 273 data_release_and_get_mem (gpgme_data_t in, size_t *r_bufferlen)
310 twoaday 328 {
311     char *buffer, *p;
312 twoaday 209 size_t n;
313    
314     gpg_data_putc (in, '\0');
315     p = gpgme_data_release_and_get_mem (in, &n);
316     buffer = m_strdup (p);
317     if (r_bufferlen)
318 twoaday 273 *r_bufferlen = n;
319 twoaday 209 gpgme_free (p);
320     return buffer;
321     }
322    
323    
324 twoaday 147 /* Read much data as possible from the socket @fd and
325     return the data in @buffer. Caller must free data.
326     Return value: 0 on success. */
327     int
328 twoaday 273 sock_read_ext (int fd, char **buffer, size_t *r_bufferlen)
329 twoaday 147 {
330     gpgme_data_t dh;
331 twoaday 209 char buf[1024];
332 twoaday 273 size_t timeout=0;
333 twoaday 328 int rc;
334 werner 36
335 twoaday 328 *buffer = NULL;
336 twoaday 209 if (gpgme_data_new (&dh))
337 twoaday 273 return SOCKET_ERROR;
338     while (timeout < default_socket_timeout) {
339 twoaday 328 rc = sock_select (fd, 500);
340 twoaday 147 if (rc == SOCKET_ERROR) {
341     gpgme_data_release (dh);
342     return rc;
343     }
344     else if (!rc)
345 twoaday 273 timeout++; /* socket not ready yet. */
346 twoaday 147 else {
347 twoaday 328 int nread = recv (fd, buf, DIM (buf), 0);
348     log_debug ("recv n=%d bytes\r\n", nread);
349 twoaday 147 if (nread == SOCKET_ERROR)
350     return SOCKET_ERROR;
351     else if (!nread)
352     break;
353     gpgme_data_write (dh, buf, nread);
354     }
355     }
356 twoaday 328
357     if (timeout >= default_socket_timeout) {
358     gpgme_data_release (dh);
359     log_debug ("sock_read_ext: timeout\r\n");
360 twoaday 273 return WPTERR_WINSOCK_TIMEOUT;
361 twoaday 328 }
362     log_debug ("sock_read_ext: success\r\n");
363 twoaday 209 *buffer = data_release_and_get_mem (dh, r_bufferlen);
364 twoaday 147 return 0;
365     }
366    
367    
368 twoaday 119 /* Write the buffer @buf with the length @buflen to a socket @fd. */
369 werner 36 static int
370 twoaday 273 sock_write (int fd, const char *buf, size_t buflen)
371 werner 36 {
372 twoaday 273 int nwritten;
373 werner 36 int nleft = buflen;
374    
375     while (nleft > 0) {
376     nwritten = send (fd, buf, nleft, 0);
377 twoaday 119 if (nwritten == SOCKET_ERROR) {
378     log_debug ("sock_write: send() failed ec=%d\r\n", net_errno);
379 werner 36 return SOCKET_ERROR;
380 twoaday 119 }
381 werner 36 nleft -= nwritten;
382 twoaday 180 buf += nwritten;
383 werner 36 }
384    
385     return 0;
386     }
387    
388    
389     /* Initialize the Winsock2 interface.*/
390     int
391     wsock_init (void)
392     {
393     WSADATA wsa;
394    
395 twoaday 119 if (WSAStartup (0x202, &wsa)) {
396     log_debug ("wsock_init: WSAStartup failed ec=%d\r\n", net_errno);
397 werner 36 return WPTERR_WINSOCK_INIT;
398 twoaday 119 }
399 werner 36 return 0;
400     }
401    
402    
403 twoaday 328 /* Cleanup the Winsock2 interface and free all resources. */
404 werner 36 void
405     wsock_end (void)
406     {
407 twoaday 328 if (default_keyserver != NULL) {
408     char str_port[64];
409     set_reg_entry_keyserver ("Default", default_keyserver);
410     free_if_alloc (default_keyserver);
411     sprintf (str_port, "%d", default_keyserver_port);
412     set_reg_entry_keyserver ("Default_Port", str_port);
413     }
414     for (int i=0; i < MAX_KEYSERVERS; i++) {
415 twoaday 273 if (server[i].name != NULL)
416 werner 36 free_if_alloc (server[i].name);
417     }
418 twoaday 180 kserver_proxy_release (&proxy);
419 werner 36 WSACleanup ();
420 twoaday 222 log_debug ("wsock_end: cleanup finished.\r\n");
421 werner 36 }
422    
423    
424     /* Return a string representation of a winsock error. */
425     const char*
426     wsock_strerror (void)
427 twoaday 211 {
428 werner 36 int ec = WSAGetLastError ();
429    
430 twoaday 211 if (!ec)
431     return "";
432 werner 36 switch (ec) {
433 twoaday 328 case WSANOTINITIALISED:
434     return _("Winsock subsystem has not been initialized");
435    
436 twoaday 119 case WSAENETDOWN:
437 twoaday 328 return _("Network subsystem has failed");
438 twoaday 211
439    
440 twoaday 328 case WSATRY_AGAIN:
441     return _("Nonauthoritative host not found, or server failure");
442    
443 twoaday 119 case WSAHOST_NOT_FOUND:
444 twoaday 211 return _("Could not resolve host name");
445    
446 twoaday 119 case WSAETIMEDOUT:
447 twoaday 211 case WSAECONNABORTED:
448     return _("Connection timeout");
449    
450     case WSAENETRESET:
451 twoaday 328 case WSAECONNRESET:
452 twoaday 211 return _("Connection resetted by peer");
453    
454 twoaday 328 case WSAENETUNREACH:
455     return _("The network cannot be reached from this host at this time");
456    
457     case WSAEHOSTUNREACH:
458     return _("A socket operation was attempted to an unreachable host");
459    
460     case WSAECONNREFUSED:
461     return _("The attempt to connect was forcefully rejected");
462    
463 twoaday 211 case WSAESHUTDOWN:
464     return _("Socket has been shutdown");
465    
466 twoaday 119 default:
467 twoaday 211 break;
468 werner 36 }
469 twoaday 211
470 twoaday 328 return _("Unknown network error");
471 werner 36 }
472    
473    
474 twoaday 181 /* Set default socket timeout for all reading operations. */
475     void
476 twoaday 273 kserver_set_socket_timeout (size_t nsec)
477 twoaday 181 {
478 twoaday 222 if (nsec < 0 || nsec > 3600)
479 twoaday 328 nsec = 10;
480 twoaday 181 default_socket_timeout = nsec;
481     }
482    
483    
484 werner 36 /* Return the last keyserver error as a string. */
485     const char*
486     kserver_strerror (void)
487     {
488 twoaday 328 return hkp_has_err? hkp_err_msg : NULL;
489 werner 36 }
490    
491    
492     /* Read a keyserver from the list at index @idx.
493     Return value: keyserver name at the given position. */
494     const char*
495 twoaday 119 kserver_get_hostname (int idx, int type, WORD *port)
496 werner 36 {
497     if (type == -1) {
498     *port = default_keyserver_port;
499     return default_keyserver;
500     }
501 twoaday 273 else if (!type && (size_t)idx < DIM (server_list)) {
502 werner 36 *port = HKP_PORT;
503     return server_list[idx];
504     }
505     return NULL;
506     }
507    
508    
509     /* Check if the computer is connected to the internet.
510     Return 0 on success -1 otherwise. */
511     int
512     kserver_check_inet_connection (void)
513     {
514     int fd;
515    
516     if (!kserver_connect (default_keyserver, default_keyserver_port, &fd)) {
517     closesocket (fd);
518     return 0;
519     }
520 twoaday 220 log_debug ("kserver_check_inet_connection: no inet connection.\r\n");
521 werner 36 return -1;
522     }
523    
524    
525 twoaday 119 /* If the request contains the keyid, it have to be
526     always postfix with '0x'+keyid. This code checks
527     if the keyid is a decimal value and if so if it contains
528 twoaday 180 the '0x'. If not it is inserted. */
529 werner 36 const char*
530     kserver_check_keyid (const char *keyid)
531     {
532 twoaday 328 static char id[64];
533 werner 36
534     if (strstr (keyid, "@"))
535     return keyid; /* email address */
536     if (strncmp (keyid, "0x", 2)) {
537     memset (&id, 0, sizeof (id));
538 twoaday 271 _snprintf (id, DIM (id)-1, "0x%s", keyid);
539 werner 36 return id;
540     }
541     return keyid;
542 twoaday 119 }
543 werner 36
544    
545 twoaday 119 /* Update the keyserver proxy user. */
546 werner 36 static void
547 twoaday 180 update_proxy_user (const char *proxy_user, const char *proxy_pass)
548 werner 36 {
549     char t[257]; /* user:pass = 127+1+127+1 = 257 */
550 twoaday 328 size_t n;
551 werner 36
552 twoaday 328 n = 4*(strlen (proxy_user) + strlen (proxy_pass))/3 + 32 + 2;
553 werner 36 free_if_alloc (proxy.base64_user);
554 twoaday 214 proxy.base64_user = safe_alloc (n+1);
555 twoaday 271 _snprintf (t, DIM (t)-1, "%s:%s", proxy_user, proxy_pass);
556 twoaday 180 base64_encode (t, proxy.base64_user);
557 werner 36 free_if_alloc (proxy.user);
558     free_if_alloc (proxy.pass);
559     proxy.user = m_strdup (proxy_user);
560     proxy.pass = m_strdup (proxy_pass);
561 twoaday 119 }
562 werner 36
563    
564 twoaday 328 /* Set the default keyserver. The position is always one. */
565 werner 36 void
566 twoaday 119 keyserver_set_default (const char *hostname, WORD port)
567 werner 36 {
568 twoaday 328 int pos=0;
569    
570     if (port == 0)
571 twoaday 220 port = HKP_PORT;
572 twoaday 328
573     free_if_alloc (default_keyserver);
574     default_keyserver = m_strdup (hostname);
575     default_keyserver_port = port;
576    
577     while (pos < MAX_KEYSERVERS) {
578     if (server[pos].is_default)
579     break;
580     if (server[pos].used) {
581     pos++;
582     continue;
583     }
584     break;
585 werner 36 }
586 twoaday 328 free_if_alloc (server[pos].name);
587     server[pos].name = m_strdup (default_keyserver);
588     server[pos].used = 1;
589     server[pos].port = port;
590     server[pos].is_default = 1;
591 twoaday 119 }
592 werner 36
593    
594 twoaday 328 /* Skip all kind of whitespace chars in @str.
595 twoaday 119 static const char*
596     skip_whitespace (const char *str)
597 werner 36 {
598 twoaday 119 while (str && *str) {
599 werner 36 if (*str == ' ' ||
600     *str == '\t' ||
601     *str == '\n' ||
602 twoaday 119 *str == '\r') {
603 werner 36 str++;
604     continue;
605     }
606     break;
607     }
608     return str;
609 twoaday 328 }*/
610 werner 36
611    
612 twoaday 270 /* Return the specified keyserver config setting @key as an integer. */
613     static int
614     get_conf_kserver_int (const char *key)
615     {
616     char *p;
617     int val = 0;
618    
619     p = get_reg_entry_keyserver (key);
620     if (p && *p)
621     val = atoi (p);
622     free_if_alloc (p);
623     return val;
624     }
625    
626    
627     /* Read the proxy configuration and store it into @prox. */
628     static void
629     read_proxy_config (keyserver_proxy_t prox)
630     {
631     char *proto;
632    
633     if (!prox)
634     return;
635    
636     proto = get_reg_entry_keyserver("Proto");
637     if (proto != NULL && strlen (proto) > 0)
638     prox->proto = atoi (proto);
639     else
640     prox->proto = PROXY_PROTO_NONE;
641     free_if_alloc (proto);
642 twoaday 328
643 twoaday 270 free_if_alloc (prox->host);
644     prox->host = get_reg_entry_keyserver ("Host");
645 twoaday 328
646 twoaday 270 free_if_alloc (prox->user);
647     prox->user = get_reg_entry_keyserver ("User");
648 twoaday 328
649 twoaday 270 free_if_alloc (prox->pass);
650     prox->pass = get_reg_entry_keyserver ("Pass");
651 twoaday 328
652 twoaday 270 prox->port = get_conf_kserver_int ("Port");
653     }
654    
655    
656 twoaday 328 static int
657     is_keyserver_present (const char *name)
658     {
659     for (int i=0; i < MAX_KEYSERVERS; i++) {
660     if (server[i].name != NULL &&
661     stricmp (server[i].name, name) == 0)
662     return 1;
663     }
664     return 0;
665     }
666    
667     /* Load the keyserver configuration. */
668 werner 36 int
669 twoaday 328 kserver_load_conf (void)
670     {
671     char *str_server, *str_port;
672     int port, list_pos;
673 werner 36
674 twoaday 328 /* If a preferred keyserver is available, load
675     * the values and store it at position 0.
676     */
677     str_server = get_reg_entry_keyserver("Default");
678     if (str_server && *str_server) {
679     port = HKP_PORT;
680     str_port = get_reg_entry_keyserver("Default_Port");
681     if (str_port && *str_port)
682     port = atoi (str_port);
683     keyserver_set_default (str_server, port);
684     free_if_alloc (str_port);
685 werner 36 }
686 twoaday 328 free_if_alloc (str_server);
687 werner 36
688 twoaday 328 /* Now add the default pool servers after the
689     * preferred keyserver if present.
690     */
691     list_pos = 1;
692     for (int i=0; server_list[i] != NULL; i++) {
693     if (is_keyserver_present (server_list[i]))
694 werner 36 continue;
695 twoaday 328 server[list_pos].used = 1;
696     server[list_pos].port = HKP_PORT;
697     server[list_pos].name = m_strdup (server_list[i]);
698     server[list_pos].is_default = 0;
699     list_pos++;
700     if (list_pos > MAX_KEYSERVERS)
701 werner 36 break;
702     }
703     return 0;
704 twoaday 147 }
705 werner 36
706    
707 twoaday 119 /* Connect to the keyserver @hostname (port @port).
708     Return value: 0 on success */
709 werner 36 int
710 twoaday 119 kserver_connect (const char *hostname, WORD port, int *conn_fd)
711 twoaday 197 {
712 werner 36 struct hostent *hp;
713     struct sockaddr_in sock;
714 twoaday 197 char host[128] = {0};
715     DWORD iaddr;
716 twoaday 271 bool use_proxy = proxy.host != NULL;
717 twoaday 197 int rc, fd;
718 werner 36
719     if (!port)
720     port = HKP_PORT;
721     if (conn_fd)
722     *conn_fd = 0;
723     hostname = skip_type_prefix (hostname);
724 twoaday 271 log_debug ("kserver_connect: %s:%d\r\n", hostname, port);
725 werner 36
726 twoaday 271 if (use_proxy && proxy.proto == PROXY_PROTO_HTTP)
727 twoaday 197 port = proxy.port;
728 werner 36 memset (&sock, 0, sizeof (sock));
729     sock.sin_family = AF_INET;
730 twoaday 197 sock.sin_port = htons (port);
731 twoaday 273 strncpy (host, use_proxy? proxy.host : hostname, DIM (host)-1);
732 twoaday 197
733 werner 36 if ((iaddr = inet_addr (host)) != INADDR_NONE)
734     memcpy (&sock.sin_addr, &iaddr, sizeof (iaddr));
735     else if ((hp = gethostbyname (host))) {
736     if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
737     log_debug ("gethostbyname: unknown address type.\r\n");
738     return WPTERR_WINSOCK_RESOLVE;
739     }
740     memcpy (&sock.sin_addr, hp->h_addr, hp->h_length);
741     }
742     else {
743 twoaday 328 log_debug ("gethostbyname(%s): failed ec=%d.\r\n", host, net_errno);
744 twoaday 271 return use_proxy? WPTERR_WINSOCK_PROXY : WPTERR_WINSOCK_RESOLVE;
745 werner 36 }
746     fd = socket (AF_INET, SOCK_STREAM, 0);
747     if (fd == INVALID_SOCKET)
748     return WPTERR_WINSOCK_SOCKET;
749     rc = connect (fd, (struct sockaddr *) &sock, sizeof (sock));
750     if (rc == SOCKET_ERROR) {
751 twoaday 119 log_debug ("connect: failed ec=%d.\r\n", net_errno);
752 werner 36 closesocket (fd);
753 twoaday 271 return use_proxy? WPTERR_WINSOCK_PROXY : WPTERR_WINSOCK_CONNECT;
754 werner 36 }
755 twoaday 328
756 werner 36 if (conn_fd)
757     *conn_fd = fd;
758     WSASetLastError (0);
759     return 0;
760 twoaday 119 }
761 werner 36
762    
763 twoaday 328 /* Check if the URL needs to be encoded or not.
764 twoaday 144 static bool
765     URL_must_encoded (const char *url)
766     {
767     if (strchr (url, '.') || strchr (url, '@') || strchr (url, ' '))
768     return true;
769     return false;
770 twoaday 328 }*/
771 twoaday 144
772    
773     /* Perform URL encoding of the given data. */
774 werner 36 static char*
775 twoaday 214 URL_encode (const char *url, DWORD ulen, DWORD *ret_nlen)
776 werner 36 {
777 twoaday 144 gpgme_data_t hd;
778 twoaday 328 char numbuf[8], *p;
779 twoaday 273 size_t i, nlen;
780 werner 36
781 twoaday 209 if (gpgme_data_new (&hd))
782     BUG (0);
783 twoaday 144 for (i=0; i < ulen; i++) {
784     if (isalnum (url[i]) || url[i] == '-')
785     gpg_data_putc (hd, url[i]);
786     else if (url[i] == ' ')
787     gpg_data_putc (hd, '+');
788 werner 36 else {
789 twoaday 144 sprintf (numbuf, "%%%02X", url[i]);
790     gpgme_data_write (hd, numbuf, strlen (numbuf));
791 werner 36 }
792     }
793 twoaday 144
794 twoaday 209 p = data_release_and_get_mem (hd, &nlen);
795 twoaday 144 if (ret_nlen)
796 twoaday 209 *ret_nlen = nlen;
797 werner 36 return p;
798     }
799    
800    
801     /* Format a request for the given keyid (send). */
802     static char*
803 twoaday 119 kserver_send_request (const char *hostname, WORD port,
804 twoaday 214 const char *pubkey, DWORD octets)
805 werner 36 {
806 twoaday 214 const char *fmt;
807     char *request;
808     char *enc_pubkey;
809     DWORD enc_octets;
810 werner 36 int reqlen;
811    
812 twoaday 119 log_debug ("kserver_send_request: %s:%d\r\n", hostname, port);
813 werner 36
814     if (!port)
815     port = HKP_PORT;
816 twoaday 144 enc_pubkey = URL_encode (pubkey, octets, &enc_octets);
817 twoaday 214 reqlen = 2*strlen (hostname) + 2*32/*port*/ + enc_octets + 32 /*len*/ + 1;
818 werner 36
819 twoaday 180 if (proxy.user && proxy.proto == PROXY_PROTO_HTTP) {
820 twoaday 214 fmt = "POST http://%s:%d/pks/add HTTP/1.0\r\n"
821     "Referer: \r\n"
822     "User-Agent: WinPT/W32\r\n"
823     "Host: %s:%d\r\n"
824     "Proxy-Authorization: Basic %s\r\n"
825     "Content-type: application/x-www-form-urlencoded\r\n"
826     "Content-length: %d\r\n"
827 twoaday 328 "Connection: close\r\n"
828 twoaday 214 "\r\n"
829     "keytext=%s"
830     "\r\n";
831     reqlen += strlen (fmt) + strlen (proxy.base64_user) + 1;
832     request = safe_alloc (reqlen+1);
833     _snprintf (request, reqlen, fmt,
834     skip_type_prefix (hostname), port, hostname, port,
835 werner 36 proxy.base64_user, enc_octets+9, enc_pubkey);
836     }
837     else {
838 twoaday 214 fmt = "POST /pks/add HTTP/1.0\r\n"
839     "Referer: \r\n"
840     "User-Agent: WinPT/W32\r\n"
841     "Host: %s:%d\r\n"
842     "Content-type: application/x-www-form-urlencoded\r\n"
843     "Content-length: %d\r\n"
844 twoaday 328 "Connection: close\r\n"
845 twoaday 214 "\r\n"
846     "keytext=%s"
847     "\r\n";
848     reqlen += strlen (fmt)+1;
849     request = safe_alloc (reqlen+1);
850     _snprintf (request, reqlen, fmt,
851     skip_type_prefix (hostname), port,
852 twoaday 119 enc_octets+9, enc_pubkey);
853 werner 36 }
854 twoaday 214
855 werner 36 free_if_alloc (enc_pubkey);
856 twoaday 220 log_debug ("request:\r\n%s\r\n", request);
857 werner 36 return request;
858 twoaday 119 }
859 werner 36
860    
861 twoaday 209 /* Interface for receiving a public key. */
862 werner 36 int
863 twoaday 209 kserver_recvkey (const char *hostname, WORD port, const char *keyid,
864 twoaday 273 char **r_key, size_t *r_keylen)
865 twoaday 119 {
866 twoaday 288 StringBuffer req;
867     const char *reqbuf;
868 twoaday 119 int conn_fd;
869 twoaday 288 int rc;
870 twoaday 119
871 werner 36 if (!port)
872     port = HKP_PORT;
873 twoaday 328 hkp_has_err = 0; /* reset */
874 werner 36 rc = kserver_connect (hostname, port, &conn_fd);
875     if (rc)
876     goto leave;
877 twoaday 214
878 twoaday 180 if (proxy.host && proxy.user && proxy.proto == PROXY_PROTO_HTTP) {
879 twoaday 288 req = req + "GET http://" + skip_type_prefix (hostname) +
880     ":" + port +
881     "/pks/lookup?op=get&search=" + keyid + " HTTP/1.0\r\n" +
882 twoaday 328 "Proxy-Authorization: Basic " + proxy.base64_user + "\r\n" +
883     "Host: " + skip_type_prefix (hostname) + ":" + port + "\r\n"+
884     "Connection: close\r\n"+
885     "\r\n";
886 werner 36 }
887 twoaday 180 else if (proxy.host && proxy.proto == PROXY_PROTO_HTTP) {
888 twoaday 288 req = req + "GET http://" + skip_type_prefix (hostname) +
889     ":" + port + "/pks/lookup?op=get&search=" + keyid +
890 twoaday 328 " HTTP/1.0\r\n" +
891     "Host: " + skip_type_prefix (hostname) + ":" + port + "\r\n"+
892     "Connection: close\r\n"+
893     "\r\n";
894 twoaday 214 }
895 twoaday 288 else
896 twoaday 328 req = req + "GET /pks/lookup?op=get&search=" + keyid +
897     " HTTP/1.0\r\n"+ // FIXME
898     "Host: " + skip_type_prefix (hostname) + ":" + port + "\r\n"+
899     "Connection: close\r\n"+
900     "\r\n";
901 twoaday 288
902 twoaday 328 log_debug ("req:\r\n%s\r\n", req.getBuffer ());
903 werner 36
904 twoaday 288 reqbuf = req.getBuffer ();
905     rc = sock_write (conn_fd, reqbuf, strlen (reqbuf));
906 werner 36 if (rc == SOCKET_ERROR) {
907     rc = WPTERR_WINSOCK_RECVKEY;
908     goto leave;
909     }
910    
911 twoaday 209 rc = sock_read_ext (conn_fd, r_key, r_keylen);
912 twoaday 147 if (rc == SOCKET_ERROR) {
913 werner 36 rc = WPTERR_WINSOCK_RECVKEY;
914     goto leave;
915     }
916    
917 twoaday 220 log_debug ("response:\r\n%s\r\n", *r_key);
918 twoaday 147 rc = check_hkp_response (*r_key, 1);
919 werner 36 if (rc)
920     goto leave;
921    
922     WSASetLastError (0);
923    
924     leave:
925     closesocket (conn_fd);
926     return rc;
927 twoaday 119 }
928 werner 36
929    
930     /* Interface to send a public key. */
931     int
932 twoaday 273 kserver_sendkey (const char *hostname, WORD port,
933     const char *pubkey, size_t len)
934 werner 36 {
935     char *request = NULL;
936 twoaday 195 char log[2048] = {0};
937 twoaday 119 int conn_fd, n;
938     int rc;
939 werner 36
940 twoaday 328 hkp_has_err = 0; /* reset */
941 werner 36 rc = kserver_connect (hostname, port, &conn_fd);
942     if (rc)
943     goto leave;
944    
945     request = kserver_send_request (hostname, port, pubkey, len);
946 twoaday 119 rc = sock_write (conn_fd, request, strlen (request));
947     if (rc == SOCKET_ERROR) {
948 werner 36 rc = WPTERR_WINSOCK_SENDKEY;
949     goto leave;
950     }
951    
952 twoaday 271 rc = sock_read (conn_fd, log, DIM (log)-1, &n);
953 twoaday 119 if (rc == SOCKET_ERROR) {
954 werner 36 rc = WPTERR_WINSOCK_SENDKEY;
955     goto leave;
956     }
957    
958 twoaday 195 log_debug ("kserver_sendkey: read %d bytes\r\n%s\r\n", n, log);
959 werner 36 rc = check_hkp_response (log, 0);
960 twoaday 119 if (rc)
961 werner 36 goto leave;
962    
963     WSASetLastError (0);
964 twoaday 273
965 werner 36 leave:
966     closesocket (conn_fd);
967     free_if_alloc (request);
968     return rc;
969 twoaday 119 }
970 werner 36
971    
972 twoaday 185 /* Check keyserver response. */
973     static int
974     kserver_search_chkresp (int fd)
975     {
976     char buf[128];
977     int n=0;
978    
979     /* parse response 'HTTP/1.0 500 OK' */
980 twoaday 271 if (sock_getline (fd, buf, DIM (buf)-1, &n))
981 twoaday 185 return WPTERR_KEYSERVER_NOTFOUND;
982    
983     log_debug ("kserver_search_chkpresp: %s\r\n", buf);
984     if (strncmp (buf, "HTTP/1.", 7))
985     return WPTERR_KEYSERVER_NOTFOUND;
986     if (strncmp (buf+(8+1), "200", 3))
987     return WPTERR_KEYSERVER_NOTFOUND;
988     return 0;
989     }
990    
991    
992     /* End the keyserver search procedure. */
993     void
994     kserver_search_end (int conn_fd)
995     {
996     log_debug ("kserver_search_end: fd=%d\r\n", conn_fd);
997     closesocket (conn_fd);
998     }
999    
1000    
1001 twoaday 214 /* Extract the amount of keys from the info record. */
1002 twoaday 273 static size_t
1003 twoaday 214 count_keys_in_response (char *buf)
1004     {
1005     char *p;
1006     int recno = 0;
1007 twoaday 273 size_t n = 0;
1008 twoaday 214
1009     /* info:1:4 */
1010     if (strncmp (buf, "info", 4))
1011     return 0;
1012     p = strtok (buf, ":");
1013     while (p != NULL) {
1014     recno++;
1015     if (recno == 3)
1016     n = atoi (p);
1017     p = strtok (NULL, ":");
1018     }
1019     return n;
1020     }
1021    
1022    
1023     /* Start the keyserver search.
1024     Connect to host @hostname and port @port.
1025     The pattern are given in @pattern.
1026     The socket is returned in @conn_fd and @nkeys contains
1027     the amount of keys which were found. */
1028 werner 36 int
1029 twoaday 185 kserver_search_begin (const char *hostname, WORD port,
1030 twoaday 273 const char *pattern, int *conn_fd, size_t *nkeys)
1031 werner 36 {
1032 twoaday 288
1033     StringBuffer req;
1034     const char *reqbuf;
1035 twoaday 185 char *enc_patt = NULL;
1036 twoaday 214 char status[128];
1037 werner 36 int rc, sock_fd;
1038 twoaday 288 int nread;
1039 twoaday 144
1040 twoaday 214 *conn_fd = 0;
1041    
1042 werner 36 rc = kserver_connect (hostname, port, &sock_fd);
1043 twoaday 214 if (rc)
1044 werner 36 goto leave;
1045 twoaday 144
1046 twoaday 185 enc_patt = URL_encode (pattern, strlen (pattern), NULL);
1047 twoaday 180 if (proxy.host && proxy.user && proxy.proto == PROXY_PROTO_HTTP) {
1048 twoaday 288 req = req + "GET http://" + skip_type_prefix (hostname) + ":" + port +
1049     "/pks/lookup?options=mr&op=index&search=" + enc_patt +
1050 twoaday 328 " HTTP/1.0\r\n" +
1051     "Host: " + skip_type_prefix (hostname) + ":" + port+ "\r\n"+
1052     "Connection: close\r\n" +
1053 twoaday 288 "Proxy-Authorization: Basic " + proxy.base64_user + "\r\n\r\n";
1054 werner 36 }
1055 twoaday 180 else if (proxy.host && proxy.proto == PROXY_PROTO_HTTP) {
1056 twoaday 288 req = req + "GET http://" + skip_type_prefix (hostname) + ":" + port +
1057     "/pks/lookup?options=mr&op=index&search=" + enc_patt +
1058 twoaday 328 " HTTP/1.0\r\n"+
1059     "Host: " + skip_type_prefix (hostname) + ":" + port+ "\r\n"+
1060     "Connection: close\r\n"+
1061     "\r\n";
1062 werner 36 }
1063     else {
1064 twoaday 288 req = req + "GET /pks/lookup?options=mr&op=index&search=" +
1065 twoaday 328 enc_patt + " HTTP/1.0\r\n" +
1066     "Host: " + skip_type_prefix (hostname) + ":" + port+ "\r\n"+
1067     "Connection: close\r\n"+
1068     "\r\n";
1069 werner 36 }
1070 twoaday 288
1071     log_debug ("kserver_search_begin:\r\n%s\r\n", req.getBuffer ());
1072     reqbuf = req.getBuffer ();
1073     if (sock_write (sock_fd, reqbuf, strlen (reqbuf)) == SOCKET_ERROR) {
1074 werner 36 rc = WPTERR_GENERAL;
1075     goto leave;
1076     }
1077    
1078 twoaday 185 rc = kserver_search_chkresp (sock_fd);
1079     if (rc) {
1080     closesocket (sock_fd);
1081     sock_fd = 0;
1082 twoaday 214 goto leave;
1083 twoaday 185 }
1084    
1085 twoaday 214 /* Skip all lines until we reach the "info:" record. */
1086     for (;;) {
1087 twoaday 288 if (sock_getline (sock_fd, status, DIM (status)-1, &nread)) {
1088 twoaday 214 log_debug ("kserver_search_begin: retrieving status line failed.\r\n");
1089     closesocket (sock_fd);
1090     sock_fd = 0;
1091     rc = WPTERR_GENERAL;
1092     break;
1093     }
1094     if (!strncmp (status, "info:", 5))
1095     break;
1096     }
1097    
1098     if (!rc)
1099     *nkeys = count_keys_in_response (status);
1100 werner 36 *conn_fd = sock_fd;
1101    
1102     leave:
1103 twoaday 185 free_if_alloc (enc_patt);
1104 werner 36 return rc;
1105 twoaday 119 }
1106 werner 36
1107    
1108 twoaday 214 /* Parse a single pub record returned by the keyserver. */
1109     static void
1110     parse_pub_record (keyserver_key_s *key, char *buf)
1111     {
1112     enum pub_rec_t {ID=1, KEYID, ALGO, SIZE, CREATE, EXPIRE};
1113     char *p;
1114     int recno = 0;
1115 twoaday 271 int off = 0;
1116 werner 36
1117 twoaday 290 /* pub:{BF3DF9B4, ED4681C9BF3DF9B4, FPR}:17:1024:925411133:: */
1118 twoaday 214 p = strtok (buf, ":");
1119     while (p != NULL) {
1120     recno++;
1121     switch (recno) {
1122     case ID:
1123     break;
1124 werner 36
1125 twoaday 271 case KEYID:
1126     /* If for any reason the returned record actually contains
1127     a fingerprint instead of a key ID, we truncate the fpr. */
1128     off = strlen (p) == 40? 32 : 0;
1129 twoaday 214 free_if_alloc (key->keyid);
1130 twoaday 271 key->keyid = m_strdup (p+off);
1131 twoaday 214 break;
1132    
1133     case ALGO:
1134     key->algo = atoi (p);
1135     break;
1136    
1137     case SIZE:
1138     key->bits = atoi (p);
1139     break;
1140    
1141     case CREATE:
1142     key->creation = strtoul (p, NULL, 10);
1143     break;
1144    
1145     case EXPIRE:
1146     key->expires = strtoul (p, NULL, 10);
1147     break;
1148     }
1149     p = strtok (NULL, ":");
1150     }
1151     }
1152    
1153    
1154     /* Parse a single user id returned by the keyserver. */
1155     static void
1156     parse_uid_record (keyserver_key_s *key, char *buf)
1157 twoaday 144 {
1158 twoaday 214 enum uid_rec_t {ID=1, UID, CREATE, EXPIRE};
1159     keyserver_uid_s *u, *n;
1160 twoaday 225 char *p, *raw;
1161 twoaday 214 int recno = 0;
1162 twoaday 144
1163 twoaday 214 /* uid:Timo Schulz <[email protected]>:1138440360:: */
1164     u = new keyserver_uid_s;
1165     memset (u, 0, sizeof *u);
1166    
1167     p = strtok (buf, ":");
1168 twoaday 144 while (p != NULL) {
1169 twoaday 214 recno++;
1170    
1171     switch (recno) {
1172     case ID:
1173     break;
1174    
1175     case UID:
1176 twoaday 225 unhexify_buffer (p, &raw);
1177     u->uid = utf8_to_native (raw);
1178     free_if_alloc (raw);
1179 twoaday 214 break;
1180    
1181     case CREATE:
1182     u->creation = strtoul (p, NULL, 10);
1183     break;
1184    
1185     case EXPIRE:
1186     u->expires = strtoul (p, NULL, 10);
1187     break;
1188 twoaday 144 }
1189 twoaday 214
1190     p = strtok (NULL, ":");
1191 twoaday 144 }
1192 twoaday 214 if (!key->uids)
1193     key->uids = u;
1194     else {
1195     for (n = key->uids; n->next; n=n->next)
1196     ;
1197     n->next = u;
1198     }
1199 twoaday 144 }
1200    
1201    
1202 twoaday 214 /* Peek the next 3 bytes to check if the next line
1203     would be a new "pub" record. In this case, return
1204     -1 as an EOF indication, 0 otherwise. */
1205     static int
1206     is_key_eof (int fd)
1207     {
1208     char buf[64];
1209     int n;
1210    
1211     n = recv (fd, buf, 3, MSG_PEEK);
1212     if (n < 3 || strncmp (buf, "pub", 3))
1213     return 0;
1214     return -1;
1215     }
1216    
1217    
1218     /* Return the next key from the search response. */
1219 werner 36 int
1220 twoaday 214 kserver_search_next (int fd, keyserver_key_s **r_key)
1221 werner 36 {
1222 twoaday 214 keyserver_uid_s *uid, *u = NULL;
1223     keyserver_key_s *key;
1224     char buf[512];
1225     int n = 0;
1226     long max = 0;
1227 werner 36
1228 twoaday 185 log_debug ("keyserver_search_next:\r\n");
1229 twoaday 214 *r_key = NULL;
1230 werner 36
1231 twoaday 214 key = new keyserver_key_s;
1232     memset (key, 0, sizeof *key);
1233     for (;;) {
1234 twoaday 271 if (sock_getline (fd, buf, DIM (buf)-1, &n))
1235 twoaday 214 break;
1236 twoaday 220 /*log_debug ("record: '%s'\r\n", buf); */
1237 twoaday 214 if (!strncmp (buf, "pub", 3))
1238     parse_pub_record (key, buf);
1239     else
1240     parse_uid_record (key, buf);
1241     if (is_key_eof (fd))
1242     break;
1243     }
1244 twoaday 144
1245 twoaday 214 /* the uid with the newest self sig is used as the
1246     primary user id. */
1247     for (uid = key->uids; uid; uid = uid->next) {
1248     if (uid->creation > max) {
1249     max = uid->creation;
1250     u = uid;
1251 werner 36 }
1252     }
1253    
1254 twoaday 214 key->main_uid = u? u : key->uids;
1255     *r_key = key;
1256 werner 36 return 0;
1257 twoaday 144 }
1258 werner 36
1259    
1260 twoaday 214 /* Release the keyserver key @key and all its elements. */
1261     void
1262     kserver_release_key (keyserver_key_s *key)
1263     {
1264     keyserver_uid_s *u;
1265    
1266     while (key->uids) {
1267     u = key->uids->next;
1268     free_if_alloc (key->uids->uid);
1269     free_if_alloc (key->uids);
1270     key->uids = u;
1271     }
1272     free_if_alloc (key->keyid);
1273     free_if_alloc (key);
1274     }
1275    
1276    
1277 twoaday 119 /* Release mbmers in the proxy context @ctx. */
1278 werner 36 void
1279 twoaday 180 kserver_proxy_release (keyserver_proxy_t ctx)
1280 werner 36 {
1281 twoaday 119 free_if_alloc (ctx->host);
1282     free_if_alloc (ctx->pass);
1283     free_if_alloc (ctx->user);
1284 twoaday 185 ctx->port = ctx->proto = 0;
1285 twoaday 119 }
1286 werner 36
1287    
1288 twoaday 273 /* Check if the given name @name is a valid inernet address
1289     which means an dotted IP or a valid DNS name.
1290     Return value: 0 on success. */
1291 werner 36 int
1292 twoaday 273 check_inet_address (const char *addr)
1293 werner 36 {
1294     const char *not_allowed = "=!ยง$%&@#*~\\/}][{<>|,;:'";
1295    
1296 twoaday 328 for (size_t i=0; i < strlen (addr); i++) {
1297 twoaday 273 if (strchr (not_allowed, addr[i]))
1298     return -1;
1299 werner 36 }
1300     return 0;
1301     }
1302 twoaday 214
1303    
1304     /* Split the URL @r_keyserver into the host and the port
1305     part if possible. */
1306     gpgme_error_t
1307     parse_keyserver_url (char **r_keyserver, unsigned short *r_port)
1308     {
1309     char *p;
1310     char *url = *r_keyserver;
1311 twoaday 328 int off;
1312 twoaday 214
1313     /* no port is given so use the default port. */
1314     p = strrchr (url, ':');
1315     if (p == strchr (url, ':')) {
1316 twoaday 328 *r_port = HKP_PORT;
1317 twoaday 214 return 0;
1318     }
1319 twoaday 226
1320     if (url[(p-url)-1] == '/') /* remove / in .de/:11371 */
1321     off = 1;
1322 twoaday 328 else
1323     off = 0;
1324 twoaday 226
1325     *r_keyserver = substr (url, 0, (p-url)-off);
1326 twoaday 214 *r_port = atoi (url+(p-url)+1);
1327 twoaday 220 free_if_alloc (url);
1328 twoaday 214 return 0;
1329     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26