From ebabaa69c0a3ba992895c7a66729e81e0923d5f1 Mon Sep 17 00:00:00 2001
From: Toni Uhlig <matzeton@googlemail.com>
Date: Thu, 5 Apr 2018 17:53:27 +0200
Subject: Initial commit.

Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
---
 src/Makefile.am   |  5 ++++
 src/log.c         |  8 ++++++
 src/log.h         | 44 ++++++++++++++++++++++++++++++
 src/log_colored.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/log_colored.h | 25 +++++++++++++++++
 src/main.c        | 35 ++++++++++++++++++++++++
 src/server.c      | 38 ++++++++++++++++++++++++++
 src/server.h      | 46 +++++++++++++++++++++++++++++++
 src/server_ssh.c  | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/server_ssh.h  | 27 +++++++++++++++++++
 src/socket.c      | 30 +++++++++++++++++++++
 src/socket.h      | 19 +++++++++++++
 src/utils.c       | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/utils.h       |  8 ++++++
 14 files changed, 517 insertions(+)
 create mode 100644 src/Makefile.am
 create mode 100644 src/log.c
 create mode 100644 src/log.h
 create mode 100644 src/log_colored.c
 create mode 100644 src/log_colored.h
 create mode 100644 src/main.c
 create mode 100644 src/server.c
 create mode 100644 src/server.h
 create mode 100644 src/server_ssh.c
 create mode 100644 src/server_ssh.h
 create mode 100644 src/socket.c
 create mode 100644 src/socket.h
 create mode 100644 src/utils.c
 create mode 100644 src/utils.h

(limited to 'src')

diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..db612f1
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,5 @@
+AM_CFLAGS = -pedantic -Wall -std=gnu99 -D_GNU_SOURCE=1
+AM_LDFLAGS = -lssh
+
+sbin_PROGRAMS = potd
+potd_SOURCES = main.c utils.c log.c log_colored.c socket.c server.c server_ssh.c
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..40ef5cb
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+#include "log.h"
+
+log_open_cb log_open = NULL;
+log_close_cb log_close = NULL;
+log_fmt_cb log_fmt = NULL;
+log_fmtex_cb log_fmtex = NULL;
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..3363395
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,44 @@
+#ifndef POTD_LOG_H
+#define POTD_LOG_H 1
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define LOGMSG_MAXLEN 255
+#define LOG_SET_FUNCS(open_cb, close_cb, fmt_cb, fmtex_cb) \
+    { \
+        log_open = open_cb; log_close = close_cb; \
+        log_fmt = fmt_cb; log_fmtex = fmtex_cb; \
+    }
+#define LOG_SET_FUNCS_VA(...) LOG_SET_FUNCS(__VA_ARGS__)
+#define D(fmt, ...) log_fmt(DEBUG, fmt, __VA_ARGS__)
+#define N(fmt, ...) log_fmt(NOTICE, fmt, __VA_ARGS__)
+#define W(fmt, ...) log_fmt(WARNING, fmt, __VA_ARGS__)
+#define E(fmt, ...) log_fmt(ERROR, fmt, __VA_ARGS__)
+#define D2(fmt, ...) log_fmtex(DEBUG, __FILE__, __LINE__, fmt, __VA_ARGS__)
+#define N2(fmt, ...) log_fmtex(NOTICE, __FILE__, __LINE__, fmt, __VA_ARGS__)
+#define W2(fmt, ...) log_fmtex(WARNING, __FILE__, __LINE__, fmt, __VA_ARGS__)
+#define E2(fmt, ...) log_fmtex(ERROR, __FILE__, __LINE__, fmt, __VA_ARGS__)
+#define W_STRERR(msg) { if (errno) W2("%s failed: %s", msg, strerror(errno)); }
+#define E_STRERR(msg) { if (errno) E2("%s failed: %s", msg, strerror(errno)); }
+#define ABORT_ON_FATAL(expr, msg) \
+    { errno = 0; if (expr) { E_STRERR(msg); abort(); } }
+
+typedef enum log_priority {
+    DEBUG = 0, NOTICE, WARNING, ERROR
+} log_priority;
+
+typedef int (*log_open_cb) (void);
+typedef void (*log_close_cb) (void);
+typedef void (*log_fmt_cb) (log_priority prio, const char *fmt, ...);
+typedef void (*log_fmtex_cb) (log_priority prio, const char *srcfile,
+                              size_t line, const char *fmt, ...);
+
+
+extern log_open_cb log_open;
+extern log_close_cb log_close;
+extern log_fmt_cb log_fmt;
+extern log_fmtex_cb log_fmtex;
+
+#endif
diff --git a/src/log_colored.c b/src/log_colored.c
new file mode 100644
index 0000000..a8a26e3
--- /dev/null
+++ b/src/log_colored.c
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#include "log_colored.h"
+
+
+int log_open_colored(void)
+{
+    if (!getenv("TERM")) {
+        fprintf(stderr, "%s\n", "Missing TERM variable in your environment.");
+        return 1;
+    }
+    if (!strstr(getenv("TERM"), "linux")
+      && !strstr(getenv("TERM"), "xterm"))
+    {
+        fprintf(stderr, "%s\n", "Unsupported TERM variable in your environment");
+        return 1;
+    }
+    return 0;
+}
+
+void log_close_colored(void)
+{
+    return;
+}
+
+void log_fmt_colored(log_priority prio, const char *fmt, ...)
+{
+    char out[LOGMSG_MAXLEN+1] = {0};
+    va_list arglist;
+
+    assert(fmt);
+    va_start(arglist, fmt);
+    assert( vsnprintf(&out[0], LOGMSG_MAXLEN, fmt, arglist) >= 0 );
+    va_end(arglist);
+
+    switch (prio) {
+        case DEBUG:
+            printf("[DEBUG]   %s\n", out);
+            break;
+        case NOTICE:
+            printf("[" GRN "NOTICE" RESET "]  %s\n", out);
+            break;
+        case WARNING:
+            printf("[" YEL "WARNING" RESET "] %s\n", out);
+            break;
+        case ERROR:
+            printf("[" RED "ERROR" RESET "]   %s\n", out);
+            break;
+    }
+}
+
+void log_fmtex_colored(log_priority prio, const char *srcfile,
+                       size_t line, const char *fmt, ...)
+{
+    char out[LOGMSG_MAXLEN+1] = {0};
+    va_list arglist;
+
+    assert(fmt);
+    va_start(arglist, fmt);
+    assert( vsnprintf(&out[0], LOGMSG_MAXLEN, fmt, arglist) >= 0 );
+    va_end(arglist);
+
+    switch (prio) {
+        case DEBUG:
+            printf("[DEBUG]   %s.%lu: %s\n", srcfile, line, out);
+            break;
+        case NOTICE:
+            printf("[" GRN "NOTICE" RESET "]  %s.%lu: %s\n", srcfile, line, out);
+            break;
+        case WARNING:
+            printf("[" YEL "WARNING" RESET "] %s.%lu: %s\n", srcfile, line, out);
+            break;
+        case ERROR:
+            printf("[" RED "ERROR" RESET "]   %s.%lu: %s\n", srcfile, line, out);
+            break;
+    }
+}
diff --git a/src/log_colored.h b/src/log_colored.h
new file mode 100644
index 0000000..c7c0014
--- /dev/null
+++ b/src/log_colored.h
@@ -0,0 +1,25 @@
+#ifndef POTD_LOG_COLORED
+#define POTD_LOG_COLORED 1
+
+#include "log.h"
+
+/* ANSI terminal color codes */
+#define RESET "\x1B[0m"
+#define GRN   "\x1B[32;1m"
+#define YEL   "\x1B[33;1m"
+#define RED   "\x1B[31;1;5m"
+/* LOG_SET_FUNCS comfort */
+#define LOG_COLORED_FUNCS log_open_colored, log_close_colored, \
+    log_fmt_colored, log_fmtex_colored
+
+
+int log_open_colored(void);
+
+void log_close_colored(void);
+
+void log_fmt_colored(log_priority prio, const char *fmt, ...);
+
+void log_fmtex_colored(log_priority prio, const char *srcfile,
+                       size_t line, const char *fmt, ...);
+
+#endif
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..7ccc404
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,35 @@
+#include "log.h"
+#include "log_colored.h"
+#include "server.h"
+#include "server_ssh.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+int main(int argc, char *argv[])
+{
+    static server_ctx srv = {0};
+
+    (void)argc;
+    (void)argv;
+
+    LOG_SET_FUNCS_VA(LOG_COLORED_FUNCS);
+    N("%s (C) 2018 Toni Uhlig (%s)", PACKAGE_STRING, PACKAGE_BUGREPORT);
+
+    ABORT_ON_FATAL( server_init_ctx(&srv, ssh_init_cb),
+        "Server initialisation" );
+    server_validate_ctx(&srv);
+
+    ABORT_ON_FATAL( socket_init_in(&srv.sock, "127.0.0.1", 2222),
+        "Socket initialisation" );
+    ABORT_ON_FATAL( socket_bind_listen(&srv.sock),
+        "Socket bind and listen" );
+    ABORT_ON_FATAL( srv.server_cbs.on_listen(&srv.server_dat),
+        "Socket on listen callback" );
+
+    D2("%s", "Server mainloop");
+    ABORT_ON_FATAL( server_mainloop(&srv),
+        "Server mainloop" );
+    return 0;
+}
diff --git a/src/server.c b/src/server.c
new file mode 100644
index 0000000..61664c5
--- /dev/null
+++ b/src/server.c
@@ -0,0 +1,38 @@
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "server.h"
+
+
+server_ctx *
+server_init_ctx(server_ctx *ctx, init_cb init_fn)
+{
+    if (!ctx)
+        ctx = (server_ctx *) malloc(sizeof(*ctx));
+    assert(ctx);
+
+    memset(ctx, 0, sizeof(*ctx));
+    if (!init_fn(ctx))
+        return NULL;
+
+    return ctx;
+}
+
+int server_validate_ctx(server_ctx *ctx)
+{
+    assert(ctx);
+    assert(ctx->server_cbs.on_connect && ctx->server_cbs.on_disconnect
+        && ctx->server_cbs.mainloop);
+    assert(ctx->server_cbs.on_free && ctx->server_cbs.on_listen
+        && ctx->server_cbs.on_shutdown);
+    return 0;
+}
+
+int server_mainloop(server_ctx *ctx)
+{
+    while (1) {
+        sleep(1);
+    }
+    return 0;
+}
diff --git a/src/server.h b/src/server.h
new file mode 100644
index 0000000..69c3ad7
--- /dev/null
+++ b/src/server.h
@@ -0,0 +1,46 @@
+#ifndef POTD_SERVER_H
+#define POTD_SERVER_H 1
+
+#include "socket.h"
+
+typedef struct server_data {
+	void *data;
+} server_data;
+
+typedef struct server_session {
+    void *data;
+} server_session;
+
+typedef int (*on_connect_cb) (struct server_data *data, struct server_session *ses);
+typedef int (*on_disconnect_cb) (struct server_data *data, struct server_session *ses);
+typedef int (*on_data_cb) (struct server_data *data, struct server_session *ses);
+typedef int (*on_free_cb) (struct server_data *data);
+typedef int (*on_listen_cb) (struct server_data *data);
+typedef int (*on_shutdown_cb) (struct server_data *data);
+
+typedef struct server_callbacks {
+    on_connect_cb on_connect;
+    on_disconnect_cb on_disconnect;
+    on_data_cb mainloop;
+    on_free_cb on_free;
+    on_listen_cb on_listen;
+    on_shutdown_cb on_shutdown;
+} server_callbacks;
+
+typedef struct server_ctx { 
+    server_callbacks server_cbs;
+    server_data server_dat;
+    psocket sock;
+} server_ctx;
+
+typedef int (*init_cb) (struct server_ctx *ctx);
+  
+
+server_ctx *
+server_init_ctx(server_ctx *ctx, init_cb init_fn);
+
+int server_validate_ctx(server_ctx *ctx);
+
+int server_mainloop(server_ctx *ctx);
+
+#endif
diff --git a/src/server_ssh.c b/src/server_ssh.c
new file mode 100644
index 0000000..92d9454
--- /dev/null
+++ b/src/server_ssh.c
@@ -0,0 +1,77 @@
+#include <stdlib.h>
+#include <libssh/callbacks.h>
+#include <libssh/server.h>
+
+#include "server_ssh.h"
+#include "server.h"
+
+static void set_default_keys(ssh_bind sshbind, int rsa_already_set,
+                      int dsa_already_set, int ecdsa_already_set);
+
+
+int ssh_on_connect(struct server_data *data, struct server_session *ses)
+{
+    return 0;
+}
+
+int ssh_on_disconnect(struct server_data *data, struct server_session *ses)
+{
+    return 0;
+}
+
+int ssh_mainloop_cb(struct server_data *data, struct server_session *ses)
+{
+    return 0;
+}
+
+int ssh_init_cb(struct server_ctx *ctx)
+{
+    ctx->server_cbs.on_connect = ssh_on_connect;
+    ctx->server_cbs.on_disconnect = ssh_on_disconnect;
+    ctx->server_cbs.mainloop = ssh_mainloop_cb;
+    ctx->server_cbs.on_free = ssh_free_cb;
+    ctx->server_cbs.on_listen = ssh_listen_cb;
+    ctx->server_cbs.on_shutdown = ssh_shutdown_cb;
+
+    ssh_init();
+    ssh_data *d = (ssh_data *) calloc(1, sizeof(*d));
+    d->sshbind = ssh_bind_new();
+    ctx->server_dat.data = d;
+    if (!d->sshbind)
+        return 1;
+
+    set_default_keys(d->sshbind, 0, 0, 0);
+    return 0;
+}
+
+int ssh_free_cb(struct server_data *data)
+{
+    return 0;
+}
+
+int ssh_listen_cb(struct server_data *data)
+{
+    return 0;
+}
+
+int ssh_shutdown_cb(struct server_data *data)
+{
+    return 0;
+}
+
+static void set_default_keys(ssh_bind sshbind, int rsa_already_set,
+                             int dsa_already_set, int ecdsa_already_set)
+{
+    if (!rsa_already_set) {
+        ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY,
+                             "./ssh_host_rsa_key");
+    }
+    if (!dsa_already_set) {
+        ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY,
+                             "./ssh_host_dsa_key");
+    }
+    if (!ecdsa_already_set) {
+        ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY,
+                             "./ssh_host_ecdsa_key");
+    }
+}
diff --git a/src/server_ssh.h b/src/server_ssh.h
new file mode 100644
index 0000000..dc80645
--- /dev/null
+++ b/src/server_ssh.h
@@ -0,0 +1,27 @@
+#ifndef POTD_SERVER_SSH_H
+#define POTD_SERVER_SSH_H 1
+
+#include <libssh/server.h>
+
+#include "server.h"
+
+typedef struct ssh_data {
+    ssh_bind sshbind;
+} ssh_data;
+
+
+int ssh_on_connect(struct server_data *data, struct server_session *ses);
+
+int ssh_on_disconnect(struct server_data *data, struct server_session *ses);
+
+int ssh_mainloop_cb(struct server_data *_data, struct server_session *ses);
+
+int ssh_init_cb(struct server_ctx *ctx);
+
+int ssh_free_cb(struct server_data *data);
+
+int ssh_listen_cb(struct server_data *data);
+
+int ssh_shutdown_cb(struct server_data *data);
+
+#endif
diff --git a/src/socket.c b/src/socket.c
new file mode 100644
index 0000000..99e4477
--- /dev/null
+++ b/src/socket.c
@@ -0,0 +1,30 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <assert.h>
+
+#include "socket.h"
+
+
+int socket_init_in(psocket *psocket, const char *listen_addr, unsigned int listen_port)
+{
+    struct in_addr addr = {0};
+
+    assert(psocket);
+    if (!inet_aton(listen_addr, &addr))
+        return 1;
+
+    psocket->sock.sin_family = AF_INET;
+    psocket->sock.sin_addr = addr;
+    psocket->sock.sin_port = htons(listen_port);
+    psocket->fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+    return psocket->fd < 0;
+}
+
+int socket_bind_listen(psocket *psocket)
+{
+    assert(psocket);
+    if (bind(psocket->fd, &psocket->sock, sizeof(psocket->sock)) < 0)
+        return 1;
+    return listen(psocket->fd, POTD_BACKLOG) < 0;
+}
diff --git a/src/socket.h b/src/socket.h
new file mode 100644
index 0000000..1b1a762
--- /dev/null
+++ b/src/socket.h
@@ -0,0 +1,19 @@
+#ifndef POTD_SOCKET_H
+#define POTD_SOCKET_H 1
+
+#include <netinet/in.h>
+
+#define POTD_BACKLOG 3
+
+typedef struct psocket {
+    int fd;
+    struct sockaddr_in sock;
+} psocket;
+
+
+int socket_init_in(psocket *psocket, const char *listen_addr,
+                   unsigned int listen_port);
+
+int socket_bind_listen(psocket *psocket);
+
+#endif
diff --git a/src/utils.c b/src/utils.c
new file mode 100644
index 0000000..5c86017
--- /dev/null
+++ b/src/utils.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#include "utils.h"
+
+#define _POSIX_PATH_MAX 256
+
+
+void set_procname(char *arg0, const char *newname)
+{
+	memset(arg0, 0, _POSIX_PATH_MAX);
+	strncpy(arg0, newname, _POSIX_PATH_MAX);
+}
+
+int daemonize(void)
+{
+    pid_t pid;
+
+    /* Fork off the parent process */
+    pid = fork();
+
+    /* An error occurred */
+    if (pid < 0)
+        exit(EXIT_FAILURE);
+
+    /* Success: Let the parent terminate */
+    if (pid > 0)
+        exit(EXIT_SUCCESS);
+
+    /* On success: The child process becomes session leader */
+    if (setsid() < 0)
+        exit(EXIT_FAILURE);
+
+    /* Catch, ignore and handle signals */
+    //TODO: Implement a working signal handler */
+    signal(SIGCHLD, SIG_IGN);
+    signal(SIGHUP, SIG_IGN);
+
+    /* Fork off for the second time*/
+    pid = fork();
+
+    /* An error occurred */
+    if (pid < 0)
+        exit(EXIT_FAILURE);
+
+    /* Success: Let the parent terminate */
+    if (pid > 0)
+        exit(EXIT_SUCCESS);
+
+    /* Set new file permissions */
+    umask(0);
+
+    /* Change the working directory to the root directory */
+    /* or another appropriated directory */
+    chdir("/");
+
+    /* Close all open file descriptors */
+    int x;
+    for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
+    {
+        close (x);
+    }
+
+    /* Open the log file */
+    openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
+
+    return 0;
+}
diff --git a/src/utils.h b/src/utils.h
new file mode 100644
index 0000000..587bf25
--- /dev/null
+++ b/src/utils.h
@@ -0,0 +1,8 @@
+#ifndef POTD_UTILS_H
+#define POTD_UTILS_H 1
+
+void set_procname(char *arg0, const char *newname);
+
+int daemonize(void);
+
+#endif
-- 
cgit v1.2.3