diff options
Diffstat (limited to 'security/portaudit/files/portaudit-cmd.sh')
-rw-r--r-- | security/portaudit/files/portaudit-cmd.sh | 390 |
1 files changed, 330 insertions, 60 deletions
diff --git a/security/portaudit/files/portaudit-cmd.sh b/security/portaudit/files/portaudit-cmd.sh index 99fdcbde8bbd..1f90e921f9d2 100644 --- a/security/portaudit/files/portaudit-cmd.sh +++ b/security/portaudit/files/portaudit-cmd.sh @@ -1,4 +1,4 @@ -#!/bin/sh -e +#!/bin/sh -efu # # Copyright (c) 2004 Oliver Eikemeier. All rights reserved. # @@ -6,8 +6,8 @@ # modification, are permitted provided that the following conditions are # met: # -# 1. Redistributions of source code must retain the above copyright notice -# this list of conditions and the following disclaimer. +# 1. Redistributions of source code must retain the above copyright notice +# this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the @@ -31,35 +31,325 @@ # $FreeBSD$ # -. %%DATADIR%%/portaudit.functions +portaudit_confs() +{ + portaudit_dir=${portaudit_dir:-"%%DATABASEDIR%%"} + portaudit_filename=${portaudit_filename:-"auditfile.tbz"} + + portaudit_fetch_env=${portaudit_fetch_env:-} + portaudit_fetch_cmd=${portaudit_fetch_cmd:-"fetch -1amp"} + + portaudit_sites=${portaudit_sites:-"http://www.FreeBSD.org/ports/"} + + if [ -r %%PREFIX%%/etc/portaudit.conf ]; then + . %%PREFIX%%/etc/portaudit.conf + fi +} + +extract_auditfile() +{ + %%BZIP2_CMD%% -dc -- "$portaudit_dir/$portaudit_filename" | \ + tar -xOf - auditfile +} + +checksum_auditfile() +{ + chksum1=`extract_auditfile | + sed -nE -e '$s/^#CHECKSUM: *MD5 *([0-9a-f]{32})$/\1/p'` + chksum2=`extract_auditfile | sed -e '$d' | md5` + [ "$chksum1" = "$chksum2" ]; +} + +getcreated_auditfile() +{ + extract_auditfile | + sed -nE -e '1s/^#CREATED: *([0-9]{4})-?([0-9]{2})-?([0-9]{2}) *([0-9]{2}):?([0-9]{2}):?([0-9]{2}).*$/\1-\2-\3 \4:\5:\6/p' +} + +gettimestamp_auditfile() +{ + extract_auditfile | + sed -nE -e '1s/^#CREATED: *([0-9]{4})-?([0-9]{2})-?([0-9]{2}).*$/\1\2\3/p' +} + +checkexpiry_auditfile() +{ + created=`gettimestamp_auditfile` + expiry=`date -u -v-$1d '+%Y%m%d'` + [ "$created" -gt "$expiry" ]; +} + +portaudit_prerequisites() +{ + if $prerequisites_checked; then + return 0 + fi + + if [ -z "${pkg_info:-}" ]; then + if [ -x "%%LOCALBASE%%/sbin/pkg_info" ]; then + pkg_info="%%LOCALBASE%%/sbin/pkg_info" + else + pkg_info="/usr/sbin/pkg_info" + fi + fi + + if [ -z "${pkg_version:-}"]; then + case "$pkg_info" in + */*) + pkg_version="${pkg_info%/*}/pkg_version";; + *) + pkg_version="pkg_version";; + esac + fi + + PKG_INSTALL_VER=`$pkg_info -qP 2>/dev/null` + if [ -z "$PKG_INSTALL_VER" -o "$PKG_INSTALL_VER" -lt %%REQPKGVER%% ]; then + echo "$pkg_info is too old, please update port sysutils/pkg_install-devel" + return 1 + fi + + if [ ! -r "$portaudit_dir/$portaudit_filename" ]; then + echo "portaudit: Database missing, run \`portaudit -F' to update." >&2 + return 2 + elif ! checksum_auditfile; then + echo "portaudit: Corrupt database." >&2 + return 2 + elif ! checkexpiry_auditfile 14; then + echo "portaudit: Database too old." >&2 + return 2 + fi + + prerequisites_checked=true + return 0 +} + +audit_installed() +{ + local rc=0 + + extract_auditfile | awk -F\| ' + BEGIN { vul=0 } + /^(#|\$)/ { next } + { + cmd="'"$pkg_info"' -E \"" $1 "\"" + while((cmd | getline pkg) > 0) { + vul++ + split($2, ref, / /) + print "Affected package: " pkg + print "Type of problem: " $3 "." + for (r in ref) + print "Reference: <" ref[r] ">" + print "" + } + close(cmd) + } + END { + print vul " problem(s) in your installed packages found." + if (vul > 0) { + print "\nYou are advised to update or deinstall" \ + " the affected package(s) immediately." + exit(1) + } + } + ' || rc=$? + + return $rc +} + +audit_file() +{ + local rc=0 + local TMPFILE= + + case "$1" in + -) + TMPFILE=`mktemp -t portaudit` + cat > "$TMPFILE" + FILE="$TMPFILE" + ;; + http://*|ftp://*|https://*|file://*) + echo "portaudit: Can't audit remote file $1" >&2 + return 2 + ;; + *) + if [ -r "$1" ]; then + FILE="$1" + else + echo "portaudit: Can't read $1" >&2 + return 2 + fi + ;; + esac + + extract_auditfile | awk -F\| ' + BEGIN { vul=0 } + /^(#|\$)/ { next } + { + cmd="'"$pkg_version"' -T - \"" $1 "\" <\"'"$FILE"'\"" + while((cmd | getline pkg) > 0) { + vul++ + split($2, ref, / /) + split(pkg, p) + print "Affected package: " p[1] + print "Type of problem: " $3 "." + for (r in ref) + print "Reference: <" ref[r] ">" + print "" + } + close(cmd) + } + END { + print vul " problem(s) found." + if (vul > 0) { + exit(1) + } + } + ' || rc=$? + + if [ -n "$TMPFILE" ]; then + rm "$TMPFILE" + fi + return $rc +} + +audit_args() +{ + local VULCNT=0 + while [ $# -gt 0 ]; do + case "$1" in + /*|-) + echo "portaudit: $1 is a file, please use the -f option" >&2 + ;; + http://*|ftp://*|https://*|file://*) + echo "portaudit: Can't audit remote file $1" >&2 + ;; + *) + if VLIST=`extract_auditfile | grep -v '^#' | $pkg_version -T "$1" -`; then + VULCNT=$(($VULCNT+1)) + echo "$VLIST" | awk -F\| '{ + print "Affected package: '$1' (matched by " $1 ")" + print "Type of problem: " $3 "." + split($2, ref, / /) + for (r in ref) + print "Reference: <" ref[r] ">" + print "" + }' + fi + ;; + esac + shift + done + $opt_quiet || echo "$VULCNT problem(s) found." + if [ $VULCNT -gt 0 ]; then + return 1 + fi +} + +audit_cwd() +{ + if [ ! -r "Makefile" ]; then + echo "portaudit: No Makefile here" >&2 + return 2 + fi + + PKGNAME=`make -VPKGNAME 2>/dev/null || true"` + + if [ -z "$PKGNAME" ]; then + echo "portaudit: Can't determine the package name" >&2 + return 2 + fi + + if VLIST=`extract_auditfile | grep -v '^#' | $pkg_version -T "$PKGNAME" -`; then + echo "$VLIST" | awk -F\| '{ + print "Affected package: '$PKGNAME' (matched by " $1 ")" + print "Type of problem: " $3 "." + split($2, ref, / /) + for (r in ref) + print "Reference: <" ref[r] ">" + print "" + }' + return 1 + fi +} + +fetch_auditfile() +{ + local rc=2 + + if [ ! -d "$portaudit_dir" ]; then + if ! mkdir -p "$portaudit_dir"; then + echo "Couldn't create $portaudit_dir, try running \`portaudit -F' as root" >&2 + return 2 + fi + fi + if [ ! -w "$portaudit_dir" ]; then + echo "Couldn't write to $portaudit_dir, try running \`portaudit -F' as root" >&2 + return 2 + + fi + cd "$portaudit_dir" + if [ -r "$portaudit_filename" ]; then + cp -f "$portaudit_filename" "$portaudit_filename.old" + fi + + $opt_verbose && echo "Attempting to fetch from $portaudit_site." + urls=`echo "$portaudit_sites" | tr -s ' \t' '\n' | sed -E -e "s/?\$/$portaudit_filename"` + + if ! env $portaudit_fetch_env $portaudit_fetch_cmd $urls; then + echo "Couldn't fetch database." >&2 + elif [ ! -f "$portaudit_dir/$portaudit_filename" ] ; then + echo "portaudit: No database." >&2 + elif ! checksum_auditfile; then + echo "portaudit: Database corrupt." >&2 + elif ! checkexpiry_auditfile 7; then + echo "portaudit: Database too old." >&2 + else + $opt_quiet || echo "New database installed." + rc=0 + break + fi + + if [ -f "$portaudit_filename.old" ]; then + if [ $rc -eq 0 ]; then + rm -f "$portaudit_filename.old" + else + mv -f "$portaudit_filename.old" "$portaudit_filename" + $opt_quiet || echo "Old database restored." + fi + fi + if [ -f "$portaudit_filename" ]; then + chmod a=r "$portaudit_filename" + fi + + return $rc +} + portaudit_confs opt_audit=false opt_auditcwd=false -opt_audittree=false opt_dbversion=false opt_fetch=false opt_file= opt_quiet=false opt_verbose=false opt_version=false +opt_expiry= if [ $# -eq 0 ] ; then opt_audit=true fi -while getopts aACdf:FqvV opt; do +while getopts aCdf:FqvVX: opt; do case "$opt" in a) opt_audit=true;; - A) - opt_audittree=true;; C) opt_auditcwd=true;; d) opt_dbversion=true;; f) - opt_file=$OPTARG;; + opt_file="$OPTARG";; F) opt_fetch=true;; q) @@ -68,91 +358,71 @@ while getopts aACdf:FqvV opt; do opt_verbose=true;; V) opt_version=true;; + X) + opt_expiry="$OPTARG";; ?) - echo "Usage: $0 -aACvVdFq [-f file]" + echo "Usage: $0 -aCdF [-f file] [pkg-name ...]" exit 2;; esac done -shift $((${OPTIND}-1)) +shift $(($OPTIND-1)) + +ret=0 if $opt_version; then echo "portaudit version %%PORTVERSION%%" fi if $opt_fetch; then - fetch_auditfile || echo "failed." + if ! fetch_auditfile; then + echo "portaudit: Download failed." >&2 + exit 2 + fi +elif [ -n "$opt_expiry" ]; then + if [ ! -r "$portaudit_dir/$portaudit_filename" ] || ! checkexpiry_auditfile "$opt_expiry"; then + $opt_quiet || echo "Downloading fresh database." + if ! fetch_auditfile; then + echo "portaudit: Download failed." >&2 + exit 2 + fi + ret=1 + fi fi if $opt_dbversion; then - if [ ! -f "${portaudit_dir}/${portaudit_filename}" ]; then - echo "portaudit: database missing. run \`portaudit -F' to update." + if [ ! -f "$portaudit_dir/$portaudit_filename" ]; then + echo "portaudit: Database missing, run \`portaudit -F' to update." >&2 exit 2 fi if ! checksum_auditfile; then - echo "portaudit: database corrupt." + echo "portaudit: Database corrupt." >&2 exit 2 fi created=`getcreated_auditfile` - echo "database created: `/bin/date -j -f '%Y-%m-%d %H:%M:%S %Z' \"${created} GMT\"`" + echo "Database created: `date -j -f '%Y-%m-%d %H:%M:%S %Z' \"$created GMT\"`" fi +prerequisites_checked=false + if $opt_audit; then portaudit_prerequisites - audit_installed || true + audit_installed || ret=$? fi if $opt_auditcwd; then portaudit_prerequisites - audit_cwd -fi - -if $opt_audittree; then - echo "auditing ports tree for known vulnerabilities" - VULCNT=0 - - portaudit_prerequisites - - cd "${PORTSDIR:=/usr/ports}" - CATEGORIES=`echo [a-z]*` - - for category in ${CATEGORIES}; do - if [ ! -d "${PORTSDIR}/${category}" ]; then continue; fi - case "${category}" in - CVS) continue ;; - Mk) continue ;; - Templates) continue ;; - Tools) continue ;; - distfiles) continue ;; - packages) continue ;; - esac - - $opt_quiet || echo "==> ${category}" - - cd "${PORTSDIR}/${category}" - PORTS=`echo *` - - for port in ${PORTS}; do - if [ ! -d "${PORTSDIR}/${category}/${port}" ]; then continue; fi - case "${port}" in - pkg) continue ;; - CVS) continue ;; - esac - - cd "${PORTSDIR}/${category}/${port}" - audit_cwd; - done - done - - echo "${VULCNT} ports with unmarked vulnerabilities." + audit_cwd || ret=$? fi if [ -n "$opt_file" ]; then portaudit_prerequisites - audit_file "$opt_file" + audit_file "$opt_file" || ret=$? fi if [ $# -gt 0 ]; then portaudit_prerequisites - audit_args "$@" + audit_args "$@" || ret=$? fi + +exit $ret |