Building problems with evhtp

This commit is contained in:
Olof hagsand 2021-03-31 12:55:38 +02:00
parent c7e7598e3b
commit e9df7b81f2
10 changed files with 134 additions and 109 deletions

View file

@ -12,9 +12,9 @@ There are two installation instructions: for libevhtp and nginx.
Download, build and install libevhtp from source. Prereqs: libevent and cmake.
```
git clone https://github.com/clicon/libevhtp.git
cd libevhtp/build
cmake -DEVHTP_DISABLE_REGEX=ON -DEVHTP_DISABLE_EVTHR=ON ..
sudo git clone https://github.com/clicon/clixon-libevhtp.git
cd clixon-libevhtp
./configure --libdir=/usr/lib
make
sudo make install
```

View file

@ -50,6 +50,9 @@
#include <openssl/err.h>
/* evhtp */
#define EVHTP_DISABLE_REGEX
#define EVHTP_DISABLE_EVTHR
#define EVHTP_EXPORT
#include <evhtp/evhtp.h>
/* cligen */

View file

@ -134,6 +134,7 @@
#include <pwd.h>
#include <ctype.h>
#include <assert.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
@ -151,6 +152,9 @@
/* evhtp */
#include <event2/buffer.h> /* evbuffer */
#define EVHTP_DISABLE_REGEX
#define EVHTP_DISABLE_EVTHR
#define EVHTP_EXPORT
#include <evhtp/evhtp.h>
#include <evhtp/sslutils.h> /* XXX inline this / use SSL directly */
@ -213,28 +217,24 @@ openspec_handle_set(clicon_handle h,
* see also this function in restcont_api_openssl.c
*/
static ssize_t
evbuf_write(struct evbuffer *ev,
int s,
SSL *ssl)
buf_write(char *buf,
size_t buflen,
int s,
SSL *ssl)
{
ssize_t retval = -1;
size_t buflen;
unsigned char *buf;
int ret;
if ((buflen = evbuffer_get_length(ev)) > 0){
buf = evbuffer_pullup(ev, -1);
if (ssl){
if ((ret = SSL_write(ssl, buf, buflen)) <= 0){
clicon_err(OE_SSL, 0, "SSL_write");
goto done;
}
if (ssl){
if ((ret = SSL_write(ssl, buf, buflen)) <= 0){
clicon_err(OE_SSL, 0, "SSL_write");
goto done;
}
else{
if (write(s, buf, buflen) < 0){
clicon_err(OE_UNIX, errno, "write");
goto done;
}
}
else{
if (write(s, buf, buflen) < 0){
clicon_err(OE_UNIX, errno, "write");
goto done;
}
}
retval = 0;
@ -787,6 +787,25 @@ close_openssl_socket(int s,
return retval;
}
/*! Send initial bad request reply before actual packet received, just after accept
* @param[in] ssl if set, it will be freed
*/
static int
accept_badrequest(clicon_handle h,
int s,
SSL *ssl)
{
int retval = -1;
char *buf = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\nContent-Type: text/plain\r\n\r\n";
clicon_debug(1, "%s", __FUNCTION__);
if (buf_write(buf, strlen(buf)+1, s, ssl) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! New data connection after accept, receive and reply on data sockte
*
* @param[in] s Socket where message arrived. read from this.
@ -798,7 +817,7 @@ close_openssl_socket(int s,
*/
static int
restconf_connection(int s,
void* arg)
void *arg)
{
int retval = -1;
evhtp_connection_t *conn = NULL;
@ -830,6 +849,7 @@ restconf_connection(int s,
}
}
if (n == 0){
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
ssl = conn->ssl;
conn->ssl = NULL;
evhtp_connection_free(conn); /* evhtp */
@ -841,27 +861,43 @@ restconf_connection(int s,
* signature:
*/
if (connection_parse_nobev(buf, n, conn) < 0){
evhtp_request_t *er;
er = evhtp_request_new(NULL, NULL);
er->conn = conn;
conn->request = er;
htparser_set_major(conn->parser, '\1');
htparser_set_minor(conn->parser, '\1');
if (restconf_badrequest(h, er) < 0)
clicon_debug(1, "%s connection_parse error", __FUNCTION__);
if (accept_badrequest(h, s, conn->ssl) < 0)
goto done;
if (conn->bev != NULL)
if (evbuf_write(bufferevent_get_output(conn->bev), s, NULL) < 0)
goto done;
evhtp_connection_free(conn);
SSL_free(ssl);
if (close_openssl_socket(s, NULL) < 0)
goto done;
conn->ssl = NULL;
evhtp_connection_free(conn);
goto ok;
}
if (conn->bev != NULL){
/* This is for 100 Continue, typically bev is set but output is empty
* if sent by fini callback
*/
if (evbuf_write(bufferevent_get_output(conn->bev), conn->sock, conn->ssl) < 0)
char *buf = NULL;
size_t buflen;
struct evbuffer *ev;
if ((ev = bufferevent_get_output(conn->bev)) != NULL){
buf = (char*)evbuffer_pullup(ev, -1);
buflen = evbuffer_get_length(ev);
if (buflen){
if (buf_write(buf, buflen, conn->sock, conn->ssl) < 0)
goto done;
}
else{
clicon_debug(1, "%s bev is NULL 1", __FUNCTION__);
if (accept_badrequest(h, s, conn->ssl) < 0) /* actually error */
goto done;
}
}
else{
clicon_debug(1, "%s bev is NULL 2", __FUNCTION__);
if (accept_badrequest(h, s, conn->ssl) < 0) /* actually error */
goto done;
}
}
else{
clicon_debug(1, "%s bev is NULL 3", __FUNCTION__);
if (accept_badrequest(h, s, conn->ssl) < 0) /* actually error */
goto done;
}
ok:
@ -935,43 +971,6 @@ restconf_checkcert_file(cxobj *xrestconf,
return retval;
}
/*! Send initial bad request reply before actual packet received, just after accept
* @param[in] ssl if set, it will be freed
*/
static int
accept_badrequest(clicon_handle h,
int s,
SSL *ssl,
evhtp_connection_t *conn)
{
int retval = -1;
evhtp_request_t *er;
/*
* Since message has not been read, the reply is constructed manually
* using http 1.1
* See note (1) http to https port:
*/
er = evhtp_request_new(NULL, NULL);
er->conn = conn;
conn->request = er;
conn->ssl = NULL;
htparser_set_major(conn->parser, '\1');
htparser_set_minor(conn->parser, '\1');
if (restconf_badrequest(h, er) < 0)
goto done;
/* XXX: should there be a body? */
if (conn->bev != NULL)
if (evbuf_write(bufferevent_get_output(conn->bev), s, ssl) < 0)
goto done;
evhtp_connection_free(conn);
if (close_openssl_socket(s, ssl) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! Accept new socket client
* @param[in] fd Socket (unix or ip)
* @param[in] arg typecast clicon_handle
@ -993,7 +992,8 @@ restconf_accept_client(int fd,
int ret;
evhtp_t *evhtp = NULL;
evhtp_connection_t *conn;
int e;
clicon_debug(1, "%s %d", __FUNCTION__, fd);
if (rsock == NULL){
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
@ -1052,17 +1052,23 @@ restconf_accept_client(int fd,
* Both error cases: Call SSL_get_error() with the return value ret
*/
if ((ret = SSL_accept(ssl)) != 1) {
int e = SSL_get_error(ssl, ret);
e = SSL_get_error(ssl, ret);
switch (e){
case SSL_ERROR_SSL: { /* 1 */
if (accept_badrequest(h, s, NULL, conn) < 0)
case SSL_ERROR_SSL: /* 1 */
clicon_debug(1, "%s SSL_ERROR_SSL (not ssl mesage on ssl socket)", __FUNCTION__);
if (accept_badrequest(h, s, NULL) < 0)
goto done;
SSL_free(ssl);
if (close_openssl_socket(s, NULL) < 0)
goto done;
conn->ssl = NULL;
evhtp_connection_free(conn);
goto ok;
}
break;
case SSL_ERROR_SYSCALL: /* 5 */
/* look at error stack/return value/errno */
clicon_debug(1, "%s SSL_ERROR_SYSCALL", __FUNCTION__);
SSL_free(ssl);
if (close_openssl_socket(s, NULL) < 0)
goto done;
@ -1092,8 +1098,18 @@ restconf_accept_client(int fd,
*/
if (restconf_auth_type_get(h) == CLIXON_AUTH_CLIENT_CERTIFICATE &&
SSL_get_peer_certificate(ssl) == NULL) { /* Get certificates (if available) */
if (accept_badrequest(h, s, ssl, conn) < 0)
if (accept_badrequest(h, s, ssl) < 0)
goto done;
if (ssl){
if ((ret = SSL_shutdown(ssl)) < 0){
int e = SSL_get_error(ssl, ret);
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
goto done;
}
SSL_free(ssl);
}
// close(s); Error (56 != 0) in Test14 [No cert: certificate required]:
// clixon_event_unreg_fd(s, restconf_connection);
goto ok;
}
/* Get the actual peer, XXX this maybe could be done in ca-auth client-cert code ?