(Done 1.18a) Make -a -q much faster (potentially) by exiting at
first mismatch.

(Done 1.18) Avoid TOCTOU by checkng config file permissions with
file handle after open, use $fh format opens instead of bareword
filehandles throughout, ignore links and character files for any
OS, not just Linux, be more restrictive on unveiling when making
changes, and switch to block form greps throughout. All but last
suggested by Gemini security assessment. Fix bug in block grep
operator precedence and allow -g <group>:schg -a -q to exit with
0 if there are no matching schg groups (just uchg; still fails
if the group doesn't exist at all) -- to be used by install.pl.

(Done 1.17) Added = prefix (lock/unlock this directory and its
contents but not subdirectories), example in Linux sample config.
Fixed taint bug on files with options, added warnings for options
used on non-directories that aren't meaningful and are ignored.
Modify unveil permissions for -a (audit).

(Done 1.16): Added -o (operational scope) to limit -a (audit) to
what can actually change in the given circumstance (based on system
securelevel). Is effective no-op if securelevel=0; ignores schg
groups if using uchg default and securelevel>0. Can be overridden
if schg groups are explicitly given with -g on the command line
(e.g., either -g schg or -g <groupname>:schg). Also updated all
sample configs to add "presecure" group for BSD and improve group
structure and consistency across platforms.

(Done 1.15b): Remove uchg-only limitation for macOS.

(Done 1.15a): Warn if config file is world-readable.

(Done 1.15): Fix bugs in -a handling when there are discrepancies with other
flags. sysunlock -a shouldn't care about non-locking flags, and syslock -a
should care about conflicting locking flags. (Handled for both BSD and Linux
cases.)

Done (1.14): Added -q (quiet) to use with -a to suppress individual reports and just
return 0 if all is as expected and 1 otherwise. This will be used by install.pl
to see if installation can proceed even if schg groups are used and system
securelevel is > 0 (if they are already unlocked).

Done (1.13):
* Allow non-root use on BSD, enforcing uchg/uappnd only and limiting
  options that don't make sense for non-root.
* Support sappnd.  No call for the arch flag (a no-op) or nodump,
  which aren't about locking. (Ditto for macOS's opaque and hidden.)

Fixed (1.12a):
* Check effective UID instead of $ENV{'USER'} on Linux, as the latter is not set in cron environment
  where the new functionality intended for logs is likely to be used.

Done (1.12):

* Added BSD user append-only flag and Linux +a flag support. This allows
  groups to be defined that use uappnd/nouappnd and +a/-a, which will only
  be modified when the group they are in is specified with -g.  If a
  given group is ONLY for append-only flags, then -g <group> will turn
  it on with syslock and off with syslock. If the given group is also
  defined for immutable flags, then -g <group>:uappnd for BSD or
  -g <group>:+a for Linux must be specified explicitly. This facilitates
  setting log files to append only and unsetting them as needed prior
  to log rotation (and resetting after log rotation is completed).
* Added glob expansion in filenames only (not directory names, no globs
  alone, only as part of file paths).

Done:

* Additional cleanup: removed glob, backticks, added taint
checking, better path validation, unveil on OpenBSD to limit
executables, check config file permissions.

Done:

* Change behavior as follows:
If immutable-flag is schg and system securelevel is > 0, sysunlock should warn but
proceed to unlock all uchg group files. Still error if individual groups are specified
that have no uchg groups.  syslock should warn that -f is required for schg groups but
proceed to lock all uchg groups (with -v).  This mirrors immutable-flag: uchg behavior:
If immutable flag is uchg and system securelevel is > 0, sysunlock warns if there are
any schg groups with -v. syslock warns if there are schg groups with -v, and requires -f
to lock them.

* Added ! for /usr/bin (needed for relinking of ssh-agent with OpenBSD 7.6)

* Permit sysunlock to unlock only the uchg portions of other groups, but
not necessarily all uchg groups, even when not in single-user mode. Allow
syslock to operate in the same way (only locking the uchg portions of the
configs group).  Method: -g <group>:uchg

* Allow the reverse of the above: schg groups (group:schg) when the default
is uchg.  sysunlock with no args when uchg is the default doesn't try to
unlock anything in the schg group if not in single-user mode.

* Added option -a (audit) that shows what should be locked but isn't
(with syslock) or what should be unlocked but isn't (with sysunlock).
Can be used with -g to check a subset of the config. (Also already have
-d debug option that shows what would be done without doing it, but that
doesn't check current state.)

* Made Linux-oriented config (linux.syslock.conf).

* Made macOS-oriented config (macos.syslock.conf).

Notes/Pointers:

* On macOS with Apple silicon, there is no single-user mode and "schg"
has become equivalent to "uchg" (no single-user requirement to unset
the flag).

* Would be nice to find a place to run sysunlock prior to library
reordering (even early daemons are too late); can't really do without
mods to /etc/rc. (Workaround is to use sysunlock -s while in single
user mode, i.e., after a shutdown, and then put syslock -s into
rc.securelevel after a long enough sleep for library and kernel
reordering to occur. This is now even more effective on OpenBSD with
-w (wait) option; reorder_libs starts before rc.securelevel execution
and kernel reordering starts a little bit after.) Best way to do this
now is -swf.

* While -w checks for lib reordering, that occurs and completes before
rc.securelevel execution, which is where it's recommended to be used, so
it's not really a useful check.  It might be better for -w to check every
five seconds instead of every second; 10 seconds is sufficient sleep time
for kernel reordering to get started. (Recently found case where 10 seconds
was insufficient and syslock ran before kernel reordering started, thus
causing kernel reordering to fail; 45 seconds was more than sufficient.)

* Hard links between directories with different settings (i.e., some uchg,
some schg) can lead to both flags being applied, which can cause issues.
E.g., /usr/libexec/makewhatis = /usr/sbin/makewhatis, so you don't want
/usr/libexec and /usr/sbin to have different flag settings.

* Probably not worth adding unveil, since it would require unveiling / with
r at a minimum, then unveiling all dirs represented in the config file. If
the config file is ordered with higher, less-specific dirs before deeper ones,
could skip unveiling more-specific dirs where the substring at the front
is already unveiled. But there are other tools which use syslock/sysunlock
and which already use unveil which could potentially cause problems (well,
maybe not, since exec/system calls have new pledge and unveil settings
and don't carry them over from the parent).

To Do:

Allow using globs in config file (e.g., /etc/hostname.*)?  Currently
generates warning and will refuse to lock/unlock due to failing
existence test. (This creates a potential root immutable file bypass
without console access on reboot via interfaces where there is no
hostname.<int> file.) (Currently disallow * and other shell metachars
in file paths.)

Need a shell script (/bin/sh) which goes into /etc/rc.d and will run
sysunlock with specific groups if PGP-signed
appropriately. (unattached signatures?)  (Note: PGP::Sign doesn't
validate the specific key ID... but do this already with some signify
tools.) [What was the point of this again? For installing updates? Not
currently seeing good reason for this.] (This has been implemented in
my distribute/install scripts; distribute config file specifies
whether specific syslock groups need to be unlocked and signs the list
with a signify key, install reads the list, checks the sigs, and does
the unlocking.)
