summaryrefslogtreecommitdiffstats
path: root/servers/auth_server_lin/src/auth_conn.cpp
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-06-17 15:54:24 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-06-17 15:54:24 -0500
commit0e11c4ce6d21acd0139345c19b6341971e679b23 (patch)
tree361adc3f2312984ba2fbf2e3189e41a55d292648 /servers/auth_server_lin/src/auth_conn.cpp
parent2c6c71334b9a5a9ee9211e4b389a239273642313 (diff)
downloadulab-0e11c4ce6d21acd0139345c19b6341971e679b23.tar.gz
ulab-0e11c4ce6d21acd0139345c19b6341971e679b23.zip
Write initial SASL/GSSAPI Kerberos classes and server code
Diffstat (limited to 'servers/auth_server_lin/src/auth_conn.cpp')
-rw-r--r--servers/auth_server_lin/src/auth_conn.cpp356
1 files changed, 356 insertions, 0 deletions
diff --git a/servers/auth_server_lin/src/auth_conn.cpp b/servers/auth_server_lin/src/auth_conn.cpp
new file mode 100644
index 0000000..517f570
--- /dev/null
+++ b/servers/auth_server_lin/src/auth_conn.cpp
@@ -0,0 +1,356 @@
+/*
+ * Remote Laboratory Authentication Server
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (c) 2012 Timothy Pearson
+ * Raptor Engineering
+ * http://www.raptorengineeringinc.com
+ */
+
+#include <stdlib.h>
+
+#include "auth_conn.h"
+
+/*
+ The AuthSocket class provides a socket that is connected with a client.
+ For every client that connects to the server, the server creates a new
+ instance of this class.
+*/
+AuthSocket::AuthSocket(int sock, TQObject *parent, const char *name) :
+ TQSocket( parent, name ) {
+
+ iplocal = NULL;
+ ipremote = NULL;
+ searchpath = NULL;
+ service = "remotefpga";
+ localdomain = NULL;
+ userdomain = NULL;
+ conn = NULL;
+
+ line = 0;
+ connect(this, SIGNAL(connectionClosed()), SLOT(deleteLater()));
+ connect(this, SIGNAL(connectionClosed()), SLOT(connectionClosedHandler()));
+ setSocket( sock );
+}
+
+AuthSocket::~AuthSocket() {
+ //
+}
+
+void AuthSocket::close() {
+ TQSocket::close();
+ connectionClosedHandler();
+}
+
+void AuthSocket::connectionClosedHandler() {
+ printf("[DEBUG] Connection from %s closed\n\r", m_remoteHost.ascii());
+}
+
+int AuthSocket::initiateKerberosHandshake() {
+ return authenticate_connection_with_kerberos(socket());
+}
+
+#define NET_SEC_BUF_SIZE (2048)
+
+static int sasl_my_log(void *context __attribute__((unused)), int priority, const char *message) {
+ const char *label;
+
+ if (!message) {
+ return SASL_BADPARAM;
+ }
+
+ switch (priority) {
+ case SASL_LOG_ERR:
+ label = "Error";
+ break;
+ case SASL_LOG_NOTE:
+ label = "Info";
+ break;
+ default:
+ label = "Other";
+ break;
+ }
+
+ printf("[SASL %s] %s\n\r", label, message);
+
+ return SASL_OK;
+}
+
+sasl_callback_t callbacks[] = {
+ {SASL_CB_LOG, (sasl_callback_ft)&sasl_my_log, NULL},
+ {SASL_CB_LIST_END, NULL, NULL}
+};
+
+void AuthSocket::free_conn(void) {
+ if (conn) {
+ sasl_dispose(&conn);
+ }
+}
+
+void AuthSocket::send_sasl_data_to_network(const char *buffer, unsigned length, int netfd)
+{
+ char *buf;
+ unsigned len, alloclen;
+ int result;
+ char txbuf[NET_SEC_BUF_SIZE];
+
+ alloclen = ((length / 3) + 1) * 4 + 1;
+ buf = (char*)malloc(alloclen);
+ if (!buf) {
+ printf("[ERROR] Unable to malloc()!\n\r");
+ return;
+ }
+
+ result = sasl_encode64(buffer, length, buf, alloclen, &len);
+ if (result != SASL_OK) {
+ printf("[ERROR] Encoding data in base64 returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ return;
+ }
+
+ sprintf(txbuf, "%s\n", buf);
+ write(netfd, txbuf, strlen(txbuf));
+
+ free(buf);
+}
+
+unsigned int AuthSocket::get_sasl_data_from_network(char *buf) {
+ unsigned int len;
+ int result;
+
+ len = 0;
+ while (1) {
+ tqApp->processEvents();
+ if (state() != TQSocket::Connected) {
+ return -1;
+ }
+ if (readBlock(buf+len, 1) > 0) {
+ if (buf[len] == '\n') {
+ buf[len] = 0;
+ break;
+ }
+ if (buf[len] != '\r') {
+ len++;
+ }
+ }
+ if (len >= NET_SEC_BUF_SIZE) {
+ break;
+ }
+ }
+
+ len = strlen(buf);
+ result = sasl_decode64(buf, (unsigned) strlen(buf), buf, NET_SEC_BUF_SIZE, &len);
+ if (result != SASL_OK) {
+ printf("[ERROR] Decoding data from base64 returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ return -1;
+ }
+ buf[len] = '\0';
+
+ return len;
+}
+
+int AuthSocket::write_data_to_client(int fd, const char* readbuf, int cc) {
+ int result = 0;
+ unsigned int len;
+ const char *data;
+
+ result=sasl_encode(conn, readbuf, cc, &data, &len);
+ if (result != SASL_OK) {
+ printf("[ERROR] Encrypting data returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ return -1;
+ }
+ send_sasl_data_to_network(data, len, fd);
+
+ return 0;
+}
+
+int AuthSocket::receive_data_from_client(char *buf, int netfd) {
+ unsigned int recv_len;
+ const char *recv_data;
+ int result;
+ int len;
+
+ len = get_sasl_data_from_network(buf);
+ if (len >= 0) {
+ result=sasl_decode(conn, buf, len, &recv_data, &recv_len);
+ if (result != SASL_OK) {
+ printf("[ERROR] Decrypting data returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ return -1;
+ }
+ strncpy(buf, recv_data, NET_SEC_BUF_SIZE);
+ }
+
+ return 0;
+ }
+
+int AuthSocket::authenticate_connection_with_kerberos(int netfd) {
+ char buf[NET_SEC_BUF_SIZE];
+ int result = 0;
+ int serverlast = 0;
+ sasl_security_properties_t secprops;
+ const char *ext_authid = NULL;
+ unsigned int len;
+ int count;
+ const char *data;
+ char user_authorized = 0;
+ sasl_ssf_t *ssf;
+
+ // FIXME
+ // Initialize default data structures
+ memset(&secprops, 0L, sizeof(secprops));
+ secprops.maxbufsize = NET_SEC_BUF_SIZE;
+ secprops.max_ssf = UINT_MAX;
+
+ result = sasl_server_init(callbacks, "remotefpga");
+ if (result != SASL_OK) {
+ printf("[ERROR] Initializing libsasl returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ return -1;
+ }
+
+ result = sasl_server_new(service, localdomain, userdomain, iplocal, ipremote, NULL, serverlast, &conn);
+ if (result != SASL_OK) {
+ printf("[ERROR] Allocating sasl connection state returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ return -1;
+ }
+
+ result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
+
+ if (result != SASL_OK) {
+ printf("[ERROR] Setting security properties returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ free_conn();
+ return -1;
+ }
+
+ puts("[DEBUG] Generating client mechanism list...");
+ result = sasl_listmech(conn, ext_authid, NULL, " ", NULL, &data, &len, &count);
+ if (result != SASL_OK) {
+ printf("[ERROR] Generating client mechanism list returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ free_conn();
+ return -1;
+ }
+
+ printf("[DEBUG] Sending list of %d mechanism(s)\n\r", count);
+ send_sasl_data_to_network(data, len, netfd);
+
+ printf("[DEBUG] Waiting for client mechanism...\n\r");
+ len = get_sasl_data_from_network(buf);
+ if (strlen(buf) < len) {
+ printf("[DEBUG] Initial response received (%d < %d) [%s]\n\r", strlen(buf), len, buf);
+ // An initial response is present
+ data = buf + strlen(buf) + 1;
+ len = len - (unsigned) strlen(buf) - 1;
+ }
+ else {
+ data = NULL;
+ len = 0;
+ }
+ result = sasl_server_start(conn, buf, data, len, &data, &len);
+ if (result != SASL_OK && result != SASL_CONTINUE) {
+ printf("[ERROR] Starting SASL negotiation returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ free_conn();
+ return -1;
+ }
+
+ while (result == SASL_CONTINUE) {
+ if (data) {
+ printf("[DEBUG] Sending response...\n\r");
+ send_sasl_data_to_network(data, len, netfd);
+ }
+ else {
+ printf("[ERROR] No data to send!\n\r");
+ free_conn();
+ return -1;
+ }
+ printf("[DEBUG] Waiting for client reply...\n\r");
+ len = get_sasl_data_from_network(buf);
+ data = NULL;
+ result = sasl_server_step(conn, buf, len, &data, &len);
+ if (result != SASL_OK && result != SASL_CONTINUE) {
+ printf("[ERROR] Performing SASL negotiation returned %s (%d)\n\r", sasl_errdetail(conn), result);
+ free_conn();
+ return -1;
+ }
+ }
+ printf("[DEBUG] Negotiation complete\n\r");
+
+ if(serverlast && data) {
+ printf("[DEBUG] Additional information needed to be sent\n\r");
+ send_sasl_data_to_network(data, len, netfd);
+ }
+
+ result = sasl_getprop(conn, SASL_USERNAME, (const void **)&data);
+ if (result != SASL_OK) {
+ printf("[WARNING] Unable to determine authenticated username!\n\r");
+ }
+ else {
+ printf("[DEBUG] Authenticated username: %s\n\r", data ? data : "(NULL)");
+ }
+
+ result = sasl_getprop(conn, SASL_DEFUSERREALM, (const void **)&data);
+ if (result != SASL_OK) {
+ printf("[WARNING] Unable to determine authenticated realm!\n\r");
+ }
+ else {
+ printf("[DEBUG] Authenticated realm: %s\n\r", data ? data : "(NULL)");
+ }
+
+ result = sasl_getprop(conn, SASL_SSF, (const void **)&ssf);
+ if (result != SASL_OK) {
+ printf("[WARNING] Unable to determine SSF!\n\r");
+ }
+ else {
+ printf("[DEBUG] Authenticated SSF: %d\n", *ssf);
+ }
+
+ // RAJA FIXME
+ if (user_authorized == 1) {
+ // Send list of available servers...
+ write_data_to_client(netfd, "OK�", strlen("OK�"));
+ }
+
+ write_data_to_client(netfd, "TESTING", strlen("TESTING"));
+
+ return 0;
+}
+
+/*
+ The AuthServer class handles new connections to the server. For every
+ client that connects, it creates a new AuthSocket -- that instance is now
+ responsible for the communication with that client.
+*/
+AuthServer::AuthServer(TQObject* parent) :
+ TQServerSocket( 4004, 1, parent ) {
+
+ if ( !ok() ) {
+ printf("[ERROR] Failed to bind to port 4004\n\r");
+ exit(1);
+ }
+}
+
+AuthServer::~AuthServer() {
+ //
+}
+
+void AuthServer::newConnection(int socket) {
+ AuthSocket *s = new AuthSocket(socket, this);
+ s->m_remoteHost = s->peerAddress().toString();
+ printf("[DEBUG] New connection from %s\n\r", s->m_remoteHost.ascii());
+ if (s->initiateKerberosHandshake() != 0) {
+ s->close();
+ }
+ else {
+ emit newConnect(s);
+ }
+}