1 #define TCP_BODY
2 
3 #include "basictcp.h"
4 
5 #include <sys/socket.h>
6 #include <unistd.h>
7 #include <arpa/inet.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 #include <stdarg.h>
11 #include "postal.h"
12 #include "userlist.h"
13 #include "address.h"
14 #include "logit.h"
15 #include "results.h"
16 
17 #ifdef USE_GNUTLS
18 int base_tcp::m_init_dh_params = 0;
19 gnutls_dh_params_t base_tcp::m_dh_params;
20 #endif
21 
base_tcp(int fd,Logit * log,Logit * debug,results * res,int ssl)22 base_tcp::base_tcp(int fd, Logit *log, Logit *debug, results *res
23 #ifdef USE_SSL
24        , int ssl
25 #endif
26       ) :
27 #ifdef USE_SSL
28    m_canTLS(false),
29    m_useTLS(ssl),
30 #endif
31    m_sock(fd)
32  , m_start(0)
33  , m_end(0)
34  , m_open(true)
35  , m_log(log)
36  , m_debug(debug)
37  , m_res(res)
38 #ifdef USE_SSL
39 #ifdef USE_OPENSSL
40  , m_sslMeth(NULL)
41  , m_sslCtx(NULL)
42  , m_ssl(NULL)
43 #else
44  , m_gnutls_session(NULL)
45 #endif
46  , m_isTLS(false)
47 #endif
48 {
49   m_poll.fd = m_sock;
50 #ifdef USE_SSL
51   if(m_useTLS)
52   {
53 #ifdef USE_OPENSSL
54 //don't seem to need this    SSL_library_init();
55     SSLeay_add_ssl_algorithms();
56     SSL_load_error_strings();
57 #endif
58   }
59 #endif
60 }
61 
~base_tcp()62 base_tcp::~base_tcp()
63 {
64 }
65 
66 #ifdef USE_SSL
67 
68 #ifdef USE_GNUTLS
69 #define DH_BITS 1024
70 
m_initialize_tls_session()71 void base_tcp::m_initialize_tls_session()
72 {
73   gnutls_init(&m_gnutls_session, GNUTLS_SERVER);
74 
75   /* avoid calling all the priority functions, since the defaults
76    * are adequate.
77    */
78   gnutls_set_default_priority(m_gnutls_session);
79   // Need to enable anonymous specifically
80   gnutls_priority_set_direct(m_gnutls_session, "NORMAL:+ANON-DH", NULL);
81 
82   gnutls_credentials_set(m_gnutls_session, GNUTLS_CRD_ANON, m_anoncred);
83 
84   gnutls_dh_set_prime_bits(m_gnutls_session, DH_BITS);
85 }
86 
m_generate_dh_params()87 void base_tcp::m_generate_dh_params()
88 {
89   /* Generate Diffie Hellman parameters - for use with DHE
90    * kx algorithms. These should be discarded and regenerated
91    * once a day, once a week or once a month. Depending on the
92    * security requirements.
93    */
94   gnutls_dh_params_init(&m_dh_params);
95   gnutls_dh_params_generate2(m_dh_params, DH_BITS);
96 }
97 #endif // USE_GNUTLS
98 
ConnectTLS()99 int base_tcp::ConnectTLS()
100 {
101 #ifdef USE_OPENSSL
102   m_sslMeth = NULL;
103   m_sslCtx = NULL;
104   m_ssl = NULL;
105 #ifndef OPENSSL_NO_SSL3
106   m_sslMeth = SSLv3_client_method();
107 #else
108   m_sslMeth = SSLv23_client_method();
109 #endif
110   if(m_sslMeth == NULL)
111   {
112 #ifndef OPENSSL_NO_SSL3
113     fprintf(stderr, "Can't get SSLv3_client_method.\n");
114 #else
115     fprintf(stderr, "Can't get SSLv23_client_method.\n");
116 #endif
117     return 2;
118   }
119   m_sslCtx = SSL_CTX_new(m_sslMeth);
120   if(m_sslCtx == NULL)
121   {
122     fprintf(stderr, "Can't SSL_CTX_new\n");
123     return 2;
124   }
125   if((m_ssl = SSL_new(m_sslCtx)) == NULL)
126   {
127     fprintf(stderr, "Can't SSL_new\n");
128     SSL_CTX_free(m_sslCtx);
129     return 2;
130   }
131   SSL_set_fd(m_ssl, m_sock);
132   if(-1 == SSL_connect(m_ssl))
133   {
134     fprintf(stderr, "Can't SSL_CONNECT\n");
135     SSL_free(m_ssl);
136     SSL_CTX_free(m_sslCtx);
137     return 1;
138   }
139   m_isTLS = true;
140 
141 // debugging code that may be useful to have around in a commented-out state.
142 #if 0
143   /* Following two steps are optional and not required for
144      data exchange to be successful. */
145 
146   /* Get the cipher - opt */
147 
148   printf ("SSL connection using %s\n", SSL_get_cipher(m_ssl));
149 
150   /* Get server's certificate (note: beware of dynamic allocation) - opt */
151 
152   X509 *server_cert;
153   server_cert = SSL_get_peer_certificate(m_ssl);
154   if(!server_cert)
155   {
156     fprintf(stderr, "Can't SSL_get_peer_certificate\n");
157     return 2;
158   }
159   printf ("Server certificate:\n");
160 
161   char *str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0);
162   if(!str)
163   {
164     fprintf(stderr, "Can't X509_NAME_oneline\n");
165     return 2;
166   }
167   printf ("\t subject: %s\n", str);
168   Free (str);
169   str = X509_NAME_oneline (X509_get_issuer_name(server_cert),0,0);
170   if(!str)
171   {
172     fprintf(stderr, "Can't X509_get_issuer_name\n");
173     return 2;
174   }
175   printf ("\t issuer: %s\n", str);
176   Free (str);
177 
178   /* We could do all sorts of certificate verification stuff here before
179      deallocating the certificate. */
180 
181   X509_free(server_cert);
182 #endif  // 0
183 #else
184 
185   gnutls_anon_allocate_server_credentials(&m_anoncred);
186   m_initialize_tls_session();
187 
188   if(!m_init_dh_params)
189   {
190     m_init_dh_params = 1;
191     m_generate_dh_params();
192   }
193 
194   gnutls_anon_set_server_dh_params(m_anoncred, m_dh_params);
195 
196   gnutls_transport_set_ptr(m_gnutls_session, (gnutls_transport_ptr_t)m_sock);
197   int rc = gnutls_handshake(m_gnutls_session);
198   if(rc < 0)
199   {
200     gnutls_deinit(m_gnutls_session);
201     return 2;
202   }
203   m_isTLS = 1;
204 
205   /* request client certificate if any.
206    */
207   gnutls_certificate_server_set_request(m_gnutls_session, GNUTLS_CERT_REQUEST);
208 
209 #endif // USE_OPENSSL
210   return 0;
211 }
212 #endif // USE_SSL
213 
disconnect()214 int base_tcp::disconnect()
215 {
216   if(m_open)
217   {
218 #ifdef USE_SSL
219     if(m_isTLS)
220     {
221 #ifdef USE_OPENSSL
222       SSL_shutdown(m_ssl);
223       close(m_sock);
224       SSL_free(m_ssl);
225       SSL_CTX_free(m_sslCtx);
226       m_isTLS = false;
227 #else
228 #endif
229     }
230     else
231 #endif
232     {
233       close(m_sock);
234     }
235   }
236   m_open = false;
237   return 0;
238 }
239 
printf(CPCCHAR fmt,...)240 ERROR_TYPE base_tcp::printf(CPCCHAR fmt, ...)
241 {
242   va_list argp;
243   va_start(argp, fmt);
244   char buf[1024];
245   int len = vsnprintf(buf, sizeof(buf), fmt, argp);
246   if(len > (int)sizeof(buf))
247     len = sizeof(buf);
248   return sendData(buf, len);
249 }
250 
sendData(CPCCHAR buf,int size)251 ERROR_TYPE base_tcp::sendData(CPCCHAR buf, int size)
252 {
253   if(!m_open)
254     return eCorrupt;
255   int sent = 0;
256   m_poll.events = POLLOUT | POLLERR | POLLHUP;
257   int rc;
258   while(sent != size)
259   {
260     rc = poll(&m_poll, 1, 60000);
261     if(rc == 0)
262     {
263       fprintf(stderr, "Server timed out on write.\n");
264       return eTimeout;
265     }
266     if(rc < 0)
267     {
268       fprintf(stderr, "Poll error.\n");
269       return eSocket;
270     }
271 #ifdef USE_SSL
272     if(m_isTLS)
273     {
274 #ifdef USE_OPENSSL
275       rc = SSL_write(m_ssl, &buf[sent], size - sent);
276 #else
277       rc = gnutls_record_send(m_gnutls_session, &buf[sent], size - sent);
278 #endif
279     }
280     else
281 #endif
282     {
283       rc = write(m_sock, &buf[sent], size - sent);
284     }
285     if(rc < 1)
286     {
287 //      fprintf(stderr, "Can't write to socket.\n");
288       return eSocket;
289     }
290     if(m_debug)
291       m_debug->Write(buf, rc);
292     sent += rc;
293   }
294   sentData(size);
295   return eNoError;
296 }
297 
readLine(char * buf,int bufSize,bool stripCR,int timeout)298 int base_tcp::readLine(char *buf, int bufSize, bool stripCR, int timeout)
299 {
300   if(!m_open)
301     return eCorrupt;
302   int ind = 0;
303   if(m_start < m_end)
304   {
305     do
306     {
307       buf[ind] = m_buf[m_start];
308       ind++;
309       m_start++;
310     }
311     while(m_start < m_end && m_buf[m_start - 1] != '\n' && ind < bufSize);
312   }
313   if(ind == bufSize || (ind > 0 && buf[ind - 1] == '\n') )
314   {
315     receivedData(ind);
316     if(m_debug)
317       m_debug->Write(buf, ind);
318     if(ind < bufSize)
319     {
320       ind--;
321       buf[ind] = '\0';
322       if(stripCR && buf[ind - 1] == '\r')
323       {
324         ind--;
325         buf[ind] = '\0';
326       }
327     }
328     return ind;
329   }
330   // buffer is empty
331   m_start = 0;
332   m_end = 0;
333 
334   time_t now = time(NULL);
335   m_poll.events = POLLIN | POLLERR | POLLHUP;
336   while(1)
337   {
338     int tmo = timeout - (time(NULL) - now);
339     int rc;
340     if(tmo < 0 || (rc = poll(&m_poll, 1, tmo * 1000)) == 0)
341     {
342       return eTimeout;
343     }
344     if(rc < 0)
345     {
346       fprintf(stderr, "Poll error.\n");
347       return eCorrupt;
348     }
349 #ifdef USE_SSL
350     if(m_isTLS)
351     {
352 #ifdef USE_OPENSSL
353       rc = SSL_read(m_ssl, m_buf, sizeof(m_buf));
354 #else
355       rc = gnutls_record_recv(m_gnutls_session, m_buf, sizeof(m_buf));
356 #endif
357     }
358     else
359 #endif
360     {
361       rc = read(m_sock, m_buf, sizeof(m_buf));
362     }
363     if(rc < 0)
364       return eSocket;
365     m_end = rc;
366     do
367     {
368       buf[ind] = m_buf[m_start];
369       ind++;
370       m_start++;
371     } while(m_start < m_end && m_buf[m_start - 1] != '\n' && ind < bufSize);
372 
373     if(ind == bufSize || (ind > 0 && buf[ind - 1] == '\n') )
374     {
375       receivedData(ind);
376       if(m_debug)
377         m_debug->Write(buf, ind);
378       if(ind < bufSize)
379       {
380         ind--;
381         buf[ind] = '\0';
382         if(stripCR && buf[ind - 1] == '\r')
383         {
384           ind--;
385           buf[ind] = '\0';
386         }
387       }
388       return ind;
389     }
390     if(m_start == m_end)
391     {
392       m_start = 0;
393       m_end = 0;
394     }
395   }
396   return 0; // never reached
397 }
398 
sentData(int)399 void base_tcp::sentData(int)
400 {
401 }
402 
receivedData(int bytes)403 void base_tcp::receivedData(int bytes)
404 {
405   m_res->dataBytes(bytes);
406 }
407 
408