op
rules is not
hard work. Sending only the support scripts your rule-base
needs is a little more work, but it is worth the effort.
op
scripts with great care.
But giving non-administrators access to
sudo
is too much -- you know they are going to
destroy something.
So you've tried to limit the damage with harder and
more detailed limits with sudo
and eventually had to
give up.
Either you've ended up doing more work yourself, or
you've given pretty much unlimited access to people that really don't need it.
If that fits you, then you are ready to move up to op
.
But to move up you need to learn how to get a better policy, not just
a sharper tool.
In this document I'm going to
present the implementation details of getting the correct configuration for
each rule to every host for every login and service you deploy.
See the op manual page, and
the If you can't trust the environment from Fixing each path to be explicit is much error-prone.
This is for Only See the example above.
The default action is a non-zero The shell is not good at finding these,
even under These just make the script larger. Someone might think that they are
required and leave them forever. If this script is going to be run
escalated it should be a hygienic as possible.
Usage messages are optional, but if you add Angle brackets in usages cause people to people type them. Use
brackets (less harm if they type one) which are standard, or no
grouping but white-space.
Add -h only if local site policy requires it.
So we don't radiate information to the black hats.
Add -V if local site policy requires it, even if the escalation
rule doesn't allow it. The superuser may still be able to check
versions with an escalated command.
Nothing screams "I'm not sure of what I'm doing!" quite as loud as
commented code in an escalated script.
Nothing radiates more information to the Black Hat guys
than a
Another novice mistake you must avoid is sending error messages
to
While this fixes all the mistakes above:
We use
The other target available here is the non-standard
The
Previously, the
Back to the directory above.
op
itself. I'm not going to cover too much of
that material (again) here. Later in this document I'm going to
spend some time showing how to do this under the master source
structure I use for all such tasks, if you've never heard of
msrc
or xapply
before
you're going to have to
Coding style and best practices
All execution scripts should be coded with great care.
These will be tested for every possible weakness. Here is a
check list of items I always go through for every script
I code or review:
If you follow the plan above, then your escalation scripts should be
must safer, easier to review, and have enough feed-back available to
maintain. These are the same rules one might apply to any application
provided as a service via PATH
from op
op
it
is mostly over before it starts. This means using the
env
lever to find your script's interpreter,
this means not hard-coding absolute paths to common tools.
Id
and/or
Source
in each script (or the like for you local
site's revision control).
hostlint
's
versions.hlc
module they automates version tracking.
It also allows a sane -V
output.
#!/usr/bin/env ksh
# This script is just an example.
#
$Id:
revision information...
#
$Source:
path information...
exit
0 when it all went well.
Masking failure dramatically limits the usefulness of automation.
exec
to pass exit status back in dead-end case statements.
exec
is really cheap, and is what you want anyway.
case _`uname -s` in
_FreeBSD)
exec kill -HUP $PIDS
;;
_Linux|SunOS)
exec kill -SIGHUP $PIDS
;;
...
*)
echo "$0: unknown platform, please update this script"
exit 70 # SOFTWARE
;;
esac
uname
matches.
MAP
'd file under
msrc
to forbid installation on an unsupported platform.
m4
m4exit
:
'ifelse(HOSTTYPE,FREEBSD,`exec kill -HUP $PIDS',
HOSTTYPE,LINUX,`exec kill -SIGHUP $PIDS',
HOSTTYPE,SUN5,`exec kill -SIGHUP $PIDS',
`errprint(__file__`: unsupported platform')m4exit(70)')`
'dnl
;;
) in all
case
statements.
-n
.
&&
to fail-fast when multiple commands must all complete to secure an escalation
cp $SOURCE/file1 $DEST/file1 &&
cp $SOURCE/file2 $DEST/file2 &&
cp $SOURCE/file3 $DEST/file3
set -e
set +e
only as needed.
set -e
cp $SOURCE/file1 $DEST/file1
cp $SOURCE/file2 $DEST/file2
cp $SOURCE/file3 $DEST/file3
set +e
sysexits.h
codes
The \t's above represent literal tabs.
sed -n -e 's/^#define[ \t][ \t]*//p' /usr/include/sysexits.h |
grep '[ \t][0-9]'
One might even turn that into a run-time spell to fetch the local
system exit codes in a script:
# Read sysexits.h, if we can, or guess based on common values
eval `sed -ne 'y,\t, ,' -e \
's,^# *define *\([_A-Z][_A-Z]*\) *\([0-9][0-9]*\).*,\1=\2,p' \
/usr/include/sysexits.h 2>/dev/null | grep . ||
echo 'EX_OK=0 EX__BASE=64 EX_USAGE=64 EX_DATAERR=65 EX_NOINPUT=66
EX_NOUSER=67 EX_NOHOST=68 EX_UNAVAILABLE=69 EX_SOFTWARE=70
EX_OSERR=71 EX_OSFILE=72 EX_CANTCREAT=73 EX_IOERR=74
EX_TEMPFAIL=75 EX_PROTOCOL=76 EX_NOPERM=77 EX_CONFIG=78
EX__MAX=78'
;
for shell statements that don't need them, remember ksh
!= perl
-h
set -x
.
That's really gross negligence to leave on in an escalated script.
stderr
for error messages
stdout
.
This is broken beyond all reason:
echo "configuration error."
exit 0
The first one doesn't give the source of the error, the
(completely useless) error message goes to
echo "$0: configuration forbids that action" 1>&2
exit 78 # CONFIG
stdout
(so the Customer never sees it), and
the status provided is success.
opal
, as well. See
opal
(1)
or the opal
tcpmux
service.
The new installation plan
In the past this directory installed every libexec
script on every host.
This was less than optimal.
mk
markup in the rule-set to
detect and install only the scripts actually referenced.
By looping through the rules with in the installed rule-base
we find only the one that a rule-file mentions,
so we know we need each.
This runs after all the rule-sets are installed.
install:
glob -sm -400 ${LIB}/\* |\
MK=-sl0 xapply -f ${C}mk -amRequired -t $$PWD/Default.mk %1${C} - |\
oue |\
MK=-sl0 LIBEXEC=${LIBEXEC} xapply -f ${C}mk -mInstall -t $$PWD/Default.mk %[1/$$]${C} -
deinstall
, which removes scripts without
any owner rule-set:
The deinstall:
( glob -sm -0/777 ${LIBEXEC}/\* ;\
glob -sm -400 ${LIB}/\* | \
MK=-sl0 xapply -f ${C}mk -amRequired -t $$PWD/Default.mk %1${C} - |\
xapply -f ${C}[ -f "${LIBEXEC}/%1" ] && echo %1${C} |\
oue -dv )|\
xapply -vf ${C}install -R %1${C} -
oue
logic there finds the script listed in
the directory, but not listed and installed by any rule-set.
A template option (under Mk
spell support-t
) provides a default
check and a default install rule. So no rule-set or script need supply
the default. If a rule requires a file not listed literally in the
rile-base then it should include a marked command to output the
name(s) of the required files:
Or a rule to force a more restrictive mode on the script:
# $Required(*): ${echo:-echo} nonObvious
An # $Install(*): ${install:-install} -c -m 0750 -g wheel %f ${LIBEXEC:-/usr/local/libexec/op}/%[f/$]
Install
marked line may also rename
the source file to some other name, which the default template doesn't do.
all
target lists any scripts missing from
the source cache. There should never be any if all is sane.
See the template file Default.mk
.
make
recipe above us forced the
installation of all scripts with an install spell like:
install:
xapply -P4 ${C}[ -s %1 ] &&\
install -cm 0755 -o root %1 ${LIBEXEC}${C} ${BIN}
See also
The op manual page, and the
op
msrc
msrc
manual page.
$Id: libexec.html,v 1.13 2013/05/18 21:42:06 ksb Exp $ by ksb.