#!/bin/bash

# 
# This script creates a Linux- and Samba-Machine-Account in an LDAP-tree.
# It must be run prior to adding the SMB-client to the domain.
# 
# Usage:
#   ./create-machine-account.sh NewMachineName$ <I>
#   (Mind the trailing "$" !)
# The optional option "I" activates "interactive" mode.
# 
# http://homex.subnet.at/~max/ldap/
# 


# # # OPTIONS # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# Default UID to use if no other MachineAccount can be found.
# (The first machine will be $DEFAULTUID + 1.)
DEFAULTUID=20000

# The Default GID is used for every machine account.
# The according group is created if it doesn't already exist.
GIDNUMBER=20000

# If set to "yes", the script queries the user for the rootbinddn-password if
# it can't be found in /etc/ldap.secret. Error-messages are printed to stdout.
# (Interactive mode can be activated by 2nd command-line-option "I".)
# 
# If set to "no", script does not query the user for the rootbinddn-password
# but exits with an error-code. (This should/must be used if the script is to
# be run by Samba to automatically create a joining-machine's account.)
# Error-messages are logged using /usr/bin/logger.
INTERACTIVE=no
if [ X_$2 == "X_I" ]; then
	INTERACTIVE=yes
fi


# # # NOTHING TO CHANGE BELOW HERE  # # # # # # # # # # # # # # # # # # # # # # # # # #

# Check for /usr/bin/logger if not run interactively:
if [ X$INTERACTIVE == "Xyes" ] && [ ! -x /usr/bin/logger ]; then
	/bin/echo "ERROR: /usr/bin/logger not installed and not run interactively."
	exit 1
fi

# Check usage:
if [ -z $1 ] || [ ! -z $3 ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "Usage: $0 NewMachineName$ <I>"
		/bin/echo "       (Mind the trailing \"$\".)"
	else
		/usr/bin/logger "create-machine-account: Usage: \"$0 NewMachineName$\ <I>\", mind the trailing \"$\"."
		/usr/bin/logger "create-machine-account: I was called similar to: \"$0 $1\""
	fi
	exit 1
fi
# Check usage: check for a trailing "$":
/bin/echo ${1} | /bin/grep \$$ > /dev/null
if [ $? != "0" ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "Usage: $0 NewMachineName$ <I>"
		/bin/echo "       (Mind the trailing \"$\".)"
	else
		/usr/bin/logger "create-machine-account: Usage: \"$0 NewMachineName$\ <I>\", mind the trailing \"$\"."
		/usr/bin/logger "create-machine-account: I was called similar to: \"$0 $1\""
	fi
	exit 1
fi


# Get the current values to connect to the LDAP-server:
ROOTBINDDN=`/bin/grep "^rootbinddn " /etc/pam_ldap.conf`
if [ ! $? == "0" ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "ERROR: Could not read the rootbinddn to connect to the LDAP-server."
	else
		/usr/bin/logger "create-machine-account: ERROR: Could not read the rootbinddn to connect to the LDAP-server."
	fi
	exit 3
fi
ROOTBINDDN=`/bin/echo $ROOTBINDDN | /usr/bin/awk '{print $2}'` 

URI=`/bin/grep "^uri " /etc/pam_ldap.conf`
if [ ! $? == "0" ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "ERROR: Could not read the uri to connect to the LDAP-server."
	else
		/usr/bin/logger "create-machine-account: ERROR: Could not read the uri to connect to the LDAP-server."
	fi
	exit 3
fi
URI=`/bin/echo $URI | /usr/bin/awk '{print $2}'`

SECRET=`/bin/cat /etc/ldap.secret`
if [ ! $? == "0" ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "NOTE: Could not read the password to connect to the LDAP-server."
		read -s -p "      Please enter the password for $ROOTBINDDN: " SECRET
		/bin/echo
	else
		/usr/bin/logger "create-machine-account: ERROR: Could not read the password to connect to the LDAP-server."
		exit 3
	fi
fi


# Need to find the highest uidNumber of any already existing machine-account:
HIGHEST=`/usr/bin/ldapsearch -b "ou=People,dc=subnet,dc=at" -H $URI -D "$ROOTBINDDN" -w $SECRET -x "(&(objectClass=posixAccount)(gecos=MachineAccount))" | /bin/grep "uidNumber: " | /usr/bin/awk '{print $2}' | /usr/bin/sort | /usr/bin/tail -n 1`
if [ -z $HIGHEST ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "WARNING: No machine account found. Using default uidNumber $DEFAULTUID as reference."
	else
		/usr/bin/logger "create-machine-account: WARNING: No machine account found. Using default uidNumber $DEFAULTUID as reference."
	fi
	HIGHEST=$DEFAULTUID
fi

# Use the highest+1 uidNumber for this new account:
UIDNUMBER=$[$HIGHEST + 1]

# Find out, whether this $UIDNUMBER is already used as a uidNumber somewhere:
LDAPRETURN=`/usr/bin/ldapsearch -b "ou=People,dc=subnet,dc=at" -H $URI -D "$ROOTBINDDN" -w $SECRET -x "(uidNumber=$UIDNUMBER)" | /bin/grep "uid: "`
if ! [ "X" == "X$LDAPRETURN" ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "ERROR: The uidNumber $UIDNUMBER is already in use by an account"
		/bin/echo "       which isn't a gecos: MachineAccount!"
		/bin/echo "       Please resolve this by hand!"
	else
		/usr/bin/logger "create-machine-account: ERROR: The uidNumber $UIDNUMBER is already in use by an account which isn't a gecos: MachineAccount!"
		/usr/bin/logger "create-machine-account: Please resolve this by hand!"
	fi
	exit 10
fi

# We got here. This means that we found a free uidNumber which is one higher than
# the highest already existing one of all (gecos=MachineAccount)'s.
# If the script is called corretly, this should always be the case
# as we use a special uidNumber-range for our machine-accounts (starting at $DEFAULTUID).


# Check if this "uid" (the new machine's name with trailing "$") is already taken:
LDAPRETURN=`/usr/bin/ldapsearch -b "ou=People,dc=subnet,dc=at" -H $URI -D "$ROOTBINDDN" -w $SECRET -x "(uid=${1})" | /bin/grep "uid: ${1}"`
if ! [ "X" == "X$LDAPRETURN" ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "ERROR: The uid ${1} already exists. Can not create this account."
	else
		/usr/bin/logger "create-machine-account: ERROR: The uid ${1} already exists. Can not create this account."
	fi
	exit 12
fi


# Create the machines' group ($GID) if necessary:
LDAPRETURN=`ldapsearch -b "ou=Group,dc=subnet,dc=at" -H $URI -D "$ROOTBINDDN" -w $SECRET -x "(&(objectClass=posixGroup)(gidNumber=$GIDNUMBER))" | /bin/grep "gidNumber: $GIDNUMBER"`
if [ "X" == "X$LDAPRETURN" ]; then
	# We need to create the group "machines" with gidNumber $GIDNUMBER:
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo
		/bin/echo "NOTE: Need to create the group \"machines\", gidNumber $GIDNUMBER."
		/bin/echo 
	else
		/usr/bin/logger "create-machine-account: NOTE: Need to create the group \"machines\", gidNumber $GIDNUMBER."
	fi
	
	MFILENAME=`/bin/date +%s`
	/bin/echo "dn: cn=machines,ou=Group,dc=subnet,dc=at" > machines-${MFILENAME}.ldif
	/bin/echo "objectClass: posixGroup" >> machines-${MFILENAME}.ldif
	/bin/echo "objectClass: top" >> machines-${MFILENAME}.ldif
	/bin/echo "cn: machines" >> machines-${MFILENAME}.ldif
	/bin/echo "gidNumber: $GIDNUMBER" >> machines-${MFILENAME}.ldif

	# Add the group to the LDAP-Server:
	/usr/bin/ldapadd -H $URI -D "$ROOTBINDDN" -x -w $SECRET -f machines-${MFILENAME}.ldif
	
	if [ ! $? == "0" ]; then
		if [ $INTERACTIVE == "yes" ]; then
			/bin/echo "ERROR: I couldn't add the "machines" group to the LDAP-server"
			/bin/echo "       but it is needed. Aborting."
		else
			/usr/bin/logger "create-machine-account: ERROR: I couldn't add the "machines" group to the LDAP-server, aborting."
		fi
		/bin/rm machines-${MFILENAME}.ldif
		exit 11
	fi
	
	# Clean-up:
	/bin/rm machines-${MFILENAME}.ldif
fi


# Construct this machine's ldif-file:
/bin/echo "dn: uid=${1},ou=People,dc=subnet,dc=at" > ${1}.ldif
/bin/echo "objectClass: posixAccount" >> ${1}.ldif
/bin/echo "uid: ${1}" >> ${1}.ldif
/bin/echo "cn: ${1}" >> ${1}.ldif
/bin/echo "userpassword: {CRYPT}X" >> ${1}.ldif
/bin/echo "loginShell: /bin/false" >> ${1}.ldif
/bin/echo "uidNumber: $UIDNUMBER" >> ${1}.ldif
/bin/echo "gidNumber: $GIDNUMBER" >> ${1}.ldif
/bin/echo "homeDirectory: /dev/null/" >> ${1}.ldif
/bin/echo "gecos: MachineAccount" >> ${1}.ldif


# Add the posixAccount to the LDAP-server:
/usr/bin/ldapadd -H $URI -D "$ROOTBINDDN" -x -w $SECRET -f ${1}.ldif
if [ ! $? == "0" ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "ERROR: Could not add the posixAccount."
	else
		/usr/bin/logger "create-machine-account: ERROR: Could not add the posixAccount."
	fi
	
	# Clean-up:
	/bin/rm ${1}.ldif

	exit 4
fi


# Delete the trailing "$":
MACHINEACCOUNT=`/bin/echo $1 | /bin/sed s/\\$$//`

# Make it a full Samba-Machine-Account:
/usr/bin/smbpasswd -a -m $MACHINEACCOUNT
if [ ! $? == "0" ]; then
	if [ $INTERACTIVE == "yes" ]; then
		/bin/echo "ERROR: Could not make the posixAccount a full machine-account."
	else
		/usr/bin/logger "create-machine-account: ERROR: Could not make the posixAccount a full machine-account."
	fi
	
	# Clean-up:
	/bin/rm ${1}.ldif
	/usr/bin/ldapdelete -H $URI -D "$ROOTBINDDN" -x -w $SECRET "uid=${1},ou=People,dc=subnet,dc=at"
	
	exit 5
fi

# Clean-up:
/bin/rm ${1}.ldif

# Log success
if [ $INTERACTIVE == "yes" ]; then
	/bin/echo "Machine account ${1} successfully created."
else
	/usr/bin/logger "create-machine-account: Machine account ${1} successfully created."
fi

