From d7ce046606ce05dd8a37e83fc48667bbe4c20093 Mon Sep 17 00:00:00 2001 From: sinanmohd Date: Mon, 22 May 2023 15:25:25 +0530 Subject: initial commit --- .gitignore | 2 + Makefile | 14 +++++++ TODO | 4 ++ config.h | 9 +++++ main.c | 89 ++++++++++++++++++++++++++++++++++++++++++ menu.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ menu.h | 3 ++ ui.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ui.h | 10 +++++ util.c | 22 +++++++++++ util.h | 26 +++++++++++++ 11 files changed, 425 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 TODO create mode 100644 config.h create mode 100644 main.c create mode 100644 menu.c create mode 100644 menu.h create mode 100644 ui.c create mode 100644 ui.h create mode 100644 util.c create mode 100644 util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d613b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +tuil diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a16e712 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +OBJECTS = main.o util.o ui.o menu.o +CC = gcc +CFLAGS = -g -Wvla -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wpedantic -fsanitize=address + +tuil: $(OBJECTS) + $(CC) $(CFLAGS) -o tuil $(OBJECTS) + +main.o: config.h menu.h util.h +menu.o: ui.h util.h +ui.o: util.o config.h + +.PHONY: clean +clean: + rm -f tuil $(OBJECTS) diff --git a/TODO b/TODO new file mode 100644 index 0000000..2fef041 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +remove controling term with ioctl +back fall to stdin +use buf to communicate with child +gets status diff --git a/config.h b/config.h new file mode 100644 index 0000000..b97716d --- /dev/null +++ b/config.h @@ -0,0 +1,9 @@ +#define MAX_PASS 128 +#define MAX_STATUS 128 + +static const char statverf = '.'; +static const char statfail = ','; +static const char statstr[] = "_-"; +static const char headpromt[] = "Authentication Required"; +static const char headverf[] = "Verifying"; +static const char headerr[] = "Authentication Failed"; diff --git a/main.c b/main.c new file mode 100644 index 0000000..1a9d483 --- /dev/null +++ b/main.c @@ -0,0 +1,89 @@ +#include + +#include "menu.h" +#include "ui.h" +#include "config.h" +#include "util.h" + +int main(int argc, char *argv[]) +{ + int errflg, fd, rc; + char c; + + State state = { + .headerr = headerr, + .headverf = headverf, + .statstr = statstr, + .statverf = statverf, + .statfail = statfail, + .cmds[PASS].name = headpromt + }; + + errflg = 0; + while ((c = getopt(argc, argv, "ip:e:v:s:r:l:c:u:d:w:")) != -1) { + switch(c) { + case 'i': + state.flag |= IGNORE_ISIG; + break; + case 'p': + state.cmds[PASS].name = optarg; + break; + case 'e': + state.headerr = optarg; + break; + case 'v': + state.headverf = optarg; + break; + case 's': + state.statstr = optarg; + break; + case 'r': + state.statverf = *optarg; + break; + case 'l': + state.statfail = *optarg; + break; + case 'c': + state.cmds[PASS].cmd = optarg; + break; + case 'u': + state.cmds[UP].name = optarg; + + while (*optarg && *optarg != '=') + optarg++; + if (*optarg == '=') + state.cmds[UP].cmd = optarg + 1; + else + errflg++; + + *optarg = '\0'; + break; + case 'd': + state.cmds[DOWN].name = optarg; + + while (*optarg && *optarg != '=') + optarg++; + if (*optarg == '=') + state.cmds[DOWN].cmd = optarg + 1; + else + errflg++; + + *optarg = '\0'; + break; + case 'w': + state.floc = optarg; + break; + case '?': + errflg++; + } + } + + if (errflg || !state.cmds[PASS].cmd) + die("usage: tuil [-ipevsrl]"); + + fd = uiinit(&state); + rc = menuinit(&state, fd) - 1; + uicleanup(); + + return rc; +} diff --git a/menu.c b/menu.c new file mode 100644 index 0000000..b73c745 --- /dev/null +++ b/menu.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "menu.h" +#include "ui.h" +#include "util.h" + +#define MAX_PASS 128 +#define NO_OPT 0 + +static char pass[MAX_PASS]; + +static int getip(const State *state, int fd); +static pid_t run(const char *cmd); +static void updatestat(const State *state, unsigned typ, int pos); + +int menuinit(const State *state, int fd) +{ + int rc, wfd = -1, status = 0; + pid_t pid; + + if (state->floc) + if ((wfd = open(state->floc, O_WRONLY | O_CREAT)) == -1) + die ("can't open %s", state->floc); + + do { + if (WEXITSTATUS(status)) + pui(state->headerr, state->statfail); + else + pui(state->cmds[PASS].name, state->statstr[0]); + + rc = getip(state, fd); + + if (wfd >= 0 && rc == PASS) + write(wfd, pass, strlen(pass)); + + pid = run(state->cmds[rc].cmd); + if (rc == PASS) { + pui(state->headverf, state->statverf); + waitpid(pid, &status, NO_OPT); + } + } while (WEXITSTATUS(status) || rc != PASS); + + if (wfd >= 0) + close(wfd); + + return rc; +} + +static int getip(const State *state, int fd) +{ + unsigned i; + int rc, floor, ceil; + + rc = floor = ceil = PASS; + if (state->cmds[DOWN].name) + floor = DOWN; + if (state->cmds[UP].name) + ceil = UP; + + for (i = 0; i + 1 < MAX_PASS; ) { + read(fd, pass + i, 1); + + if (pass[i] == DEL) { + if (i > 0) + --i; + } else if (pass[i] == NL) { + break; + } else if (i >= 2 && pass[i-2] == ESC && pass[i-1] == '[' ) { + if (pass[i] == 'A' && rc < ceil) + ++rc; + else if (pass[i] == 'B' && rc > floor) + --rc; + i -= 2; + } else { + ++i; + } + + pheader(state->cmds[rc].name); + updatestat(state, rc, i); + } + + pass[i] = '\0'; + return rc; +} + +static void updatestat(const State *state, unsigned typ, int pos) +{ + if (typ == PASS) { + if (pos) + genrandstat(state->cmds[PASS].name, state->statstr); + else + pstaticstat(state->cmds[PASS].name, state->statstr[0]); + } else { + pstaticstat(state->cmds[typ].name, state->statverf); + } +} + +static pid_t run(const char *cmd) +{ + pid_t pid; + + if ((pid = fork()) == 0) { + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + execlp("sh", "sh", "-c", cmd, NULL); + die("run: fork(): %s", cmd); + } + + return pid; +} diff --git a/menu.h b/menu.h new file mode 100644 index 0000000..de5bda5 --- /dev/null +++ b/menu.h @@ -0,0 +1,3 @@ +#include "util.h" + +int menuinit(const State *state, int fd); diff --git a/ui.c b/ui.c new file mode 100644 index 0000000..4578240 --- /dev/null +++ b/ui.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "ui.h" + +#define MAX_STATUS 128 + +static char stbuf[MAX_STATUS]; + +static unsigned short rows; +static unsigned short cols; +static struct termios prevstate; +static int tty_fd; + +int uiinit(const State *state) +{ + struct winsize w; + struct termios t; + + if ((tty_fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) + die("getpass: can't open /dev/tty for input"); + + tcgetattr(tty_fd, &t); + prevstate = t; + if (state->flag & IGNORE_ISIG) + t.c_lflag &= ~(ISIG); + t.c_lflag &= ~(ECHO|INLCR|IGNCR|ICANON); + t.c_iflag |= ICRNL; + tcsetattr(tty_fd, TCSAFLUSH, &t); + tcdrain(tty_fd); + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &w) == -1) + die("ioctl() failed"); + + rows = w.ws_row; + cols = w.ws_col; + + printf("%c7", ESC); /* save cursor */ + printf("%c[?47h", ESC); /* use alt buffer */ + printf("%c[?25l", ESC); /* hide cursor */ + printf("%c[2J", ESC); /* clear vt */ + + return tty_fd; +} + +void pheader(const char *s) +{ + unsigned short col, row; + + row = rows / 2; + col = (cols - strlen(s)) / 2; + + printf("%c[%d;%dH", ESC, row, col); /* pos curosr */ + printf("%c[2K", ESC); /* clear line */ + puts(s); +} + +void pstatus(const char *s) +{ + unsigned short col, row; + + row = rows / 2 + 1; + col = (cols - strlen(s)) / 2; + + printf("%c[%d;%dH", ESC, row, col); /* pos cursor */ + printf("%c[2K", ESC); /* clear line */ + puts(s); +} + +void pstaticstat(const char *head, const char c) +{ + size_t stlen; + + if ((stlen = strlen(head)) > MAX_STATUS - 1) + stlen = MAX_STATUS - 1; + stbuf[stlen] = '\0'; + + memset(stbuf, c, stlen); + pstatus(stbuf); +} + +void genrandstat(const char *head, const char *statstr) +{ + int entropy; + size_t srlen, stlen, i; + + if ((stlen = strlen(head)) > MAX_STATUS - 1) + stlen = MAX_STATUS - 1; + srlen = strlen(statstr); + + for (entropy = i = 0; i < stlen; ++i, entropy /= srlen) { + if (!entropy) + entropy = rand(); + + stbuf[i] = statstr[entropy % srlen]; + } + + stbuf[stlen] = '\0'; + pstatus(stbuf); +} + +void uicleanup(void) +{ + printf("%c[2J", ESC); /* clear vt */ + printf("%c[?25h", ESC); /* show cursor */ + printf("%c[?47l", ESC); /* use normal buffer */ + printf("%c8", ESC); /* restore cursor */ + + tcsetattr(tty_fd, TCSAFLUSH, &prevstate); + close(tty_fd); +} + +void pui(const char *head, const char stat) +{ + size_t stlen; + + if ((stlen = strlen(head)) > MAX_STATUS - 1) + stlen = MAX_STATUS - 1; + stbuf[stlen] = '\0'; + + pheader(head); + pstatus(memset(stbuf, stat, stlen)); +} diff --git a/ui.h b/ui.h new file mode 100644 index 0000000..3cde7fe --- /dev/null +++ b/ui.h @@ -0,0 +1,10 @@ +#include +#include "util.h" + +int uiinit(const State *state); +void pheader(const char *s); +void pstatus(const char *s); +void genrandstat(const char *head, const char *statstr); +void pui(const char *head, const char stat); +void pstaticstat(const char *head, const char c); +void uicleanup(void); diff --git a/util.c b/util.c new file mode 100644 index 0000000..d8c65b8 --- /dev/null +++ b/util.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include +#include "util.h" + +void die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, ap); + if (errno) + fprintf(stderr, " (%d): %s\n", errno, strerror(errno)); + else + fputc('\n', stderr);; + va_end(ap); + + exit(errno); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..41f2e28 --- /dev/null +++ b/util.h @@ -0,0 +1,26 @@ +#ifndef UTIL_H + +enum ascii { NL = 10, ESC = 27, DEL = 127 }; +enum flags { IGNORE_ISIG = 1 << 0 }; +enum iptyp { DOWN = 0, PASS = 1, UP = 2 }; + +typedef struct { + const char *name; + const char *cmd; +} Menu; + +typedef struct { + int flag; + char statverf; + char statfail; + const char *headverf; + const char *headerr; + const char *statstr; + const char *floc; + Menu cmds[3]; +} State; + +void die(const char *fmt, ...); + +#define UTIL_H +#endif -- cgit v1.2.3