|
@@ -0,0 +1,274 @@
|
|
|
+#include <stdio.h>
|
|
|
+#include <string.h>
|
|
|
+#include <unistd.h>
|
|
|
+
|
|
|
+#include <pty.h>
|
|
|
+#include <termios.h>
|
|
|
+#include <fcntl.h>
|
|
|
+
|
|
|
+#include <sys/select.h>
|
|
|
+#include <sys/wait.h>
|
|
|
+
|
|
|
+#include <signal.h> // handle Ctrl-C/SIGINT
|
|
|
+
|
|
|
+#include <time.h> // usleep(), nanonsleep() ?
|
|
|
+#include <strings.h> // strcasecmp
|
|
|
+
|
|
|
+#include <stdlib.h> // random()
|
|
|
+
|
|
|
+#define TARGET "./mySTIC"
|
|
|
+#define BSIZE 1024
|
|
|
+#define LOGGING
|
|
|
+
|
|
|
+const char * it_is_now(void) {
|
|
|
+ static char buffer[100];
|
|
|
+ time_t timer;
|
|
|
+ struct tm* tm_info;
|
|
|
+
|
|
|
+ timer = time(NULL);
|
|
|
+ tm_info = localtime(&timer);
|
|
|
+ strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
|
|
|
+ return buffer;
|
|
|
+}
|
|
|
+
|
|
|
+void slow_write(int fd, int speed, char * buffer, int len) {
|
|
|
+ int x;
|
|
|
+ for( x = 0; x < len; x++) {
|
|
|
+ usleep(speed);
|
|
|
+ write( fd, &buffer[x], 1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void harry_event(int fd) {
|
|
|
+ // Make something happen
|
|
|
+ char clear[] = "\b \b";
|
|
|
+ int x;
|
|
|
+ char haha[] = "Hahaha hahaha!!!";
|
|
|
+ char beep = '\a';
|
|
|
+
|
|
|
+ slow_write(fd, 11500, haha, strlen(haha) );
|
|
|
+ write(fd, &beep, 1);
|
|
|
+ sleep(3);
|
|
|
+ for( x = 0; x < strlen(haha); x++ ) {
|
|
|
+ write(fd, clear, strlen(clear) );
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+NOTE: Logging is single file, don't use in production!
|
|
|
+It won't handle multiple writers.
|
|
|
+*/
|
|
|
+char * username = NULL;
|
|
|
+char * fullname = NULL;
|
|
|
+
|
|
|
+void pcopy(char * pstring, char * str) {
|
|
|
+ int len = (int)*pstring;
|
|
|
+ strncpy( str, pstring+1, len );
|
|
|
+ str[len] = 0;
|
|
|
+}
|
|
|
+
|
|
|
+int locate_user(const char *alias) {
|
|
|
+ FILE * user;
|
|
|
+ char buffer[0x600];
|
|
|
+ char temp[100];
|
|
|
+
|
|
|
+ user = fopen("data/users.dat", "rb");
|
|
|
+ if (user == NULL)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ // Carry on!
|
|
|
+ while (fread(buffer, 0x600, 1, user) == 1) {
|
|
|
+ pcopy( buffer + 0x6d, temp );
|
|
|
+ if ( strcasecmp( temp, username) == 0) {
|
|
|
+ pcopy(buffer + 0x8c, temp );
|
|
|
+ fullname = strdup(temp);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ printf("Alias: %s\n", temp);
|
|
|
+ pcopy(buffer + 0x8c, temp );
|
|
|
+ printf("Full Name: %s\n", temp );
|
|
|
+ */
|
|
|
+ }
|
|
|
+ fclose(user);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+// Buffers are BSIZE + 1, so a buffer that size can strcpy safely.
|
|
|
+
|
|
|
+void mangle( char * buffer ) {
|
|
|
+ // Ok, we want to look for words to:
|
|
|
+ // MaNGlE , or transpose (both?!)
|
|
|
+ // or possibly transpose words
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+int main(int argc, char * argv[])
|
|
|
+{
|
|
|
+ int master;
|
|
|
+ pid_t pid;
|
|
|
+
|
|
|
+#ifdef LOGGING
|
|
|
+ FILE * fp;
|
|
|
+
|
|
|
+ fp = fopen("mystic_pipe.data", "wb");
|
|
|
+ if ( fp == NULL ) {
|
|
|
+ return 2;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ srandom(time(NULL));
|
|
|
+
|
|
|
+ // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz -PUWISHPASSWORD
|
|
|
+
|
|
|
+ // -U<username>
|
|
|
+ for (int x = 0; x < argc; x++) {
|
|
|
+ if (strncmp("-U", argv[x], 2) == 0) {
|
|
|
+ username = argv[x] + 2;
|
|
|
+#ifdef LOGGING
|
|
|
+ fprintf(fp, "Username: [%s]\n", username);
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (username != NULL) {
|
|
|
+ locate_user(username);
|
|
|
+#ifdef LOGGING
|
|
|
+ fprintf(fp, "Username: [%s] A.K.A. [%s]\n", username, fullname);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ // With IGNBRK I don't think I need this anymore.
|
|
|
+ // signal(SIGINT, SIG_IGN);
|
|
|
+
|
|
|
+ pid = forkpty(&master, NULL, NULL, NULL);
|
|
|
+
|
|
|
+ // impossible to fork
|
|
|
+ if (pid < 0) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // child
|
|
|
+ else if (pid == 0) {
|
|
|
+ char *args[20]; // max 20 args
|
|
|
+ int x;
|
|
|
+ args[0] = TARGET;
|
|
|
+
|
|
|
+ for ( x = 1; x < argc; x++ ) {
|
|
|
+ args[x] = argv[x];
|
|
|
+ };
|
|
|
+ args[x] = NULL;
|
|
|
+ // char *args[] = { "vim", "test.txt", NULL }; // argv; //{ NULL };
|
|
|
+
|
|
|
+ // run Mystic, run!
|
|
|
+ execvp( TARGET, args);
|
|
|
+ }
|
|
|
+
|
|
|
+ // parent
|
|
|
+ else {
|
|
|
+ // remove the echo
|
|
|
+ // ICANON - raw mode. No more line buffering!
|
|
|
+ struct termios tios, orig1;
|
|
|
+ struct timeval timeout;
|
|
|
+ int last_event;
|
|
|
+
|
|
|
+ tcgetattr(master, &tios);
|
|
|
+ tios.c_lflag &= ~(ECHO | ECHONL | ICANON );
|
|
|
+ tcsetattr(master, TCSAFLUSH, &tios);
|
|
|
+
|
|
|
+ tcgetattr(1, &orig1);
|
|
|
+ tios = orig1;
|
|
|
+ tios.c_iflag &= ~(ICRNL | IXON); // Disable software flow control
|
|
|
+
|
|
|
+ tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN );
|
|
|
+
|
|
|
+ // https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
|
|
|
+ // ISIG should be Ctrl-C and Ctrl-Z IGNBRK +
|
|
|
+ tcsetattr(1, TCSAFLUSH, &tios);
|
|
|
+
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+
|
|
|
+ // define estruturas para o select, que serve para verificar qual
|
|
|
+ // se tornou "pronto pra uso"
|
|
|
+ fd_set read_fd;
|
|
|
+ fd_set write_fd;
|
|
|
+ fd_set except_fd;
|
|
|
+
|
|
|
+ // inicializa as estruturas
|
|
|
+ FD_ZERO(&read_fd);
|
|
|
+ FD_ZERO(&write_fd);
|
|
|
+ FD_ZERO(&except_fd);
|
|
|
+
|
|
|
+ // atribui o descritor master, obtido pelo forkpty, ao read_fd
|
|
|
+ FD_SET(master, &read_fd);
|
|
|
+ // atribui o stdin ao read_fd
|
|
|
+ FD_SET(STDIN_FILENO, &read_fd);
|
|
|
+
|
|
|
+ // o descritor tem que ser unico para o programa, a documentacao
|
|
|
+ // recomenda um calculo entre os descritores sendo usados + 1
|
|
|
+
|
|
|
+ // we're in luck! The last parameter is time interval/timeout. :D
|
|
|
+ timeout.tv_sec = 10;
|
|
|
+ timeout.tv_usec = 0;
|
|
|
+
|
|
|
+ // select(master+1, &read_fd, &write_fd, &except_fd, NULL);
|
|
|
+ if ( select(master+1, &read_fd, &write_fd, &except_fd, &timeout) == 0 ) {
|
|
|
+ // This means timeout!
|
|
|
+ harry_event(STDOUT_FILENO);
|
|
|
+#ifdef LOGGING
|
|
|
+ fprintf(fp, "%s : TICK\n", it_is_now());
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ char input[BSIZE + 1];
|
|
|
+ char output[BSIZE + 1];
|
|
|
+ int total;
|
|
|
+
|
|
|
+ // read_fd esta atribuido com read_fd?
|
|
|
+ if (FD_ISSET(master, &read_fd))
|
|
|
+ {
|
|
|
+ // leia o que bc esta mandando
|
|
|
+ if ((total = read(master, &output, BSIZE)) != -1) {
|
|
|
+ // e escreva isso na saida padrao
|
|
|
+ output[total] = 0;
|
|
|
+
|
|
|
+ if (random() % 20 < 3) {
|
|
|
+ mangle( output );
|
|
|
+ }
|
|
|
+
|
|
|
+ write(STDOUT_FILENO, &output, total);
|
|
|
+
|
|
|
+ // This is OUTPUT from the BBS
|
|
|
+#ifdef LOGGING
|
|
|
+ fprintf(fp, ">> [%s]\n", output);
|
|
|
+#endif
|
|
|
+ } else
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // read_fd esta atribuido com a entrada padrao?
|
|
|
+ if (FD_ISSET(STDIN_FILENO, &read_fd))
|
|
|
+ {
|
|
|
+ // leia a entrada padrao
|
|
|
+ total = read(STDIN_FILENO, &input, BSIZE);
|
|
|
+ input[total] = 0;
|
|
|
+ // e escreva no bc
|
|
|
+ write(master, &input, total);
|
|
|
+
|
|
|
+ // This is INPUT from the USER
|
|
|
+#ifdef LOGGING
|
|
|
+ fprintf(fp, "<< [%s]\n", input);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ tcsetattr(1, TCSAFLUSH, &orig1);
|
|
|
+#ifdef LOGGING
|
|
|
+ fclose(fp);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|