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

Diff of /trunk/Src/wptKeyserver.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.32  
changed lines
  Added in v.400

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26