greywolf@unisoft.UUCP (The Grey Wolf) (10/28/88)
Posting-number: Volume 5, Issue 17 Submitted-by: "The Grey Wolf" <greywolf@unisoft.UUCP> Archive-name: vipw [Some comments: (1) some shells break or slow down when the leading character on lines in a here document is the same as the leading character of the "EOF word". This has got that bug! (I fixed it, just in case.) (2) The code is in "debug mode"; rearrange the comments a bit to make a working version. (3) I hate to tell you, greywolf, but this thing is just as useful under Xenix or System V; neither of which are guaranteed to mount /usr. Stupid parochialisms are why this critter's needed in the first place! ++bsa] After seeing the questions on comp.unix.questions about a vipw program, I thought I would submit one. It seems to me to be completely portable; if not, the tweaks required are likely minimal. It includes sanity checking for a uid 0 entry (verification of shell, home directory, password); and produces appropriate messages explaining what happened. Enjoy. Comments? Flames? -> ...!{sun,ucbvax,well,uunet}!unisoft!greywolf -----cut here----------cut here----------cut here----------cut here----- #!/bin/sh - # This is a shell archive, meaning: # 1: delete everything above the #! /bin/sh - line. # 2: use sh (NOT csh) to unpack the archive. # # This file contains: # vipw.sh (3832 bytes) # # Packed by greywolf@unisoft.UniSoft (The Grey Wolf) 30 September 1988 sed 's/^FOO_//g' << '_BAR_' > vipw.sh FOO_#! /bin/sh - FOO_# vipw: edit passwd file with locking. FOO_# unicom!greywolf FOO_ FOO_# PATH and IFS are here for paranoia's sake FOO_# The path may be modified as necessary. FOO_IFS=' FOO_' FOO_PATH=/etc:/bin:/usr/bin:/usr/ucb:/usr/etc:/usr/local/bin export PATH IFS FOO_ FOO_EDITOR=${EDITOR-vi} FOO_ FOO_# PASSWD=/etc/passwd PTMP=/etc/ptmp FOO_PASSWD=./passwd PTMP=./ptmp FOO_ FOO_# if the temp file exists, tell 'em to come back later. FOO_ FOO_if [ -f $PTMP ] FOO_then echo "vipw: temp file busy, try again later." FOO_ exit 0 FOO_fi FOO_ FOO_# simplify cleanup FOO_trap "/bin/rm -f $PTMP ; exit 0" 0 1 2 3 15 FOO_ FOO_cp $PASSWD $PTMP # so we don't have the real thing. FOO_if chmod 600 $PTMP # This could be something like 644... FOO_then : FOO_else exit $? FOO_fi FOO_ FOO_# check if /usr is mounted; if we're single-user, it likely isn't, at least FOO_# on any SANE implementation of a hierarchy. (Sun 4.0 is not a sane hier- FOO_# archy in my opinion.) FOO_ FOO_if mount | grep "/usr " > /dev/null FOO_then mount=0 FOO_else mount=1 # set a flag to umount /usr later FOO_ if mount /usr FOO_ then : FOO_ else echo "mounting /usr failed" FOO_ exit $? # if it failed, we have problems -- better leave FOO_ fi FOO_fi FOO_ FOO_# edit the thing. FOO_ FOO_$EDITOR $PTMP FOO_ FOO_# was it changed? don't shuffle files unnecessarily. FOO_ FOO_if cmp -s $PTMP $PASSWD FOO_then echo "No changes appear to have been made." FOO_ exit 0 FOO_fi FOO_ FOO_# FOO_# check the super-user password entry. There MUST be at least one user with FOO_# uid 0. If not, then we exit. If the password is not of the 13 char FOO_# length, then it cannot be decrypted, so we exit. If the password has an FOO_# asterisk in it, it cannot be decrypted, so we exit. If the ptmp file gets FOO_# deleted/trashed, we don't even bother moving it. If root's login shell is FOO_# not executable, then we don't allow it, and we exit. If root's passwd is FOO_# zero-length, then we issue a warning only. FOO_# Replacing root's (bad) shell with /bin/sh is tricky without another tmp FOO_# file, and that's getting sloppy. FOO_ FOO_# we don't demand "root" as the first uid 0 entry. I use "wizard" on some FOO_# machines. FOO_ FOO_echo "verifying superuser password entry..." FOO_ FOO_# length of a minimal superuser password entry when echoed portably is FOO_# 14 chars: FOO_# "root::0:0::/:" + the newline that echo prints. FOO_ FOO_if [ `cat $PTMP | wc -c` -lt 14 ] FOO_then echo "panic: zero-length file! FOO_passwd file unchanged." FOO_ exit 1 FOO_fi FOO_ FOO_# look for a uid 0 entry -- this MUST be first on the line or this will fail. FOO_if pwd=`head -1 $PTMP | egrep '^[^:]*:[^:]*:0:[0-9^:]*:[^:]*:[^:]*:.*[^:]$'` FOO_then pwd="`echo $pwd | FOO_ sed -e 's/::/:NULL:/g' \ FOO_ -e 's/:.*\*[^:]*:/:STAR:/g' -e 's,:$,:/bin/sh,'`" FOO_else echo "panic: basic super-user entry missing FOO_passwd file unchanged." FOO_ exit 1 FOO_fi FOO_ FOO_# split the root entry for easy access FOO_set `echo "$pwd" | FOO_ awk -F: '{ printf "%s %s %d %d %s %s",$1,$2,$3,$4,$6,$7 }'` FOO_ FOO_pw_name="$1" pw_passwd="$2" pw_uid="$3" pw_gid="$4" FOO_pw_dir="$5" pw_shell="$6" FOO_ FOO_ FOO_not_ok=0 # everything is ok until we find otherwise FOO_ FOO_# The length of a password will be 13 chars; when echoed portably it will be FOO_# 14 chars due to the newline returned by echo FOO_ FOO_if [ `echo "$pw_passwd" | wc -c` -lt 14 ] FOO_then if [ "$pw_passwd" = "NULL" ] FOO_ then echo "warning: null super-user passwd." FOO_ not_ok=1 FOO_ else FOO_ echo "panic: impossible super-user password. FOO_passwd file unchanged." FOO_ exit 1 FOO_ fi FOO_fi FOO_ FOO_# root MUST log into / as home directory. Why? Enforcement of convention. FOO_# if you don't like it, change it. FOO_ FOO_if [ ! "$pw_dir" = "/" ] FOO_then echo "panic: bad super-user directory. FOO_passwd file unchanged." FOO_ exit 1 FOO_fi FOO_ FOO_# We have to have an existing executable shell, or else root's login/su FOO_# attempts will fail miserably. FOO_# Why doesn't test have a -x option?!? FOO_ FOO_if [ ! -f "$pw_shell" ] FOO_then echo "panic: can't find shell $pw_shell! FOO_passwd file unchanged." FOO_ exit 1 FOO_fi FOO_ FOO_if [ $not_ok -eq 0 ] FOO_then echo ok. FOO_fi FOO_ FOO_# make passwd file read-only to discourage direct use of an editor on the FOO_# file. FOO_chmod 444 $PTMP FOO_mv -f $PTMP $PASSWD FOO_echo done. FOO_exit 0 _BAR_ if [ `cat vipw.sh` -ne 3832 ] then echo "vipw.sh unpacked with wrong size -- should be 3832 bytes fi # end of shar file.