#!/bin/bash set -e #Copyright (c) 1999-2000, William L. Stearns #See top of Mason script for copyright and licensing information. #Last YYYY code used: 0019, use 0020 next CKPTMGT=" mgt: Ground0" ; #ckpt $CKPTMGT MASONDIR=${MASONDIR:-"/var/lib/mason/"} MASONCONF=${MASONCONF:-"/etc/masonrc"} MASONLIB=${MASONLIB:-"${MASONDIR}masonlib"} #MASONLIB=${MASONLIB:-"${MASONDIR}masonlib"} #My editor of choice (mcedit) gets quoting backwards if there is an odd number of these. if [ -f $MASONLIB ]; then . $MASONLIB else #Can't use wrap here - no library to load it from. echo Missing $MASONLIB library file. Please get a complete copy of Mason from >/dev/stderr echo http://www.pobox.com/~wstearns/mason/ . Exiting. >/dev/stderr sleep 10 exit 1 fi catchall #Put in a default handler for everything; don't just let children die. trap preexit 0 #This gets nullified if we get a SIGHUP or SIGINT - see mgtcleanup. killrunningmason () { #A backgrounded Mason is a pain in the %$^#^%$ to kill... #I think I may have found my wooden stake. Have the equivalent of a pipe to mason; a #file which is tailed along with /var/log/messages into mason when it's run. When #we need to kill mason, echo '!!EXIT!!' into it and have mason look for it on stdin. #Until I'm sure this works, I'll keep the old "bludgeon it to death with sigs" #approach as a backup. if [ -n "$KILLFILES" ]; then for ONEKILLFILE in $KILLFILES ; do echo '!!EXIT!!' >>$ONEKILLFILE done sleep 5 for ONEKILLFILE in $KILLFILES ; do rm -f $ONEKILLFILE 2>/dev/null || : done KILLFILES="" fi if [ -n "$MASONTAILPID" ]; then kill -TERM $MASONTAILPID 2>/dev/null || : ; MASONTAILPID="" ; sleep 1 ; fi if [ -n "$MASONPID" ]; then #FIXME - check if it's still running first? #wrap Killing active $MASONPID >/dev/stderr kill -HUP $MASONPID 2>/dev/null || : sleep 2 kill -TERM $MASONPID 2>/dev/null || : MASONPID="" fi if [ -f "$MASONPIDFILE" ]; then for ONEPID in `cat $MASONPIDFILE` ; do if type -path ps >/dev/null 2>/dev/null && type -path grep >/dev/null 2>/dev/null ; then if [ -n "`ps ax | grep "^[[:space:]]*$ONEPID[[:space:]]" | grep mason`" ]; then #wrap Killing background $ONEPID >/dev/stderr kill -TERM $ONEPID 2>/dev/null || : sleep 2 kill -9 $ONEPID 2>/dev/null || : fi else kill -TERM $ONEPID 2>/dev/null || : fi done cat /dev/null >$MASONPIDFILE || : #SUDO? fi } CKPTMGT=" mgt: trap" ; #ckpt $CKPTMGT mgtcleanup () { #FIXME - should this be 'trap 0'? trap - 0 #If we received a signal, no need to process a "crash". unset CKPTMGT CKPTMASON CKPTCHECKSYS CKPTCLIENTPORTRANGE \ CKPTGENERALIZEIP CKPTIPLE CKPTIPLT CKPTISNUMERICIP CKPTLOADCONF \ CKPTSERVERPORTRANGE CKPTADDCOUNTS CKPTNAMEOF CKPTBROADCASTOF \ CKPTCHECKCONF CKPTDELCOUNTS CKPTFLUSHFIREWALL CKPTPORT2CISCOPORT \ CKPTPROTONUM2NAME CKPTRULETAG CKPTRUNFIREWALL \ CKPTSETTOS CKPTSORTRULEFILE \ CKPTUNIQRULEFILE CKPTUPDATECOUNTS CKPTNETWORKOF || : if [ -n "$VIEWTAILPID" ]; then kill -TERM $VIEWTAILPID 2>/dev/null || : ; VIEWTAILPID="" ; fi killrunningmason CKPTMGT="" echo wrap ${WARN}Exiting - you may need to reset the firewall...${NORM} exit 0 } trap mgtcleanup SIGINT #Ctrl-C generates this reprocess-newrules () { rm -f $NEWRULEFILE.tmp || : mv -f $NEWRULEFILE $NEWRULEFILE.tmp || : touch $NEWRULEFILE || : cat $NEWRULEFILE.tmp | $MASONDECIDE 10<&1 11>>$BASERULEFILE 12>>$NEWRULEFILE 13>/dev/null rm -f $NEWRULEFILE.tmp || : } if [ -f $MASONCONF ]; then #the entire loadconf function is not required . $MASONCONF fi CKPTMGT=" mgt: start" ; #ckpt $CKPTMGT checksys checkconf EXITCONTROL="NO" MASONPID="" MASONTAILPID="" VIEWTAILPID="" KILLFILES="" killrunningmason while [ ! "$EXITCONTROL" = "YES" ]; do clear echo $ENH "${HEADER}---- ${BLUE}Mason${HEADER} firewall builder for Linux ----$NORM" echo $ENH "${HEADER}---- Learning shell for Mason. ----$NORM" echo $ENH "${HEADER}---- see http://www.pobox.com/~wstearns/mason/ for more info. ----$NORM" echo $ENH "${HEADER}---- William Stearns ----$NORM" if [ -n "$MASONVER" ]; then echo $ENH "${HEADER}(This is release $MASONVER)$NORM" fi if [ -n "$MASONPID$MASONTAILPID" ]; then echo Mason is currently in learn mode. echo echo $ENH ${KEY}EL${NORM}: ${KEY}E${NORM}nd ${KEY}L${NORM}earning. showstate 'Mason-gui-text: Main menu, learning in the background' else echo Mason IS NOT currently learning. echo echo $ENH ${KEY}BL${NORM}: ${KEY}B${NORM}egin ${KEY}L${NORM}earning. showstate 'Mason-gui-text: Main menu, not learning' fi echo $ENH ${KEY}EB${NORM}: ${KEY}E${NORM}dit ${KEY}B${NORM}ase firewall rule file. #=> end learn echo $ENH ${KEY}EN${NORM}: ${KEY}E${NORM}dit ${KEY}N${NORM}ew firewall rule file. #=> end learn, ask to merge rulefiles when done echo $ENH ${KEY}MR${NORM}: ${KEY}M${NORM}erge ${KEY}R${NORM}ules from new to base. echo $ENH ${KEY}CS${NORM}: ${KEY}C${NORM}hange mason ${KEY}S${NORM}ettings. #=> sigusr1 mason when done echo $ENH ${KEY}LC${NORM}: ${KEY}L${NORM}ock this ${KEY}C${NORM}onsole and display new rules. echo $ENH ${KEY}Q${NORM}: ${KEY}Q${NORM}uit. #CKPTMGT=" mgt: Waiting for main menu choice" ; #ckpt $CKPTMGT CKPTMGT="" ; #ckpt $CKPTMGT read CHOICE || : CKPTMGT=" mgt: Calling $CHOICE" ; #ckpt $CKPTMGT case $CHOICE in [Bb][Ll]) wrap Begin Learning. showstate 'Mason-gui-text: starting to learn' echo CKPTMGT=" mgt: BL, flushing" ; #ckpt $CKPTMGT flushfirewall CKPTMGT=" mgt: BL, learning" ; #ckpt $CKPTMGT runfirewall LEARN CKPTMGT=" mgt: BL, set killfile" ; #ckpt $CKPTMGT NEWKILLFILE="$MASONDIR$RANDOM.tempflagfile" #FIXME - mktemp/mkstemp? touch $NEWKILLFILE || logfail $LINENO mason-gui-text: YYYY 0019 KILLFILES="$KILLFILES $NEWKILLFILE" CKPTMGT=" mgt: BL, tail" ; #ckpt $CKPTMGT if /bin/false ; then #Is there _any_ _friggin'_ _way_ to handle this cleanly and catch a non-zero return code? #Should we set +e here? ( tail -q -f --lines=0 $PACKETLOGFILE $KILLFILES | $MASONEXE >>$NEWRULEFILE ) & #nohup just before tail removed #SUDO on tail? MASONTAILPID="$MASONTAILPID `ps axf | grep -v grep | grep -A 1 '^[[:space:]]*$![[:space:]]' | tail -1 | awk '{print $1}' || logfail $LINENO mason-gui-text: YYYY 0001`" #I am open to ideas on better ways to figure out the pid of the tail command. Anyone? Bueller? MASONPID="$MASONPID `ps axf | grep -v grep | grep -A 2 '^[[:space:]]*$![[:space:]]' | tail -1 | awk '{print $1}' || logfail $LINENO mason-gui-text: YYYY 0002`" #FIXME - display this first so as not to mix output? wrap Mason is now running in the background. I will be showing the log output. Press Enter when you want to return to the main menu - Mason will continue to run in the background until you choose \"EL\" from the main menu. #tail -f --lines=0 $PACKETLOGFILE $NEWRULEFILE & CKPTMGT=" mgt: BL, background tail" ; #ckpt $CKPTMGT set +e #Turn off failure checking - I don't know how to handle a failure return code from it. tail -f --lines=0 $NEWRULEFILE & VIEWTAILPID="$VIEWTAILPID $!" set -e echo $ENH Press ${KEY}ENTER${NORM} to return to the main menu CKPTMGT=" mgt: BL, press enter" ; #ckpt $CKPTMGT read JUNK || : CKPTMGT=" mgt: BL, killtail" ; #ckpt $CKPTMGT kill -TERM $VIEWTAILPID 2>/dev/null || : ; VIEWTAILPID="" else #FIXME - check all files trap : SIGINT #make ctrl-c trap do nothing when running mason-decide #trap '{ echo Ctrl-C caught by mgt }' SIGINT #Ctrl-C tail -q -f --lines=0 $PACKETLOGFILE $KILLFILES | $MASONEXE | $MASONDECIDE 10<&1 11>>$BASERULEFILE 12>>$NEWRULEFILE 13>>$NEWKILLFILE #SUDO on tail? killrunningmason flushfirewall runfirewall STANDARD trap mgtcleanup SIGINT #Ctrl-C fi ;; [Ee][Ll]) showstate 'Mason-gui-text: Ending the learning process' if [ -n "`cat $NEWRULEFILE | sed -e 's/#.*//' | grep -v '^[[:space:]]*$' | grep -v '^export' || :`" ]; then #formerly YYYY 0003 wrap You still have unmerged rules in $NEWRULEFILE. Would you like to process them now? ${KEY}Y${NORM}/${KEY}N${NORM}? if askYN ; then reprocess-newrules ; fi fi wrap End Learning. killrunningmason flushfirewall runfirewall STANDARD ;; [Ee][Bb]) wrap Edit Base rule file. showstate 'Mason-gui-text: Edit base rule file' if [ -z "$EDITOR" ]; then wrap ${WARN}EDITOR was not set in your environment. Please set it with something like \"export EDITOR=mcedit\"${NORM} sleep 10 else cp -pf $BASERULEFILE $BASERULEFILE.bak || logfail $LINENO mason-gui-text: YYYY 0004 addcounts $BASERULEFILE $EDITOR $BASERULEFILE || logfail $LINENO mason-gui-text: YYYY 0005 if diff -bB <(sed -e 's/#.*//' -e 's/[[:space:]]//g' $BASERULEFILE | uniq || logfail $LINENO mason-gui-text: YYYY 0006) <(sed -e 's/#.*//' -e 's/[[:space:]]//g' $BASERULEFILE.bak | uniq || logfail $LINENO mason-gui-text: YYYY 0007) >/dev/null ; then wrap No changes made. else wrap Changes made, restarting firewall flushfirewall if [ -n "$MASONPID$MASONTAILPID" ]; then runfirewall LEARN else runfirewall STANDARD fi fi fi ;; [Ee][Nn]) wrap Edit the new rule file. showstate 'Mason-gui-text: Edit new rule file' if [ -z "$EDITOR" ]; then wrap ${WARN}EDITOR was not set in your environment. Please set it with something like \"export EDITOR=mcedit\"${NORM} sleep 10 else if [ -n "$MASONPID$MASONTAILPID" ]; then wrap Ending the learn process. ; fi killrunningmason uniqrulefile $NEWRULEFILE $EDITOR $NEWRULEFILE || logfail $LINENO mason-gui-text: YYYY 0008 if diff -bB <(sed -e 's/#.*//' -e 's/[[:space:]]//g' $NEWRULEFILE | uniq || logfail $LINENO mason-gui-text: YYYY 0009) <(sed -e 's/#.*//' -e 's/[[:space:]]//g' $NEWRULEFILE.bak | uniq || logfail $LINENO mason-gui-text: YYYY 0010) >/dev/null ; then wrap No changes made. else if [ -n "$MASONPID$MASONTAILPID" ]; then wrap Changes made, restarting firewall flushfirewall runfirewall LEARN else wrap Changes made, but no need to restart firewall as Mason is not running. fi fi fi ;; [Mm][Rr]) CKPTMGT=" mgt: start mr" ; #ckpt $CKPTMGT showstate 'Mason-gui-text: Merging rules' wrap Do you want to merge some, all, or none of the rules in this file to the base rule file? Enter \"${KEY}some${NORM}\", \"${KEY}all${NORM}\", or \"${KEY}none${NORM}\". unset WHATTOMERGE || : read WHATTOMERGE || : case $WHATTOMERGE in [Aa][Ll][Ll]) CKPTMGT=" mgt: mr all" ; #ckpt $CKPTMGT cp -pf $BASERULEFILE $BASERULEFILE.bak || logfail $LINENO mason-gui-text: YYYY 0011 #FIXME - should we or not? #uniqrulefile $NEWRULEFILE echo "#Rules merged from the new rule file:" >>$BASERULEFILE #cat $NEWRULEFILE | sed -e 's/^/#/' >>$BASERULEFILE #Use this version if you want to force them commented cat $NEWRULEFILE >>$BASERULEFILE || logfail $LINENO mason-gui-text: YYYY 0012 cat /dev/null >$NEWRULEFILE || logfail $LINENO mason-gui-text: YYYY 0013 wrap You will probably want to edit the base rule file next. ;; [Ss][Oo][Mm][Ee]) CKPTMGT=" mgt: mr some" ; #ckpt $CKPTMGT wrap What string identifies the rules to merge? unset MERGEID || : read MERGEID || : wrap There are `grep "$MERGEID" $NEWRULEFILE | wc -l` rules with that ID, and `grep -v "$MERGEID" $NEWRULEFILE | wc -l` lines without it, `cat $NEWRULEFILE | wc -l` total. if echo "Do you want to continue ({KEY}Y${NORM}/${KEY}N${NORM})" ; askYN ; then CKPTMGT=" mgt: mr some continue" ; #ckpt $CKPTMGT cp -pf $BASERULEFILE $BASERULEFILE.bak || logfail $LINENO mason-gui-text: YYYY 0014 #FIXME - should we or not? #uniqrulefile $NEWRULEFILE CKPTMGT=" mgt: mr some continue header" ; #ckpt $CKPTMGT echo "#Rules merged from the new rule file:" >>$BASERULEFILE #cat $NEWRULEFILE | grep "$MERGEID" | sed -e 's/^/#/' >>$BASERULEFILE CKPTMGT=" mgt: mr some continue append to base" ; #ckpt $CKPTMGT cat $NEWRULEFILE | grep "$MERGEID" >>$BASERULEFILE || : CKPTMGT=" mgt: mr some continue remove from new" ; #ckpt $CKPTMGT cat $NEWRULEFILE | grep -v "$MERGEID" >$NEWRULEFILE.tmp || : #Grep returns false if we happen to merge everything. CKPTMGT=" mgt: mr some continue overwrite new" ; #ckpt $CKPTMGT cat $NEWRULEFILE.tmp >$NEWRULEFILE || : CKPTMGT=" mgt: mr some continue remove tmp" ; #ckpt $CKPTMGT rm -f $NEWRULEFILE.tmp || : wrap You will probably want to edit the base rule file next. else wrap Aborting merge. fi ;; esac ;; [Cc][Ss]) if [ -z "$EDITOR" ]; then wrap ${WARN}EDITOR was not set in your environment. Please set it with something like \"export EDITOR=mcedit\"${NORM} sleep 10 else #wrap Here are the non-comment lines in $MASONCONF: #echo #cat $MASONCONF | sed -e 's/#.*//' | grep -v '^$' | uniq #echo #wrap Press ${KEY}enter${NORM} to edit this file #read JUNK showstate 'Mason-gui-text: Changing settings' cp -pf $MASONCONF ${MASONDIR}masonrc.bak || : $EDITOR $MASONCONF || logfail $LINENO mason-gui-text: YYYY 0015 if diff -bB <(sed -e 's/#.*//' -e 's/[[:space:]]//g' $MASONCONF | uniq || logfail $LINENO mason-gui-text: YYYY 0016) <(sed -e 's/#.*//' -e 's/[[:space:]]//g' ${MASONDIR}masonrc.bak | uniq || logfail $LINENO mason-gui-text: YYYY 0017) >/dev/null ; then wrap No changes made. rm -f ${MASONDIR}masonrc.bak || : else if [ -f $MASONCONF ]; then . $MASONCONF fi checkconf if [ -n "$MASONPID$MASONTAILPID" ]; then wrap Changes made, signalling mason to reread configuration. kill -USR1 $MASONPID 2>/dev/null || : else wrap Changes made. fi fi fi ;; [Ll][Cc]) if ! type -path vlock >/dev/null 2>/dev/null ; then wrap ${WARN}The vlock utility is not on this system. It is required to be able to lock the console. Once installed, this option will be available again.${NORM} sleep 15 else showstate 'Mason-gui-text: Locked console' if [ -n "$MASONPID$MASONTAILPID" ]; then #tail -f --lines=0 $PACKETLOGFILE $NEWRULEFILE & #FIXME - 'set +e' here? tail -f --lines=0 $NEWRULEFILE & VIEWTAILPID="$VIEWTAILPID $!" else wrap Mason is not currently learning, but I will lock this terminal anyways. fi vlock || : if [ -n "$VIEWTAILPID" ]; then kill -TERM $VIEWTAILPID 2>/dev/null || : ; VIEWTAILPID="" ; fi fi ;; [Qq]) showstate 'Mason-gui-text: Exiting' if [ -n "`cat $NEWRULEFILE | sed -e 's/#.*//' | grep -v '^[[:space:]]*$' | grep -v '^export' || :`" ]; then #formerly YYYY 0018 echo -n $ENH You may still have unmerged rules in $NEWRULEFILE. Would you like to process these now? ${KEY}Y${NORM}/${KEY}N${NORM} if askYN ; then reprocess-newrules ; fi fi EXITCONTROL="YES" wrap Exiting. Returning to the standard firewall. if [ -n "$VIEWTAILPID" ]; then kill -TERM $VIEWTAILPID 2>/dev/null || : ; VIEWTAILPID="" ; fi killrunningmason flushfirewall runfirewall STANDARD ;; *) wrap ${WARN}Unknown choice. Please enter the one or two character code.${NORM} ;; esac sleep 2 done CKPTMGT="" showstate ''