#!/bin/bash # login.defs and lib/getdef.c contain support for third party variables. # It also contains support for variables that are unusable in installations with PAM support enabled. # This script generates a list of used and unused variables in login.defs # with respect to the current configuration. # Arguments: arguments of osc build # If the shadow-login_defs-check-unused.lst is generated, you should # update login.defs. set -o errexit echo "Preparing..." # Check for required commands which quilt >/dev/null which osc >/dev/null # login.defs is shared with util-linux login, su and runuser. # Extract list of referenced variables. if ! test -f openSUSE:Factory/util-linux/BUILD/*/configure.ac ; then echo "Checking out util-linux..." if test -d ../util-linux ; then echo -n "../util-linux found. Are you preparing new version? (y/N) " read if test "${REPLY:0:1}" = "y" ; then mkdir -p openSUSE:Factory cp -a ../util-linux openSUSE:Factory/ else osc co openSUSE:Factory util-linux fi else osc co openSUSE:Factory util-linux fi cd openSUSE:Factory/util-linux quilt setup -d BUILD util-linux.spec cd BUILD/* quilt push -a cd ../../../.. fi echo "Extracting variables from util-linux..." cd openSUSE:Factory/util-linux/BUILD/* ( grep -rh getlogindefs . | sed -n 's/^.*getlogindefs[a-z_]*("\([A-Z0-9_]*\)".*$/\1/p' grep -rh logindefs_setenv . | sed -n 's/^.*logindefs_setenv*("[A-Z0-9_]*", "\([A-Z0-9_]*\)".*$/\1/p' ) | LC_ALL=C sort -u >../../../../shadow-login_defs-check-util-linux.lst cd ../../../.. # login.defs is shared pam_unix*.so, pam_faildelay.so and pam_umask.so. # Extract list of referenced variables. if ! test -f openSUSE:Factory/pam/BUILD/*/configure.ac ; then echo "Checking out pam..." if test -d ../pam ; then echo -n "../pam found. Are you preparing new version? (y/N) " read if test "${REPLY:0:1}" = "y" ; then mkdir -p openSUSE:Factory cp -a ../pam openSUSE:Factory/ else osc co openSUSE:Factory pam fi else osc co openSUSE:Factory pam fi cd openSUSE:Factory/pam quilt setup -d BUILD pam.spec cd BUILD/* quilt push -a cd ../../../.. fi echo "Extracting variables from pam..." cd openSUSE:Factory/pam/BUILD/* grep -rh LOGIN_DEFS . | sed -n 's/CRYPTO_KEY/\"HMAC_CRYPTO_ALGO\"/g;s/^.*search_key *([A-Za-z_]*, *[A-Z_]*LOGIN_DEFS, *"\([A-Z0-9_]*\)").*$/\1/p' | LC_ALL=C sort -u >../../../../shadow-login_defs-check-pam.lst cd ../../../.. if ! test -f shadow-login_defs-check-build/stamp ; then echo "Performing preprocessing of shadow by osc..." if ! test -f shadow.spec.shadow-login_defs-check-save ; then cp -a shadow.spec shadow.spec.shadow-login_defs-check-save # In case of shadow, variables extraction is more complicated. The list # depends on configure options, so we have to perform a fake build and # extract variables from prepreocessed sources. # sed -i '/^%make_build/i\_smp_mpflags="%{?_smp_mpflags} -k CPPFLAGS=\\"-E\\""' shadow.spec sed -i 's/^%make_build/%make_build -k CPPFLAGS=\\"-E\\"/' shadow.spec if cmp -s shadow.spec shadow.spec.shadow-login_defs-check-save ; then echo "$0: Please fix sed expression modifying shadow.spec." mv shadow.spec.shadow-login_defs-check-save shadow.spec exit 1 fi fi if osc build "$@" ; then echo "This build command was expected to fail, but it succeeded." echo "$0: Please fix sed expression modifying shadow.spec." mv shadow.spec.shadow-login_defs-check-save shadow.spec exit 1 else echo "This build command was expected to fail." echo "" fi mv shadow.spec.shadow-login_defs-check-save shadow.spec BUILD_ROOT=$(osc lbl | sed -n 's/^.*Using BUILD_ROOT=//p') BUILD_DIR=$(osc lbl | sed -n 's/^.* cd //p' | head -n1) rm -rf shadow-login_defs-check-build mkdir shadow-login_defs-check-build cp -a "$BUILD_ROOT/$BUILD_DIR"/shadow-* shadow-login_defs-check-build/ touch shadow-login_defs-check-build/stamp fi echo "Extracting list of deleted binaries..." sed -n 's~rm %{buildroot}/%{_\(s\|\)bindir}/\(.*\)$~\2~p' shadow-login_defs-check-deleted.lst # The build above is optional only for case of failure or edits in the # code below. If any other build was performed, don't expect correct # results. cd shadow-login_defs-check-build/shadow-* echo "Extracting variables from etc/login.defs..." # Extract variables referenced in login.defs, both active and commented out. sed -n "s/^#//;s/\([A-Z0-9_]*\)\([[:space:]].*\|\)$/\1/p" ../../shadow-login_defs-check-login_defs.lst LC_ALL=C sort -u ../../shadow-login_defs-check-login_defs.lst >../../shadow-login_defs-check-login_defs-sorted.lst echo "Extracting variables from lib/getdef.c..." # Extract variables referenced in lib/getdef.c using current defines. sed -n 's/^\(},\|\) {"\([A-Z0-9_]*\)", /\2/p' ../../shadow-login_defs-check-getdef.lst LC_ALL=C sort -u ../../shadow-login_defs-check-getdef.lst >../../shadow-login_defs-check-getdef-sorted.lst echo "Extracting variables from shadow..." # Extract variables referenced in preprocessed files. grep -r '\(getdef[a-z_]*\|call_script\|is_listed\) *( *"[A-Za-z0-9_]*"' | grep '[^ ]*\.o:' >../../shadow-login_defs-check-shadow.log cd ../.. export RC=0 echo "" echo "" echo "Performing checks..." sed ' s/^.*\(getdef[a-z_]*\|call_script\|is_listed*\) *( *"\([A-Za-z0-9_]*\)".*$/\2/ ' ../../shadow-login_defs-check-shadow-all.lst sed 's%^\(.*\)%/^.*\\\/\1\.o:/d%' shadow-login_defs-check-deleted.sed sed -f shadow-login_defs-check-deleted.sed shadow-login_defs-check-shadow-used.lst if ! test -s shadow-login_defs-check-deleted.sed ; then echo " BUG: Empty shadow-login_defs-check-deleted.sed Results will be unreliable!" if test $RC -le 4 ; then export RC=4 ; fi fi echo "" echo "Checking that variables in login.defs are referred only once..." if test $(wc -l shadow-login_defs-check-login_defs.lst | sed 's/ .*//') != $(wc -l shadow-login_defs-check-login_defs-sorted.lst | sed 's/ .*//') ; then echo " ERROR: Some variable referred at more places of login.defs!" LC_ALL=C sort shadow-login_defs-check-login_defs.lst >shadow-login_defs-check-login_defs-sorted-nu.lst diff shadow-login_defs-check-login_defs-sorted-nu.lst shadow-login_defs-check-login_defs-sorted.lst if test $RC -le 3 ; then export RC=3 ; fi fi echo "" echo "Checking that variables in lib/getdef.c are referred only once..." if test $(wc -l shadow-login_defs-check-getdef.lst | sed 's/ .*//') != $(wc -l shadow-login_defs-check-getdef-sorted.lst | sed 's/ .*//') ; then echo " ERROR: Some variable referred at more places of lib/getdef.c!" LC_ALL=C sort shadow-login_defs-check-getdef.lst >shadow-login_defs-check-getdef-sorted-nu.lst diff shadow-login_defs-check-getdef-sorted-nu.lst shadow-login_defs-check-getdef-sorted.lst if test $RC -le 3 ; then export RC=3 ; fi fi cat shadow-login_defs-check-shadow-used.lst shadow-login_defs-check-util-linux.lst shadow-login_defs-check-pam.lst | LC_ALL=C sort -u >shadow-login_defs-check-all-used.lst # RC inside pipe cannot be read directly. Use 3 for a real stdout inside the pipe, and use stdout for RC. exec 3>&1 function report_packages() { echo -n " (" grep -l $1 shadow-login_defs-check-{shadow-used,util-linux,pam}.lst | sed 's/shadow-login_defs-check-//;s/\.lst//;s/-used//;s/$/, /;$s/, $//' | tr -d '\n' echo -n ")" } # Extracting variables from shadow is not capable to identify compiled-but-unused library code. # This function will identify known false matches. function falsematch() { case "$1" in # MAIL_* used by library call mailcheck() used only by login.c that is deleted in the spec. MAIL_* ) return 0 ;; # FTMP_FILE used by library call failtmp() used only by login.c that is deleted in the spec. FTMP_FILE ) return 0 ;; # ISSUE_FILE used by library call login_prompt() used only by login.c that is deleted in the spec. ISSUE_FILE ) return 0 ;; # PREVENT_NO_AUTH us used only by login.c and su.c that are deleted in the spec. PREVENT_NO_AUTH ) return 0 ;; * ) return 1 ;; esac } echo "" echo "Checking that all used variables are covered by login.defs..." RC=$(cat shadow-login_defs-check-all-used.lst | ( while read ; do if falsematch "$REPLY" ; then echo " FALSE MATCH: Variable $REPLY is not present in login.defs$(report_packages $REPLY)" >&3 continue fi if ! grep -q -x "$REPLY" shadow-login_defs-check-login_defs-sorted.lst ; then echo " NOTICE: Variable $REPLY is not present in login.defs$(report_packages $REPLY)" >&3 if test $RC -le 2 ; then RC=2 ; fi fi done echo $RC ) ) echo "" echo "Checking that all used variables are covered by lib/getdef.c..." RC=$(cat shadow-login_defs-check-all-used.lst | ( while read ; do if falsematch "$REPLY" ; then continue ; fi if ! grep -q -x "$REPLY" shadow-login_defs-check-getdef.lst ; then echo " ERROR: Variable $REPLY is missing in the parser$(report_packages $REPLY)" >&3 if test $RC -le 3 ; then RC=3 ; fi fi done echo $RC ) ) echo "" echo "Checking that all used variables referred in login.defs are valid..." RC=$(cat shadow-login_defs-check-login_defs.lst | ( while read ; do if ! grep -q -x "$REPLY" shadow-login_defs-check-all-used.lst ; then echo " ERROR: Failed to find reference for $REPLY" >&3 if test $RC -le 3 ; then RC=3 ; fi fi if ! grep -q -x "$REPLY" shadow-login_defs-check-getdef.lst ; then echo " BUG: Parser does not contain reference for $REPLY" >&3 if test $RC -le 4 ; then RC=4 ; fi fi done echo $RC ) ) echo "" echo "" echo "All checks finished." echo -n "Result: " case $RC in 0) echo "OK." ;; 1) echo "Notices only. Action is optional." ;; 2) echo "Warnings only. Evaluation is needed." ;; 3) echo "Errors found. Fix is recommended." ;; 4) echo "Fatal error. Fix has to be done." ;; esac if test $RC -ge 1 ; then exit 1 fi echo " If you ported shadow-util-linux.patch to the new util-linux version, please submit these updates: Change in util-linux.spec:" sed -n 's/^Version:[[:space:]]*/Requires: login_defs-support-for-util-linux >= /p' = /p'