#!/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..." osc co openSUSE:Factory util-linux 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..." osc co openSUSE:Factory pam 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/^.*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. patch <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 ;; * ) 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'