aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2024-09-29 18:26:07 -0400
committerIan Moffett <ian@osmora.org>2024-09-29 18:26:07 -0400
commit6107a37ae0f8ad89ab6d2d36f93cc0d47f8bb47a (patch)
treef9172d51fb8a36b934843610cdc9a38cbbfc52da
parent8e470bc3663da4a5bbb771a4a6fbaf8a4cae224d (diff)
project: Move server/client code into library
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r--client/main.c190
-rw-r--r--lib/include/libostp/server.h (renamed from ostp.d/include/net/listen.h)27
-rw-r--r--lib/include/libostp/session.h75
-rw-r--r--lib/include/net/auth.h (renamed from ostp.d/include/net/auth.h)7
-rw-r--r--lib/include/otconfig.h (renamed from ostp.d/include/otconfig.h)0
-rw-r--r--lib/libostp/auth.c (renamed from ostp.d/net/otd_auth.c)120
-rw-r--r--lib/libostp/param.c (renamed from ostp.d/net/otd_param.c)25
-rw-r--r--lib/libostp/server.c (renamed from ostp.d/net/otd_listen.c)173
-rw-r--r--lib/libostp/session.c299
-rw-r--r--ostp.d/init/main.c (renamed from ostp.d/init/otd_init.c)27
10 files changed, 600 insertions, 343 deletions
diff --git a/client/main.c b/client/main.c
index 6bc5a5e..0f87639 100644
--- a/client/main.c
+++ b/client/main.c
@@ -27,186 +27,38 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <net/stpsession.h>
-#include <net/param.h>
-#include <crypto/ecdh.h>
-#include <arpa/inet.h>
-#include <defs.h>
+#include <libostp/session.h>
#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <string.h>
#define CENTRAL_SERVER "149.248.6.149"
-#define OSTP_PORT 5352
+// #define CENTRAL_SERVER "127.0.0.1"
-static const char *pap_codestr[] = {
- [PAP_SUCCESS] = "success",
- [PAP_BAD_SPW] = "bad SPW",
- [PAP_BAD_PERMS] = "insufficient permissions",
- [PAP_RESOURCE] = "server out of resources"
-};
-
-static void
-log_pubkey(uint8_t pubkey[])
+int
+main(int argc, char **argv)
{
- for (size_t i = 0; i < 32; ++i) {
- printf("%02X ", pubkey[i] & 0xFF);
- if (i != 0 && i % 4 == 0) {
- printf("\n");
- }
+ char buf[] = "Hello, World!\n";
+ char recv_buf[4096];
+ struct ostp_session s;
+ int err;
+
+ if ((err = session_new(CENTRAL_SERVER, &s)) < 0) {
+ fprintf(stderr, "Failed to create new session!\n");
+ return err;
}
- printf("\n");
-}
-
-static int
-negotiate_spw(int sockfd, const unsigned char *session_key)
-{
- struct aes_message am;
- struct msg_frame msg_frame;
- struct pap pap;
- unsigned char *tmp;
- int error;
-
- /* Create a PAP and encrypt it */
- pap.spw = 0x8000;
- pap.code = 0;
-
- while (1) {
- if ((error = send_frame(sockfd, &pap, sizeof(pap), session_key)) < 0) {
- return error;
- }
-
- /* Receive the PAP the server replies with */
- if ((error = recv_frame(sockfd, sizeof(pap), session_key, &pap)) < 0) {
- return error;
- }
- /*
- * If the server echos our PAP with code 0 then it has
- * applied our session parameters! However, there is
- * a chance arbitration will be needed and we need
- * to look out for that too...
- */
- if (pap.code == 0) {
- printf("** Negotiation success\n");
- break;
+ if (argc >= 2) {
+ if (session_send(buf, sizeof(buf), &s) < 0) {
+ fprintf(stderr, "Failed to send data to server!\n");
+ return -1;
}
-
- printf("** Arbitration needed, server says: %s\n", pap_codestr[pap.code]);
- printf("** Server proposes SPW of 0x%0X, accepting\n", pap.spw);
- pap.spw |= PAP_SPW_QSR;
- pap.code = 0;
- }
-
- return 0;
-}
-
-static void
-recv_motd(int sockfd, const unsigned char *session_key)
-{
- char buf[4096];
- int len;
-
- /* Receive the PAP the server replies with */
- if ((len = recv_frame(sockfd, sizeof(buf), session_key, buf)) < 0) {
- printf("Failed to recv MOTD...\n");
- return;
- }
-
- buf[len] = '\0';
- printf("%s\n", buf);
-}
-
-static int
-request_session(void)
-{
- struct sockaddr_in addr;
- struct session_request stp_sq;
- struct x25519_keypair keypair;
- unsigned char serv_pubkey[32];
- unsigned char *session_key;
- int error, sockfd;
-
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = inet_addr(CENTRAL_SERVER);
- addr.sin_port = htons(OSTP_PORT);
-
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sockfd < 0) {
- return sockfd;
- }
-
- error = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
- if (error < 0) {
- printf("Failed to connect!\n");
- close(sockfd);
- return error;
- }
-
- printf("Generating keys...\n");
-
- /* Generate an ephemeral keypair */
- if ((error = gen_x25519_keypair(&keypair)) < 0) {
- printf("Key generation failed!\n");
- close(sockfd);
- return error;
- }
-
- /*
- * Setup the session request and add our public
- * key to it.
- *
- * TODO: Use the 'U' bit in options.
- */
- memset(stp_sq.hash, 0, sizeof(stp_sq.hash));
- stp_sq.options = 0;
- memcpy(stp_sq.pubkey, keypair.pubkey, sizeof(stp_sq.pubkey));
- log_pubkey(keypair.pubkey);
-
- printf("Sending session request...\n");
- error = send(sockfd, &stp_sq, sizeof(stp_sq), 0);
- if (error < 0) {
- perror("Failed to send session request");
- close(sockfd);
- return error;
- }
-
- error = recv(sockfd, serv_pubkey, sizeof(serv_pubkey), 0);
- if (error < 0) {
- perror("Failed to get public key from peer\n");
- close(sockfd);
- return error;
}
- if (error == 0) {
- printf("Connection closed by peer\n");
- close(sockfd);
- return 0;
+ if (session_recv(recv_buf, sizeof(recv_buf), &s) < 0) {
+ fprintf(stderr, "Failed to recv data from server!\n");
+ return -1;
}
- printf("Got public key from server\n");
- log_pubkey(serv_pubkey);
-
- printf("Deriving session key...\n");
- gen_session_key(keypair.privkey, serv_pubkey, &session_key);
-
- /* Send server SPW bits */
- if ((error = negotiate_spw(sockfd, session_key)) < 0) {
- printf("Session Parameter Negotiation failed\n");
- free_session_key(session_key);
- close(sockfd);
- return error;
- }
-
- recv_motd(sockfd, session_key);
- free_session_key(session_key);
- close(sockfd);
+ printf("%s\n", recv_buf);
+ session_close(&s);
return 0;
}
-
-int
-main(void)
-{
- return request_session();
-}
diff --git a/ostp.d/include/net/listen.h b/lib/include/libostp/server.h
index 03ba7a4..a7a737b 100644
--- a/ostp.d/include/net/listen.h
+++ b/lib/include/libostp/server.h
@@ -27,9 +27,28 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NET_LISTEN_H_
-#define NET_LISTEN_H_
+#ifndef LIBOSTP_SERVER_H_
+#define LIBOSTP_SERVER_H_
-int net_listen(void);
+#include <sys/select.h>
+#include <libostp/session.h>
+#include <stddef.h>
-#endif /* NET_LISTEN_H_ */
+#define MAX_CLIENTS 32
+
+struct ostp_listener {
+ int(*on_recv)(struct ostp_session *session, const char *buf, size_t len);
+ int port;
+
+ /* -- Private -- */
+ int clients[MAX_CLIENTS];
+ int serv_sockfd;
+ fd_set client_fds;
+};
+
+void listener_init(struct ostp_listener *lp);
+int listener_bind(struct ostp_session *sp, struct ostp_listener *lp);
+int listener_poll(struct ostp_session *sp, struct ostp_listener *lp);
+void listener_cleanup(struct ostp_listener *lp);
+
+#endif /* !LIBOSTP_SERVER_H_ */
diff --git a/lib/include/libostp/session.h b/lib/include/libostp/session.h
new file mode 100644
index 0000000..591ac0e
--- /dev/null
+++ b/lib/include/libostp/session.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team.
+ * 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 Hyra 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 OWNER 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.
+ */
+
+#ifndef LIBOSTP_SESSION_H_
+#define LIBOSTP_SESSION_H_
+
+#include <stdint.h>
+
+#define LIBOSTP_DEBUG 1
+
+struct ostp_session {
+ unsigned char *session_key;
+ int sockfd;
+};
+
+/*
+ * Create a new ostp ostp_session.
+ *
+ * @host: IPv4 address of OST host.
+ * @res: Output for new ostp_session structure.
+ */
+int session_new(const char *host, struct ostp_session *res);
+
+/*
+ * Close an existing/running ostp_session.
+ *
+ * @ostp_session: Session to close.
+ */
+int session_close(struct ostp_session *session);
+
+/*
+ * Encrypt and send data to server.
+ *
+ * @data: Data to send.
+ * @len: Length of data.
+ * @ostp_session: Running ostp_session.
+ */
+int session_send(void *data, uint16_t len, const struct ostp_session *session);
+
+/*
+ * Receive data from the server.
+ *
+ * @buf: Buffer for received data.
+ * @len: Length of buffer.
+ * @ostp_session: Running ostp_session.
+ */
+int session_recv(void *buf, uint16_t len, const struct ostp_session *session);
+
+#endif /* LIBOSTP_SESSION_H_ */
diff --git a/ostp.d/include/net/auth.h b/lib/include/net/auth.h
index 76567c3..d672231 100644
--- a/ostp.d/include/net/auth.h
+++ b/lib/include/net/auth.h
@@ -31,8 +31,11 @@
#define NET_AUTH_H_
#include <net/stpsession.h>
+#include <libostp/session.h>
+#include <libostp/server.h>
-int handle_srq(int client_fd, struct session_request *srq);
-int negotiate_spw(int client_fd, unsigned char *session_key);
+int handle_srq(struct ostp_session *sp, struct ostp_listener *lp,
+ struct session_request *srq);
+int negotiate_spw(struct ostp_session *sp, unsigned char *session_key);
#endif /* NET_AUTH_H_ */
diff --git a/ostp.d/include/otconfig.h b/lib/include/otconfig.h
index 9487556..9487556 100644
--- a/ostp.d/include/otconfig.h
+++ b/lib/include/otconfig.h
diff --git a/ostp.d/net/otd_auth.c b/lib/libostp/auth.c
index 67b4885..d32c06a 100644
--- a/ostp.d/net/otd_auth.c
+++ b/lib/libostp/auth.c
@@ -28,41 +28,13 @@
*/
#include <sys/wait.h>
-#include <arpa/inet.h>
#include <net/auth.h>
-#include <net/listen.h>
-#include <net/param.h>
-#include <net/stpsession.h>
#include <crypto/ecdh.h>
#include <otconfig.h>
+#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
-
-#define KEY_BYTE_WIDTH 32
-
-static void
-log_pubkey(uint8_t pubkey[KEY_BYTE_WIDTH])
-{
- for (size_t i = 0; i < KEY_BYTE_WIDTH; ++i) {
- printf("%02X ", pubkey[i] & 0xFF);
- if (i != 0 && i % 4 == 0) {
- printf("\n");
- }
- }
-
- printf("\n");
-}
-
-static void
-send_motd(int client_fd, const unsigned char *session_key)
-{
- char motd[] = MOTD;
-
- printf("Sending MOTD...\n");
- if (send_frame(client_fd, motd, sizeof(motd), session_key) < 0) {
- printf("Failed to session MOTD\n");
- }
-}
+#include <stdlib.h>
/*
* Check a password to see if it matches with
@@ -95,7 +67,7 @@ pwcheck(char *username, char *pw)
}
static int
-passwd_auth(int client_fd, const unsigned char *session_key)
+passwd_auth(struct ostp_session *sp, const unsigned char *session_key)
{
int error;
struct session_auth auth;
@@ -105,7 +77,7 @@ passwd_auth(int client_fd, const unsigned char *session_key)
return 0;
}
- error = recv_frame(client_fd, sizeof(auth), session_key, &auth);
+ error = recv_frame(sp->sockfd, sizeof(auth), session_key, &auth);
if (error < 0) {
return error;
}
@@ -113,7 +85,7 @@ passwd_auth(int client_fd, const unsigned char *session_key)
if (pwcheck(auth.username, auth.password) != 0) {
printf("Got bad password for %s\n", auth.username);
auth.code = AUTH_BAD_PW;
- error = send_frame(client_fd, &auth, sizeof(auth), session_key);
+ error = send_frame(sp->sockfd, &auth, sizeof(auth), session_key);
if (error < 0) {
printf("Failed to ACK user authentication with frame\n");
}
@@ -121,7 +93,7 @@ passwd_auth(int client_fd, const unsigned char *session_key)
}
auth.code = AUTH_SUCCESS;
- error = send_frame(client_fd, &auth, sizeof(auth), session_key);
+ error = send_frame(sp->sockfd, &auth, sizeof(auth), session_key);
if (error < 0) {
printf("Failed to ACK user authentication with frame\n");
return error;
@@ -129,39 +101,52 @@ passwd_auth(int client_fd, const unsigned char *session_key)
return 0;
}
-static int
-client_echo(int client_fd, const unsigned char *session_key)
+static void
+send_motd(struct ostp_session *sp, const unsigned char *session_key)
{
- char buf[4096];
- int error;
+ char motd[] = MOTD;
- error = recv_frame(client_fd, sizeof(buf) - 1, session_key, buf);
- if (error < 0) {
- return error;
+ printf("Sending MOTD...\n");
+ if (send_frame(sp->sockfd, motd, sizeof(motd), session_key) < 0) {
+ printf("Failed to session MOTD\n");
}
+}
- /* Echo frame to all clients */
- for (size_t i = 1; i < MAX_CLIENTS; ++i) {
- if (clients[i] <= 0)
- continue;
-
- send_frame(clients[i], buf, sizeof(buf), session_key);
+static int
+session_run(struct ostp_session *sp, struct ostp_listener *lp,
+ const unsigned char *session_key)
+{
+ char buf[4096];
+ size_t len;
+
+ while (1) {
+ for (int i = 1; i < MAX_CLIENTS; ++i) {
+ if (lp->clients[i] <= 0)
+ continue;
+ if (FD_ISSET(lp->clients[i], &lp->client_fds) <= 0)
+ continue;
+
+ len = recv_frame(lp->clients[i], sizeof(buf) - 1, session_key, buf);
+ if (len < 0) {
+ printf("recv_frame() failure, packet lost\n");
+ continue;
+ }
+ if (len == 0) {
+ return 0;
+ }
+ if (lp->on_recv != NULL) {
+ lp->on_recv(sp, buf, len);
+ }
+ }
}
-
- return 0;
}
-/*
- * Verify the session request packet and handle
- * the rest.
- *
- * @client_fd: File descriptor for client socket.
- * @srq: Session request packet.
- */
+
int
-handle_srq(int client_fd, struct session_request *srq)
+handle_srq(struct ostp_session *sp, struct ostp_listener *lp, struct session_request *srq)
{
struct x25519_keypair keypair;
unsigned char *session_key;
+ pid_t child;
int error;
if (REQUIRE_USER_AUTH && !ISSET(srq->options, SESSION_REQ_USER)) {
@@ -171,8 +156,6 @@ handle_srq(int client_fd, struct session_request *srq)
return -1;
}
- printf("Got public key from peer: \n");
- log_pubkey(srq->pubkey);
printf("Generating keys...\n");
if (gen_x25519_keypair(&keypair) < 0) {
@@ -181,7 +164,7 @@ handle_srq(int client_fd, struct session_request *srq)
}
/* Send back our our public key */
- error = send(client_fd, keypair.pubkey, keypair.pubkey_len, 0);
+ error = send(sp->sockfd, keypair.pubkey, keypair.pubkey_len, 0);
if (error < 0) {
perror("Failed to send public key");
return error;
@@ -193,13 +176,24 @@ handle_srq(int client_fd, struct session_request *srq)
return error;
}
+ /* Try user auth, not needed if REQUIRE_USER_AUTH is 0 */
+ if (passwd_auth(sp, session_key) != 0) {
+ return -1;
+ }
+
/* Handle any requested session parameters */
- if ((error = negotiate_spw(client_fd, session_key)) < 0) {
+ if ((error = negotiate_spw(sp, session_key)) < 0) {
free_session_key(session_key);
return error;
}
- send_motd(client_fd, session_key);
- free_session_key(session_key);
+ send_motd(sp, session_key);
+
+ /* Dispatch a thread and handle this session */
+ child = fork();
+ if (child == 0) {
+ session_run(sp, lp, session_key);
+ exit(0);
+ }
return 0;
}
diff --git a/ostp.d/net/otd_param.c b/lib/libostp/param.c
index fe33bd8..4c14733 100644
--- a/ostp.d/net/otd_param.c
+++ b/lib/libostp/param.c
@@ -28,18 +28,17 @@
*/
#include <net/stpsession.h>
-#include <net/param.h>
+#include <libostp/session.h>
#include <crypto/aes.h>
+#include <net/param.h>
+#include <net/auth.h>
#include <otconfig.h>
-#include <defs.h>
-#include <string.h>
-#include <stdlib.h>
#include <stdio.h>
static int
-handle_pap(int client_fd, const struct pap *pap, const unsigned char *session_key)
+handle_pap(struct ostp_session *sp, const struct pap *pap, const unsigned char *session_key)
{
- int error = 0;
+ int error = -1;
uint8_t attempts = 0;
struct pap tmp_pap = *pap;
const size_t LEN = sizeof(struct pap);
@@ -49,7 +48,7 @@ handle_pap(int client_fd, const struct pap *pap, const unsigned char *session_ke
/* Quick session request, jump right in! */
if (ISSET(tmp_pap.spw, PAP_SPW_QSR)) {
printf("Got QSR, starting session...\n");
- send_frame(client_fd, &tmp_pap, LEN, session_key);
+ send_frame(sp->sockfd, &tmp_pap, LEN, session_key);
return 0;
}
@@ -62,15 +61,15 @@ handle_pap(int client_fd, const struct pap *pap, const unsigned char *session_ke
printf("Got bad SPW from client\n");
printf("Attempting arbitration...\n");
- tmp_pap.spw = 0x0;
+ tmp_pap.spw = 0;
tmp_pap.code = PAP_BAD_SPW;
/* Send in PAP and wait for response */
- if ((error = send_frame(client_fd, &tmp_pap, LEN, session_key)) < 0) {
+ if ((error = send_frame(sp->sockfd, &tmp_pap, LEN, session_key)) < -1) {
printf("Failed to send PAP frame\n");
return -1;
}
- if ((error = recv_frame(client_fd, LEN, session_key, &tmp_pap)) < 0) {
+ if ((error = recv_frame(sp->sockfd, LEN, session_key, &tmp_pap)) < -1) {
printf("Failed to recv PAP frame\n");
return error;
}
@@ -82,16 +81,16 @@ handle_pap(int client_fd, const struct pap *pap, const unsigned char *session_ke
}
int
-negotiate_spw(int client_fd, unsigned char *session_key)
+negotiate_spw(struct ostp_session *sp, unsigned char *session_key)
{
const size_t LEN = sizeof(struct pap);
struct pap pap;
int error;
/* Get PAP from the network */
- if ((error = recv_frame(client_fd, LEN, session_key, &pap)) < 0) {
+ if ((error = recv_frame(sp->sockfd, LEN, session_key, &pap)) < -1) {
return error;
}
- return handle_pap(client_fd, &pap, session_key);
+ return handle_pap(sp, &pap, session_key);
}
diff --git a/ostp.d/net/otd_listen.c b/lib/libostp/server.c
index 216db33..0013ce2 100644
--- a/ostp.d/net/otd_listen.c
+++ b/lib/libostp/server.c
@@ -27,109 +27,128 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/select.h>
-#include <arpa/inet.h>
+#include <libostp/server.h>
#include <net/auth.h>
#include <net/stpsession.h>
-#include <defs.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
+#include <arpa/inet.h>
#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
-#define LISTEN_PORT 5352
#define MAX_BACKLOG 4
-#define MAX_CLIENTS 32
-
-static int serv_sock;
-static int clients[MAX_CLIENTS] = {0};
-
-static void
-signal_handle(int sig)
-{
- printf("Cleaning up... goodbye!\n");
-
- for (int i = 0; i < MAX_CLIENTS; ++i) {
- close(clients[i]);
- }
-
- close(serv_sock);
- exit(0);
-}
+#define LISTEN_PORT 5352
static int
-handle_client(struct sockaddr_in *caddr, int clientno)
+handle_client(struct sockaddr_in *caddr, struct ostp_session *sp, struct ostp_listener *lp,
+ int clientno)
{
struct session_request srq;
ssize_t nread;
- int client_fd;
- client_fd = clients[clientno];
+ sp->sockfd = lp->clients[clientno];
/* Try to read in the session request */
- if ((nread = read(client_fd, &srq, sizeof(srq))) < 0) {
+ if ((nread = read(sp->sockfd, &srq, sizeof(srq))) < 0) {
printf("Read failure...\n");
- close(client_fd);
- clients[clientno] = -1;
+ close(sp->sockfd);
+ lp->clients[clientno] = -1;
return -1;
}
if (nread == 0) {
printf("Connection closed by peer\n");
- close(client_fd);
- clients[clientno] = -1;
+ close(sp->sockfd);
+ lp->clients[clientno] = -1;
return -1;
}
/* Is this even a session request? */
if (nread != sizeof(srq)) {
printf("Rejecting data - not a session request...\n");
- close(client_fd);
- clients[clientno] = -1;
+ close(sp->sockfd);
+ lp->clients[clientno] = -1;
return -1;
}
/* Handle the session request */
- if (handle_srq(client_fd, &srq) < 0) {
- close(client_fd);
- clients[clientno] = -1;
+ if (handle_srq(sp, lp, &srq) < 0) {
+ close(sp->sockfd);
+ lp->clients[clientno] = -1;
return -1;
}
return 0;
}
-static void
-read_clients(void)
+/*
+ * Put a listener in a known state during
+ * initialization.
+ */
+void
+listener_init(struct ostp_listener *lp)
+{
+ lp->port = LISTEN_PORT;
+ lp->on_recv = NULL;
+}
+
+int
+listener_bind(struct ostp_session *sp, struct ostp_listener *lp)
+{
+ struct sockaddr_in saddr;
+ int error;
+
+ lp->serv_sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sp->sockfd < 0) {
+ perror("Failed to create socket\n");
+ return -1;
+ }
+
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = INADDR_ANY;
+ saddr.sin_port = htons(LISTEN_PORT);
+ error = bind(lp->serv_sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
+ if (error < 0) {
+ perror("Failed to bind socket\n");
+ close(lp->serv_sockfd);
+ return error;
+ }
+
+ if ((error = listen(lp->serv_sockfd, MAX_BACKLOG)) < 0) {
+ perror("Failed to listen");
+ return error;
+ }
+
+ return 0;
+}
+
+int
+listener_poll(struct ostp_session *sp, struct ostp_listener *lp)
{
struct sockaddr_in caddr;
- fd_set fds;
socklen_t caddr_len;
int client_sock, error = 0;
char *ip;
- memset(clients, -1, sizeof(clients));
- clients[0] = serv_sock;
+ memset(lp->clients, -1, sizeof(lp->clients));
+ lp->clients[0] = lp->serv_sockfd;
while (1) {
- FD_ZERO(&fds);
+ FD_ZERO(&lp->client_fds);
for (int i = 0; i < MAX_CLIENTS; ++i) {
- if (clients[i] >= 0)
- FD_SET(clients[i], &fds);
+ if (lp->clients[i] >= 0)
+ FD_SET(lp->clients[i], &lp->client_fds);
}
- if (select(1024, &fds, NULL, NULL, NULL) < 0) {
+ if (select(1024, &lp->client_fds, NULL, NULL, NULL) < 0) {
perror("select");
continue;
}
/* Check if the servers socket has new connections */
- if (FD_ISSET(serv_sock, &fds)) {
+ if (FD_ISSET(lp->serv_sockfd, &lp->client_fds)) {
caddr_len = sizeof(caddr);
- client_sock = accept(serv_sock, (struct sockaddr *)&caddr,
+ client_sock = accept(lp->serv_sockfd, (struct sockaddr *)&caddr,
&caddr_len);
if (client_sock < 0) {
@@ -138,8 +157,8 @@ read_clients(void)
}
for (int i = 0; i < MAX_CLIENTS; ++i) {
- if (clients[i] < 0) {
- clients[i] = client_sock;
+ if (lp->clients[i] < 0) {
+ lp->clients[i] = client_sock;
ip = inet_ntoa(caddr.sin_addr);
printf("Incoming connection from %s\n", ip);
break;
@@ -147,56 +166,30 @@ read_clients(void)
}
}
- /* Handle from data from clients */
+ /* Handle from data from lp->clients */
for (int i = 1; i < MAX_CLIENTS; ++i) {
- if (clients[i] <= 0)
+ if (lp->clients[i] <= 0)
continue;
- if (FD_ISSET(clients[i], &fds) <= 0)
+ if (FD_ISSET(lp->clients[i], &lp->client_fds) <= 0)
continue;
- handle_client(&caddr, i);
+ handle_client(&caddr, sp, lp, i);
break;
}
}
close(client_sock);
- close(serv_sock);
+ close(lp->serv_sockfd);
}
-/*
- * Begin listening for incoming connections
- * and handle them.
- */
-int
-net_listen(void)
+void
+listener_cleanup(struct ostp_listener *lp)
{
- struct sockaddr_in saddr;
- int error;
-
- signal(SIGTERM, signal_handle);
- signal(SIGINT, signal_handle);
-
- serv_sock = socket(AF_INET, SOCK_STREAM, 0);
- if (serv_sock < 0) {
- perror("Failed to create socket\n");
- return -1;
- }
-
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = INADDR_ANY;
- saddr.sin_port = htons(LISTEN_PORT);
- error = bind(serv_sock, (struct sockaddr *)&saddr, sizeof(saddr));
- if (error < 0) {
- perror("Failed to bind socket\n");
- close(serv_sock);
- return error;
- }
-
- if ((error = listen(serv_sock, MAX_BACKLOG)) < 0) {
- perror("Failed to listen");
- return error;
+ for (int i = 0; i < MAX_CLIENTS; ++i) {
+ if (lp->clients[i] > 0) {
+ close(lp->clients[i]);
+ }
}
- read_clients();
- __builtin_unreachable();
+ close(lp->serv_sockfd);
}
diff --git a/lib/libostp/session.c b/lib/libostp/session.c
new file mode 100644
index 0000000..4bc6fb4
--- /dev/null
+++ b/lib/libostp/session.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team.
+ * 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 Hyra 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 OWNER 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 <libostp/session.h>
+#include <net/stpsession.h>
+#include <net/param.h>
+#include <crypto/ecdh.h>
+#include <defs.h>
+#include <arpa/inet.h>
+#include <termios.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define OSTP_PORT 5352
+
+#if LIBOSTP_DEBUG
+#define LOG(...) printf("libostp: %s", __VA_ARGS__)
+#else
+#define LOG(...) (void)0
+#endif
+
+static const char *pap_codestr[] = {
+ [PAP_SUCCESS] = "success",
+ [PAP_BAD_SPW] = "bad SPW",
+ [PAP_BAD_PERMS] = "insufficient permissions",
+ [PAP_RESOURCE] = "server out of resources"
+};
+
+static const char *auth_codestr[] = {
+ [AUTH_SUCCESS] = "successful auth",
+ [AUTH_BAD_PW] = "bad username or password"
+};
+
+static int
+send_auth(int sockfd, const unsigned char *session_key)
+{
+ struct session_auth auth;
+ struct termios oldt, newt;
+ int c, index = 0;
+ int error;
+
+ printf("** Please authenticate yourself **\n");
+ printf("Username: ");
+
+ /* Fetch username and clean it up */
+ fgets(auth.username, sizeof(auth.username), stdin);
+ auth.username[strcspn(auth.username, "\n")] = '\0';
+
+ /* Hide input */
+ tcgetattr(STDIN_FILENO, &oldt);
+ newt = oldt;
+ newt.c_lflag &= ~(ECHO | ICANON);
+ tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+
+ printf("Password: ");
+ while (index < (sizeof(auth.password) - 1)) {
+ c = getchar();
+
+ if (c == '\n') {
+ printf("\n");
+ break;
+ }
+
+ if (c == 127 || c == '\b') {
+ if (index > 0) {
+ auth.password[index] = '\0';
+ index--;
+ printf("\b \b");
+ }
+ } else {
+ auth.password[index++] = c;
+ printf("*");
+ }
+ }
+
+ auth.code = 0;
+ auth.password[index] = '\0';
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+
+ /* Send frame with session auth */
+ error = send_frame(sockfd, &auth, sizeof(auth), session_key);
+ if (error < 0) {
+ printf("Failed to send user authentication\n");
+ return error;
+ }
+
+ /* Try to get server reply */
+ error = recv_frame(sockfd, sizeof(auth), session_key, &auth);
+ if (error < 0) {
+ LOG("Failed to get user authentication ACK from server\n");
+ return error;
+ }
+
+ /* Did it fail? */
+ if (auth.code != AUTH_SUCCESS) {
+ LOG("Failed to authenticate, server says: %s\n",
+ auth_codestr[auth.code]);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+client_negotiate_spw(int sockfd, const unsigned char *session_key)
+{
+ struct aes_message am;
+ struct msg_frame msg_frame;
+ struct pap pap;
+ unsigned char *tmp;
+ int error;
+
+ /* Create a PAP and encrypt it */
+ pap.spw = 0x8000;
+ pap.code = 0;
+
+ while (1) {
+ if ((error = send_frame(sockfd, &pap, sizeof(pap), session_key)) < 0) {
+ return error;
+ }
+
+ /* Receive the PAP the server replies with */
+ if ((error = recv_frame(sockfd, sizeof(pap), session_key, &pap)) < 0) {
+ return error;
+ }
+
+ /*
+ * If the server echos our PAP with code 0 then it has
+ * applied our session parameters! However, there is
+ * a chance arbitration will be needed and we need
+ * to look out for that too...
+ */
+ if (pap.code == 0) {
+ LOG("** Negotiation success\n");
+ break;
+ }
+
+ LOG("** Arbitration needed, server says: %s\n", pap_codestr[pap.code]);
+ LOG("** Server proposes SPW of 0x%0X, accepting\n", pap.spw);
+ pap.spw |= PAP_SPW_QSR;
+ pap.code = 0;
+ }
+
+ return 0;
+}
+
+static void
+recv_motd(int sockfd, const unsigned char *session_key)
+{
+ char buf[4096];
+ int len;
+
+ /* Receive the PAP the server replies with */
+ if ((len = recv_frame(sockfd, sizeof(buf) - 1, session_key, buf)) < 0) {
+ printf("Failed to recv MOTD...\n");
+ return;
+ }
+
+ buf[len] = '\0';
+ printf("%s\n", buf);
+}
+
+int
+session_new(const char *host, struct ostp_session *res)
+{
+ struct sockaddr_in addr;
+ struct session_request stp_sq;
+ struct x25519_keypair keypair;
+ unsigned char serv_pubkey[32];
+ unsigned char *session_key;
+ int error, sockfd;
+
+ res->session_key = NULL;
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(host);
+ addr.sin_port = htons(OSTP_PORT);
+
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd < 0) {
+ return sockfd;
+ }
+
+ error = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
+ if (error < 0) {
+ LOG("Failed to connect!\n");
+ close(sockfd);
+ return error;
+ }
+
+ LOG("Generating keys...\n");
+
+ /* Generate an ephemeral keypair */
+ if ((error = gen_x25519_keypair(&keypair)) < 0) {
+ LOG("Key generation failed!\n");
+ close(sockfd);
+ return error;
+ }
+
+ /*
+ * Setup the session request and add our public
+ * key to it. We also assume user authentication.
+ */
+ memset(stp_sq.hash, 0, sizeof(stp_sq.hash));
+ stp_sq.options = SESSION_REQ_USER;
+ memcpy(stp_sq.pubkey, keypair.pubkey, sizeof(stp_sq.pubkey));
+
+ LOG("Sending session request...\n");
+ error = send(sockfd, &stp_sq, sizeof(stp_sq), 0);
+ if (error < 0) {
+ perror("Failed to send session request");
+ close(sockfd);
+ return error;
+ }
+
+ error = recv(sockfd, serv_pubkey, sizeof(serv_pubkey), 0);
+ if (error < 0) {
+ perror("Failed to get public key from peer\n");
+ close(sockfd);
+ return error;
+ }
+
+ if (error == 0) {
+ LOG("Connection closed by peer\n");
+ close(sockfd);
+ return 0;
+ }
+
+ LOG("Got public key from server\n");
+ LOG("Deriving session key...\n");
+ gen_session_key(keypair.privkey, serv_pubkey, &session_key);
+
+ /* User authentication occurs before sending SPWs */
+ if ((error = send_auth(sockfd, session_key)) < 0) {
+ return error;
+ }
+
+ /* Send server SPW bits */
+ if ((error = client_negotiate_spw(sockfd, session_key)) < 0) {
+ LOG("Session Parameter Negotiation failed\n");
+ free_session_key(session_key);
+ close(sockfd);
+ return error;
+ }
+
+ recv_motd(sockfd, session_key);
+ res->sockfd = sockfd;
+ res->session_key = session_key;
+ return 0;
+}
+
+int
+session_close(struct ostp_session *session)
+{
+ if (session->session_key == NULL) {
+ free_session_key(session->session_key);
+ }
+ close(session->sockfd);
+ return 0;
+}
+
+int
+session_send(void *data, uint16_t len, const struct ostp_session *session)
+{
+ return send_frame(session->sockfd, data, len, session->session_key);
+}
+
+int
+session_recv(void *buf, uint16_t len, const struct ostp_session *session)
+{
+ return recv_frame(session->sockfd, len, session->session_key, buf);
+}
diff --git a/ostp.d/init/otd_init.c b/ostp.d/init/main.c
index 4b899b4..08e020e 100644
--- a/ostp.d/init/otd_init.c
+++ b/ostp.d/init/main.c
@@ -27,11 +27,34 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <net/listen.h>
+#include <libostp/session.h>
+#include <libostp/server.h>
+#include <string.h>
#include <stdio.h>
+static int
+blah(struct ostp_session *s, const char *buf, size_t len)
+{
+ printf("Got data!\n");
+ return 0;
+}
+
int
main(void)
{
- return net_listen();
+ struct ostp_listener l;
+ struct ostp_session s;
+ int error;
+
+ listener_init(&l);
+ l.on_recv = blah;
+
+ if ((error = listener_bind(&s, &l)) < 0) {
+ return error;
+ }
+ if ((error = listener_poll(&s, &l)) < 0) {
+ return error;
+ }
+
+ return 0;
}