GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/bio/bss_conn.c Lines: 142 256 55.5 %
Date: 2017-11-07 Branches: 59 144 41.0 %

Line Branch Exec Source
1
/* $OpenBSD: bss_conn.c,v 1.33 2017/01/29 17:49:22 beck Exp $ */
2
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3
 * All rights reserved.
4
 *
5
 * This package is an SSL implementation written
6
 * by Eric Young (eay@cryptsoft.com).
7
 * The implementation was written so as to conform with Netscapes SSL.
8
 *
9
 * This library is free for commercial and non-commercial use as long as
10
 * the following conditions are aheared to.  The following conditions
11
 * apply to all code found in this distribution, be it the RC4, RSA,
12
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13
 * included with this distribution is covered by the same copyright terms
14
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15
 *
16
 * Copyright remains Eric Young's, and as such any Copyright notices in
17
 * the code are not to be removed.
18
 * If this package is used in a product, Eric Young should be given attribution
19
 * as the author of the parts of the library used.
20
 * This can be in the form of a textual message at program startup or
21
 * in documentation (online or textual) provided with the package.
22
 *
23
 * Redistribution and use in source and binary forms, with or without
24
 * modification, are permitted provided that the following conditions
25
 * are met:
26
 * 1. Redistributions of source code must retain the copyright
27
 *    notice, this list of conditions and the following disclaimer.
28
 * 2. Redistributions in binary form must reproduce the above copyright
29
 *    notice, this list of conditions and the following disclaimer in the
30
 *    documentation and/or other materials provided with the distribution.
31
 * 3. All advertising materials mentioning features or use of this software
32
 *    must display the following acknowledgement:
33
 *    "This product includes cryptographic software written by
34
 *     Eric Young (eay@cryptsoft.com)"
35
 *    The word 'cryptographic' can be left out if the rouines from the library
36
 *    being used are not cryptographic related :-).
37
 * 4. If you include any Windows specific code (or a derivative thereof) from
38
 *    the apps directory (application code) you must include an acknowledgement:
39
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40
 *
41
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51
 * SUCH DAMAGE.
52
 *
53
 * The licence and distribution terms for any publically available version or
54
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55
 * copied and put under another distribution licence
56
 * [including the GNU Public Licence.]
57
 */
58
59
#include <sys/socket.h>
60
61
#include <netinet/in.h>
62
63
#include <errno.h>
64
#include <netdb.h>
65
#include <stdio.h>
66
#include <string.h>
67
#include <unistd.h>
68
69
#include <openssl/bio.h>
70
#include <openssl/buffer.h>
71
#include <openssl/err.h>
72
73
#define SOCKET_PROTOCOL IPPROTO_TCP
74
75
typedef struct bio_connect_st {
76
	int state;
77
78
	char *param_hostname;
79
	char *param_port;
80
	int nbio;
81
82
	unsigned char ip[4];
83
	unsigned short port;
84
85
	struct sockaddr_in them;
86
87
	/* int socket; this will be kept in bio->num so that it is
88
	 * compatible with the bss_sock bio */
89
90
	/* called when the connection is initially made
91
	 *  callback(BIO,state,ret);  The callback should return
92
	 * 'ret'.  state is for compatibility with the ssl info_callback */
93
	int (*info_callback)(const BIO *bio, int state, int ret);
94
} BIO_CONNECT;
95
96
static int conn_write(BIO *h, const char *buf, int num);
97
static int conn_read(BIO *h, char *buf, int size);
98
static int conn_puts(BIO *h, const char *str);
99
static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
100
static int conn_new(BIO *h);
101
static int conn_free(BIO *data);
102
static long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *);
103
104
static int conn_state(BIO *b, BIO_CONNECT *c);
105
static void conn_close_socket(BIO *data);
106
BIO_CONNECT *BIO_CONNECT_new(void);
107
void BIO_CONNECT_free(BIO_CONNECT *a);
108
109
static BIO_METHOD methods_connectp = {
110
	.type = BIO_TYPE_CONNECT,
111
	.name = "socket connect",
112
	.bwrite = conn_write,
113
	.bread = conn_read,
114
	.bputs = conn_puts,
115
	.ctrl = conn_ctrl,
116
	.create = conn_new,
117
	.destroy = conn_free,
118
	.callback_ctrl = conn_callback_ctrl
119
};
120
121
static int
122
conn_state(BIO *b, BIO_CONNECT *c)
123
{
124
15842
	int ret = -1, i;
125
	unsigned long l;
126
	char *p, *q;
127
	int (*cb)(const BIO *, int, int) = NULL;
128
129
7921
	if (c->info_callback != NULL)
130
		cb = c->info_callback;
131
132
	for (;;) {
133


63368
		switch (c->state) {
134
		case BIO_CONN_S_BEFORE:
135
7921
			p = c->param_hostname;
136
7921
			if (p == NULL) {
137
				BIOerror(BIO_R_NO_HOSTNAME_SPECIFIED);
138
				goto exit_loop;
139
			}
140
150499
			for (; *p != '\0'; p++) {
141

150497
				if ((*p == ':') || (*p == '/'))
142
				break;
143
			}
144
145
7921
			i= *p;
146
7921
			if ((i == ':') || (i == '/')) {
147
7919
				*(p++) = '\0';
148
7919
				if (i == ':') {
149
79190
					for (q = p; *q; q++)
150
31676
						if (*q == '/') {
151
							*q = '\0';
152
							break;
153
						}
154
7919
					free(c->param_port);
155
7919
					c->param_port = strdup(p);
156
7919
				}
157
			}
158
159
7921
			if (c->param_port == NULL) {
160
				BIOerror(BIO_R_NO_PORT_SPECIFIED);
161
				ERR_asprintf_error_data("host=%s",
162
				    c->param_hostname);
163
				goto exit_loop;
164
			}
165
			c->state = BIO_CONN_S_GET_IP;
166
7921
			break;
167
168
		case BIO_CONN_S_GET_IP:
169
7921
			if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0)
170
				goto exit_loop;
171
			c->state = BIO_CONN_S_GET_PORT;
172
7921
			break;
173
174
		case BIO_CONN_S_GET_PORT:
175
7921
			if (c->param_port == NULL) {
176
				/* abort(); */
177
				goto exit_loop;
178
7921
			} else if (BIO_get_port(c->param_port, &c->port) <= 0)
179
				goto exit_loop;
180
			c->state = BIO_CONN_S_CREATE_SOCKET;
181
7921
			break;
182
183
		case BIO_CONN_S_CREATE_SOCKET:
184
			/* now setup address */
185
7921
			memset((char *)&c->them, 0, sizeof(c->them));
186
7921
			c->them.sin_family = AF_INET;
187
7921
			c->them.sin_port = htons((unsigned short)c->port);
188
			l = (unsigned long)
189
15842
			    ((unsigned long)c->ip[0] << 24L)|
190
15842
			    ((unsigned long)c->ip[1] << 16L)|
191
15842
			    ((unsigned long)c->ip[2] << 8L)|
192
7921
			    ((unsigned long)c->ip[3]);
193
7921
			c->them.sin_addr.s_addr = htonl(l);
194
7921
			c->state = BIO_CONN_S_CREATE_SOCKET;
195
196
7921
			ret = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
197
7921
			if (ret == -1) {
198
				SYSerror(errno);
199
				ERR_asprintf_error_data("host=%s:%s",
200
				    c->param_hostname, c->param_port);
201
				BIOerror(BIO_R_UNABLE_TO_CREATE_SOCKET);
202
				goto exit_loop;
203
			}
204
7921
			b->num = ret;
205
			c->state = BIO_CONN_S_NBIO;
206
7921
			break;
207
208
		case BIO_CONN_S_NBIO:
209
7921
			if (c->nbio) {
210
				if (!BIO_socket_nbio(b->num, 1)) {
211
					BIOerror(BIO_R_ERROR_SETTING_NBIO);
212
					ERR_asprintf_error_data("host=%s:%s",
213
					    c->param_hostname, c->param_port);
214
					goto exit_loop;
215
				}
216
			}
217
7921
			c->state = BIO_CONN_S_CONNECT;
218
219
#if defined(SO_KEEPALIVE)
220
7921
			i = 1;
221
7921
			i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i));
222
7921
			if (i < 0) {
223
				SYSerror(errno);
224
				ERR_asprintf_error_data("host=%s:%s",
225
				    c->param_hostname, c->param_port);
226
				BIOerror(BIO_R_KEEPALIVE);
227
				goto exit_loop;
228
			}
229
#endif
230
			break;
231
232
		case BIO_CONN_S_CONNECT:
233
7921
			BIO_clear_retry_flags(b);
234
15842
			ret = connect(b->num,
235
7921
			(struct sockaddr *)&c->them,
236
			sizeof(c->them));
237
7921
			b->retry_reason = 0;
238
7921
			if (ret < 0) {
239
				if (BIO_sock_should_retry(ret)) {
240
					BIO_set_retry_special(b);
241
					c->state = BIO_CONN_S_BLOCKED_CONNECT;
242
					b->retry_reason = BIO_RR_CONNECT;
243
				} else {
244
					SYSerror(errno);
245
					ERR_asprintf_error_data("host=%s:%s",
246
					    c->param_hostname, c->param_port);
247
					BIOerror(BIO_R_CONNECT_ERROR);
248
				}
249
				goto exit_loop;
250
			} else
251
				c->state = BIO_CONN_S_OK;
252
7921
			break;
253
254
		case BIO_CONN_S_BLOCKED_CONNECT:
255
			i = BIO_sock_error(b->num);
256
			if (i) {
257
				BIO_clear_retry_flags(b);
258
				SYSerror(i);
259
				ERR_asprintf_error_data("host=%s:%s",
260
				    c->param_hostname, c->param_port);
261
				BIOerror(BIO_R_NBIO_CONNECT_ERROR);
262
				ret = 0;
263
				goto exit_loop;
264
			} else
265
				c->state = BIO_CONN_S_OK;
266
			break;
267
268
		case BIO_CONN_S_OK:
269
			ret = 1;
270
7921
			goto exit_loop;
271
		default:
272
			/* abort(); */
273
			goto exit_loop;
274
		}
275
276
87131
		if (cb != NULL) {
277
			if (!(ret = cb((BIO *)b, c->state, ret)))
278
				goto end;
279
		}
280
	}
281
282
	/* Loop does not exit */
283
exit_loop:
284
7921
	if (cb != NULL)
285
		ret = cb((BIO *)b, c->state, ret);
286
end:
287
7921
	return (ret);
288
7921
}
289
290
BIO_CONNECT *
291
BIO_CONNECT_new(void)
292
{
293
	BIO_CONNECT *ret;
294
295
15842
	if ((ret = malloc(sizeof(BIO_CONNECT))) == NULL)
296
		return (NULL);
297
7921
	ret->state = BIO_CONN_S_BEFORE;
298
7921
	ret->param_hostname = NULL;
299
7921
	ret->param_port = NULL;
300
7921
	ret->info_callback = NULL;
301
7921
	ret->nbio = 0;
302
7921
	ret->ip[0] = 0;
303
7921
	ret->ip[1] = 0;
304
7921
	ret->ip[2] = 0;
305
7921
	ret->ip[3] = 0;
306
7921
	ret->port = 0;
307
7921
	memset((char *)&ret->them, 0, sizeof(ret->them));
308
7921
	return (ret);
309
7921
}
310
311
void
312
BIO_CONNECT_free(BIO_CONNECT *a)
313
{
314
15842
	if (a == NULL)
315
		return;
316
317
7921
	free(a->param_hostname);
318
7921
	free(a->param_port);
319
7921
	free(a);
320
15842
}
321
322
BIO_METHOD *
323
BIO_s_connect(void)
324
{
325
15842
	return (&methods_connectp);
326
}
327
328
static int
329
conn_new(BIO *bi)
330
{
331
15842
	bi->init = 0;
332
7921
	bi->num = -1;
333
7921
	bi->flags = 0;
334
7921
	if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
335
		return (0);
336
	else
337
7921
		return (1);
338
7921
}
339
340
static void
341
conn_close_socket(BIO *bio)
342
{
343
	BIO_CONNECT *c;
344
345
15842
	c = (BIO_CONNECT *)bio->ptr;
346
7921
	if (bio->num != -1) {
347
		/* Only do a shutdown if things were established */
348
7921
		if (c->state == BIO_CONN_S_OK)
349
7921
			shutdown(bio->num, SHUT_RDWR);
350
7921
		close(bio->num);
351
7921
		bio->num = -1;
352
7921
	}
353
7921
}
354
355
static int
356
conn_free(BIO *a)
357
{
358
	BIO_CONNECT *data;
359
360
15842
	if (a == NULL)
361
		return (0);
362
7921
	data = (BIO_CONNECT *)a->ptr;
363
364
7921
	if (a->shutdown) {
365
7921
		conn_close_socket(a);
366
7921
		BIO_CONNECT_free(data);
367
7921
		a->ptr = NULL;
368
7921
		a->flags = 0;
369
7921
		a->init = 0;
370
7921
	}
371
7921
	return (1);
372
7921
}
373
374
static int
375
conn_read(BIO *b, char *out, int outl)
376
{
377
	int ret = 0;
378
	BIO_CONNECT *data;
379
380
109064
	data = (BIO_CONNECT *)b->ptr;
381
54532
	if (data->state != BIO_CONN_S_OK) {
382
		ret = conn_state(b, data);
383
		if (ret <= 0)
384
			return (ret);
385
	}
386
387
54532
	if (out != NULL) {
388
54532
		errno = 0;
389
54532
		ret = read(b->num, out, outl);
390
54532
		BIO_clear_retry_flags(b);
391
54532
		if (ret <= 0) {
392
			if (BIO_sock_should_retry(ret))
393
				BIO_set_retry_read(b);
394
		}
395
	}
396
54532
	return (ret);
397
54532
}
398
399
static int
400
conn_write(BIO *b, const char *in, int inl)
401
{
402
	int ret;
403
	BIO_CONNECT *data;
404
405
31680
	data = (BIO_CONNECT *)b->ptr;
406
15840
	if (data->state != BIO_CONN_S_OK) {
407
7919
		ret = conn_state(b, data);
408
7919
		if (ret <= 0)
409
			return (ret);
410
	}
411
412
15840
	errno = 0;
413
15840
	ret = write(b->num, in, inl);
414
15840
	BIO_clear_retry_flags(b);
415
15840
	if (ret <= 0) {
416
		if (BIO_sock_should_retry(ret))
417
			BIO_set_retry_write(b);
418
	}
419
15840
	return (ret);
420
15840
}
421
422
static long
423
conn_ctrl(BIO *b, int cmd, long num, void *ptr)
424
{
425
	BIO *dbio;
426
	int *ip;
427
	const char **pptr;
428
	long ret = 1;
429
	BIO_CONNECT *data;
430
431
134651
	data = (BIO_CONNECT *)b->ptr;
432
433



87127
	switch (cmd) {
434
	case BIO_CTRL_RESET:
435
		ret = 0;
436
		data->state = BIO_CONN_S_BEFORE;
437
		conn_close_socket(b);
438
		b->flags = 0;
439
		break;
440
	case BIO_C_DO_STATE_MACHINE:
441
		/* use this one to start the connection */
442
2
		if (data->state != BIO_CONN_S_OK)
443
2
			ret = (long)conn_state(b, data);
444
		else
445
			ret = 1;
446
		break;
447
	case BIO_C_GET_CONNECT:
448
		if (ptr != NULL) {
449
			pptr = (const char **)ptr;
450
			if (num == 0) {
451
				*pptr = data->param_hostname;
452
453
			} else if (num == 1) {
454
				*pptr = data->param_port;
455
			} else if (num == 2) {
456
				*pptr = (char *)&(data->ip[0]);
457
			} else if (num == 3) {
458
				*((int *)ptr) = data->port;
459
			}
460
			if ((!b->init) || (ptr == NULL))
461
				*pptr = "not initialized";
462
			ret = 1;
463
		}
464
		break;
465
	case BIO_C_SET_CONNECT:
466
7923
		if (ptr != NULL) {
467
7923
			b->init = 1;
468
7923
			if (num == 0) {
469
7921
				free(data->param_hostname);
470
7921
				data->param_hostname = strdup(ptr);
471
7923
			} else if (num == 1) {
472
2
				free(data->param_port);
473
2
				data->param_port = strdup(ptr);
474
2
			} else if (num == 2) {
475
				unsigned char *p = ptr;
476
				free(data->param_hostname);
477
				if (asprintf(&data->param_hostname,
478
					"%u.%u.%u.%u", p[0], p[1],
479
					p[2], p[3]) == -1)
480
					data->param_hostname = NULL;
481
				memcpy(&(data->ip[0]), ptr, 4);
482
			} else if (num == 3) {
483
				free(data->param_port);
484
				data->port= *(int *)ptr;
485
				if (asprintf(&data->param_port, "%d",
486
					data->port) == -1)
487
					data->param_port = NULL;
488
			}
489
		}
490
		break;
491
	case BIO_C_SET_NBIO:
492
		data->nbio = (int)num;
493
		break;
494
	case BIO_C_GET_FD:
495
15840
		if (b->init) {
496
15840
			ip = (int *)ptr;
497
15840
			if (ip != NULL)
498
15840
				*ip = b->num;
499
15840
			ret = b->num;
500
15840
		} else
501
			ret = -1;
502
		break;
503
	case BIO_CTRL_GET_CLOSE:
504
		ret = b->shutdown;
505
		break;
506
	case BIO_CTRL_SET_CLOSE:
507
		b->shutdown = (int)num;
508
		break;
509
	case BIO_CTRL_PENDING:
510
	case BIO_CTRL_WPENDING:
511
		ret = 0;
512
		break;
513
	case BIO_CTRL_FLUSH:
514
		break;
515
	case BIO_CTRL_DUP:
516
		{
517
			dbio = (BIO *)ptr;
518
			if (data->param_port)
519
				BIO_set_conn_port(dbio, data->param_port);
520
			if (data->param_hostname)
521
				BIO_set_conn_hostname(dbio,
522
				    data->param_hostname);
523
			BIO_set_nbio(dbio, data->nbio);
524
			/* FIXME: the cast of the function seems unlikely to be a good idea */
525
			(void)BIO_set_info_callback(dbio,
526
			    (bio_info_cb *)data->info_callback);
527
		}
528
		break;
529
	case BIO_CTRL_SET_CALLBACK:
530
		{
531
#if 0 /* FIXME: Should this be used?  -- Richard Levitte */
532
			BIOerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
533
			ret = -1;
534
#else
535
			ret = 0;
536
#endif
537
		}
538
		break;
539
	case BIO_CTRL_GET_CALLBACK:
540
		{
541
			int (**fptr)(const BIO *bio, int state, int xret);
542
543
			fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
544
			*fptr = data->info_callback;
545
		}
546
		break;
547
	default:
548
		ret = 0;
549
15838
		break;
550
	}
551
47524
	return (ret);
552
}
553
554
static long
555
conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
556
{
557
	long ret = 1;
558
	BIO_CONNECT *data;
559
560
	data = (BIO_CONNECT *)b->ptr;
561
562
	switch (cmd) {
563
	case BIO_CTRL_SET_CALLBACK:
564
		{
565
			data->info_callback = (int (*)(const struct bio_st *, int, int))fp;
566
		}
567
		break;
568
	default:
569
		ret = 0;
570
		break;
571
	}
572
	return (ret);
573
}
574
575
static int
576
conn_puts(BIO *bp, const char *str)
577
{
578
	int n, ret;
579
580
	n = strlen(str);
581
	ret = conn_write(bp, str, n);
582
	return (ret);
583
}
584
585
BIO *
586
BIO_new_connect(char *str)
587
{
588
	BIO *ret;
589
590
4
	ret = BIO_new(BIO_s_connect());
591
2
	if (ret == NULL)
592
		return (NULL);
593
2
	if (BIO_set_conn_hostname(ret, str))
594
2
		return (ret);
595
	else {
596
		BIO_free(ret);
597
		return (NULL);
598
	}
599
2
}
600