203 lines
4.0 KiB
C
203 lines
4.0 KiB
C
/*
|
|
* Copyright (C) 2012 Martin Willi
|
|
* Copyright (C) 2012 revosec AG
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*/
|
|
|
|
#include "pt_tls_dispatcher.h"
|
|
#include "pt_tls_server.h"
|
|
|
|
#include <threading/thread.h>
|
|
#include <utils/debug.h>
|
|
#include <processing/jobs/callback_job.h>
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
typedef struct private_pt_tls_dispatcher_t private_pt_tls_dispatcher_t;
|
|
|
|
/**
|
|
* Private data of an pt_tls_dispatcher_t object.
|
|
*/
|
|
struct private_pt_tls_dispatcher_t {
|
|
|
|
/**
|
|
* Public pt_tls_dispatcher_t interface.
|
|
*/
|
|
pt_tls_dispatcher_t public;
|
|
|
|
/**
|
|
* Listening socket
|
|
*/
|
|
int fd;
|
|
|
|
/**
|
|
* Client authentication requirements
|
|
*/
|
|
pt_tls_auth_t auth;
|
|
|
|
/**
|
|
* Server identity
|
|
*/
|
|
identification_t *server;
|
|
|
|
/**
|
|
* Peer identity
|
|
*/
|
|
identification_t *peer;
|
|
|
|
/**
|
|
* TNCCS protocol handler constructor
|
|
*/
|
|
pt_tls_tnccs_constructor_t *create;
|
|
};
|
|
|
|
/**
|
|
* Open listening server socket
|
|
*/
|
|
static bool open_socket(private_pt_tls_dispatcher_t *this, host_t *host)
|
|
{
|
|
this->fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (this->fd == -1)
|
|
{
|
|
DBG1(DBG_TNC, "opening PT-TLS socket failed: %s", strerror(errno));
|
|
return FALSE;
|
|
}
|
|
if (bind(this->fd, host->get_sockaddr(host),
|
|
*host->get_sockaddr_len(host)) == -1)
|
|
{
|
|
DBG1(DBG_TNC, "binding to PT-TLS socket failed: %s", strerror(errno));
|
|
return FALSE;
|
|
}
|
|
if (listen(this->fd, 5) == -1)
|
|
{
|
|
DBG1(DBG_TNC, "listen on PT-TLS socket failed: %s", strerror(errno));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Handle a single PT-TLS client connection
|
|
*/
|
|
static job_requeue_t handle(pt_tls_server_t *connection)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
switch (connection->handle(connection))
|
|
{
|
|
case NEED_MORE:
|
|
continue;
|
|
case FAILED:
|
|
case SUCCESS:
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return JOB_REQUEUE_NONE;
|
|
}
|
|
|
|
/**
|
|
* Clean up connection state
|
|
*/
|
|
static void cleanup(pt_tls_server_t *connection)
|
|
{
|
|
int fd;
|
|
|
|
fd = connection->get_fd(connection);
|
|
connection->destroy(connection);
|
|
close(fd);
|
|
}
|
|
|
|
METHOD(pt_tls_dispatcher_t, dispatch, void,
|
|
private_pt_tls_dispatcher_t *this,
|
|
pt_tls_tnccs_constructor_t *create)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
pt_tls_server_t *connection;
|
|
tnccs_t *tnccs;
|
|
bool old;
|
|
int fd;
|
|
|
|
old = thread_cancelability(TRUE);
|
|
fd = accept(this->fd, NULL, NULL);
|
|
thread_cancelability(old);
|
|
if (fd == -1)
|
|
{
|
|
DBG1(DBG_TNC, "accepting PT-TLS failed: %s", strerror(errno));
|
|
continue;
|
|
}
|
|
|
|
tnccs = create(this->server, this->peer);
|
|
if (!tnccs)
|
|
{
|
|
close(fd);
|
|
continue;
|
|
}
|
|
connection = pt_tls_server_create(this->server, fd, this->auth, tnccs);
|
|
if (!connection)
|
|
{
|
|
close(fd);
|
|
continue;
|
|
}
|
|
lib->processor->queue_job(lib->processor,
|
|
(job_t*)callback_job_create_with_prio((callback_job_cb_t)handle,
|
|
connection, (void*)cleanup,
|
|
(callback_job_cancel_t)return_false,
|
|
JOB_PRIO_CRITICAL));
|
|
}
|
|
}
|
|
|
|
METHOD(pt_tls_dispatcher_t, destroy, void,
|
|
private_pt_tls_dispatcher_t *this)
|
|
{
|
|
if (this->fd != -1)
|
|
{
|
|
close(this->fd);
|
|
}
|
|
this->server->destroy(this->server);
|
|
this->peer->destroy(this->peer);
|
|
free(this);
|
|
}
|
|
|
|
/**
|
|
* See header
|
|
*/
|
|
pt_tls_dispatcher_t *pt_tls_dispatcher_create(host_t *address,
|
|
identification_t *id, pt_tls_auth_t auth)
|
|
{
|
|
private_pt_tls_dispatcher_t *this;
|
|
|
|
INIT(this,
|
|
.public = {
|
|
.dispatch = _dispatch,
|
|
.destroy = _destroy,
|
|
},
|
|
.server = id->clone(id),
|
|
/* we currently don't authenticate the peer, use %any identity */
|
|
.peer = identification_create_from_encoding(ID_ANY, chunk_empty),
|
|
.fd = -1,
|
|
.auth = auth,
|
|
);
|
|
|
|
if (!open_socket(this, address))
|
|
{
|
|
destroy(this);
|
|
return NULL;
|
|
}
|
|
|
|
return &this->public;
|
|
}
|