Control PAM Access by Time with pam_time
Locking an account out of login or su to certain hours is exactly what pam_time does, working from one rule file instead of a bespoke script. The examples use Linux-PAM 1.5.3 from Debian package libpam-modules:amd64 version 1.5.3-5ubuntu5.7. Allow about twenty minutes, plus a maintenance window if you are applying this to a real login service.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need root access to edit /etc/security/time.conf and the relevant file under /etc/pam.d. The module reads that configuration during an account check; it does not authenticate users. A malformed rule can deny access, so keep an existing root shell or console session open while testing.
1. Check the installed module and current configuration
These are ordinary, read-only checks:
$ dpkg-query -W -f='${Package} ${Version}\n' libpam-modules:amd64
libpam-modules:amd64 1.5.3-5ubuntu5.7
$ test -r /usr/lib/x86_64-linux-gnu/security/pam_time.so && echo 'pam_time module is present'
pam_time module is present
$ sudo sed -n '1,160p' /etc/security/time.conf
The default configuration file is /etc/security/time.conf. On this machine it contains comments and no active rules; preserve any you find. PAM configuration is service-specific, so identify the service you actually want to restrict first, such as login, su, or an application with its own file.
Checkpoint
Record the exact PAM service name and keep the current contents of both files available for recovery.
2. Understand the four fields
Each active line in time.conf has this shape:
services;ttys;users;times
The service, terminal and user fields are logic lists: | for OR, & for AND, and a leading ! for NOT. The wildcard * may appear only once in each of those fields. The time field uses two-letter day codes and a 24-hour range, for example MoFr0900-1700. Accepted day codes are Mo, Tu, We, Th, Fr, Sa, Su, Wk, Wd and Al.
- All three of the first fields must match before a rule is active, so a rule can be narrower than its individual tokens suggest.
- A finish time earlier than the start time runs across midnight.
- Repeated day codes cancel each other out, so never write a day twice when you mean to include it.
3. Build a harmless test rule in a separate file
Do not edit the live file first. Create a temporary configuration owned by root, using a service and account that exist on your host. This example applies to the login service, any terminal beginning tty, and one placeholder account, denying it outside weekday working hours:
$ umask 077
$ cat > /tmp/pam-time-test.conf <<'EOF'
login;tty*;TEST_USER;!Wk0900-1700
EOF
$ sudo sed -n '1,20p' /tmp/pam-time-test.conf
login;tty*;TEST_USER;!Wk0900-1700
Replace TEST_USER with a real non-privileged test account before using the file. The leading ! means the rule matches anything except weekdays from 09:00 through 17:00; because pam_time denies access when a matching rule says the time is disallowed, this line denies the selected account outside that window. It does not create the account, change its password, or terminate an existing session.
Checkpoint
Check the four semicolon-separated fields and the account spelling. A missing field, a wrong service name or an unexpected terminal name will make a test misleading.
4. Install the rule only after backing up the live file
This is a security-sensitive change that can affect logins. Make a dated backup first, then append the reviewed rule with elevated privileges. Do not overwrite the file with an unreviewed heredoc:
$ sudo cp --preserve=mode,ownership,timestamps /etc/security/time.conf /etc/security/time.conf.bak
$ sudo sh -c 'cat /tmp/pam-time-test.conf >> /etc/security/time.conf'
$ sudo tail -n 5 /etc/security/time.conf
There is no separate daemon to reload here. The module reads the file whenever the PAM account check runs. Existing sessions are not ended automatically; the manual explicitly warns that no daemon enforces the end of a session, so test a new account check rather than an already-open one.
5. Add pam_time to the service's account stack
Add one account line to the target service file, after backing it up. The module provides only the account type:
$ sudo cp --preserve=mode,ownership,timestamps /etc/pam.d/login /etc/pam.d/login.bak
$ sudoedit /etc/pam.d/login
Add this line in the account section:
account required pam_time.so
For a different service, edit that service's file instead of copying this line into every PAM stack. If your deployment uses an included account stack, understand the include order before adding a second check. The required control flag records a failure while letting the rest of the stack run; the final account result still denies access when this module returns PAM_PERM_DENIED.
To use another configuration path, pass the documented module option on the same line:
account required pam_time.so conffile=/etc/security/time.conf
That option overrides the default file. Keep the alternate file root-owned and readable by the PAM process. Do not add debug routinely, since it writes diagnostic information to syslog; noaudit suppresses audit reporting for denied logins where audit support is available, which is a logging decision rather than a way to permit access.
6. Verify from a separate session and recover if needed
Open a second console or SSH session before testing. Use the test account and a service that actually reaches the edited PAM stack. If the current time is outside the allowed window, an account check should fail; if inside, it should pass. The exact prompt or error text belongs to the calling service, so check the command's exit status and the service log rather than expecting one universal message.
$ su - TEST_USER -c 'id -un'
$ printf 'status: %s\n' "$?"
status: 0
That successful result only means something when the current time, terminal and service actually match the rule.
Recovery
If the check is denied unexpectedly, or you lose the test path, restore both backups immediately:
$ sudo cp --preserve=mode,ownership,timestamps /etc/security/time.conf.bak /etc/security/time.conf
$ sudo cp --preserve=mode,ownership,timestamps /etc/pam.d/login.bak /etc/pam.d/login
$ sudo tail -n 5 /etc/security/time.conf
$ sudo tail -n 12 /etc/pam.d/login
Once the rule is confirmed, replace TEST_USER with the intended account or group expression and retest at both an allowed and a denied time. Keep the backup until the next maintenance cycle, and remove the temporary file only after the live configuration is verified:
$ rm -- /tmp/pam-time-test.conf
Done means
- The installed module and Linux-PAM package version were checked.
- The rule has four correct fields and matches the intended service, terminal and user.
- The live files were backed up before the PAM change.
- A new account check succeeded during an allowed period and was denied during a disallowed period.
- You know existing sessions are not ended by pam_time.
- The rollback copies remain available until the change is trusted.