File: //usr/share/sendmail/update_db
#!/bin/sh -e
#-----------------------------------------------------------------------------
#
# $Sendmail: update_db,v 8.15.2 2021-03-16 16:04:16 cowboy Exp $
#
# Update Sendmail databases for Debian
#
# Copyright (c) 1998-2010 Richard Nelson. All Rights Reserved.
#
# Notes (to all):
# * assumes makemap dbtype /etc/mail/database < /etc/mail/database
#
# Notes (to self):
# * changes made herein *must* be reflected in
# parse_mc,update_mk,update_db,debian.m4
# * multiple db options not supported
# * userdb can also have multiple databases and then a forward!
# * need sendmail stop/start
#
#-----------------------------------------------------------------------------
set -e;
# List of db files/features/etc
db_files="databases Makefile crontab QUEUE_GROUP sendmail.cf submit.cf \
confCR_FILE confCT_FILE confCW_FILE confUSERDB_SPEC \
access_db authinfo bitdomain domaintable \
genericstable mailertable uucpdomain \
use_cw_file use_ct_file virtusertable ALIAS_FILE";
# Path to other sendmail helpers
if [ -x ./update_sendmail ]; then
sm_path='.';
elif [ -x $(dirname $0)/update_sendmail ]; then
sm_path=$(dirname $0);
else
sm_path=/usr/share/sendmail;
fi;
# Bring in sendmail.conf for the network definitions
if [ ! -f /etc/mail/sendmail.conf ]; then
if [ -x $sm_path/update_conf ]; then
$sm_path/update_conf;
fi;
fi;
if [ -f /etc/mail/sendmail.conf ]; then
. /etc/mail/sendmail.conf;
fi;
if [ "$HANDS_OFF" != 'No' ]; then
exit 0;
fi;
# control amount of output
verbosity=0;
# flag used to ensure only one newaliases command is run
newaliases_run=0;
# flag used to indicate a dataset has been moved, may need another update
changed=0;
# max return code
max_rc=0;
missing_rqd=0;
missing_opt=0;
missing_cre=0;
m4_errors=0;
#-------------------------------------------------------------
# Initial update of sendmail.mc/databases
#-------------------------------------------------------------
initial () {
if [ $verbosity -gt 1 ]; then
echo "initial()";
fi;
# Sigh... I wish this was in Perl...
$sm_path/parse_mc || true;
};
#-------------------------------------------------------------
# Handle found databases
#-------------------------------------------------------------
is_found () {
if [ $verbosity -gt 1 ]; then
echo "is_found: $dbfeat - $dbname";
fi;
process=1;
case "$dbfeat" in
ALIAS_FILE)
if [ -f /etc/mail/aliases ] & [ ! -f /etc/aliases ]; then
echo "Moving /etc/mail/aliases to /etc/aliases";
mv /etc/mail/aliases /etc/aliases;
ln -sf ../aliases /etc/mail/aliases;
fi;
;;
submit.cf)
if [ ! -f /usr/share/sendmail/cf/feature/msp.m4 ]; then
rm -f /etc/mail/submit.cf 2>/dev/null;
rm -f /etc/mail/submit.cf.errors 2>/dev/null;
process=0;
fi;
;;
*)
;;
esac;
};
#-------------------------------------------------------------
# Handle missing databases:
# moving /etc/xxx to /etc/mail/xxx
# rename /etc/mail/xxx to /etc/mail/yyy
#-------------------------------------------------------------
move_file () {
if [ -f $1 ]; then
if [ ! -L $1 ]; then
echo "Moving $1 to $dbname.";
mv $1 $dbname;
chown root:smmsp $dbname;
chmod 0644 $dbname;
if [ -f $1.db ]; then
mv -f /etc/$1.db $dbname.db;
fi;
if [ -f $1.pag ]; then
mv -f /etc/$1.pag $dbname.pag;
fi;
if [ -f $1.dir ]; then
mv -f /etc/$1.dir $dbname.dir;
fi;
changed=1;
process=1;
else
echo "$1 is a link, move it to $dbname";
if [ "$dbopts" = "-o" ]; then
missing_opt=`expr $missing_opt + 1`;
else
missing_rqd=`expr $missing_rqd + 1`;
fi;
fi;
true;
else
false;
fi;
};
rename_file () {
if [ -f /etc/mail/$1 ]; then
echo "Renaming /etc/mail/$1 to $dbname.";
mv /etc/mail/$1 $dbname;
chown root:smmsp $dbname;
chmod 0644 $dbname;
changed=1;
process=1;
true;
else
false;
fi;
};
is_not_found () {
if [ $verbosity -gt 1 ]; then
echo "is_not_found: $dbfeat - $dbname";
fi;
case "$dbfeat" in
databases|Makefile)
:;
;;
use_cw_file|confCW_FILE)
if move_file /etc/local-host-names; then
:;
elif rename_file sendmail.cw; then
:;
elif move_file /etc/sendmail.cw; then
:;
else
missing_cre=`expr $missing_cre + 1`;
echo "Warning: $dbfeat source" \
"file not found: $dbname";
echo " it was created";
echo "localhost" > $dbname;
echo `hostname -f` >> $dbname;
chown root:smmsp $dbname;
chmod 0644 $dbname;
fi;
;;
use_ct_file|confCT_FILE)
if move_file /etc/trusted-users; then
:;
elif rename_file sendmail.ct; then
:;
elif move_file /etc/sendmail.ct; then
:;
else
missing_cre=`expr $missing_cre + 1`;
echo "Warning: $dbfeat source" \
"file not found: $dbname";
echo " it was created";
touch $dbname;
chown root:smmsp $dbname;
chmod 0644 $dbname;
fi;
;;
HELP_FILE)
if move_file /etc/sendmail.hf; then
:;
elif rename_file sendmail.hf; then
:;
else
echo "Error: $dbfeat source file not found: $dbname";
missing_rqd=`expr $missing_rqd + 1`;
process=0;
fi;
;;
ALIAS_FILE)
if [ -e /etc/$dbsname ]; then
echo "Linking /etc/$dbsname to $dbname";
ln -sf ../$dbsname $dbname;
if [ -f /etc/$dbsname.db ]; then
mv /etc/$dbsname.db /etc/mail;
fi;
if [ -f /etc/$dbsname.pag ]; then
mv /etc/$dbsname.pag /etc/mail;
fi;
if [ -f /etc/$dbsname.dir ]; then
mv /etc/$dbsname.dir /etc/mail;
fi;
elif [ "$dbopts" = "-o" ]; then
echo "Informational: $dbfeat source" \
"file not found: $dbname";
missing_opt=`expr $missing_opt + 1`;
process=0;
else
echo "Error: $dbfeat source file not found: $dbname";
missing_rqd=`expr $missing_rqd + 1`;
process=0;
fi;
;;
*.cf)
mcfile=$(echo "$dbsname" | sed -e 's/\..*//')
if move_file /etc/$dbsname; then
if [ -f /etc/${mcfile}.cf ]; then
mv -f /etc/${mcfile}.cf /etc/mail/;
fi;
elif [ "$mcfile" = "sendmail" ]; then
cp /usr/share/sendmail/cf/debian/sendmail.mc \
$dbname;
chown root:smmsp $dbname;
chmod 0644 $dbname;
elif [ "$mcfile" = "submit" ]; then
cp /usr/share/sendmail/cf/debian/submit.mc \
$dbname;
chown root:smmsp $dbname;
chmod 0644 $dbname;
elif [ "$dbopts" = "-o" ]; then
echo "Informational: $dbfeat source" \
"file not found: $dbname";
missing_opt=`expr $missing_opt + 1`;
process=0;
else
echo "Error: $dbfeat source file not found: $dbname";
missing_rqd=`expr $missing_rqd + 1`;
process=0;
fi;
;;
QUEUE_GROUP)
echo "Warning: $dbfeat source" \
"file not found: $dbname";
echo " it was created";
mkdir -p $dbname;
chown root:smmsp $dbname;
chmod 02750 $dbname;
;;
crontab)
if [ -x $sm_path/update_conf ]; then
$sm_path/update_conf;
fi;
;;
access_db)
missing_cre=`expr $missing_cre + 1`;
echo "Warning: $dbfeat source" \
"file not found: $dbname";
echo " it was created";
cp /usr/share/sendmail/examples/db/access \
/etc/mail/;
chown root:root $dbname;
chmod 0644 $dbname;
;;
*)
if move_file /etc/$dbsname; then
:;
elif [ "$dbopts" = "-o" ]; then
:;
else
missing_cre=`expr $missing_cre + 1`;
echo "Warning: $dbfeat source" \
"file not found: $dbname";
echo " it was created";
touch $dbname;
chown root:smmsp $dbname;
chmod 0644 $dbname;
fi;
;;
esac;
};
#-------------------------------------------------------------
# Handle empty databases
#-------------------------------------------------------------
is_empty () {
if [ $verbosity -gt 1 ]; then
echo "is_empty: $dbfeat - $dbname";
fi;
if [ $process -eq 1 ]; then
if [ "$dbtype" != "-" ]; then
rm -f $dbname.db;
rm -f $dbname.pag;
rm -f $dbname.dir;
fi;
case "$dbfeat" in
databases|Makefile)
:;
;;
access_db)
cp /usr/share/sendmail/examples/db/access \
/etc/mail/;
chown root:root $dbname;
chmod 0644 $dbname;
;;
*)
echo "Informational: $dbfeat file empty: $dbname";
if [ "$dbopts" = "-o" ]; then
process=0;
fi;
;;
esac;
fi;
};
#-------------------------------------------------------------
# Handle no data (exists, but is only comments) databases
#-------------------------------------------------------------
is_comments () {
if [ $verbosity -gt 1 ]; then
echo "is_comments: $dbfeat - $dbname";
fi;
if [ $process -eq 1 ] && [ -s "$dbname" ]; then
if [ "$dbtype" != "-" ]; then
rm -f $dbname.db;
rm -f $dbname.pag;
rm -f $dbname.dir;
fi;
case "$dbfeat" in
databases|Makefile)
:;
;;
*)
echo "Informational: $dbfeat no data: $dbname";
if [ "$dbopts" = "-o" ]; then
process=0;
fi;
;;
esac;
fi;
};
#-------------------------------------------------------------
# Handle normal databases (exists, has data)
#-------------------------------------------------------------
is_normal () {
if [ $verbosity -gt 1 ]; then
echo "is_normal: $dbfeat - $dbname";
fi;
# Make sure sensitive databases are *not* generally readable
if [ "$dbsname" = "authinfo" ] \
|| [ "$dbsname" = "access" ]; then
chmod go-rwx $dbname;
fi;
if [ $process -eq 1 ] && [ $max_rc -eq 0 ]; then
case "$dbtype" in
'-'|text|ldap)
:;
;;
parse_mc)
$sm_path/parse_mc || true;
;;
update_conf)
$sm_path/update_conf || true;
;;
update_mk)
$sm_path/update_mk || true;
;;
btree)
echo "Updating $dbname...";
/usr/sbin/makemap -d $dbtype $dbname.new.db < $dbname;
chown root:smmsp $dbname.new.db;
chmod 0644 $dbname.new.db;
mv -f $dbname.new.db $dbname.db;
;;
dbm | btree | hash)
echo "Updating $dbname...";
/usr/sbin/makemap $dbtype $dbname.new.db < $dbname;
if [ "$dbsname" = "authinfo" ] \
|| [ "$dbsname" = "access" ]; then
chown smmta:smmsp $dbname.new.db;
chmod 0640 $dbname.new.db;
else
chown root:smmsp $dbname.new.db;
chmod 0640 $dbname.new.db;
fi;
mv -f $dbname.new.db $dbname.db;
;;
newaliases)
echo "Updating $dbname...";
if [ $newaliases_run -eq 0 ]; then
newaliases_run=1;
/usr/libexec/sendmail/newaliases || true;
fi;
if [ -f $dbname.db ]; then
chown smmta:smmsp $dbname.db;
chmod 0640 $dbname.db;
fi;
;;
m4)
mcfile=$(echo "$dbsname" | sed -e 's/\..*//');
echo "Creating /etc/mail/${mcfile}.cf...";
rm -f /etc/mail/${mcfile}.cf.errors;
m4 /etc/mail/${mcfile}.mc \
> /etc/mail/${mcfile}.cf.new \
2> /etc/mail/${mcfile}.cf.errors || true;
echo "### /etc/mail/${mcfile}.mc ###" \
>> /etc/mail/${mcfile}.cf.new;
sed -e 's/^/# /' /etc/mail/${mcfile}.mc \
>> /etc/mail/${mcfile}.cf.new;
chown root:smmsp /etc/mail/${mcfile}.cf.new;
chmod 0644 /etc/mail/${mcfile}.cf.new;
if [ ! -s /etc/mail/${mcfile}.cf.errors ]; then
rm -f /etc/mail/${mcfile}.cf.errors;
else
chown root:smmsp /etc/mail/${mcfile}.cf.errors;
cat /etc/mail/${mcfile}.cf.errors;
echo " ";
m4_errors=1;
fi;
# Can't tell if the errors are fatal or not ;-{
mv -f /etc/mail/${mcfile}.cf.new \
/etc/mail/${mcfile}.cf;
;;
*)
echo "$dbtype map not done herein";
;;
esac;
fi;
};
#-------------------------------------------------------------
# Handle completion
#-------------------------------------------------------------
final () {
if [ $verbosity -gt 1 ]; then
echo "final()";
fi;
};
# status report if not for single database
if [ -z "$1" ]; then
echo "Checking {sendmail,submit}.mc and related databases...";
else
db_files="$1";
fi;
initial;
for file in $db_files; do \
line=$(grep -Ee "^[[:space:]]*$file" \
/etc/mail/databases || true);
while ([ "$line" != "" ]); do
str=$(echo "$line" | head -n 1)
line=$(echo "$line" | tail -n +2)
# Strip line back into four pieces: feature, type, opts, name
dbfeat=$(echo "$str" | cut -d ":" -f 1);
dbtype=$(echo "$str" | cut -d ":" -f 2);
dbopts=$(echo "$str" | cut -d ":" -f 3);
dbname=$(echo "$str" | cut -d ":" -f 4);
dbregx=$(echo "$str" | cut -d ":" -f 5);
if [ $(dirname "$dbname") = "/etc/mail" ]; then
dbsname=$(basename "$dbname");
elif [ $(dirname "$dbname") = "/etc" ]; then
dbsname=$(basename "$dbname");
else
dbsname="$dbname";
fi;
if [ "$dbopts" = "-" ]; then
dbopts="";
fi;
if [ "$dbregx" = "-" ]; then
dbregx="";
fi;
# Check to see if we're doing one, or all
if [ ! -z "$1" ]; then
if [ "$1" = "$dbfeat" ] \
|| [ "$1" = "$dbname" ] \
|| [ "$1" = "$dbsname" ]; then
:;
else
continue;
fi;
fi;
# Check for special database types
case "$dbtype" in
ldap)
if [ $verbosity -gt 0 ]; then
echo "Skipping $dbname...";
fi;
continue
;;
dbm | btree | hash)
if [ ! -x /usr/libexec/sendmail/makemap ]; then
echo "Delaying $dbname...";
continue;
fi;
;;
newaliases)
if [ ! -x /usr/libexec/sendmail/newaliases ]; then
echo "Delaying $dbname...";
continue;
fi;
;;
*)
;;
esac;
# Kluge for aliases...
if [ "$dbname" = "ldap" ]; then
continue;
fi;
if [ "$dbname" = "null" ]; then
continue;
fi;
process=1;
if [ $verbosity -gt 0 ]; then
echo "Processing $dbname...";
fi;
# Check for database existance
if [ -f "$dbname" ] || [ -d "$dbname" ]; then
is_found;
else
is_not_found;
fi;
# Skip the rest for directories
if [ ! -d "$dbname" ]; then
# Check for something in database
if [ ! -s "$dbname" ]; then
is_empty;
fi;
# Check for real data (not just comments)
if [ $process -eq 1 ]; then
if ! grep -qEe "^[[:space:]]*[^$\#]" $dbname; then
is_comments;
fi;
fi;
# Finally, assume a normal file...
is_normal;
fi;
done;
done;
final;
# Final notices...
if [ $changed -ne 0 ]; then
echo " ";
echo "Informational: Some changes were made to file locations";
echo " Make sure sendmail.cf is rebuilt";
if [ $max_rc -lt 1 ]; then
max_rc=1;
fi;
fi;
if [ $missing_opt -ne 0 ]; then
echo " ";
echo "Informational: $missing_opt optional database(s) sources";
echo " were not found, please investigate.";
fi;
if [ $missing_cre -ne 0 ]; then
echo " ";
echo "Warning: $missing_cre database(s) sources";
echo " were not found, (but were created)";
echo " please investigate.";
fi;
if [ $missing_rqd -ne 0 ]; then
echo " ";
echo "Error: $missing_rqd required database(s) sources";
echo " were not found, correct this before starting sendmail!";
if [ $max_rc -lt 2 ]; then
max_rc=2;
fi;
fi;
if [ $missing_opt -ne 0 ] || [ $missing_rqd -ne 0 ]; then
echo " ";
echo "$0 assumes that databases, and their source datasets";
echo "have the same base name (not counting the .db). If this is not";
echo "true, $0 can not rebuild your databases to make sure";
echo "they will work with the newer sendmail. You will have to do this";
echo "yourself - before starting sendmail.";
echo " ";
fi;
if [ $m4_errors -ne 0 ]; then
echo " ";
echo "Warning: These messages were issued while creating sendmail.cf";
echo " make sure they are benign before starting sendmail!";
echo " ";
if [ -f /etc/mail/sendmail.cf.errors ]; then
echo "Errors in generating sendmail.cf";
cat /etc/mail/sendmail.cf.errors;
fi;
if [ -f /etc/mail/submit.cf.errors ]; then
echo "Errors in generating submit.cf";
cat /etc/mail/submit.cf.errors;
fi;
echo " "
if [ $max_rc -lt 2 ]; then
max_rc=2;
fi;
fi;
exit $max_rc;