diff --git a/bbs.c b/bbs.c index 2d2f616..20c0db4 100644 --- a/bbs.c +++ b/bbs.c @@ -20,7 +20,7 @@ struct bbs_config conf; struct user_record *gUser; int gSocket; - +int sshBBS; int usertimeout; int timeoutpaused; @@ -145,11 +145,19 @@ void s_printf(char *fmt, ...) { } void s_putchar(char c) { - write(gSocket, &c, 1); + if (sshBBS) { + putchar(c); + } else { + write(gSocket, &c, 1); + } } void s_putstring(char *c) { - write(gSocket, c, strlen(c)); + if (sshBBS) { + printf("%s", c); + } else { + write(gSocket, c, strlen(c)); + } } void s_displayansi_p(char *file) { @@ -194,31 +202,35 @@ char s_getchar() { int len; do { - - len = read(gSocket, &c, 1); - + + if (sshBBS) { + len = read(stdin, &c, 1); + } else { + len = read(gSocket, &c, 1); + } if (len == 0) { disconnect("Socket Closed"); } - while (c == 255) { - len = read(gSocket, &c, 1); - if (len == 0) { - disconnect("Socket Closed"); - } else if (c == 255) { - usertimeout = 10; - return c; - } - len = read(gSocket, &c, 1); - if (len == 0) { - disconnect("Socket Closed"); - } - len = read(gSocket, &c, 1); - if (len == 0) { - disconnect("Socket Closed"); + if (!sshBBS) { + while (c == 255) { + len = read(gSocket, &c, 1); + if (len == 0) { + disconnect("Socket Closed"); + } else if (c == 255) { + usertimeout = 10; + return c; + } + len = read(gSocket, &c, 1); + if (len == 0) { + disconnect("Socket Closed"); + } + len = read(gSocket, &c, 1); + if (len == 0) { + disconnect("Socket Closed"); + } } - } - + } if (c == '\r') { @@ -298,8 +310,10 @@ void disconnect(char *calledby) { } dolog("Node %d disconnected (%s)", mynode, calledby); sprintf(buffer, "%s/nodeinuse.%d", conf.bbs_path, mynode); - remove(buffer); - close(gSocket); + remove(buffer); + if (!sshBBS) { + close(gSocket); + } exit(0); } @@ -456,7 +470,7 @@ void automessage_display() { s_getc(); } -void runbbs(int socket, char *ip) { +void runbbs_real(int socket, char *ip, int ssh) { char buffer[256]; char password[17]; @@ -476,10 +490,17 @@ void runbbs(int socket, char *ip) { ipaddress = ip; - write(socket, iac_echo, 3); - write(socket, iac_sga, 3); - - gUser = NULL; + if (!ssh) { + write(socket, iac_echo, 3); + write(socket, iac_sga, 3); + gUser = NULL; + sshBBS = 0; + } else { + sshBBS = 1; + } + + + gSocket = socket; s_printf("Magicka BBS v%d.%d (%s), Loading...\r\n", VERSION_MAJOR, VERSION_MINOR, VERSION_STR); @@ -506,7 +527,9 @@ void runbbs(int socket, char *ip) { if (mynode == 0) { s_printf("Sorry, all nodes are in use. Please try later\r\n"); - close(socket); + if (!ssh) { + close(socket); + } exit(1); } @@ -527,42 +550,70 @@ void runbbs(int socket, char *ip) { s_displayansi("issue"); - s_printf("\e[0mEnter your Login Name or NEW to create an account\r\n"); - s_printf("Login:> "); + if (!ssh) { + s_printf("\e[0mEnter your Login Name or NEW to create an account\r\n"); + s_printf("Login:> "); - s_readstring(buffer, 25); + s_readstring(buffer, 25); - if (strcasecmp(buffer, "new") == 0) { - user = new_user(); - } else { - s_printf("\r\nPassword:> "); - s_readpass(password, 16); - user = check_user_pass(buffer, password); - if (user == NULL) { - s_printf("\r\nIncorrect Login.\r\n"); - disconnect("Incorrect Login"); - } + if (strcasecmp(buffer, "new") == 0) { + user = new_user(); + } else { + s_printf("\r\nPassword:> "); + s_readpass(password, 16); + user = check_user_pass(buffer, password); + if (user == NULL) { + s_printf("\r\nIncorrect Login.\r\n"); + disconnect("Incorrect Login"); + } - for (i=1;i<=conf.nodes;i++) { - sprintf(buffer, "%s/nodeinuse.%d", conf.bbs_path, i); - if (stat(buffer, &s) == 0) { - nodefile = fopen(buffer, "r"); - if (!nodefile) { - dolog("Error opening nodefile!"); - disconnect("Error opening nodefile!"); - } - fgets(buffer, 256, nodefile); + for (i=1;i<=conf.nodes;i++) { + sprintf(buffer, "%s/nodeinuse.%d", conf.bbs_path, i); + if (stat(buffer, &s) == 0) { + nodefile = fopen(buffer, "r"); + if (!nodefile) { + dolog("Error opening nodefile!"); + disconnect("Error opening nodefile!"); + } + fgets(buffer, 256, nodefile); - if (strcasecmp(user->loginname, buffer) == 0) { - fclose(nodefile); - s_printf("\r\nYou are already logged in.\r\n"); - disconnect("Already Logged in"); + if (strcasecmp(user->loginname, buffer) == 0) { + fclose(nodefile); + s_printf("\r\nYou are already logged in.\r\n"); + disconnect("Already Logged in"); + } + fclose(nodefile); } - fclose(nodefile); - } - } - } + } + } + } else { + if (gUser != NULL) { + user = gUser; + s_printf("\e[0mWelcome back %s. Press enter to log in...\r\n", gUser->loginname); + s_getc(); + for (i=1;i<=conf.nodes;i++) { + sprintf(buffer, "%s/nodeinuse.%d", conf.bbs_path, i); + if (stat(buffer, &s) == 0) { + nodefile = fopen(buffer, "r"); + if (!nodefile) { + dolog("Error opening nodefile!"); + disconnect("Error opening nodefile!"); + } + fgets(buffer, 256, nodefile); + if (strcasecmp(user->loginname, buffer) == 0) { + fclose(nodefile); + s_printf("\r\nYou are already logged in.\r\n"); + disconnect("Already Logged in"); + } + fclose(nodefile); + } + } + } else { + gUser = new_user(); + user = gUser; + } + } sprintf(buffer, "%s/nodeinuse.%d", conf.bbs_path, mynode); nodefile = fopen(buffer, "w"); if (!nodefile) { @@ -649,3 +700,11 @@ void runbbs(int socket, char *ip) { dolog("%s is logging out, on node %d", user->loginname, mynode); disconnect("Log out"); } + +void runbbs(int socket, char *ip) { + runbbs_real(socket, ip, 0); +} + +void runbbs_ssh(char *ip) { + runbbs_real(-1, ip, 1); +} diff --git a/chat_system.c b/chat_system.c index e103a8c..717b84c 100644 --- a/chat_system.c +++ b/chat_system.c @@ -110,8 +110,9 @@ void chat_system(struct user_record *user) { char *message; char *sep; char *target; - memset(inputbuffer, 0, 80); - if (conf.irc_server == NULL) { + + memset(inputbuffer, 0, 80); + if (conf.irc_server == NULL) { s_putstring("\r\nSorry, Chat is not supported on this system.\r\n"); return; } diff --git a/main.c b/main.c index 9e63576..7974d3f 100644 --- a/main.c +++ b/main.c @@ -17,8 +17,14 @@ extern struct bbs_config conf; extern struct user_record *gUser; + +int ssh_pid = -1; + void sigterm_handler(int s) { + if (ssh_pid != -1) { + kill(ssh_pid, SIGTERM); + } remove(conf.pid_file); exit(0); } @@ -376,12 +382,85 @@ int ssh_authenticate(ssh_session p_ssh_session) { } while(1); } +char *ssh_getip(ssh_session session) { + struct sockaddr_storage tmp; + struct sockaddr_in *sock; + unsigned int len = 100; + char ip[100] = "\0"; + + getpeername(ssh_get_fd(session), (struct sockaddr*)&tmp, &len); + sock = (struct sockaddr_in *)&tmp; + inet_ntop(AF_INET, &sock->sin_addr, ip, len); + + return strdup(ip); +} + +static int ssh_copy_fd_to_chan(socket_t fd, int revents, void *userdata) { + ssh_channel chan = (ssh_channel)userdata; + char buf[2048]; + int sz = 0; + + if(!chan) { + close(fd); + return -1; + } + if(revents & POLLIN) { + sz = read(fd, buf, 2048); + if(sz > 0) { + ssh_channel_write(chan, buf, sz); + } + } + if(revents & POLLHUP) { + ssh_channel_close(chan); + sz = -1; + } + return sz; +} + +static int ssh_copy_chan_to_fd(ssh_session session, + ssh_channel channel, + void *data, + uint32_t len, + int is_stderr, + void *userdata) { + int fd = *(int*)userdata; + int sz; + (void)session; + (void)channel; + (void)is_stderr; + + sz = write(fd, data, len); + return sz; +} + +static void ssh_chan_close(ssh_session session, ssh_channel channel, void *userdata) { + int fd = *(int*)userdata; + (void)session; + (void)channel; + + close(fd); +} + +struct ssh_channel_callbacks_struct ssh_cb = { + .channel_data_function = ssh_copy_chan_to_fd, + .channel_eof_function = ssh_chan_close, + .channel_close_function = ssh_chan_close, + .userdata = NULL +}; + void serverssh(int port) { ssh_session p_ssh_session; ssh_bind p_ssh_bind; int err; int pid; + int shell; + int fd; ssh_channel chan = 0; + int bbs_pid; + char *ip; + ssh_event event; + short events; + err = ssh_init(); if (err == -1) { fprintf(stderr, "Error starting SSH server.\n"); @@ -458,8 +537,45 @@ void serverssh(int port) { exit(-1); } - + ip = ssh_getip(p_ssh_session); + + bbs_pid = forkpty(&fd, NULL, NULL, NULL); + if (bbs_pid == 0) { + runbbs_ssh(ip); + exit(0); + } + free(ip); + ssh_cb.userdata = &fd; + ssh_callbacks_init(&ssh_cb); + ssh_set_channel_callbacks(chan, &cb); + + events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL; + + event = ssh_event_new(); + if(event == NULL) { + ssh_finalize(); + exit(0); + } + if(ssh_event_add_fd(event, fd, events, ssh_copy_fd_to_chan, chan) != SSH_OK) { + ssh_finalize(); + exit(0); + } + if(ssh_event_add_session(event, p_ssh_session) != SSH_OK) { + ssh_finalize(); + exit(0); + } + + do { + ssh_event_dopoll(event, 1000); + } while(!ssh_channel_is_closed(chan)); + + ssh_event_remove_fd(event, fd); + + ssh_event_remove_session(event, p_ssh_session); + + ssh_event_free(event); } + ssh_finalize(); exit(0); } else if (pid > 0) { @@ -494,6 +610,19 @@ void server(int port) { exit(1); } + if (conf.ssh_server) { + // fork ssh server + ssh_pid = fork(); + + if (ssh_pid > 0) { + serverssh(conf.ssh_port); + exit(0); + } + if (ssh_pid != 0) { + fprintf(stderr, "Error forking ssh server."); + } + } + socket_desc = socket(AF_INET, SOCK_STREAM, 0); if (socket_desc == -1) { remove(conf.pid_file);