GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/crypto/../../libssl/src/crypto/bio/bss_conn.c Lines: 0 256 0.0 %
Date: 2016-12-06 Branches: 0 145 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: bss_conn.c,v 1.32 2014/11/26 05:37:26 bcook 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
	int ret = -1, i;
125
	unsigned long l;
126
	char *p, *q;
127
	int (*cb)(const BIO *, int, int) = NULL;
128
129
	if (c->info_callback != NULL)
130
		cb = c->info_callback;
131
132
	for (;;) {
133
		switch (c->state) {
134
		case BIO_CONN_S_BEFORE:
135
			p = c->param_hostname;
136
			if (p == NULL) {
137
				BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_SPECIFIED);
138
				goto exit_loop;
139
			}
140
			for (; *p != '\0'; p++) {
141
				if ((*p == ':') || (*p == '/'))
142
				break;
143
			}
144
145
			i= *p;
146
			if ((i == ':') || (i == '/')) {
147
				*(p++) = '\0';
148
				if (i == ':') {
149
					for (q = p; *q; q++)
150
						if (*q == '/') {
151
							*q = '\0';
152
							break;
153
						}
154
					free(c->param_port);
155
					c->param_port = strdup(p);
156
				}
157
			}
158
159
			if (c->param_port == NULL) {
160
				BIOerr(BIO_F_CONN_STATE, 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
			break;
167
168
		case BIO_CONN_S_GET_IP:
169
			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
			break;
173
174
		case BIO_CONN_S_GET_PORT:
175
			if (c->param_port == NULL) {
176
				/* abort(); */
177
				goto exit_loop;
178
			} else if (BIO_get_port(c->param_port, &c->port) <= 0)
179
				goto exit_loop;
180
			c->state = BIO_CONN_S_CREATE_SOCKET;
181
			break;
182
183
		case BIO_CONN_S_CREATE_SOCKET:
184
			/* now setup address */
185
			memset((char *)&c->them, 0, sizeof(c->them));
186
			c->them.sin_family = AF_INET;
187
			c->them.sin_port = htons((unsigned short)c->port);
188
			l = (unsigned long)
189
			    ((unsigned long)c->ip[0] << 24L)|
190
			    ((unsigned long)c->ip[1] << 16L)|
191
			    ((unsigned long)c->ip[2] << 8L)|
192
			    ((unsigned long)c->ip[3]);
193
			c->them.sin_addr.s_addr = htonl(l);
194
			c->state = BIO_CONN_S_CREATE_SOCKET;
195
196
			ret = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
197
			if (ret == -1) {
198
				SYSerr(SYS_F_SOCKET, errno);
199
				ERR_asprintf_error_data("host=%s:%s",
200
				    c->param_hostname, c->param_port);
201
				BIOerr(BIO_F_CONN_STATE,
202
				    BIO_R_UNABLE_TO_CREATE_SOCKET);
203
				goto exit_loop;
204
			}
205
			b->num = ret;
206
			c->state = BIO_CONN_S_NBIO;
207
			break;
208
209
		case BIO_CONN_S_NBIO:
210
			if (c->nbio) {
211
				if (!BIO_socket_nbio(b->num, 1)) {
212
					BIOerr(BIO_F_CONN_STATE,
213
					    BIO_R_ERROR_SETTING_NBIO);
214
					ERR_asprintf_error_data("host=%s:%s",
215
					    c->param_hostname, c->param_port);
216
					goto exit_loop;
217
				}
218
			}
219
			c->state = BIO_CONN_S_CONNECT;
220
221
#if defined(SO_KEEPALIVE)
222
			i = 1;
223
			i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i));
224
			if (i < 0) {
225
				SYSerr(SYS_F_SOCKET, errno);
226
				ERR_asprintf_error_data("host=%s:%s",
227
				    c->param_hostname, c->param_port);
228
				BIOerr(BIO_F_CONN_STATE, BIO_R_KEEPALIVE);
229
				goto exit_loop;
230
			}
231
#endif
232
			break;
233
234
		case BIO_CONN_S_CONNECT:
235
			BIO_clear_retry_flags(b);
236
			ret = connect(b->num,
237
			(struct sockaddr *)&c->them,
238
			sizeof(c->them));
239
			b->retry_reason = 0;
240
			if (ret < 0) {
241
				if (BIO_sock_should_retry(ret)) {
242
					BIO_set_retry_special(b);
243
					c->state = BIO_CONN_S_BLOCKED_CONNECT;
244
					b->retry_reason = BIO_RR_CONNECT;
245
				} else {
246
					SYSerr(SYS_F_CONNECT, errno);
247
					ERR_asprintf_error_data("host=%s:%s",
248
					    c->param_hostname, c->param_port);
249
					BIOerr(BIO_F_CONN_STATE,
250
					    BIO_R_CONNECT_ERROR);
251
				}
252
				goto exit_loop;
253
			} else
254
				c->state = BIO_CONN_S_OK;
255
			break;
256
257
		case BIO_CONN_S_BLOCKED_CONNECT:
258
			i = BIO_sock_error(b->num);
259
			if (i) {
260
				BIO_clear_retry_flags(b);
261
				SYSerr(SYS_F_CONNECT, i);
262
				ERR_asprintf_error_data("host=%s:%s",
263
				    c->param_hostname, c->param_port);
264
				BIOerr(BIO_F_CONN_STATE,
265
				    BIO_R_NBIO_CONNECT_ERROR);
266
				ret = 0;
267
				goto exit_loop;
268
			} else
269
				c->state = BIO_CONN_S_OK;
270
			break;
271
272
		case BIO_CONN_S_OK:
273
			ret = 1;
274
			goto exit_loop;
275
		default:
276
			/* abort(); */
277
			goto exit_loop;
278
		}
279
280
		if (cb != NULL) {
281
			if (!(ret = cb((BIO *)b, c->state, ret)))
282
				goto end;
283
		}
284
	}
285
286
	/* Loop does not exit */
287
exit_loop:
288
	if (cb != NULL)
289
		ret = cb((BIO *)b, c->state, ret);
290
end:
291
	return (ret);
292
}
293
294
BIO_CONNECT *
295
BIO_CONNECT_new(void)
296
{
297
	BIO_CONNECT *ret;
298
299
	if ((ret = malloc(sizeof(BIO_CONNECT))) == NULL)
300
		return (NULL);
301
	ret->state = BIO_CONN_S_BEFORE;
302
	ret->param_hostname = NULL;
303
	ret->param_port = NULL;
304
	ret->info_callback = NULL;
305
	ret->nbio = 0;
306
	ret->ip[0] = 0;
307
	ret->ip[1] = 0;
308
	ret->ip[2] = 0;
309
	ret->ip[3] = 0;
310
	ret->port = 0;
311
	memset((char *)&ret->them, 0, sizeof(ret->them));
312
	return (ret);
313
}
314
315
void
316
BIO_CONNECT_free(BIO_CONNECT *a)
317
{
318
	if (a == NULL)
319
		return;
320
321
	free(a->param_hostname);
322
	free(a->param_port);
323
	free(a);
324
}
325
326
BIO_METHOD *
327
BIO_s_connect(void)
328
{
329
	return (&methods_connectp);
330
}
331
332
static int
333
conn_new(BIO *bi)
334
{
335
	bi->init = 0;
336
	bi->num = -1;
337
	bi->flags = 0;
338
	if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
339
		return (0);
340
	else
341
		return (1);
342
}
343
344
static void
345
conn_close_socket(BIO *bio)
346
{
347
	BIO_CONNECT *c;
348
349
	c = (BIO_CONNECT *)bio->ptr;
350
	if (bio->num != -1) {
351
		/* Only do a shutdown if things were established */
352
		if (c->state == BIO_CONN_S_OK)
353
			shutdown(bio->num, SHUT_RDWR);
354
		close(bio->num);
355
		bio->num = -1;
356
	}
357
}
358
359
static int
360
conn_free(BIO *a)
361
{
362
	BIO_CONNECT *data;
363
364
	if (a == NULL)
365
		return (0);
366
	data = (BIO_CONNECT *)a->ptr;
367
368
	if (a->shutdown) {
369
		conn_close_socket(a);
370
		BIO_CONNECT_free(data);
371
		a->ptr = NULL;
372
		a->flags = 0;
373
		a->init = 0;
374
	}
375
	return (1);
376
}
377
378
static int
379
conn_read(BIO *b, char *out, int outl)
380
{
381
	int ret = 0;
382
	BIO_CONNECT *data;
383
384
	data = (BIO_CONNECT *)b->ptr;
385
	if (data->state != BIO_CONN_S_OK) {
386
		ret = conn_state(b, data);
387
		if (ret <= 0)
388
			return (ret);
389
	}
390
391
	if (out != NULL) {
392
		errno = 0;
393
		ret = read(b->num, out, outl);
394
		BIO_clear_retry_flags(b);
395
		if (ret <= 0) {
396
			if (BIO_sock_should_retry(ret))
397
				BIO_set_retry_read(b);
398
		}
399
	}
400
	return (ret);
401
}
402
403
static int
404
conn_write(BIO *b, const char *in, int inl)
405
{
406
	int ret;
407
	BIO_CONNECT *data;
408
409
	data = (BIO_CONNECT *)b->ptr;
410
	if (data->state != BIO_CONN_S_OK) {
411
		ret = conn_state(b, data);
412
		if (ret <= 0)
413
			return (ret);
414
	}
415
416
	errno = 0;
417
	ret = write(b->num, in, inl);
418
	BIO_clear_retry_flags(b);
419
	if (ret <= 0) {
420
		if (BIO_sock_should_retry(ret))
421
			BIO_set_retry_write(b);
422
	}
423
	return (ret);
424
}
425
426
static long
427
conn_ctrl(BIO *b, int cmd, long num, void *ptr)
428
{
429
	BIO *dbio;
430
	int *ip;
431
	const char **pptr;
432
	long ret = 1;
433
	BIO_CONNECT *data;
434
435
	data = (BIO_CONNECT *)b->ptr;
436
437
	switch (cmd) {
438
	case BIO_CTRL_RESET:
439
		ret = 0;
440
		data->state = BIO_CONN_S_BEFORE;
441
		conn_close_socket(b);
442
		b->flags = 0;
443
		break;
444
	case BIO_C_DO_STATE_MACHINE:
445
		/* use this one to start the connection */
446
		if (data->state != BIO_CONN_S_OK)
447
			ret = (long)conn_state(b, data);
448
		else
449
			ret = 1;
450
		break;
451
	case BIO_C_GET_CONNECT:
452
		if (ptr != NULL) {
453
			pptr = (const char **)ptr;
454
			if (num == 0) {
455
				*pptr = data->param_hostname;
456
457
			} else if (num == 1) {
458
				*pptr = data->param_port;
459
			} else if (num == 2) {
460
				*pptr = (char *)&(data->ip[0]);
461
			} else if (num == 3) {
462
				*((int *)ptr) = data->port;
463
			}
464
			if ((!b->init) || (ptr == NULL))
465
				*pptr = "not initialized";
466
			ret = 1;
467
		}
468
		break;
469
	case BIO_C_SET_CONNECT:
470
		if (ptr != NULL) {
471
			b->init = 1;
472
			if (num == 0) {
473
				free(data->param_hostname);
474
				data->param_hostname = strdup(ptr);
475
			} else if (num == 1) {
476
				free(data->param_port);
477
				data->param_port = strdup(ptr);
478
			} else if (num == 2) {
479
				unsigned char *p = ptr;
480
				free(data->param_hostname);
481
				if (asprintf(&data->param_hostname,
482
					"%u.%u.%u.%u", p[0], p[1],
483
					p[2], p[3]) == -1)
484
					data->param_hostname = NULL;
485
				memcpy(&(data->ip[0]), ptr, 4);
486
			} else if (num == 3) {
487
				free(data->param_port);
488
				data->port= *(int *)ptr;
489
				if (asprintf(&data->param_port, "%d",
490
					data->port) == -1)
491
					data->param_port = NULL;
492
			}
493
		}
494
		break;
495
	case BIO_C_SET_NBIO:
496
		data->nbio = (int)num;
497
		break;
498
	case BIO_C_GET_FD:
499
		if (b->init) {
500
			ip = (int *)ptr;
501
			if (ip != NULL)
502
				*ip = b->num;
503
			ret = b->num;
504
		} else
505
			ret = -1;
506
		break;
507
	case BIO_CTRL_GET_CLOSE:
508
		ret = b->shutdown;
509
		break;
510
	case BIO_CTRL_SET_CLOSE:
511
		b->shutdown = (int)num;
512
		break;
513
	case BIO_CTRL_PENDING:
514
	case BIO_CTRL_WPENDING:
515
		ret = 0;
516
		break;
517
	case BIO_CTRL_FLUSH:
518
		break;
519
	case BIO_CTRL_DUP:
520
		{
521
			dbio = (BIO *)ptr;
522
			if (data->param_port)
523
				BIO_set_conn_port(dbio, data->param_port);
524
			if (data->param_hostname)
525
				BIO_set_conn_hostname(dbio,
526
				    data->param_hostname);
527
			BIO_set_nbio(dbio, data->nbio);
528
			/* FIXME: the cast of the function seems unlikely to be a good idea */
529
			(void)BIO_set_info_callback(dbio,
530
			    (bio_info_cb *)data->info_callback);
531
		}
532
		break;
533
	case BIO_CTRL_SET_CALLBACK:
534
		{
535
#if 0 /* FIXME: Should this be used?  -- Richard Levitte */
536
			BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
537
			ret = -1;
538
#else
539
			ret = 0;
540
#endif
541
		}
542
		break;
543
	case BIO_CTRL_GET_CALLBACK:
544
		{
545
			int (**fptr)(const BIO *bio, int state, int xret);
546
547
			fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
548
			*fptr = data->info_callback;
549
		}
550
		break;
551
	default:
552
		ret = 0;
553
		break;
554
	}
555
	return (ret);
556
}
557
558
static long
559
conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
560
{
561
	long ret = 1;
562
	BIO_CONNECT *data;
563
564
	data = (BIO_CONNECT *)b->ptr;
565
566
	switch (cmd) {
567
	case BIO_CTRL_SET_CALLBACK:
568
		{
569
			data->info_callback = (int (*)(const struct bio_st *, int, int))fp;
570
		}
571
		break;
572
	default:
573
		ret = 0;
574
		break;
575
	}
576
	return (ret);
577
}
578
579
static int
580
conn_puts(BIO *bp, const char *str)
581
{
582
	int n, ret;
583
584
	n = strlen(str);
585
	ret = conn_write(bp, str, n);
586
	return (ret);
587
}
588
589
BIO *
590
BIO_new_connect(char *str)
591
{
592
	BIO *ret;
593
594
	ret = BIO_new(BIO_s_connect());
595
	if (ret == NULL)
596
		return (NULL);
597
	if (BIO_set_conn_hostname(ret, str))
598
		return (ret);
599
	else {
600
		BIO_free(ret);
601
		return (NULL);
602
	}
603
}
604