561 lines
13 KiB
C
561 lines
13 KiB
C
#include <stdio.h>
|
|
#include <sys/stat.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <libgen.h>
|
|
#include <signal.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/ioctl.h>
|
|
#include <fcntl.h>
|
|
#include <iconv.h>
|
|
#if defined(linux)
|
|
# include <pty.h>
|
|
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
|
# include <util.h>
|
|
#elif defined(__FreeBSD__)
|
|
# include <libutil.h>
|
|
#elif defined(__sun)
|
|
# include "os/sunos.h"
|
|
#endif
|
|
#include "bbs.h"
|
|
#include "lua/lua.h"
|
|
#include "lua/lualib.h"
|
|
#include "lua/lauxlib.h"
|
|
|
|
extern struct bbs_config conf;
|
|
extern int mynode;
|
|
extern int gSocket;
|
|
extern int sshBBS;
|
|
extern int bbs_stderr;
|
|
|
|
int running_door_pid = 0;
|
|
int running_door = 0;
|
|
|
|
extern int telnet_bin_mode;
|
|
extern int timeoutpaused;
|
|
|
|
void doorchld_handler(int s)
|
|
{
|
|
// waitpid() might overwrite errno, so we save and restore it:
|
|
while(waitpid(-1, NULL, WNOHANG) > 0);
|
|
|
|
running_door = 0;
|
|
}
|
|
|
|
int write_door32sys(struct user_record *user) {
|
|
struct stat s;
|
|
char buffer[1024];
|
|
FILE *fptr;
|
|
char *ptr;
|
|
int i;
|
|
|
|
sprintf(buffer, "%s/node%d", conf.bbs_path, mynode);
|
|
|
|
if (stat(buffer, &s) != 0) {
|
|
mkdir(buffer, 0755);
|
|
}
|
|
|
|
snprintf(buffer, 1024, "%s/node%d/door32.sys", conf.bbs_path, mynode);
|
|
|
|
fptr = fopen(buffer, "w");
|
|
|
|
if (!fptr) {
|
|
dolog("Unable to open %s for writing!", buffer);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(fptr, "2\r\n"); // telnet type
|
|
fprintf(fptr, "%d\r\n", gSocket); // socket
|
|
fprintf(fptr, "38400\r\n"); // baudrate
|
|
fprintf(fptr, "Magicka %d.%d\r\n", VERSION_MAJOR, VERSION_MINOR);
|
|
fprintf(fptr, "%d\r\n", user->id);
|
|
fprintf(fptr, "%s %s\r\n", user->firstname, user->lastname);
|
|
fprintf(fptr, "%s\r\n", user->loginname);
|
|
fprintf(fptr, "%d\r\n", user->sec_level);
|
|
fprintf(fptr, "%d\r\n", user->timeleft);
|
|
fprintf(fptr, "1\r\n"); // ansi emulation = 1
|
|
fprintf(fptr, "%d\r\n", mynode);
|
|
|
|
fclose(fptr);
|
|
|
|
// create dorinfo1.def
|
|
|
|
sprintf(buffer, "%s/node%d/dorinfo1.def", conf.bbs_path, mynode);
|
|
|
|
fptr = fopen(buffer, "w");
|
|
|
|
if (!fptr) {
|
|
dolog("Unable to open %s for writing!", buffer);
|
|
return 1;
|
|
}
|
|
|
|
strcpy(buffer, conf.sysop_name);
|
|
|
|
ptr = NULL;
|
|
|
|
for (i=0;i<strlen(buffer);i++) {
|
|
if (buffer[i] == ' ') {
|
|
ptr = &buffer[i+1];
|
|
buffer[i] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
fprintf(fptr, "%s\r\n", conf.bbs_name); // telnet type
|
|
fprintf(fptr, "%s\r\n", buffer);
|
|
if (ptr != NULL) {
|
|
fprintf(fptr, "%s\r\n", ptr);
|
|
} else {
|
|
fprintf(fptr, "\r\n");
|
|
}
|
|
fprintf(fptr, "COM1\r\n"); // com port
|
|
fprintf(fptr, "38400 BAUD,N,8,1\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
fprintf(fptr, "%s\r\n", user->firstname);
|
|
fprintf(fptr, "%s\r\n", user->lastname);
|
|
fprintf(fptr, "%s\r\n", user->location);
|
|
fprintf(fptr, "1\r\n");
|
|
fprintf(fptr, "%d\r\n", user->sec_level);
|
|
fprintf(fptr, "%d\r\n", user->timeleft);
|
|
fprintf(fptr, "-1\r\n");
|
|
|
|
fclose(fptr);
|
|
|
|
// create door.sys
|
|
|
|
sprintf(buffer, "%s/node%d/door.sys", conf.bbs_path, mynode);
|
|
|
|
fptr = fopen(buffer, "w");
|
|
|
|
if (!fptr) {
|
|
dolog("Unable to open %s for writing!", buffer);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(fptr, "COM1:\r\n");
|
|
fprintf(fptr, "38400\r\n");
|
|
fprintf(fptr, "8\r\n");
|
|
fprintf(fptr, "%d\r\n", mynode);
|
|
fprintf(fptr, "38400\r\n");
|
|
fprintf(fptr, "Y\r\n");
|
|
fprintf(fptr, "N\r\n");
|
|
fprintf(fptr, "Y\r\n");
|
|
fprintf(fptr, "Y\r\n");
|
|
fprintf(fptr, "%s %s\r\n", user->firstname, user->lastname);
|
|
fprintf(fptr, "%s\r\n", user->location);
|
|
fprintf(fptr, "00-0000-0000\r\n");
|
|
fprintf(fptr, "00-0000-0000\r\n");
|
|
fprintf(fptr, "SECRET\r\n");
|
|
fprintf(fptr, "%d\r\n", user->sec_level);
|
|
fprintf(fptr, "%d\r\n", user->timeson);
|
|
fprintf(fptr, "01-01-1971\r\n");
|
|
fprintf(fptr, "%d\r\n", user->timeleft * 60);
|
|
fprintf(fptr, "%d\r\n", user->timeleft);
|
|
fprintf(fptr, "GR\r\n");
|
|
fprintf(fptr, "25\r\n");
|
|
fprintf(fptr, "N\r\n");
|
|
fprintf(fptr, "\r\n");
|
|
fprintf(fptr, "\r\n");
|
|
fprintf(fptr, "\r\n");
|
|
fprintf(fptr, "%d\r\n", user->id);
|
|
fprintf(fptr, "\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
fprintf(fptr, "99999\r\n");
|
|
fprintf(fptr, "01-01-1971\r\n");
|
|
fprintf(fptr, "\r\n");
|
|
fprintf(fptr, "\r\n");
|
|
fprintf(fptr, "%s\r\n", conf.sysop_name);
|
|
fprintf(fptr, "%s\r\n", user->loginname);
|
|
fprintf(fptr, "none\r\n");
|
|
fprintf(fptr, "Y\r\n");
|
|
fprintf(fptr, "N\r\n");
|
|
fprintf(fptr, "Y\r\n");
|
|
fprintf(fptr, "7\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
fprintf(fptr, "01-01-1971\r\n");
|
|
fprintf(fptr, "00:00\r\n");
|
|
fprintf(fptr, "00:00\r\n");
|
|
fprintf(fptr, "32768\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
fprintf(fptr, "None.\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
fprintf(fptr, "0\r\n");
|
|
|
|
fclose(fptr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void rundoor(struct user_record *user, char *cmd, int stdio, char *codepage) {
|
|
char *arguments[4];
|
|
int door_out;
|
|
char buffer[10];
|
|
|
|
if (sshBBS) {
|
|
door_out = STDOUT_FILENO;
|
|
} else {
|
|
door_out = gSocket;
|
|
}
|
|
arguments[0] = strdup(cmd);
|
|
sprintf(buffer, "%d", mynode);
|
|
arguments[1] = strdup(buffer);
|
|
sprintf(buffer, "%d", door_out);
|
|
arguments[2] = strdup(buffer);
|
|
arguments[3] = NULL;
|
|
|
|
runexternal(user, cmd, stdio, arguments, NULL, 0, codepage);
|
|
|
|
free(arguments[0]);
|
|
free(arguments[1]);
|
|
free(arguments[2]);
|
|
}
|
|
|
|
void runexternal(struct user_record *user, char *cmd, int stdio, char *argv[], char *cwd, int raw, char *codepage) {
|
|
|
|
char buffer[1024];
|
|
int ret;
|
|
unsigned char c;
|
|
int len;
|
|
int master;
|
|
int slave;
|
|
fd_set fdset;
|
|
int t;
|
|
struct winsize ws;
|
|
struct sigaction sa;
|
|
int door_in;
|
|
int door_out;
|
|
int i;
|
|
int gotiac;
|
|
int flush;
|
|
iconv_t ic;
|
|
|
|
struct timeval thetimeout;
|
|
struct termios oldit;
|
|
struct termios oldot;
|
|
struct termios oldit2;
|
|
|
|
char inbuf[256];
|
|
char outbuf[512];
|
|
int h;
|
|
int g;
|
|
char *ptr1;
|
|
char *ptr2;
|
|
char *ptr2p;
|
|
size_t ouc;
|
|
size_t inc;
|
|
size_t sz;
|
|
char **args;
|
|
int arg_count;
|
|
pid_t pid;
|
|
int iac;
|
|
char iac_binary_will[] = {IAC, IAC_WILL, IAC_TRANSMIT_BINARY, '\0'};
|
|
char iac_binary_do[] = {IAC, IAC_DO, IAC_TRANSMIT_BINARY, '\0'};
|
|
char iac_binary_wont[] = {IAC, IAC_WONT, IAC_TRANSMIT_BINARY, '\0'};
|
|
char iac_binary_dont[] = {IAC, IAC_DONT, IAC_TRANSMIT_BINARY, '\0'};
|
|
|
|
timeoutpaused = 1;
|
|
|
|
if (write_door32sys(user) != 0) {
|
|
return;
|
|
}
|
|
|
|
if (stdio) {
|
|
if (sshBBS) {
|
|
door_in = STDIN_FILENO;
|
|
door_out = STDOUT_FILENO;
|
|
} else {
|
|
door_in = gSocket;
|
|
door_out = gSocket;
|
|
}
|
|
|
|
|
|
|
|
ws.ws_row = 24;
|
|
ws.ws_col = 80;
|
|
|
|
running_door = 1;
|
|
|
|
if (!sshBBS) {
|
|
if (openpty(&master, &slave, NULL, NULL, &ws) == 0) {
|
|
sa.sa_handler = doorchld_handler;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
|
|
perror("sigaction");
|
|
exit(1);
|
|
}
|
|
if (raw) {
|
|
ttySetRaw(master, &oldit2);
|
|
ttySetRaw(slave, &oldit2);
|
|
}
|
|
pid = fork();
|
|
if (pid < 0) {
|
|
return;
|
|
} else if (pid == 0) {
|
|
if (cwd != NULL) {
|
|
chdir(cwd);
|
|
}
|
|
close(master);
|
|
|
|
dup2(slave, 0);
|
|
dup2(slave, 1);
|
|
|
|
close(slave);
|
|
|
|
setsid();
|
|
|
|
ioctl(0, TIOCSCTTY, 1);
|
|
|
|
execvp(cmd, argv);
|
|
} else {
|
|
running_door_pid = pid;
|
|
gotiac = 0;
|
|
flush = 0;
|
|
|
|
while(running_door || !flush) {
|
|
FD_ZERO(&fdset);
|
|
FD_SET(master, &fdset);
|
|
FD_SET(door_in, &fdset);
|
|
if (master > door_in) {
|
|
t = master + 1;
|
|
} else {
|
|
t = door_in + 1;
|
|
}
|
|
|
|
thetimeout.tv_sec = 5;
|
|
thetimeout.tv_usec = 0;
|
|
|
|
ret = select(t, &fdset, NULL, NULL, &thetimeout);
|
|
if (ret > 0) {
|
|
if (FD_ISSET(door_in, &fdset)) {
|
|
len = read(door_in, inbuf, 256);
|
|
if (len == 0) {
|
|
close(master);
|
|
disconnect("Socket Closed");
|
|
return;
|
|
}
|
|
g = 0;
|
|
for (h=0;h<len;h++) {
|
|
c = inbuf[h];
|
|
if (!raw) {
|
|
if (c == '\n' || c == '\0') {
|
|
continue;
|
|
}
|
|
}
|
|
if (!running_door) {
|
|
continue;
|
|
}
|
|
|
|
if (c == 255) {
|
|
if (gotiac == 1) {
|
|
outbuf[g++] = c;
|
|
gotiac = 0;
|
|
} else {
|
|
gotiac = 1;
|
|
}
|
|
} else {
|
|
if (gotiac == 1) {
|
|
if (c == 254 || c == 253 || c == 252 || c == 251) {
|
|
gotiac = 2;
|
|
iac = c;
|
|
} else if (c == 250) {
|
|
gotiac = 3;
|
|
} else {
|
|
gotiac = 0;
|
|
}
|
|
} else if (gotiac == 2) {
|
|
switch (iac) {
|
|
case IAC_WILL:
|
|
if (c == 0) {
|
|
if (telnet_bin_mode != 1) {
|
|
telnet_bin_mode = 1;
|
|
write(master, iac_binary_do, 3);
|
|
}
|
|
}
|
|
break;
|
|
case IAC_WONT:
|
|
if (c == 0) {
|
|
if (telnet_bin_mode != 0) {
|
|
telnet_bin_mode = 0;
|
|
write(master, iac_binary_dont, 3);
|
|
}
|
|
}
|
|
break;
|
|
case IAC_DO:
|
|
if (c == 0) {
|
|
if (telnet_bin_mode != 1) {
|
|
telnet_bin_mode = 1;
|
|
write(master, iac_binary_will, 3);
|
|
}
|
|
}
|
|
break;
|
|
case IAC_DONT:
|
|
if (c == 0) {
|
|
if (telnet_bin_mode != 0) {
|
|
telnet_bin_mode = 0;
|
|
write(master, iac_binary_wont, 3);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
gotiac = 0;
|
|
} else if (gotiac == 3) {
|
|
if (c == 240) {
|
|
gotiac = 0;
|
|
}
|
|
} else {
|
|
outbuf[g++] = c;
|
|
}
|
|
}
|
|
}
|
|
if (codepage == NULL || (strcmp(codepage, "CP437") == 0 && user->codepage == 0) || (strcmp(codepage, "UTF-8") == 0 && user->codepage == 1)) {
|
|
write(master, outbuf, g);
|
|
} else {
|
|
if (user->codepage == 0) {
|
|
ic = iconv_open(codepage, "CP437");
|
|
} else {
|
|
ic = iconv_open(codepage, "UTF-8");
|
|
}
|
|
ptr1 = outbuf;
|
|
ptr2 = (char *)malloc((g + 1) * 4);
|
|
ptr2p = ptr2;
|
|
memset(ptr2, 0, (g + 1) * 4);
|
|
inc = g;
|
|
ouc = (g + 1) * 4;
|
|
|
|
iconv(ic, &ptr1, &inc, &ptr2, &ouc);
|
|
write(master, ptr2p, ptr2 - ptr2p);
|
|
|
|
free(ptr2p);
|
|
iconv_close(ic);
|
|
}
|
|
} else if (FD_ISSET(master, &fdset)) {
|
|
len = read(master, inbuf, 256);
|
|
if (len == 0) {
|
|
close(master);
|
|
break;
|
|
}
|
|
g = 0;
|
|
for (h=0;h<len;h++) {
|
|
c = inbuf[h];
|
|
if (c == 255) {
|
|
outbuf[g++] = c;
|
|
}
|
|
outbuf[g++] = c;
|
|
}
|
|
if (codepage == NULL || (strcmp(codepage, "CP437") == 0 && user->codepage == 0) || (strcmp(codepage, "UTF-8") == 0 && user->codepage == 1)) {
|
|
write(door_out, outbuf, g);
|
|
} else {
|
|
if (user->codepage == 0) {
|
|
ic = iconv_open("CP437", codepage);
|
|
} else {
|
|
ic = iconv_open("UTF-8", codepage);
|
|
}
|
|
ptr1 = outbuf;
|
|
ptr2 = (char *)malloc((g + 1) * 4);
|
|
ptr2p = ptr2;
|
|
memset(ptr2, 0, (g + 1) * 4);
|
|
inc = g;
|
|
ouc = (g + 1) * 4;
|
|
|
|
sz = iconv(ic, &ptr1, &inc, &ptr2, &ouc);
|
|
if (sz == -1) {
|
|
perror("Iconv");
|
|
}
|
|
write(door_out, ptr2p, ptr2 - ptr2p);
|
|
|
|
free(ptr2p);
|
|
iconv_close(ic);
|
|
}
|
|
}
|
|
} else {
|
|
if (!running_door) {
|
|
flush = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
if (raw) {
|
|
ttySetRaw(STDIN_FILENO, &oldit);
|
|
ttySetRaw(STDOUT_FILENO, &oldot);
|
|
}
|
|
|
|
sa.sa_handler = doorchld_handler;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
|
|
perror("sigaction");
|
|
exit(1);
|
|
}
|
|
pid = fork();
|
|
if (pid < 0) {
|
|
return;
|
|
} else if (pid == 0) {
|
|
if (cwd != NULL) {
|
|
chdir(cwd);
|
|
}
|
|
|
|
dup2(bbs_stderr, 2);
|
|
execvp(cmd, argv);
|
|
} else {
|
|
while(running_door) {
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
if (raw) {
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldit);
|
|
tcsetattr(STDOUT_FILENO, TCSANOW, &oldot);
|
|
}
|
|
}
|
|
} else {
|
|
if (!sshBBS) {
|
|
snprintf(buffer, 1024, "%s", cmd);
|
|
for (i=1;argv[i] != NULL; i++) {
|
|
snprintf(&buffer[strlen(buffer)], 1024 - strlen(buffer), " %s", argv[i]);
|
|
}
|
|
if (cwd != NULL) {
|
|
chdir(cwd);
|
|
}
|
|
args = (char **)malloc(sizeof (char *));
|
|
arg_count = 0;
|
|
args[arg_count] = strtok(buffer, " ");
|
|
while (args[arg_count] != NULL) {
|
|
arg_count++;
|
|
args = (char **)realloc(args, sizeof(char *) * (arg_count + 1));
|
|
args[arg_count] = strtok(NULL, " ");
|
|
}
|
|
cmd = strdup(args[0]);
|
|
pid = fork();
|
|
if (pid == 0) {
|
|
execvp(cmd, args);
|
|
exit(0);
|
|
} else if (pid > 0) {
|
|
waitpid(pid, &ret, 0);
|
|
} else {
|
|
ret = -1;
|
|
}
|
|
free(cmd);
|
|
free(args);
|
|
if (cwd != NULL) {
|
|
chdir(conf.bbs_path);
|
|
}
|
|
} else {
|
|
s_printf(get_string(51));
|
|
}
|
|
}
|
|
timeoutpaused = 0;
|
|
}
|