ucspi-ssl 0.13.03
ucspi-ssl
Loading...
Searching...
No Matches
sslclient.c
Go to the documentation of this file.
1
6#include <unistd.h>
7#include <open.h>
8#include <sys/types.h>
9#include <sys/param.h>
10#include <netdb.h>
11#include <arpa/inet.h>
12#include "ucspissl.h"
13#include "sig.h"
14#include "exit.h"
15#include "getoptb.h"
16#include "uint_t.h"
17#include "fmt.h"
18#include "scan.h"
19#include "str.h"
20#include "ip.h"
21#include "socket_if.h"
22#include "fd.h"
23#include "stralloc.h"
24#include "buffer.h"
25#include "getln.h"
26#include "logmsg.h"
27#include "pathexec.h"
28#include "timeoutconn.h"
29#include "remoteinfo.h"
30#include "dnsresolv.h"
31#include "byte.h"
32#include "ndelay.h"
33#include "wait.h"
34#include "auto_cafile.h"
35#include "auto_cadir.h"
36#include "auto_ciphers.h"
37
38#define WHO "sslclient"
39
40void nomem(void) {
41 logmsg(WHO,111,FATAL,"out of memory");
42}
43void env(const char *s,const char *t) {
44 if (!pathexec_env(s,t)) nomem();
45}
46
47void usage(void) {
48 logmsg(WHO,100,USAGE,"sslclient \
49[ -463hHrRdDiqQveEsSnNxX ] \
50[ -i localip ] \
51[ -p localport ] \
52[ -T timeoutconn ] \
53[ -l localname ] \
54[ -t timeoutinfo ] \
55[ -I interface ] \
56[ -a cafile ] \
57[ -A cadir ] \
58[ -c certfile ] \
59[ -z ciphers ] \
60[ -k keyfile ] \
61[ -K keypassfile ] \
62[ -V verifydepth ] \
63[ -w progtimeout ] \
64host port program");
65}
66
67int verbosity = 1;
68int flagdelay = 0;
71int flag3 = 0;
72int flagsslenv = 0;
73int flagtcpenv = 0;
74int flagsni = 0;
75unsigned long itimeout = 26;
76unsigned long ctimeout[2] = { 2, 58 };
77unsigned int progtimeout = 3600;
78uint32 netif = 0;
79
80const char *loopback = "127.0.0.1";
81char iplocal[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
82uint16 portlocal = 0;
83const char *forcelocal = 0;
84
85char ipremote[16];
87
88const char *hostname;
89int flagname = 1;
91static stralloc addresses;
92static stralloc certname;
93static stralloc moreaddresses;
94
95static stralloc tmp;
96static stralloc fqdn;
97static char strnum[FMT_ULONG];
98static char ipstr[IP6_FMT];
99
100char seed[128];
101
102char bspace[16];
103buffer b;
104
105SSL_CTX *ctx;
106const char *certfile = 0;
107const char *keyfile = 0;
108const char *keypass = 0;
109const char *cafile = auto_cafile;
110const char *cadir = auto_cadir;
111const char *ciphers = auto_ciphers;
112stralloc password = {0};
113int match = 0;
115
116int pi[2];
117int po[2];
118int pt[2];
119
121{
122 int fd;
123
124 if (!password.len) {
125 fd = open_read(keypass);
126 if (fd == -1)
127 logmsg(WHO,111,ERROR,B("unable to read password from: ",keypass));
128
129 buffer_init(&b,buffer_unixread,fd,bspace,sizeof(bspace));
130 if (getln(&b,&password,&match,'\0') == -1)
131 logmsg(WHO,111,ERROR,B("unable to read password from: ",keypass));
132 close(fd);
133 if (match) --password.len;
134 }
135}
136
138 if (!password.len) {
139 buffer_init(&b,buffer_unixread,3,bspace,sizeof(bspace));
140 if (getln(&b,&password,&match,'\0') == -1)
141 logmsg(WHO,111,ERROR,"unable to read password from FD3");
142 close(3);
143 if (match) --password.len;
144 }
145}
146
147int passwd_cb(char *buf,int size,int rwflag,void *userdata) {
148 if (size < password.len)
149 logmsg(WHO,111,ERROR,"password too long");
150
151 byte_copy(buf,password.len,password.s);
152 return password.len;
153}
154
155int main(int argc,char * const *argv)
156{
157 unsigned long u;
158 int opt;
159 const char *x;
160 int j;
161 int s;
162 int r;
163 int cloop;
164 SSL *ssl;
165 int wstat;
166 int ipflag = 0;
167
168 dns_random_init(seed);
169
170 close(6);
171 close(7);
172 sig_ignore(sig_pipe);
173
174 while ((opt = getoptb(argc,(char **)argv,"dDvqQhHrRimM:p:t:T:l:a:A:c:z:k:K:V:346eEsSnN0xXw:")) != opteof)
175 switch(opt) {
176 case '4': ipflag = 1; break;
177 case '6': ipflag = 0; break;
178 case 'd': flagdelay = 1; break;
179 case 'D': flagdelay = 0; break;
180 case 'm': flagsni = 1; break;
181 case 'M': flagsni = 0; break;
182 case 'v': verbosity = 2; break;
183 case 'q': verbosity = 0; break;
184 case 'Q': verbosity = 1; break;
185 case 'l': forcelocal = optarg; break;
186 case 'H': flagremotehost = 0; break;
187 case 'h': flagremotehost = 1; break;
188 case 'R': flagremoteinfo = 0; break;
189 case 'r': flagremoteinfo = 1; break;
190 case 't': scan_ulong(optarg,&itimeout); break;
191 case 'T': j = scan_ulong(optarg,&ctimeout[0]);
192 if (optarg[j] == '+') ++j;
193 scan_ulong(optarg + j,&ctimeout[1]); break;
194 case 'w': scan_uint(optarg,&progtimeout); break;
195 case 'i': if (!ip6_scan(optarg,iplocal)) usage(); break;
196 case 'I': netif = socket_getifidx(optarg); break;
197 case 'p': scan_ulong(optarg,&u); portlocal = u; break;
198 case 'a': cafile = optarg; break;
199 case 'A': cadir = optarg; break;
200 case 'c': certfile = optarg; break;
201 case 'z': ciphers = optarg; break;
202 case 'k': keyfile = optarg; break;
203 case 'K': keypass = optarg; break;
204 case 'V': scan_ulong(optarg,&u); verifydepth = u; break;
205 case '3': flag3 = 1; break;
206 case 'S': flagsslenv = 0; break;
207 case 's': flagsslenv = 1; break;
208 case 'E': flagtcpenv = 0; break;
209 case 'e': flagtcpenv = 1; break;
210 case 'N': flagname = 0; break;
211 case 'n': flagname = 1; break;
212 case 'x': flagservercert = 1; break;
213 case 'X': flagservercert = 0; break;
214 default: usage();
215 }
216 argv += optind;
217
218 if (!verbosity)
219 buffer_2->fd = -1;
220
221 hostname = *argv;
222 if (!hostname || str_equal((char *)hostname,"")) usage();
223 if (str_equal((char *)hostname,"0")) hostname = loopback;
224
225 x = *++argv;
226 if (!x) usage();
227 if (!x[scan_ulong(x,&u)])
228 portremote = u;
229 else {
230 struct servent *se;
231 se = getservbyname(x,"tcp");
232 if (!se)
233 logmsg(WHO,111,FATAL,B("unable to figure out port number for ",x));
234 uint16_unpack_big((char*)&se->s_port,&portremote);
235 }
236
237 if (flag3) read_passwd();
238 if (keypass) read_pwdfile();
239
240 if (cafile && str_equal(cafile,"")) cafile = 0;
241 if (cadir && str_equal(cadir,"")) cadir= 0;
242 if (ciphers && str_equal(ciphers,"")) ciphers= 0;
243
244 if (certfile && str_equal(certfile,"")) certfile = 0;
245 if (keyfile && str_equal(keyfile,"")) keyfile = 0;
246 if (keypass && str_equal(keypass,"")) keypass = 0;
247
248 if (!*++argv) usage();
249
250 /* IP address only */
251
252 if (ip4_scan(hostname,ipremote)) {
253 if (!stralloc_copyb(&addresses,(char *)V4mappedprefix,12)) nomem();
254 if (!stralloc_catb(&addresses,ipremote,4)) nomem();
255 byte_copy(iplocal,16,addresses.s);
256 } else if (ip6_scan(hostname,ipremote)) {
257 if (!stralloc_copyb(&addresses,ipremote,16)) nomem();
258 byte_copy(iplocal,16,addresses.s);
259 }
260
261 if (addresses.len < 4) {
262 if (!stralloc_copys(&tmp,hostname)) nomem();
263 dns_ip_qualify(&addresses,&fqdn,&tmp);
264 if (addresses.len < 16)
265 logmsg(WHO,111,ERROR,B("No IP address for: ",hostname));
266 }
267
268 if (addresses.len == 16) {
269 ctimeout[0] += ctimeout[1];
270 ctimeout[1] = 0;
271 }
272
273 for (cloop = 0; cloop < 2; ++cloop) {
274 if (!stralloc_copys(&moreaddresses,"")) nomem();
275 for (j = 0; j + 16 <= addresses.len; j += 16) {
276 if (ipflag == 1 || ip6_isv4mapped(addresses.s + j)) {
277 s = socket_tcp4();
278 if (s == -1) logmsg(WHO,111,FATAL,"unable to create socket");
279 r = socket_bind4(s,iplocal,portlocal);
280 } else {
281 s = socket_tcp6();
282 if (s == -1) logmsg(WHO,111,FATAL,"unable to create socket");
283 r = socket_bind6(s,iplocal,portlocal,netif);
284 }
285 strnum[fmt_ulong(strnum,portlocal)] = 0;
286 if (r == -1) logmsg(WHO,111,FATAL,B("unable to bind to socket for local port: ",strnum));
287 if (timeoutconn(s,addresses.s + j,portremote,ctimeout[cloop],netif) == 0)
288 goto CONNECTED;
289 close(s);
290 if (!cloop && ctimeout[1] && (errno == ETIMEDOUT)) {
291 if (!stralloc_catb(&moreaddresses,addresses.s + j,16)) nomem();
292 }
293 else {
294 strnum[fmt_ulong(strnum,portremote)] = 0;
295 if (ip6_isv4mapped(addresses.s + j))
296 ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0;
297 else
298 ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0;
299 }
300 }
301 if (!stralloc_copy(&addresses,&moreaddresses)) nomem();
302 }
303 logmsg(WHO,110,DROP,B("unable to connect to: ",ipstr," port: ",strnum));
304
305 _exit(111);
306
307 CONNECTED:
308
309 /* Local */
310
311 if (socket_local(s,iplocal,&portlocal,&netif) == -1)
312 logmsg(WHO,111,FATAL,"unable to get local address");
313
314 if (ip6_isv4mapped(iplocal)) {
315 env("PROTO","TCP6");
316 ipstr[ip4_fmt(ipstr,iplocal + 12)] = 0;
317 } else {
318 env("PROTO","TCP6");
319 if (flagtcpenv && netif) env("TCP6INTERFACE",socket_getifname(netif));
320 ipstr[ip6_fmt(ipstr,iplocal)] = 0;
321 }
322
323 env("SSLLOCALIP",ipstr);
324 if (flagtcpenv) env("TCPLOCALIP",ipstr);
325
326 strnum[fmt_ulong(strnum,portlocal)] = 0;
327 env("SSLLOCALPORT",strnum);
328 if (flagtcpenv) env("TCPLOCALPORT",strnum);
329
330 x = forcelocal;
331 if (!x)
332 if (dns_name(&tmp,iplocal) >= 0) {
333 if (!stralloc_0(&tmp)) nomem();
334 x = tmp.s;
335 }
336 env("SSLLOCALHOST",x);
337 if (flagtcpenv) env("TCPLOCALHOST",x);
338
339 /* Remote */
340
341 if (socket_remote(s,ipremote,&portremote,&netif) == -1)
342 logmsg(WHO,111,FATAL,"unable to get remote address");
343
344 if (ip6_isv4mapped(ipremote))
345 ipstr[ip4_fmt(ipstr,ipremote + 12)] = 0;
346 else
347 ipstr[ip6_fmt(ipstr,ipremote)] = 0;
348
349 env("SSLREMOTEIP",ipstr);
350 if (flagtcpenv) env("TCPREMOTEIP",ipstr);
351
352 strnum[fmt_ulong(strnum,portremote)] = 0;
353 env("SSLREMOTEPORT",strnum);
354 if (flagtcpenv) env("TCPREMOTEPORT",strnum);
355
356 x = 0;
357 if (flagremotehost)
358 if (dns_name(&tmp,ipremote) >= 0) {
359 if (!stralloc_0(&tmp)) nomem();
360 x = tmp.s;
361 }
362
363 env("SSLREMOTEHOST",x);
364 if (flagtcpenv) env("TCPREMOTEHOST",x);
365
366 x = 0;
367 if (flagremoteinfo)
369 if (!stralloc_0(&tmp)) nomem();
370 x = tmp.s;
371 }
372 env("SSLREMOTEINFO",x);
373 if (flagtcpenv) env("TCPREMOTEINFO",x);
374
375 /* Context */
376
377 ctx = ssl_client();
378 ssl_errstr();
379 if (!ctx)
380 logmsg(WHO,111,FATAL,"unable to create TLS context");
381
383 case -1: logmsg(WHO,111,ERROR,"unable to load certificate");
384 case -2: logmsg(WHO,111,ERROR,"unable to load key pair");
385 case -3: logmsg(WHO,111,ERROR,"key does not match certificate");
386 default: break;
387 }
388
390 logmsg(WHO,111,ERROR,"unable to load CA list");
391
392 if (!ssl_ciphers(ctx,ciphers))
393 logmsg(WHO,111,ERROR,"unable to set cipher list");
394
395 ssl = ssl_new(ctx,s);
396 if (!ssl) logmsg(WHO,111,FATAL,"unable to create TLS instance");
397
398 if (flagsni)
399 if (!SSL_set_tlsext_host_name(ssl,hostname))
400 logmsg(WHO,111,FATAL,B("unable to set TLS SNI extensions for hostname: ",(char *)hostname));
401
402 for (cloop = 0; cloop < 2; ++cloop) {
403 if (!ssl_timeoutconn(ssl,ctimeout[cloop])) goto SSLCONNECTED;
404 if (!cloop && ctimeout[1]) continue;
405 logmsg(WHO,111,FATAL,"unable to TLS connect");
406 }
407
408 _exit(111);
409
410 SSLCONNECTED:
411
412 ndelay_off(s);
413
414 if (flagservercert)
415 switch(ssl_verify(ssl,hostname,&certname)) {
416 case -1:
417 logmsg(WHO,110,ERROR,"no server certificate");
418 case -2:
419 logmsg(WHO,110,ERROR,"missing credentials (CA) or unable to validate server certificate");
420 case -3:
421 if (!stralloc_0(&certname)) nomem();
422 if (flagname)
423 logmsg(WHO,110,ERROR,B("server hostname does not match certificate: ",(char *)hostname," <=> ",certname.s));
424 default: break;
425 }
426
427 if (verbosity >= 2)
428 log_who(WHO,B("tls connected to: ",ipstr," port: ",strnum));
429
430 if (!flagdelay)
431 socket_tcpnodelay(s); /* if it fails, bummer */
432
433 if (pipe(pi) == -1) logmsg(WHO,111,FATAL,"unable to create pipe");
434 if (pipe(po) == -1) logmsg(WHO,111,FATAL,"unable to create pipe");
435 if (pi[0] == 7) {
436 if (pipe(pt) == -1) logmsg(WHO,111,FATAL,"unable to create pipe");
437 close(pi[0]); close(pi[1]);
438 pi[0] = pt[0]; pi[1] = pt[1];
439 }
440 if (po[1] == 6) {
441 if (pipe(pt) == -1) logmsg(WHO,111,FATAL,"unable to create pipe");
442 close(po[0]); close(po[1]);
443 po[0] = pt[0]; po[1] = pt[1];
444 }
445
446 switch (opt = fork()) {
447 case -1:
448 logmsg(WHO,111,FATAL,"unable to fork");
449 case 0:
450 break;
451 default:
452 close(pi[0]); close(po[1]);
453 if (ssl_io(ssl,pi[1],po[0],progtimeout)) {
454 logmsg(WHO,110,DROP,"unable to speak TLS");
455 ssl_close(ssl);
456 wait_pid(&wstat,opt);
457 _exit(111);
458 }
459 ssl_close(ssl);
460 if (wait_pid(&wstat,opt) > 0)
461 _exit(wait_exitcode(wstat));
462 _exit(0);
463 }
464 ssl_close(ssl); close(pi[1]); close(po[0]);
465
466 if (flagsslenv && !ssl_client_env(ssl,0)) nomem();
467
468 if (fd_move(6,pi[0]) == -1)
469 logmsg(WHO,111,FATAL,"unable to set up descriptor 6");
470 if (fd_move(7,po[1]) == -1)
471 logmsg(WHO,111,FATAL,"unable to set up descriptor 7");
472 sig_uncatch(sig_pipe);
473
474 pathexec(argv);
475 logmsg(WHO,111,FATAL,B("unable to run: ",*argv));
476
477 return 0; /* never happens, but avoids compile warning */
478}
const char auto_cadir[]
const char auto_cafile[]
const char auto_ciphers[]
int main()
Definition: chkshsgr.c:7
void _exit()
int remoteinfo(stralloc *out, char ipremote[16], uint16 portremote, char iplocal[16], uint16 portlocal, unsigned int timeout, uint32 netif)
Definition: remoteinfo.c:86
int ssl_ca(SSL_CTX *ctx, const char *certfile, const char *certdir, int d)
Definition: ssl_ca.c:3
int ssl_certkey(SSL_CTX *ctx, const char *certfile, const char *keyfile, pem_password_cb *passwd_cb)
Definition: ssl_certkey.c:3
int ssl_ciphers(SSL_CTX *ctx, const char *ciphers)
Definition: ssl_ciphers.c:3
int ssl_client_env(SSL *ssl, stralloc *sa)
Definition: ssl_env.c:447
int ssl_io(SSL *ssl, int fdleft, int fdright, unsigned int timeout)
Definition: ssl_io.c:20
SSL * ssl_new(SSL_CTX *ctx, int s)
Definition: ssl_new.c:4
int ssl_timeoutconn(SSL *ssl, unsigned int timeout)
Definition: ssl_timeout.c:60
int ssl_verify(SSL *ssl, const char *hostname, stralloc *dnsout)
Definition: ssl_verify.c:10
void read_pwdfile()
Definition: sslclient.c:120
uint16 portremote
Definition: sslclient.c:86
stralloc password
Definition: sslclient.c:112
const char * certfile
Definition: sslclient.c:106
int verbosity
Definition: sslclient.c:67
uint16 portlocal
Definition: sslclient.c:82
const char * ciphers
Definition: sslclient.c:111
int flag3
Definition: sslclient.c:71
char iplocal[16]
Definition: sslclient.c:81
int flagsni
Definition: sslclient.c:74
unsigned long ctimeout[2]
Definition: sslclient.c:76
int pt[2]
Definition: sslclient.c:118
const char * keypass
Definition: sslclient.c:108
unsigned long itimeout
Definition: sslclient.c:75
const char * cadir
Definition: sslclient.c:110
int flagremotehost
Definition: sslclient.c:70
unsigned int progtimeout
Definition: sslclient.c:77
int flagremoteinfo
Definition: sslclient.c:69
const char * forcelocal
Definition: sslclient.c:83
buffer b
Definition: sslclient.c:103
const char * cafile
Definition: sslclient.c:109
char ipremote[16]
Definition: sslclient.c:85
void nomem(void)
Definition: sslclient.c:40
int flagservercert
Definition: sslclient.c:90
void env(const char *s, const char *t)
Definition: sslclient.c:43
const char * keyfile
Definition: sslclient.c:107
const char * hostname
Definition: sslclient.c:88
const char * loopback
Definition: sslclient.c:80
void read_passwd()
Definition: sslclient.c:137
int flagdelay
Definition: sslclient.c:68
int passwd_cb(char *buf, int size, int rwflag, void *userdata)
Definition: sslclient.c:147
uint32 netif
Definition: sslclient.c:78
int match
Definition: sslclient.c:113
int pi[2]
Definition: sslclient.c:116
SSL_CTX * ctx
Definition: sslclient.c:105
int flagtcpenv
Definition: sslclient.c:73
int flagname
Definition: sslclient.c:89
#define WHO
Definition: sslclient.c:38
char bspace[16]
Definition: sslclient.c:102
char seed[128]
Definition: sslclient.c:100
void usage(void)
Definition: sslclient.c:47
int verifydepth
Definition: sslclient.c:114
int flagsslenv
Definition: sslclient.c:72
int po[2]
Definition: sslclient.c:117
char buf[SSL_NAME_LEN]
Definition: sslhandle.c:127
Header file to be used with sqmail; previously called ssl.h. (name clash)
#define ssl_client()
Definition: ucspissl.h:39
#define ssl_errstr()
Definition: ucspissl.h:61
#define ssl_close(ssl)
Definition: ucspissl.h:63