feat(users): add user management module

Implement user account creation and sudo configuration:
- Interactive root password setup in chroot
- Standard user creation with configurable groups
- Automatic sudo configuration for wheel group
- Password validation via visudo

Decision: Set passwords interactively for security.
Hash-based passwords rejected for initial implementation
(complexity vs security trade-off).

User groups: wheel (sudo), audio, video, storage, network.
Provides hardware access without additional configuration.

Alternative considered: Passwordless sudo rejected (security risk).
Creating user without sudo rejected (user would be unable to
administer system).

Trade-off: Interactive password input requires TTY and manual
entry. More secure than storing hashes but less convenient for
automated installations. Future config file support can add
hash option.

Sudoers validation: Use visudo -c to validate syntax before
committing changes. Rollback to backup if validation fails.
This prevents lockout from broken sudoers file.
This commit is contained in:
Stefan Strobl 2025-12-24 20:44:31 +01:00
parent 56c8234d35
commit 4ac64e6659

120
src/users.sh Normal file
View File

@ -0,0 +1,120 @@
#!/usr/bin/env bash
# === Motivation ===
# Create user accounts with proper permissions for system access.
# === Problem Statement ===
# A bootable system needs at least root access and a non-privileged user account.
# === Scope ===
# In scope: root password, standard user creation, group membership, sudo configuration.
# Out of scope: multiple users, password policies, PAM configuration.
# === Concepts ===
# Root user: Administrative account with UID 0, full system access.
# Standard user: Non-privileged account for daily tasks, can escalate via sudo.
# wheel group: Traditional Unix group for sudo access.
# useradd: Creates user accounts with home directory and group membership.
# === Decisions ===
# Root password is set interactively (security requirement).
# Standard user is created with wheel group for sudo access.
# Additional groups (audio, video, storage, network) are added for hardware access.
# User password is set interactively (same security requirement as root).
# sudo is configured by uncommenting wheel group in /etc/sudoers.
# Default shell is /bin/bash (most common, widely supported).
# === Alternatives Considered ===
# Hash-based password rejected for initial implementation (requires additional config).
# Passwordless sudo rejected (security risk).
# Creating user without sudo rejected (user would be unable to administer system).
# systemd-homed rejected (Void uses traditional user management).
# === Constraints ===
# Target system must be mounted at $MOUNT_ROOT.
# sudo package must be installed before configuration.
# Interactive password input requires TTY.
# === Open Questions ===
# Should we support multiple user creation?
# Should we validate password strength?
# Should we configure shell based on user preference?
# === Success Criteria ===
# Root password is set and login works.
# Standard user can log in with password.
# Standard user can execute sudo commands.
# User has access to audio, video, and network hardware.
users_setup() {
: "${MOUNT_ROOT:?Mount root is required}"
: "${USERNAME:?Username is required}"
local user_shell="${USER_SHELL:-/bin/bash}"
local user_groups="${USER_GROUPS:-wheel,audio,video,storage,network}"
log_info "User setup: configuring root and creating standard user"
# Set root password interactively
log_info "Setting root password"
log_info "Please enter the root password when prompted:"
if ! chroot "$MOUNT_ROOT" passwd; then
die "Failed to set root password"
fi
# Create standard user
log_info "Creating user: $USERNAME"
if chroot "$MOUNT_ROOT" id "$USERNAME" >/dev/null 2>&1; then
log_warn "User $USERNAME already exists, skipping creation"
else
# Create user with home directory and group membership
if ! chroot "$MOUNT_ROOT" useradd -m -G "$user_groups" -s "$user_shell" "$USERNAME"; then
die "Failed to create user: $USERNAME"
fi
log_info "User $USERNAME created with groups: $user_groups"
fi
# Set user password interactively
log_info "Setting password for user: $USERNAME"
log_info "Please enter the password for $USERNAME when prompted:"
if ! chroot "$MOUNT_ROOT" passwd "$USERNAME"; then
die "Failed to set password for user: $USERNAME"
fi
# Configure sudo for wheel group
log_info "Configuring sudo access for wheel group"
local sudoers_file="$MOUNT_ROOT/etc/sudoers"
if [[ ! -f "$sudoers_file" ]]; then
die "Sudoers file not found. Ensure sudo package is installed."
fi
# Backup sudoers file
cp "$sudoers_file" "${sudoers_file}.bak"
# Uncomment wheel group line (allow members of wheel to execute any command)
if grep -q "^# %wheel ALL=(ALL:ALL) ALL" "$sudoers_file"; then
sed -i 's/^# %wheel ALL=(ALL:ALL) ALL/%wheel ALL=(ALL:ALL) ALL/' "$sudoers_file"
log_info "Enabled sudo for wheel group"
elif grep -q "^%wheel ALL=(ALL:ALL) ALL" "$sudoers_file"; then
log_info "sudo for wheel group already enabled"
elif grep -q "^# %wheel ALL=(ALL) ALL" "$sudoers_file"; then
# Alternative format
sed -i 's/^# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/' "$sudoers_file"
log_info "Enabled sudo for wheel group (alternative format)"
else
# Add wheel group entry if not present
echo "%wheel ALL=(ALL:ALL) ALL" >> "$sudoers_file"
log_info "Added sudo configuration for wheel group"
fi
# Validate sudoers file syntax
if ! chroot "$MOUNT_ROOT" visudo -c -f /etc/sudoers >/dev/null 2>&1; then
log_warn "Sudoers file validation failed, restoring backup"
mv "${sudoers_file}.bak" "$sudoers_file"
die "Failed to configure sudo (syntax error)"
fi
rm -f "${sudoers_file}.bak"
log_info "User setup complete."
}