#!/bin/bash
##
## Ad-hoc Winbind auto-config script for Solaris 10 client
## Copyright (c) 2007 SATOH Fumiyasu @ OSS Technology Co., Japan
##                    <http://www.osstech.co.jp/>
##

set -u
umask 0022

PATH="/opt/osstech/bin:/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin:/sbin:/usr/sbin"
export PATH

t()
{
  echo
  echo "$@"
}

warn()
{
  echo "$0: WARNING: $1" 1>&2
}

err()
{
  echo "$0: ERROR: $1" 1>&2
}

die()
{
  err "$1"
  exit ${2:-1}
}

ping_ad()
{
  ldapsearch -x -h "$1" -l 10 -z none -b '' -s base 'objectClass=*' >/dev/null 2>&1
  return $?
}

## ======================================================================

root=""
cmd_usage="Usage: $0 TEMPLATEDIR"

if [ $# -ne 1 ]; then
  echo "$cmd_usage"
  exit 0
fi

tmpl_dir="$1"; shift
datetime="$(date +%Y%m%d%H%M%S)"

## ----------------------------------------------------------------------

echo "Winbind auto-config script for Solaris 10 client"

t "Preparing ..."
echo "datetime: $datetime"
echo "template directory: $tmpl_dir"

file_old_suffix=".$datetime.winbind-conf.old"

tmpl_dir="$tmpl_dir/conf"

admin_pass="$tmpl_dir/admin"

hosts_src="$tmpl_dir/hosts"
hosts_dst="$root/etc/hosts"
krb5_conf_src="$tmpl_dir/krb5.conf"
krb5_conf_dst="$root/opt/osstech/etc/krb5.conf"
smb_conf_src="$tmpl_dir/smb.conf"
smb_conf_dst="$root/opt/osstech/etc/samba/smb.conf"

nsswitch_conf_src="$root/etc/nsswitch.dns"
nsswitch_conf_dst="$root/etc/nsswitch.conf"
pam_conf_dst="$root/etc/pam.conf"
defaultdomain_dst="$root/etc/defaultdomain"

if type nawk >/dev/null 2>&1; then
  awk_cmd="nawk"
elif type awk >/dev/null 2>&1; then
  awk_cmd="awk"
else
  die "awk command not found" 1>&2
fi
echo "awk command: $awk_cmd"

read admin pass <"$admin_pass"
if [ -z "$admin" -o -z "$pass" ]; then
  die "AD administrator name and/or password not set: $admin_pass"
fi
echo "administrator name: $admin"

domain="$(sed -n 's/[ 	]*realm[ 	]=[ 	]//p' "$smb_conf_src" |tr A-Z a-z)"
if [ -z "$domain" ]; then
  die "AD domain not set: $smb_conf_src"
fi
echo "AD domain: $domain"

## Check environment
## ======================================================================

## Check domain controller(s) and create awk script to edit hosts file
## ----------------------------------------------------------------------

t "Checking domain controller(s) ..."

edit_hosts_awk=""

while read ip names; do
  ip="${ip###*}"
  names="${names%%#*}"
  [ -z "$ip" ] && continue
  [ -z "$names" ] && continue
  echo "domain controller: $names ($ip)"

  ping_ad "$ip"
  if [ $? -ne 0 ]; then
    set -- $names
    die "domain controller does not respond"
  fi

  smbclient_out="$(smbclient -L "$ip" -U"$admin%$pass" -d0 >/dev/null 2>&1)"
  if [ $? -ne 0 ]; then
    die "domain controller reject administrator <$admin> to connect: $smbclient_out"
  fi

  names_notresolved=""
  for name in $names; do
    ping_ad "$name"
    if [ $? -ne 0 ]; then
      names_notresolved="$names_notresolved $name"
    fi
  done

  if [ -n "$names_notresolved" ]; then
    edit_hosts_awk="$edit_hosts_awk"'
      $1=="'$ip'" && !name["'"$name"'"] {
	$0 = $0"'"$names_notresolved"'"
	ip["'"$ip"'"] = name["'"$name"'"] = 1
      }
      END {
	if (!ip["'"$ip"'"]) {
	  print "'"$ip\t${names_notresolved## }"'"
	}
      }
    '
  fi
done <"$hosts_src"

## Check my hostname
## ----------------------------------------------------------------------

t "Checking my hostname"

my_name="$(hostname |sed 's/\.*//')"

## Check if we can retrieve my FQDN through gethostbyname(nodename).
## See also samba-3.0.*/source/lib/util.c:name_to_fqdn()...
get_my_fqdn_or_ip_perl='
  ## FIXME: Check if gethostbyname fails
  ($name, $aliases, $x, $x, $addr) = gethostbyname("'"$my_name"'");
  ## FIXME: We ignore 2nd and more addresses now
  $ip = join(".", unpack("C4", $addr));
  $fqdn = (grep(/\./, $name, split(/\s+/, $aliases)))[0];
  if (!defined($fqdn)) {
    print "$ip\n";
    exit(1);
  }
  print "$fqdn\n";
  exit(0);
'

my_fqdn_or_ip="$(perl -e "$get_my_fqdn_or_ip_perl")"
if [ $? -eq 0 ]; then
  my_fqdn="$my_fqdn_or_ip"
else
  my_ip="$my_fqdn_or_ip"
  my_fqdn="$my_name.$domain"
  edit_hosts_awk="$edit_hosts_awk"'
    $1=="'$my_ip'" {
      $0 = $0"'" $my_fqdn"'"
      my_ip = 1
    }
    END {
      if (!my_ip) {
	print "'"$my_ip\t$my_fqdn"'"
      }
    }
  '
fi

echo "hostname: $my_fqdn"

## Backup current files
## ======================================================================

t "Backuping current config files ..."

for name in hosts krb5_conf smb_conf nsswitch_conf pam_conf defaultdomain; do
  eval 'file="$'"$name"'_dst"'
  file_old="$file$file_old_suffix"
  eval "$name"'_old="$file_old"'
  echo -n "config file: $file"
  [ -f "$file" ] || { echo " not found (skipped)"; continue; }
  [ -f "$file_old" ] && die "backup file already exists: $file_old"
  echo " -> $file_old"
  cp -p "$file" "$file_old"
done

## Apply configs for Samba/Winbind
## ======================================================================

t "Applying configs for Samba/Winbind ..."

echo "config file: $hosts_dst"
"$awk_cmd" "$edit_hosts_awk {print}" <"$hosts_old" >"$hosts_dst"

echo "config file: $krb5_conf_dst"
cp "$krb5_conf_src" "$krb5_conf_dst"

echo "config file: $smb_conf_dst"
cp "$smb_conf_src" "$smb_conf_dst"

## ----------------------------------------------------------------------

t "Joining Samba/Winbind to AD domain ..."

net ads join -U "$admin%$pass"
if [ $? -ne 0 ]; then
  die "cannot join to AD domain"
fi

## Apply configs for NSS/PAM
## ======================================================================

t "Applying configs for NSS/PAM ..."

echo "config file: $nsswitch_conf_dst"
"$awk_cmd" '$1=="passwd:" || $1=="group:" {$0=$0" winbind"}{print}' \
  <$nsswitch_conf_src \
  >$nsswitch_conf_dst

echo "config file: $pam_conf_dst"
awk '
    $0 ~ /^#/ {
      ## Comment
      print
      next
    }
    $4 ~ /^pam_winbind\.so/ {
      ## Remove old pam_winbind config
      next
    }
    $2 == "auth" && $4 ~ /^pam_authtok_get\.so/ {
      print
      print $1"\tauth sufficient\t\tpam_winbind.so.1 use_first_pass"
      next
    }
    $2 == "account" && $4 ~ /^pam_unix_account\.so/ {
      print $1"\taccount sufficient\tpam_winbind.so.1"
      print
      next
    }
    {
      print
    }
  ' \
  <"$pam_conf_old" \
  >"$pam_conf_dst"

## Adjust services
## ======================================================================

## Start Winbind service
## ----------------------------------------------------------------------

t "Activating Winbind service ..."

/etc/init.d/winbind stop
/etc/init.d/winbind off

sleep 2

/etc/init.d/winbind start
/etc/init.d/winbind on

## Stop NIS client
## ----------------------------------------------------------------------

t "Disactivating NIS client service ..."

svcadm disable network/nis/client
svcadm disable name-service-cache
rm -f "$defaultdomain_dst"
# rename /var/yp/binding/domain/ypservers  or /var/yp/binding/*/ypservers?

## ======================================================================

echo
echo "Done."

