summaryrefslogtreecommitdiff
path: root/src/cmd/login
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/login')
-rw-r--r--src/cmd/login/login.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/cmd/login/login.c b/src/cmd/login/login.c
new file mode 100644
index 0000000..0f9e8b7
--- /dev/null
+++ b/src/cmd/login/login.c
@@ -0,0 +1,89 @@
+#include <camellia/flags.h>
+#include <camellia/syscalls.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <camellia/fs/misc.h>
+
+static const char *shell = "/bin/shell";
+
+static void cutspace(char *s) {
+ for (; *s; s++) {
+ if (isspace(*s)) {
+ *s = '\0';
+ break;
+ }
+ }
+}
+
+static bool segcmp(const char *path, int idx, const char *s2) {
+ if (idx < 0) return false;
+ while (idx > 0) {
+ if (*path == '\0') return false;
+ if (*path == '/') idx--;
+ path++;
+ }
+ /* path is at the start of the selected segment */
+ while (*s2 && *path++ == *s2++);
+ return (*path == '\0' || *path == '/') && *s2 == '\0';
+}
+
+static void drv(const char *user) {
+ char *buf = malloc(PATH_MAX);
+ for (;;) {
+ struct ufs_request req;
+ hid_t reqh = ufs_wait(buf, PATH_MAX, &req);
+ if (reqh < 0) break;
+ switch (req.op) {
+ case VFSOP_OPEN:
+ if (segcmp(buf, 1, "Users") && segcmp(buf, 2, user)) { // /Users/$user/**
+ forward_open(reqh, buf, req.len, req.flags);
+ } else if (segcmp(buf, 1, "Users") && segcmp(buf, 3, "private")) { // /Users/*/private/**
+ _sys_fs_respond(reqh, NULL, -EACCES, 0);
+ } else if (!OPEN_WRITEABLE(req.flags)) {
+ forward_open(reqh, buf, req.len, req.flags);
+ } else {
+ _sys_fs_respond(reqh, NULL, -EACCES, 0);
+ }
+ break;
+
+ default:
+ _sys_fs_respond(reqh, NULL, -1, 0);
+ break;
+ }
+ }
+ free(buf);
+}
+
+static void trylogin(const char *user) {
+ if (strcmp(user, "root") != 0) {
+ char buf[128];
+ snprintf(buf, sizeof buf, "/Users/%s/", user);
+ if (chdir(buf) < 0) {
+ printf("no such user: %s\n", user);
+ return;
+ }
+ MOUNT_AT("/") { drv(user); }
+ }
+
+ execv(shell, NULL);
+ fprintf(stderr, "login: couldn't launch %s\n", shell);
+ exit(1);
+}
+
+int main(void) {
+ char user[64];
+ printf("\nCamellia\n");
+ for (;;) {
+ printf("login: ");
+ fgets(user, sizeof user, stdin);
+ if (ferror(stdin)) return -1;
+
+ cutspace(user);
+ if (user[0]) trylogin(user);
+ }
+}