Esempio n. 1
0
static OCSP_RESPONSE *ocsp_get_response(CLI *c, OCSP_REQUEST *req) {
    BIO *bio=NULL;
    OCSP_REQ_CTX *req_ctx=NULL;
    OCSP_RESPONSE *resp=NULL;
    int err;

    /* connect specified OCSP server (responder) */
    c->fd=s_socket(c->opt->ocsp_addr.sa.sa_family, SOCK_STREAM, 0,
        1, "OCSP: socket (auth_user)");
    if(c->fd<0)
        goto cleanup;
    if(connect_blocking(c, &c->opt->ocsp_addr, addr_len(&c->opt->ocsp_addr)))
        goto cleanup;
    bio=BIO_new_fd(c->fd, BIO_NOCLOSE);
    if(!bio)
        goto cleanup;
    s_log(LOG_DEBUG, "OCSP: server connected");

    /* OCSP protocol communication loop */
    req_ctx=OCSP_sendreq_new(bio, c->opt->ocsp_path, req, -1);
    if(!req_ctx) {
        sslerror("OCSP: OCSP_sendreq_new");
        goto cleanup;
    }
    while(OCSP_sendreq_nbio(&resp, req_ctx)==-1) {
        s_poll_init(c->fds);
        s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio));
        err=s_poll_wait(c->fds, c->opt->timeout_busy, 0);
        if(err==-1)
            sockerror("OCSP: s_poll_wait");
        if(err==0)
            s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded");
        if(err<=0)
            goto cleanup;
    }
    /* s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx); */
    /* http://www.mail-archive.com/[email protected]/msg61691.html */
    if(!resp) {
        if(ERR_peek_error())
            sslerror("OCSP: OCSP_sendreq_nbio");
        else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */
            s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error");
    }

cleanup:
    if(req_ctx)
        OCSP_REQ_CTX_free(req_ctx);
    if(bio)
        BIO_free_all(bio);
    if(c->fd>=0) {
        closesocket(c->fd);
        c->fd=-1; /* avoid double close on cleanup */
    }
    return resp;
}
Esempio n. 2
0
File: client.c Progetto: l7s/stunnel
static void make_sockets(CLI *c, int fd[2]) { /* make a pair of connected sockets */
#ifdef INET_SOCKET_PAIR
    SOCKADDR_UNION addr;
    socklen_t addrlen;
    int s; /* temporary socket awaiting for connection */

    s=s_socket(AF_INET, SOCK_STREAM, 0, 1, "socket#1");
    if(s<0)
        longjmp(c->err, 1);
    c->fd=s_socket(AF_INET, SOCK_STREAM, 0, 1, "socket#2");
    if(c->fd<0)
        longjmp(c->err, 1);

    addrlen=sizeof addr;
    memset(&addr, 0, addrlen);
    addr.in.sin_family=AF_INET;
    addr.in.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
    addr.in.sin_port=htons(0); /* dynamic port allocation */
    if(bind(s, &addr.sa, addrlen))
        log_error(LOG_DEBUG, get_last_socket_error(), "bind#1");
    if(bind(c->fd, &addr.sa, addrlen))
        log_error(LOG_DEBUG, get_last_socket_error(), "bind#2");

    if(listen(s, 1)) {
        closesocket(s);
        sockerror("listen");
        longjmp(c->err, 1);
    }
    if(getsockname(s, &addr.sa, &addrlen)) {
        closesocket(s);
        sockerror("getsockname");
        longjmp(c->err, 1);
    }
    if(connect_blocking(c, &addr, addr_len(addr))) {
        closesocket(s);
        longjmp(c->err, 1);
    }
    fd[0]=s_accept(s, &addr.sa, &addrlen, 1, "accept");
    if(fd[0]<0) {
        closesocket(s);
        longjmp(c->err, 1);
    }
    fd[1]=c->fd;
    c->fd=-1;
    closesocket(s); /* don't care about the result */
#else
    if(s_socketpair(AF_UNIX, SOCK_STREAM, 0, fd, 1, "socketpair"))
        longjmp(c->err, 1);
#endif
}
Esempio n. 3
0
File: client.c Progetto: l7s/stunnel
static int connect_remote(CLI *c) { /* connect remote host */
    SOCKADDR_UNION addr;
    SOCKADDR_LIST resolved_list, *address_list;
    int fd, ind_try, ind_cur;

    /* setup address_list */
    if(c->opt->option.delayed_lookup) {
        resolved_list.num=0;
        if(!name2addrlist(&resolved_list,
                c->opt->remote_address, DEFAULT_LOOPBACK)) {
            s_log(LOG_ERR, "No host resolved");
            longjmp(c->err, 1);
        }
        address_list=&resolved_list;
    } else /* use pre-resolved addresses */
        address_list=&c->opt->remote_addr;

    /* try to connect each host from the list */
    for(ind_try=0; ind_try<address_list->num; ind_try++) {
        if(c->opt->failover==FAILOVER_RR) {
            ind_cur=address_list->cur;
            /* the race condition here can be safely ignored */
            address_list->cur=(ind_cur+1)%address_list->num;
        } else { /* FAILOVER_PRIO */
            ind_cur=ind_try; /* ignore address_list->cur */
        }
        memcpy(&addr, address_list->addr+ind_cur, sizeof addr);

        c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "remote socket");
        if(c->fd<0)
            longjmp(c->err, 1);

        if(c->bind_addr.num) /* explicit local bind or transparent proxy */
            local_bind(c);

        if(connect_blocking(c, &addr, addr_len(addr))) {
            closesocket(c->fd);
            c->fd=-1;
            continue; /* next IP */
        }
        print_bound_address(c);
        fd=c->fd;
        c->fd=-1;
        return fd; /* success! */
    }
    longjmp(c->err, 1);
    return -1; /* some C compilers require a return value */
}
Esempio n. 4
0
File: client.c Progetto: l7s/stunnel
static int connect_transparent(CLI *c) { /* connect the original dst */
    SOCKADDR_UNION addr;
    socklen_t addrlen=sizeof addr;
    int retval;

    if(getsockopt(c->local_rfd.fd, SOL_IP, SO_ORIGINAL_DST,
            &addr, &addrlen)) {
        sockerror("setsockopt SO_ORIGINAL_DST");
        longjmp(c->err, 1);
    }
    c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "remote socket");
    if(c->fd<0)
        longjmp(c->err, 1);
    if(c->bind_addr.num) /* explicit local bind or transparent proxy */
        local_bind(c);
    if(connect_blocking(c, &addr, addr_len(addr)))
        longjmp(c->err, 1); /* socket closed on cleanup */
    print_bound_address(c);
    retval=c->fd;
    c->fd=-1;
    return retval; /* success! */
}
Esempio n. 5
0
static int connect_remote(CLI * c)
{
	int fd, ind_try, ind_cur;
	SOCKADDR_LIST *remote_addr;	

	remote_addr = dynamic_remote_addr(c);
	
	for (ind_try = 0; ind_try < remote_addr->num; ind_try++) {
		if (c->opt->failover == FAILOVER_RR) {
			ind_cur = remote_addr->cur;
			
			remote_addr->cur = (ind_cur + 1) % remote_addr->num;
		} else {	
			ind_cur = ind_try;	
		}

		c->fd = s_socket(remote_addr->addr[ind_cur].sa.sa_family,
				 SOCK_STREAM, 0, 1, "remote socket");
		if (c->fd < 0)
			longjmp(c->err, 1);

		local_bind(c);	

		if (connect_blocking(c, &remote_addr->addr[ind_cur],
				     addr_len(&remote_addr->addr[ind_cur]))) {
			closesocket(c->fd);
			c->fd = -1;
			continue;	
		}
		print_bound_address(c);
		fd = c->fd;
		c->fd = -1;
		return fd;	
	}
	longjmp(c->err, 1);
	return -1;		
}
Esempio n. 6
0
/* connect remote host */
static int connect_remote(CLI *c) {
    int fd, ind_try, ind_cur;
    SOCKADDR_LIST *remote_addr; /* list of connect_blocking() targets */

    remote_addr=dynamic_remote_addr(c);
    /* try to connect each host from the list */
    for(ind_try=0; ind_try<remote_addr->num; ind_try++) {
        if(c->opt->failover==FAILOVER_RR) {
            ind_cur=remote_addr->cur;
            /* the race condition here can be safely ignored */
            remote_addr->cur=(ind_cur+1)%remote_addr->num;
        } else { /* FAILOVER_PRIO */
            ind_cur=ind_try; /* ignore remote_addr->cur */
        }

        c->fd=s_socket(remote_addr->addr[ind_cur].sa.sa_family,
            SOCK_STREAM, 0, 1, "remote socket");
        if(c->fd<0)
            longjmp(c->err, 1);

        local_bind(c); /* explicit local bind or transparent proxy */

        if(connect_blocking(c, &remote_addr->addr[ind_cur],
                addr_len(&remote_addr->addr[ind_cur]))) {
            closesocket(c->fd);
            c->fd=-1;
            continue; /* next IP */
        }
        print_bound_address(c);
        fd=c->fd;
        c->fd=-1;
        return fd; /* success! */
    }
    longjmp(c->err, 1);
    return -1; /* some C compilers require a return value */
}
Esempio n. 7
0
File: client.c Progetto: l7s/stunnel
static void auth_user(CLI *c) {
#ifndef _WIN32_WCE
    struct servent *s_ent;    /* structure for getservbyname */
#endif
    SOCKADDR_UNION ident;     /* IDENT socket name */
    char *line, *type, *system, *user;

    if(!c->opt->username)
        return; /* -u option not specified */
    c->fd=s_socket(c->peer_addr.addr[0].sa.sa_family, SOCK_STREAM,
        0, 1, "socket (auth_user)");
    if(c->fd<0)
        longjmp(c->err, 1);
    memcpy(&ident, &c->peer_addr.addr[0], sizeof ident);
#ifndef _WIN32_WCE
    s_ent=getservbyname("auth", "tcp");
    if(s_ent) {
        ident.in.sin_port=s_ent->s_port;
    } else
#endif
    {
        s_log(LOG_WARNING, "Unknown service 'auth': using default 113");
        ident.in.sin_port=htons(113);
    }
    if(connect_blocking(c, &ident, addr_len(ident)))
        longjmp(c->err, 1);
    s_log(LOG_DEBUG, "IDENT server connected");
    fdprintf(c, c->fd, "%u , %u",
        ntohs(c->peer_addr.addr[0].in.sin_port),
        ntohs(c->opt->local_addr.addr[0].in.sin_port));
    line=fdgetline(c, c->fd);
    closesocket(c->fd);
    c->fd=-1; /* avoid double close on cleanup */
    type=strchr(line, ':');
    if(!type) {
        s_log(LOG_ERR, "Malformed IDENT response");
        str_free(line);
        longjmp(c->err, 1);
    }
    *type++='\0';
    system=strchr(type, ':');
    if(!system) {
        s_log(LOG_ERR, "Malformed IDENT response");
        str_free(line);
        longjmp(c->err, 1);
    }
    *system++='\0';
    if(strcmp(type, " USERID ")) {
        s_log(LOG_ERR, "Incorrect INETD response type");
        str_free(line);
        longjmp(c->err, 1);
    }
    user=strchr(system, ':');
    if(!user) {
        s_log(LOG_ERR, "Malformed IDENT response");
        str_free(line);
        longjmp(c->err, 1);
    }
    *user++='\0';
    while(*user==' ') /* skip leading spaces */
        ++user;
    if(strcmp(user, c->opt->username)) {
        safestring(user);
        s_log(LOG_WARNING, "Connection from %s REFUSED by IDENT (user %s)",
            c->accepted_address, user);
        str_free(line);
        longjmp(c->err, 1);
    }
    s_log(LOG_INFO, "IDENT authentication passed");
    str_free(line);
}
Esempio n. 8
0
static int ocsp_check(CLI *c, X509_STORE_CTX *callback_ctx) {
    int error, retval=0;
    SOCKADDR_UNION addr;
    X509 *cert;
    X509 *issuer=NULL;
    OCSP_CERTID *certID;
    BIO *bio=NULL;
    OCSP_REQUEST *request=NULL;
    OCSP_RESPONSE *response=NULL;
    OCSP_BASICRESP *basicResponse=NULL;
    ASN1_GENERALIZEDTIME *revoked_at=NULL,
        *this_update=NULL, *next_update=NULL;
    int status, reason;

    /* connect specified OCSP server (responder) */
    c->fd=s_socket(c->opt->ocsp_addr.addr[0].sa.sa_family, SOCK_STREAM, 0,
        0, "OCSP: socket (auth_user)");
    if(c->fd<0)
        return 0; /* reject connection */
    memcpy(&addr, &c->opt->ocsp_addr.addr[0], sizeof addr);
    if(connect_blocking(c, &addr, addr_len(addr)))
        goto cleanup;
    s_log(LOG_DEBUG, "OCSP: server connected");

    /* get current certificate ID */
    cert=X509_STORE_CTX_get_current_cert(callback_ctx); /* get current cert */
    if(X509_STORE_CTX_get1_issuer(&issuer, callback_ctx, cert)!=1) {
        sslerror("OCSP: X509_STORE_CTX_get1_issuer");
        goto cleanup;
    }
    certID=OCSP_cert_to_id(0, cert, issuer);
    if(!certID) {
        sslerror("OCSP: OCSP_cert_to_id");
        goto cleanup;
    }

    /* build request */
    request=OCSP_REQUEST_new();
    if(!request) {
        sslerror("OCSP: OCSP_REQUEST_new");
        goto cleanup;
    }
    if(!OCSP_request_add0_id(request, certID)) {
        sslerror("OCSP: OCSP_request_add0_id");
        goto cleanup;
    }
    OCSP_request_add1_nonce(request, 0, -1);

    /* send the request and get a response */
    /* FIXME: this code won't work with ucontext threading */
    /* (blocking sockets are used) */
    bio=BIO_new_fd(c->fd, BIO_NOCLOSE);
    response=OCSP_sendreq_bio(bio, c->opt->ocsp_path, request);
    if(!response) {
        sslerror("OCSP: OCSP_sendreq_bio");
        goto cleanup;
    }
    error=OCSP_response_status(response);
    if(error!=OCSP_RESPONSE_STATUS_SUCCESSFUL) {
        s_log(LOG_WARNING, "OCSP: Responder error: %d: %s",
            error, OCSP_response_status_str(error));
        goto cleanup;
    }
    s_log(LOG_DEBUG, "OCSP: Response received");

    /* verify the response */
    basicResponse=OCSP_response_get1_basic(response);
    if(!basicResponse) {
        sslerror("OCSP: OCSP_response_get1_basic");
        goto cleanup;
    }
    if(OCSP_check_nonce(request, basicResponse)<=0) {
        sslerror("OCSP: OCSP_check_nonce");
        goto cleanup;
    }
    if(OCSP_basic_verify(basicResponse, NULL,
            c->opt->revocation_store, c->opt->ocsp_flags)<=0) {
        sslerror("OCSP: OCSP_basic_verify");
        goto cleanup;
    }
    if(!OCSP_resp_find_status(basicResponse, certID, &status, &reason,
            &revoked_at, &this_update, &next_update)) {
        sslerror("OCSP: OCSP_resp_find_status");
        goto cleanup;
    }
    s_log(LOG_NOTICE, "OCSP: Status: %d: %s",
        status, OCSP_cert_status_str(status));
    log_time(LOG_INFO, "OCSP: This update", this_update);
    log_time(LOG_INFO, "OCSP: Next update", next_update);
    /* check if the response is valid for at least one minute */
    if(!OCSP_check_validity(this_update, next_update, 60, -1)) {
        sslerror("OCSP: OCSP_check_validity");
        goto cleanup;
    }
    if(status==V_OCSP_CERTSTATUS_REVOKED) {
        if(reason==-1)
            s_log(LOG_WARNING, "OCSP: Certificate revoked");
        else
            s_log(LOG_WARNING, "OCSP: Certificate revoked: %d: %s",
                reason, OCSP_crl_reason_str(reason));
        log_time(LOG_NOTICE, "OCSP: Revoked at", revoked_at);
        goto cleanup;
    }
    retval=1; /* accept connection */
cleanup:
    if(bio)
        BIO_free_all(bio);
    if(issuer)
        X509_free(issuer);
    if(request)
        OCSP_REQUEST_free(request);
    if(response)
        OCSP_RESPONSE_free(response);
    if(basicResponse)
        OCSP_BASICRESP_free(basicResponse);
    closesocket(c->fd);
    c->fd=-1; /* avoid double close on cleanup */
    return retval;
}
Esempio n. 9
0
static void auth_user(CLI * c, char *accepted_address)
{
	struct servent *s_ent;	
	SOCKADDR_UNION ident;	
	char *line, *type, *system, *user;

	if (!c->opt->username)
		return;		
	if (c->peer_addr.sa.sa_family == AF_UNIX) {
		s_log(LOG_INFO, "IDENT not supported on Unix sockets");
		return;
	}
	c->fd = s_socket(c->peer_addr.sa.sa_family, SOCK_STREAM,
			 0, 1, "socket (auth_user)");
	if (c->fd < 0)
		longjmp(c->err, 1);
	memcpy(&ident, &c->peer_addr, c->peer_addr_len);
	s_ent = getservbyname("auth", "tcp");
	if (s_ent) {
		ident.in.sin_port = s_ent->s_port;
	} else {
		s_log(LOG_WARNING, "Unknown service 'auth': using default 113");
		ident.in.sin_port = htons(113);
	}
	if (connect_blocking(c, &ident, addr_len(&ident)))
		longjmp(c->err, 1);
	s_log(LOG_DEBUG, "IDENT server connected");
	fd_printf(c, c->fd, "%u , %u",
		  ntohs(c->peer_addr.in.sin_port),
		  ntohs(c->opt->local_addr.in.sin_port));
	line = fd_getline(c, c->fd);
	closesocket(c->fd);
	c->fd = -1;		
	type = strchr(line, ':');
	if (!type) {
		s_log(LOG_ERR, "Malformed IDENT response");
		str_free(line);
		longjmp(c->err, 1);
	}
	*type++ = '\0';
	system = strchr(type, ':');
	if (!system) {
		s_log(LOG_ERR, "Malformed IDENT response");
		str_free(line);
		longjmp(c->err, 1);
	}
	*system++ = '\0';
	if (strcmp(type, " USERID ")) {
		s_log(LOG_ERR, "Incorrect INETD response type");
		str_free(line);
		longjmp(c->err, 1);
	}
	user = strchr(system, ':');
	if (!user) {
		s_log(LOG_ERR, "Malformed IDENT response");
		str_free(line);
		longjmp(c->err, 1);
	}
	*user++ = '\0';
	while (*user == ' ')	
		++user;
	if (strcmp(user, c->opt->username)) {
		safestring(user);
		s_log(LOG_WARNING,
		      "Connection from %s REFUSED by IDENT (user %s)",
		      accepted_address, user);
		str_free(line);
		longjmp(c->err, 1);
	}
	s_log(LOG_INFO, "IDENT authentication passed");
	str_free(line);
}