FreeBSD User and Permission Management Guide
FreeBSD has a layered permission model that goes far beyond basic Unix file permissions. Users, groups, ACLs, login classes, the MAC framework, and file flags give you fine-grained control over who can do what on the system.
This guide covers the full stack, from basic user administration through advanced mandatory access control. Every command runs on FreeBSD 14.
User Management Fundamentals
Creating Users
The pw command is FreeBSD's user administration tool. It is more scriptable than adduser:
shpw useradd -n jsmith -c "John Smith" -m -s /bin/sh -G wheel,staff
Flags:
-n-- username-c-- comment (full name)-m-- create home directory-s-- login shell-G-- supplementary groups
Set the password:
shpasswd jsmith
For batch user creation:
shcat > /tmp/users.txt << 'EOF' jsmith:John Smith:staff,wheel mjones:Mary Jones:staff,finance bwilson:Bob Wilson:staff EOF while IFS=: read -r user fullname groups; do pw useradd -n "$user" -c "$fullname" -m -s /bin/sh -G "$groups" echo "changeme" | pw usermod -n "$user" -h 0 done < /tmp/users.txt
Modifying Users
Add a user to additional groups:
shpw groupmod finance -m jsmith
Change a user's shell:
shpw usermod -n jsmith -s /usr/local/bin/bash
Lock an account (disable login without deleting):
shpw lock jsmith
Unlock:
shpw unlock jsmith
Deleting Users
Remove a user and their home directory:
shpw userdel -n jsmith -r
Without -r, the home directory is preserved. Good practice: lock the account first, verify no running processes, then delete.
shpw lock jsmith ps aux | grep jsmith pw userdel -n jsmith -r
Viewing User Information
shid jsmith finger jsmith pw usershow jsmith
List all users:
shpw usershow -a
Group Management
Creating Groups
shpw groupadd -n finance pw groupadd -n engineering pw groupadd -n management
Managing Group Membership
Add users to a group:
shpw groupmod finance -m jsmith,mjones
Remove a user from a group:
shpw groupmod finance -d bwilson
View group membership:
shpw groupshow finance getent group finance
The wheel Group
The wheel group controls su access. Only users in wheel can su to root:
shpw groupmod wheel -m jsmith
This is enforced by PAM in /etc/pam.d/su:
shauth requisite pam_group.so no_warn group=wheel root_only
Standard Unix Permissions
Permission Basics
Every file has an owner, a group, and three permission sets: owner, group, others. Each set has read (r=4), write (w=2), and execute (x=1).
shls -la /data/shared/
Set permissions:
shchmod 750 /data/finance chown root:finance /data/finance
This gives the owner (root) full access, the finance group read and execute, and others nothing.
The Setgid Bit
For shared directories, the setgid bit ensures new files inherit the directory's group:
shchmod 2770 /data/finance
Without setgid, new files get the creator's primary group. With setgid, they get the directory's group -- critical for shared workspaces.
Umask
The umask controls default permissions for new files. Set it system-wide in /etc/login.conf or per-user in shell profile:
sh# In /etc/login.conf under the default class: # :umask=022: # Per-user in ~/.profile: umask 027
A umask of 027 means new files get 640 (rw-r-----) and directories get 750 (rwxr-x---).
POSIX ACLs
Standard Unix permissions are limited to one owner, one group, and everyone else. ACLs add fine-grained access for multiple users and groups.
Enable ACLs
ACLs are supported on UFS and ZFS. On UFS, enable them per-mount:
shtunefs -a enable /dev/ada0p2 mount -o acls /dev/ada0p2 /data
On ZFS, ACLs are always available. For NFSv4-style ACLs:
shzfs set acltype=nfsv4 zroot/data
Setting ACLs
Grant a specific user read access to a directory:
shsetfacl -m u:mjones:rx /data/reports
Grant a group write access:
shsetfacl -m g:finance:rwx /data/budget
Set a default ACL so new files inherit permissions:
shsetfacl -d -m g:finance:rwx /data/budget
Viewing ACLs
shgetfacl /data/budget
Output:
sh# file: /data/budget # owner: root # group: finance user::rwx group::rwx group:finance:rwx mask::rwx other::--- default:user::rwx default:group::rwx default:group:finance:rwx default:mask::rwx default:other::---
Removing ACLs
Remove a specific entry:
shsetfacl -x u:mjones /data/reports
Remove all ACLs:
shsetfacl -b /data/reports
NFSv4 ACLs on ZFS
ZFS supports the richer NFSv4 ACL model with inheritance, deny entries, and more granular permissions:
shsetfacl -m u:mjones:rwxpDdaARWcCos:fd:allow /data/project
This is verbose but powerful. The flags control individual permissions like delete, read attributes, write ACL, and more.
Login Classes
Login classes define resource limits and environment settings for groups of users. They are configured in /etc/login.conf.
Viewing the Default Class
shcat /etc/login.conf | head -40
Creating a Custom Login Class
Add a restricted class for external contractors:
shcat >> /etc/login.conf << 'EOF' contractor:\ :maxproc=50:\ :openfiles=256:\ :stacksize=8M:\ :memoryuse=512M:\ :cputime=4h:\ :umask=077:\ :tc=default: EOF
Rebuild the login database:
shcap_mkdb /etc/login.conf
Assign the class to a user:
shpw usermod -n contractor1 -L contractor
Resource Limits via Login Classes
Common limits:
| Limit | Description | Example |
|-------|-------------|---------|
| maxproc | Max processes | 100 |
| openfiles | Max open files | 512 |
| memoryuse | Max memory per process | 1G |
| cputime | Max CPU time per process | 8h |
| filesize | Max file size | 2G |
| coredumpsize | Max core dump size | 0 (disable) |
Create a developer class with generous limits:
shcat >> /etc/login.conf << 'EOF' developer:\ :maxproc=1024:\ :openfiles=8192:\ :stacksize=64M:\ :memoryuse=4G:\ :cputime=unlimited:\ :umask=022:\ :tc=default: EOF cap_mkdb /etc/login.conf
Capabilities and Privilege Escalation
sudo Configuration
Install and configure sudo for controlled privilege escalation:
shpkg install sudo visudo
Common configurations:
sh# Allow wheel group full sudo access %wheel ALL=(ALL:ALL) ALL # Allow deploy user to restart services without password deploy ALL=(root) NOPASSWD: /usr/sbin/service nginx restart, /usr/sbin/service php-fpm restart # Allow backup user to run ZFS commands backup ALL=(root) NOPASSWD: /sbin/zfs snapshot *, /sbin/zfs send *, /sbin/zfs list *
doas: A Simpler Alternative
shpkg install doas
Configure /usr/local/etc/doas.conf:
shcat > /usr/local/etc/doas.conf << 'EOF' permit persist :wheel permit nopass deploy as root cmd /usr/sbin/service args nginx restart permit nopass deploy as root cmd /usr/sbin/service args php-fpm restart deny :contractor EOF
The persist keyword remembers authentication for 5 minutes, like sudo.
MAC Framework (Mandatory Access Control)
FreeBSD's MAC framework enforces security policies that even root cannot override (when configured properly).
MAC Modules
FreeBSD includes several MAC modules:
| Module | Purpose |
|--------|---------|
| mac_bsdextended | File system firewall rules |
| mac_portacl | Allow non-root port binding |
| mac_seeotheruids | Hide other users' processes |
| mac_partition | Process partition isolation |
mac_seeotheruids: Hide Processes
Prevent users from seeing other users' processes:
shkldload mac_seeotheruids echo 'mac_seeotheruids_load="YES"' >> /boot/loader.conf sysctl security.mac.seeotheruids.enabled=1
Now ps aux run by a normal user only shows their own processes. Root still sees everything.
mac_portacl: Non-Root Port Binding
Allow a specific user to bind to privileged ports without running as root:
shkldload mac_portacl echo 'mac_portacl_load="YES"' >> /boot/loader.conf
Allow user www (UID 80) to bind to ports 80 and 443:
shsysctl security.mac.portacl.rules="uid:80:tcp:80,uid:80:tcp:443" echo 'security.mac.portacl.rules=uid:80:tcp:80,uid:80:tcp:443' >> /etc/sysctl.conf
mac_bsdextended: Filesystem Firewall
Create rules that restrict file access at the kernel level:
shkldload mac_bsdextended echo 'mac_bsdextended_load="YES"' >> /boot/loader.conf
Prevent the contractor group from accessing /data/finance:
shugidfw add subject gid contractor object path /data/finance mode n
List active rules:
shugidfw list
These rules are enforced by the kernel and cannot be bypassed even by file permission changes.
File Flags: chflags
FreeBSD file flags provide protection beyond standard permissions. They work at the filesystem level and can prevent modification even by root.
Common Flags
| Flag | Meaning |
|------|---------|
| schg | System immutable (root cannot modify in securelevel > 0) |
| uchg | User immutable (owner cannot modify) |
| sappnd | System append-only |
| uappnd | User append-only |
| sunlnk | System undeletable |
| uunlnk | User undeletable |
Making Files Immutable
Protect critical configuration files:
shchflags schg /etc/rc.conf chflags schg /boot/loader.conf chflags schg /etc/pf.conf
Now even root cannot modify these files:
shecho "test" >> /etc/rc.conf # rc.conf: Operation not permitted
To modify them, remove the flag first:
shchflags noschg /etc/rc.conf
Append-Only Logs
Make log files append-only so they cannot be truncated or overwritten:
shchflags sappnd /var/log/auth.log chflags sappnd /var/log/security
New log entries can be written, but existing entries cannot be modified or deleted.
Securelevel
Combine file flags with securelevel for defense-in-depth. At securelevel 1 or higher, system flags (schg, sappnd) cannot be removed even by root:
shsysctl kern.securelevel=1
Set in /etc/rc.conf to enforce at boot:
shsysrc kern_securelevel_enable="YES" sysrc kern_securelevel="1"
At securelevel 1: system flags are locked, kernel modules cannot be loaded/unloaded, and /dev/mem is read-only. This is powerful for production servers where the configuration should not change.
Warning: To modify system-flagged files after setting securelevel, you must reboot into single-user mode.
Auditing Permission Changes
Track who changes what:
shsysrc auditd_enable="YES" service auditd start
Configure audit policy in /etc/security/audit_control:
shcat > /etc/security/audit_control << 'EOF' dir:/var/audit flags:lo,aa,fc,fd,fw,fm minfree:5 naflags:lo,aa policy:cnt,argv filesz:2M expire-after:30d EOF
Review audit logs:
shpraudit /var/audit/current | tail -20
The flags fc,fd,fw,fm audit file creation, deletion, write, and attribute modification respectively.
FAQ
Q: What is the difference between pw and adduser?
A: pw is the low-level tool for scripting. adduser is an interactive wrapper around pw. Use pw in scripts and automation, adduser for one-off interactive user creation.
Q: Can I use LDAP or Active Directory for user authentication?
A: Yes. Install nss_ldap and pam_ldap for LDAP integration, or use sssd for Active Directory. Configure /etc/nsswitch.conf to add ldap as a passwd/group source.
Q: How do ACLs interact with standard Unix permissions?
A: The ACL mask limits the effective permissions of group and named user/group entries. Standard permissions show the ACL mask as the group permission. If the mask is r-x, no ACL entry can grant write access.
Q: Should I use sudo or doas?
A: doas is simpler and has a smaller attack surface. Use it for straightforward "allow user X to run command Y as root" policies. Use sudo when you need logging, command aliases, or complex per-host rules.
Q: How do I prevent users from running cron jobs?
A: Create /var/cron/deny and add one username per line. Or create /var/cron/allow to whitelist only specific users.
Q: What securelevel should I use in production?
A: Securelevel 1 for most production servers. It prevents kernel module loading and protects system-flagged files. Securelevel 2 adds protection against disk device writes. Securelevel 3 adds packet filter rule protection.
Q: How do I audit all file access by a specific user?
A: Add the user to the audit system. In /etc/security/audit_user, add: username:fc,fd,fr,fw,fm:no. This audits all file operations for that user.
Q: Can I limit disk space per user?
A: Yes. On UFS, use traditional quotas (edquota -u username). On ZFS, create per-user datasets with quotas: zfs create -o quota=10G zroot/home/jsmith.