aboutsummaryrefslogtreecommitdiff
path: root/laim.c
diff options
context:
space:
mode:
Diffstat (limited to 'laim.c')
-rw-r--r--laim.c165
1 files changed, 104 insertions, 61 deletions
diff --git a/laim.c b/laim.c
index cd491ad..8e1648e 100644
--- a/laim.c
+++ b/laim.c
@@ -1,4 +1,4 @@
-// laim (0.3.0): a lame mail server
+// laim (0.3.0-0): a lame mail server
//
// creator: moon flower fields
// website: coffin.ir
@@ -200,6 +200,10 @@ u64 now() {
return ts.tv_sec;
}
+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); }
+
u64 room_user_count(char *room_path) {
static char members_path[ SZ ];
sit(members_path, room_path, ".members/");
@@ -218,7 +222,6 @@ u64 room_user_count(char *room_path) {
int fd = openat(dir_fd, d->d_name, O_RDONLY);
if (fd >= 0) {
if (flock(fd, LOCK_EX | LOCK_NB) == 0) {
- flock(fd, LOCK_UN);
unlinkat(dir_fd, d->d_name, 0);
} else {
count++;
@@ -269,10 +272,6 @@ void list_users(int dir_fd, bool rooms) {
}
}
-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); \
@@ -330,7 +329,12 @@ void printmail(char path[ SZ ], u64 after) {
return;
}
u64 total = 0;
- read(cfd, &total, sizeof(u64));
+ if (read(cfd, &total, sizeof(u64)) != sizeof(u64)) {
+ close(cfd);
+ close(dir_fd);
+ writes("!");
+ return;
+ }
close(cfd);
for (u64 i = 0; i < total; i++) { printindex(dir_fd, str_u64(i), after); }
@@ -341,7 +345,7 @@ 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));
+ if (read(cfd, &count, sizeof(u64)) != sizeof(u64)) count = 0;
count++;
lseek(cfd, 0, SEEK_SET);
if (write(cfd, &count, sizeof(u64)) != sizeof(u64)) {
@@ -381,6 +385,10 @@ bool field_more = false;
field_more = false; \
for (u8 _i = 0; _i < 64; _i++) { \
int _ch = get_char(); \
+ if (_i == 0 && (char) _ch == '.') { \
+ writes(err); \
+ fail_action; \
+ } \
if (_ch == field_sep) { \
(buf)[ _i ] = 0; \
_term = true; \
@@ -439,29 +447,45 @@ static char member_file[ SZ ] = { 0 };
void leave_room() {
if (member_fd < 0) return;
- flock(member_fd, LOCK_UN);
+ sopen(member_fd);
close(member_fd);
member_fd = -1;
unlink(member_file);
- if (ephemeral && room_user_count((char *) filename) == 0) {
- static char mp2[ SZ ];
- sit(mp2, filename, ".members/");
- *glob_buf = 0;
- rmdir(mp2);
- int cfd2 = open(count_filename, O_RDONLY);
- u64 total2 = 0;
- if (cfd2 >= 0) {
- read(cfd2, &total2, 8);
- close(cfd2);
- }
- for (u64 i = 0; i < total2; i++) {
- static char mp[ SZ ];
- sit(mp, filename, str_u64(i));
- *glob_buf = 0;
- unlink(mp);
+ if (ephemeral) {
+ int room_fd = open(filename, O_RDONLY | O_DIRECTORY);
+ if (room_fd >= 0) {
+ slock(room_fd);
+
+ if (room_user_count((char *) filename) == 0) {
+ // wipe .members/
+ static char mp2[ SZ ];
+ sit(mp2, filename, ".members/");
+ *glob_buf = 0;
+ rmdir(mp2);
+
+ // read .count for mail
+ int cfd2 = open(count_filename, O_RDONLY);
+ u64 total2 = 0;
+ if (cfd2 >= 0) {
+ if (read(cfd2, &total2, 8) == 8) {
+ for (u64 i = 0; i < total2; i++) {
+ static char mp[ SZ ];
+ sit(mp, filename, str_u64(i));
+ *glob_buf = 0;
+ unlink(mp);
+ }
+ }
+ close(cfd2);
+ }
+
+ // cleanup
+ unlink(count_filename);
+ rmdir(filename);
+ }
+
+ sopen(room_fd);
+ close(room_fd);
}
- unlink(count_filename);
- rmdir(filename);
}
ephemeral = false;
}
@@ -641,22 +665,6 @@ laim_start:;
memcopy(user_path + 6, user, userlen);
user_path[ 6 + userlen ] = 0;
- // check lastlogin before sleeping
- char last_login[ SZ ] = { 0 };
- sit(last_login, "mail/", user, "/.login");
- *glob_buf = 0;
- {
- int login_fd = open(last_login, O_RDONLY);
- u64 old_ts = 0, old_pid = 0;
- if (login_fd >= 0) {
- read(login_fd, &old_ts, 8);
- read(login_fd, &old_pid, 8);
- close(login_fd);
- }
- if (old_pid > 0) syscall(62, old_pid, 9); // kill old
- if (now() - old_ts < 5) sleep(1); // fly swatter
- }
-
if (access(user_path, F_OK) != 0) {
writes("I");
sleep(1);
@@ -678,7 +686,36 @@ laim_start:;
}
memzero(actual_pass, 65);
close(fd);
+
writes("O");
+
+ // check lastlogin before sleeping
+ char last_login[ SZ ] = { 0 };
+ sit(last_login, "mail/", user, "/.login");
+ *glob_buf = 0;
+
+ {
+ int login_fd = open(last_login, O_RDWR | O_CREAT, 0600);
+ if (login_fd >= 0) {
+ u64 old_ts = 0, old_pid = 0;
+ read(login_fd, &old_ts, 8);
+ read(login_fd, &old_pid, 8);
+
+ if (old_pid > 0) syscall(62, old_pid, 9); // kill old
+ if (now() - old_ts < 5) sleep(1); // fly swatter
+
+ // atomic replace
+ ftruncate(login_fd, 0);
+ u64 ts = now();
+ u64 pid = syscall(39); // getpid
+ write(login_fd, &ts, 8);
+ write(login_fd, &pid, 8);
+
+ close(login_fd);
+ }
+ // skip on fail
+ }
+
// only fallthrough
} else if (action == EOF) {
return 1;
@@ -689,20 +726,6 @@ laim_start:;
// -- authorized from here on out --
- { // write last login
- char last_login[ SZ ] = { 0 };
- sit(last_login, "mail/", user, "/.login");
- int login_fd = open(last_login, O_RDWR | O_CREAT, 0600);
- if (login_fd >= 0) {
- ftruncate(login_fd, 0);
- u64 ts = now();
- u64 pid = syscall(39); // getpid
- write(login_fd, &ts, 8);
- write(login_fd, &pid, 8);
- close(login_fd);
- }
- }
-
// remove password from memory
memzero(pass, 65);
@@ -903,23 +926,37 @@ laim_start:;
close(ifd);
writes("O");
} else if (c == 'D') {
+ if (member_fd >= 0) {
+ writes("!");
+ goto while_end;
+ }
+
// replaces indexed mail with last mail
// always delete last-to-first
u64 index = scan_u64();
- int dir_fd = open(filename, O_PATH | O_DIRECTORY);
+ int dir_fd = open(filename, O_RDONLY | O_DIRECTORY);
if (dir_fd < 0) err("8");
+ slock(dir_fd);
+
int cfd = openat(dir_fd, ".count", O_RDWR);
if (cfd < 0) {
+ sopen(dir_fd);
close(dir_fd);
err("8");
}
u64 total = 0;
- read(cfd, &total, 8);
+ if (read(cfd, &total, 8) != 8) {
+ close(cfd);
+ sopen(dir_fd);
+ close(dir_fd);
+ err("8");
+ }
if (total == 0 || index >= total) {
close(cfd);
+ sopen(dir_fd);
close(dir_fd);
err("8");
}
@@ -931,8 +968,9 @@ laim_start:;
*glob_buf = 0;
nlod(dst, index);
*glob_buf = 0;
- if (syscall(264, dir_fd, src, dir_fd, dst) < 0) {
+ if (syscall(264, dir_fd, src, dir_fd, dst) < 0) { // renameat2
close(cfd);
+ sopen(dir_fd);
close(dir_fd);
err("8");
}
@@ -941,10 +979,14 @@ laim_start:;
unlinkat(dir_fd, str_u64(last), 0);
lseek(cfd, 0, SEEK_SET);
- write(cfd, &total, 8);
+ if (write(cfd, &total, 8) != 8) {
+ writes("you're out of disk space or something. literally idk how this could happen\n");
+ break;
+ }
ftruncate(cfd, 8);
close(cfd);
+ sopen(dir_fd);
close(dir_fd);
writes("O");
} else if (c == 'C') { // change password
@@ -978,6 +1020,7 @@ laim_start:;
while_end:;
}
+ leave_room();
flush();
return 0;
}