Ejemplo n.º 1
0
static int SSL_recvwithtimeout(BUFF *fb, char *buf, int len)
{
    int iostate = 1;
    fd_set fdset;
    struct timeval tv;
    int err = WSAEWOULDBLOCK;
    int rv;
    int sock = fb->fd_in;
    SSL *ssl;
    int retry;

    ssl = ap_ctx_get(fb->ctx, "ssl");

    if (!(tv.tv_sec = ap_check_alarm()))
        return (SSL_read(ssl, buf, len));

    rv = ioctlsocket(sock, FIONBIO, &iostate);
    iostate = 0;
    ap_assert(!rv);
    rv = SSL_read(ssl, buf, len);
    if (rv <= 0) {
        if (BIO_sock_should_retry(rv)) {
            do {
                retry = 0;
                FD_ZERO(&fdset);
                FD_SET((unsigned int)sock, &fdset);
                tv.tv_usec = 0;
                rv = select(FD_SETSIZE, &fdset, NULL, NULL, &tv);
                if (rv == SOCKET_ERROR)
                    err = WSAGetLastError();
                else if (rv == 0) {
                    ioctlsocket(sock, FIONBIO, &iostate);
                    ap_check_alarm();
                    WSASetLastError(WSAEWOULDBLOCK);
                    return (SOCKET_ERROR);
                }
                else {
                    rv = SSL_read(ssl, buf, len);
                    if (rv == SOCKET_ERROR) {
                        if (BIO_sock_should_retry(rv)) {
                          ap_log_error(APLOG_MARK,APLOG_DEBUG, NULL,
                                       "select claimed we could read, "
                                       "but in fact we couldn't. "
                                       "This is a bug in Windows.");
                          retry = 1;
                          Sleep(100);
                        }
                        else {
                            err = WSAGetLastError();
                        }
                    }
                }
            } while(retry);
        }
    }
    ioctlsocket(sock, FIONBIO, &iostate);
    if (rv == SOCKET_ERROR)
        WSASetLastError(err);
    return (rv);
}
Ejemplo n.º 2
0
/*-
 * BIO_accept_ex - Accept new incoming connections
 * @sock: the listening socket
 * @addr: the BIO_ADDR to store the peer address in
 * @options: BIO socket options, applied on the accepted socket.
 *
 */
int BIO_accept_ex(int accept_sock, BIO_ADDR *addr_, int options)
{
    socklen_t len;
    int accepted_sock;
    BIO_ADDR locaddr;
    BIO_ADDR *addr = addr_ == NULL ? &locaddr : addr_;

    len = sizeof(*addr);
    accepted_sock = accept(accept_sock,
                           BIO_ADDR_sockaddr_noconst(addr), &len);
    if (accepted_sock == -1) {
        if (!BIO_sock_should_retry(accepted_sock)) {
            SYSerr(SYS_F_ACCEPT, get_last_socket_error());
            BIOerr(BIO_F_BIO_ACCEPT_EX, BIO_R_ACCEPT_ERROR);
        }
        return INVALID_SOCKET;
    }

    if (!BIO_socket_nbio(accepted_sock, (options & BIO_SOCK_NONBLOCK) != 0)) {
        closesocket(accepted_sock);
        return INVALID_SOCKET;
    }

    return accepted_sock;
}
Ejemplo n.º 3
0
static int dgram_write(BIO *b, const char *in, int inl)
	{
	int ret;
	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
	clear_socket_error();

    if ( data->connected )
        ret=writesocket(b->num,in,inl);
    else
#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
        ret=sendto(b->num, (char *)in, inl, 0, &data->peer, sizeof(data->peer));
#else
        ret=sendto(b->num, in, inl, 0, &data->peer, sizeof(data->peer));
#endif

	BIO_clear_retry_flags(b);
	if (ret <= 0)
		{
		if (BIO_sock_should_retry(ret))
			{
			BIO_set_retry_write(b);  
			data->_errno = get_last_socket_error();

#if 0 /* higher layers are responsible for querying MTU, if necessary */
			if ( data->_errno == EMSGSIZE)
				/* retrieve the new MTU */
				BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
#endif
			}
		}
	return(ret);
	}
Ejemplo n.º 4
0
static int fd_read(BIO *b, char *out,int outl)
#endif
	{
	int ret=0;

	if (out != NULL)
		{
#ifndef BIO_FD
		clear_socket_error();
		ret=readsocket(b->num,out,outl);
#else
		clear_sys_error();
		ret=read(b->num,out,outl);
#endif
		BIO_clear_retry_flags(b);
		if (ret <= 0)
			{
#ifndef BIO_FD
			if (BIO_sock_should_retry(ret))
#else
			if (BIO_fd_should_retry(ret))
#endif
				BIO_set_retry_read(b);
			}
		}
	return(ret);
	}
Ejemplo n.º 5
0
static int conn_read(BIO *b, char *out, int outl)
	{
	int ret=0;
	BIO_CONNECT *data;

	data=(BIO_CONNECT *)b->ptr;
	if (data->state != BIO_CONN_S_OK)
		{
		ret=conn_state(b,data);
		if (ret <= 0)
				return(ret);
		}

	if (out != NULL)
		{
		clear_socket_error();
		ret=readsocket(b->num,out,outl);
		BIO_clear_retry_flags(b);
		if (ret <= 0)
			{
			if (BIO_sock_should_retry(ret))
				BIO_set_retry_read(b);
			}
		}
	return(ret);
	}
Ejemplo n.º 6
0
int BIO_accept(int sock, char **ip_port)
{
    BIO_ADDR res;
    int ret = -1;

    ret = BIO_accept_ex(sock, &res, 0);
    if (ret == (int)INVALID_SOCKET) {
        if (BIO_sock_should_retry(ret)) {
            ret = -2;
            goto end;
        }
        SYSerr(SYS_F_ACCEPT, get_last_socket_error());
        BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR);
        goto end;
    }

    if (ip_port != NULL) {
        char *host = BIO_ADDR_hostname_string(&res, 1);
        char *port = BIO_ADDR_service_string(&res, 1);
        *ip_port = OPENSSL_zalloc(strlen(host) + strlen(port) + 2);
        strcpy(*ip_port, host);
        strcat(*ip_port, ":");
        strcat(*ip_port, port);
        OPENSSL_free(host);
        OPENSSL_free(port);
    }

 end:
    return ret;
}
Ejemplo n.º 7
0
/*-
 * doConnection - make a connection
 * Args:
 *              scon    = earlier ssl connection for session id, or NULL
 * Returns:
 *              SSL *   = the connection pointer.
 */
static SSL *doConnection(SSL *scon)
{
    BIO *conn;
    SSL *serverCon;
    int width, i;
    fd_set readfds;

    if ((conn = BIO_new(BIO_s_connect())) == NULL)
        return (NULL);

/*      BIO_set_conn_port(conn,port);*/
    BIO_set_conn_hostname(conn, host);

    if (scon == NULL)
        serverCon = SSL_new(tm_ctx);
    else {
        serverCon = scon;
        SSL_set_connect_state(serverCon);
    }

    SSL_set_bio(serverCon, conn, conn);

    /* ok, lets connect */
    for (;;) {
        i = SSL_connect(serverCon);
        if (BIO_sock_should_retry(i)) {
            BIO_printf(bio_err, "DELAY\n");

            i = SSL_get_fd(serverCon);
            width = i + 1;
            FD_ZERO(&readfds);
            openssl_fdset(i, &readfds);
            /*
             * Note: under VMS with SOCKETSHR the 2nd parameter is currently
             * of type (int *) whereas under other systems it is (void *) if
             * you don't have a cast it will choke the compiler: if you do
             * have a cast then you can either go for (int *) or (void *).
             */
            select(width, (void *)&readfds, NULL, NULL, NULL);
            continue;
        }
        break;
    }
    if (i <= 0) {
        BIO_printf(bio_err, "ERROR\n");
        if (verify_error != X509_V_OK)
            BIO_printf(bio_err, "verify error:%s\n",
                       X509_verify_cert_error_string(verify_error));
        else
            ERR_print_errors(bio_err);
        if (scon == NULL)
            SSL_free(serverCon);
        return NULL;
    }

    return serverCon;
}
Ejemplo n.º 8
0
int OpenSSLUtils::getBioShouldRetryWrite(int r) {
  int ret = 0;
#if defined(OPENSSL_IS_BORINGSSL)
  ret = boringssl_bio_fd_should_retry(r);
#else
  ret = BIO_sock_should_retry(r);
#endif
  return ret;
}
Ejemplo n.º 9
0
/***********************************************************************
 * doConnection - make a connection
 * Args:
 *		scon	= earlier ssl connection for session id, or NULL
 * Returns:
 *		SSL *	= the connection pointer.
 */
static SSL *
doConnection(SSL * scon)
{
	BIO *conn;
	SSL *serverCon;
	int width, i;
	fd_set readfds;

	if ((conn = BIO_new(BIO_s_connect())) == NULL)
		return (NULL);

/*	BIO_set_conn_port(conn,port);*/
	BIO_set_conn_hostname(conn, host);

	if (scon == NULL)
		serverCon = SSL_new(tm_ctx);
	else {
		serverCon = scon;
		SSL_set_connect_state(serverCon);
	}

	SSL_set_bio(serverCon, conn, conn);

#if 0
	if (scon != NULL)
		SSL_set_session(serverCon, SSL_get_session(scon));
#endif

	/* ok, lets connect */
	for (;;) {
		i = SSL_connect(serverCon);
		if (BIO_sock_should_retry(i)) {
			BIO_printf(bio_err, "DELAY\n");

			i = SSL_get_fd(serverCon);
			width = i + 1;
			FD_ZERO(&readfds);
			FD_SET(i, &readfds);
			select(width, &readfds, NULL, NULL, NULL);
			continue;
		}
		break;
	}
	if (i <= 0) {
		BIO_printf(bio_err, "ERROR\n");
		if (verify_error != X509_V_OK)
			BIO_printf(bio_err, "verify error:%s\n",
			    X509_verify_cert_error_string(verify_error));
		else
			ERR_print_errors(bio_err);
		if (scon == NULL)
			SSL_free(serverCon);
		return NULL;
	}
	return serverCon;
}
Ejemplo n.º 10
0
/***********************************************************************
 * doConnection - make a connection
 * Args:
 *		scon	= earlier ssl connection for session id, or NULL
 * Returns:
 *		SSL *	= the connection pointer.
 */
static SSL *
doConnection(SSL * scon)
{
	struct pollfd pfd[1];
	SSL *serverCon;
	BIO *conn;
	long verify_error;
	int i;

	if ((conn = BIO_new(BIO_s_connect())) == NULL)
		return (NULL);

/*	BIO_set_conn_port(conn,port);*/
	BIO_set_conn_hostname(conn, s_time_config.host);

	if (scon == NULL)
		serverCon = SSL_new(tm_ctx);
	else {
		serverCon = scon;
		SSL_set_connect_state(serverCon);
	}

	SSL_set_bio(serverCon, conn, conn);

	/* ok, lets connect */
	for (;;) {
		i = SSL_connect(serverCon);
		if (BIO_sock_should_retry(i)) {
			BIO_printf(bio_err, "DELAY\n");

			i = SSL_get_fd(serverCon);
			pfd[0].fd = i;
			pfd[0].events = POLLIN;
			poll(pfd, 1, -1);
			continue;
		}
		break;
	}
	if (i <= 0) {
		BIO_printf(bio_err, "ERROR\n");
		verify_error = SSL_get_verify_result(serverCon);
		if (verify_error != X509_V_OK)
			BIO_printf(bio_err, "verify error:%s\n",
			    X509_verify_cert_error_string(verify_error));
		else
			ERR_print_errors(bio_err);
		if (scon == NULL)
			SSL_free(serverCon);
		return NULL;
	}
	return serverCon;
}
Ejemplo n.º 11
0
static int sock_write(BIO *b, const char *in, int inl)
{
    int ret;

    clear_socket_error();
    ret = writesocket(b->num, in, inl);
    BIO_clear_retry_flags(b);
    if (ret <= 0) {
        if (BIO_sock_should_retry(ret))
            BIO_set_retry_write(b);
    }
    return (ret);
}
Ejemplo n.º 12
0
static int sock_read(BIO *b, char *out, int outl)
{
    int ret = 0;

    if (out != NULL) {
        clear_socket_error();
        ret = readsocket(b->num, out, outl);
        BIO_clear_retry_flags(b);
        if (ret <= 0) {
            if (BIO_sock_should_retry(ret))
                BIO_set_retry_read(b);
        }
    }
    return (ret);
}
Ejemplo n.º 13
0
int BIO_accept(int sock, char **addr)
	{
	int ret=INVALID_SOCKET;
	static struct sockaddr_in from;
	unsigned long l;
	unsigned short port;
	int len;
	char *p;

	memset((char *)&from,0,sizeof(from));
	len=sizeof(from);
	/* Note: under VMS with SOCKETSHR the fourth parameter is currently
	 * of type (int *) whereas under other systems it is (void *) if
	 * you don't have a cast it will choke the compiler: if you do
	 * have a cast then you can either go for (int *) or (void *).
	 */
	ret=accept(sock,(struct sockaddr *)&from,(void *)&len);
	if (ret == INVALID_SOCKET)
		{
		if(BIO_sock_should_retry(ret)) return -2;
		SYSerr(SYS_F_ACCEPT,get_last_socket_error());
		BIOerr(BIO_F_BIO_ACCEPT,BIO_R_ACCEPT_ERROR);
		goto end;
		}

	if (addr == NULL) goto end;

	l=ntohl(from.sin_addr.s_addr);
	port=ntohs(from.sin_port);
	if (*addr == NULL)
		{
		if ((p=OPENSSL_malloc(24)) == NULL)
			{
			BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
			goto end;
			}
		*addr=p;
		}
	BIO_snprintf(*addr,24,"%d.%d.%d.%d:%d",
		     (unsigned char)(l>>24L)&0xff,
		     (unsigned char)(l>>16L)&0xff,
		     (unsigned char)(l>> 8L)&0xff,
		     (unsigned char)(l     )&0xff,
		     port);
end:
	return(ret);
	}
Ejemplo n.º 14
0
int ipfix_ssl_init_con( SSL *con )
{
    extern FILE *mlog_fp; // todo: see if this is working
    int i;
    char *str;
    long verify_error;
    char buf[100];

    if ((i=SSL_accept(con)) <= 0) {
        if (BIO_sock_should_retry(i)) {
            mlogf( 0, "[ipfix_ssl_init] DELAY\n");
            return -1;
        }

        mlogf( 0, "[ipfix_ssl_init] ERROR\n");
        verify_error=SSL_get_verify_result( con );
        if (verify_error != X509_V_OK) {
            mlogf( 0, "[ipfix_ssl_init] verify error: %s\n",
                   X509_verify_cert_error_string(verify_error));
        }
        else
            ERR_print_errors_fp( mlog_fp );

        return -1;
    }

    if ( 1 <= mlog_get_vlevel() ) {
        PEM_write_SSL_SESSION( mlog_fp, SSL_get_session(con));

        if ( SSL_get_shared_ciphers(con, buf, sizeof buf) != NULL) {
            mlogf( 3, "[ipfix] Shared ciphers:%s\n", buf);
        }
        str=(char*)SSL_CIPHER_get_name( SSL_get_current_cipher(con) );
        mlogf( 3,  "[ipfix] CIPHER is %s\n",(str != NULL)?str:"(NONE)");
        if (SSL_ctrl(con,SSL_CTRL_GET_FLAGS,0,NULL) &
            TLS1_FLAGS_TLS_PADDING_BUG) {
            mlogf( 1, "[ipfix] Peer has incorrect TLSv1 block padding\n");
        }
    }

    return 0;
}
Ejemplo n.º 15
0
/*-
 * BIO_connect - connect to an address
 * @sock: the socket to connect with
 * @addr: the address to connect to
 * @options: BIO socket options
 *
 * Connects to the address using the given socket and options.
 *
 * Options can be a combination of the following:
 * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages.
 * - BIO_SOCK_NONBLOCK: Make the socket non-blocking.
 * - BIO_SOCK_NODELAY: don't delay small messages.
 *
 * options holds BIO socket options that can be used
 * You should call this for every address returned by BIO_lookup
 * until the connection is successful.
 *
 * Returns 1 on success or 0 on failure.  On failure errno is set
 * and an error status is added to the OpenSSL error stack.
 */
int BIO_connect(int sock, const BIO_ADDR *addr, int options)
{
    const int on = 1;

    if (sock == -1) {
        BIOerr(BIO_F_BIO_CONNECT, BIO_R_INVALID_SOCKET);
        return 0;
    }

    if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0))
        return 0;

    if (options & BIO_SOCK_KEEPALIVE) {
        if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
                       (const void *)&on, sizeof(on)) != 0) {
            SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
            BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_KEEPALIVE);
            return 0;
        }
    }

    if (options & BIO_SOCK_NODELAY) {
        if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
                       (const void *)&on, sizeof(on)) != 0) {
            SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
            BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_NODELAY);
            return 0;
        }
    }

    if (connect(sock, BIO_ADDR_sockaddr(addr),
                BIO_ADDR_sockaddr_size(addr)) == -1) {
        if (!BIO_sock_should_retry(-1)) {
            SYSerr(SYS_F_CONNECT, get_last_socket_error());
            BIOerr(BIO_F_BIO_CONNECT, BIO_R_CONNECT_ERROR);
        }
        return 0;
    }
    return 1;
}
Ejemplo n.º 16
0
static int conn_write(BIO *b, const char *in, int inl)
	{
	int ret;
	BIO_CONNECT *data;

	data=(BIO_CONNECT *)b->ptr;
	if (data->state != BIO_CONN_S_OK)
		{
		ret=conn_state(b,data);
		if (ret <= 0) return(ret);
		}

	clear_socket_error();
	ret=writesocket(b->num,in,inl);
	BIO_clear_retry_flags(b);
	if (ret <= 0)
		{
		if (BIO_sock_should_retry(ret))
			BIO_set_retry_write(b);
		}
	return(ret);
	}
Ejemplo n.º 17
0
static int fd_write(BIO *b, const char *in, int inl)
#endif
	{
	int ret;
	
#ifndef BIO_FD
	clear_socket_error();
	ret=writesocket(b->num,in,inl);
#else
	clear_sys_error();
	ret=write(b->num,in,inl);
#endif
	BIO_clear_retry_flags(b);
	if (ret <= 0)
		{
#ifndef BIO_FD
		if (BIO_sock_should_retry(ret))
#else
		if (BIO_fd_should_retry(ret))
#endif
			BIO_set_retry_write(b);
		}
	return(ret);
	}
Ejemplo n.º 18
0
int
BIO_accept(int sock, char **addr)
{
	int ret = -1;
	unsigned long l;
	unsigned short port;
	char *p, *tmp;

	struct {
		socklen_t len;
		union {
			struct sockaddr sa;
			struct sockaddr_in sa_in;
			struct sockaddr_in6 sa_in6;
		} from;
	} sa;

	sa.len = sizeof(sa.from);
	memset(&sa.from, 0, sizeof(sa.from));
	ret = accept(sock, &sa.from.sa, &sa.len);
	if (ret == -1) {
		if (BIO_sock_should_retry(ret))
			return -2;
		SYSerr(SYS_F_ACCEPT, errno);
		BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR);
		goto end;
	}

	if (addr == NULL)
		goto end;

#ifdef EAI_FAMILY
	do {
		char   h[NI_MAXHOST], s[NI_MAXSERV];
		size_t nl;

		if (getnameinfo(&sa.from.sa, sa.len, h, sizeof(h),
		    s, sizeof(s), NI_NUMERICHOST|NI_NUMERICSERV))
			break;
		nl = strlen(h) + strlen(s) + 2;
		p = *addr;
		if (p) {
			*p = '\0';
			if (!(tmp = realloc(p, nl))) {
				close(ret);
				ret = -1;
				free(p);
				*addr = NULL;
				BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
				goto end;
			}
			p = tmp;
		} else {
			p = malloc(nl);
		}
		if (p == NULL) {
			close(ret);
			ret = -1;
			BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
			goto end;
		}
		*addr = p;
		snprintf(*addr, nl, "%s:%s", h, s);
		goto end;
	} while (0);
#endif
	if (sa.from.sa.sa_family != AF_INET)
		goto end;
	l = ntohl(sa.from.sa_in.sin_addr.s_addr);
	port = ntohs(sa.from.sa_in.sin_port);
	if (*addr == NULL) {
		if ((p = malloc(24)) == NULL) {
			close(ret);
			ret = -1;
			BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
			goto end;
		}
		*addr = p;
	}
	snprintf(*addr, 24, "%d.%d.%d.%d:%d",
	    (unsigned char)(l >> 24L) & 0xff, (unsigned char)(l >> 16L) & 0xff,
	    (unsigned char)(l >> 8L) & 0xff, (unsigned char)(l) & 0xff, port);

end:
	return (ret);
}
Ejemplo n.º 19
0
static int acpt_state(BIO *b, BIO_ACCEPT *c)
{
    BIO *bio = NULL, *dbio;
    int s = -1, ret = -1;

    for (;;) {
        switch (c->state) {
        case ACPT_S_BEFORE:
            if (c->param_addr == NULL && c->param_serv == NULL) {
                BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED);
                ERR_add_error_data(4,
                                   "hostname=", c->param_addr,
                                   " service=", c->param_serv);
                goto exit_loop;
            }

            /* Because we're starting a new bind, any cached name and serv
             * are now obsolete and need to be cleaned out.
             * QUESTION: should this be done in acpt_close_socket() instead?
             */
            OPENSSL_free(c->cache_accepting_name);
            c->cache_accepting_name = NULL;
            OPENSSL_free(c->cache_accepting_serv);
            c->cache_accepting_serv = NULL;
            OPENSSL_free(c->cache_peer_name);
            c->cache_peer_name = NULL;
            OPENSSL_free(c->cache_peer_serv);
            c->cache_peer_serv = NULL;

            c->state = ACPT_S_GET_ADDR;
            break;

        case ACPT_S_GET_ADDR:
            {
                int family = AF_UNSPEC;
                switch (c->accept_family) {
                case BIO_FAMILY_IPV6:
                    if (1) { /* This is a trick we use to avoid bit rot.
                              * at least the "else" part will always be
                              * compiled.
                              */
#ifdef AF_INET6
                        family = AF_INET6;
                    } else {
#endif
                        BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY);
                        goto exit_loop;
                    }
                    break;
                case BIO_FAMILY_IPV4:
                    family = AF_INET;
                    break;
                case BIO_FAMILY_IPANY:
                    family = AF_UNSPEC;
                    break;
                default:
                    BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY);
                    goto exit_loop;
                }
                if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER,
                               family, SOCK_STREAM, &c->addr_first) == 0)
                    goto exit_loop;
            }
            if (c->addr_first == NULL) {
                BIOerr(BIO_F_ACPT_STATE, BIO_R_LOOKUP_RETURNED_NOTHING);
                goto exit_loop;
            }
            /* We're currently not iterating, but set this as preparation
             * for possible future development in that regard
             */
            c->addr_iter = c->addr_first;
            c->state = ACPT_S_CREATE_SOCKET;
            break;

        case ACPT_S_CREATE_SOCKET:
            ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
                             BIO_ADDRINFO_socktype(c->addr_iter),
                             BIO_ADDRINFO_protocol(c->addr_iter), 0);
            if (ret == (int)INVALID_SOCKET) {
                SYSerr(SYS_F_SOCKET, get_last_socket_error());
                ERR_add_error_data(4,
                                   "hostname=", c->param_addr,
                                   " service=", c->param_serv);
                BIOerr(BIO_F_ACPT_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
                goto exit_loop;
            }
            c->accept_sock = ret;
            b->num = ret;
            c->state = ACPT_S_LISTEN;
            break;

        case ACPT_S_LISTEN:
            {
                if (!BIO_listen(c->accept_sock,
                                BIO_ADDRINFO_address(c->addr_iter),
                                c->bind_mode)) {
                    BIO_closesocket(c->accept_sock);
                    goto exit_loop;
                }
            }

            {
                union BIO_sock_info_u info;

                info.addr = &c->cache_accepting_addr;
                if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS,
                                   &info)) {
                    BIO_closesocket(c->accept_sock);
                    goto exit_loop;
                }
            }

            c->cache_accepting_name =
                BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1);
            c->cache_accepting_serv =
                BIO_ADDR_service_string(&c->cache_accepting_addr, 1);
            c->state = ACPT_S_ACCEPT;
            s = -1;
            ret = 1;
            goto end;

        case ACPT_S_ACCEPT:
            if (b->next_bio != NULL) {
                c->state = ACPT_S_OK;
                break;
            }
            BIO_clear_retry_flags(b);
            b->retry_reason = 0;

            OPENSSL_free(c->cache_peer_name);
            c->cache_peer_name = NULL;
            OPENSSL_free(c->cache_peer_serv);
            c->cache_peer_serv = NULL;

            s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr,
                              c->accepted_mode);

            /* If the returned socket is invalid, this might still be
             * retryable
             */
            if (s < 0) {
                if (BIO_sock_should_retry(s)) {
                    BIO_set_retry_special(b);
                    b->retry_reason = BIO_RR_ACCEPT;
                    goto end;
                }
            }

            /* If it wasn't retryable, we fail */
            if (s < 0) {
                ret = s;
                goto exit_loop;
            }

            bio = BIO_new_socket(s, BIO_CLOSE);
            if (bio == NULL)
                goto exit_loop;

            BIO_set_callback(bio, BIO_get_callback(b));
            BIO_set_callback_arg(bio, BIO_get_callback_arg(b));

            /*
             * If the accept BIO has an bio_chain, we dup it and put the new
             * socket at the end.
             */
            if (c->bio_chain != NULL) {
                if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL)
                    goto exit_loop;
                if (!BIO_push(dbio, bio))
                    goto exit_loop;
                bio = dbio;
            }
            if (BIO_push(b, bio) == NULL)
                goto exit_loop;

            c->cache_peer_name =
                BIO_ADDR_hostname_string(&c->cache_peer_addr, 1);
            c->cache_peer_serv =
                BIO_ADDR_service_string(&c->cache_peer_addr, 1);
            c->state = ACPT_S_OK;
            bio = NULL;
            ret = 1;
            goto end;

        case ACPT_S_OK:
            if (b->next_bio == NULL) {
                c->state = ACPT_S_ACCEPT;
                break;
            }
            ret = 1;
            goto end;

        default:
            ret = 0;
            goto end;
        }
    }

  exit_loop:
    if (bio != NULL)
        BIO_free(bio);
    else if (s >= 0)
        BIO_closesocket(s);
  end:
    return ret;
}
Ejemplo n.º 20
0
static int init_ssl_connection(SSL *con)
{
	int i;
#ifdef DEBUG
	const char *str;
	X509 *peer;
	static char buf[BUFSIZ];
#endif
	long verify_error;
	int err = 0;

	if ((i = SSL_accept(con)) <= 0)
	{
		err = SSL_get_error (con, i);
		if ((SSL_ERROR_WANT_READ == err) || (SSL_ERROR_WANT_WRITE == err))
			fprintf (stderr, "%s: %s(): Error [SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE]\n", \
				__FILE__, __func__);

		if (BIO_sock_should_retry (i))
		{
			BIO_printf(bio_s_out, "DELAY\n");
			return 1;
		}

		
		BIO_printf(bio_err, "ERROR\n");
		verify_error = SSL_get_verify_result (con);
		if (verify_error != X509_V_OK)
		{
			BIO_printf(bio_err,"verify error:%s\n",
				X509_verify_cert_error_string(verify_error));
		}
		else
		{
			fprintf (stderr, "%s: %s(): X509_V_OK but error\n", __FILE__, __func__);
			ERR_print_errors (bio_err);
		}
		return 0;
	}

#ifdef DEBUG
	PEM_write_bio_SSL_SESSION (bio_s_out, SSL_get_session (con));

	peer = SSL_get_peer_certificate (con);
	if (NULL != peer)
	{
		BIO_printf (bio_s_out, "Client certificate\n");
		PEM_write_bio_X509 (bio_s_out, peer);
		X509_NAME_oneline (X509_get_subject_name (peer), buf, sizeof buf);
		BIO_printf (bio_s_out, "subject = %s\n", buf);
		X509_NAME_oneline (X509_get_issuer_name (peer), buf, sizeof buf);
		BIO_printf (bio_s_out, "issuer = %s\n", buf);
		X509_free(peer);
	}

	if (SSL_get_shared_ciphers (con, buf, sizeof buf) != NULL)
		BIO_printf (bio_s_out, "Shared ciphers: %s\n", buf);
	str = SSL_CIPHER_get_name (SSL_get_current_cipher (con));
	BIO_printf (bio_s_out, "CIPHER is %s\n", (str != NULL) ? str : "(NONE)");
#endif
	if (con->hit) BIO_printf (bio_s_out, "Reused session-id\n");
	if (SSL_ctrl (con, SSL_CTRL_GET_FLAGS, 0, NULL) & TLS1_FLAGS_TLS_PADDING_BUG)
		BIO_printf (bio_s_out, "Peer has incorrect TLSv1 block padding\n");

	return 1;
}
Ejemplo n.º 21
0
int BIO_accept(int sock, char **addr)
	{
	int ret=INVALID_SOCKET;
	unsigned long l;
	unsigned short port;
	char *p;

	struct {
	/*
	 * As for following union. Trouble is that there are platforms
	 * that have socklen_t and there are platforms that don't, on
	 * some platforms socklen_t is int and on some size_t. So what
	 * one can do? One can cook #ifdef spaghetti, which is nothing
	 * but masochistic. Or one can do union between int and size_t.
	 * One naturally does it primarily for 64-bit platforms where
	 * sizeof(int) != sizeof(size_t). But would it work? Note that
	 * if size_t member is initialized to 0, then later int member
	 * assignment naturally does the job on little-endian platforms
	 * regardless accept's expectations! What about big-endians?
	 * If accept expects int*, then it works, and if size_t*, then
	 * length value would appear as unreasonably large. But this
	 * won't prevent it from filling in the address structure. The
	 * trouble of course would be if accept returns more data than
	 * actual buffer can accomodate and overwrite stack... That's
	 * where early OPENSSL_assert comes into picture. Besides, the
	 * only 64-bit big-endian platform found so far that expects
	 * size_t* is HP-UX, where stack grows towards higher address.
	 * <appro>
	 */
	union { size_t s; int i; } len;
	union {
		struct sockaddr sa;
		struct sockaddr_in sa_in;
#if OPENSSL_USE_IPV6
		struct sockaddr_in6 sa_in6;
#endif
		} from;
	} sa;

	sa.len.s=0;
	sa.len.i=sizeof(sa.from);
	memset(&sa.from,0,sizeof(sa.from));
	ret=accept(sock,&sa.from.sa,(void *)&sa.len);
	if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0)
		{
		OPENSSL_assert(sa.len.s<=sizeof(sa.from));
		sa.len.i = (unsigned int)sa.len.s;
		}
	if (ret == INVALID_SOCKET)
		{
		if(BIO_sock_should_retry(ret)) return -2;
		SYSerr(SYS_F_ACCEPT,get_last_socket_error());
		BIOerr(BIO_F_BIO_ACCEPT,BIO_R_ACCEPT_ERROR);
		goto end;
		}

	if (addr == NULL) goto end;

#ifdef EAI_FAMILY
	do {
	char   h[NI_MAXHOST],s[NI_MAXSERV];
	size_t nl;
	static union {	void *p;
			int (*f)(const struct sockaddr *,size_t/*socklen_t*/,
				 char *,size_t,char *,size_t,int);
			} p_getnameinfo = {NULL};
			/* 2nd argument to getnameinfo is specified to
			 * be socklen_t. Unfortunately there is a number
			 * of environments where socklen_t is not defined.
			 * As it's passed by value, it's safe to pass it
			 * as size_t... <appro> */

	if (p_getnameinfo.p==NULL)
		{
		if ((p_getnameinfo.p=DSO_global_lookup("getnameinfo"))==NULL)
			p_getnameinfo.p=(void*)-1;
		}
	if (p_getnameinfo.p==(void *)-1) break;

	if ((*p_getnameinfo.f)(&sa.from.sa,sa.len.i,h,sizeof(h),s,sizeof(s),
	    NI_NUMERICHOST|NI_NUMERICSERV)) break;
	nl = strlen(h)+strlen(s)+2;
	p = *addr;
	if (p)	{ *p = '\0'; p = OPENSSL_realloc(p,nl);	}
	else	{ p = OPENSSL_malloc(nl);		}
	if (p==NULL)
		{
		BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
		goto end;
		}
	*addr = p;
	BIO_snprintf(*addr,nl,"%s:%s",h,s);
	goto end;
	} while(0);
#endif
	if (sa.from.sa.sa_family != AF_INET) goto end;
	l=ntohl(sa.from.sa_in.sin_addr.s_addr);
	port=ntohs(sa.from.sa_in.sin_port);
	if (*addr == NULL)
		{
		if ((p=OPENSSL_malloc(24)) == NULL)
			{
			BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
			goto end;
			}
		*addr=p;
		}
	BIO_snprintf(*addr,24,"%d.%d.%d.%d:%d",
		     (unsigned char)(l>>24L)&0xff,
		     (unsigned char)(l>>16L)&0xff,
		     (unsigned char)(l>> 8L)&0xff,
		     (unsigned char)(l     )&0xff,
		     port);
end:
	return(ret);
	}
Ejemplo n.º 22
0
static int conn_state(BIO *b, BIO_CONNECT *c)
	{
	int ret= -1,i;
	unsigned long l;
	char *p,*q;
	int (*cb)()=NULL;

	if (c->info_callback != NULL)
		cb=c->info_callback;

	for (;;)
		{
		switch (c->state)
			{
		case BIO_CONN_S_BEFORE:
			p=c->param_hostname;
			if (p == NULL)
				{
				BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTNAME_SPECIFIED);
				goto exit_loop;
				}
			for ( ; *p != '\0'; p++)
				{
				if ((*p == ':') || (*p == '/')) break;
				}

			i= *p;
			if ((i == ':') || (i == '/'))
				{

				*(p++)='\0';
				if (i == ':')
					{
					for (q=p; *q; q++)
						if (*q == '/')
							{
							*q='\0';
							break;
							}
					if (c->param_port != NULL)
						OPENSSL_free(c->param_port);
					c->param_port=BUF_strdup(p);
					}
				}

			if (c->param_port == NULL)
				{
				BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED);
				ERR_add_error_data(2,"host=",c->param_hostname);
				goto exit_loop;
				}
			c->state=BIO_CONN_S_GET_IP;
			break;

		case BIO_CONN_S_GET_IP:
			if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0)
				goto exit_loop;
			c->state=BIO_CONN_S_GET_PORT;
			break;

		case BIO_CONN_S_GET_PORT:
			if (c->param_port == NULL)
				{
				/* abort(); */
				goto exit_loop;
				}
			else if (BIO_get_port(c->param_port,&c->port) <= 0)
				goto exit_loop;
			c->state=BIO_CONN_S_CREATE_SOCKET;
			break;

		case BIO_CONN_S_CREATE_SOCKET:
			/* now setup address */
			memset((char *)&c->them,0,sizeof(c->them));
			c->them.sin_family=AF_INET;
			c->them.sin_port=htons((unsigned short)c->port);
			l=(unsigned long)
				((unsigned long)c->ip[0]<<24L)|
				((unsigned long)c->ip[1]<<16L)|
				((unsigned long)c->ip[2]<< 8L)|
				((unsigned long)c->ip[3]);
			c->them.sin_addr.s_addr=htonl(l);
			c->state=BIO_CONN_S_CREATE_SOCKET;

			ret=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
			if (ret == INVALID_SOCKET)
				{
				SYSerr(SYS_F_SOCKET,get_last_socket_error());
				ERR_add_error_data(4,"host=",c->param_hostname,
					":",c->param_port);
				BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET);
				goto exit_loop;
				}
			b->num=ret;
			c->state=BIO_CONN_S_NBIO;
			break;

		case BIO_CONN_S_NBIO:
			if (c->nbio)
				{
				if (!BIO_socket_nbio(b->num,1))
					{
					BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO);
					ERR_add_error_data(4,"host=",
						c->param_hostname,
						":",c->param_port);
					goto exit_loop;
					}
				}
			c->state=BIO_CONN_S_CONNECT;

#if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE)
			i=1;
			i=setsockopt(b->num,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
			if (i < 0)
				{
				SYSerr(SYS_F_SOCKET,get_last_socket_error());
				ERR_add_error_data(4,"host=",c->param_hostname,
					":",c->param_port);
				BIOerr(BIO_F_CONN_STATE,BIO_R_KEEPALIVE);
				goto exit_loop;
				}
#endif
			break;

		case BIO_CONN_S_CONNECT:
			BIO_clear_retry_flags(b);
			ret=connect(b->num,
				(struct sockaddr *)&c->them,
				sizeof(c->them));
			b->retry_reason=0;
			if (ret < 0)
				{
				if (BIO_sock_should_retry(ret))
					{
					BIO_set_retry_special(b);
					c->state=BIO_CONN_S_BLOCKED_CONNECT;
					b->retry_reason=BIO_RR_CONNECT;
					}
				else
					{
					SYSerr(SYS_F_CONNECT,get_last_socket_error());
					ERR_add_error_data(4,"host=",
						c->param_hostname,
						":",c->param_port);
					BIOerr(BIO_F_CONN_STATE,BIO_R_CONNECT_ERROR);
					}
				goto exit_loop;
				}
			else
				c->state=BIO_CONN_S_OK;
			break;

		case BIO_CONN_S_BLOCKED_CONNECT:
			i=BIO_sock_error(b->num);
			if (i)
				{
				BIO_clear_retry_flags(b);
				SYSerr(SYS_F_CONNECT,i);
				ERR_add_error_data(4,"host=",
					c->param_hostname,
					":",c->param_port);
				BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR);
				ret=0;
				goto exit_loop;
				}
			else
				c->state=BIO_CONN_S_OK;
			break;

		case BIO_CONN_S_OK:
			ret=1;
			goto exit_loop;
		default:
			/* abort(); */
			goto exit_loop;
			}

		if (cb != NULL)
			{
			if (!(ret=cb((BIO *)b,c->state,ret)))
				goto end;
			}
		}

	/* Loop does not exit */
exit_loop:
	if (cb != NULL)
		ret=cb((BIO *)b,c->state,ret);
end:
	return(ret);
	}