+/*
+ * Copyright (c) 2016, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
#include <gsscon.h>
+#include <gssapi.h>
#include <fcntl.h>
#include <talloc.h>
#include <unistd.h>
#include <tr_debug.h>
#include <trp_internal.h>
+#include <tr_socket.h>
/* Threading note: mutex lock is only used for protecting get_status() and set_status().
* If needed, locking for other operations (notably adding/removing connections) must be managed
conn->fd=fd;
}
+/* we use the gss name of the peer to identify it */
+static TRP_RC trp_connection_set_peer(TRP_CONNECTION *conn)
+{
+ OM_uint32 major_status=0;
+ OM_uint32 minor_status=0;
+ gss_name_t source_name=GSS_C_NO_NAME;
+ gss_name_t target_name=GSS_C_NO_NAME;
+ gss_buffer_desc peer_display_name={0,NULL};
+ int local=0;
+
+ major_status=gss_inquire_context(&minor_status,
+ *trp_connection_get_gssctx(conn),
+ &source_name,
+ &target_name,
+ NULL,
+ NULL,
+ NULL,
+ &local,
+ NULL);
+
+ if (major_status != GSS_S_COMPLETE) {
+ tr_err("trp_connection_set_peer: unable to identify GSS peer.");
+ if (source_name!=GSS_C_NO_NAME)
+ gss_release_name(&minor_status, &source_name);
+ if (target_name!=GSS_C_NO_NAME)
+ gss_release_name(&minor_status, &target_name);
+ return TRP_ERROR;
+ }
+
+ if (local) {
+ /* we are the source, peer is the target */
+ major_status=gss_display_name(&minor_status, target_name, &peer_display_name, NULL);
+ } else {
+ /* we are the target, peer is the source */
+ major_status=gss_display_name(&minor_status, source_name, &peer_display_name, NULL);
+ }
+ gss_release_name(&minor_status, &source_name);
+ gss_release_name(&minor_status, &target_name);
+
+ conn->peer=tr_new_name(peer_display_name.value);
+ if (conn->peer==NULL)
+ tr_err("trp_connection_set_peer: unable to allocate peer name.");
+ else {
+ if (conn->peer->len != peer_display_name.length) {
+ tr_err("trp_connection_set_peer: error converting GSS display name to TR_NAME.");
+ tr_free_name(conn->peer);
+ conn->peer=NULL;
+ }
+ }
+ gss_release_buffer(&minor_status, &peer_display_name);
+
+ if (conn->peer==NULL)
+ return TRP_ERROR;
+
+ tr_debug("trp_connection_set_peer: set peer for %p to %.*s (%p).", conn, conn->peer->len, conn->peer->buf, conn->peer);
+ return TRP_SUCCESS;
+}
+
+TR_NAME *trp_connection_get_peer(TRP_CONNECTION *conn)
+{
+ return conn->peer;
+}
+
TR_NAME *trp_connection_get_gssname(TRP_CONNECTION *conn)
{
return conn->gssname;
TRP_CONNECTION_STATUS trp_connection_get_status(TRP_CONNECTION *conn)
{
- TRP_CONNECTION_STATUS status;
+ TRP_CONNECTION_STATUS status=TRP_CONNECTION_UNKNOWN;
trp_connection_lock(conn);
status=conn->status;
trp_connection_unlock(conn);
static void trp_connection_set_status(TRP_CONNECTION *conn, TRP_CONNECTION_STATUS status)
{
+ TRP_CONNECTION_STATUS old_status=TRP_CONNECTION_UNKNOWN;
trp_connection_lock(conn);
+ old_status=conn->status;
conn->status=status;
trp_connection_unlock(conn);
+ if ((status!=old_status) && (conn->status_change_cb!=NULL))
+ conn->status_change_cb(conn, conn->status_change_cookie);
}
pthread_t *trp_connection_get_thread(TRP_CONNECTION *conn)
static int trp_connection_destructor(void *object)
{
TRP_CONNECTION *conn=talloc_get_type_abort(object, TRP_CONNECTION); /* aborts on wrong type */
- if ((trp_connection_get_status(conn)!=TRP_CONNECTION_DOWN)
+ if ((trp_connection_get_status(conn)!=TRP_CONNECTION_CLOSED)
&& (trp_connection_get_fd(conn)!=-1))
close(trp_connection_get_fd(conn));
+ if (conn->peer!=NULL)
+ tr_free_name(conn->peer);
if (conn->gssname!=NULL)
tr_free_name(conn->gssname);
return 0;
trp_connection_set_fd(new_conn, -1);
trp_connection_set_gssname(new_conn, NULL);
trp_connection_mutex_init(new_conn);
- trp_connection_set_status(new_conn, TRP_CONNECTION_DOWN);
+ new_conn->peer=NULL; /* no true set function for this */
+ new_conn->status_change_cb=NULL;
+ new_conn->status_change_cookie=NULL;
+ new_conn->status=TRP_CONNECTION_CLOSED;
+
thread=talloc(new_conn, pthread_t);
- gssctx=talloc(new_conn, gss_ctx_id_t);
- if (gssctx==NULL) {
+ if (thread==NULL) {
talloc_free(new_conn);
return NULL;
}
- trp_connection_set_gssctx(new_conn, gssctx);
- if (thread==NULL) {
+ trp_connection_set_thread(new_conn, thread);
+
+ gssctx=talloc(new_conn, gss_ctx_id_t);
+ if (gssctx==NULL) {
talloc_free(new_conn);
return NULL;
}
- trp_connection_set_thread(new_conn, thread);
+ trp_connection_set_gssctx(new_conn, gssctx);
talloc_set_destructor((void *)new_conn, trp_connection_destructor);
}
return new_conn;
void trp_connection_close(TRP_CONNECTION *conn)
{
- close(trp_connection_get_fd(conn));
+ if ((conn->status!=TRP_CONNECTION_DOWN) && (conn->fd>0))
+ close(trp_connection_get_fd(conn));
trp_connection_set_fd(conn, -1);
trp_connection_set_status(conn, TRP_CONNECTION_DOWN);
}
gss_buffer_desc nameBuffer = {0, NULL};
gss_ctx_id_t *gssctx=trp_connection_get_gssctx(conn);
- /* TODO: shouldn't really peek into TR_NAME... */
nameBuffer.length = trp_connection_get_gssname(conn)->len;
- nameBuffer.value = trp_connection_get_gssname(conn)->buf;
+ nameBuffer.value = tr_name_strdup(trp_connection_get_gssname(conn));
tr_debug("trp_connection_auth: beginning passive authentication");
+ if (trp_connection_get_status(conn)!=TRP_CONNECTION_AUTHORIZING)
+ tr_warning("trp_connection_auth: warning: connection was not in TRP_CONNECTION_AUTHORIZING state.");
+
rc = gsscon_passive_authenticate(trp_connection_get_fd(conn), nameBuffer, gssctx, auth_callback, callback_data);
gss_release_buffer(NULL, &nameBuffer);
if (rc!=0) {
tr_debug("trp_connection_auth: Error from gsscon_passive_authenticate(), rc = 0x%08X.", rc);
+ trp_connection_set_status(conn, TRP_CONNECTION_DOWN);
return -1;
}
if (rc = gsscon_authorize(*gssctx, &auth, &autherr)) {
tr_debug("trp_connection_auth: Error from gsscon_authorize, rc = %d, autherr = %d.",
rc, autherr);
+ trp_connection_set_status(conn, TRP_CONNECTION_DOWN);
return -1;
}
+ trp_connection_set_peer(conn);
+ trp_connection_set_status(conn, TRP_CONNECTION_UP);
+
if (auth)
tr_debug("trp_connection_auth: Connection authenticated, fd = %d.", trp_connection_get_fd(conn));
else
int conn_fd=-1;
TRP_CONNECTION *conn=NULL;
- conn_fd = accept(listen, NULL, NULL);
+ conn_fd = tr_sock_accept(listen);
if (0 > conn_fd) {
- tr_notice("trp_connection_accept: accept() returned error.");
+ tr_notice("trp_connection_accept: Error accepting connection.");
return NULL;
}
conn=trp_connection_new(mem_ctx);
trp_connection_set_fd(conn, conn_fd);
trp_connection_set_gssname(conn, gssname);
- trp_connection_set_status(conn, TRP_CONNECTION_UP);
+ trp_connection_set_status(conn, TRP_CONNECTION_AUTHORIZING);
return conn;
}
/* Initiate connection */
-TRP_RC trp_connection_initiate(TRP_CONNECTION *conn, const char *server, unsigned int port)
+TRP_RC trp_connection_initiate(TRP_CONNECTION *conn, char *server, unsigned int port)
{
int err = 0;
int fd=-1;
"trustrouter",
&fd,
trp_connection_get_gssctx(conn));
- tr_debug("trp_connection_initiate: connected");
-
if (err) {
- talloc_free(conn);
+ tr_err("trp_connection_initiate: connection failed.");
return TRP_ERROR;
} else {
+ tr_debug("trp_connection_initiate: connected.");
trp_connection_set_fd(conn, fd);
+ if (trp_connection_set_peer(conn)!=TRP_SUCCESS) {
+ tr_err("trp_connection_initiate: error setting peer gssname.");
+ trp_connection_close(conn);
+ return TRP_ERROR;
+ }
trp_connection_set_status(conn, TRP_CONNECTION_UP);
return TRP_SUCCESS;
}