From a36eb32d33108d15e4544fe5c9695e32dc3ccf27 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Tue, 21 Apr 2026 04:52:41 +0200 Subject: [PATCH] feat: add Smart web UI build and configuration files --- CMakeLists.txt | 80 ++++++ apply.pl | 8 +- config.h.cmake | 23 ++ nwwebui.c | 618 +++++++++++++++++++++++++++++++++++++++++++ settings.pl | 2 +- smart => smart.cmake | 32 +-- smart.conf | 11 - smart.conf.cmake | 24 ++ static.pl | 2 +- 9 files changed, 768 insertions(+), 32 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 config.h.cmake create mode 100644 nwwebui.c rename smart => smart.cmake (86%) delete mode 100644 smart.conf create mode 100644 smart.conf.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bfbcd3b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,80 @@ +################################# +# Project +############## + +################################# +# Dependencies +############## + +find_package(OpenSSL REQUIRED) + +find_library(PAM_LIB pam REQUIRED) +find_library(DL_LIB dl REQUIRED) + +################################# +# Generated files +############## + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/config.h" + IMMEDIATE @ONLY) + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/smart.conf.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/smart.conf" + IMMEDIATE @ONLY) + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/smart.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/smart" + IMMEDIATE @ONLY) + +################################# +# Compiler Switches +############## + +INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_BINARY_DIR}/include +) + +################################# +# Source Files +############## + +add_executable(nwwebui nwwebui.c) +add_executable(check_login check_login.c) + +################################# +# Linking +############## + +target_link_libraries(nwwebui + OpenSSL::SSL + OpenSSL::Crypto +) + +target_link_libraries(check_login + ${PAM_LIB} + ${DL_LIB} +) + +################################# +# Install Files +############## + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/smart.conf DESTINATION ${MARS_NWE_INSTALL_FULL_CONFDIR}) +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/smart DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}) + +install(PROGRAMS apply.pl DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}) +install(PROGRAMS readconfig.pl DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}) +install(PROGRAMS settings.pl DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}) +install(PROGRAMS static.pl DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}) + +install(DIRECTORY static/ DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) + +install(TARGETS check_login DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}) + +install(TARGETS nwwebui DESTINATION ${CMAKE_INSTALL_SBINDIR}) diff --git a/apply.pl b/apply.pl index ecf8328..576fd3f 100644 --- a/apply.pl +++ b/apply.pl @@ -138,17 +138,17 @@ sub handle_request() if( $p{mars_config} ne $mars_config ) { # Just append the line. Messy but easy. ;) - open( FILE, '>>' . $base . 'smart.conf' ); + open( FILE, '>>' . $smart_conf_path ) or die "Could not open $smart_conf_path: $!"; print( FILE "\n" . '$mars_config = \'' . $p{mars_config} . '\';' . "\n" ); close( FILE ); } - open( FILE, '>' . $base . '.nwclient' ); + open( FILE, '>' . $smart_nwclient_path ) or die "Could not open $smart_nwclient_path: $!"; print( FILE $p{bind_server} . '/' . $p{bind_user} . ' ' . $p{bind_pass } . "\n" ); close( FILE ); - chown( scalar( getpwnam( $nonroot_user ) ), 0, $base . '.nwclient' ); - chmod( 0600, $base . '.nwclient' ); + chown( scalar( getpwnam( $nonroot_user ) ), 0, $smart_nwclient_path ); + chmod( 0600, $smart_nwclient_path ); } elsif( $c[1] eq 'users' ) { diff --git a/config.h.cmake b/config.h.cmake new file mode 100644 index 0000000..a6f7144 --- /dev/null +++ b/config.h.cmake @@ -0,0 +1,23 @@ +#ifndef NWWEBUI_CONFIG_H +#define NWWEBUI_CONFIG_H + +#define DEFAULT_SMART_CONF "@MARS_NWE_INSTALL_FULL_CONFDIR@/smart.conf" +#define DEFAULT_SMART_PERL "@MARS_NWE_INSTALL_FULL_LIBEXEC@/smart" + +#define LOG_PATH_DEFAULT "@MARS_NWE_LOG_DIR@/nwwebui.log" + +#define LOG_LEVEL_ERROR 0 +#define LOG_LEVEL_INFO 1 +#define LOG_LEVEL_DEBUG 2 +#define LOG_LEVEL_DEFAULT LOG_LEVEL_INFO + +#define DEFAULT_BIND_IP "0.0.0.0" +#define DEFAULT_TLS_PORT 9443 + +#define DEFAULT_CERT_FILE "@MARS_NWE_INSTALL_FULL_CONFDIR@/server.crt" +#define DEFAULT_KEY_FILE "@MARS_NWE_INSTALL_FULL_CONFDIR@/server.key" + +#define NW_BACKLOG 64 +#define NW_BUF_SZ 16384 + +#endif diff --git a/nwwebui.c b/nwwebui.c new file mode 100644 index 0000000..9900287 --- /dev/null +++ b/nwwebui.c @@ -0,0 +1,618 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +typedef struct { + char bind_ip[64]; + int tls_port; + + char cert_file[512]; + char key_file[512]; + + char smart_conf[512]; + char smart_perl_path[512]; +} nw_config_t; + +static FILE *g_log_fp = NULL; +static int g_log_level = LOG_LEVEL_DEFAULT; + +/* ------------------------------------------------------------ */ +/* Logging */ +/* ------------------------------------------------------------ */ + +static void log_open(void) { + if (!g_log_fp) { + g_log_fp = fopen(LOG_PATH_DEFAULT, "a"); + if (!g_log_fp) { + g_log_fp = stderr; + } + } +} + +static void log_msg(int level, const char *fmt, ...) { + if (level > g_log_level) { + return; + } + + log_open(); + + time_t now = time(NULL); + struct tm tm_now; + localtime_r(&now, &tm_now); + + char tbuf[64]; + strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", &tm_now); + + const char *lvl = "INFO"; + if (level == LOG_LEVEL_ERROR) { + lvl = "ERROR"; + } else if (level == LOG_LEVEL_DEBUG) { + lvl = "DEBUG"; + } + + fprintf(g_log_fp, "[%s] [%s] ", tbuf, lvl); + + va_list ap; + va_start(ap, fmt); + vfprintf(g_log_fp, fmt, ap); + va_end(ap); + + fputc('\n', g_log_fp); + fflush(g_log_fp); +} + +static void die(const char *msg) { + log_msg(LOG_LEVEL_ERROR, "%s: %s", msg, strerror(errno)); + exit(EXIT_FAILURE); +} + +static void ssl_die(const char *msg) { + log_msg(LOG_LEVEL_ERROR, "%s", msg); + ERR_print_errors_fp(g_log_fp ? g_log_fp : stderr); + exit(EXIT_FAILURE); +} + +/* ------------------------------------------------------------ */ +/* Helpers */ +/* ------------------------------------------------------------ */ + +static void trim(char *s) { + char *p = s; + while (*p && isspace((unsigned char)*p)) { + p++; + } + if (p != s) { + memmove(s, p, strlen(p) + 1); + } + + size_t len = strlen(s); + while (len > 0 && isspace((unsigned char)s[len - 1])) { + s[len - 1] = '\0'; + len--; + } +} + +static void strip_quotes(char *s) { + size_t len = strlen(s); + if (len >= 2) { + if ((s[0] == '\'' && s[len - 1] == '\'') || + (s[0] == '"' && s[len - 1] == '"')) { + memmove(s, s + 1, len - 2); + s[len - 2] = '\0'; + } + } +} + +static int parse_perl_assignment(const char *line, char *key, size_t ksz, char *val, size_t vsz) { + /* Expected format: + $variable = 'value'; + $variable = 1234; + */ + + const char *p = line; + + while (*p && isspace((unsigned char)*p)) { + p++; + } + if (*p != '$') { + return 0; + } + p++; + + size_t ki = 0; + while (*p && (isalnum((unsigned char)*p) || *p == '_')) { + if (ki + 1 < ksz) { + key[ki++] = *p; + } + p++; + } + key[ki] = '\0'; + + while (*p && isspace((unsigned char)*p)) { + p++; + } + if (*p != '=') { + return 0; + } + p++; + + while (*p && isspace((unsigned char)*p)) { + p++; + } + + size_t vi = 0; + while (*p && *p != ';' && *p != '\n' && *p != '\r') { + if (vi + 1 < vsz) { + val[vi++] = *p; + } + p++; + } + val[vi] = '\0'; + + trim(key); + trim(val); + strip_quotes(val); + + return key[0] != '\0'; +} + +static int file_exists_and_executable(const char *path) { + return access(path, X_OK) == 0; +} + +static int set_nonblocking(int fd) { + int flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) { + return -1; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + return -1; + } + return 0; +} + +/* ------------------------------------------------------------ */ +/* smart.conf loading */ +/* ------------------------------------------------------------ */ + +static void init_defaults(nw_config_t *cfg, const char *smart_conf_path) { + memset(cfg, 0, sizeof(*cfg)); + + snprintf(cfg->bind_ip, sizeof(cfg->bind_ip), "%s", DEFAULT_BIND_IP); + cfg->tls_port = DEFAULT_TLS_PORT; + + snprintf(cfg->cert_file, sizeof(cfg->cert_file), "%s", DEFAULT_CERT_FILE); + snprintf(cfg->key_file, sizeof(cfg->key_file), "%s", DEFAULT_KEY_FILE); + + /* Use the built-in default path unless smart.conf overrides it */ + snprintf(cfg->smart_perl_path, sizeof(cfg->smart_perl_path), "%s", DEFAULT_SMART_PERL); + + snprintf(cfg->smart_conf, sizeof(cfg->smart_conf), "%s", smart_conf_path); +} + +static void load_smart_conf(nw_config_t *cfg) { + FILE *fp = fopen(cfg->smart_conf, "r"); + if (!fp) { + log_msg(LOG_LEVEL_ERROR, "Could not open smart.conf: %s", cfg->smart_conf); + die("fopen smart.conf"); + } + + char line[2048]; + while (fgets(line, sizeof(line), fp)) { + char key[256]; + char val[1024]; + + if (!parse_perl_assignment(line, key, sizeof(key), val, sizeof(val))) { + continue; + } + + if (strcmp(key, "nw_bind_ip") == 0) { + snprintf(cfg->bind_ip, sizeof(cfg->bind_ip), "%s", val); + } else if (strcmp(key, "nw_tls_port") == 0) { + cfg->tls_port = atoi(val); + } else if (strcmp(key, "nw_cert_file") == 0) { + snprintf(cfg->cert_file, sizeof(cfg->cert_file), "%s", val); + } else if (strcmp(key, "nw_key_file") == 0) { + snprintf(cfg->key_file, sizeof(cfg->key_file), "%s", val); + } else if (strcmp(key, "smart_perl_path") == 0) { + /* Override the default path only if smart.conf defines it */ + snprintf(cfg->smart_perl_path, sizeof(cfg->smart_perl_path), "%s", val); + } + } + + fclose(fp); + + if (cfg->tls_port <= 0) { + cfg->tls_port = DEFAULT_TLS_PORT; + } +} + +/* ------------------------------------------------------------ */ +/* Listener / TLS */ +/* ------------------------------------------------------------ */ + +static int create_listener(const char *bind_ip, int port) { + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + die("socket"); + } + + int yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { + close(fd); + die("setsockopt(SO_REUSEADDR)"); + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons((uint16_t)port); + + if (strcmp(bind_ip, "0.0.0.0") == 0) { + addr.sin_addr.s_addr = htonl(INADDR_ANY); + } else { + if (inet_pton(AF_INET, bind_ip, &addr.sin_addr) != 1) { + close(fd); + log_msg(LOG_LEVEL_ERROR, "Invalid bind IP: %s", bind_ip); + exit(EXIT_FAILURE); + } + } + + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + close(fd); + die("bind"); + } + + if (listen(fd, NW_BACKLOG) < 0) { + close(fd); + die("listen"); + } + + return fd; +} + +static ssize_t write_all_fd(int fd, const unsigned char *buf, size_t len) { + size_t off = 0; + + while (off < len) { + ssize_t n = write(fd, buf + off, len - off); + if (n < 0) { + if (errno == EINTR) { + continue; + } + if (errno == EAGAIN || errno == EWOULDBLOCK) { + continue; + } + return -1; + } + if (n == 0) { + break; + } + off += (size_t)n; + } + + return (ssize_t)off; +} + +static ssize_t send_all_ssl(SSL *ssl, const unsigned char *buf, size_t len) { + size_t off = 0; + + while (off < len) { + int n = SSL_write(ssl, buf + off, (int)(len - off)); + if (n <= 0) { + int err = SSL_get_error(ssl, n); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + continue; + } + return -1; + } + off += (size_t)n; + } + + return (ssize_t)off; +} + +/* ------------------------------------------------------------ */ +/* Perl launcher */ +/* ------------------------------------------------------------ */ + +static pid_t spawn_smart_perl(const nw_config_t *cfg, int *child_stdin_fd, int *child_stdout_fd) { + int inpipe[2] = { -1, -1 }; + int outpipe[2] = { -1, -1 }; + + if (pipe(inpipe) < 0) { + die("pipe stdin"); + } + + if (pipe(outpipe) < 0) { + close(inpipe[0]); + close(inpipe[1]); + die("pipe stdout"); + } + + pid_t pid = fork(); + if (pid < 0) { + close(inpipe[0]); + close(inpipe[1]); + close(outpipe[0]); + close(outpipe[1]); + die("fork"); + } + + if (pid == 0) { + /* Child process: + stdin <- parent writes client request data here + stdout -> parent reads response data here + stderr -> merged into stdout for logging/debugging + */ + if (dup2(inpipe[0], STDIN_FILENO) < 0) { + perror("dup2 stdin"); + _exit(127); + } + if (dup2(outpipe[1], STDOUT_FILENO) < 0) { + perror("dup2 stdout"); + _exit(127); + } + if (dup2(outpipe[1], STDERR_FILENO) < 0) { + perror("dup2 stderr"); + _exit(127); + } + + close(inpipe[0]); + close(inpipe[1]); + close(outpipe[0]); + close(outpipe[1]); + + execl(cfg->smart_perl_path, cfg->smart_perl_path, (char *)NULL); + + perror("execl smart_perl_path"); + _exit(127); + } + + close(inpipe[0]); + close(outpipe[1]); + + *child_stdin_fd = inpipe[1]; + *child_stdout_fd = outpipe[0]; + + return pid; +} + +/* ------------------------------------------------------------ */ +/* Connection handler */ +/* ------------------------------------------------------------ */ + +static void handle_connection(SSL_CTX *ctx, int client_fd, const nw_config_t *cfg) { + SSL *ssl = NULL; + int child_stdin_fd = -1; + int child_stdout_fd = -1; + pid_t child_pid = -1; + unsigned char buf[NW_BUF_SZ]; + + ssl = SSL_new(ctx); + if (!ssl) { + log_msg(LOG_LEVEL_ERROR, "SSL_new failed"); + goto cleanup; + } + + SSL_set_fd(ssl, client_fd); + + if (SSL_accept(ssl) <= 0) { + log_msg(LOG_LEVEL_ERROR, "SSL_accept failed"); + ERR_print_errors_fp(g_log_fp ? g_log_fp : stderr); + goto cleanup; + } + + log_msg(LOG_LEVEL_INFO, "Accepted new TLS connection"); + + child_pid = spawn_smart_perl(cfg, &child_stdin_fd, &child_stdout_fd); + + if (set_nonblocking(child_stdout_fd) < 0) { + log_msg(LOG_LEVEL_ERROR, "Could not set child stdout non-blocking"); + goto cleanup; + } + + for (;;) { + struct pollfd pfd; + pfd.fd = child_stdout_fd; + pfd.events = POLLIN | POLLHUP | POLLERR; + pfd.revents = 0; + + /* Read from TLS client, decrypt data, and forward it to Perl stdin */ + int n = SSL_read(ssl, buf, sizeof(buf)); + if (n > 0) { + if (write_all_fd(child_stdin_fd, buf, (size_t)n) < 0) { + log_msg(LOG_LEVEL_ERROR, "Write to Perl stdin failed"); + break; + } + } else { + int err = SSL_get_error(ssl, n); + if (err == SSL_ERROR_ZERO_RETURN) { + break; + } + if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) { + break; + } + } + + /* Read any output from the Perl process and send it back through TLS */ + int pr = poll(&pfd, 1, 10); + if (pr > 0 && (pfd.revents & (POLLIN | POLLHUP | POLLERR))) { + ssize_t rn = read(child_stdout_fd, buf, sizeof(buf)); + if (rn > 0) { + if (send_all_ssl(ssl, buf, (size_t)rn) < 0) { + log_msg(LOG_LEVEL_ERROR, "SSL_write failed"); + break; + } + } else if (rn == 0) { + break; + } else if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { + break; + } + } + + /* Exit if the child process is already gone */ + if (child_pid > 0) { + int status = 0; + pid_t w = waitpid(child_pid, &status, WNOHANG); + if (w == child_pid) { + break; + } + } + } + +cleanup: + if (child_stdin_fd >= 0) { + close(child_stdin_fd); + } + if (child_stdout_fd >= 0) { + close(child_stdout_fd); + } + + if (child_pid > 0) { + int status = 0; + pid_t w = waitpid(child_pid, &status, WNOHANG); + if (w == 0) { + kill(child_pid, SIGTERM); + waitpid(child_pid, &status, 0); + } + } + + if (ssl) { + SSL_shutdown(ssl); + SSL_free(ssl); + } + + close(client_fd); +} + +static void reap_children(int sig) { + (void)sig; + while (waitpid(-1, NULL, WNOHANG) > 0) { + } +} + +/* ------------------------------------------------------------ */ +/* Main */ +/* ------------------------------------------------------------ */ + +int main(int argc, char **argv) { + const char *smart_conf_path = DEFAULT_SMART_CONF; + + if (argc > 1) { + smart_conf_path = argv[1]; + } + + signal(SIGCHLD, reap_children); + signal(SIGPIPE, SIG_IGN); + + log_open(); + log_msg(LOG_LEVEL_INFO, "nwwebui starting"); + + nw_config_t cfg; + init_defaults(&cfg, smart_conf_path); + load_smart_conf(&cfg); + + if (!file_exists_and_executable(cfg.smart_perl_path)) { + log_msg(LOG_LEVEL_ERROR, + "SMArT Perl program is missing or not executable: %s", + cfg.smart_perl_path); + return EXIT_FAILURE; + } + + log_msg(LOG_LEVEL_INFO, "Using SMArT Perl path: %s", cfg.smart_perl_path); + + log_msg(LOG_LEVEL_INFO, + "Config loaded: bind=%s:%d cert=%s key=%s smart.conf=%s", + cfg.bind_ip, + cfg.tls_port, + cfg.cert_file, + cfg.key_file, + cfg.smart_conf); + + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + + SSL_CTX *ctx = SSL_CTX_new(TLS_server_method()); + if (!ctx) { + ssl_die("SSL_CTX_new failed"); + } + + SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); + + if (SSL_CTX_use_certificate_file(ctx, cfg.cert_file, SSL_FILETYPE_PEM) <= 0) { + ssl_die("Could not load certificate file"); + } + + if (SSL_CTX_use_PrivateKey_file(ctx, cfg.key_file, SSL_FILETYPE_PEM) <= 0) { + ssl_die("Could not load private key file"); + } + + if (!SSL_CTX_check_private_key(ctx)) { + ssl_die("Private key does not match certificate"); + } + + int listen_fd = create_listener(cfg.bind_ip, cfg.tls_port); + + log_msg(LOG_LEVEL_INFO, + "TLS wrapper listening on %s:%d and launching %s", + cfg.bind_ip, + cfg.tls_port, + cfg.smart_perl_path); + + for (;;) { + struct sockaddr_in peer; + socklen_t peerlen = sizeof(peer); + + int client_fd = accept(listen_fd, (struct sockaddr *)&peer, &peerlen); + if (client_fd < 0) { + if (errno == EINTR) { + continue; + } + log_msg(LOG_LEVEL_ERROR, "accept failed: %s", strerror(errno)); + continue; + } + + pid_t pid = fork(); + if (pid < 0) { + log_msg(LOG_LEVEL_ERROR, "fork failed: %s", strerror(errno)); + close(client_fd); + continue; + } + + if (pid == 0) { + close(listen_fd); + handle_connection(ctx, client_fd, &cfg); + SSL_CTX_free(ctx); + _exit(0); + } + + close(client_fd); + } + + close(listen_fd); + SSL_CTX_free(ctx); + return 0; +} diff --git a/settings.pl b/settings.pl index edc088c..cfa0a8c 100644 --- a/settings.pl +++ b/settings.pl @@ -1167,7 +1167,7 @@ EOF } elsif( $c[1] eq 'smart' ) { - open( FILE, '<' . $base . '.nwclient' ); + open( FILE, '<' . $smart_nwclient_path ) or die "Could not open $smart_nwclient_path: $!"; $x = ; close( FILE ); diff --git a/smart b/smart.cmake similarity index 86% rename from smart rename to smart.cmake index c25826c..c52a90a 100755 --- a/smart +++ b/smart.cmake @@ -25,16 +25,18 @@ $redirected = 0; -$server_id = 'Server: SMArT/Perl/0.99'; -$base = $0; -$base =~ s/\/[^\/]*$//g; -$base .= '/'; +$server_id = 'Server: SMArT/Perl/@MARS_NWE_VERSION@'; -do( $base . 'smart.conf' ); +do( '@MARS_NWE_INSTALL_FULL_CONFDIR@/smart.conf' ) + or die "Could not load @MARS_NWE_INSTALL_FULL_CONFDIR@/smart.conf: $@ $!"; close( STDERR ); -open( STDERR, '>>' . $base . 'error.log' ); -$ENV{HOME} = $base; +open( STDERR, '>>' . $smart_log_path ) + or die "Could not open $smart_log_path: $!"; + +$ENV{HOME} = '@MARS_NWE_INSTALL_FULL_CONFDIR@'; +$smart_libexec_dir = '@MARS_NWE_INSTALL_FULL_LIBEXEC@'; +$smart_libexec_dir =~ s#/*$##; $l = ; $l =~ s/[\n\r]//g; @@ -75,7 +77,7 @@ else if( $l[0] ne 'root' ) { error( 401 ); } else - { if( $x = system( $base . 'check_login', @l ) ) + { if( $x = system( $smart_check_login, @l ) ) { error( 401 ); } } } } @@ -104,14 +106,14 @@ foreach $p ( @p ) if( $c[0] eq 'apply' ) { - do( $base . 'readconfig.pl' ); - do( $base . 'apply.pl' ); + do( $smart_libexec_dir . '/readconfig.pl' ); + do( $smart_libexec_dir . '/apply.pl' ); handle_request(); exit; } elsif( $c[0] eq 'settings' ) { - do( $base . 'readconfig.pl' ); + do( $smart_libexec_dir . '/readconfig.pl' ); } drop_root(); @@ -137,11 +139,11 @@ EOF } elsif( $c[0] eq 'static' ) { - do( $base . 'static.pl' ); + do( $smart_libexec_dir . '/static.pl' ); } elsif( $c[0] eq 'settings' ) { - do( $base . 'settings.pl' ); + do( $smart_libexec_dir . '/settings.pl' ); } else { @@ -239,7 +241,7 @@ EOF sub get_server { - open( SFILE, '<' . $base . '.nwclient' ); + open( SFILE, '<' . $smart_nwclient_path ); chomp( $line = ); close( SFILE ); @@ -249,7 +251,7 @@ sub get_server sub get_bindery_password { - open( SFILE, '<' . $base . '.nwclient' ); + open( SFILE, '<' . $smart_nwclient_path ); chomp( $line = ); close( SFILE ); diff --git a/smart.conf b/smart.conf deleted file mode 100644 index f158177..0000000 --- a/smart.conf +++ /dev/null @@ -1,11 +0,0 @@ -$COLOR_BACK = "#F0F0FF"; -$COLOR_HEAD_BACK = "#C0C0FF"; -$COLOR_HEAD_FORE = "#000000"; -$COLOR_SUBH_BACK = "#D0D0FF"; -$COLOR_SUBH_FORE = "#000000"; -$COLOR_TEXT_BACK = "#E0E0FF"; -$COLOR_TEXT_FORE = "#000000"; - -$mars_config = '/usr/local/etc/nwserv.conf'; - -$nonroot_user = 'nobody'; diff --git a/smart.conf.cmake b/smart.conf.cmake new file mode 100644 index 0000000..7ce1f6f --- /dev/null +++ b/smart.conf.cmake @@ -0,0 +1,24 @@ +$COLOR_BACK = "#F0F0FF"; +$COLOR_HEAD_BACK = "#C0C0FF"; +$COLOR_HEAD_FORE = "#000000"; +$COLOR_SUBH_BACK = "#D0D0FF"; +$COLOR_SUBH_FORE = "#000000"; +$COLOR_TEXT_BACK = "#E0E0FF"; +$COLOR_TEXT_FORE = "#000000"; + +$mars_config = '@MARS_NWE_INSTALL_FULL_CONFDIR@/nwserv.conf'; + +$nonroot_user = 'nobody'; + +$smart_conf_path = '@MARS_NWE_INSTALL_FULL_CONFDIR@/smart.conf'; +$smart_nwclient_path = '@MARS_NWE_INSTALL_FULL_CONFDIR@/.nwclient'; +$smart_static_dir = '@MARS_NWE_INSTALL_FULL_LIBEXEC@/static'; +$smart_log_path = '@MARS_NWE_LOG_DIR@/smart.log'; + +$smart_check_login = '@MARS_NWE_INSTALL_FULL_LIBEXEC@/check_login'; + +$nw_bind_ip = '0.0.0.0'; +$nw_tls_port = 9443; + +$nw_cert_file = '@MARS_NWE_INSTALL_FULL_CONFDIR@/server.crt'; +$nw_key_file = '@MARS_NWE_INSTALL_FULL_CONFDIR@/server.key'; diff --git a/static.pl b/static.pl index 62731ae..02894a4 100644 --- a/static.pl +++ b/static.pl @@ -26,7 +26,7 @@ sub handle_request() { $f = $c[1]; $f =~ s/[^-_\.A-Za-z0-9]//g; - if( ! open( FILE, $base . 'static/' . $f ) ) + if( ! open( FILE, $smart_static_dir . '/' . $f ) ) { error( 404 ); }