diff --git a/exec/addfiles.js b/exec/addfiles.js index 37da051ee8ce66218367251822c75ebab23651b3..0084acf5e491d4533568c4d3172908d1682e2c79 100644 --- a/exec/addfiles.js +++ b/exec/addfiles.js @@ -31,6 +31,16 @@ function archive_date(file) return t; } +function proper_lib_name(name) +{ + for(var i in file_area.lib_list) { + var lib = file_area.lib_list[i]; + if(lib.name.toLowerCase() == name.toLowerCase()) + return lib.name; + } + return name; +} + var uploader; var listfile; var date_fmt; @@ -47,29 +57,36 @@ for(var i = 0; i < argc; i++) { while(opt[0] == '-') opt = opt.slice(1); if(opt == '?' || opt.toLowerCase() == "help") { - writeln("usage: [-options] [dir-code] [listfile] [desc-off]"); + writeln("usage: [dir-spec] [-options] [listfile] [desc-off]"); + writeln(); + writeln("dir-spec:"); + writeln(" -all Add files in all directories of all libraries (implies -auto)"); + writeln(" -lib=<name> * Add files in all directories of specified library (implies -auto)"); + writeln(" -dir=<code>,... * Add files in multiple specified directories"); + writeln(" dir-code Internal code of (one and only) directory to add files to"); + writeln(" * indicates parameters that can be combined and/or specified multiple times"); + writeln(" Note: If no directories are specified, one will be prompted for."); + writeln(); writeln("options:"); - writeln(" -all add files in all libraries/directories (implies -auto)"); - writeln(" -lib=<name> add files in all directories of specified library (implies -auto)"); - writeln(" -auto add files only to directories that have Auto-ADDFILES enabled"); - writeln(" -from=<name> specify uploader's user name (may require quotes)"); - writeln(" -file=<name> specify files to add (wildcards supported, default: *)"); - writeln(" -ex=<filename> add to excluded filename list"); - writeln(" (default: " + default_excludes.join(',') + ")"); - writeln(" -diz always extract/use description in archive"); - writeln(" -update update existing file entries (default is to skip them)"); - writeln(" -readd re-add existing file entries (so they appear as newly-uploaded"); - writeln(" -date[=fmt] include today's date in description"); - writeln(" -fdate[=fmt] include file's date in description"); - writeln(" -adate[=fmt] include newest archived file date in description"); - writeln(" (fmt = optional strftime date/time format string)"); - writeln(" -delete delete list after import"); - writeln(" -v increase verbosity of output"); - writeln(" -debug enable debug output"); - writeln("optional:"); - writeln(" dir-code: File directory internal code"); - writeln(" listfile: Name of listfile (e.g. FILES.BBS)"); - writeln(" desc-off: Description character offset (number)"); + writeln(" -auto Add files only to directories that have Auto-ADDFILES enabled (in SCFG)"); + writeln(" -from=<name> Specify uploader's user name (may require quotes)"); + writeln(" -file=<name> Specify files to add (wildcards supported, default: *)"); + writeln(" -ex=<filename> Add to excluded filename list"); + writeln(" (default: " + default_excludes.join(',') + ")"); + writeln(" -diz Always extract/use description in archive (e.g. FILE_ID.DIZ)"); + writeln(" -update Update existing file entries (default is to skip them)"); + writeln(" -readd Re-add existing file entries (so they appear as newly-uploaded"); + writeln(" -date[=fmt] Include today's date in description"); + writeln(" -fdate[=fmt] Include file's date in description"); + writeln(" -adate[=fmt] Include newest archived file date in description"); + writeln(" (fmt = optional strftime date/time format string)"); + writeln(" -delete Delete list after import"); + writeln(" -v Increase verbosity of output"); + writeln(" -debug Enable debug output"); + writeln(); + writeln("optional listfile parameters:"); + writeln(" listfile Name of listfile to import (e.g. FILES.BBS)"); + writeln(" desc-off Description character-offset in listfile (e.g. 40)"); exit(0); } if(opt.indexOf("ex=") == 0) { @@ -77,9 +94,12 @@ for(var i = 0; i < argc; i++) { continue; } if(opt.indexOf("lib=") == 0) { - var libname = opt.slice(4); + var libname = proper_lib_name(opt.slice(4)); if(!file_area.lib[libname]) { alert("Library not found: " + libname); + writeln("Valid library names:"); + for(var i in file_area.lib) + writeln("\t" + file_area.lib[i].name); exit(1); } for(var j = 0; j < file_area.lib[libname].dir_list.length; j++) @@ -87,6 +107,10 @@ for(var i = 0; i < argc; i++) { options.auto = true; continue; } + if(opt.indexOf("dir=") == 0) { + dir_list.push.apply(dir_list, opt.slice(4).split(',')); + continue; + } if(opt.indexOf("file=") == 0) { include = opt.slice(5); continue; @@ -111,6 +135,7 @@ for(var i = 0; i < argc; i++) { continue; } if(opt == "all") { + dir_list.length = 0; for(var dir in file_area.dir) dir_list.push(dir); options.auto = true; @@ -153,8 +178,8 @@ var updated = 0; var renamed = 0; var missing = []; for(var d = 0; d < dir_list.length; d++) { - - var code = dir_list[d]; + + var code = dir_list[d].toLowerCase(); var dir = file_area.dir[code]; if(!dir) { alert("Directory '" + code + "' does not exist in configuration"); @@ -163,7 +188,7 @@ for(var d = 0; d < dir_list.length; d++) { if(options.auto && (dir.settings & DIR_NOAUTO)) continue; writeln("Adding files to " + dir.lib_name + " " + dir.name); - + var filebase = new FileBase(code); if(!filebase.open("r")) { alert("Failed to open: " + filebase.file); @@ -208,7 +233,6 @@ for(var d = 0; d < dir_list.length; d++) { } file_list = file_list.filter(function(obj) { return wildmatch(obj.name, include); }); - for(var i = 0; i < file_list.length; i++) { var file = file_list[i]; file.from = uploader; diff --git a/src/comio/comio_nix.c b/src/comio/comio_nix.c index af7098fc31f67f0b4c276a3369ab79999051d627..cc3a66217fbdf469e2c65a6db2f4bfd006e054bc 100644 --- a/src/comio/comio_nix.c +++ b/src/comio/comio_nix.c @@ -362,15 +362,27 @@ bool comSetBits(COM_HANDLE handle, size_t byteSize, size_t stopBits) switch(byteSize) { case 5: t.c_cflag |= CS5; +#ifdef ISTRIP + t.c_iflag |= ISTRIP; +#endif break; case 6: t.c_cflag |= CS6; +#ifdef ISTRIP + t.c_iflag |= ISTRIP; +#endif break; case 7: t.c_cflag |= CS7; +#ifdef ISTRIP + t.c_iflag |= ISTRIP; +#endif break; default: t.c_cflag |= CS8; +#ifdef ISTRIP + t.c_iflag &= ~(ISTRIP); +#endif break; } if(stopBits == 2) diff --git a/src/sbbs3/logfile.cpp b/src/sbbs3/logfile.cpp index 29d986902a8cd46584532bba8e8c2f3ba7b520ca..6692f853d636c9e84ac81c63d8303dd46a86fd0a 100644 --- a/src/sbbs3/logfile.cpp +++ b/src/sbbs3/logfile.cpp @@ -271,14 +271,19 @@ void sbbs_t::logch(char ch, bool comma) void sbbs_t::errormsg(int line, const char* function, const char *src, const char* action, const char *object ,int access, const char *extinfo) { - char str[2048]; + char repeat[128] = ""; char errno_str[128]; char errno_info[256] = ""; + static const char* lastfunc; + static int lastline; + static time_t lasttime; + static uint repeat_count; /* prevent recursion */ if(errormsg_inside) return; errormsg_inside=true; + now=time(NULL); if(errno != 0 && strcmp(action, ERR_CHK) != 0) safe_snprintf(errno_info, sizeof(errno_info), "%d (%s) " @@ -291,25 +296,36 @@ void sbbs_t::errormsg(int line, const char* function, const char *src, const cha #endif ); - safe_snprintf(str,sizeof(str),"ERROR %s" + int level = LOG_ERR; + if(function == lastfunc && line == lastline) { + ++repeat_count; + snprintf(repeat, sizeof repeat, "[x%u]", repeat_count + 1); + // De-duplicate by reducing severity of log messages + if((now - lasttime) < 12*60*60) + level = LOG_WARNING; + } else + repeat_count = 0; + lastfunc = function; + lastline = line; + lasttime = now; + lprintf(level, "!ERROR%s %s" "in %s line %u (%s) %s \"%s\" access=%d %s%s" + ,repeat ,errno_info ,src, line, function, action, object, access ,extinfo==NULL ? "":"info=" ,extinfo==NULL ? "":extinfo); - lprintf(LOG_ERR, "!%s", str); if(online == ON_REMOTE) { int savatr=curatr; attr(cfg.color[clr_err]); - bprintf("\7\r\n!ERROR %s %s\r\n", action, object); /* tell user about error */ + bprintf("\7\r\n!ERROR%s %s %s\r\n", repeat, action, object); /* tell user about error */ bputs("\r\nThe sysop has been notified.\r\n"); pause(); attr(savatr); CRLF; } - safe_snprintf(str,sizeof(str),"ERROR %s %s", action, object); - if(cfg.node_num>0) { + if(repeat_count == 0 && cfg.node_num>0) { if(getnodedat(cfg.node_num,&thisnode, true)) { if(thisnode.errors<UCHAR_MAX) thisnode.errors++; @@ -317,12 +333,14 @@ void sbbs_t::errormsg(int line, const char* function, const char *src, const cha putnodedat(cfg.node_num,&thisnode); } } - now=time(NULL); if(logfile_fp!=NULL) { - if(logcol!=1) - fputs(log_line_ending, logfile_fp); - fprintf(logfile_fp,"!! %s%s", str, log_line_ending); + fprintf(logfile_fp,"%s!! ERROR%s %s %s%s" + ,logcol == 1 ? "" : log_line_ending + ,repeat + ,action + ,object + ,log_line_ending); logcol=1; fflush(logfile_fp); } diff --git a/src/ssh/CMakeLists.txt b/src/ssh/CMakeLists.txt index f4b2e184ab14b0fa6a30d868a0df3883a10c7900..8f1c2905f53910b70da5cfe44cf7bad8ecf6d6c0 100644 --- a/src/ssh/CMakeLists.txt +++ b/src/ssh/CMakeLists.txt @@ -32,4 +32,7 @@ target_link_libraries(deuce-ssh_static INTERFACE stdthreads) target_link_libraries(deuce-ssh_shared PRIVATE ${OPENSSL_CRYPTO_LIBRARIES}) target_link_libraries(deuce-ssh_shared PRIVATE stdthreads) +add_executable(client EXCLUDE_FROM_ALL client.c) +target_link_libraries(client PRIVATE stdthreads deuce-ssh) + install(TARGETS deuce-ssh FILE_SET HEADERS) diff --git a/src/ssh/client.c b/src/ssh/client.c new file mode 100644 index 0000000000000000000000000000000000000000..2203cba333900dfe03b3fb80d9dbd70e7444df60 --- /dev/null +++ b/src/ssh/client.c @@ -0,0 +1,179 @@ +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <errno.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <threads.h> + +#include "ssh.h" + +int sock = -1; +size_t txbufsz; +size_t txbuflen; +uint8_t *txbuf; +atomic_bool *tx_terminate; +cnd_t tx_cnd; +mtx_t tx_mtx; +struct deuce_ssh_session sess; + +int +tx_thread(void *arg) +{ + while ((tx_terminate == NULL || *tx_terminate == false) && (sock != -1)) { + mtx_lock(&tx_mtx); + if (txbufsz == 0) + cnd_wait(&tx_cnd, &tx_mtx); + mtx_unlock(&tx_mtx); + struct pollfd fd = { + .fd = sock, + .events = POLLOUT | POLLRDHUP, + .revents = 0, + }; + if (poll(&fd, 1, 5000) == 1) { + if (fd.revents & POLLOUT) { + mtx_lock(&tx_mtx); + ssize_t sent = send(sock, txbuf, txbuflen, MSG_NOSIGNAL); + if (sent > 0) { + memmove(txbuf, &txbuf[sent], txbuflen - sent); + txbuflen -= sent; + } + else if (sent == -1) { + switch(errno) { + case EAGAIN: + case ENOBUFS: + break; + default: + shutdown(sock, SHUT_WR); + *tx_terminate = true; + break; + } + } + mtx_unlock(&tx_mtx); + } + if (fd.revents & (POLLHUP | POLLRDHUP)) { + shutdown(sock, SHUT_WR); + *tx_terminate = true; + } + } + } + return 0; +} + +static int +tx(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata) +{ + mtx_lock(&tx_mtx); + if (txbuflen + bufsz > txbufsz) { + uint8_t *nb = realloc(txbuf, txbuflen + bufsz); + if (nb == NULL) { + mtx_unlock(&tx_mtx); + return DEUCE_SSH_ERROR_ALLOC; + } + else { + tx_terminate = terminate; + txbuf = nb; + memcpy(&txbuf[txbuflen], buf, bufsz); + txbufsz = txbuflen + bufsz; + if (txbuflen == 0) + cnd_signal(&tx_cnd); + txbuflen += bufsz; + } + } + mtx_unlock(&tx_mtx); + return 0; +} + +static int +rx(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata) +{ + size_t rxlen = 0; + + while ((*terminate == false) && (sock != -1) && rxlen < bufsz) { + struct pollfd fd = { + .fd = sock, + .events = POLLIN | POLLRDHUP, + .revents = 0, + }; + if (poll(&fd, 1, 5000) == 1) { + if (fd.revents & POLLIN) { + ssize_t received = recv(sock, &buf[rxlen], bufsz - rxlen, MSG_DONTWAIT); + if (received > 0) { + rxlen += received; + } + else if (received == -1) { + switch(errno) { + case EAGAIN: + case EINTR: + break; + default: + shutdown(sock, SHUT_RD); + *terminate = true; + break; + } + } + } + if (fd.revents & (POLLHUP | POLLRDHUP)) { + shutdown(sock, SHUT_RD); + *terminate = true; + } + } + } + return 0; +} + +static int +rxline(uint8_t *buf, size_t bufsz, size_t *bytes_received, atomic_bool *terminate, void *cbdata) +{ + size_t pos = 0; + bool lastcr = false; + + for (;;) { + int res = rx(&buf[pos], 1, terminate, cbdata); + if (res < 0) + return res; + if (buf[pos] == '\r') + lastcr = true; + if (buf[pos] == '\n' && lastcr) { + *bytes_received = pos + 1; + return 0; + } + if (pos + 1 < bufsz) + pos++; + } +} + +static int +extra_line(uint8_t *buf, size_t bufsz, void *cbdata) +{ + fprintf(stdout, "%.*s\n", (int)bufsz, buf); + return 0; +} + + +int main(int argc, char **argv) +{ + struct sockaddr_in sa = { + .sin_len = sizeof(struct sockaddr_in), + .sin_family = AF_INET, + .sin_port = htons(22), + .sin_addr = htonl(0x7f000001), + }; + mtx_init(&tx_mtx, mtx_plain); + cnd_init(&tx_cnd); + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock == -1) + return 1; + + if (connect(sock, (struct sockaddr *)&sa, sa.sin_len) == -1) + return 1; + if (deuce_ssh_transport_set_callbacks(tx, rx, rxline, extra_line) != 0) + return 1; + thrd_t thr; + thrd_create(&thr, tx_thread, NULL); + deuce_ssh_session_init(&sess); + int res; + thrd_join(thr, &res); +} diff --git a/src/ssh/ssh-trans.c b/src/ssh/ssh-trans.c index 5fa1ab01a2e60f9f94b1b3b251adc463f5d340a0..91d2eda8daced2569876bc28146070f8479d1b45 100644 --- a/src/ssh/ssh-trans.c +++ b/src/ssh/ssh-trans.c @@ -5,7 +5,22 @@ #include "ssh.h" #include "ssh-trans.h" +typedef struct deuce_ssh_transport_global_config { + atomic_bool used; + const char *software_version; + const char *version_comment; + size_t kex_entries; + char **kex_name; + deuce_ssh_kex_handler_t *kex_handler; + deuce_ssh_kex_cleanup_t *kex_cleanup; + int (*tx)(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata); + int (*rx)(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata); + int (*rx_line)(uint8_t *buf, size_t bufsz, size_t *bytes_received, atomic_bool *terminate, void *cbdata); + int (*extra_line_cb)(uint8_t *buf, size_t bufsz, void *cbdata); +} *deuce_ssh_transport_global_config_t; + static const char * const sw_ver = "DeuceSSH-0.0"; +static struct deuce_ssh_transport_global_config gconf; static inline bool has_nulls(uint8_t *buf, size_t buflen) @@ -17,7 +32,7 @@ static inline bool missing_crlf(uint8_t *buf, size_t buflen) { assert(buflen >= 2); - return (buf[buflen - 1] == '\n' && buf[buflen - 2] == '\r'); + return (buf[buflen - 1] != '\n' || buf[buflen - 2] != '\r'); } static inline bool @@ -33,7 +48,7 @@ is_20(uint8_t *buf, size_t buflen) { if (buflen < 8) return false; - return (buf[4] == '2' && buf[5] != '.' && buf[6] != '0' && buf[7] != '-'); + return (buf[4] == '2' && buf[5] == '.' && buf[6] == '0' && buf[7] == '-'); } static inline void * @@ -53,7 +68,7 @@ version_ex(deuce_ssh_session_t sess) uint8_t line[256]; while (!sess->terminate) { - res = sess->rx_line(line, sizeof(line) - 1, &received, &sess->terminate, sess->rx_line_cbdata); + res = gconf.rx_line(line, sizeof(line) - 1, &received, &sess->terminate, sess->rx_line_cbdata); if (res < 0) { sess->terminate = true; return res; @@ -83,9 +98,9 @@ version_ex(deuce_ssh_session_t sess) assert(res == thrd_success); return 0; } - if (sess->extra_line_cb) { + if (gconf.extra_line_cb) { line[received] = 0; - res = sess->extra_line_cb(line, received, sess->extra_line_cbdata); + res = gconf.extra_line_cb(line, received, sess->extra_line_cbdata); if (res < 0) { sess->terminate = true; return res; @@ -122,38 +137,44 @@ tx_handshake(void *arg) { deuce_ssh_session_t sess = arg; int res; + uint8_t line[255]; + size_t sz = 0; /* Handshake */ - res = sess->tx((uint8_t *)"SSH-2.0-", 8, &sess->terminate, sess->tx_cbdata); - if (res < 0) { - sess->terminate = true; - return res; + memcpy(line, "SSH-2.0-", 8); + sz += 8; + size_t asz = strlen(gconf.software_version); + if (sz + asz + 2 > 255) + return DEUCE_SSH_ERROR_TOOLONG; + memcpy(&line[sz], gconf.software_version, asz); + sz += asz; + if (gconf.version_comment != NULL) { + memcpy(&line[sz], " ", 1); + sz += 1; + asz = strlen(gconf.version_comment); + if (sz + asz + 2 > 255) + return DEUCE_SSH_ERROR_TOOLONG; + memcpy(&line[sz], gconf.version_comment, asz); + sz += asz; } - size_t sz = strlen(sess->software_version); - res = sess->tx((uint8_t *)sess->software_version, sz, &sess->terminate, sess->tx_cbdata); + memcpy(&line[sz], "\r\n", 2); + sz += 2; + res = gconf.tx(line, sz, &sess->terminate, sess->tx_cbdata); if (res < 0) { sess->terminate = true; return res; } - if (sess->version_comment != NULL) { - res = sess->tx((uint8_t *)" ", 1, &sess->terminate, sess->tx_cbdata); - if (res < 0) { - sess->terminate = true; - return res; - } - sz = strlen(sess->version_comment); - res = sess->tx((uint8_t *)sess->software_version, sz, &sess->terminate, sess->tx_cbdata); - if (res < 0) { - sess->terminate = true; - return res; - } - } return 0; } void deuce_ssh_transport_cleanup(deuce_ssh_session_t sess) { + if (sess->trans->kex_selected != SIZE_MAX) { + if (gconf.kex_cleanup[sess->trans->kex_selected] != NULL) + gconf.kex_cleanup[sess->trans->kex_selected](sess); + sess->trans->kex_selected = SIZE_MAX; + } free(sess->remote_software_version); sess->remote_software_version = NULL; free(sess->remote_version_comment); @@ -163,9 +184,13 @@ deuce_ssh_transport_cleanup(deuce_ssh_session_t sess) int deuce_ssh_transport_init(deuce_ssh_session_t sess) { - if (sess->software_version == NULL) - sess->software_version = sw_ver; + gconf.used = true; + if (gconf.software_version == NULL) + gconf.software_version = sw_ver; + sess->trans = calloc(1, sizeof(struct deuce_ssh_transport_state)); + if (sess->trans == NULL) + return DEUCE_SSH_ERROR_ALLOC; thrd_t thrd; if (thrd_create(&thrd, rx_thread, sess) != thrd_success) return DEUCE_SSH_ERROR_INIT; @@ -176,7 +201,55 @@ deuce_ssh_transport_init(deuce_ssh_session_t sess) thrd_join(thrd, &tres); return res; } + sess->trans->kex_selected = SIZE_MAX; + sess->trans->kex_state = 0; + + sess->trans->transport_thread = thrd; + return 0; +} + +int +deuce_ssh_transport_register_kex(const char *name, deuce_ssh_kex_handler_t kex_handler, deuce_ssh_kex_cleanup_t kex_cleanup) +{ + if (gconf.used) + return DEUCE_SSH_ERROR_TOOLATE; + if (gconf.kex_entries + 1 == SIZE_MAX) + return DEUCE_SSH_ERROR_TOOMANY; + char **newnames = realloc(gconf.kex_name, sizeof(gconf.kex_name[0]) * (gconf.kex_entries + 1)); + if (newnames == NULL) + return DEUCE_SSH_ERROR_ALLOC; + gconf.kex_name = newnames; + gconf.kex_name[gconf.kex_entries] = strdup(name); + + deuce_ssh_kex_handler_t *newhandlers = realloc(gconf.kex_handler, sizeof(gconf.kex_handler[0]) * (gconf.kex_entries + 1)); + if (newhandlers == NULL) { + free(gconf.kex_name[gconf.kex_entries]); + return DEUCE_SSH_ERROR_ALLOC; + } + gconf.kex_handler = newhandlers; + gconf.kex_handler[gconf.kex_entries] = kex_handler; + + deuce_ssh_kex_cleanup_t *newcleanup = realloc(gconf.kex_cleanup, sizeof(gconf.kex_cleanup[0]) * (gconf.kex_entries + 1)); + if (newcleanup == NULL) { + free(gconf.kex_name[gconf.kex_entries]); + return DEUCE_SSH_ERROR_ALLOC; + } + gconf.kex_cleanup = newcleanup; + gconf.kex_cleanup[gconf.kex_entries] = kex_cleanup; + + gconf.kex_entries++; + return 0; +} + +int +deuce_ssh_transport_set_callbacks(deuce_ssh_transport_io_cb_t tx, deuce_ssh_transport_io_cb_t rx, deuce_ssh_transport_rxline_cb_t rx_line, deuce_ssh_transport_extra_line_cb_t extra_line_cb) +{ + if (gconf.used) + return DEUCE_SSH_ERROR_TOOLATE; + gconf.tx = tx; + gconf.rx = rx; + gconf.rx_line = rx_line; + gconf.extra_line_cb = extra_line_cb; - sess->transport_thread = thrd; return 0; } diff --git a/src/ssh/ssh-trans.h b/src/ssh/ssh-trans.h index 11e68f23377db9920c204d7975f1623451af4e93..f388531ed0b2f34b95c78f30a186b6c244d7e811 100644 --- a/src/ssh/ssh-trans.h +++ b/src/ssh/ssh-trans.h @@ -1,5 +1,6 @@ // RFC-4253 +#include "ssh.h" #include "ssh-arch.h" #ifndef DEUCE_SSH_TRANS_H @@ -33,19 +34,41 @@ #define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 #define SSH_DISCONNECT_ILLEGAL_USER_NAME 15 -struct deuce_ssh_transport_packet { +typedef struct deuce_ssh_transport_packet { deuce_ssh_string_t payload; deuce_ssh_string_t random_padding; deuce_ssh_string_t mac; deuce_ssh_uint32_t packet_length; deuce_ssh_byte_t padding; -}; +} *deuce_ssh_transport_packet_t; -struct deuce_ssh_transport_state { +typedef int (*deuce_ssh_kex_handler_t)(deuce_ssh_transport_packet_t pkt, deuce_ssh_session_t sess); +typedef void (*deuce_ssh_kex_cleanup_t)(deuce_ssh_session_t sess); + +typedef struct deuce_ssh_transport_state { uint32_t tx_seq; uint32_t rx_seq; bool client; -}; + + /* Transport options */ + thrd_t transport_thread; + + /* KEX options */ + void *kex_cbdata; + uint32_t kex_state; + size_t kex_selected; + + /* KEX outputs */ + size_t shared_secret_sz; + uint8_t *shared_secret; + size_t exchange_hash_sz; + uint8_t *exchange_hash; + + size_t enc_selected; + size_t mac_selected; + size_t comp_selected; + +} *deuce_ssh_transport_state_t; int deuce_ssh_transport_init(deuce_ssh_session_t sess); void deuce_ssh_transport_cleanup(deuce_ssh_session_t sess); diff --git a/src/ssh/ssh.c b/src/ssh/ssh.c index 4b645ee0de20dd4ef3306a616ca8bbc77bf6ec25..c688776e9a64e1926a0923c92c3d29c3669459c8 100644 --- a/src/ssh/ssh.c +++ b/src/ssh/ssh.c @@ -9,9 +9,8 @@ deuce_ssh_session_init(deuce_ssh_session_t sess) return DEUCE_SSH_ERROR_INIT; res = deuce_ssh_transport_init(sess); - if (res < 0) { + if (res < 0) return res; - } sess->initialized = true; return 0; @@ -24,7 +23,7 @@ deuce_ssh_session_terminate(deuce_ssh_session_t sess) if (atomic_compare_exchange_strong(&sess->initialized, &t, false)) { sess->terminate = true; int tres; - thrd_join(sess->transport_thread, &tres); + thrd_join(sess->trans->transport_thread, &tres); sess->terminate = false; return true; } diff --git a/src/ssh/ssh.h b/src/ssh/ssh.h index 7036cbad02f0d7aa629115361a9605962b7783f9..41bce6f58413a020fe630a7f16cfde2649caf2e5 100644 --- a/src/ssh/ssh.h +++ b/src/ssh/ssh.h @@ -20,6 +20,14 @@ _Static_assert(0, "threads.h support required"); #define DEUCE_SSH_ERROR_ALLOC -3 #define DEUCE_SSH_ERROR_INIT -4 #define DEUCE_SSH_ERROR_TERMINATED -5 +#define DEUCE_SSH_ERROR_TOOLATE -6 +#define DEUCE_SSH_ERROR_TOOMANY -7 +#define DEUCE_SSH_ERROR_TOOLONG -8 + +typedef struct deuce_ssh_transport_state *deuce_ssh_transport_state_t; +typedef int (*deuce_ssh_transport_io_cb_t)(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata); +typedef int (*deuce_ssh_transport_rxline_cb_t)(uint8_t *buf, size_t bufsz, size_t *bytes_received, atomic_bool *terminate, void *cbdata); +typedef int (*deuce_ssh_transport_extra_line_cb_t)(uint8_t *buf, size_t bufsz, void *cbdata); typedef struct deuce_ssh_session { /* Global */ @@ -27,26 +35,22 @@ typedef struct deuce_ssh_session { atomic_bool initialized; atomic_bool terminate; - /* Transport options */ - const char *software_version; - const char *version_comment; + /* Transport Remote information */ + char *remote_software_version; + char *remote_version_comment; + void *tx_cbdata; - int (*tx)(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata); void *rx_cbdata; - int (*rx)(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata); void *rx_line_cbdata; - int (*rx_line)(uint8_t *buf, size_t bufsz, size_t *bytes_received, atomic_bool *terminate, void *cbdata); void *extra_line_cbdata; - int (*extra_line_cb)(uint8_t *buf, size_t bufsz, void *cbdata); - thrd_t transport_thread; - /* Transport Remote information */ - char *remote_software_version; - char *remote_version_comment; + deuce_ssh_transport_state_t trans; } *deuce_ssh_session_t; int deuce_ssh_session_init(deuce_ssh_session_t sess); bool deuce_ssh_session_terminate(deuce_ssh_session_t sess); void deuce_ssh_session_cleanup(deuce_ssh_session_t sess); +int deuce_ssh_transport_set_callbacks(deuce_ssh_transport_io_cb_t tx, deuce_ssh_transport_io_cb_t rx, deuce_ssh_transport_rxline_cb_t rx_line, deuce_ssh_transport_extra_line_cb_t extra_line_cb); + #endif diff --git a/src/xpdev/filewrap.c b/src/xpdev/filewrap.c index 35ebe13eab869dd9a8d3db1795d58171e6f58deb..c7415dea0ba6678681c2ff60f7b573d7dc8a05e2 100644 --- a/src/xpdev/filewrap.c +++ b/src/xpdev/filewrap.c @@ -70,24 +70,28 @@ off_t filelength(int fd) return(st.st_size); } -// See https://patchwork.kernel.org/patch/9289177/ -#if defined(F_OFD_SETLK) && _FILE_OFFSET_BITS != 64 - #undef F_OFD_SETLK -#endif - -#if defined(__linux__) && !defined(F_OFD_SETLK) - #warning Linux OFD locks not enabled! -#endif - -#if defined(F_OFD_SETLK) - #undef F_SETLK - #define F_SETLK F_OFD_SETLK +/*************************************/ +/* Use OFD fcntl() locks when we can */ +/*************************************/ +#if defined __linux__ + #define USE_FCNTL_LOCKS + // See https://patchwork.kernel.org/patch/9289177/ + #if defined F_OFD_SETLK && _FILE_OFFSET_BITS != 64 + #undef F_OFD_SETLK + #endif + + #if defined F_OFD_SETLK + #undef F_SETLK + #define F_SETLK F_OFD_SETLK + #else + #warning Linux OFD locks not enabled! + #endif #endif /* Sets a lock on a portion of a file */ int lock(int fd, off_t pos, off_t len) { -#if !defined(BSD) +#if defined USE_FCNTL_LOCKS struct flock alock = {0}; // fcntl() will return EBADF if we try to set a write lock a file opened O_RDONLY @@ -117,7 +121,7 @@ int lock(int fd, off_t pos, off_t len) int unlock(int fd, off_t pos, off_t len) { -#if !defined(BSD) +#if defined USE_FCNTL_LOCKS struct flock alock = {0}; alock.l_type = F_UNLCK; /* remove the lock */ @@ -195,7 +199,7 @@ int sopen(const char *fn, int sh_access, int share, ...) if (share == SH_DENYNO || share == SH_COMPAT) /* no lock needed */ return fd; -#if !defined(BSD) +#if defined USE_FCNTL_LOCKS struct flock alock = {0}; // lock entire file from offset 0