# Users and permissions SchOS has accounts, a login prompt, and file permissions that the kernel enforces. Until now every process was root and `uid` was bookkeeping; this is the part that makes it a multi-user system. ## What you meet - **`login` on all twelve terminals, tty1–tty12.** `etc/schos-getty` takes the terminal back from whoever had it and runs `login`, which asks who is there and starts their shell; when the shell exits `schinit` starts the prompt again. Alt+F1…F12 (or Ctrl+Alt+F1…F12) switches between them. (There is no longer a login-free root shell on tty6.) - **One account in the image: `root`**, with an empty password, so `login` lets it in without asking — it is a live image. `passwd` sets one. More users are an `adduser` away; `wheel` is empty, so `su` and `doas` have no one to serve until then. - **`su` and `passwd`** (`cmd/su`, `cmd/passwd`) are setuid root and small programs of their own, not toybox applets: toybox is one binary under every name, and a setuid copy of it can be asked for any applet by naming it, as root. `su` to root takes membership in `wheel`, whatever the password. - **`doas`** (Alpine's, setuid) with `permit nopass :wheel` in `/etc/doas.conf`. ## What the kernel enforces | | | |---|---| | open, create, unlink, rename, link | the usual owner/group/other bits, `w`+`x` on the directory, and the sticky bit (`/tmp`) | | path walk | `x` on every directory searched | | `exec` | `x` on the file; set-user-id and set-group-id make the new image run as its owner or group, and the saved ids follow | | `chmod`, `chown`, `utimensat` | owner or root; a non-root `chown` drops the set-id bits | | `access` / `faccessat` | by the *real* ids (`AT_EACCESS` for the effective ones) | | `kill`, `tkill`, `tgkill` | root, or a target whose real or saved uid is one of yours. The kernel's own signals (`SIGPIPE`, the terminal's) are nobody's to refuse | | `mount`, `umount`, `chroot`, `reboot`, `shutdown`, `setgroups`, `mknod` of a device | root | | `setuid` family | root may set anything; anyone else only to an id they already hold | Root reads and writes everything and executes a file only if some execute bit is set. A process's supplementary groups (`setgroups`) are consulted along with its effective group. Ownership is stored by SchFS (it always had the fields); FAT volumes belong to everyone, since they cannot say otherwise, and `/proc` and `/sys` are root's. `inode_permission()` in `kernel/fs/fs.c` is the one check; the rest of this is call sites. ## Devices `/dev` is built by the kernel and each node has the owner, group and mode in the `devnodes[]` table of `kernel/fs/devfs.c`: `null` and `zero` are 0666, terminals `root:tty 0660`, `fb0` `root:video`, input `root:input`, raw disks `root:disk`, `pci`, `dbg` and `netdev` root's alone. `chmod` and `chown` on a node are kept (login claims its terminal this way, and udev sets modes) in an override table applied whenever the inode is loaded. A new pseudo-terminal's slave belongs to whoever opened `ptmx`. udev would set a node it has no rule for to 0600, which made `/dev/null` root-only, so `etc/udev-schos.rules` (installed as `90-schos.rules`) names the kernel's devices with the answers the kernel gave. ## The image Everything in the image is owned by root: the build host's user means nothing inside it. `mkschfs --owners FILE` takes the exceptions, one `path uid gid [mode]` per line (`tools/posix/mkaroot.sh` writes it: the modes of `/tmp`, `/var/tmp` and `/root`). The setuid bits are set on `su`, `passwd` and `doas` in the root tree directly, because `apk` run as an ordinary user may have dropped them. ## Not done - **No PAM and no `/etc/securetty`.** `login` is busybox's and checks `/etc/shadow` itself. - **No capabilities.** Root is `euid == 0`, all of it. - **No per-user `/run`, no logind.** X as a non-root user works (`startx` as `schos`, under QEMU: Window Maker up) by group permission alone — video, input and tty — and `/etc/X11/Xwrapper.config` lets anyone start it, because the wrapper's "console users" test looks for a Linux VT on a standard descriptor that xinit's server child does not keep. - **`/proc` and `/sys` hide nothing from other users.** - **`mprotect` is still not enforced** ([kernel.md](kernel.md)).