#!/bin/ksh93 -- # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Check :include: aliases (in files configured in sendmail.cf) and .forward # files to make sure the files and their parent directory paths all have # proper permissions. And check the master alias file(s) too. # # For details see http://www.sendmail.com/sm/open_source/docs/vendor_info/sun/migration.html#Security # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Portions Copyright 2014 Jens Elkner. PATH=/bin # Check the group- and world-writable bits on the given file. function analyze { if [[ ! -e "$1" ]]; then print "$2: $1 does not exist" (( bogus_dirs++ )) return fi typeset PERMS=${ ls -Lldn "$1" ; } if [[ ${PERMS:5:1} == 'w' && ${PERMS:8:1} == 'w' ]]; then print "$2: $1 is group and world writable" (( bogus_dirs++ )) elif [[ ${PERMS:8:1} == 'w' ]]; then print "$2: $1 is world writable" (( bogus_dirs++ )) elif [[ ${PERMS:5:1} == 'w' ]]; then print "$2: $1 is group writable" (( bogus_dirs++ )) fi } # Break down the given file name into its components, and call analyze with # each of them. E.g., an argument of /usr/local/aliases/foo.list would call # analyze in turn with arguments: # * /usr/local/aliases/foo.list # * /usr/local/aliases # * /usr/local # * /usr function break_down { typeset j APATH="$1" while [[ -n ${APATH} ]]; do analyze "${APATH}" "$1" APATH=${APATH%/*} done } integer bogus_dirs=0 # global variable function doMain { typeset config=/etc/mail/sendmail.cf LINE arg typeset -a FILES FIELDS # These should be OK themselves, but other packages may have screwed up the # permissions on /etc or /etc/mail . And best to check in case non-standard # alias paths are used. while read LINE ; do if [[ ${LINE:0:2} == 'OA' ]]; then LINE=${LINE:2} elif [[ ${LINE:0:12} == 'O AliasFile=' ]]; then LINE=${LINE:12} else continue fi LINE=${LINE//,/ } # pathes should not contain whitespaces ;-) LINE=${LINE/*:} FILES+=( ${LINE} ) done < $config # Find all valid :include: files used in alias files configured in # sendmail.cf integer I=${#FILES[@]} for (( I--; I >= 0; I-- )) ; do [[ ! -r ${FILES[$I]} ]] && continue # analyze handles this while read LINE ; do [[ ${LINE:0:1} == '#' ]] && continue if [[ ${LINE} =~ :include: ]]; then LINE=${LINE/*:include:} LINE=${LINE%%,*} FILES+=( ${LINE} ) fi done < ${FILES[$I]} done # Check .forward files as well. If the argument "ALL" is given, do it for # everyone. If no argument to the script is given, just do it for the # current user. O/w, do it for all arguments. if (( ! $# )); then arg="${ id -run ; }" elif [[ $1 == 'ALL' ]] ; then arg='' else arg="$*" fi typeset OLDIFS="${IFS}" getent passwd ${arg} | while read LINE ; do IFS=: FIELDS=( ${LINE} ) IFS="${OLDIFS}" [[ -f ${FIELDS[5]}/.forward ]] && FILES+=( "${FIELDS[5]}/.forward" ) done break_down "${FILES[@]}" / (( ! bogus_dirs )) && print 'No unsafe directories found.' } X="[+NAME?check-permissions - check check permissions on mail rerouting files]"' [+DESCRIPTION?The check-permissions script is intended as a migration aid for \bsendmail\b(1M). It checks the \b/etc/mail/sendmail.cf\b file for all configured alias files, and checks the alias files for \b:include:\b files. It also checks for certain \b.forward\b files. For each file that check-permissions checks, it verifies that none of the parent directories are group- or world-writable. If any directories are overly permissive, it is reported. Otherwise it reports that no unsafe directories were found.] [+?As to which \b.forward\b files are checked, it depends on the arguments included on the command line. If no argument is given, the current user'"'"'s home directory is checked for the presence of a \b.forward\b file. If any arguments are given, they are assumed to be valid logins, and the home directory of each one is checked.] [+?If the special argument \bALL\b is given, the \bpasswd\b entry in the \b/etc/nsswitch.conf\b file is checked, and all password entries that can be obtained through the switch file are checked. In large domains, this can be time-consuming.] [+OPERANDS?The following operands are supported:] { [+\alogin\a?Checks the home directory for user \alogin\a.] [+ALL?Checks the home directory of all users.] } [h:help?Print this help and exit] [F:functions?Print out the list of all defined functionsi in this script and exit.] [T:trace]:[fnlist?A comma separated list of functions of this script to trace.] [+FILES]{ [+/etc/mail/sendmail.cf?Defines environment for sendmail.] [+/etc/mail/aliases?ASCII mail aliases file.] } [+SEE ALSO?\bgetent\b(1M), \bsendmail\b(1M), \baliases\b(4)] \n\n[\alogin\a] ' while getopts -a 'check-permissions' "${ print $X ; }" OPT ; do case "$OPT" in F) typeset +f ; exit 0 ;; T) [[ ${OPTARG} == 'ALL' ]] && \ typeset -ft ${ typeset +f ; } || typeset -ft ${OPTARG//,/ } ;; h) $0 --man ; exit ;; esac done X=$((OPTIND-1)) shift $X doMain "$@"