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

Annotation of /trunk/Src/wptKeyserver.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 290 - (hide annotations)
Sat Mar 10 11:18:34 2007 UTC (17 years, 11 months ago) by twoaday
File size: 36848 byte(s)


1 werner 36 /* wptKeyserver.cpp - W32 Keyserver Access
2 twoaday 288 * Copyright (C) 2000-2007 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
43     keyserver server[MAX_KEYSERVERS] = {0};
44 twoaday 180 keyserver_proxy_s proxy = {0};
45 twoaday 119 static const char *server_list[] = {
46 twoaday 193 "hkp://sks.keyserver.penguin.de",
47 werner 36 "hkp://subkeys.pgp.net",
48     "ldap://keyserver.pgp.com",
49     NULL
50     };
51    
52    
53 twoaday 119 static char hkp_errmsg[1024]; /* Holds the error message from the server */
54     static int hkp_err = 0; /* != 0 indicates an error occurred. */
55    
56 twoaday 147 /* Default keyserver and port. */
57     char *default_keyserver = NULL;
58     WORD default_keyserver_port = 0;
59 twoaday 119
60 twoaday 273 /* Default socket timeout (secs). */
61     static size_t default_socket_timeout = 6;
62 twoaday 119
63 twoaday 214
64     /* Wrapper for safe memory allocation. */
65     static char*
66     safe_alloc (DWORD n)
67     {
68     char *p;
69    
70     p = new char[n+1];
71     if (!p)
72     BUG (0);
73     memset (p, 0, n);
74     return p;
75     }
76    
77 twoaday 180 /* Basic64 encode the input @inbuf to @outbuf. */
78 werner 36 static void
79 twoaday 180 base64_encode (const char *inbuf, char *outbuf)
80 twoaday 181 {
81     char base64code[] =
82     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
83 twoaday 180 int index = 0, temp = 0, res = 0;
84 twoaday 271 int i, inputlen, len = 0;
85 werner 36
86 twoaday 180 inputlen = strlen (inbuf);
87     for (i = 0; i < inputlen; i++) {
88 werner 36 res = temp;
89 twoaday 180 res = (res << 8) | (inbuf[i] & 0xFF);
90 werner 36 switch (index++) {
91 twoaday 180 case 0:
92     outbuf[len++] = base64code[res >> 2 & 0x3F];
93     res &= 0x3;
94     break;
95     case 1:
96     outbuf[len++] = base64code[res >> 4 & 0x3F];
97     res &= 0xF;
98     break;
99     case 2:
100     outbuf[len++] = base64code[res >> 6 & 0x3F];
101     outbuf[len++] = base64code[res & 0x3F];
102     res = index = 0;
103     break;
104 werner 36 }
105     temp = res;
106     }
107    
108 twoaday 180 if (index == 2) {
109     outbuf[len++] = base64code[temp << 2 & 0x3F];
110     outbuf[len++] = '=';
111 werner 36 }
112 twoaday 180 else if (index == 1) {
113     outbuf[len++] = base64code[temp << 4 & 0x3F];
114     outbuf[len++] = '=';
115     outbuf[len++] = '=';
116     }
117    
118     outbuf[len] = '\0';
119 twoaday 119 }
120 werner 36
121    
122 twoaday 222 /* Check that the given buffer contains a valid keyserver URL
123     and return the prefix length, 0 in case of an error. */
124     static int
125     check_URL (const char *buf)
126     {
127     const char *proto[] = {
128     "ldap://",
129     "http://",
130     "finger://",
131     "hkp://",
132     NULL};
133     int i;
134    
135     if (strlen (buf) < 7)
136     return 0;
137    
138     for (i=0; proto[i] != NULL; i++) {
139     if (strstr (buf, proto[i]))
140     return strlen (proto[i]);
141     }
142     return 0;
143     }
144    
145    
146 werner 36 /* Skip the URL schema and return only the host part of it. */
147 twoaday 119 static const char*
148     skip_type_prefix (const char *hostname)
149 werner 36 {
150 twoaday 222 int pos;
151    
152     if (!hostname)
153     return hostname;
154    
155     pos = check_URL (hostname);
156     if (pos > 0)
157     hostname += pos;
158 werner 36 return hostname;
159     }
160    
161 twoaday 229 /* Parse the keyserver response and extract the human
162     readable text passages. */
163     static int
164     parse_keyserver_error (const char *resp, char *txt, size_t txtlen)
165     {
166     char *p, *p2;
167 werner 36
168 twoaday 229 /* If we find no 'Error' substring, we assume a success. */
169     if (!stristr (resp, "Error"))
170 twoaday 231 return -1;
171 twoaday 229
172     memset (txt, 0, txtlen);
173     p = strstr (resp, "\r\n\r\n");
174     if (!p)
175     return -1;
176     resp += (p-resp);
177     p = strstr (resp, "<h1>");
178     if (!p)
179     return -1;
180     resp += (p-resp)+strlen ("<h1>");
181     p = strstr (resp, "</h1>");
182     if (!p)
183     return -1;
184     resp += (p-resp)+strlen ("</h1>");
185     p2 = strstr (resp, "</body>");
186     if (p2 != NULL)
187     memcpy (txt, resp, (p2-resp));
188     else {
189     if (!strnicmp (resp, "<p>", 3))
190     resp += 3;
191     while (resp && *resp == '\r' || *resp == '\n')
192     resp++;
193     memcpy (txt, resp, strlen (resp));
194     }
195     return 0;
196     }
197    
198    
199 werner 36 /* Check that the keyserver response indicates an OK.
200     Return 0 on success. */
201     static int
202     check_hkp_response (const char *resp, int recv)
203 twoaday 229 {
204     int ec;
205 werner 36
206 twoaday 220 log_debug ("check_hkp_response: '%s'\r\n", resp);
207 werner 36 ec = recv ? WPTERR_WINSOCK_RECVKEY : WPTERR_WINSOCK_SENDKEY;
208     if (!strstr (resp, "HTTP/1.0 200 OK") &&
209 twoaday 229 !strstr (resp, "HTTP/1.1 200 OK") &&
210     !strstr (resp, "HTTP/1.0 500 OK") &&
211     !strstr (resp, "HTTP/1.1 500 OK"))
212     return ec; /* http error */
213    
214 twoaday 271 if (!parse_keyserver_error (resp, hkp_errmsg, DIM (hkp_errmsg)-2)) {
215 twoaday 229 if (!strlen (hkp_errmsg))
216 twoaday 271 _snprintf (hkp_errmsg, DIM (hkp_errmsg)-1,
217 twoaday 229 "Unknown keyserver error");
218     hkp_err = 1;
219 werner 36 return ec;
220     }
221     return 0;
222     }
223    
224    
225     /* Read a single line (\r\n) from a socket.
226     Return 0 on success. */
227     static int
228     sock_getline (int fd, char *buf, int buflen, int *nbytes)
229     {
230     char ch;
231 twoaday 180 int nread = 0;
232 werner 36
233     if (nbytes)
234     *nbytes = 0;
235     *buf = 0;
236     while (recv (fd, &ch, 1, 0) > 0) {
237     *buf++ = ch;
238 twoaday 180 nread++;
239     if (ch == '\r')
240     continue; /* remove this char. */
241     if (ch == '\n' || nread == (buflen - 1)) {
242 werner 36 *buf = 0;
243     if (nbytes)
244 twoaday 180 *nbytes = nread;
245 werner 36 return 0;
246     }
247     }
248    
249     return -1;
250     }
251    
252    
253     /* Perform a select() on the given fd to find out
254     is there is data for reading. Wait at least @nsecs seconds. */
255     static int
256     sock_select (int fd, int nsecs)
257     {
258     FD_SET rfd;
259     timeval tv = {nsecs, 0};
260    
261     FD_ZERO (&rfd);
262     FD_SET (fd, &rfd);
263 twoaday 119 if (select (fd + 1, &rfd, NULL, NULL, &tv) == SOCKET_ERROR) {
264     log_debug ("sock_select: select() failed ec=%d.\r\n", net_errno);
265 werner 36 return SOCKET_ERROR;
266 twoaday 119 }
267 werner 36 if (FD_ISSET (fd, &rfd))
268     return 1;
269     return 0;
270     }
271    
272    
273 twoaday 119 /* Read from a socket @fd to buffer @buf with a fixed timeout
274     of 10 seconds. The amount of bytes which were read are
275     returned in @nbytes.
276 werner 36 Return value: 0 on success. */
277     static int
278 twoaday 273 sock_read (int fd, char *buf, size_t buflen, int *nbytes)
279 twoaday 181 {
280 twoaday 273 int nread;
281     size_t nleft = buflen;
282     size_t n = 0;
283     int rc;
284 twoaday 195
285     if (nbytes)
286     *nbytes = 0;
287 werner 36 while (nleft > 0) {
288 twoaday 181 if (n >= default_socket_timeout)
289 werner 36 return WPTERR_WINSOCK_TIMEOUT;
290     rc = sock_select (fd, 1);
291     if (rc == SOCKET_ERROR)
292 twoaday 119 return rc;
293     else if (!rc)
294 werner 36 n++;
295     else {
296     nread = recv (fd, buf, nleft, 0);
297 twoaday 119 if (nread == SOCKET_ERROR) {
298     log_debug ("sock_read: recv() failed ec=%d.\r\n", net_errno);
299 werner 36 return SOCKET_ERROR;
300 twoaday 119 }
301 werner 36 else if (!nread)
302     break;
303     nleft -= nread;
304     buf += nread;
305     }
306     }
307     if (nbytes)
308     *nbytes = buflen - nleft;
309    
310     return 0;
311     }
312    
313 twoaday 209
314     /* Helper to create a string from the gpgme data and
315     then release the gpgme data object. */
316     char*
317 twoaday 273 data_release_and_get_mem (gpgme_data_t in, size_t *r_bufferlen)
318 twoaday 209 {
319     size_t n;
320     char *buffer, *p;
321    
322     gpg_data_putc (in, '\0');
323     p = gpgme_data_release_and_get_mem (in, &n);
324     buffer = m_strdup (p);
325     if (r_bufferlen)
326 twoaday 273 *r_bufferlen = n;
327 twoaday 209 gpgme_free (p);
328     return buffer;
329     }
330    
331    
332 twoaday 147 /* Read much data as possible from the socket @fd and
333     return the data in @buffer. Caller must free data.
334     Return value: 0 on success. */
335     int
336 twoaday 273 sock_read_ext (int fd, char **buffer, size_t *r_bufferlen)
337 twoaday 147 {
338     gpgme_data_t dh;
339 twoaday 209 char buf[1024];
340 twoaday 273 size_t timeout=0;
341 twoaday 147 int nread, rc;
342 werner 36
343 twoaday 209 if (gpgme_data_new (&dh))
344 twoaday 273 return SOCKET_ERROR;
345     while (timeout < default_socket_timeout) {
346 twoaday 147 rc = sock_select (fd, 1);
347     if (rc == SOCKET_ERROR) {
348     gpgme_data_release (dh);
349     return rc;
350     }
351     else if (!rc)
352 twoaday 273 timeout++; /* socket not ready yet. */
353 twoaday 147 else {
354 twoaday 271 nread = recv (fd, buf, DIM (buf), 0);
355 twoaday 147 if (nread == SOCKET_ERROR)
356     return SOCKET_ERROR;
357     else if (!nread)
358     break;
359     gpgme_data_write (dh, buf, nread);
360     }
361     }
362 twoaday 273 if (timeout >= default_socket_timeout)
363     return WPTERR_WINSOCK_TIMEOUT;
364 twoaday 209 *buffer = data_release_and_get_mem (dh, r_bufferlen);
365 twoaday 147 return 0;
366     }
367    
368    
369 twoaday 119 /* Write the buffer @buf with the length @buflen to a socket @fd. */
370 werner 36 static int
371 twoaday 273 sock_write (int fd, const char *buf, size_t buflen)
372 werner 36 {
373 twoaday 273 int nwritten;
374 werner 36 int nleft = buflen;
375    
376     while (nleft > 0) {
377     nwritten = send (fd, buf, nleft, 0);
378 twoaday 119 if (nwritten == SOCKET_ERROR) {
379     log_debug ("sock_write: send() failed ec=%d\r\n", net_errno);
380 werner 36 return SOCKET_ERROR;
381 twoaday 119 }
382 werner 36 nleft -= nwritten;
383 twoaday 180 buf += nwritten;
384 werner 36 }
385    
386     return 0;
387     }
388    
389    
390     /* Initialize the Winsock2 interface.*/
391     int
392     wsock_init (void)
393     {
394     WSADATA wsa;
395    
396 twoaday 119 if (WSAStartup (0x202, &wsa)) {
397     log_debug ("wsock_init: WSAStartup failed ec=%d\r\n", net_errno);
398 werner 36 return WPTERR_WINSOCK_INIT;
399 twoaday 119 }
400 werner 36 return 0;
401     }
402    
403    
404     /* Cleanup the Winsock2 interface. */
405     void
406     wsock_end (void)
407     {
408 twoaday 150 char *p;
409 werner 36 int i;
410    
411 twoaday 271 #ifdef WINPT_MOBILE
412     p = m_strdup ("keyserver.conf");
413     #else
414 twoaday 150 p = make_special_filename (CSIDL_APPDATA, "winpt\\keyserver.conf", NULL);
415 twoaday 271 #endif
416 twoaday 150 kserver_save_conf (p);
417     free_if_alloc (p);
418 werner 36 free_if_alloc (default_keyserver);
419     for (i=0; i < MAX_KEYSERVERS; i++) {
420 twoaday 273 if (server[i].name != NULL)
421 werner 36 free_if_alloc (server[i].name);
422     }
423 twoaday 180 kserver_proxy_release (&proxy);
424 werner 36 WSACleanup ();
425 twoaday 222 log_debug ("wsock_end: cleanup finished.\r\n");
426 werner 36 }
427    
428    
429     /* Return a string representation of a winsock error. */
430     const char*
431     wsock_strerror (void)
432 twoaday 211 {
433 werner 36 int ec = WSAGetLastError ();
434    
435 twoaday 211 if (!ec)
436     return "";
437 werner 36 switch (ec) {
438 twoaday 119 case WSAENETDOWN:
439 twoaday 211 return _("Network unreachable");
440    
441     case WSAEHOSTUNREACH:
442     return _("Host unreachable");
443    
444 twoaday 119 case WSAHOST_NOT_FOUND:
445 twoaday 211 return _("Could not resolve host name");
446    
447     case WSAECONNREFUSED:
448     return _("Connection refused");
449    
450 twoaday 119 case WSAETIMEDOUT:
451 twoaday 211 case WSAECONNABORTED:
452     return _("Connection timeout");
453    
454     case WSAENETRESET:
455     case WSAECONNRESET:
456     return _("Connection resetted by peer");
457    
458     case WSAESHUTDOWN:
459     return _("Socket has been shutdown");
460    
461 twoaday 119 default:
462 twoaday 211 break;
463 werner 36 }
464 twoaday 211
465     return "";
466 werner 36 }
467    
468    
469 twoaday 181 /* Set default socket timeout for all reading operations. */
470     void
471 twoaday 273 kserver_set_socket_timeout (size_t nsec)
472 twoaday 181 {
473 twoaday 222 if (nsec < 0 || nsec > 3600)
474 twoaday 181 nsec = 0;
475     default_socket_timeout = nsec;
476     }
477    
478    
479 werner 36 /* Return the last keyserver error as a string. */
480     const char*
481     kserver_strerror (void)
482     {
483     if (hkp_err)
484     return hkp_errmsg;
485     return NULL;
486     }
487    
488    
489     /* Read a keyserver from the list at index @idx.
490     Return value: keyserver name at the given position. */
491     const char*
492 twoaday 119 kserver_get_hostname (int idx, int type, WORD *port)
493 werner 36 {
494     if (type == -1) {
495     *port = default_keyserver_port;
496     return default_keyserver;
497     }
498 twoaday 273 else if (!type && (size_t)idx < DIM (server_list)) {
499 twoaday 222 /* XXX: handle non HKP servers. */
500 werner 36 *port = HKP_PORT;
501     return server_list[idx];
502     }
503     return NULL;
504     }
505    
506    
507     /* Check if the computer is connected to the internet.
508     Return 0 on success -1 otherwise. */
509     int
510     kserver_check_inet_connection (void)
511     {
512     int fd;
513    
514     if (!kserver_connect (default_keyserver, default_keyserver_port, &fd)) {
515     closesocket (fd);
516     return 0;
517     }
518 twoaday 220 log_debug ("kserver_check_inet_connection: no inet connection.\r\n");
519 werner 36 return -1;
520     }
521    
522    
523 twoaday 119 /* If the request contains the keyid, it have to be
524     always postfix with '0x'+keyid. This code checks
525     if the keyid is a decimal value and if so if it contains
526 twoaday 180 the '0x'. If not it is inserted. */
527 werner 36 const char*
528     kserver_check_keyid (const char *keyid)
529     {
530 twoaday 222 static char id[22];
531 werner 36
532     if (strstr (keyid, "@"))
533     return keyid; /* email address */
534     if (strncmp (keyid, "0x", 2)) {
535     memset (&id, 0, sizeof (id));
536 twoaday 271 _snprintf (id, DIM (id)-1, "0x%s", keyid);
537 werner 36 return id;
538     }
539     return keyid;
540 twoaday 119 }
541 werner 36
542    
543 twoaday 119 /* Update the keyserver proxy user. */
544 werner 36 static void
545 twoaday 180 update_proxy_user (const char *proxy_user, const char *proxy_pass)
546 werner 36 {
547     char t[257]; /* user:pass = 127+1+127+1 = 257 */
548     int n = 0;
549    
550     n = 4*strlen (proxy_user) / 3 + 32 + strlen (proxy_pass) + 2;
551     free_if_alloc (proxy.base64_user);
552 twoaday 214 proxy.base64_user = safe_alloc (n+1);
553 twoaday 271 _snprintf (t, DIM (t)-1, "%s:%s", proxy_user, proxy_pass);
554 twoaday 180 base64_encode (t, proxy.base64_user);
555 werner 36 free_if_alloc (proxy.user);
556     free_if_alloc (proxy.pass);
557     proxy.user = m_strdup (proxy_user);
558     proxy.pass = m_strdup (proxy_pass);
559 twoaday 119 }
560 werner 36
561    
562     /* Get the port number from the given protocol. */
563     static int
564     port_from_proto (int proto)
565     {
566     switch (proto) {
567 twoaday 226 case KSPROTO_LDAP: return LDAP_PORT;
568 werner 36 case KSPROTO_FINGER: return FINGER_PORT;
569 twoaday 214 case KSPROTO_HTTP: return HKP_PORT;
570 werner 36 }
571     return 0;
572     }
573    
574    
575     /* Get the port number from the given URL. */
576     static int
577 twoaday 180 proto_from_URL (const char *buf)
578 werner 36 {
579 twoaday 214 if (strstr (buf, "ldap"))
580 werner 36 return KSPROTO_LDAP;
581 twoaday 226 else if (strstr (buf, "finger"))
582 werner 36 return KSPROTO_FINGER;
583     return KSPROTO_HKP;
584     }
585    
586    
587 twoaday 220 /* Set the default keyserver.
588     If @hostname is NULL, use the predefined keyserver. */
589 werner 36 void
590 twoaday 119 keyserver_set_default (const char *hostname, WORD port)
591 werner 36 {
592 twoaday 220 if (!port)
593     port = HKP_PORT;
594 twoaday 181 if (hostname != NULL) {
595 werner 36 free_if_alloc (default_keyserver);
596     default_keyserver = m_strdup (hostname);
597     default_keyserver_port = port;
598     }
599 twoaday 220 if (!default_keyserver) {
600 twoaday 181 default_keyserver = m_strdup (DEF_HKP_KEYSERVER);
601 twoaday 220 default_keyserver_port = HKP_PORT;
602     }
603 werner 36 server[0].name = m_strdup (default_keyserver);
604     server[0].used = 1;
605     server[0].port = port;
606     server[0].proto = proto_from_URL (default_keyserver);
607 twoaday 119 }
608 werner 36
609    
610 twoaday 119 /* Skip all kind of whitespace chars in @str. */
611     static const char*
612     skip_whitespace (const char *str)
613 werner 36 {
614 twoaday 119 while (str && *str) {
615 werner 36 if (*str == ' ' ||
616     *str == '\t' ||
617     *str == '\n' ||
618 twoaday 119 *str == '\r') {
619 werner 36 str++;
620     continue;
621     }
622     break;
623     }
624     return str;
625     }
626    
627    
628 twoaday 150 /* Save the keyserver config file in @conf. */
629     int
630     kserver_save_conf (const char *conf)
631     {
632     FILE *fp;
633     int pos;
634    
635     fp = fopen (conf, "wb");
636     if (!fp) {
637     msg_box (NULL, _("Could not save keyserver.conf file"),
638     _("Keyserver"), MB_ERR);
639     return -1;
640     }
641    
642 twoaday 180 fprintf (fp, "# do NOT manually modify this file, it will be "
643     "generated automatically!!\r\n");
644 twoaday 150 for (pos = 0; pos < MAX_KEYSERVERS; pos++) {
645     if (!server[pos].used)
646     continue;
647 twoaday 165 fprintf (fp, "%s:%d\r\n", server[pos].name, server[pos].port);
648 twoaday 150 }
649     fclose (fp);
650     return 0;
651     }
652    
653    
654 twoaday 270 /* Return the specified keyserver config setting @key as an integer. */
655     static int
656     get_conf_kserver_int (const char *key)
657     {
658     char *p;
659     int val = 0;
660    
661     p = get_reg_entry_keyserver (key);
662     if (p && *p)
663     val = atoi (p);
664     free_if_alloc (p);
665     return val;
666     }
667    
668    
669     /* Read the proxy configuration and store it into @prox. */
670     static void
671     read_proxy_config (keyserver_proxy_t prox)
672     {
673     char *proto;
674    
675     if (!prox)
676     return;
677    
678     proto = get_reg_entry_keyserver("Proto");
679     if (proto != NULL && strlen (proto) > 0)
680     prox->proto = atoi (proto);
681     else
682     prox->proto = PROXY_PROTO_NONE;
683     free_if_alloc (proto);
684     free_if_alloc (prox->host);
685     prox->host = get_reg_entry_keyserver ("Host");
686     free_if_alloc (prox->user);
687     prox->user = get_reg_entry_keyserver ("User");
688     free_if_alloc (prox->pass);
689     prox->pass = get_reg_entry_keyserver ("Pass");
690     prox->port = get_conf_kserver_int ("Port");
691     }
692    
693    
694 twoaday 147 /* Load the keyserver config file @conf. */
695 werner 36 int
696 twoaday 147 kserver_load_conf (const char *conf)
697 twoaday 193 {
698 werner 36 FILE *fp;
699 twoaday 180 char buf[1024], *s, *p;
700 werner 36 char *user = NULL, *pass = NULL;
701 twoaday 273 int no_config=0, chk_pos;
702 twoaday 73 int pos;
703 werner 36
704     for (pos = 0; pos < MAX_KEYSERVERS; pos++) {
705     server[pos].used = 0;
706     server[pos].port = HKP_PORT;
707 twoaday 273 server[pos].name = NULL;
708 werner 36 }
709    
710     fp = fopen (conf, "rb");
711     if (!fp) {
712     for (pos = 0; server_list[pos]; pos++) {
713     server[pos].used = 1;
714     server[pos].name = m_strdup (server_list[pos]);
715     server[pos].proto = proto_from_URL (server_list[pos]);
716     }
717 twoaday 273 no_config = 1;
718 werner 36 }
719 twoaday 270 read_proxy_config (&proxy);
720 werner 36 if (user && pass)
721 twoaday 180 update_proxy_user (user, pass);
722 werner 36 else if (user && !pass || !user && pass) {
723 twoaday 248 msg_box (NULL, _("Invalid proxy configuration. "
724 twoaday 231 "You need to set a user and a password "
725 twoaday 147 "to use proxy authentication!"),
726     _("Proxy Error"), MB_ERR);
727 werner 36 }
728     /* check if the host has a http:// prefix and skip it */
729 twoaday 147 if (proxy.host && !strncmp (proxy.host, "http://", 7)) {
730 twoaday 119 char *host = m_strdup (proxy.host+7);
731 werner 36 free_if_alloc (proxy.host);
732 twoaday 119 proxy.host = host;
733 werner 36 }
734     free_if_alloc (user);
735     free_if_alloc (pass);
736    
737     pos = 0;
738 twoaday 147 while (fp && !feof (fp)) {
739 twoaday 271 s = fgets (buf, DIM (buf)-1, fp);
740 werner 36 if (!s)
741     break;
742     if (strstr (buf, "\r\n"))
743     buf[strlen (buf)-2] = '\0';
744     if (strstr (buf, "\n"))
745     buf[strlen (buf)-1] = '\0';
746     s = (char *)skip_whitespace (buf);
747     if (*s == '#' || strlen (s) < 7)
748     continue;
749 twoaday 222 chk_pos = check_URL (s);
750     if (!chk_pos) {
751 werner 36 msg_box (NULL, _("All entries of this file must have a valid prefix.\n"
752     "Currently HKP/HTTP, LDAP and FINGER are supported.\n"),
753     _("Keyserver Error"), MB_ERR);
754     continue;
755     }
756     p = strchr (s+chk_pos, ':');
757     server[pos].used = 1;
758     server[pos].proto = proto_from_URL (s);
759     server[pos].port = port_from_proto (server[pos].proto);
760     if (!p)
761     server[pos].name = m_strdup (s);
762     else {
763     server[pos].port = atol (p+1);
764     if (server[pos].port < 0 || server[pos].port > 65536)
765     server[pos].port = HKP_PORT;
766 twoaday 214 server[pos].name = safe_alloc ((p-s)+2);
767 werner 36 memset (server[pos].name, 0, (p-s)+2);
768     memcpy (server[pos].name, s, (p-s));
769     }
770     pos++;
771 twoaday 147 if (pos > MAX_KEYSERVERS) {
772     msg_box (NULL, _("The keyserver limit is exceeded"),
773     _("Keyserver Warning"), MB_INFO);
774 werner 36 break;
775     }
776     }
777     if (fp)
778     fclose (fp);
779 twoaday 73 if (!pos) {
780 twoaday 273 /* Only issue an error if the config file exist but
781 twoaday 180 it has no valid entries. */
782 werner 36 keyserver_set_default (NULL, HKP_PORT);
783     if (!no_config)
784 twoaday 147 return WPTERR_CONFIG_FILE;
785 werner 36 }
786    
787     return 0;
788 twoaday 147 }
789 werner 36
790    
791 twoaday 119 /* Connect to the keyserver @hostname (port @port).
792     Return value: 0 on success */
793 werner 36 int
794 twoaday 119 kserver_connect (const char *hostname, WORD port, int *conn_fd)
795 twoaday 197 {
796 werner 36 struct hostent *hp;
797     struct sockaddr_in sock;
798 twoaday 197 char host[128] = {0};
799     DWORD iaddr;
800 twoaday 271 bool use_proxy = proxy.host != NULL;
801 twoaday 197 int rc, fd;
802 werner 36
803     if (!port)
804     port = HKP_PORT;
805     if (conn_fd)
806     *conn_fd = 0;
807     hostname = skip_type_prefix (hostname);
808 twoaday 271 log_debug ("kserver_connect: %s:%d\r\n", hostname, port);
809 werner 36
810 twoaday 271 if (use_proxy && proxy.proto == PROXY_PROTO_HTTP)
811 twoaday 197 port = proxy.port;
812 werner 36 memset (&sock, 0, sizeof (sock));
813     sock.sin_family = AF_INET;
814 twoaday 197 sock.sin_port = htons (port);
815 twoaday 273 strncpy (host, use_proxy? proxy.host : hostname, DIM (host)-1);
816 twoaday 197
817 werner 36 if ((iaddr = inet_addr (host)) != INADDR_NONE)
818     memcpy (&sock.sin_addr, &iaddr, sizeof (iaddr));
819     else if ((hp = gethostbyname (host))) {
820     if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
821     log_debug ("gethostbyname: unknown address type.\r\n");
822     return WPTERR_WINSOCK_RESOLVE;
823     }
824     memcpy (&sock.sin_addr, hp->h_addr, hp->h_length);
825     }
826     else {
827 twoaday 119 log_debug ("gethostbyname: failed ec=%d.\r\n", net_errno);
828 twoaday 271 return use_proxy? WPTERR_WINSOCK_PROXY : WPTERR_WINSOCK_RESOLVE;
829 werner 36 }
830     fd = socket (AF_INET, SOCK_STREAM, 0);
831     if (fd == INVALID_SOCKET)
832     return WPTERR_WINSOCK_SOCKET;
833     rc = connect (fd, (struct sockaddr *) &sock, sizeof (sock));
834     if (rc == SOCKET_ERROR) {
835 twoaday 119 log_debug ("connect: failed ec=%d.\r\n", net_errno);
836 werner 36 closesocket (fd);
837 twoaday 271 return use_proxy? WPTERR_WINSOCK_PROXY : WPTERR_WINSOCK_CONNECT;
838 werner 36 }
839    
840 twoaday 185 if (proxy.proto == PROXY_PROTO_SOCKS5) {
841 twoaday 271 /* XXX: finish code and provide errors constants. */
842 twoaday 180 rc = socks_handshake (&proxy, fd, hostname, port);
843     if (rc) {
844     closesocket (fd);
845 twoaday 271 return WPTERR_GENERAL;
846 twoaday 180 }
847     }
848    
849 werner 36 if (conn_fd)
850     *conn_fd = fd;
851     WSASetLastError (0);
852     return 0;
853 twoaday 119 }
854 werner 36
855    
856 twoaday 222 /* Check if the URL needs to be encoded or not. */
857 twoaday 144 static bool
858     URL_must_encoded (const char *url)
859     {
860     if (strchr (url, '.') || strchr (url, '@') || strchr (url, ' '))
861     return true;
862     return false;
863     }
864    
865    
866     /* Perform URL encoding of the given data. */
867 werner 36 static char*
868 twoaday 214 URL_encode (const char *url, DWORD ulen, DWORD *ret_nlen)
869 werner 36 {
870 twoaday 144 gpgme_data_t hd;
871 twoaday 209 char numbuf[5], *p;
872 twoaday 273 size_t i, nlen;
873 werner 36
874 twoaday 209 if (gpgme_data_new (&hd))
875     BUG (0);
876 twoaday 144 for (i=0; i < ulen; i++) {
877     if (isalnum (url[i]) || url[i] == '-')
878     gpg_data_putc (hd, url[i]);
879     else if (url[i] == ' ')
880     gpg_data_putc (hd, '+');
881 werner 36 else {
882 twoaday 144 sprintf (numbuf, "%%%02X", url[i]);
883     gpgme_data_write (hd, numbuf, strlen (numbuf));
884 werner 36 }
885     }
886 twoaday 144
887 twoaday 209 p = data_release_and_get_mem (hd, &nlen);
888 twoaday 144 if (ret_nlen)
889 twoaday 209 *ret_nlen = nlen;
890 werner 36 return p;
891     }
892    
893    
894     /* Format a request for the given keyid (send). */
895     static char*
896 twoaday 119 kserver_send_request (const char *hostname, WORD port,
897 twoaday 214 const char *pubkey, DWORD octets)
898 werner 36 {
899 twoaday 214 const char *fmt;
900     char *request;
901     char *enc_pubkey;
902     DWORD enc_octets;
903 werner 36 int reqlen;
904    
905 twoaday 119 log_debug ("kserver_send_request: %s:%d\r\n", hostname, port);
906 werner 36
907     if (!port)
908     port = HKP_PORT;
909 twoaday 144 enc_pubkey = URL_encode (pubkey, octets, &enc_octets);
910 twoaday 214 reqlen = 2*strlen (hostname) + 2*32/*port*/ + enc_octets + 32 /*len*/ + 1;
911 werner 36
912 twoaday 180 if (proxy.user && proxy.proto == PROXY_PROTO_HTTP) {
913 twoaday 214 fmt = "POST http://%s:%d/pks/add HTTP/1.0\r\n"
914     "Referer: \r\n"
915     "User-Agent: WinPT/W32\r\n"
916     "Host: %s:%d\r\n"
917     "Proxy-Authorization: Basic %s\r\n"
918     "Content-type: application/x-www-form-urlencoded\r\n"
919     "Content-length: %d\r\n"
920     "\r\n"
921     "keytext=%s"
922     "\r\n";
923     reqlen += strlen (fmt) + strlen (proxy.base64_user) + 1;
924     request = safe_alloc (reqlen+1);
925     _snprintf (request, reqlen, fmt,
926     skip_type_prefix (hostname), port, hostname, port,
927 werner 36 proxy.base64_user, enc_octets+9, enc_pubkey);
928     }
929     else {
930 twoaday 214 fmt = "POST /pks/add HTTP/1.0\r\n"
931     "Referer: \r\n"
932     "User-Agent: WinPT/W32\r\n"
933     "Host: %s:%d\r\n"
934     "Content-type: application/x-www-form-urlencoded\r\n"
935     "Content-length: %d\r\n"
936     "\r\n"
937     "keytext=%s"
938     "\r\n";
939     reqlen += strlen (fmt)+1;
940     request = safe_alloc (reqlen+1);
941     _snprintf (request, reqlen, fmt,
942     skip_type_prefix (hostname), port,
943 twoaday 119 enc_octets+9, enc_pubkey);
944 werner 36 }
945 twoaday 214
946 werner 36 free_if_alloc (enc_pubkey);
947 twoaday 220 log_debug ("request:\r\n%s\r\n", request);
948 werner 36 return request;
949 twoaday 119 }
950 werner 36
951    
952 twoaday 209 /* Interface for receiving a public key. */
953 werner 36 int
954 twoaday 209 kserver_recvkey (const char *hostname, WORD port, const char *keyid,
955 twoaday 273 char **r_key, size_t *r_keylen)
956 twoaday 119 {
957 twoaday 288 StringBuffer req;
958     const char *reqbuf;
959 twoaday 119 int conn_fd;
960 twoaday 288 int rc;
961 twoaday 119
962 werner 36 if (!port)
963     port = HKP_PORT;
964 twoaday 214 hkp_err = 0; /* reset */
965 werner 36 rc = kserver_connect (hostname, port, &conn_fd);
966     if (rc)
967     goto leave;
968 twoaday 214
969 twoaday 180 if (proxy.host && proxy.user && proxy.proto == PROXY_PROTO_HTTP) {
970 twoaday 288 req = req + "GET http://" + skip_type_prefix (hostname) +
971     ":" + port +
972     "/pks/lookup?op=get&search=" + keyid + " HTTP/1.0\r\n" +
973     "Proxy-Authorization: Basic " + proxy.base64_user + "\r\n\r\n";
974 werner 36 }
975 twoaday 180 else if (proxy.host && proxy.proto == PROXY_PROTO_HTTP) {
976 twoaday 288 req = req + "GET http://" + skip_type_prefix (hostname) +
977     ":" + port + "/pks/lookup?op=get&search=" + keyid +
978     " HTTP/1.0\r\n\r\n";
979 twoaday 214 }
980 twoaday 288 else
981     req = req + "GET /pks/lookup?op=get&search=" + keyid +
982     " HTTP/1.0\r\n\r\n";
983    
984     log_debug ("req:\r\n%s\r\n", req.getBuffer ());
985 werner 36
986 twoaday 288 reqbuf = req.getBuffer ();
987     rc = sock_write (conn_fd, reqbuf, strlen (reqbuf));
988 werner 36 if (rc == SOCKET_ERROR) {
989     rc = WPTERR_WINSOCK_RECVKEY;
990     goto leave;
991     }
992    
993 twoaday 209 rc = sock_read_ext (conn_fd, r_key, r_keylen);
994 twoaday 147 if (rc == SOCKET_ERROR) {
995 werner 36 rc = WPTERR_WINSOCK_RECVKEY;
996     goto leave;
997     }
998    
999 twoaday 220 log_debug ("response:\r\n%s\r\n", *r_key);
1000 twoaday 147 rc = check_hkp_response (*r_key, 1);
1001 werner 36 if (rc)
1002     goto leave;
1003    
1004     WSASetLastError (0);
1005    
1006     leave:
1007     closesocket (conn_fd);
1008     return rc;
1009 twoaday 119 }
1010 werner 36
1011    
1012     /* Interface to send a public key. */
1013     int
1014 twoaday 273 kserver_sendkey (const char *hostname, WORD port,
1015     const char *pubkey, size_t len)
1016 werner 36 {
1017     char *request = NULL;
1018 twoaday 195 char log[2048] = {0};
1019 twoaday 119 int conn_fd, n;
1020     int rc;
1021 werner 36
1022     hkp_err = 0; /* reset */
1023     rc = kserver_connect (hostname, port, &conn_fd);
1024     if (rc)
1025     goto leave;
1026    
1027     request = kserver_send_request (hostname, port, pubkey, len);
1028 twoaday 119 rc = sock_write (conn_fd, request, strlen (request));
1029     if (rc == SOCKET_ERROR) {
1030 werner 36 rc = WPTERR_WINSOCK_SENDKEY;
1031     goto leave;
1032     }
1033    
1034 twoaday 271 rc = sock_read (conn_fd, log, DIM (log)-1, &n);
1035 twoaday 119 if (rc == SOCKET_ERROR) {
1036 werner 36 rc = WPTERR_WINSOCK_SENDKEY;
1037     goto leave;
1038     }
1039    
1040 twoaday 195 log_debug ("kserver_sendkey: read %d bytes\r\n%s\r\n", n, log);
1041 werner 36 rc = check_hkp_response (log, 0);
1042 twoaday 119 if (rc)
1043 werner 36 goto leave;
1044    
1045     WSASetLastError (0);
1046 twoaday 273
1047 werner 36 leave:
1048     closesocket (conn_fd);
1049     free_if_alloc (request);
1050     return rc;
1051 twoaday 119 }
1052 werner 36
1053    
1054 twoaday 185 /* Check keyserver response. */
1055     static int
1056     kserver_search_chkresp (int fd)
1057     {
1058     char buf[128];
1059     int n=0;
1060    
1061     /* parse response 'HTTP/1.0 500 OK' */
1062 twoaday 271 if (sock_getline (fd, buf, DIM (buf)-1, &n))
1063 twoaday 185 return WPTERR_KEYSERVER_NOTFOUND;
1064    
1065     log_debug ("kserver_search_chkpresp: %s\r\n", buf);
1066     if (strncmp (buf, "HTTP/1.", 7))
1067     return WPTERR_KEYSERVER_NOTFOUND;
1068     if (strncmp (buf+(8+1), "200", 3))
1069     return WPTERR_KEYSERVER_NOTFOUND;
1070     return 0;
1071     }
1072    
1073    
1074     /* End the keyserver search procedure. */
1075     void
1076     kserver_search_end (int conn_fd)
1077     {
1078     log_debug ("kserver_search_end: fd=%d\r\n", conn_fd);
1079     closesocket (conn_fd);
1080     }
1081    
1082    
1083 twoaday 214 /* Extract the amount of keys from the info record. */
1084 twoaday 273 static size_t
1085 twoaday 214 count_keys_in_response (char *buf)
1086     {
1087     char *p;
1088     int recno = 0;
1089 twoaday 273 size_t n = 0;
1090 twoaday 214
1091     /* info:1:4 */
1092     if (strncmp (buf, "info", 4))
1093     return 0;
1094     p = strtok (buf, ":");
1095     while (p != NULL) {
1096     recno++;
1097     if (recno == 3)
1098     n = atoi (p);
1099     p = strtok (NULL, ":");
1100     }
1101     return n;
1102     }
1103    
1104    
1105     /* Start the keyserver search.
1106     Connect to host @hostname and port @port.
1107     The pattern are given in @pattern.
1108     The socket is returned in @conn_fd and @nkeys contains
1109     the amount of keys which were found. */
1110 werner 36 int
1111 twoaday 185 kserver_search_begin (const char *hostname, WORD port,
1112 twoaday 273 const char *pattern, int *conn_fd, size_t *nkeys)
1113 werner 36 {
1114 twoaday 288
1115     StringBuffer req;
1116     const char *reqbuf;
1117 twoaday 185 char *enc_patt = NULL;
1118 twoaday 214 char status[128];
1119 werner 36 int rc, sock_fd;
1120 twoaday 288 int nread;
1121 twoaday 144
1122 twoaday 214 *conn_fd = 0;
1123    
1124 werner 36 rc = kserver_connect (hostname, port, &sock_fd);
1125 twoaday 214 if (rc)
1126 werner 36 goto leave;
1127 twoaday 144
1128 twoaday 185 enc_patt = URL_encode (pattern, strlen (pattern), NULL);
1129 twoaday 180 if (proxy.host && proxy.user && proxy.proto == PROXY_PROTO_HTTP) {
1130 twoaday 288 req = req + "GET http://" + skip_type_prefix (hostname) + ":" + port +
1131     "/pks/lookup?options=mr&op=index&search=" + enc_patt +
1132     " HTTP/1.0\r\n"
1133     "Proxy-Authorization: Basic " + proxy.base64_user + "\r\n\r\n";
1134 werner 36 }
1135 twoaday 180 else if (proxy.host && proxy.proto == PROXY_PROTO_HTTP) {
1136 twoaday 288 req = req + "GET http://" + skip_type_prefix (hostname) + ":" + port +
1137     "/pks/lookup?options=mr&op=index&search=" + enc_patt +
1138     " HTTP/1.0\r\n\r\n";
1139 werner 36 }
1140     else {
1141 twoaday 288 req = req + "GET /pks/lookup?options=mr&op=index&search=" +
1142     enc_patt + " HTTP/1.0\r\n\r\n";
1143 werner 36 }
1144 twoaday 288
1145     log_debug ("kserver_search_begin:\r\n%s\r\n", req.getBuffer ());
1146     reqbuf = req.getBuffer ();
1147     if (sock_write (sock_fd, reqbuf, strlen (reqbuf)) == SOCKET_ERROR) {
1148 werner 36 rc = WPTERR_GENERAL;
1149     goto leave;
1150     }
1151    
1152 twoaday 185 rc = kserver_search_chkresp (sock_fd);
1153     if (rc) {
1154     closesocket (sock_fd);
1155     sock_fd = 0;
1156 twoaday 214 goto leave;
1157 twoaday 185 }
1158    
1159 twoaday 214 /* Skip all lines until we reach the "info:" record. */
1160     for (;;) {
1161 twoaday 288 if (sock_getline (sock_fd, status, DIM (status)-1, &nread)) {
1162 twoaday 214 log_debug ("kserver_search_begin: retrieving status line failed.\r\n");
1163     closesocket (sock_fd);
1164     sock_fd = 0;
1165     rc = WPTERR_GENERAL;
1166     break;
1167     }
1168     if (!strncmp (status, "info:", 5))
1169     break;
1170     }
1171    
1172     if (!rc)
1173     *nkeys = count_keys_in_response (status);
1174 werner 36 *conn_fd = sock_fd;
1175    
1176     leave:
1177 twoaday 185 free_if_alloc (enc_patt);
1178 werner 36 return rc;
1179 twoaday 119 }
1180 werner 36
1181    
1182 twoaday 214 /* Parse a single pub record returned by the keyserver. */
1183     static void
1184     parse_pub_record (keyserver_key_s *key, char *buf)
1185     {
1186     enum pub_rec_t {ID=1, KEYID, ALGO, SIZE, CREATE, EXPIRE};
1187     char *p;
1188     int recno = 0;
1189 twoaday 271 int off = 0;
1190 werner 36
1191 twoaday 290 /* pub:{BF3DF9B4, ED4681C9BF3DF9B4, FPR}:17:1024:925411133:: */
1192 twoaday 214 p = strtok (buf, ":");
1193     while (p != NULL) {
1194     recno++;
1195     switch (recno) {
1196     case ID:
1197     break;
1198 werner 36
1199 twoaday 271 case KEYID:
1200     /* If for any reason the returned record actually contains
1201     a fingerprint instead of a key ID, we truncate the fpr. */
1202     off = strlen (p) == 40? 32 : 0;
1203 twoaday 214 free_if_alloc (key->keyid);
1204 twoaday 271 key->keyid = m_strdup (p+off);
1205 twoaday 214 break;
1206    
1207     case ALGO:
1208     key->algo = atoi (p);
1209     break;
1210    
1211     case SIZE:
1212     key->bits = atoi (p);
1213     break;
1214    
1215     case CREATE:
1216     key->creation = strtoul (p, NULL, 10);
1217     break;
1218    
1219     case EXPIRE:
1220     key->expires = strtoul (p, NULL, 10);
1221     break;
1222     }
1223     p = strtok (NULL, ":");
1224     }
1225     }
1226    
1227    
1228     /* Parse a single user id returned by the keyserver. */
1229     static void
1230     parse_uid_record (keyserver_key_s *key, char *buf)
1231 twoaday 144 {
1232 twoaday 214 enum uid_rec_t {ID=1, UID, CREATE, EXPIRE};
1233     keyserver_uid_s *u, *n;
1234 twoaday 225 char *p, *raw;
1235 twoaday 214 int recno = 0;
1236 twoaday 144
1237 twoaday 214 /* uid:Timo Schulz <[email protected]>:1138440360:: */
1238     u = new keyserver_uid_s;
1239     memset (u, 0, sizeof *u);
1240    
1241     p = strtok (buf, ":");
1242 twoaday 144 while (p != NULL) {
1243 twoaday 214 recno++;
1244    
1245     switch (recno) {
1246     case ID:
1247     break;
1248    
1249     case UID:
1250 twoaday 225 unhexify_buffer (p, &raw);
1251     u->uid = utf8_to_native (raw);
1252     free_if_alloc (raw);
1253 twoaday 214 break;
1254    
1255     case CREATE:
1256     u->creation = strtoul (p, NULL, 10);
1257     break;
1258    
1259     case EXPIRE:
1260     u->expires = strtoul (p, NULL, 10);
1261     break;
1262 twoaday 144 }
1263 twoaday 214
1264     p = strtok (NULL, ":");
1265 twoaday 144 }
1266 twoaday 214 if (!key->uids)
1267     key->uids = u;
1268     else {
1269     for (n = key->uids; n->next; n=n->next)
1270     ;
1271     n->next = u;
1272     }
1273 twoaday 144 }
1274    
1275    
1276 twoaday 214 /* Peek the next 3 bytes to check if the next line
1277     would be a new "pub" record. In this case, return
1278     -1 as an EOF indication, 0 otherwise. */
1279     static int
1280     is_key_eof (int fd)
1281     {
1282     char buf[64];
1283     int n;
1284    
1285     n = recv (fd, buf, 3, MSG_PEEK);
1286     if (n < 3 || strncmp (buf, "pub", 3))
1287     return 0;
1288     return -1;
1289     }
1290    
1291    
1292     /* Return the next key from the search response. */
1293 werner 36 int
1294 twoaday 214 kserver_search_next (int fd, keyserver_key_s **r_key)
1295 werner 36 {
1296 twoaday 214 keyserver_uid_s *uid, *u = NULL;
1297     keyserver_key_s *key;
1298     char buf[512];
1299     int n = 0;
1300     long max = 0;
1301 werner 36
1302 twoaday 185 log_debug ("keyserver_search_next:\r\n");
1303 twoaday 214 *r_key = NULL;
1304 werner 36
1305 twoaday 214 key = new keyserver_key_s;
1306     memset (key, 0, sizeof *key);
1307     for (;;) {
1308 twoaday 271 if (sock_getline (fd, buf, DIM (buf)-1, &n))
1309 twoaday 214 break;
1310 twoaday 220 /*log_debug ("record: '%s'\r\n", buf); */
1311 twoaday 214 if (!strncmp (buf, "pub", 3))
1312     parse_pub_record (key, buf);
1313     else
1314     parse_uid_record (key, buf);
1315     if (is_key_eof (fd))
1316     break;
1317     }
1318 twoaday 144
1319 twoaday 214 /* the uid with the newest self sig is used as the
1320     primary user id. */
1321     for (uid = key->uids; uid; uid = uid->next) {
1322     if (uid->creation > max) {
1323     max = uid->creation;
1324     u = uid;
1325 werner 36 }
1326     }
1327    
1328 twoaday 214 key->main_uid = u? u : key->uids;
1329     *r_key = key;
1330 werner 36 return 0;
1331 twoaday 144 }
1332 werner 36
1333    
1334 twoaday 214 /* Release the keyserver key @key and all its elements. */
1335     void
1336     kserver_release_key (keyserver_key_s *key)
1337     {
1338     keyserver_uid_s *u;
1339    
1340     while (key->uids) {
1341     u = key->uids->next;
1342     free_if_alloc (key->uids->uid);
1343     free_if_alloc (key->uids);
1344     key->uids = u;
1345     }
1346     free_if_alloc (key->keyid);
1347     free_if_alloc (key);
1348     }
1349    
1350    
1351 twoaday 119 /* Release mbmers in the proxy context @ctx. */
1352 werner 36 void
1353 twoaday 180 kserver_proxy_release (keyserver_proxy_t ctx)
1354 werner 36 {
1355 twoaday 119 free_if_alloc (ctx->host);
1356     free_if_alloc (ctx->pass);
1357     free_if_alloc (ctx->user);
1358 twoaday 185 ctx->port = ctx->proto = 0;
1359 twoaday 119 }
1360 werner 36
1361    
1362 twoaday 133 /* Spawn a process given by @cmdl. */
1363     static int
1364     spawn_application (char *cmdl)
1365     {
1366     STARTUPINFO si;
1367     PROCESS_INFORMATION pi;
1368     int rc = 0;
1369    
1370     memset (&si, 0, sizeof (si));
1371     si.cb = sizeof (si);
1372     si.dwFlags = STARTF_USESHOWWINDOW;
1373     si.wShowWindow = SW_HIDE;
1374     memset (&pi, 0, sizeof (pi));
1375    
1376     if (!CreateProcess (NULL, cmdl, NULL, NULL, FALSE, 0,
1377     NULL, NULL, &si, &pi)) {
1378     log_box ("Keyserver Plugin", MB_ERR, "Could not spawn helper process");
1379     rc = -1;
1380     }
1381    
1382     CloseHandle (pi.hThread);
1383     WaitForSingleObject (pi.hProcess, INFINITE);
1384     CloseHandle (pi.hProcess);
1385     return rc;
1386     }
1387    
1388    
1389 twoaday 209 static FILE*
1390     do_spawn_ldap_helper (const char *host, const char *keyid)
1391     {
1392     FILE *fp = NULL;
1393 twoaday 278 StringBuffer cmd;
1394     char *sep, *p, *ksprg;
1395 twoaday 209 char outf[256], inf[256];
1396     size_t n;
1397 werner 36
1398 twoaday 133 p = get_gnupg_prog ();
1399     n = strlen (p) + 1 + 128;
1400 twoaday 214 ksprg = safe_alloc (n+1);
1401 werner 36 if (!ksprg)
1402     BUG (0);
1403 twoaday 133 sep = strrchr (p, '\\');
1404     if (sep != NULL)
1405     p[(sep-p)] = 0;
1406    
1407     _snprintf (ksprg, n, "%s\\gpgkeys_ldap.exe", p);
1408 werner 36 free_if_alloc (p);
1409     if (file_exist_check (ksprg)) {
1410 twoaday 133 log_box ("LDAP Keyserver Plugin", MB_ERR,
1411     "%s: could not find LDAP keyserver module!", ksprg);
1412 twoaday 209 fp = NULL;
1413 werner 36 goto leave;
1414 twoaday 175 }
1415 twoaday 271 get_temp_name (outf, DIM (outf)-1, keyid);
1416     get_temp_name (inf, DIM (inf)-1, NULL);
1417 twoaday 175 fp = fopen (inf, "w+b");
1418     if (!fp) {
1419     log_box ("LDAP Keyserver Plugin", MB_ERR, "%s: %s", inf,
1420 werner 36 winpt_strerror (WPTERR_FILE_OPEN));
1421     goto leave;
1422     }
1423 twoaday 175 fprintf (fp,
1424 twoaday 133 "VERSION 1\n"
1425 twoaday 273 "PROGRAM %d.%d.%d\n"
1426 twoaday 133 "SCHEME ldap\n"
1427 werner 36 "HOST %s\n"
1428     "COMMAND GET\n"
1429     "\n"
1430 twoaday 133 "%s\n",
1431 twoaday 273 gpgver[0], gpgver[1], gpgver[2],
1432 twoaday 133 host? skip_type_prefix (host): "64.94.85.200", keyid);
1433 twoaday 175 fclose (fp);
1434 werner 36
1435 twoaday 278 cmd = ksprg;
1436     cmd = cmd + " -o " + outf + " " + inf;
1437     if (spawn_application ((char*)cmd.getBuffer ())) {
1438 twoaday 209 fp = NULL;
1439 werner 36 goto leave;
1440     }
1441 twoaday 175 fp = fopen (outf, "rb");
1442 twoaday 209 if (!fp)
1443 werner 36 log_box ("LDAP Keyserver Plugin", MB_ERR, "%s: %s", outf,
1444     winpt_strerror (WPTERR_FILE_OPEN));
1445 twoaday 209
1446     leave:
1447     DeleteFile (inf);
1448     DeleteFile (outf);
1449     free_if_alloc (ksprg);
1450     return fp;
1451     }
1452    
1453     /* Receive an key via LDAP from host @host with the keyid @keyid.
1454     @key contains the key on success. */
1455     int
1456     ldap_recvkey (const char *host, const char *keyid,
1457 twoaday 273 char **r_key, size_t *r_keylen)
1458 twoaday 209 {
1459     gpgme_data_t raw;
1460     FILE *fp;
1461     const char *s;
1462     char buf[512];
1463     int start_key = 0, failed = 0;
1464     int rc = 0;
1465    
1466     fp = do_spawn_ldap_helper (host, keyid);
1467     if (!fp)
1468     return WPTERR_GENERAL;
1469    
1470     if (gpgme_data_new (&raw))
1471     BUG (0);
1472 twoaday 175 while (!feof (fp)) {
1473 twoaday 271 s = fgets (buf, DIM (buf)-1, fp);
1474 twoaday 133 if (!s)
1475 werner 36 break;
1476 twoaday 133 if (strstr (s, "KEY") && strstr (s, "FAILED")) {
1477     failed = 1;
1478     break;
1479     }
1480     if (!start_key && strstr (s, "KEY") && strstr (s, "BEGIN")) {
1481 werner 36 start_key = 1;
1482     continue;
1483 twoaday 209 }
1484 twoaday 133 if (!start_key)
1485 werner 36 continue;
1486 twoaday 209 gpgme_data_write (raw, buf, strlen (buf));
1487     if (strstr (s, "KEY") && strstr (s, "END"))
1488 werner 36 break;
1489     }
1490 twoaday 175 fclose (fp);
1491 werner 36
1492 twoaday 209 if (failed)
1493 werner 36 rc = WPTERR_WINSOCK_RECVKEY;
1494 twoaday 209 *r_key = data_release_and_get_mem (raw, r_keylen);
1495 werner 36 return rc;
1496 twoaday 119 }
1497 werner 36
1498    
1499 twoaday 119 /* Receive an key via FINGER from host @host with the user @user.
1500     On success @key contains the key. */
1501 werner 36 int
1502 twoaday 209 finger_recvkey (const char *host, const char *user,
1503 twoaday 273 char **r_key, size_t *r_keylen)
1504 werner 36 {
1505 twoaday 209 gpgme_data_t raw;
1506 twoaday 271 char buf[256+1];
1507 werner 36 int fd, nread;
1508     int start_key = 0;
1509     int rc=0;
1510    
1511 twoaday 180 rc = kserver_connect (host, FINGER_PORT, &fd);
1512     if (rc)
1513     return rc;
1514 werner 36
1515 twoaday 180 sock_write (fd, user, strlen (user));
1516     sock_write (fd, "\r\n", 2);
1517 werner 36
1518 twoaday 209 if (gpgme_data_new (&raw))
1519 twoaday 273 return WPTERR_WINSOCK_RECVKEY;
1520 twoaday 209
1521     for (;;) {
1522 twoaday 278 if (sock_getline (fd, buf, DIM (buf)-1, &nread))
1523 twoaday 180 break;
1524 werner 36 strcat (buf, "\n");
1525     if (strstr (buf, "BEGIN PGP PUBLIC KEY BLOCK")) {
1526 twoaday 209 gpgme_data_write (raw, buf, nread);
1527 werner 36 start_key = 1;
1528     }
1529     else if (strstr (buf, "END PGP PUBLIC KEY BLOCK" ) && start_key) {
1530 twoaday 209 gpgme_data_write (raw, buf, nread);
1531 werner 36 start_key--;
1532     break;
1533     }
1534 twoaday 209 else if (start_key)
1535     gpgme_data_write (raw, buf, nread);
1536 werner 36 }
1537 twoaday 209
1538 werner 36 closesocket (fd);
1539     if (start_key != 0)
1540     rc = WPTERR_WINSOCK_RECVKEY;
1541 twoaday 209 *r_key = data_release_and_get_mem (raw, r_keylen);
1542 werner 36 return rc;
1543     }
1544    
1545    
1546 twoaday 273 /* Check if the given name @name is a valid inernet address
1547     which means an dotted IP or a valid DNS name.
1548     Return value: 0 on success. */
1549 werner 36 int
1550 twoaday 273 check_inet_address (const char *addr)
1551 werner 36 {
1552     const char *not_allowed = "=!ยง$%&@#*~\\/}][{<>|,;:'";
1553 twoaday 273 size_t i;
1554 werner 36
1555 twoaday 273 for (i=0; i < strlen (addr); i++) {
1556     if (strchr (not_allowed, addr[i]))
1557     return -1;
1558 werner 36 }
1559     return 0;
1560     }
1561 twoaday 214
1562    
1563     /* Split the URL @r_keyserver into the host and the port
1564     part if possible. */
1565     gpgme_error_t
1566     parse_keyserver_url (char **r_keyserver, unsigned short *r_port)
1567     {
1568     char *p;
1569     char *url = *r_keyserver;
1570 twoaday 226 int off = 0;
1571 twoaday 214
1572     /* no port is given so use the default port. */
1573     p = strrchr (url, ':');
1574     if (p == strchr (url, ':')) {
1575     int port = port_from_proto (proto_from_URL (url));
1576     if (!port)
1577     port = HKP_PORT;
1578     *r_port = port;
1579     return 0;
1580     }
1581 twoaday 226
1582     if (url[(p-url)-1] == '/') /* remove / in .de/:11371 */
1583     off = 1;
1584    
1585     *r_keyserver = substr (url, 0, (p-url)-off);
1586 twoaday 214 *r_port = atoi (url+(p-url)+1);
1587 twoaday 220 free_if_alloc (url);
1588 twoaday 214 return 0;
1589     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26