Add /bin/sh and /bin/login, demo users

This commit is contained in:
Mark
2020-01-17 23:02:33 +02:00
parent abf9715e43
commit 44cfef634b
14 changed files with 802 additions and 1020 deletions
+17 -2
View File
@@ -5,7 +5,8 @@ KERNEL_HDRS?=kernel-hdr
CC=x86_64-elf-yggdrasil-gcc
DIRS=$(O) \
$(STAGE)
$(STAGE) \
$(O)/sh
HDRS=$(shell find $(S) -type f -name "*.h")
STAGE_BIN=$(STAGE)/init \
$(STAGE)/bin/hexd \
@@ -14,7 +15,15 @@ STAGE_BIN=$(STAGE)/init \
$(STAGE)/bin/date \
$(STAGE)/bin/uname \
$(STAGE)/bin/mount \
$(STAGE)/bin/umount
$(STAGE)/bin/umount \
$(STAGE)/bin/sh \
$(STAGE)/bin/rm \
$(STAGE)/bin/mkdir \
$(STAGE)/bin/login
sh_OBJS=$(O)/sh/sh.o \
$(O)/sh/readline.o \
$(O)/sh/builtin.o \
$(O)/sh/cmd.o
usr_CFLAGS=-msse \
-msse2 \
@@ -49,3 +58,9 @@ $(STAGE)/init: init.c
$(STAGE)/bin/%: core/bin/%.c
$(CC) -o $@ $(usr_CFLAGS) $(usr_LDFLAGS) $<
$(STAGE)/bin/sh: $(sh_OBJS)
$(CC) -o $@ $(usr_LDFLAGS) $(sh_OBJS)
$(O)/sh/%.o: sh/%.c $(shell find sh -name "*.h")
$(CC) -c -o $@ $(usr_CFLAGS) $<
+183
View File
@@ -0,0 +1,183 @@
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <pwd.h>
struct spwd {
char *sp_namp;
char *sp_pwdp;
};
static ssize_t getline(char *buf, size_t lim, char pwchr) {
size_t c = 0;
char chr;
while (1) {
if (c == lim) {
return -1;
}
if (read(STDIN_FILENO, &chr, 1) != 1) {
return -1;
}
switch (chr) {
case '\n':
putchar('\n');
buf[c] = 0;
return c;
case '\b':
if (c) {
buf[--c] = 0;
puts2("\033[D \033[D");
}
break;
default:
if (chr >= ' ' && chr < 255) {
if (pwchr) {
putchar(pwchr);
} else {
putchar(chr);
}
buf[c++] = chr;
}
break;
}
}
}
static int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t buf_size) {
int fd = open("/etc/shadow", O_RDONLY, 0);
if (fd < 0) {
return fd;
}
while (gets_safe(fd, buf, buf_size) > 0) {
char *p0 = strchr(buf, ':');
if (!p0) {
break;
}
char *p1 = strchr(p0 + 1, ':');
if (!p1) {
break;
}
*p0 = 0;
*p1 = 0;
if (strcmp(buf, name)) {
continue;
}
close(fd);
sp->sp_namp = buf;
sp->sp_pwdp = p0 + 1;
return 0;
}
close(fd);
errno = ENOENT;
return -1;
}
static int loginuid(uid_t uid, gid_t gid, const char *sh) {
int sh_pid = fork();
if (sh_pid < 0) {
return -1;
}
if (sh_pid == 0) {
if (setuid(uid) || setgid(gid)) {
perror("login");
exit(-1);
}
const char *argp[] = { sh, NULL };
exit(execve(sh, argp, NULL));
} else {
int st;
waitpid(sh_pid, &st);
return 0;
}
}
static int loginas(const char *name) {
char pwbuf[512];
struct passwd pwd;
struct passwd *res;
const char *shell;
if (getpwnam_r(name, &pwd, pwbuf, sizeof(pwbuf), &res) != 0) {
perror("getpwnam_r()");
return -1;
}
shell = res->pw_shell;
if (access(shell, X_OK) != 0) {
perror(shell);
printf("Using /bin/sh instead\n");
shell = "/bin/sh";
}
return loginuid(res->pw_uid, res->pw_gid, shell);
}
int main(int argc, char **argv) {
// Arguments are ignored
if (getuid() != 0) {
printf("login must be run as root\n");
return -1;
}
int attempt = 0;
char line_buf[64];
char spnam_buf[128];
struct spwd sp;
while (access("/etc/shadow", R_OK) != 0) {
perror("/etc/shadow");
// Login as passwordless root?
if (loginuid(0, 0, "/bin/sh") != 0) {
return -1;
}
// Maybe after this session /etc/shadow becomes available
}
while (1) {
if (attempt == 3) {
puts2("\033[2J\033[1;1f");
attempt = 0;
}
printf("login: ");
if (getline(line_buf, sizeof(line_buf), 0) < 0) {
break;
}
if (getspnam_r(line_buf, &sp, spnam_buf, sizeof(spnam_buf)) != 0) {
perror("getspnam_r()");
++attempt;
continue;
}
printf("password: ");
if (getline(line_buf, sizeof(line_buf), '*') < 0) {
++attempt;
continue;
}
// No hashing yet, so just compare passwords
if (!strcmp(line_buf, sp.sp_pwdp)) {
loginas(sp.sp_namp);
// After returning from shell, go here
attempt = 3;
continue;
} else {
++attempt;
}
}
return -1;
}
+16
View File
@@ -0,0 +1,16 @@
#include <stdio.h>
int main(int argc, char **argv) {
if (argc <= 1) {
printf("usage: mkdir <path> ...\n");
return -1;
}
int res = 0;
for (int i = 1; i < argc; ++i) {
res += mkdir(argv[i], 0755);
}
return res;
}
+88
View File
@@ -0,0 +1,88 @@
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#define RM_RECURSIVE (1 << 0)
static int rm_node(const char *path, int flags) {
struct stat st;
if (stat(path, &st) != 0) {
perror(path);
return -1;
}
if ((st.st_mode & S_IFMT) == S_IFDIR) {
if (!(flags & RM_RECURSIVE)) {
printf("%s: Is a directory\n", path);
return -1;
}
DIR *dir = opendir(path);
if (!dir) {
perror(path);
return -1;
}
struct dirent *ent;
char child_path[256];
int yes = 1;
while ((ent = readdir(dir))) {
if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) {
snprintf(child_path, sizeof(child_path), "%s/%s", path, ent->d_name);
if (rm_node(child_path, flags) != 0) {
yes = 0;
}
}
}
closedir(dir);
if (!yes) {
printf("%s: Is a directory\n", path);
return -1;
}
if (rmdir(path) != 0) {
perror(path);
return -1;
}
return 0;
} else {
if (unlink(path) != 0) {
perror(path);
return -1;
}
return 0;
}
}
int main(int argc, char **argv) {
// 1 - recurse
int flags = 0;
int c;
if (argc <= 1) {
printf("usage: rm [-r] <path> ...\n");
return -1;
}
while ((c = getopt(argc, argv, "r")) != -1) {
switch (c) {
case 'r':
flags |= RM_RECURSIVE;
break;
default:
printf("usage: rm [-r] <path> ...");
return -1;
}
}
for (int i = optind; i < argc; ++i) {
rm_node(argv[i], flags);
}
return 0;
}
+2
View File
@@ -0,0 +1,2 @@
root:toor:
alnyan:password:
+8 -1018
View File
File diff suppressed because it is too large Load Diff
+96
View File
@@ -0,0 +1,96 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "builtin.h"
#include "cmd.h"
#define DEF_BUILTIN(b_name) \
static int __bcmd_##b_name(const struct cmd_exec *cmd)
#define DECL_BUILTIN(b_name) \
{ .name = #b_name, .exec = __bcmd_##b_name }
struct sh_builtin {
const char *name;
int (*exec) (const struct cmd_exec *cmd);
};
static struct sh_builtin __builtins[];
////
DEF_BUILTIN(exit) {
if (cmd->argc > 1) {
exit(atoi(cmd->args[1]));
}
exit(0);
}
DEF_BUILTIN(cd) {
if (cmd->argc != 2) {
printf("usage: cd <path>\n");
return -1;
}
return chdir(cmd->args[1]);
}
DEF_BUILTIN(clear) {
puts2("\033[2J\033[1;1f");
return 0;
}
// TODO: support usernames (getpwnam_r)
DEF_BUILTIN(setid) {
if (cmd->argc == 2) {
// Assume gid == uid
if (setuid(atoi(cmd->args[1])) != 0) {
return -1;
}
if (setgid(atoi(cmd->args[1])) != 0) {
return -1;
}
return 0;
}
if (cmd->argc != 3) {
printf("usage: setid <uid> <gid>\n");
return -1;
}
if (setuid(atoi(cmd->args[1])) != 0) {
return -1;
}
if (setgid(atoi(cmd->args[2])) != 0) {
return -1;
}
return 0;
}
DEF_BUILTIN(builtins) {
for (size_t i = 0; __builtins[i].name; ++i) {
printf("%s ", __builtins[i].name);
}
printf("\n");
return 0;
}
////
static struct sh_builtin __builtins[] = {
DECL_BUILTIN(builtins),
DECL_BUILTIN(cd),
DECL_BUILTIN(clear),
DECL_BUILTIN(exit),
DECL_BUILTIN(setid),
{NULL}
};
int builtin_exec(const struct cmd_exec *cmd, int *cmd_res) {
for (size_t i = 0; i < sizeof(__builtins) / sizeof(__builtins[0]); ++i) {
if (!strcmp(__builtins[i].name, cmd->args[0])) {
*cmd_res = __builtins[i].exec(cmd);
return 0;
}
}
return -1;
}
+5
View File
@@ -0,0 +1,5 @@
#pragma once
struct cmd_exec;
int builtin_exec(const struct cmd_exec *cmd, int *res);
+121
View File
@@ -0,0 +1,121 @@
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include "builtin.h"
#include "config.h"
#include "cmd.h"
static int make_cmd(char *input, struct cmd_exec *ex) {
char *p = strchr(input, ' ');
char *e;
if (!p) {
ex->args[0] = input;
ex->args[1] = NULL;
ex->argc = 1;
return 0;
}
*p++ = 0;
ex->args[0] = input;
ex->argc = 1;
while (1) {
while (isspace(*p)) {
++p;
}
if (!*p) {
break;
}
e = strchr(p, ' ');
if (!e) {
ex->args[ex->argc++] = p;
break;
} else {
*e++ = 0;
ex->args[ex->argc++] = p;
p = e;
}
}
ex->args[ex->argc] = NULL;
return 0;
}
//
static int cmd_spawn(const char *path, const struct cmd_exec *cmd, int *cmd_res) {
int pid;
if ((pid = fork()) < 0) {
perror("fork()");
return -1;
}
if (pid == 0) {
exit(execve(path, (const char *const *) cmd->args, NULL));
} else {
if (waitpid(pid, cmd_res) != 0) {
perror("waitpid()");
}
return 0;
}
}
static int cmd_exec_binary(const struct cmd_exec *cmd, int *cmd_res) {
char path_path[256];
int res;
if (cmd->args[0][0] == '.' || cmd->args[0][0] == '/') {
if ((res = access(cmd->args[0], X_OK)) != 0) {
perror(cmd->args[0]);
return res;
}
strcpy(path_path, cmd->args[0]);
return cmd_spawn(path_path, cmd, cmd_res);
}
snprintf(path_path, sizeof(path_path), "%s/%s", PATH, cmd->args[0]);
if ((res = access(path_path, X_OK)) == 0) {
return cmd_spawn(path_path, cmd, cmd_res);
}
return -1;
}
static int cmd_exec(const struct cmd_exec *cmd) {
int res, cmd_res;
if ((res = builtin_exec(cmd, &cmd_res)) == 0) {
return cmd_res;
}
if ((res = cmd_exec_binary(cmd, &cmd_res)) == 0) {
return cmd_res;
}
printf("sh: command not found: %s\n", cmd->args[0]);
return -1;
}
int eval(char *str) {
struct cmd_exec cmd;
while (isspace(*str)) {
++str;
}
if (!*str) {
return 0;
}
if (make_cmd(str, &cmd) != 0) {
abort();
}
return cmd_exec(&cmd);
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
struct cmd_exec {
size_t argc;
char *args[12];
};
int eval(char *str);
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#define COLOR_RED "\033[31m"
#define COLOR_GREEN "\033[32m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_MAGENTA "\033[35m"
#define COLOR_CYAN "\033[36m"
#define COLOR_RESET "\033[0m"
// TODO: take this from env (kernel does not support env yet)
#define PATH "/bin"
#define PS1 COLOR_MAGENTA "%u" COLOR_RESET \
"@" \
COLOR_CYAN "%h" COLOR_RESET " " \
COLOR_YELLOW "%d" COLOR_RESET \
" %# "
+145
View File
@@ -0,0 +1,145 @@
#include <sys/select.h>
#include <stdio.h>
#define KEY_UP (256)
#define KEY_DOWN (257)
#define KEY_RIGHT (258)
#define KEY_LEFT (259)
// With support for escape sequences
static int getch_del(void) {
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 500000
};
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
int res;
if ((res = select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv)) < 0) {
return res;
}
if (FD_ISSET(STDIN_FILENO, &fds)) {
res = 0;
if (read(STDIN_FILENO, &res, 1) != 1) {
return -1;
}
return res;
} else {
return -1;
}
}
static int escape_read(void) {
// Maybe [
int c = getch_del();
if (c < 0) {
return '\033';
}
if (c != '[') {
return -1;
}
c = getch_del();
switch (c) {
case 'A':
return KEY_UP;
case 'B':
return KEY_DOWN;
case 'C':
return KEY_RIGHT;
case 'D':
return KEY_LEFT;
default:
return -1;
}
}
static int getch(void) {
char c;
if (read(STDIN_FILENO, &c, 1) < 0) {
return -1;
}
if (c == '\033') {
int r = escape_read();
if (r > 0) {
return r;
}
}
return c;
}
int readline(char *buf, size_t lim) {
int len = 0;
int cur = 0;
int chr;
while (1) {
if ((chr = getch()) <= 0) {
return -1;
}
if (len == lim) {
printf("Input line is too long\n");
return -1;
}
switch (chr) {
case KEY_LEFT:
if (cur) {
puts2("\033[D");
--cur;
}
break;
case KEY_RIGHT:
if (cur < len) {
puts2("\033[C");
++cur;
}
break;
}
if (chr == '\n') {
putchar(chr);
buf[len] = 0;
break;
} else if (chr == '\b') {
if (cur) {
--cur;
for (int i = cur; i < len - 1; ++i) {
buf[i] = buf[i + 1];
}
puts2("\033[D\033[s");
--len;
for (int i = cur; i < len; ++i) {
putchar(buf[i]);
}
puts2(" \033[u");
}
} else if (chr >= ' ' && chr < 255) {
putchar(chr);
puts2("\033[s");
for (int i = cur; i < len; ++i) {
putchar(buf[i]);
}
puts2("\033[u");
for (int i = len; i > cur; --i) {
buf[i] = buf[i - 1];
}
buf[cur++] = chr;
++len;
}
}
return len;
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
int readline(char *buf, size_t lim);
+93
View File
@@ -0,0 +1,93 @@
#include <string.h>
#include <stdio.h>
#include <pwd.h>
#include "readline.h"
#include "config.h"
#include "cmd.h"
// Data needed for prompt
static char p_hostname[64];
static char p_username[64];
static char p_cwd[256];
static uid_t p_uid;
//static gid_t p_gid;
static void update_prompt(void) {
struct utsname _u;
struct passwd _p;
struct passwd *p;
char pwbuf[512];
p_uid = getuid();
if (getcwd(p_cwd, sizeof(p_cwd)) == NULL) {
perror("getcwd()");
p_cwd[0] = 0;
}
if (uname(&_u) != 0) {
perror("uname()");
p_hostname[0] = 0;
} else {
strcpy(p_hostname, _u.nodename);
}
if (getpwuid_r(p_uid, &_p, pwbuf, sizeof(pwbuf), &p) != 0) {
perror("getpwuid_r()");
p_username[0] = 0;
} else {
strcpy(p_username, p->pw_name);
}
}
static void display_prompt(void) {
const char *p = PS1;
while (*p) {
if (*p == '%') {
switch (*++p) {
case '#':
putchar(p_uid == 0 ? '#' : '$');
break;
case 'h':
puts2(p_hostname);
break;
case 'u':
puts2(p_username);
break;
case 'd':
puts2(p_cwd);
break;
default:
putchar('%');
putchar(*p);
break;
}
} else {
putchar(*p);
}
++p;
}
}
int main(int argc, char **argv) {
char linebuf[256];
int res;
while (1) {
update_prompt();
display_prompt();
if (readline(linebuf, sizeof(linebuf)) < 0) {
break;
}
if ((res = eval(linebuf)) != 0) {
printf(COLOR_RED "Status: %d" COLOR_RESET "\n", res);
}
}
return 0;
}