#!/bin/ksh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#

#
# Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
#

NSCD_INDICATOR=/var/tsol/doors/nscd_per_label
export LANG=C

# The labeled_parseNet function is used by functions in this file
# and by txzonemgr. So changes must be verified in both places.
# The function takes either a zonecfg net or anet resource, passed in
# via $net. It parses the keywords, and sets the following variables:
#
# ipaddr - the IP address, including the cidr suffix if present
# defaultrouter -if present
# physical - the corresponding global zone interface

function labeled_parseNet {
	typeset alpha

	ipaddr="..."
	linkname="..."
	vlan_id="..."
	shift 1
	while (( $# > 1)) do
		case $1 in
			"lower-link:")
				physical=$2
				;;
			"physical:")
				physical=$2
				;;
			"address:")
				if [ $2 != "..." ]; then
					ipaddr="$2"
				fi
				;;
			"allowed-address:")
				if [ $2 != "..." ]; then
					ipaddr="$2"
				fi
				;;
			"defrouter:")
				defrouter="$2"
				;;
			"linkname:")
				linkname=$2
				;;
			"vlan-id:")
				vlan_id=$2
				;;
		esac
		shift 1
	done
#
#	If address is a hostname, return IP address
#
	alpha=$(echo $ipaddr|grep ^[A-z]|grep -v :)
	if [[ ! -z $alpha ]]; then
		ipaddr=$(getent hosts $ipaddr|nawk '{print $1}')
		if [[ -z $ipaddr ]] ; then
			ipaddr="..."
		fi
	fi
}
 
# The _getIPconfig function is only used in this file.
# It is used to determine the hostname and IP address
# of the labeled zone. In addition to the variables set
# by labeled_parseNet, it also sets the variable $hostname.

function _getIPconfig {
	typeset hostattr
	typeset cidr

	ipType=$(zonecfg -z $ZONENAME info ip-type|cut -d" " -f2)
	if [ $ipType = exclusive ] ; then
		net=$(zonecfg -z $ZONENAME info anet 2>/dev/null)
	else
		net=$(zonecfg -z $ZONENAME info net 2>/dev/null)
	fi
	if [[ ! -n $net ]]; then
		hostname=$(hostname)
		ipaddr=127.0.0.1
		return 1
	fi
	net=$(echo $net|sed 's/ not specified/: .../g')
	labeled_parseNet $net
	if [ $ipaddr = ... ]; then
		ipaddr=127.0.0.1
		return 1
	fi

	hostattr=$(zonecfg -z $ZONENAME info attr name=hostname 2>/dev/null)
	if [[ -n $hostattr ]]; then
		hostname=$(echo $hostattr|cut -d" " -f7)
		return 0
	else
		cidr=$(echo $ipaddr|grep /|cut -f2 -d/)
		if [[ -n $cidr ]]; then
			# remove the optional cidr suffix
			# which is input to getNetmask()

			ipaddr=$(echo $ipaddr|cut -f1 -d/)
		fi
		getent=$(getent hosts $ipaddr)
		if [ $? = 0 ]; then
			hostname=$(echo $getent|nawk '{print $2}')
		else
			hostname=$ZONENAME
		fi
		return 0
	fi
}
	
# The labeled_unsharePasswed function removes the passwd and shadow
# lofs mounts that are part of the shared name service configuration.
# This function is also called by txzonemgr so changes must be 
# verified in both files.

function labeled_unsharePasswd {
	zonecfg -z $1 remove fs dir=/etc/passwd >/dev/null 2>&1
	zonecfg -z $1 remove fs dir=/etc/shadow >/dev/null 2>&1
}

# The labeled_sharePasswed function sets the passwd and shadow
# lofs mounts that are part of the shared name service configuration.
# This function is also called by txzonemgr so changes must be 
# verified in both files.

function labeled_sharePasswd {
	passwd=$(zonecfg -z $1 info|grep /etc/passwd)
	if [ $? -eq 1 ] ; then
		zonecfg -z $1 "add fs; \
		    set special=/etc/passwd; \
		    set dir=/etc/passwd; \
		    set type=lofs; \
		    add options ro; \
		    end" 2>/dev/null
	fi
	shadow=$(zonecfg -z $1 info|grep /etc/shadow)
	if [ $? -eq 1 ] ; then
		zonecfg -z $1 "add fs; \
		    set special=/etc/shadow; \
		    set dir=/etc/shadow; \
		    set type=lofs; \
		    add options ro; \
		    end" 2>/dev/null
	fi
}

#
# The _auto_home function automates NFS sharing of the minimum labeled
# home directory with higher lableled zones. Reading the lowest
# labeled home directory is required by updatehome(1).
#
# An auto_home_<zonename> automap entry is created and stored in
# /var/tsol/doors/automount, which is then readable to all zones.
#
# Although zone administrators can configure their own automount
# entries, it is done automatically here to make things easier.
#
function _auto_home {
	typeset ZONE_ETC_DIR=$l_zonepath/root/etc
	typeset ZONE_AUTO_HOME=$ZONE_ETC_DIR/auto_home_$ZONENAME
	typeset TNZONECFG=/etc/security/tsol/tnzonecfg
	typeset AUTOMOUNTDIR=/var/tsol/doors/automount

	if [ -f $NSCD_INDICATOR -a $1 = clone ] ; then
		if [ ! -f $ZONE_AUTO_HOME -a  $LOGNAME != "root" ]; then
			echo "$LOGNAME\tlocalhost:/export/home/$LOGNAME" >> \
			    $ZONE_AUTO_HOME
		fi
	fi

	# Find the labeled zone corresponding to the minimum label
	typeset deflabel=$(chk_encodings -a|grep "Default User Sensitivity"|\
	   sed 's/= /=/'|sed 's/"/'''/g|cut -d"=" -f2)
	typeset DEFAULTLABEL=$(atohexlabel "${deflabel}")

	typeset minzone_entry=$(grep ${DEFAULTLABEL} $TNZONECFG)
	if [[ ! -n $minzone_entry ]]; then
		return
	fi
	typeset minzone=$(echo $minzone_entry|cut -d: -f1)
	typeset am=auto_home_$minzone

	if [ $minzone = $ZONENAME ]; then
		# If the current zone has the minimum label,
		# check if its home directories can be shared.

		# An explicit IP address assignment is required
		# for a zone to be a multilevel NFS server.
		
		_getIPconfig || return

		# Save the automount entry for other zones to import

		if [ ! -d $AUTOMOUNTDIR ] ; then
			mkdir $AUTOMOUNTDIR
		fi
		echo "+$am" > $AUTOMOUNTDIR/$am
		echo "*	${ipaddr}:/export/home/&" \
		    >> $AUTOMOUNTDIR/$am 

		# Configure multilevel NFS ports if
		# this hasn't been done already.
	
		tncfg -z $ZONENAME "add mlp_private=111/tcp;\
		    add mlp_private=111/udp;\
		    add mlp_private=2049/tcp" >/dev/null 2>&1
	else
		# If an automount map exists, then copy it into the higher
		# labeled zone.

		if [ -f $AUTOMOUNTDIR/$am ]; then
			cp $AUTOMOUNTDIR/$am $ZONE_ETC_DIR/$am
			mountpoint="/zone/${minzone}/home"
			
			# Add map to auto_master if necessary

			entry=$(grep ^$mountpoint $ZONE_ETC_DIR/auto_master)
			if [ $? != 0 ] ;then
				entry="$mountpoint	$am	-nobrowse"
				echo $entry >> $ZONE_ETC_DIR/auto_master
			fi
		else
			rm $ZONE_ETC_DIR/$am 2>/dev/null
		fi
	fi
}

# The labeled_printsysconfig function generates a custom
# SC profile for a labeled zone using properies from the
# zone's configuration file and global zone settings.

function labeled_printsysconfig {
	typeset fmtsvc='<service name="%s" version="1" type="service">\n<instance name="%s" enabled="true">\n'
	typeset fmtgrp='<property_group name="%s" type="%s">\n'
	typeset fmtval='<propval name="%s" type="%s" value="%s"/>\n'
	typeset fmtendsvc='</property_group>\n</instance>\n</service>\n'

	print '<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">'
	print '<service_bundle type="profile" name="system configuration">'
	printf "$fmtsvc" milestone/config default
	printf "$fmtgrp" configuration application
	printf "$fmtval" configure boolean true
	printf "$fmtval" interactive_config boolean false
	printf "$fmtval" config_groups astring $1
	printf "$fmtendsvc"

	typeset ldap=$(svcprop -p general/enabled ldap/client)
	if [ $ldap = true ] ; then
		printf "$fmtsvc" network/ldap/client default
		printf "$fmtgrp" config application
		searchbase=$(svcprop -p config/search_base network/ldap/client)
		printf "$fmtval" search_base astring "$searchbase"
		serverlist=$(svcprop -p config/server_list network/ldap/client)
		printf "$fmtval" server_list astring "$serverlist"
		profName=$(svcprop -p config/profile network/ldap/client)
		printf "$fmtval" profile astring $profName
		print '</property_group>'

		printf "$fmtgrp" cred application
		profDN=$(svcprop -p cred/bind_dn network/ldap/client)
		printf "$fmtval" bind_dn astring $profDN
		profPwd=$(ldapclient list | \
		    grep "^NS_LDAP_BINDPASSWD" | cut -d " " -f2)
		printf "$fmtval" bind_passwd astring $profPwd
		printf "$fmtendsvc"

		printf "$fmtsvc" system/name-service/switch default
		printf "$fmtgrp" config application
		printf "$fmtval" default astring "files ldap"
		printf "$fmtval" netgroup astring "ldap"
		printf "$fmtendsvc"
	fi

	_getIPconfig
	printf "$fmtsvc" system/identity node
	printf "$fmtgrp" config application
	printf "$fmtval" nodename astring $hostname
	printf "$fmtendsvc"

	typeset locale=$(svcprop -p environment/LANG system/environment:init 2>/dev/null)
	if [ $? = 0 -a $locale != '""' ]; then
		printf "$fmtsvc" system/environment init
		printf "$fmtgrp" environment application
		printf "$fmtval" LANG astring $locale
		printf "$fmtendsvc"
	fi

	typeset timezone=$(svcprop -p timezone/localtime system/timezone:default)
	printf "$fmtsvc" system/timezone default
	printf "$fmtgrp" timezone application
	printf "$fmtval" localtime astring $timezone
	printf "$fmtendsvc"

	printf "$fmtsvc" system/console-login default
	printf "$fmtgrp" ttymon application
	printf "$fmtval" terminal_type astring vt100
	printf "$fmtendsvc"

	if [ -f $NSCD_INDICATOR  -a $LOGNAME != "root" ]; then
		printf "$fmtsvc" system/config-user default
		printf "$fmtgrp" root_account application
		rootpwd=$(grep "^root:" /etc/shadow|cut -d : -f2)
		printf "$fmtval" password astring $rootpwd
		printf "$fmtval" type astring role
		print '</property_group>'
		printf "$fmtgrp" user_account application
		printf "$fmtval" login astring gfaden
		userpwd=$(grep "^${LOGNAME}:" /etc/shadow|cut -d : -f2)
		printf "$fmtval" password astring $userpwd
		printf "$fmtval" roles astring root

		getent passwd $LOGNAME|while IFS=: \
		    read name pw uid gid descr home shell; do
			printf "$fmtval" uid astring $uid
			printf "$fmtval" gid astring $gid
			printf "$fmtval" description astring "$descr"
			printf "$fmtval" shell astring $shell
		done
		printf "$fmtendsvc"
	fi
	print '</service_bundle>'
}

# The labeled_reconfigure function is used to generate a
# a customized SC profile for a cloned zone, and to setup
# some nameservice-specific properties for the user account.
# It is called by the common clone code when the user runs zoneadm
# without specifying a SC profile for a labeled zone.

# $1 specifies how much to configure.
# possible values are "system,identity,network,location,users"
#
# $2 specifies if the unconfiguration should be destructive
# possible values are --destructive and null
# Returns 0 if successful, and 1 if mount failure

function labeled_reconfigure {
	if [ -f $NSCD_INDICATOR ] ; then
		labeled_unsharePasswd $ZONENAME
	else
		labeled_sharePasswd $ZONENAME
	fi
	# change "system" to "users" when partial
	# reconfiguration is supported
	l_zonepath=$(zoneadm -z $ZONENAME list -p|cut -d : -f4)
        zoneadm -z $ZONENAME mount -f
	typeset zonestate=$(zoneadm -z $ZONENAME list -p | cut -d : -f 3)
	if [ $zonestate != mounted ] ; then
		gettext "error getting zone $ZONENAME mounted.\n"
		return 1
	fi

	_auto_home clone

	typeset configured SCPROFILE ZONE_PROFILE_DIR
	configured=$l_zonepath/root/var/svc/log/milestone-config:default.log

	# A zone can't be unconfigured until it is configured
	# so if the config service has no log file yet we assume
	# if has never been configured, and we can just place
	# the profile in the site directory.

	if [ ! -f $configured ]; then
		ZONE_PROFILE_DIR=$l_zonepath/root/etc/svc/profile/site
		SCPROFILE=${ZONE_PROFILE_DIR}/sc_profile.xml
		touch $SCPROFILE
		chmod 400 $SCPROFILE
		labeled_printsysconfig system >$SCPROFILE
	elif ([ -f $NSCD_INDICATOR ] || _getIPconfig); then
		ZONE_PROFILE_DIR=$l_zonepath/lu/system/volatile
		SCPROFILE_TMP=$(mktemp ${ZONE_PROFILE_DIR}/sc_profile-XXXX)
		SCPROFILE=${SCPROFILE_TMP}.xml
		mv $SCPROFILE_TMP $SCPROFILE
		labeled_printsysconfig $1 >$SCPROFILE
		typeset SC_CONFIG_BASE=$(basename $SCPROFILE)
		zlogin -S $ZONENAME "export _UNCONFIG_ALT_ROOT=/a; \
		    /usr/sbin/sysconfig configure -g $1 \
		    -c /system/volatile/$SC_CONFIG_BASE $2"
	fi
	zoneadm -z $ZONENAME unmount
	return $?
}

# The labeled_configure function is used to setup the
# some nameservice-specific properties for the user account.
# It is called by common pkgcreatezone code after a labeled zone
# has been installed, to set up user account properties

function labeled_configure {
	typeset l_zonepath=$(zoneadm -z $ZONENAME list -p|cut -d : -f4)
	_auto_home install
	if [ -f $NSCD_INDICATOR ] ; then
		labeled_unsharePasswd $ZONENAME
	else
		labeled_sharePasswd $ZONENAME
	fi
}	

# The labeled_makeSCprofile() function is used to create
# a customized SC profile for a new labeled zone.
# It is called by the common pkgcreatezone code when user runs
# zoneadm without specifying a SC profile for a labeled zone.
# The pathname of the new SC profile is set in
# the variable $temp_scprofile which is then passed to
# auto-install in the common pkgcreatezone code.

function labeled_makeSCprofile {
	temp_scprofile=$(mktemp -t sc_profile.XXXX)
	if [[ -z $temp_scprofile ]]; then
		print "$f_mktemp"
		exit $ZONE_SUBPROC_NOTCOMPLETE
	fi
	mv $temp_scprofile ${temp_scprofile}.xml
	temp_scprofile=${temp_scprofile}.xml
	labeled_printsysconfig system >$temp_scprofile
}
