Compare commits

..

5 Commits

Author SHA1 Message Date
5aba1c5f15 su: Make it setuid root, ask for a password, and accept a username
It asks for a password only if you are not root, obviously.
2022-10-28 20:57:13 +02:00
477af66cdc ps: Show usernames of processes, using getpwuid() 2022-10-28 20:55:39 +02:00
7d0e442cde libc: Add /etc/passwd and the pwd.h API
getpwent, getpwnam, getpwuid... they may have been a pain to implement but once they work they're awesome :)

Right now passwords are stored in plaintext in the world-readable passwd file, which is not good.
But I don't have any sort of hashing implemented so it'll stay that way for now.
2022-10-28 20:55:00 +02:00
e05f3f5325 Kernel: Read file modes from the initrd, filtering out write permissions 2022-10-28 20:52:10 +02:00
a2d9ada4dc oopsie 2022-10-28 19:38:04 +02:00
9 changed files with 291 additions and 8 deletions

View File

@ -17,6 +17,7 @@ build: $(REAL_APPS)
install: $(REAL_APPS) install: $(REAL_APPS)
@mkdir -p $(LUNA_ROOT)/initrd/bin @mkdir -p $(LUNA_ROOT)/initrd/bin
cp $(REAL_APPS) $(LUNA_ROOT)/initrd/bin cp $(REAL_APPS) $(LUNA_ROOT)/initrd/bin
@chmod a+s $(LUNA_ROOT)/initrd/bin/su
clean: clean:
rm -f $(APPS_BIN)/* rm -f $(APPS_BIN)/*

View File

@ -1,5 +1,6 @@
#include <errno.h> #include <errno.h>
#include <luna/pstat.h> #include <luna/pstat.h>
#include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -17,7 +18,9 @@ pid_t get_current_max_threads()
void display_process(struct pstat* pstatbuf) void display_process(struct pstat* pstatbuf)
{ {
printf("%d %d %ld %ld %s %s (%ld ms)\n", pstatbuf->pt_uid, pstatbuf->pt_gid, pstatbuf->pt_pid, pstatbuf->pt_ppid, struct passwd* pwd = getpwuid(pstatbuf->pt_uid);
if (!pwd && errno) perror("getpwuid");
printf("%s %ld %ld %s %s (%ld ms)\n", pwd ? pwd->pw_name : "???", pstatbuf->pt_pid, pstatbuf->pt_ppid,
pstatbuf->pt_name, pstatname(pstatbuf), pstatbuf->pt_time); pstatbuf->pt_name, pstatname(pstatbuf), pstatbuf->pt_time);
} }
@ -41,4 +44,5 @@ int main()
{ {
if (try_pstat(pid, &pst)) { display_process(&pst); } if (try_pstat(pid, &pst)) { display_process(&pst); }
} }
endpwent();
} }

View File

@ -1,9 +1,10 @@
#include <errno.h>
#include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
char* default_argv[] = {"/bin/sh", NULL};
void run_program(char** argv) void run_program(char** argv)
{ {
execv(argv[0], argv); execv(argv[0], argv);
@ -12,26 +13,64 @@ void run_program(char** argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void strip_newline(char* str)
{
size_t len = strlen(str);
if (str[len - 1] == '\n') str[len - 1] = 0;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
if (argc == 1) if (argc == 1)
{ {
fprintf(stderr, "Usage: %s [uid] [command | sh]\n", argv[0]); fprintf(stderr, "Usage: %s [username] [command | login shell]\n", argv[0]);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (setuid(atoi(argv[1])) < 0) if (getuid() != 0)
{
fprintf(stderr, "%s must be setuid root", argv[0]);
return EXIT_FAILURE;
}
struct passwd* user = getpwnam(argv[1]);
if (!user)
{
if (errno) perror("getpwnam");
else
fprintf(stderr, "Unknown user %s\n", argv[1]);
return EXIT_FAILURE;
}
if (getuid() != geteuid()) // we were started from a non-root user
{
printf("Password: ");
char buf[BUFSIZ];
fgets(buf, BUFSIZ, stdin);
strip_newline(buf);
putchar('\n');
if (strcmp(buf, user->pw_passwd) != 0)
{
fprintf(stderr, "Invalid password\n");
return EXIT_FAILURE;
}
}
if (setuid(user->pw_uid) < 0)
{ {
perror("setuid"); perror("setuid");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (setgid(atoi(argv[1])) < 0) if (setgid(user->pw_gid) < 0)
{ {
perror("setgid"); perror("setgid");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
char* default_argv[] = {user->pw_shell, NULL};
if (argc == 2) run_program(default_argv); if (argc == 2) run_program(default_argv);
else else
run_program(argv + 2); run_program(argv + 2);

2
initrd/etc/passwd Normal file
View File

@ -0,0 +1,2 @@
root:secure:0:0:Administrator:/:/bin/sh
selene:moon:1:1:Default User:/:/bin/sh

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <sys/types.h>
#define TAR_MAGIC "ustar" #define TAR_MAGIC "ustar"
#define TAR_BLOCKSIZE 512 #define TAR_BLOCKSIZE 512
@ -33,6 +34,7 @@ namespace InitRD
uint64_t size; uint64_t size;
uint64_t size_in_blocks; uint64_t size_in_blocks;
void* addr; void* addr;
mode_t mode;
}; };
uint64_t get_total_blocks(); uint64_t get_total_blocks();

View File

@ -62,6 +62,13 @@ InitRD::File InitRD::get_file(TarHeader* header)
} }
result.addr = (void*)((uint64_t)header + TAR_BLOCKSIZE); result.addr = (void*)((uint64_t)header + TAR_BLOCKSIZE);
result.size_in_blocks = Utilities::get_blocks_from_size(TAR_BLOCKSIZE, result.size); result.size_in_blocks = Utilities::get_blocks_from_size(TAR_BLOCKSIZE, result.size);
result.mode = 0;
multiplier = 1;
for (int i = 6; i >= 0; i--)
{
result.mode += (mode_t)(multiplier * (header->mode[i] - 48));
multiplier *= 8;
}
return result; return result;
} }
@ -345,7 +352,7 @@ static bool initrd_register_file(InitRD::File& f, uint64_t inode)
node.read_func = initrd_read; node.read_func = initrd_read;
node.length = f.size; node.length = f.size;
node.type = VFS_FILE; node.type = VFS_FILE;
node.mode = 0555; node.mode = f.mode & 07555; // don't allow writing
node.uid = node.gid = 0; node.uid = node.gid = 0;
strncpy(node.name, buffer, sizeof(node.name)); strncpy(node.name, buffer, sizeof(node.name));
strncpy(f.name, buffer, sizeof(f.name)); strncpy(f.name, buffer, sizeof(f.name));

View File

@ -311,7 +311,7 @@ void sys_close(Context* context, int fd)
{ {
int err; int err;
Descriptor* file = Scheduler::current_task()->descriptor_from_fd(fd, err); Descriptor* file = Scheduler::current_task()->descriptor_from_fd(fd, err);
if (!err) if (!file)
{ {
context->rax = -err; context->rax = -err;
return; return;

42
libs/libc/include/pwd.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef _PWD_H
#define _PWD_H
#include <sys/types.h>
/* Structure representing a password file entry. */
struct passwd
{
char* pw_name;
char* pw_passwd;
uid_t pw_uid;
gid_t pw_gid;
char* pw_gecos;
char* pw_dir;
char* pw_shell;
};
#ifdef __cplusplus
extern "C"
{
#endif
/* Returns the next password file entry. */
struct passwd* getpwent(void);
/* Returns the first password file entry with a login name matching name, or NULL if there are none. */
struct passwd* getpwnam(const char* name);
/* Returns the first password file entry with a user ID matching uid, or NULL if there are none. */
struct passwd* getpwuid(uid_t uid);
/* Rewinds to the first password file entry. */
void setpwent(void);
/* Ends password file processing. */
void endpwent(void);
#ifdef __cplusplus
}
#endif
#endif

186
libs/libc/src/pwd.cpp Normal file
View File

@ -0,0 +1,186 @@
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static FILE* pwd_file = nullptr;
static int initialize_pwd(FILE** stream)
{
int pwfd = open("/etc/passwd", O_RDONLY | O_CLOEXEC);
if (pwfd < 0) return 0;
FILE* file = fdopen(pwfd, "r");
if (!file) return 0;
*stream = file;
return 1;
}
static int pwd_unbuffered_fgetc(FILE* stream)
{
char c;
fread(&c, 1, 1, stream);
if (ferror(stream) || feof(stream)) return EOF;
return (int)c;
}
static char* pwd_unbuffered_fgets(char* buf, size_t size, FILE* stream)
{
char* s = buf;
memset(buf, 0, size);
while (size)
{
int c = pwd_unbuffered_fgetc(stream);
if (c == EOF)
{
if (ferror(stream)) return NULL;
if (feof(stream))
{
if (s != buf) return s;
else
return NULL;
};
}
size--;
*buf = (char)c;
buf++;
*buf = 0;
if ((char)c == '\n') return s;
}
return s;
}
static char* pwd_strchrtok(char* s, char delim)
{
static char* saved = nullptr;
if (s) saved = s;
else
s = saved;
if (!saved) return nullptr;
char* loc = strchr(saved, delim);
if (loc)
{
saved = loc + 1;
if (*saved == 0) saved = nullptr;
*loc = 0;
}
else { saved = nullptr; }
return s;
}
static void pwd_strip_newline(char* buf)
{
size_t len = strlen(buf);
if (buf[len - 1] == '\n') buf[len - 1] = 0;
}
static struct passwd* internal_getpwent(FILE* stream)
{
#define PWENT_INVALID \
do { \
errno = EINVAL; \
return NULL; \
} while (0)
static struct passwd result;
static char buf[BUFSIZ];
if (!pwd_unbuffered_fgets(buf, BUFSIZ, stream)) return NULL;
pwd_strip_newline(buf);
result.pw_name = pwd_strchrtok(buf, ':');
if (!result.pw_name) PWENT_INVALID;
result.pw_passwd = pwd_strchrtok(NULL, ':');
if (!result.pw_passwd) PWENT_INVALID;
char* uid_string = pwd_strchrtok(NULL, ':');
if (!uid_string) PWENT_INVALID;
result.pw_uid = atoi(uid_string);
char* gid_string = pwd_strchrtok(NULL, ':');
if (!gid_string) PWENT_INVALID;
result.pw_gid = atoi(gid_string);
result.pw_gecos = pwd_strchrtok(NULL, ':');
if (!result.pw_gecos) PWENT_INVALID;
result.pw_dir = pwd_strchrtok(NULL, ':');
if (!result.pw_dir) PWENT_INVALID;
result.pw_shell = pwd_strchrtok(NULL, ':');
if (!result.pw_shell) PWENT_INVALID;
return &result;
}
extern "C"
{
struct passwd* getpwent()
{
if (!pwd_file)
{
if (!initialize_pwd(&pwd_file)) return NULL;
}
if (feof(pwd_file))
{
endpwent();
return NULL;
}
return internal_getpwent(pwd_file);
}
struct passwd* getpwnam(const char* name)
{
static FILE* pwnam_file = nullptr;
if (!pwnam_file)
{
if (!initialize_pwd(&pwnam_file)) return NULL;
}
else
rewind(pwnam_file);
struct passwd* pwd = internal_getpwent(pwnam_file);
while (pwd)
{
if (strcmp(pwd->pw_name, name) == 0) break;
if (feof(pwnam_file))
{
pwd = nullptr;
break;
}
pwd = internal_getpwent(pwnam_file);
}
return pwd; // if we matched one, pwd contains a pointer to it. else it is NULL
}
struct passwd* getpwuid(uid_t uid)
{
static FILE* pwuid_file = nullptr;
if (!pwuid_file)
{
if (!initialize_pwd(&pwuid_file)) return NULL;
}
else
rewind(pwuid_file);
struct passwd* pwd = internal_getpwent(pwuid_file);
while (pwd)
{
if (pwd->pw_uid == uid) break;
if (feof(pwuid_file))
{
pwd = nullptr;
break;
}
pwd = internal_getpwent(pwuid_file);
}
return pwd; // if we matched one, pwd contains a pointer to it. else it is NULL
}
void setpwent()
{
if (pwd_file) rewind(pwd_file);
}
void endpwent()
{
if (pwd_file)
{
fclose(pwd_file);
pwd_file = nullptr;
}
}
}