#!/bin/ksh -p
#
# ident "@(#)dhcp_config_linux.ksh	1.14 04/10/21 SMI"
#
# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

UTDHCPDIR="$ETCDIR"/net/dhcp
DHCPDCONF=/etc/dhcpd.conf
UTDHCPFILE="$UTDHCPDIR"/utdhcp
OPTIONSFILENAME="SunRay-options"
OPTIONSFILE="$UTDHCPDIR"/"$OPTIONSFILENAME"
SUBNETFILEPREFIX="SunRay-subnet-"
SUBNETFILEPATHPREFIX="$UTDHCPDIR"/"$SUBNETFILEPREFIX"
INTFILEPREFIX="SunRay-interface-"
INTFILEPATHPREFIX="$UTDHCPDIR"/"$INTFILEPREFIX"
ETHERFILEPREFIX="/SunRay-ether-"
ETHERFILEPATHPREFIX="$UTDHCPDIR"/"$ETHERFILEPREFIX"
TMPLISTFILE="/var/opt/SUNWut/tmp/$$.files"

# for SuSE based systems
SYSDHCPD="/etc/sysconfig/dhcpd"
INCLUDEKEY="DHCPD_CONF_INCLUDE_FILES"
INTKEY="DHCPD_INTERFACE"
CHROOTKEY="DHCPD_RUN_CHROOTED"
CHROOTED=false

# remote subnet comment line
DUMMY_SUBNET_COMMENT="# Sun Ray: dummy subnet to support DHCP clients on remote subnets"

CheckChrooted() {
	grep $CHROOTKEY $SYSDHCPD | grep -i yes 2>/dev/null 1>&2
	if [[ $? -eq 0 ]]; then
		CHROOTED=true
	else
		CHROOTED=false
	fi	
}

GenerateOptionsDHCPDBlock() {
	if [[ -n $UT_DHCP_AUTHPORT ]]; then
                print "	option NewT.AuthPort $UT_DHCP_AUTHPORT;"
        fi
        if [[ -n $UT_DHCP_NEWTVER ]]; then
                print "	option NewT.NewTVer \"$UT_DHCP_NEWTVER\";"
        fi
        if [[ -n $UT_DHCP_LOGHOST ]]; then
                print "	option NewT.LogHost $UT_DHCP_LOGHOST;"
        fi
        if [[ -n $UT_DHCP_LOGKERNEL ]]; then
                print "	option NewT.LogKern $UT_DHCP_LOGKERNEL;"
        fi
        if [[ -n $UT_DHCP_LOGNET ]]; then
                print "	option NewT.LogNet $UT_DHCP_LOGNET;"
        fi
        if [[ -n $UT_DHCP_LOGUSB ]]; then
                print "	option NewT.LogUSB $UT_DHCP_LOGUSB;"
        fi
        if [[ -n $UT_DHCP_LOGVIDEO ]]; then
                print "	option NewT.LogVid $UT_DHCP_LOGVIDEO;"
        fi
        if [[ -n $UT_DHCP_LOGAPPLICATION ]]; then
                print "	option NewT.LogAppl $UT_DHCP_LOGAPPLICATION;"
        fi
        if [[ -n $UT_DHCP_NEWTBANDWIDTH ]]; then
                print "	option NewT.NewTBW $UT_DHCP_NEWTBANDWIDTH;"
        fi
        if [[ -n $UT_DHCP_BARRIERLEVEL ]]; then
                print "	option NewT.BarrierLevel $UT_DHCP_BARRIERLEVEL;"
        fi
        if [[ -n $UT_DHCP_NEWTFLAGS ]]; then
                print "	option NewT.NewTFlags $UT_DHCP_NEWTFLAGS"
        fi
        if [[ -n $UT_DHCP_NEWTDISPINDEX ]]; then
                print "	option NewT.NewTDispIndx $UT_DHCP_NEWTDISPINDEX"
        fi
}

DeleteGenericInclude() {
	typeset DELKEY=$1
	typeset INTF=${2:-}
	sed -e "/^include.*$DELKEY/d" $DHCPDCONF > $DHCPDCONF.$$
	GenerateSysconfigDHCPD delete $DELKEY $INTF
	rm -f $DHCPDCONF 2>/dev/null
	mv $DHCPDCONF.$$ $DHCPDCONF 2>/dev/null
	rm -f $SYSDHCPD 2>/dev/null
        mv $SYSDHCPD.$$ $SYSDHCPD 2>/dev/null
}

InsertGenericInclude() {
	typeset INSKEY=$1
	typeset INTF=${2:-}
	if $CHROOTED; then
		OPTGREP="/etc/$OPTIONSFILENAME"
	else
		OPTGREP="$OPTIONSFILE"
	fi
	ls $DHCPDCONF | xargs grep "$OPTGREP" >/dev/null
	if [[ $? != 0 ]]; then
		sed -e "1i\
		include \"$INSKEY\";" $DHCPDCONF > $DHCPDCONF.$$
	else		
		sed -e "/^include.*SunRay-options/a\
		include \"$INSKEY\";" $DHCPDCONF > $DHCPDCONF.$$
	fi
	GenerateSysconfigDHCPD add $INSKEY $INTF
	rm -f $SYSDHCPD 2>/dev/null
	mv $SYSDHCPD.$$ $SYSDHCPD 2>/dev/null
	rm -f $DHCPDCONF 2>/dev/null
        mv $DHCPDCONF.$$ $DHCPDCONF 2>/dev/null
}

InsertOptionsInclude() {
	INSKEY=$1
        sed -e "1i\
        include \"$INSKEY\";" $DHCPDCONF > $DHCPDCONF.$$
	GenerateSysconfigDHCPD add $INSKEY
	rm -f $SYSDHCPD 2>/dev/null
        mv $SYSDHCPD.$$ $SYSDHCPD 2>/dev/null
        rm -f $DHCPDCONF 2>/dev/null
        mv $DHCPDCONF.$$ $DHCPDCONF 2>/dev/null
}

GenerateSysconfigDHCPD() {

	typeset INTF=${3:-}
	INCLUDELINE=""
	DHCPDINT=""
	INTLINE=""
	if [[ ! -f $SYSDHCPD ]]; then
		return 0
	fi
	. $SYSDHCPD
	typeset file=${2#*\"}
	typeset file=${file%\"*}
	DHCPDINT=${file##*/}
	INCLUDELINE="$DHCPD_CONF_INCLUDE_FILES"
	INTLINE="$DHCPD_INTERFACE"
	case $1 in
	(add)
		print $DHCPD_CONF_INCLUDE_FILES | grep $2 2>/dev/null 1>&2
		if [[ $? -ne 0 ]]; then
			INCLUDELINE="$DHCPD_CONF_INCLUDE_FILES $2"
		fi
		case $DHCPDINT in
		(*subnet*)
			if [[ -n $INTF ]]; then
				print $DHCPD_INTERFACE | grep "$INTF" 2>/dev/null 1>&2
				if [[ $? -ne 0 ]]; then
					INTLINE="$DHCPD_INTERFACE $INTF"
				fi
			fi
			;;
		(*interface*)
			print $DHCPD_INTERFACE | grep "${DHCPDINT##*-}" 2>/dev/null 1>&2
			if [[ $? -ne 0 ]]; then
				INTLINE="$DHCPD_INTERFACE ${DHCPDINT##*-}"
			fi
			;;
		esac	
		;;
	(delete)
		print $DHCPD_CONF_INCLUDE_FILES | grep $2 2>/dev/null 1>&2
		if [[ $? -eq 0 ]]; then
			OLDLINE="$DHCPD_CONF_INCLUDE_FILES"
			RemoveEntryFromLine $2
			INCLUDELINE="$NEWLINE"
		fi
		case $DHCPDINT in
		(*subnet*)
                        print $INCLUDELINE | grep "SunRay-subnet" 2>/dev/null 1>&2
  			if [[ $? != 0 ]] && [[ -n $INTF ]]; then
				print $DHCPD_INTERFACE | grep $INTF 2>/dev/null 1>&2
     				if [[ $? -eq 0 ]]; then
                                        OLDLINE="$DHCPD_INTERFACE"
                                        RemoveEntryFromLine $INTF
                                        INTLINE="$NEWLINE"
				fi
			fi
                        ;;
		(*interface*)
			print $DHCPD_INTERFACE | grep "${DHCPDINT##*-}" 2>/dev/null 1>&2
			if [[ $? -eq 0 ]]; then
				OLDLINE="$DHCPD_INTERFACE"
				RemoveEntryFromLine "${DHCPDINT##*-}"
				INTLINE="$NEWLINE"
			fi
			;;
		esac
		;;
	esac
	cp $SYSDHCPD $SYSDHCPD.$$
	ed - $SYSDHCPD.$$ <<-! 2>/dev/null 1>&2
	g/^$INCLUDEKEY/d
	i
	$INCLUDEKEY="$INCLUDELINE"
	.
	w
	q
	!
	if [[ $? -ne 0 ]]; then
		print -us "Error: unable to edit $SYSDHCPD"
		return 1
	fi
	ed - $SYSDHCPD.$$ <<-! 2>/dev/null 1>&2
	g/^$INTKEY/d
	i
	$INTKEY="$INTLINE"
	.
	w
	q
	!
	if [[ $? -ne 0 ]]; then
                print -us "Error: unable to edit $SYSDHCPD"
                return 1
        fi
}

RemoveEntryFromLine() {
	NEWLINE=`print "$1 $OLDLINE" | awk '{
					n = split($OLDLINE, a, " ")
					out = ""
					for (i = 1; i <= n; i++) {
						if (match(a[i], $1) == 0) {
							out = out " " a[i]
						}
      					}
					printf "%s", out
				}'`
}

ProcessOptions() {
        VALUE=""
        INARG="$1"

        case $INARG in
                (option*NewT.AuthPort*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.AuthPort }
                                VALUE=${VALUE%;}
                                print "authport=$VALUE" >> $UTDHCPFILE
                        fi
                        ;;
                (option*NewT.NewTVer*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.NewTVer }
                                VALUE=${VALUE%;}
				# strip imbedded quotes if any
				VALUE=${VALUE#\"}
				VALUE=${VALUE%\"}
                                print "newtver=$VALUE" >> $UTDHCPFILE
                        fi
                        ;;
                (option*NewT.NewTBW*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.NewTBW }
                                VALUE=${VALUE%;}
                                print "newtbandwidth=$VALUE" >> $UTDHCPFILE
                        fi
                        ;;
                (option*NewT.LogHost*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.LogHost }
                                VALUE=${VALUE%;}
                                print "loghost=$VALUE" >> $UTDHCPFILE
                        fi
                        ;;
                (option*NewT.LogKern*)
			if $BEGAN; then
                                VALUE=${INARG#option NewT.LogKern }
                                VALUE=${VALUE%;}
                                print "logkernel=$VALUE" >> $UTDHCPFILE
                        fi
                        ;;
                (option*NewT.LogNet*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.LogNet }
                                VALUE=${VALUE%;}
                                print "lognet=$VALUE" >> $UTDHCPFILE
                        fi
                        ;;
                (option*NewT.LogUSB*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.LogUSB }
                                VALUE=${VALUE%;}
                                print "logusb=$VALUE" >> $UTDHCPFILE
                        fi    
                        ;;
                (option*NewT.LogVid*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.LogVid }
                                VALUE=${VALUE%;}
                                print "logvideo=$VALUE" >> $UTDHCPFILE
                        fi   
                        ;;
                (option*NewT.LogAppl*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.LogAppl }
                                VALUE=${VALUE%;}
                                print "logapplication=$VALUE" >> $UTDHCPFILE
                        fi   
                        ;;
                (option*NewT.NewtDispIndx*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.NewtDispIndx }
                                VALUE=${VALUE%;}
                                print "newtdispindex=$VALUE" >> $UTDHCPFILE
                        fi  
                        ;;
                (option*NewT.NewtFlags*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.NewtFlags }
                                VALUE=${VALUE%;}
                                print "newtflags=$VALUE" >> $UTDHCPFILE
                        fi
			;;
                (option*NewT.BarrierLevel*)
                        if $BEGAN; then
                                VALUE=${INARG#option NewT.BarrierLevel }
                                VALUE=${VALUE%;}
                                print "barrierlevel=$VALUE" >> $UTDHCPFILE
                        fi  
                        ;;
                esac
        return 0
}

TranslateDHCPDConf() {

	rm -f $UTDHCPFILE 2>/dev/null
	if [[ ! -f $DHCPDCONF ]]; then
		return 1
        fi
        TranslateOptions
	TranslateEther
        TranslateSubnet
	TranslateInterface
	return 0
}

TranslateOptions() {
        BEGAN=false

        if [[ ! -f $OPTIONSFILE ]]; then
                return 1
        fi

        while read OPTIONS
        do
                case $OPTIONS in
                (subclass*SunRay*SUNW.NewT.SUNW*)
                        if $BEGAN; then
                                rm -f $UTDHCPFILE
                                return 2
                        fi
                        print "begin options" >> $UTDHCPFILE
                        BEGAN=true
                        ;;
                (\})
                        if $BEGAN; then
                                BEGAN=false
                                print "end" >> $UTDHCPFILE
                        fi
                        ;;
                (*)
                        if $BEGAN; then
                                ProcessOptions "$OPTIONS"
                                if [[ $? != 0 ]]; then
                                        return 2
                                fi
                        fi
                        ;;
                esac
        done < $OPTIONSFILE

        return 0
}

ProcessSubnet() {
	subnetoptions="$1"
	if [[ -z $subnetoptions ]]; then
		return 1
	fi

	case $subnetoptions in
		(option*routers*)
			if $BEGAN; then
				VALUE=${subnetoptions#option routers }
				VALUE=${VALUE%;}
				print "routers=$VALUE" >> $UTDHCPFILE
			fi
			;;
		(option*subnet-mask*)
			if $BEGAN; then
				VALUE=${subnetoptions#option subnet-mask }
				VALUE=${VALUE%;}
				print "subnetmask=$VALUE" >> $UTDHCPFILE
			fi
			;;
		(option*broadcast-address*)
			if $BEGAN; then
				VALUE=${subnetoptions#option broadcast-address }
				VALUE=${VALUE%;}
				print "broadcast=$VALUE" >> $UTDHCPFILE
			fi
			;;
		(option*interface-mtu*)
			if $BEGAN; then
				VALUE=${subnetoptions#option interface-mtu }
				VALUE=${VALUE%;}
				print "mtu=$VALUE" >> $UTDHCPFILE
			fi
			;;
		(range*)
			if $BEGAN; then
				VALUE=${subnetoptions#range }
				VALUE=${VALUE%;}
				print "range=$VALUE" >> $UTDHCPFILE
			fi
			;;
		(option*NewT.AuthSrvr*)
			if $BEGAN; then
				VALUE=${subnetoptions#option NewT.AuthSrvr }
				VALUE=${VALUE%;}
				print "authsrvr=$VALUE" >> $UTDHCPFILE
			fi
                        ;;
		(option*NewT.FWSrvr*)
			if $BEGAN; then
				VALUE=${subnetoptions#option NewT.FWSrvr }
				VALUE=${VALUE%;}
				print "firmwaresrvr=$VALUE" >> $UTDHCPFILE
			fi
                        ;;
		(option*NewT.AltAuth*)
			if $BEGAN; then
				VALUE=${subnetoptions#option NewT.AltAuth }
				VALUE=${VALUE%;}
				print "altauthlist=$VALUE" >> $UTDHCPFILE
			fi
                        ;;
		(*)
                   	if $BEGAN; then
				ProcessOptions "$subnetoptions"
                                if [[ $? != 0 ]]; then
					rm -f $UTDHCPFILE
					rm -f $TMPLISTFILE 2>/dev/null
                                        return 2
                                fi
                        fi
                        ;;
		esac
	return 0	
}

TranslateEther() {
	BEGAN=false
	VALUE=""

	ls $UTDHCPDIR | sort -g | grep "SunRay-ether" > $TMPLISTFILE
	if [[ $? != 0 ]]; then
		rm -f $TMPLISTFILE 2>/dev/null
		return 1
	fi

        while read etherfile
	do
          	while read eth
		do
                case $eth in
                (subclass*SunRayEther*)
			if $BEGAN; then
				rm -f $UTDHCPFILE
				rm -f $TMPLISTFILE 2>/dev/null
				return 2
			fi
			print "begin ether" >> $UTDHCPFILE
			ETHER=${eth#subclass \"SunRayEther\" 1:}
			ETHER=${ETHER% \{}
			normalizeEther
			print "macaddress=$ETHER" >> $UTDHCPFILE
			BEGAN=true
			;;
		(\})
                    	if $BEGAN; then
				print "end" >> $UTDHCPFILE
				BEGAN=false
			fi
                        ;;
		(*)
                   	if $BEGAN; then
				ProcessOptions "$eth"
				if [[ $? != 0 ]]; then
                                        rm -f $UTDHCPFILE
                                        rm -f $TMPLISTFILE 2>/dev/null
                                        return 2
				fi
			fi
                        ;;
		esac
		done < $UTDHCPDIR/$etherfile
	done < $TMPLISTFILE
	rm -f $TMPLISTFILE 2>/dev/null
	return 0
}

#
# isDummySubnet(): checks for the Sun Ray dummy subnet line in the subnet file
# specified.  The dummy subnet line is defined in $DUMMY_SUBNET_COMMENT.
#
# Parameters:
#	$1 file name
#
# Returns:
#	0 if dummy line found.
#	1 otherwise
#
isDummySubnet() {

	FILE=$1
	if [ ! -f $FILE ]; then
		return 1
	fi
	grep -q "^${DUMMY_SUBNET_COMMENT}" $FILE 2> /dev/null
	return $?
}


#
# TranslateSubnet() - translates the subnet files from DHCP format to
# utadm format.
#
# Parameters:
#	$1 if specified, the input subnet file in DHCP format
#
# Returns:
#	0 if successful
#	1 otherwise
#
TranslateSubnet() {

	typeset TSUBNET
	typeset INFILE=${1:-}
	typeset Skip_Dummy_Subnet=true
        BEGAN=false
        VALUE=""

	if [ -z "$INFILE" ]; then
		# list all the subnet files
		ls $UTDHCPDIR | sort -g | grep "SunRay-subnet" > $TMPLISTFILE
		if [[ $? != 0 ]]; then
			rm -f $TMPLISTFILE 2>/dev/null
			return 1
		fi
	else
		# use the specified file
		print `basename $INFILE` > $TMPLISTFILE
		# when passing specific file, do not skip even if it's a dummy
		# subnet file
		Skip_Dummy_Subnet=false
	fi

	while read SUBFILE
	do
		if $Skip_Dummy_Subnet && isDummySubnet $UTDHCPDIR/$SUBFILE; then
			# skip dummy subnet files
			continue
		fi
        	while read TSUBNET
        	do
		case $TSUBNET in
		(subnet*netmask*)
			if $BEGAN; then
				rm -f $UTDHCPFILE
				rm -f $TMPLISTFILE 2>/dev/null
				return 2
			fi
                        print "begin subnet" >> $UTDHCPFILE
			TEMPSTRING=${TSUBNET#subnet }
			VALUE=${TEMPSTRING% netmask*}
			print "network=$VALUE" >> $UTDHCPFILE
			VALUE=${TEMPSTRING#*netmask }
			VALUE=${VALUE% \{}
			print "netmask=$VALUE" >> $UTDHCPFILE
			BEGAN=true
			;;
		(\})
                    	if $BEGAN; then
				print "end" >> $UTDHCPFILE
				BEGAN=false
			fi
                        ;;
		(*)
                   	if $BEGAN; then
				ProcessSubnet "$TSUBNET"
				if [[ $? != 0 ]]; then
                                        rm -f $UTDHCPFILE
                                        rm -f $TMPLISTFILE 2>/dev/null
                                        return 2
				fi
			fi
                        ;;
		esac
        	done < $UTDHCPDIR/$SUBFILE
	done < $TMPLISTFILE
	rm -f $TMPLISTFILE 2>/dev/null
        return 0
}

TranslateInterface() {
	BEGAN=false
	VALUE=""

	ls $UTDHCPDIR | sort -g | grep "SunRay-interface" > $TMPLISTFILE
	if [[ $? != 0 ]]; then
		rm -f $TMPLISTFILE 2>/dev/null
		return 1
	fi

	while read IFILE
	do
        while read INT
	do
		case $INT in
		(subnet*netmask*)
			if $BEGAN; then
				rm -f $UTDHCPFILE
				rm -f $TMPLISTFILE 2>/dev/null
				return 2
			fi
                        print "begin interface" >> $UTDHCPFILE
			TEMPSTRING=${INT#subnet }
			VALUE=${TEMPSTRING% netmask*}
			print "network=$VALUE" >> $UTDHCPFILE
			VALUE=${TEMPSTRING#*netmask }
			VALUE=${VALUE% \{}
			print "netmask=$VALUE" >> $UTDHCPFILE
			BEGAN=true
			;;
		(option*NewT.Intf*)
			if $BEGAN; then
				VALUE=${INT#option NewT.Intf }
				VALUE=${VALUE%;}
				# strip imbedded quotes if any
				VALUE=${VALUE#\"}
                                VALUE=${VALUE%\"}
				print "interface=$VALUE" >> $UTDHCPFILE
			fi
                        ;;
		(\#option*hostname*)
			if $BEGAN; then
				VALUE=${INT#\#option hostname }
				VALUE=${VALUE%;}
				print "hostname=$VALUE" >> $UTDHCPFILE
			fi
                        ;;
		(option*dhcp-server-identifier*)
			if $BEGAN; then
                                VALUE=${INT#option dhcp-server-identifier }
                                VALUE=${VALUE%;}
                                print "ip=$VALUE" >> $UTDHCPFILE
                        fi
                        ;;
		(\})
                    	if $BEGAN; then
				print "end" >> $UTDHCPFILE
				BEGAN=false
			fi
                        ;;
		(*)
                   	if $BEGAN; then
				ProcessSubnet "$INT"
				if [[ $? != 0 ]]; then
                                        rm -f $UTDHCPFILE
                                        rm -f $TMPLISTFILE 2>/dev/null
                                        return 2
				fi
			fi
                        ;;
		esac
	done < $UTDHCPDIR/$IFILE
	done < $TMPLISTFILE
	rm -f $TMPLISTFILE 2>/dev/null
	return 0
}
