aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar moon <moon@coffin.ir> 2026-04-05 14:17:54 +0330
committerGravatar moon <moon@coffin.ir> 2026-04-05 14:17:54 +0330
commit194468c465e84879592853260b788ea17ca0f1e8 (patch)
treeea1049f12117adab46e13dd9ce6ab3d22e0a5248
parentdocumentation (diff)
laim 0.2.3
-rw-r--r--laim.c600
1 files changed, 600 insertions, 0 deletions
diff --git a/laim.c b/laim.c
new file mode 100644
index 0000000..a58b08e
--- /dev/null
+++ b/laim.c
@@ -0,0 +1,600 @@
+// laim (0.2.3): a lame mail server
+// centeralized design, manual admin sign-up
+// files are easily parsable by other programs, and this can act as a sort of IPC as well.
+// use --boot to run this program over TCP+TLS
+// connect to it with `ncat --ssl <address> <port>`
+// or `nc <address> <port>` if not running under SSL
+//
+// stripped using elfkickers' sstrip
+// compressed using `upx --ultra-brute laim --lzma --no-align`
+//
+// created by Moon Flower Fields (https://coffin.ir/)
+// or @moonflowerfields on Telegram
+
+// very funny.
+#define COMEDIAN false
+
+#define SZ 64 + 5 + 1 + 1
+#define EOF -1
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+typedef uint64_t u64;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef u8 byte;
+typedef byte bool;
+const bool true = 1;
+const bool false = 0;
+
+struct linux_dirent64 {
+ u64 d_ino;
+ u64 d_off;
+ u16 d_reclen;
+ u8 d_type;
+ char d_name[];
+};
+
+char get_char() {
+GETCHAR_START:;
+ char buf[ 1 ];
+ if (read(STDIN_FILENO, buf, 1) == 0) return EOF;
+ if (buf[ 0 ] == '\r') goto GETCHAR_START; // band-aid fix.
+ return buf[ 0 ];
+}
+
+char *sadd(char *p, const char *s) {
+ while (*s) *p++ = *s++;
+ return p;
+}
+
+void memcopy(char *s, const char *d, u64 len) {
+ for (u64 i = 0; i < len; i++) s[ i ] = d[ i ];
+}
+
+void memzero(char* s, u64 len) {
+ for (u64 i = 0; i < len; i++) s[i] = 0;
+}
+
+char *nadd(char *p, u64 n) {
+ if (!n) {
+ *p++ = '0';
+ return p;
+ }
+ char tmp[ 20 ];
+ int i = 20;
+ while (n) {
+ tmp[ --i ] = '0' + (n % 10);
+ n /= 10;
+ }
+ int len = 20 - i;
+ memcopy(p, tmp + i, len);
+ return p + len;
+}
+
+void print_u64(u64 n) {
+ char tmp[ 20 ];
+ char *p = nadd(tmp, n);
+ write(STDOUT_FILENO, tmp, p - tmp);
+}
+
+typedef struct {
+ char buf[ 21 ];
+ int len;
+} u64str;
+
+u64str str_u64(u64 n) {
+ u64str s;
+ char *p = nadd(s.buf, n);
+ *p = 0;
+ s.len = p - s.buf;
+ return s;
+}
+
+u64 scan_u64() {
+ u64 n = 0;
+ char tsbuf[ 21 ];
+ int len = read(STDIN_FILENO, tsbuf, sizeof(tsbuf) - 1);
+ for (int i = 0; i < len; i++) {
+ if (tsbuf[ i ] >= '0' && tsbuf[ i ] <= '9') n = n * 10 + (tsbuf[ i ] - '0');
+ else
+ break;
+ }
+ return n;
+}
+
+u64 lenstr(const char *str) {
+ u64 i = 0;
+ while (str[i]) i++;
+ return i;
+}
+
+void writes(const char *string) { write(STDOUT_FILENO, string, lenstr(string)); }
+
+void list_users(int dir_fd) {
+ char buf[ 1024 ];
+ int n;
+ while ((n = syscall(217, dir_fd, buf, sizeof(buf))) > 0) {
+ for (int off = 0; off < n;) {
+ struct linux_dirent64 *d = (struct linux_dirent64 *) (buf + off);
+ if (d->d_name[ 0 ] != '.') {
+ write(STDOUT_FILENO, d->d_name, lenstr(d->d_name));
+ char lastlogin[ SZ ] = { 0 };
+ char *p = lastlogin;
+ p = sadd(p, "mail/");
+ p = sadd(p, d->d_name);
+ p = sadd(p, "/.login");
+ int login_fd = open(lastlogin, O_RDONLY);
+ if (login_fd >= 0) {
+ u64 ts;
+ read(login_fd, &ts, 8);
+ writes(" ");
+ print_u64(ts);
+ writes("\n");
+ close(login_fd);
+ } else {
+ writes(" 0\n");
+ }
+ }
+ off += d->d_reclen;
+ }
+ }
+}
+
+int smake(char *name) { return open(name, O_RDWR | O_CREAT, 0600); }
+void slock(int fd) { flock(fd, LOCK_EX); }
+void sopen(int fd) { flock(fd, LOCK_UN); }
+
+#define err(a) \
+ ({ \
+ writes(a); \
+ continue; \
+ })
+
+void printmail(char path[ SZ ], u64 after) {
+ mkdir(path, 0700); // make it if it doesnt exist
+
+ int dir_fd = open(path, O_RDONLY | O_DIRECTORY);
+ if (dir_fd < 0) return;
+
+ int cfd = openat(dir_fd, ".count", O_RDONLY);
+ if (cfd < 0) {
+ writes(";");
+ close(dir_fd);
+ return;
+ }
+ u64 total = 0;
+ read(cfd, &total, sizeof(u64));
+ close(cfd);
+
+ for (u64 i = 0; i < total; i++) {
+ u64str name = str_u64(i);
+ int mail_fd = openat(dir_fd, name.buf, O_RDONLY);
+ if (mail_fd < 0) continue;
+ flock(mail_fd, LOCK_SH);
+
+ struct stat st;
+ fstat(mail_fd, &st);
+ if (st.st_size == 0) {
+ close(mail_fd);
+ continue;
+ }
+
+ u64 ts = 0;
+ char tsbuf[ 21 ];
+ int n = read(mail_fd, tsbuf, sizeof(tsbuf) - 1);
+ if (n <= 0) {
+ close(mail_fd);
+ continue;
+ }
+ tsbuf[ n ] = 0;
+ for (int j = 0; j < n; j++) {
+ if (tsbuf[ j ] >= '0' && tsbuf[ j ] <= '9') ts = ts * 10 + (tsbuf[ j ] - '0');
+ else {
+ lseek(mail_fd, j - n, SEEK_CUR);
+ break;
+ }
+ }
+
+ if (ts < after) {
+ close(mail_fd);
+ continue;
+ }
+
+ char *p, header[ 64 + 1 ] = { 0 };
+ p = nadd(header, i);
+ *p++ = '\n';
+ write(STDOUT_FILENO, header, p - header);
+ p = nadd(header, ts);
+ write(STDOUT_FILENO, header, p - header);
+
+ char buf[ 256 ];
+ int r;
+ while ((r = read(mail_fd, buf, sizeof(buf))) > 0) write(STDOUT_FILENO, buf, r);
+
+ writes("\n\neof\n");
+ close(mail_fd);
+ }
+ close(dir_fd);
+}
+
+u64 create_index(int dirfd) {
+ int cfd = openat(dirfd, ".count", O_RDWR | O_CREAT, 0600);
+ if (cfd < 0) return -1;
+ u64 count = 0;
+ read(cfd, &count, sizeof(u64));
+ count++;
+ lseek(cfd, 0, SEEK_SET);
+ if (write(cfd, &count, sizeof(u64)) != sizeof(u64)) {
+ close(cfd);
+ return -1;
+ }
+ ftruncate(cfd, sizeof(u64));
+ close(cfd);
+ return count - 1;
+}
+
+const char motd[] = "a laim server!\n";
+const char docs[] = {
+#embed "docs.txt"
+ , 0
+};
+const char source[] = {
+#embed "laim.c"
+ , 0
+};
+const char makefile[] = {
+ #embed "Makefile"
+ ,
+};
+
+// used for both passwords and usernames.
+// not my fault if you wanna use a weird pass.
+bool is_path_char(char c) {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.'
+ || c == ' ' || c == '$';
+}
+
+#define read_field(buf, err, fail_action, len_buf) \
+ ({ \
+ bool _term = false; \
+ for (u8 _i = 0; _i < 64; _i++) { \
+ (buf)[ _i ] = get_char(); \
+ if ((buf)[ _i ] == '\n') { \
+ (buf)[ _i ] = 0; \
+ _term = true; \
+ if (len_buf != NULL) { \
+ u8 *ptr = len_buf; \
+ *ptr = _i; \
+ } \
+ break; \
+ } \
+ if (!is_path_char((buf)[ _i ])) { \
+ writes(err); \
+ fail_action; \
+ } \
+ } \
+ if (!_term) { \
+ writes(err); \
+ fail_action; \
+ } \
+ })
+
+// timing safe or whatever.
+bool safe_cmp(char *left, char *right, u64 size) {
+ bool nonmatch = false;
+ bool ended = false;
+ for (u64 i = 0; i < size; i++) {
+ nonmatch = ((*left != *right) && !ended) | nonmatch;
+ ended = (*left == 0 || *right == 0) | ended;
+ left++, right++;
+ }
+ return !nonmatch;
+}
+
+void openwrite(char *filename, const char *content) {
+ int fd = open(filename, O_RDWR | O_CREAT, 0600);
+ write(fd, content, lenstr(content));
+ close(fd);
+}
+
+int main(int argc, char **argv) {
+ char path[ 4096 ] = {0};
+ readlink("/proc/self/exe", path, sizeof(path) - 1);
+
+ if (argc > 1) {
+ if (safe_cmp(argv[ 1 ], "--help", 6) || safe_cmp(argv[ 1 ], "-h", 2)) {
+ writes(
+ "laim: lame mail server\n"
+ "created by: moon (coffin.ir)\n"
+ "\n"
+ "laim is a mail server that operates on STDIO.\n"
+ "it is meant to be run with a networking program, such as socat, or busybox's tcpsvd.\n"
+ "it can be served over SSL using socat or busybox's ssl_server, which pipes TLS to I/O.\n"
+ "\n"
+ "usage:\n"
+ " ");
+ writes(argv[ 0 ]);
+ writes(
+ " --help\n"
+ " shows this message (non-zero exit)\n"
+ " ");
+ writes(argv[ 0 ]);
+ writes(
+ " --open\n"
+ " extracts the program's source code and build files (non-zero exit)\n"
+ " ");
+ writes(argv[ 0 ]);
+ writes(
+ " --boot <bind_addr> <bind_port> <ssl_joint_path>\n"
+ " re-runs laim, wrapped with ssl_server and tcpsvd, provided a busybox with those applets is "
+ "installed.\n"
+ "\n");
+ return 1;
+ } else if (safe_cmp(argv[ 1 ], "--open", 6)) {
+ openwrite("laim.c", source);
+ openwrite("docs.txt", docs);
+ openwrite("Makefile", makefile);
+ writes("done\n");
+ return 1;
+ } else if (safe_cmp(argv[ 1 ], "--boot", 6)) {
+ if (argc != 5) {
+ writes("too many / too little args, read --help\n");
+ return 1;
+ }
+ char *new_argv[] = { "tcpsvd", "-v", argv[ 2 ], argv[ 3 ], "ssl_server", "-f", argv[ 4 ], path };
+ execvp("busybox", new_argv);
+ } else {
+ writes("unknown arg\n");
+ return 1;
+ }
+ }
+
+ char user[ 64 + 1 ] = { 0 }, pass[ 64 + 1 ] = { 0 };
+ u8 userlen = 0;
+ // v=1
+ writes("laim\2\n");
+
+ // manipulates:
+ // users/ - user db, manually add users
+ // mail/ - mails directory, each filename is a username
+ mkdir("users", 0700);
+ mkdir("mail", 0700);
+ mkdir("mail/broadcast", 0700);
+
+__BACK_TO_START:;
+ memzero(user, 65);
+ memzero(pass, 65);
+ int action = get_char();
+ if (action == 'M') {
+ writes(motd);
+ goto __BACK_TO_START;
+ } else if (action == 'L') {
+ // username
+ read_field(user, "4", goto __BACK_TO_START, &userlen);
+ // password
+ read_field(pass, "5", goto __BACK_TO_START, NULL);
+
+ char user_path[ 5 + 1 + 64 + 1 ] = "users/";
+ memcopy(user_path + 6, user, userlen);
+ user_path[ 6 + userlen ] = 0;
+
+ if (access(user_path, F_OK) != 0) {
+ writes("N");
+ goto __BACK_TO_START;
+ }
+
+ int fd = open(user_path, O_RDONLY);
+ if (fd < 0) {
+ writes("err:fopen\n");
+ return 1;
+ }
+ char actual_pass[ 65 ] = { 0 };
+ int pass_size = read(fd, actual_pass, 64);
+ actual_pass[ pass_size ] = 0;
+ if (!safe_cmp(pass, actual_pass, 64)) { // safe timing or whatever.
+ writes("I");
+ sleep(2); // punish user
+ goto __BACK_TO_START;
+ }
+ memzero(actual_pass, 65);
+ close(fd);
+ writes("O");
+ // only fallthrough
+ } else if (action == EOF) {
+ return 1;
+ } else {
+ writes("?");
+ goto __BACK_TO_START;
+ }
+
+ // -- authorized from here on out --
+
+ { // write last login
+ char last_login[ SZ ] = { 0 };
+ char *p = last_login;
+ p = sadd(p, "mail/");
+ p = sadd(p, user);
+ p = sadd(p, "/.login");
+ int login_fd = open(last_login, O_RDWR | O_CREAT, 0600);
+ if (login_fd >= 0) {
+ ftruncate(login_fd, 0);
+ u64 ts = time(NULL);
+ write(login_fd, &ts, 8);
+ close(login_fd);
+ }
+ }
+
+ bool broadcast_mode = false; // kinda useless. may delete. TODO
+
+ // remove password from memory
+ memzero(pass, 65);
+
+ // make sure user has a mail dir
+ char user_filename[ SZ ] = { 0 };
+ char *p = user_filename;
+ p = sadd(p, "mail/");
+ p = sadd(p, user);
+ p = sadd(p, "/");
+ mkdir(user_filename, 0700);
+
+ char user_count_filename[ SZ ] = { 0 };
+ p = sadd(user_count_filename, user_filename);
+ p = sadd(p, ".count");
+
+ char broadcast_filename[ SZ ] = "mail/broadcast/";
+ char broadcast_count_filename[ SZ ] = "mail/broadcast/.count";
+
+ char *filename = user_filename;
+ char *count_filename = user_count_filename;
+
+ int _c;
+ while ((_c = get_char()) != EOF) {
+ if (_c == '\n') continue;
+ char c = _c;
+ if (c == 'G') { // get all mail
+ printmail(filename, 0);
+ } else if (c == 'W') { // whoami
+ if (COMEDIAN) writes("you're... you!");
+ else { writes(user); }
+ writes("\n");
+ } else if (c == 'E') { // count inbox size, includes deleted mails
+ int count_fd = open(count_filename, O_RDONLY);
+ if (count_fd < 0) err("!");
+ u64 result = 0;
+ int size = read(count_fd, &result, 8);
+ if (size < 8) {
+ close(count_fd);
+ err("!");
+ }
+ close(count_fd);
+ print_u64(result);
+ writes("\n");
+ } else if (c == 'B') { // turn on broadcast mode.
+ broadcast_mode = true;
+ filename = broadcast_filename;
+ count_filename = broadcast_count_filename;
+ writes("O");
+ } else if (c == 'Q') { // turn off broadcast mode.
+ broadcast_mode = false;
+ filename = user_filename;
+ count_filename = user_count_filename;
+ writes("O");
+ } else if (c == 'U') { // list all users
+ int dir_fd = open("users/", O_RDONLY | O_DIRECTORY);
+ if (dir_fd < 0) {
+ writes("err:dir\n");
+ continue;
+ }
+ list_users(dir_fd);
+ close(dir_fd);
+ } else if (c == 'T') { // get mail after X
+ printmail(filename, scan_u64());
+ } else if (c == 'S') { // send mail
+ char target[ 64 + 1 ];
+ read_field(target, "7", goto __WHILE_END, NULL);
+
+ char dest_path[ 64 + 5 + 1 + 20 + 1 ];
+ p = sadd(dest_path, "mail/");
+ p = sadd(p, target);
+ p = sadd(p, "/");
+ mkdir(dest_path, 0700);
+
+ // lock directory and calculate size to prevent issues
+ int dir_fd = open(dest_path, O_RDONLY | O_DIRECTORY);
+ if (dir_fd < 0) {
+ writes("err:dir\n");
+ continue;
+ }
+ slock(dir_fd);
+
+ u64 index = create_index(dir_fd);
+ if (index == -1) {
+ writes("!");
+ continue;
+ }
+ p = sadd(dest_path, "mail/");
+ p = sadd(p, target);
+ p = sadd(p, "/");
+ p = nadd(p, index);
+
+ int user_fd = smake(dest_path);
+ if (user_fd < 0) {
+ sopen(dir_fd);
+ close(dir_fd);
+ writes("err:smake\n");
+ continue;
+ }
+ slock(user_fd);
+ sopen(dir_fd);
+ close(dir_fd);
+
+ u64 timestamp = time(NULL);
+ print_u64(timestamp);
+ writes("\n");
+ writes(user);
+ writes("\n");
+
+ bool hit_limit = false;
+
+ u64 total_size = 0;
+ char buf[ 256 ];
+ int read_size;
+ while ((read_size = read(STDIN_FILENO, buf, 256)) != 0 && read_size > 0) {
+ total_size += read_size;
+ write(user_fd, buf, read_size);
+ if (total_size > 65536) {
+ hit_limit = true;
+ writes(".");
+ break;
+ }
+ }
+
+ if (!hit_limit) writes("O");
+
+ sopen(user_fd);
+ close(user_fd);
+ } else if (c == 'D') { // delete mail
+ u64 index = scan_u64();
+
+ char dest_path[ 64 + 5 + 1 + 20 + 1 ];
+ p = sadd(dest_path, filename);
+ p = nadd(p, index);
+ if (unlink(dest_path) < 0) err("8");
+ else { err("O"); }
+ } else if (c == 'C') { // change password
+ char newpass[ 65 ], newpass2[ 65 ];
+ u8 passlen, passlen2;
+ read_field(newpass, "6", goto __WHILE_END, &passlen);
+ read_field(newpass2, "7", goto __WHILE_END, &passlen2);
+
+ // passwords don't match
+ if (passlen != passlen2) err("K");
+ if (safe_cmp(newpass, newpass2, passlen) != 0) err("K");
+
+ char user_path[ 6 + 64 + 1 ] = "users/";
+ memcopy(user_path + 6, user, userlen);
+ user_path[ 6 + userlen ] = 0;
+
+ int ufd = smake(user_path);
+ if (ufd < 0) err("8");
+ slock(ufd);
+ int newpass_len = lenstr(newpass);
+ write(ufd, newpass, newpass_len);
+ ftruncate(ufd, newpass_len); // if newpass_len < oldpass_len
+ sopen(ufd);
+ close(ufd);
+ writes("O");
+ } else {
+ writes("?");
+ }
+ __WHILE_END:;
+ }
+
+ return 0;
+}