Bugtraq mailing list archives

Re: Security hole in mgetty+sendfax


From: gert () GREENIE MUC DE (Gert Doering)
Date: Fri, 25 Jul 1997 10:14:37 +0200


-----BEGIN PGP SIGNED MESSAGE-----

Hi,

Gert Doering wrote:
[Mgetty+sendfax security problem]

begin 644 faxq+faxrunq.tar.gz

Well... some minor points:

- - this is not releated to the "Hylafax" (formerly FlexFax) package.
  Hylafax has a "faxq" program as well, but it works completely different
  and is not affected.

- - the URL for mgetty is http://www.leo.org/~doering/mgetty/, but the
  patch is not yet there (weekend).

- - somehow the uuencode'd file got corrupted traversing bugtraq's relay
  mailer [linux-security got it correctly], so I'll append it again, as
  a "shar" archive.

gert

#!/bin/sh
# This is a shell archive (produced by shar 3.52.3)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 07/25/1997 07:55 UTC by gert@greenie
# Source directory /u/gert/src/mgetty/fax
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   3507 -rw-r--r-- faxq
#   8247 -rw-r--r-- faxrunq
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo 'WARNING: not restoring timestamps'
fi
rm -f 1231235999 $$.touch
#
# ============= faxq ==============
if test -f 'faxq' && test X"$1" != X"-c"; then
  echo 'x - skipping faxq (File already exists)'
else
  echo 'x - extracting faxq (Text)'
  sed 's/^X//' << 'SHAR_EOF' > 'faxq' &&
#!/bin/sh
#
# faxq program
#
# like "lpq" or "mailq", show jobs waiting in the output queue
#
# SCCS: @(#)faxq.in     4.3 97/07/24 Copyright (C) 1994 Gert Doering
#
FAX_SPOOL=/usr/spool/fax
FAX_SPOOL_OUT=/usr/spool/fax/outgoing
X
#
# echo program that will accept escapes (bash: "echo -e", sun: /usr/5bin/echo)
#
echo="echo"
X
#
# an awk that is not stone-old-brain-dead (that is, not oawk...)
#
AWK=awk
X
if cd $FAX_SPOOL_OUT
then:
else
X    $echo "cannot chdir to $FAX_SPOOL_OUT..." >&2
X    exit 1
fi
X
jobs="*/JOB"
requeue=""
X
for flag
do
X    case $flag in
X       -v) verbose="true" ;;
X       -o) jobs="*/JOB.done" ;;
X       -s) jobs="*/JOB.s*" ;;
X       -a) jobs="*/JOB*" ;;
X       -r) jobs="*/JOB.s*"; requeue="true" ;;
X       *) cat <<EOF_MSG >&2
$0: invalid option: $flag
valid options:
X  -o: show old jobs
X  -s: show suspended jobs
X  -a: show all jobs
X  -v: verbose output
X  -r: restart suspended jobs
EOF_MSG
X          exit 1 ;;
X    esac
done
X
jobs=`ls $jobs 2>/dev/null`
[ -z "$jobs" ] && $echo "no jobs."
for i in $jobs
do
X    USER=""; PHONE=""; PAGES=""; MAILTO=""; VERBTO="";
X    ACCT=""; INPUT=""; PRI=""; RE=""
X
X    if [ -z "$verbose" ]
X    then
X       eval `tr -d '\042\047\140\134\044\073' <$i | \
X            $AWK '$1=="user" { printf "USER=%s;", $2 }
X                  $1=="phone" { printf "PHONE=%s;", $2 }
X                  $1=="pages" { printf "PAGES=%d;", NF-1 }
X                  $1=="priority" { printf "PRI=\" pri=%s.\"", $2}' -`
X       $echo "$i: queued by $USER. $PAGES page(s) to $PHONE.$PRI"
X    else
X       eval `tr -d '\042\047\140\134\044\073' <$i | \
X            $AWK '$1=="user" { printf "USER=%s;", $2 }
X                  $1=="mail"  { printf "MAILTO=\"%s\";", substr( $0, 6 ) }
X                  $1=="phone" { printf "PHONE=%s;", $2 }
X                  $1=="verbose_to" \
X                              { printf "VERBTO=\"%s\";", substr( $0, 12 ) }
X                  $1=="acct_handle" \
X                              { printf "ACCT=\"%s\";", substr( $0, 13 ) }
X                  $1=="input" { printf "INPUT=\"%s\";", substr( $0, 7 ) }
X                  $1=="time"  { printf "TIME=\"%s:%s\";",
X                                substr( $0, 6, 2 ), substr( $0, 8,2 ) }
X                  $1=="subject"{ printf "RE=\"%s\";", substr( $0, 9 ) }
X                  $1=="priority"{ printf "PRI=\"%s\";", $2 }
X                  $1=="pages" { if ( NF==2 ) printf "PAGES=\"%s\";", $2
X                                else if ( NF==3 )
X                                     printf "PAGES=\"%s %s\";", $2, $3
X                                else
X                                     printf "PAGES=\"%s ... %s\";", $2, $NF
X                              }' -`
X       $echo "$i:"
X       $echo "\tQueued by: $USER"
X       if [ -z "$VERBTO" ]
X       then
X       $echo "\t       to: $PHONE"
X       else
X       $echo "\t       to: $VERBTO ($PHONE)"
X       fi
X       test ! -z "$RE" && \
X       $echo "\t       Re: $RE"
X       test ! -z "$MAILTO" && \
X       $echo "\t   E-Mail: $MAILTO"
X       test ! -z "$INPUT" && \
X       $echo "\t    Input: $INPUT"
X       $echo "\t    Pages: $PAGES"
X       test ! -z "$TIME" && \
X       $echo "\tSend time: $TIME"
X       test ! -z "$ACCT" && \
X       $echo "\tAcct info: $ACCT"
X       test ! -z "$PRI" && \
X       $echo "\t Priority: $PRI"
X
X       sed -e '/Status/!d' -e 's/Status/           Status:/' $i
X       if [ -f "$i.locked" ] ; then
X        $echo "\t   Status: LOCKED (being sent right now)"
X       else
X       expr $i : ".*done$" >/dev/null ||
X       $echo "\t   Status: not sent yet"
X       fi
X    fi
X
# if "requeue", requeue *.suspended-Jobs
X    if [ -n "$requeue" ] && expr "$i" : ".*JOB.s" >/dev/null
X    then
X       d=`dirname $i`
X       if [ ! -w $d ] ; then
X           $echo "$i: not owner, can't restart"
X       else
X           $echo "Status "`date`" - reactivated by $LOGNAME" >>$i
X           mv $i $d/JOB
X       fi
X    fi
X
done
X
test -n "$verbose" -a -n "$jobs" -a -r .last_run &&
X    $echo "\nLast \`\`faxrunq'' run at: `cat .last_run`"
X
SHAR_EOF
  $shar_touch -am 0724205497 'faxq' &&
  chmod 0644 'faxq' ||
  echo 'restore of faxq failed'
  shar_count="`wc -c < 'faxq'`"
  test 3507 -eq "$shar_count" ||
    echo "faxq: original size 3507, current size $shar_count"
fi
# ============= faxrunq ==============
if test -f 'faxrunq' && test X"$1" != X"-c"; then
  echo 'x - skipping faxrunq (File already exists)'
else
  echo 'x - extracting faxrunq (Text)'
  sed 's/^X//' << 'SHAR_EOF' > 'faxrunq' &&
#!/bin/sh
#
# faxrunq
#
# look for outgoing fax jobs, send them via sendfax, if succesful, remove
# them from the outgoing queue (and send a mail to the originator of the
# job)
#
# There are still a lot rough edges - but it works, and should give you an
# idea how to improve it
#
# SCCS: @(#)faxrunq.in  4.3 97/07/24 Copyright (C) 1994 Gert Doering
X
FAX_SPOOL=/usr/spool/fax
FAX_SPOOL_OUT=/usr/spool/fax/outgoing
FAX_SENDER="/usr/local/sbin/sendfax"
FAX_ACCT=$FAX_SPOOL/acct.log
X
MAILER="/usr/lib/mail/execmail"
X
CONF_FILE="/usr/local/etc/mgetty+sendfax/faxrunq.config"
X
#
# echo program that will accept escapes (bash: "echo -e", sun: /usr/5bin/echo)
#
echo="echo"
X
#
# awk program that is not stone-old-brain-dead (that is, not oawk...)
#
AWK=awk
X
#
# make sure we'll find "newslock" and other good stuff when run from "cron"...
#
PATH=/usr/local/bin:$PATH
X
#
# set defaults, then process configuration file (if it exists)
#
do_mail_s="TRUE"
do_mail_f="TRUE"
exec_pgm_s=""
exec_pgm_f=""
max_fail_costly=5
max_fail_total=10
delete_sent=""
X
if [ -r $CONF_FILE ] ; then
X    eval `$AWK '/^ *#/ { next }
X            $1 == "success-send-mail" \
X               { printf "do_mail_s=\"%s\";", ($2 ~ /^[yYjJtT1]/)? "T":"" }
X            $1 == "failure-send-mail" \
X               { printf "do_mail_f=\"%s\";", ($2 ~ /^[yYjJtT1]/)? "T":"" }
X            $1 == "success-call-program" \
X               { printf "exec_pgm_s=\"%s\";", $2 }
X            $1 == "failure-call-program" \
X               { printf "exec_pgm_f=\"%s\";", $2 }
X            $1 == "maxfail-costly" && $2 ~ /^[0-9]/ \
X               { printf "max_fail_costly=\"%s\";", $2 }
X            $1 == "maxfail-total" && $2 ~ /^[0-9]/ \
X               { printf "max_fail_total=\"%s\";", $2 }
X            $1 == "delete-sent-jobs" \
X               { printf "delete_sent=\"%s\";", ($2 ~ /^[yYjJtT1]/)? "T":"" }
X            END { printf "\n" }' $CONF_FILE`
fi
X
#
# command line arguments
#
usage="usage: $0 [-s] [-q]"
X
while:
do
X    case "$1" in
# sleep 30 seconds after each job, give modem time to settle
X       -s) sleepwait=30;shift;;
# quiet operation
X       -q) exec >/dev/null ; shift ;;
# invalid option
X       -*) $echo "$0: unknown option: $1" >&2
X            $echo "$usage" >&2
X           exit 1
X           ;;
X       *) break
X    esac
done
X
if [ $# -gt 0 ]
then
X    $echo "$usage" >&2
X    exit 1
fi
X
#
# go to fax spool directory, process all JOB files
#
X
cd $FAX_SPOOL_OUT || exit 1
X
status="0"
jobs=`ls */JOB 2>/dev/null`
for job in $jobs
do
X    if [ $status -eq 4 -a -n "$sleepwait" ]
X    then
#     old stat :no connect; modem allows next redial in $sleepwait secs
X      $echo "sleeping $sleepwait seconds"
X      sleep $sleepwait
X    fi
X    cd $FAX_SPOOL_OUT/`dirname $job`
X    $echo "processing $job..."
#
#   lock JOB file (by 'link(2)'ing it to JOB.locked)
#   'newslock' is a small C program that just calls link(argv[1], argv[2])
#
X    # make sure Lock will be removed in case the shell aborts
X    trap "rm -f JOB.locked 2>/dev/null" 0
X    trap "rm -f JOB.locked 2>/dev/null ; exit 20" 1 2 3 15
X
X    newslock JOB JOB.locked 2>/dev/null
X    if [ $? -ne 0 ]
X    then
X       $echo "already locked"
X       trap 0 1 2 3 15
X       continue
X    fi
#
# get user to notify (->$MAIL_TO), phone number (->$PHONE) and
# earliest send time (->$TIME)
#
X    eval `tr -d '\042\047\140\134\044\073' <JOB | \
X         $AWK 'BEGIN { user=""; mail=""; verbto=""; time=""; re=""; }
X               $1=="user" { user=$2 }
X               $1=="mail" { mail=substr( $0, 6) }
X               $1=="phone" { printf "PHONE=%s;", $2 }
X               $1=="time" { time=$2 }
X               $1=="verbose_to" { verbto=substr($0,12) }
X               $1=="subject" { re=substr($0,9) }
X               END { if ( mail != "" ) printf "MAIL_TO=\"%s\";", mail
X                                  else printf "MAIL_TO=\"%s\";", user
X                     printf "TIME=\"%s\";", time
X                     printf "VERBOSE_TO=\"%s\";", verbto
X                     printf "RE=\"%s\"", re }' - `
X
#
# check whether send time is reached
#
X    if [ ! -z "$TIME" ]
X    then
X       if [ `date "+%H""%M"` -lt $TIME ]
X       then
X           $echo "...send time not reached, postponing job"
X           rm JOB.locked
X           continue
X       fi
X    fi
X
#
# construct command line to execute
#
X    command=`tr -d '\042\047\140\134\044\073' <JOB | \
X             $AWK 'BEGIN { phone="-"; flags=""; pages="" }
X                 $1=="phone" { phone=$2 }
X                 $1=="header"     { flags=flags" -h "$2 }
X                 $1=="poll"       { flags=flags" -p" }
X                 $1=="normal_res" { flags=flags" -n" }
X                 $1=="acct_handle" { flags=flags" -A \""substr($0,13)"\"" }
X                 $1=="pages" { for( i=2; i<=NF; i++) pages=pages$i" " }
X                 END { printf "'"$FAX_SENDER"' -v%s %s %s", \
X                              flags, phone, pages }' -`
X
#
# execute faxsend command
#
X    $echo "$command"
X    eval $command
#
# handle return values
#
X    status=$?
X    $echo "command exited with status $status"
X
#
# string to include in subject line
#
X    if [ -z "$VERBOSE_TO" ]
X    then
X        subject="your fax to $PHONE"
X    else
X        subject="your fax to $VERBOSE_TO ($PHONE)"
X    fi
X
#
# evaluate return codes, if success, remove fax job from queue
#
X    if [ $status -eq 0 ]
X    then
X       # transmission successful
X       $echo "Status "`date`" successfully sent" >>JOB
X
X       # update accounting log
X       $echo "$MAIL_TO $PHONE "`date`" success" >>$FAX_ACCT
X
X       # send mail, if requested
X       if [ -n "$do_mail_s" ] ; then
X           $echo "    send mail to $MAIL_TO..."
X           (
X             trap 0                    # catch BASH bug
X             $echo "To: $MAIL_TO"
X             $echo "Subject: OK: $subject"
X             $echo "From: root (Fax Subsystem)\n"
X             $echo "Your fax has been sent successfully at: \c"
X             date
X             test -z "$RE" || \
X               $echo "(Subject was: $RE)\n"
X             $echo "\n\nJob / Log file:"
X             cat JOB
X             tries=`grep Status JOB | sed -e '1d' | wc -l`
X             $echo "\nSending succeeded after" $tries "unsuccessful tries."
X           ) |
X           $MAILER "$MAIL_TO"
X       fi
X
X       # call "success" handler program (if requested)
X       if [ -n "$exec_pgm_s" ] ; then
X           $echo "    calling program $exec_pgm_s..."
X           $exec_pgm_s $FAX_SPOOL_OUT/$job
X       fi
X
X       # job is done -> remove it from the queue
X       mv JOB JOB.done
X
X       # completely remove JOB directory (only if requested)
X       # instead of this, the job could be archived by "$exec_pgm_s" or so
X       if [ -n "$delete_sent" ] ; then
X           $echo "    deleting job files + directory..."
X           cd $FAX_SPOOL_OUT
X           rm -rf `dirname $job`
X       fi
X
X    elif [ $status -lt 10 ]
X    then
X       # error before starting to transmit (try again)
X       why="unknown" ; case $status in
X           1) why="errors in command line" ;;
X           2) why="cannot open fax device (locked?)" ;;
X           3) why="modem initialization error" ;;
X           4) why="dial failed - BUSY" ;;
X           5) why="dial failed - NO DIALTONE" ;;
X       esac
X       $echo "Status "`date`" failed, exit($status): $why" >>JOB
X    else
X       # error while transmitting, considered fatal
X       why="unknown" ; case $status in
X           10) why="dial failed - NO CARRIER" ;;
X           11) why="protocol failure, waiting for XON" ;;
X           12) why="protocol failure sending page" ;;
X       esac
X       $echo "Status "`date`" FATAL FAILURE, exit($status): $why" >>JOB
X
X       # update accounting log
X       $echo "$MAIL_TO $PHONE "`date`" fail: $why" >>$FAX_ACCT
X
X       # if failed <max_fail_costly> times, suspend job
X       if [ `grep "FATAL FAILURE" JOB | wc -l` -ge $max_fail_costly ]
X       then
X           $echo "Status "`date`" job suspended: too many FATAL errors" >>JOB
X
X           # send mail, if requested
X           if [ -n "$do_mail_f" ] ; then
X               echo "    send mail to $MAIL_TO..."
X               (
X                 trap 0                        # catch BASH bug
X                 $echo "To: $MAIL_TO"
X                 $echo "Subject: FAIL: $subject failed"
X                 $echo "From: root (Fax Subsystem)\n"
X                 $echo "It was not possible to send your fax to $PHONE!\n"
X                 test -z "$RE" || \
X                   $echo "(Subject was: $RE)\n"
X                 $echo "The fax job is suspended, you can requeue it with the command:"
X                 $echo "    cd $FAX_SPOOL_OUT/"`dirname $job`
X                 $echo "    mv JOB.suspended JOB\n"
X                 $echo "log file follows:"
X                 cat JOB ) |
X               $MAILER "$MAIL_TO"
X           fi
X
X           # call error handler, if requested
X           if [ -n "$exec_pgm_f" ] ; then
X               $echo "    calling program $exec_pgm_f..."
X               $exec_pgm_f $FAX_SPOOL_OUT/$job
X           fi
X
X           #
X           # suspend job (but do not delete it)
X           #
X           mv JOB JOB.suspended 2>/dev/null
X       fi
X    fi
#
# unlock job (even if the JOB has been renamed to JOB.suspended or
#             JOB.done, the link to JOB.locked still exists!)
#
X    rm -f JOB.locked
done
X
trap 0 1 2 3 15
X
#
# touch the time stamp, to make faxspool happy
#
rm -f $FAX_SPOOL_OUT/.last_run
date >$FAX_SPOOL_OUT/.last_run
chmod 644 $FAX_SPOOL_OUT/.last_run
SHAR_EOF
  $shar_touch -am 0724205497 'faxrunq' &&
  chmod 0644 'faxrunq' ||
  echo 'restore of faxrunq failed'
  shar_count="`wc -c < 'faxrunq'`"
  test 8247 -eq "$shar_count" ||
    echo "faxrunq: original size 8247, current size $shar_count"
fi
exit 0
- --
ftp.leo.org:/pub/comp/networking/communication/modem/mgetty/mgetty*.tar.gz
greenie (login: nuucp, 089/3545988):/pub/uploads/mgetty1.1*.tar.gz
***** SEE THE DOCS on ***** http://www.leo.org/~doering/mgetty/ *****

Gert 'Mr. Mgetty' Doering   ---   gert () greenie muc de   ---   mgetty () muc de

-----BEGIN PGP SIGNATURE-----
Version: 2.6.2i

iQCVAwUBM9hga6kuBuNlUUl1AQHgaQP+NlvJS7Fk+hPFsV4hTkJuo7tW+ZjI0n6c
m7zaGR5mT1gR73GikeCAQJUfmrCU2KQRDWQYe4eXChXfvk31yF3Yg+A7thpAjpJb
d2H56MEKypOooKLR0HsBaDp5ds2jqPp2pzQA5LPNcktCyfJ4VQ/TTSt/Bi5b1wRX
Ufa8AMOJ7vU=
=AAPP
-----END PGP SIGNATURE-----



Current thread: