From d039eca8d4269333fb103042b37b15138ddcadfc Mon Sep 17 00:00:00 2001 From: toni Date: Wed, 11 Jan 2017 01:07:23 +0100 Subject: initial commit --- Makefile | 59 ++++++ README.md | 25 +++ aes.c | 411 +++++++++++++++++++++++++++++++++++++++ asciihexer.c | 46 +++++ config.h | 31 +++ dummyshell.c | 622 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gol.c | 469 ++++++++++++++++++++++++++++++++++++++++++++ suidcmd.c | 98 ++++++++++ xidle.c | 45 +++++ 9 files changed, 1806 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 aes.c create mode 100644 asciihexer.c create mode 100644 config.h create mode 100644 dummyshell.c create mode 100644 gol.c create mode 100644 suidcmd.c create mode 100644 xidle.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4815a84 --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +CC := gcc +CFLAGS := -O2 -g -Wall -ffunction-sections -fdata-sections -ffast-math -fomit-frame-pointer -fexpensive-optimizations +LDFLAGS := +RM := rm -rf +LIBS := -lcurses + +TARGETS := aes asciihexer dummyshell suidcmd + +ifneq ($(strip $(MAKE_NCURSES)),) +TARGETS += gol +endif +ifneq ($(strip $(MAKE_X11)),) +TARGETS += xidle +endif + + +all: $(TARGETS) + +%.o: %.c + @echo 'Building file: $<' + @echo 'Invoking: GCC C Compiler' + $(CC) $(CFLAGS) -D_GNU_SOURCE=1 -D_HAVE_CONFIG=1 -std=c99 -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + +aes: aes.o +asciihexer: asciihexer.o +dummyshell: dummyshell.o +suidcmd: suidcmd.o + @echo 'Building target: $@' + @echo 'Invoking: GCC C Linker' + $(CC) $(LDFLAGS) -o "$@" "$<" + @echo 'Finished building target: $@' + @echo ' ' + +gol: gol.o + @echo 'Building target: $@' + @echo 'Invoking: GCC C Linker' + $(CC) $(LDFLAGS) -o "$@" "$<" -lncurses + @echo 'Finished building target: $@' + @echo ' ' + +xidle: xidle.o + @echo 'Building target: $@' + @echo 'Invoking: GCC C Linker' + $(CC) $(LDFLAGS) -o "$@" "$<" -lX11 -lXext -lXss + @echo 'Finished building target: $@' + @echo ' ' + +clean: + -$(RM) aes.o asciihexer.o dummyshell.o gol.o suidcmd.o xidle.o + -$(RM) aes.d asciihexer.d dummyshell.d gol.d suidcmd.d xidle.d + -$(RM) aes asciihexer dummyshell gol suidcmd xidle + -@echo ' ' + +rebuild: clean all + +.PHONY: all clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..bbef6f1 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +some tools +======== + +aes.c +======== +A minimal working aes implementation.
+ +asciihexer.c +======== +Magic ascii-2-hex app.
+ +dummyshell.c +======== +A minimalistic restricted system-usage/messaging/command-exec shell.
+ +gol.c +======== +Conway's GameOfLife - written by Steffen Vogel / bugfixed,improved by myself.
+ +suidcmd.c +======== +Run arbitrary commands (useful for running non-suid programs on non-suid fs).
+ +
+Thats all folks.
diff --git a/aes.c b/aes.c new file mode 100644 index 0000000..ba31b41 --- /dev/null +++ b/aes.c @@ -0,0 +1,411 @@ +// AES Implementation by X-N2O +// Started: 15:41:35 - 18 Nov 2009 +// Finished: 20:03:59 - 21 Nov 2009 +// Logarithm, S-Box, and RCON tables are not hardcoded +// Instead they are generated when the program starts +// All of the code below is based from the AES specification +// You can find it at http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf +// You may use this code as you wish, but do not remove this comment +// This is only a proof of concept, and should not be considered as the most efficient implementation + +#include +#include +#include + +#define AES_RPOL 0x011b // reduction polynomial (x^8 + x^4 + x^3 + x + 1) +#define AES_GEN 0x03 // gf(2^8) generator (x + 1) +#define AES_SBOX_CC 0x63 // S-Box C constant + +#define KEY_128 (128/8) +#define KEY_192 (192/8) +#define KEY_256 (256/8) + +#define aes_mul(a, b) ((a)&&(b)?g_aes_ilogt[(g_aes_logt[(a)]+g_aes_logt[(b)])%0xff]:0) +#define aes_inv(a) ((a)?g_aes_ilogt[0xff-g_aes_logt[(a)]]:0) + +unsigned char g_aes_logt[256], g_aes_ilogt[256]; +unsigned char g_aes_sbox[256], g_aes_isbox[256]; + +typedef struct { + unsigned char state[4][4]; + int kcol; + size_t rounds; + unsigned long keysched[0]; +} aes_ctx_t; + +void aes_init(); +aes_ctx_t *aes_alloc_ctx(unsigned char *key, size_t keyLen); +inline unsigned long aes_subword(unsigned long w); +inline unsigned long aes_rotword(unsigned long w); +void aes_keyexpansion(aes_ctx_t *ctx); + +inline unsigned char aes_mul_manual(unsigned char a, unsigned char b); // use aes_mul instead + +void aes_subbytes(aes_ctx_t *ctx); +void aes_shiftrows(aes_ctx_t *ctx); +void aes_mixcolumns(aes_ctx_t *ctx); +void aes_addroundkey(aes_ctx_t *ctx, int round); +void aes_encrypt(aes_ctx_t *ctx, unsigned char input[16], unsigned char output[16]); + +void aes_invsubbytes(aes_ctx_t *ctx); +void aes_invshiftrows(aes_ctx_t *ctx); +void aes_invmixcolumns(aes_ctx_t *ctx); +void aes_decrypt(aes_ctx_t *ctx, unsigned char input[16], unsigned char output[16]); + +void aes_free_ctx(aes_ctx_t *ctx); + +void init_aes() +{ + int i; + unsigned char gen; + + // build logarithm table and it's inverse + gen = 1; + for(i = 0; i < 0xff; i++) { + g_aes_logt[gen] = i; + g_aes_ilogt[i] = gen; + gen = aes_mul_manual(gen, AES_GEN); + } + + // build S-Box and it's inverse + for(i = 0; i <= 0xff; i++) { + char bi; + unsigned char inv = aes_inv(i); + + g_aes_sbox[i] = 0; + for(bi = 0; bi < 8; bi++) { + // based on transformation 5.1 + // could also be done with a loop based on the matrix + g_aes_sbox[i] |= ((inv & (1<rounds = rounds; + ctx->kcol = keyLen/4; + memcpy(ctx->keysched, key, keyLen); + ctx->keysched[43] = 0; + aes_keyexpansion(ctx); + } + + return ctx; +} + +inline unsigned long aes_subword(unsigned long w) +{ + return g_aes_sbox[w & 0x000000ff] | + (g_aes_sbox[(w & 0x0000ff00) >> 8] << 8) | + (g_aes_sbox[(w & 0x00ff0000) >> 16] << 16) | + (g_aes_sbox[(w & 0xff000000) >> 24] << 24); +} + +inline unsigned long aes_rotword(unsigned long w) +{ + // May seem a bit different from the spec + // It was changed because unsigned long is represented with little-endian convention on x86 + // Should not depend on architecture, but this is only a POC + return ((w & 0x000000ff) << 24) | + ((w & 0x0000ff00) >> 8) | + ((w & 0x00ff0000) >> 8) | + ((w & 0xff000000) >> 8); +} + +void aes_keyexpansion(aes_ctx_t *ctx) +{ + unsigned long temp; + unsigned long rcon; + register int i; + + rcon = 0x00000001; + for(i = ctx->kcol; i < (4*(ctx->rounds+1)); i++) { + temp = ctx->keysched[i-1]; + if(!(i%ctx->kcol)) { + temp = aes_subword(aes_rotword(temp)) ^ rcon; + rcon = aes_mul(rcon, 2); + } else if(ctx->kcol > 6 && i%ctx->kcol == 4) + temp = aes_subword(temp); + ctx->keysched[i] = ctx->keysched[i-ctx->kcol] ^ temp; + } +} + +inline unsigned char aes_mul_manual(unsigned char a, unsigned char b) +{ + register unsigned short ac; + register unsigned char ret; + + ac = a; + ret = 0; + while(b) { + if(b & 0x01) + ret ^= ac; + ac <<= 1; + b >>= 1; + if(ac & 0x0100) + ac ^= AES_RPOL; + } + + return ret; +} + +void aes_subbytes(aes_ctx_t *ctx) +{ + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + ctx->state[x][y] = g_aes_sbox[ctx->state[x][y]]; + } +} + +void aes_shiftrows(aes_ctx_t *ctx) +{ + unsigned char nstate[4][4]; + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + nstate[x][y] = ctx->state[x][(y+x) & 0x03]; + } + + memcpy(ctx->state, nstate, sizeof(ctx->state)); +} + +void aes_mixcolumns(aes_ctx_t *ctx) +{ + unsigned char nstate[4][4]; + int i; + + for(i = 0; i < 4; i++) { + nstate[0][i] = aes_mul(0x02, ctx->state[0][i]) ^ + aes_mul(0x03, ctx->state[1][i]) ^ + ctx->state[2][i] ^ + ctx->state[3][i]; + nstate[1][i] = ctx->state[0][i] ^ + aes_mul(0x02, ctx->state[1][i]) ^ + aes_mul(0x03, ctx->state[2][i]) ^ + ctx->state[3][i]; + nstate[2][i] = ctx->state[0][i] ^ + ctx->state[1][i] ^ + aes_mul(0x02, ctx->state[2][i]) ^ + aes_mul(0x03, ctx->state[3][i]); + nstate[3][i] = aes_mul(0x03, ctx->state[0][i]) ^ + ctx->state[1][i] ^ + ctx->state[2][i] ^ + aes_mul(0x02, ctx->state[3][i]); + } + + memcpy(ctx->state, nstate, sizeof(ctx->state)); +} + +void aes_addroundkey(aes_ctx_t *ctx, int round) +{ + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + ctx->state[x][y] = ctx->state[x][y] ^ + ((ctx->keysched[round*4+y] & (0xff << (x*8))) >> (x*8)); + } +} + +void aes_encrypt(aes_ctx_t *ctx, unsigned char input[16], unsigned char output[16]) +{ + int i; + + // copy input to state + for(i = 0; i < 16; i++) + ctx->state[i & 0x03][i >> 2] = input[i]; + + aes_addroundkey(ctx, 0); + + for(i = 1; i < ctx->rounds; i++) { + aes_subbytes(ctx); + aes_shiftrows(ctx); + aes_mixcolumns(ctx); + aes_addroundkey(ctx, i); + } + + aes_subbytes(ctx); + aes_shiftrows(ctx); + aes_addroundkey(ctx, ctx->rounds); + + // copy state to output + for(i = 0; i < 16; i++) + output[i] = ctx->state[i & 0x03][i >> 2]; +} + +void aes_invshiftrows(aes_ctx_t *ctx) +{ + unsigned char nstate[4][4]; + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + nstate[x][(y+x) & 0x03] = ctx->state[x][y]; + } + + memcpy(ctx->state, nstate, sizeof(ctx->state)); +} + +void aes_invsubbytes(aes_ctx_t *ctx) +{ + int i; + + for(i = 0; i < 16; i++) { + int x, y; + + x = i & 0x03; + y = i >> 2; + ctx->state[x][y] = g_aes_isbox[ctx->state[x][y]]; + } +} + +void aes_invmixcolumns(aes_ctx_t *ctx) +{ + unsigned char nstate[4][4]; + int i; + + for(i = 0; i < 4; i++) { + nstate[0][i] = aes_mul(0x0e, ctx->state[0][i]) ^ + aes_mul(0x0b, ctx->state[1][i]) ^ + aes_mul(0x0d, ctx->state[2][i]) ^ + aes_mul(0x09, ctx->state[3][i]); + nstate[1][i] = aes_mul(0x09, ctx->state[0][i]) ^ + aes_mul(0x0e, ctx->state[1][i]) ^ + aes_mul(0x0b, ctx->state[2][i]) ^ + aes_mul(0x0d, ctx->state[3][i]); + nstate[2][i] = aes_mul(0x0d, ctx->state[0][i]) ^ + aes_mul(0x09, ctx->state[1][i]) ^ + aes_mul(0x0e, ctx->state[2][i]) ^ + aes_mul(0x0b, ctx->state[3][i]); + nstate[3][i] = aes_mul(0x0b, ctx->state[0][i]) ^ + aes_mul(0x0d, ctx->state[1][i]) ^ + aes_mul(0x09, ctx->state[2][i]) ^ + aes_mul(0x0e, ctx->state[3][i]); + } + + memcpy(ctx->state, nstate, sizeof(ctx->state)); +} + +void aes_decrypt(aes_ctx_t *ctx, unsigned char input[16], unsigned char output[16]) +{ + int i; + + // copy input to state + for(i = 0; i < 16; i++) + ctx->state[i & 0x03][i >> 2] = input[i]; + + aes_addroundkey(ctx, ctx->rounds); + for(i = ctx->rounds-1; i >= 1; i--) { + aes_invshiftrows(ctx); + aes_invsubbytes(ctx); + aes_addroundkey(ctx, i); + aes_invmixcolumns(ctx); + } + + aes_invshiftrows(ctx); + aes_invsubbytes(ctx); + aes_addroundkey(ctx, 0); + + // copy state to output + for(i = 0; i < 16; i++) + output[i] = ctx->state[i & 0x03][i >> 2]; +} + +void aes_free_ctx(aes_ctx_t *ctx) +{ + free(ctx); +} + +#define PRINT_BYTES(bPtr, siz, offset) { int _bPtr_idx; for (_bPtr_idx = offset; _bPtr_idx < offset+siz; _bPtr_idx++) { printf("%02X ", bPtr[_bPtr_idx]); } printf("\n"); } +int main(int argc, char *argv[]) +{ + if (argc != 3) { + fprintf(stderr, "usage: %s [KEY] [MSG]\n", argv[0]); + return 1; + } + + size_t klen = strlen(argv[1]); + unsigned char key[KEY_128]; + memcpy(key, argv[1], klen); + + size_t plen = strlen(argv[2]); + unsigned char ptext[plen+1]; + memcpy(ptext, argv[2], plen); + ptext[plen] = '\0'; + + unsigned char ctext[plen+1]; + memset(ctext, '\0', plen+1); + unsigned char decptext[plen+1]; + memset(decptext, '\0', plen+1); + + aes_ctx_t *ctx; + + init_aes(); + ctx = aes_alloc_ctx(key, sizeof(key)); + if(!ctx) { + perror("aes_alloc_ctx"); + return EXIT_FAILURE; + } + printf("Encrypted[HEX]..: "); + aes_encrypt(ctx, ptext, ctext); + PRINT_BYTES(ctext, sizeof(ctext), 0); + aes_decrypt(ctx, ctext, decptext); + printf("Decrypted[HEX]..: "); + PRINT_BYTES(decptext, sizeof(decptext), 0); + printf("Decrypted[ASCII]: "); + puts((char*)decptext); + + aes_free_ctx(ctx); + return EXIT_SUCCESS; +} + diff --git a/asciihexer.c b/asciihexer.c new file mode 100644 index 0000000..afa1cd0 --- /dev/null +++ b/asciihexer.c @@ -0,0 +1,46 @@ +#include +#include +#include + +#define ASCII_HEXLEN 3 + + +static void defaultHexOut(char *text) { + int i; + size_t len; + + for (i = 0; i < (len = strlen(text)); i++) { + printf("0x%X%c", text[i], (i == len-1 ? '\n' : ' ')); + } +} + +static void dwordHexOut(char *text) { + int i; + size_t len; + + for (i = 0; i < (len = strlen(text)); i++) { + printf("%s%X%s", (i % 4 == 0 ? (i == 0 ? "0x" : " 0x") : ""), text[i], (i == len-1 ? "\n" : "")); + } +} + +static void strHexOut(char *text) { + int i; + size_t len; + + for (i = 0; i < (len = strlen(text)); i++) { + printf("%s%X%s", (i == 0 ? "0x" : ""), text[i], (i == len-1 ? "\n" : "")); + } +} + +int main(int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr, "usage: %s [TEXT]\n", argv[0]); + return 1; + } + + defaultHexOut(argv[1]); + dwordHexOut(argv[1]); + strHexOut(argv[1]); + return 0; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..beafcf6 --- /dev/null +++ b/config.h @@ -0,0 +1,31 @@ +/************** + * GameOfLife * + **************/ + +/* the number of random spawns per cycle */ +#define RANDOM_SPAWNS 20 + +/* enable hotkeys q, p, c, +/- */ +#define ENABLE_HOTKEYS 1 + +/* enable the upper status bar */ +#define ENABLE_STATUS 1 + +/* enable the cursor */ +#define ENABLE_CURSOR 1 + +/* set the cursor symbol */ +#define CURSOR_CHAR '#' + + +/************** + * DummyShell * + **************/ + +#define _HAS_CMD 1 +#define _HAS_MSG 1 +#define _HAS_HOSTENT 1 +#define _HAS_SIGNAL 1 +#define _HAS_UTMP 1 +#define _HAS_SYSINFO 1 + diff --git a/dummyshell.c b/dummyshell.c new file mode 100644 index 0000000..aa3c17a --- /dev/null +++ b/dummyshell.c @@ -0,0 +1,622 @@ +/* + * build with: gcc -Wall -O2 -D_GNU_SOURCE=1 -D_HAS_CMD=1 -D_HAS_MSG=1 -D_HAS_HOSTENT=1 -D_HAS_SIGNAL=1 -D_HAS_UTMP=1 -D_HAS_SYSINFO -ffunction-sections -fdata-sections -ffast-math -fomit-frame-pointer dummyshell.c -o dummyshell + * strip -s dummyshell + */ + + +#ifdef _HAVE_CONFIG +#include "config.h" +#endif +#include +#include +#include +#include +#include +#include +#include /* isprint(...) */ +#include /* ioctl(...) */ +#include /* UINT8_MAX */ +#include /* memset(...) */ +#include +#include /* getpwuid(...) */ +#ifdef _HAS_CMD +#include +#else +#warning "COMMANDS(_HAS_CMD) disabled!" +#endif +#ifdef _HAS_MSG +#include +#include +#else +#warning "MESSAGE(_HAS_MSG) disabled!" +#endif +#ifdef _HAS_HOSTENT +#include +#include +#include +#include +#else +#warning "HOSTENT(_HAS_HOSTENT) disabled!" +#endif +#ifdef _HAS_SIGNAL +#include /* signal(...) */ +#else +#warning "SIGNAL(_HAS_SIGNAL) disabled!" +#endif +#ifdef _HAS_UTMP +#include /* utmp structure */ +#else +#warning "UTMP(_HAS_UTMP) disabled!" +#endif +#ifdef _HAS_SYSINFO +#include "sys/types.h" /* sysinfo structture */ +#include "sys/sysinfo.h" /* sysinfo(...) */ +#else +#warning "SYSINFO(_HAS_SYSINFO) disabled!" +#endif + +/* for print_memusage() and print cpuusage() see: http://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process */ + + +static const char keymsg[] = " ['q'-EXIT | 'm'-MESSAGE | 'c'-CMDS] "; +static const char txtheader[] = + "**************\n" + "* dummyshell *\n" + "**************\n" + "!(C) by Toni Uhlig\n" + "@see: https://raw.githubusercontent.com/lnslbrty/foo-scripts/master/dummyshell.c\n"; + +static volatile unsigned char doLoop = 1; + + +static void printQuitLoop(void) { + printf("quit in 3 .. "); + fflush(stdout); + sleep(1); + printf("2 .. "); + fflush(stdout); + sleep(1); + printf("1 .. "); + fflush(stdout); + sleep(1); + printf("\n"); + doLoop = 0; +} + +#define I_CLEARBUF 0x1 +static char readInput(char* buf, size_t* siz, size_t szMax, char key, int flags) { + if (flags & I_CLEARBUF) { + memset(&buf[0], '\0', szMax); + *siz = 0; + } else switch (key) { + case '\n': + break; + case 127: + if (*siz > 0) + buf[--(*siz)] = '\0'; + break; + case EOF: break; + default: + if (isprint(key) && *siz < szMax) + buf[(*siz)++] = key; + break; + } + return key; +} + +#ifdef _HAS_CMD +struct __attribute__((__packed__)) cmd { + char* name; + char* path; + char* defargs; +}; + +static struct cmd cmds[] = { + { "ether-wake", "/var/media/ftp/bin/suid-ether-wake", "-b -i lan" }, + { "echo", "/bin/echo", NULL }, + { NULL, NULL, NULL } +}; + +static void print_cmds(void) +{ + size_t idx = 0; + printf("\33[2K\r[COMMANDS]\n"); + while ( cmds[idx++].path != NULL ) { + printf(" [%lu] %s\n", (unsigned long int)idx-1, ( cmds[idx-1].name != NULL ? cmds[idx-1].name : "unknown" )); + } +} + +int safe_exec(const char* cmdWithArgs) +{ + pid_t child; + if ( (child = fork()) == 0 ) { + size_t szCur = 0, szMax = 10; + char** args = calloc(szMax, sizeof(char**)); + const char* cmd = NULL; + + const char* prv = cmdWithArgs; + const char* cur = NULL; + while ( (cur = strchr(prv, ' ')) ) { + if (cmd == NULL) + cmd = strndup(prv, cur-prv); + + args[szCur++] = strndup(prv, cur-prv); + if (szCur >= szMax) { + szMax *= 2; + args = realloc(args, sizeof(char**)*szMax); + } + + cur++; + prv = cur; + } + if (cmd == NULL) { + cmd = cmdWithArgs; + } else { + args[szCur++] = strndup(prv, cur-prv); + } + args[szCur] = NULL; + execv(cmd, args); + exit(-5); + } else if (child != -1) { + int retval = 0; + waitpid(child, &retval, 0); + return retval; + } + return -6; +} + +static int exec_cmd(size_t i, char* args, size_t szArgs) +{ + size_t idx = (size_t)-1; + while ( cmds[++idx].path != NULL ) { + if (idx == i) { + size_t siz = strlen(cmds[idx].path)+szArgs+1; + char execbuf[siz+1]; + memset(&execbuf[0], '\0', siz+1); + snprintf(&execbuf[0], siz+1, "%s %s", cmds[idx].path, args); + return safe_exec(&execbuf[0]); + } + } + return -7; +} +#endif + +#ifdef _HAS_MSG +#define MSGFILE "/tmp/dummyshell.msg" +#define STRLEN(str) (sizeof(str)/sizeof(str[0])) +static int msgfd = -1; +static int init_msg(void) +{ + msgfd = open(MSGFILE, O_RDWR | O_CREAT | O_APPEND | O_DSYNC | O_RSYNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (msgfd < 0) { + fprintf(stderr, "fopen(\"%s\") with write access: %s\n", MSGFILE, strerror(errno)); + msgfd = open(MSGFILE, O_RDONLY | O_CREAT | O_APPEND | O_DSYNC | O_RSYNC); + if (msgfd < 0) { + fprintf(stderr, "fopen(\"%s\") readonly: %s\n", MSGFILE, strerror(errno)); + return -1; + } + } + return 0; +} + +struct __attribute__((__packed__)) msgHdr { + uint8_t szFrom; + uint8_t szMsg; + time_t timestamp; +}; + +struct __attribute__((__packed__)) msg { + char* from; + char* msg; +}; + +static int read_msg(struct msgHdr* hdr, struct msg* msg) +{ + if (msgfd < 0) return -1; + int ok = 1; + size_t rb = 0; + if ( (rb = read(msgfd, hdr, sizeof(struct msgHdr)*1)) == sizeof(struct msgHdr)*1 ) { + msg->from = calloc(hdr->szFrom+1, sizeof(char)); + msg->msg = calloc(hdr->szMsg+1, sizeof(char)); + if ( (rb = read(msgfd, &(msg->from[0]), sizeof(char)*hdr->szFrom)) != sizeof(char)*hdr->szFrom ) + ok = 0; + if ( (rb = read(msgfd, &(msg->msg[0]), sizeof(char)*hdr->szMsg)) != sizeof(char)*hdr->szMsg ) + ok = 0; + char newline = 0; + if ( (rb = read(msgfd, &newline, sizeof(char)*1)) != sizeof(char)*1 ) + ok = 0; + if (!ok || newline != '\n') { + free(msg->from); + free(msg->msg); + msg->from = NULL; + msg->msg = NULL; + return -1; + } + return 0; + } + return -1; +} + +static int print_msg(void) { + struct msgHdr hdr; + struct msg msg; + memset(&hdr, '\0', sizeof(struct msgHdr)); + memset(&msg, '\0', sizeof(struct msg)); + if (read_msg(&hdr, &msg) == 0) { + struct tm localtime; + struct passwd* pwd = NULL; + unsigned long int uid = strtoul(msg.from, NULL, 10); + if ( (pwd = getpwuid((uid_t)uid)) ) { + free(msg.from); + msg.from = strdup(pwd->pw_name); + } + if (localtime_r(&hdr.timestamp, &localtime) != NULL) { + printf("\33[2K\r[%02d-%02d-%04d %02d:%02d:%02d] Message from %s: %s\n", localtime.tm_mday, localtime.tm_mon+1, 1900+localtime.tm_year, localtime.tm_hour, localtime.tm_min, localtime.tm_sec, msg.from, msg.msg); + } else { + printf("\33[2K\r\aMessage from %s: %s\n", msg.from, msg.msg); + } + free(msg.from); + free(msg.msg); + return 0; + } + return -1; +} + +static int write_msg(char* msg) { + char from[6]; + memset(&from[0], '\0', STRLEN(from)); + if (snprintf(&from[0], STRLEN(from), "%u", getuid()) > 0) { + struct msgHdr hdr; + hdr.szFrom = strnlen(from, STRLEN(from)); + hdr.szMsg = strnlen(msg, UINT8_MAX); + hdr.timestamp = time(NULL); + char* buf = calloc(sizeof(hdr) + hdr.szFrom + hdr.szMsg + 2, sizeof(char)); + if (buf) { + memcpy(buf, &hdr, sizeof(hdr)); + memcpy(buf+sizeof(hdr), from, hdr.szFrom); + memcpy(buf+sizeof(hdr)+hdr.szFrom, msg, hdr.szMsg); + *(buf + sizeof(hdr) + hdr.szFrom + hdr.szMsg) = '\n'; + int failed = 1; + if ( write(msgfd, buf, sizeof(char)*(sizeof(hdr)+hdr.szFrom+hdr.szMsg+1)) == sizeof(char)*(sizeof(hdr)+hdr.szFrom+hdr.szMsg+1) ) + failed = 0; + free(buf); + return failed; + } + } + return -1; +} +#endif + +#ifdef _HAS_HOSTENT +#define ARP_STRING_LEN 1024 +#define ARP_IP_LEN 32 +#define XSTR(s) STR(s) +#define STR(s) #s +static void print_nethost(void) +{ + FILE *arpCache = fopen("/proc/net/arp", "r"); + if (arpCache != NULL) { + char arpline[ARP_STRING_LEN+1]; + memset(&arpline[0], '\0', ARP_STRING_LEN+1); + if (fgets(arpline, ARP_STRING_LEN, arpCache)) { + char arpip[ARP_IP_LEN+1]; + memset(&arpip[0], '\0', ARP_IP_LEN); + const char nonline[] = "\33[2K\rhost online...: "; + size_t i = 0; + while (1 == fscanf(arpCache, "%" XSTR(ARP_IP_LEN) "s %*s %*s %*s %*s %*s", &arpip[0])) { + struct in_addr ip; + struct hostent *hp = NULL; + if (inet_aton(&arpip[0], &ip)) { + hp = gethostbyaddr((const void *)&ip, sizeof ip, AF_INET); + } + char *herrmsg = NULL; + if (hp == NULL) { + switch (h_errno) { + case HOST_NOT_FOUND: herrmsg = "HOST UNKNOWN"; break; + case NO_ADDRESS: herrmsg = "IP UNKNOWN"; break; + case NO_RECOVERY: herrmsg = "SERVER ERROR"; break; + case TRY_AGAIN: herrmsg = "TEMPORARY ERROR"; break; + } + } + printf("%s[%lu] %.*s aka %s\n", nonline, (long unsigned int)++i, ARP_IP_LEN, arpip, (hp != NULL ? hp->h_name : herrmsg)); + memset(&arpip[0], '\0', ARP_IP_LEN); + } + } + fclose(arpCache); + } +} +#endif + +#ifdef _HAS_UTMP +#ifndef _GNU_SOURCE +size_t +strnlen(const char *str, size_t maxlen) +{ + const char *cp; + for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--); + return (size_t)(cp - str); +} +#endif + +static void print_utmp(void) +{ + int utmpfd = open("/var/run/utmp", O_RDONLY); + if (utmpfd >= 0) { + struct utmp ut; + memset(&ut, '\0', sizeof(struct utmp)); + const char uonline[] = "\33[2K\ruser online...: "; + size_t i = 0; + while ( read(utmpfd, &ut, sizeof(struct utmp)) == sizeof(struct utmp) && strnlen(ut.ut_user, UT_NAMESIZE) > 0 ) { + if (strnlen(ut.ut_host, UT_HOSTSIZE) > 0) { + printf("%s[%lu] %.*s from %.*s\n", uonline, (long unsigned int)++i, UT_NAMESIZE, ut.ut_user, UT_HOSTSIZE, ut.ut_host); + } else { + printf("%s[%lu] %.*s\n", uonline, (long unsigned int)++i, UT_NAMESIZE, ut.ut_user); + } + } + } +} +#endif + +#ifdef _HAS_SYSINFO +static unsigned long long lastTotalUser, lastTotalUserLow, lastTotalSys, lastTotalIdle; + +static void init_cpuusage(){ + FILE* file = fopen("/proc/stat", "r"); + if (file) { + fscanf(file, "cpu %llu %llu %llu %llu", &lastTotalUser, &lastTotalUserLow, + &lastTotalSys, &lastTotalIdle); + fclose(file); + } +} + +static void print_cpuusage(){ + double percent; + FILE* file; + unsigned long long totalUser, totalUserLow, totalSys, totalIdle, total; + + file = fopen("/proc/stat", "r"); + fscanf(file, "cpu %llu %llu %llu %llu", &totalUser, &totalUserLow, + &totalSys, &totalIdle); + fclose(file); + + if (totalUser < lastTotalUser || totalUserLow < lastTotalUserLow || + totalSys < lastTotalSys || totalIdle < lastTotalIdle){ + //Overflow detection. Just skip this value. + percent = -1.0; + } else{ + total = (totalUser - lastTotalUser) + (totalUserLow - lastTotalUserLow) + + (totalSys - lastTotalSys); + percent = total; + total += (totalIdle - lastTotalIdle); + percent /= total; + percent *= 100; + } + + lastTotalUser = totalUser; + lastTotalUserLow = totalUserLow; + lastTotalSys = totalSys; + lastTotalIdle = totalIdle; + + printf("CPU...........: %.02f%%\n", percent); +} + +static void print_memusage(void) +{ + struct sysinfo meminfo; + memset(&meminfo, '\0', sizeof(struct sysinfo)); + if (sysinfo(&meminfo) == 0) { + unsigned long long totalvmem = meminfo.totalram; + totalvmem += meminfo.totalswap; + totalvmem *= meminfo.mem_unit; + unsigned long long usedvmem = meminfo.totalram - meminfo.freeram; + usedvmem += meminfo.totalswap - meminfo.freeswap; + usedvmem *= meminfo.mem_unit; + printf("VMEM(used/max): %llu/%lld (Mb)\n", (usedvmem/(1024*1024)), (totalvmem/(1024*1024))); + } +} +#endif + +#ifdef _HAS_SIGNAL +void SigIntHandler(int signum) +{ + if (signum == SIGINT) { + doLoop = 0; + } +} +#endif + +enum mainState { MS_DEFAULT, MS_MESSAGE, MS_COMMAND }; + +int main(int argc, char** argv) +{ + enum mainState state = MS_DEFAULT; + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + +#ifdef _HAS_SIGNAL + signal(SIGINT, SigIntHandler); +#endif + size_t inputsiz = 0, absiz = UINT8_MAX; + struct winsize wsiz; + ioctl(0, TIOCGWINSZ, &wsiz); + if (wsiz.ws_col < absiz) + absiz = wsiz.ws_col - 3; + char inputbuf[absiz+1]; + memset(&inputbuf[0], '\0', absiz+1); +#ifdef _HAS_MSG + if (init_msg() != 0) + return 1; + if (argc > 1) { + const char optRmsg[] = "readmsg"; + const char optWmsg[] = "writemsg"; + const char optNofollow[] = "-n"; + if (strncmp(argv[1], optRmsg, STRLEN(optRmsg)) == 0) { + if (argc == 2) while (doLoop) { + if (print_msg() != 0) + sleep(1); + } else if (argc == 3) { + if (strncmp(argv[2], optNofollow, STRLEN(optNofollow)) == 0) { + while (print_msg() == 0) {} + } else { + fprintf(stderr, "%s readmsg [-n]\n", argv[0]); + return 1; + } + } + return 0; + } else if (strncmp(argv[1], optWmsg, STRLEN(optWmsg)) == 0) { + if (argc == 3) { + return write_msg(argv[2]); + } else { + fprintf(stderr, "%s writemsg msg\n", argv[0]); + } + return 0; + } else { + fprintf(stderr, "usage: %s [readmsg [-n] | writemsg msg]\n", argv[0]); + return 1; + } + } +#endif +#ifdef _HAS_SYSINFO + init_cpuusage(); +#endif + int flags = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); + + static struct termios oldt, newt; + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + + printf("%s\n", txtheader); + fd_set fds; + time_t start = time(NULL); + time_t cur; + unsigned char mins = 0, hrs = 0; + while (doLoop > 0) { + cur = time(NULL); + double diff = difftime(cur, start); +#if defined(_HAS_UTMP) || defined(_HAS_SYSINFO) + if ((unsigned int)diff % 60 == 0) { + if (diff != 0 && ++mins == 60) { + mins = 0; + hrs++; + } + struct tm localtime; + if (localtime_r(&cur, &localtime) != NULL) { + printf("\33[2K\r--- %02d:%02d:%02d ---\n", localtime.tm_hour, localtime.tm_min, localtime.tm_sec); + } +#ifdef _HAS_UTMP + print_utmp(); +#endif +#ifdef _HAS_HOSTENT + print_nethost(); +#endif +#ifdef _HAS_SYSINFO + print_memusage(); + print_cpuusage(); +#endif + } +#endif +#ifdef _HAS_MSG + while (print_msg() == 0) {} +#endif + switch (state) { + case MS_DEFAULT: + printf("\r--- %02d:%02d:%02d ---%s", hrs, mins, ((unsigned int)diff % 60), keymsg); + break; + case MS_MESSAGE: + case MS_COMMAND: +#if defined(_HAS_MSG) || defined(_HAS_CMD) + printf("\33[2K\r> %s", inputbuf); +#endif + break; + } + fflush(stdout); + + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + int ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv); + if (doLoop == 1 && ret == 0) { + tv.tv_sec = 1; + tv.tv_usec = 0; + } else if (FD_ISSET(STDIN_FILENO, &fds)) { + char key = getchar(); + switch (state) { + case MS_DEFAULT: + switch ( key ) { + case 'q': +#ifdef _HAS_SIGNAL + signal(SIGINT, SIG_IGN); +#endif + printQuitLoop(); + break; + case 'm': +#ifdef _HAS_MSG + state = MS_MESSAGE; +#else + printf("\n"); +#endif + break; + case 'c': +#ifdef _HAS_CMD + print_cmds(); + state = MS_COMMAND; +#else + printf("\n"); +#endif + break; + default: printf("unknown key: %c\n", key); break; + } + break; + case MS_COMMAND: + case MS_MESSAGE: + switch (readInput(&inputbuf[0], &inputsiz, absiz, key, 0)) { + case '\n': + if (state == MS_MESSAGE) { +#ifdef _HAS_MSG + printf("\33[2K\rSending message(%lu): %s\n", (long unsigned int)inputsiz, inputbuf); + if (write_msg(inputbuf) != 0) + printf("Sending failed.\n"); +#endif + } else if (state == MS_COMMAND) { +#ifdef _HAS_CMD + int inputFail = 0; + if (inputsiz < 3) { + inputFail++; + } else { + char* endptr = NULL; + unsigned long int tmpi = strtoul(inputbuf, &endptr, 10); + if (*endptr == ' ') { + endptr++; + printf("\33[2K\rExec CMD #%lu with args: %s\n", tmpi, endptr); + int retval; + switch ( (retval = exec_cmd(tmpi, endptr, strlen(endptr))) ) { + case -7: printf("unknown cmd #%lu\n", tmpi); break; + case -6: printf("fork error cmd #%lu\n", tmpi); break; + case -5: printf("execute cmd #%lu\n", tmpi); break; + + case 0: break; + default: printf("Something went wrong, child returned: %d\n", retval); break; + } + } else inputFail++; + } + if (inputFail > 0) + printf("\33[2K\rFORMAT: [cmd#] [params]\n"); +#endif + } + state = MS_DEFAULT; + readInput(&inputbuf[0], &inputsiz, absiz, 0, I_CLEARBUF); + break; + } + fflush(stdout); + break; + } + } + } + while (getchar() != EOF) {} + + tcsetattr( STDIN_FILENO, TCSANOW, &oldt); + return 0; +} diff --git a/gol.c b/gol.c new file mode 100644 index 0000000..77d54a6 --- /dev/null +++ b/gol.c @@ -0,0 +1,469 @@ +/** + * @author Steffen Vogel , Toni Uhlig + * @copyright Copyright (c) 2010-2014, Steffen Vogel, Toni Uhlig + * @license http://opensource.org/licenses/gpl-license.php GNU Public License + */ + +#include +#include +#include +#include +#include +#include +#include + +/* configuration */ +#include "config.h" + +#if defined(RANDOM_SPAWNS) +static uint8_t rnd_spawns = 0xFF; +#endif + +struct config { + uint8_t paused:1; + uint8_t quit:1; + uint8_t menu:1; + uint8_t reprint:1; +}; + +struct pattern { + uint8_t width; + uint8_t height; + uint8_t * data; +}; + +struct cursor { + uint8_t x; + uint8_t y; +}; + +uint8_t start[3][3] = { + {0, 1, 1}, + {1, 1, 0}, + {0, 1, 0} +}; + +uint8_t glider[3][3] = { + {0, 1, 0}, + {0, 0, 1}, + {1, 1, 1} +}; + +uint8_t segler[4][5] = { + {0, 1, 1, 1, 1}, + {1, 0, 0, 0, 1}, + {0, 0, 0, 0, 1}, + {1, 0, 0, 1, 0} +}; + +uint8_t buffer[7][3] = { + {1, 1, 1}, + {1, 0, 1}, + {1, 0, 1}, + {0, 0, 0}, + {1, 0, 1}, + {1, 0, 1}, + {1, 1, 1} +}; + +uint8_t kreuz[3][3] = { + {0, 1, 0}, + {1, 1, 1}, + {0, 1, 0} +}; + +uint8_t ship[3][3] = { + {1, 1, 0}, + {1, 0, 1}, + {0, 1, 1} +}; + +/* initialize world with zero (dead cells) */ +void clean_world(uint8_t ** world, uint8_t width, uint8_t height) { + int a; + for (a = 0; a < width; a++) { + memset(world[a], 0, height * sizeof(uint8_t)); + } +} + +/* allocate memory for world */ +uint8_t ** create_world(uint8_t width, uint8_t height) { + uint8_t ** world = calloc(width, sizeof(uint8_t *)); + int a; + for (a = 0; a < width; a++) { + world[a] = calloc(height, sizeof(uint8_t)); + } + + clean_world(world, width, height); + return world; +} + +void free_world(uint8_t ** world, uint8_t width, uint8_t height) { + int a; + for (a = 0; a < width; a++) { + free(world[a]); + } + free(world); +} + +/* insert pattern at (x|y) into world */ +void inhabit_world(struct pattern pattern, uint8_t x, uint8_t y, uint8_t ** world, uint8_t width, uint8_t height) { + uint8_t a, b; + + for (a = 0; a < pattern.height; a++) { + int c = a; + if ((y + c) >= height) c -= height; + + for (b = 0; b < pattern.width; b++) { + int d = b; + if ((x + d) >= width) d -= width; + world[x+d][y+c] = pattern.data[(a*pattern.width)+b]; + } + } +} + +/* calc alive cells */ +uint8_t calc_cell_count(uint8_t ** world, uint8_t width, uint8_t height) { + int cell_count = 0; + uint8_t a, b; + + for (a = 0; a < width; a++) { + for (b = 0; b < height; b++) { + cell_count += (world[a][b]) ? 1 : 0; + } + } + + return cell_count; +} + +uint8_t calc_cell_neighbours(uint8_t x, uint8_t y, uint8_t ** world, uint8_t width, uint8_t height) { + uint8_t neighbours = 0; + int a, b; + + for (a = x-1; a <= x+1; a++) { + int c = a; + if (a < 0) c += width; + if (a >= width) c -= width; + + for (b = y-1; b <= y+1; b++) { + int d = b; + if (a == x && b == y) continue; + if (b < 0) d += height; + if (b >= height) d -= height; + + neighbours += (world[c][d] > 0) ? 1 : 0; + } + } + + return neighbours; /* 0 <= neighbours <= 8 */ +} + +uint8_t calc_next_cell_gen(uint8_t x, uint8_t y, uint8_t ** world, uint8_t width, uint8_t height) { + fflush(stdout); + uint8_t neighbours = calc_cell_neighbours(x, y, world, width, height); + uint8_t alive = world[x][y]; + + if (alive) { + if (neighbours > 3 || neighbours < 2) { + return 0; /* died by over-/underpopulation */ + } + else { + return 1; /* kept alive */ + } + } + else if (neighbours == 3) { + return 1; /* born */ + } + else { + return 0; /* still dead */ + } +} + +void calc_next_gen(uint8_t ** world, uint8_t ** next_gen, uint8_t width, uint8_t height) { + uint8_t x, y; + + for (x = 0; x < width; x++) { + for (y = 0; y < height; y++) { + next_gen[x][y] = calc_next_cell_gen(x, y, world, width, height); + } + } + + /* copy world */ + for (x = 0; x < width; x++) { + for (y = 0; y < height; y++) { + world[x][y] = next_gen[x][y]; + } + } +} + +/* print world with colors and count of neighbours */ +void print_world(uint8_t ** world, uint8_t width, uint8_t height) { + uint8_t x, y; + move(0, 0); /* reset cursor */ + + /* cells */ + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + uint8_t neighbours = calc_cell_neighbours(x, y, world, width, height); + + if (neighbours > 1) attron(COLOR_PAIR(neighbours)); + addch((world[x][y]) ? '0' + neighbours : ' '); + if (neighbours > 1) attroff(COLOR_PAIR(neighbours)); + } + } +} + +#ifdef ENABLE_CURSOR +void print_cursor(uint8_t ** world, struct cursor cur) { + uint8_t color = (world[cur.x][cur.y]) ? 7 : 6; + + move(cur.y, cur.x); + addch(CURSOR_CHAR | A_BLINK | A_BOLD | A_STANDOUT | COLOR_PAIR(color)); +} +#endif + +#ifdef ENABLE_HOTKEYS +#define MENU_WIDTH 25 +void print_menu(uint8_t width, uint8_t height) { + uint8_t startx, starty, mwdth_rel, posy = 0; + + mwdth_rel = (uint8_t) (MENU_WIDTH)/2+10; + startx = (uint8_t) (width/2) - mwdth_rel; + starty = (uint8_t) (height/2) - (uint8_t) (mwdth_rel/2); + attron(COLOR_PAIR(1)); + for (int i = 0; i < MENU_WIDTH; i++) { + mvprintw(starty, startx+i, "-"); + mvprintw(starty+(mwdth_rel*2/3), startx+i, "-"); + if (i % 2 == 0) { + mvprintw(starty+posy+1, startx-1, "|"); + mvprintw(starty+posy+1, startx+MENU_WIDTH, "|"); + posy++; + } + } + mvprintw(starty, startx-1, "+"); + mvprintw(starty, startx+MENU_WIDTH, "+"); + mvprintw(starty+posy+1, startx-1, "+"); + mvprintw(starty+posy+1, startx+MENU_WIDTH, "+"); + for (int i = startx; i < startx+MENU_WIDTH; i++) { + for (int j = starty+1; j <= starty+posy; j++) { + mvprintw(j, i, " "); + } + } + mvprintw(starty+1, startx+1, "q ~ Exit"); + mvprintw(starty+3, startx+1, "c ~ Clear Screen"); +#if defined(RANDOM_SPAWNS) + mvprintw(starty+5, startx+1, "d ~ Rnd Spawns [%d]", (rnd_spawns == 0 ? 0 : 1)); +#endif + mvprintw(starty+7, startx+1, "p ~ Pause"); + mvprintw(starty+9, startx+1, "+/- ~ Change Framerate"); + mvprintw(starty+11, startx+1, "0-5 ~ Create Pattern"); + attroff(COLOR_PAIR(1)); +} +#endif + +/* set up ncurses screen */ +WINDOW * init_screen() { + WINDOW * win = initscr(); + noecho(); + timeout(0); + keypad(win, 1); + mousemask(BUTTON1_PRESSED, NULL); + mouseinterval(200); + curs_set(0); + + start_color(); + init_color(COLOR_CYAN, 500, 1000, 0); /* redefine as orange */ + + init_pair(1, COLOR_BLACK, COLOR_WHITE); + init_pair(2, COLOR_WHITE, COLOR_BLACK); + init_pair(3, COLOR_GREEN, COLOR_BLACK); + init_pair(4, COLOR_YELLOW, COLOR_BLACK); + init_pair(5, COLOR_CYAN, COLOR_BLACK); + init_pair(6, COLOR_BLUE, COLOR_BLACK); + init_pair(7, COLOR_MAGENTA, COLOR_BLACK); + init_pair(8, COLOR_RED, COLOR_BLACK); + + return win; +} + +uint8_t **init_world(WINDOW *win, uint8_t **worlds[2], uint8_t *width, uint8_t *height) { + getmaxyx(win, *height, *width); + for (int i = 0; i < 2; i++) + worlds[i] = create_world(*width, *height); + return (worlds[0]); +} + +void free_all(uint8_t **worlds[2], uint8_t width, uint8_t height) { + free_world(worlds[0], width, height); + free_world(worlds[1], width, height); +} + +// returns realloc'd && resized world +uint8_t **resized(WINDOW *win, uint8_t **worlds[2], uint8_t *width, uint8_t *height) { + free_world(worlds[0], *width, *height); + free_world(worlds[1], *width, *height); + return (init_world(win, worlds, width, height)); +} + +int main(int argc, char * argv[]) { + WINDOW * win = init_screen(); +#ifdef ENABLE_CURSOR + MEVENT event; +#endif + + /* predefined patterns */ + struct pattern patterns[] = { + {3, 3, (uint8_t *) start}, + {3, 3, (uint8_t *) glider}, + {5, 4, (uint8_t *) segler}, + {3, 7, (uint8_t *) buffer}, + {8, 4, (uint8_t *) kreuz}, + {6, 6, (uint8_t *) ship} + }; + struct cursor cur = {0, 0}; + struct config cfg; + + int generation = 0, input, framerate = 17; + uint8_t width, height; + uint8_t ** worlds[2], ** world; +#if defined(RANDOM_SPAWNS) + int idle_gens = 0; + srand(time(NULL)); +#endif + + memset(&cfg, '\0', sizeof(struct config)); + /* initialize world */ + world = init_world(win, worlds, &width, &height); + /* make the world real */ + inhabit_world(patterns[3], width/2, height/2, worlds[0], width, height); + + /* simulation loop */ + while(!cfg.quit) { + if (!cfg.paused) { + /* calc next generation */ + usleep(1 / (float) framerate * 1000000); /* sleep */ + calc_next_gen(world, worlds[++generation % 2], width, height); + world = worlds[generation % 2]; /* new world */ + } + + /* handle events */ + switch (input = getch()) { +#ifdef ENABLE_HOTKEYS + case '+': /* increase framerate */ + framerate++; + break; + + case '-': /* decrease framerate */ + if (framerate > 1) framerate--; + break; + + case 'q': /* quit */ + cfg.quit = 1; + break; +#if defined(RANDOM_SPAWNS) + case 'd': /* disable random spawn */ + rnd_spawns = ~rnd_spawns; + break; +#endif + case 'p': /* pause */ + cfg.paused ^= 1; + break; + + case 'c': /* clean world */ + clean_world(world, width, height); + generation = 0; + break; +#endif +#if defined(ENABLE_HOTKEYS) || defined(ENABLE_CURSOR) + case '0': /* insert pattern */ + case '1': + case '2': + case '3': + case '4': + case '5': + inhabit_world(patterns[input - '0'], cur.x, cur.y, world, width, height); + break; +#endif +#ifdef ENABLE_CURSOR + case ' ': /* toggle cell at cursor position */ + world[cur.x][cur.y] = (world[cur.x][cur.y]) ? 0 : 1; + break; + + case KEY_MOUSE: /* move cursor to mouse posititon */ + if (getmouse(&event) == OK && event.bstate & BUTTON1_PRESSED) { + cur.x = event.x; + cur.y = event.y; + if (cur.x >= width) cur.x = width - 1; + if (cur.y >= height) cur.y = height - 1; + world[cur.x][cur.y] = (world[cur.x][cur.y]) ? 0 : 1; + } + break; + + case KEY_UP: + if (cur.y > 0) { + cur.y--; + } + break; + + case KEY_DOWN: + if (cur.y < height-1) { + cur.y++; + } + break; + + case KEY_LEFT: + if (cur.x > 0) { + cur.x--; + } + break; + + case KEY_RIGHT: + if (cur.x < width-1) { + cur.x++; + } + break; + case KEY_RESIZE: + world = resized(win, worlds, &width, &height); + break; +#endif + } + +#if defined(RANDOM_SPAWNS) + if (rnd_spawns) { + /* spawn a new pattern at a random position, if nothing happens */ + idle_gens++; + if (idle_gens >= RANDOM_SPAWNS && !cfg.paused) + { + idle_gens = 0; + inhabit_world(patterns[rand() % (sizeof(patterns)/sizeof(patterns[0]))], rand() % (width - 1), rand() % (height - 1), world, width, height); + } + } +#endif + + /* update screen */ + print_world(world, width, height); +#ifdef ENABLE_CURSOR + print_cursor(world, cur); +#endif +#ifdef ENABLE_STATUS + attron(COLOR_PAIR(1)); + for (int i = 0; i < width; i++) mvprintw(0, width - i, " "); + mvprintw(0, 0, "[generation:%4d] [cells:%3d] [fps:%2d] [width:%d] [height:%d] [cursor:%2d|%2d]", generation, calc_cell_count(world, width, height), framerate, width, height, cur.x, cur.y); + if (cfg .paused) mvprintw(0, width-6, "PAUSED"); + attroff(COLOR_PAIR(1)); +#endif + +#ifdef ENABLE_HOTKEYS + if (cfg.paused) { + print_menu(width, height); + usleep(1); + } +#endif + refresh(); + } + + free_all(worlds, width, height); + delwin(win); + endwin(); /* exit ncurses mode */ + return (EXIT_SUCCESS); +} diff --git a/suidcmd.c b/suidcmd.c new file mode 100644 index 0000000..b601c15 --- /dev/null +++ b/suidcmd.c @@ -0,0 +1,98 @@ +/* + * build with: gcc -std=c99 -D_GNU_SOURCE=1 -Wall -O2 -ffunction-sections -fdata-sections -fomit-frame-pointer ./suidcmd.c -o ./suidcmd + * strip -s ./suidcmd + */ + +#ifdef _HAVE_CONFIG +#include "config.h" +#endif +#include +#include +#include +#include +#include + + +#ifndef CMD +#define CMD "/usr/sbin/ether-wake" +#endif + + +int safe_exec(const char* cmdWithArgs) +{ + pid_t child; + if ( (child = fork()) == 0 ) { + size_t szCur = 0, szMax = 10; + char** args = calloc(szMax, sizeof(char**)); + const char* cmd = NULL; + + const char* prv = cmdWithArgs; + const char* cur = NULL; + while ( (cur = strchr(prv, ' ')) ) { + if (cmd == NULL) + cmd = strndup(prv, cur-prv); + + args[szCur++] = strndup(prv, cur-prv); + if (szCur >= szMax) { + szMax *= 2; + args = realloc(args, sizeof(char**)*szMax); + } + + cur++; + prv = cur; + } + if (cmd == NULL) { + cmd = cmdWithArgs; + } else { + args[szCur++] = strndup(prv, cur-prv); + } + args[szCur] = NULL; + execv(cmd, args); + } else { + int retval = 0; + waitpid(child, &retval, 0); + return retval; + } + return -1; +} + +int main(int argc, char** argv) +{ + uid_t ruid, euid, suid; + + if (getresuid(&ruid, &euid, &suid) != 0) { + perror("getresuid()"); + } else { + printf("%s: RUID:%u , EUID:%u , SUID:%u\n", argv[0], ruid, euid, suid); + } + + if (setuid(0) != 0) { + perror("setuid(0)"); + } else printf("%s: setuid(0)\n", argv[0]); + + char* cmd = NULL; + if (asprintf(&cmd, "%s", CMD) <= 0) { + fprintf(stderr, "%s: asprintf(\"%s\") error\n", argv[0], CMD); + return 1; + } + + char* prev_cmd = NULL; + for (int i = 1; i < argc; ++i) { + prev_cmd = cmd; + if (asprintf(&cmd, "%s %s", prev_cmd, argv[i]) < 0) { + fprintf(stderr, "%s: asprintf(\"%s\") error\n", argv[0], argv[i]); + return 1; + } + free(prev_cmd); + } + + int retval = -1; + switch ( (retval = safe_exec(cmd)) ) { + case -1: fprintf(stderr, "%s: could not create child process..\n", argv[0]); return 1; + case 127: fprintf(stderr, "%s: could not execute shell (child process)..\n", argv[0]); return 1; + default: + printf("%s: child process returned with: %d\n", argv[0], retval); + } + free(cmd); + return 0; +} diff --git a/xidle.c b/xidle.c new file mode 100644 index 0000000..c2794fc --- /dev/null +++ b/xidle.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include + + +/* Report amount of X server idle time. */ +/* gcc xidle.c -o xidle -lX11 -lXext -lXss */ + +int main(int argc, char *argv[]) +{ + Display *display; + int event_base, error_base; + XScreenSaverInfo info; + float seconds; + unsigned int d_seconds = 0; + + if (argc == 2) { + d_seconds = atoi(argv[1]); + } + + display = XOpenDisplay(""); + if (!display) + return -1; + + if (XScreenSaverQueryExtension(display, &event_base, &error_base) == true) { + if (XScreenSaverQueryInfo(display, DefaultRootWindow(display), &info) != true) { + fprintf(stderr, "Error: XScreenSaver QueryInfo failed\n"); + return -1; + } + seconds = (float)info.idle/1000.0f; + if ( d_seconds > 0 ) { + if (d_seconds <= (unsigned int) seconds) { + return 1; + } + } else { + printf("%f\n",seconds); + } + return 0; + } else { + fprintf(stderr,"Error: XScreenSaver Extension not present\n"); + return -1; + } +} + -- cgit v1.2.3