#!/bin/ksh93

LIC='[-?2.0 ]
[-copyright?Copyright (c) 2013 Jens Elkner. All rights reserved.]
[-license?CDDL 1.0]'

SDIR=$( cd ${ dirname $0; }; printf "${PWD}" )
typeset -r FPROG=${.sh.file}
typeset -r PROG=${FPROG##*/}
[[ -z ${OSNAME} ]] && typeset -r OSNAME=${ uname -s ; }
if [[ ${OSNAME} == 'SunOS' ]]; then
	typeset -r SED='gsed'
	X=${ uname -v ; }
	typeset -r -i OSREL=${ printf "%d%03d" ${X%.*} ${.sh.match:1} ; }
else
	# assume linux
	typeset -r SED='sed'
	X=${ lsb_release -sr ; }
	typeset -r -i OSREL=${ printf "%d%03d" "${X%.*}" "${.sh.match:1}" ; }
fi

for H in log.kshlib man.kshlib ; do
	X=${SDIR}/$H
	[[ -r $X ]] && . $X && continue
	X=${SDIR}/../etc/$H
	[[ -r $X ]] && . $X && continue
	X=${ whence $H ; }

	[[ -z $X ]] && print -u2 "$H nicht gefunden - Abbruch." && exit 1
	. $X
done
unset H

typeset -T ApacheEnv_t=(
	typeset -h 'ServiceName der default httpd Instanz' svc=''
	typeset -h 'Apache Version. Empty on Linux.' vers=''
	typeset -h 'Apache httpd Install-Root-Ordner' root=''
	typeset -h 'Name des ZFS, unter welchem das datadir angelegt werden soll, falls noch nicht vorhanden.' zfsbase=''
	typeset -h 'Das Basisverzeichnis, in welches per default der Web-Daten-Ordner httpd angelegt wird.' basedir='/data'
	typeset -h 'Default Web-Daten-Ordner (i.d.R. /var/apache2/$VERS)' defdatadir=''
	typeset -h 'Web-Daten-Ordner, der per default die Unterordner conf, sites und logs enthält. Default: /data/httpd' datadir="${_.basedir}/httpd"
	typeset -h 'Default Config-Ordner (i.d.R. /etc/apache2/$VERS/)' defcfgdir=''
	typeset -h 'Config-Ordner. Default: /data/web/httpd/conf/' cfgdir="${_.datadir}/conf"
	typeset -h 'Default Logfile-Ordner (i.d.R. /var/apache2/$VERS/logs)' deflogdir=''
	typeset -h 'Logfile-Ordner (bei uns /data/httpd/log an /var/log/httpd gemountet). Default: /var/log/httpd' logdir='/var/log/httpd'
	typeset -h 'Default Ordner, der icons/ und errors/ enthält (i.d.R. $defdatadir)' defsharedir=''
	typeset -h 'Default Ordner, der das Apache manual/ enthält (i.d.R. $root)' defdocdir=''
	typeset -h 'User name, dem die Config-Ordner/Dateien gehören sollen. Default: webadm' owner='webadm'
	typeset -h 'Gruppe, der die Config-Ordner/Dateien gehören sollen. Default: staff' group='staff'
	typeset -h 'Das aktuelle Datum (Timestamp).' date=${ date '+%Y%m%d-%H:%M:%S'; }
	typeset -ih 'Indikator, ob die relevanten HTTP-Verzeichnisse bereits gecheckt worden sind (Wert == 0 falls nicht)' dirsok=0
	typeset -ih 'Indikator, ob die relevanten HTTPd Config-Dateien überschrieben werden sollen (Wert == 1). Backup-Datei wird voher angelegt.' overwrite=0
	typeset -h 'Fully qualified domain name der website' fqdn=''
	typeset -h 'Hostname der website (erste componente des fqdn)' host=''
	typeset -ih 'Indikator, ob die neuen configs bereits geschrieben wurden' config=0
	typeset -ih 'Indikator, ob der cert Hasher bereits aktualisiert wurde' hasher=0
	typeset -ih 'Indikator, ob der service bereits aktualisiert wurde' svcok=0
	typeset -h 'Temp file' tfile=''
	typeset -h 'HTTP port to use. Default: 80' port=80
	typeset -h 'HTTPS port to use. Default: 443' sslport=443
	typeset -ih 'Solaris binary to use - {32|64}bit. Default: 64' bits=64
	typeset -h 'Server type (event|worker|prefork)' stype='worker'

	function init {
		[[ ${OSNAME} == 'SunOS' ]] && (( OSREL >= 11003 )) && _.stype='event'
		[[ -n $1 ]] && _.setBaseDir "$1"
		_.fqdn=${ hostname; }
		_.host=${_.fqdn%%.*}
		typeset -a X=( ${ getent hosts ${_.fqdn} ; } )
		typeset H
		X[0]=${_.fqdn}
		for H in ${X[@]} ; do
			[[ $H != ${_.fqdn} && ${H//./ } != $H ]] && { _.fqdn=$H ; break ; }
		done

		if [[ ${OSNAME} != 'SunOS' || ${ zonename; } != 'global' ]];then
			_.zfsbase='pool1'
		else
			H=${ zfs list pool1 2>/dev/null ; }
			[[ -z $H ]] && _.zfsbase=rpool/ || _.zfsbase=pool1/
			_.zfsbase+="${_.host}"
		fi
		_.tfile=${ mktemp /tmp/web.XXXXXX ; }
		[[ -z ${_.tfile} ]] && exit 1
	}

	function getServerRootSolaris {
		[[ -n ${_.svc} ]] && return
		typeset Y X=${ svcs -a | grep /http:apache | sort -b -k 3 | tail -1 ; }
		if [[ -z $X ]]; then
			Log.fatal 'Es gibt keinen http:apache* Service.' \
				'\nPackage /web/server/apache-22 oder höher nicht installiert?'
			exit 1
		fi
		# since 11.3 there is no 32bit httpd anymore -> 64/ subdir vanished
		(( OSREL < 11003 )) && Y='bin/64/httpd' || Y='bin/httpd'
		_.svc=${X##*svc:}
		X=${ svcprop -p tm_man_httpd8/manpath ${_.svc} 2>/dev/null; }
		X=${X%/*}
		if [[ -z $X ]] || [[ ! -x $X/$Y ]]; then
			X=${ pkg search -l -H -o search.match '*/bin/httpd' 2>/dev/null; }
			X=/${X%/bin/httpd}
		fi
		if [[ ! -x $X/$Y ]]; then
			Log.fatal 'Konnte ServerRoot nicht bestimmen.' \
				'\nPackage /web/server/apache-22 oder höher nicht installiert?'
			return 1
		fi
		print "$X"
	}

	function getServerRootLinux {
		if [[ ! -f /usr/lib/apache2/modules/mod_alias.so ]]; then
			Log.fatal 'Konnte ServerRoot nicht bestimmen.' \
				'\nPackage apache2 nicht installiert?'
			return 1
		fi
		print '/usr/lib/apache2'
	}

	function getDefaults {
		typeset X
		if [[ ${OSNAME} == 'SunOS' ]]; then
			X=${ _.getServerRootSolaris ; }
		else
			X=${ _.getServerRootLinux ; }
		fi
		[[ -z $X ]] && exit 1
		_.root=$X
		if [[ ${OSNAME} == 'SunOS' ]]; then
			_.vers=/${X##*/}
			_.defdatadir=/var/apache2${_.vers}
			_.defsharedir=${_.defdatadir}
			_.defdocdir=${_.root}
			_.deflogdir=${_.defdatadir}/logs
		else
			# assume debian crap
			_.vers=
			_.defdatadir=/var/www
			_.defsharedir=/usr/share/apache2
			_.defdocdir=/usr/share/doc/apache2-doc
			_.deflogdir=/var/log/apache2
		fi
		_.defcfgdir=/etc/apache2${_.vers}
		_.date=${ date '+%Y%m%d-%H:%M:%S'; }
		[[ -z ${_.basedir} ]] && _.basedir=/data
		[[ -z ${_.datadir} ]] && _.datadir=${_.basedir}/httpd
		[[ -z ${_.cfgdir} ]] && _.cfgdir=${_.datadir}/conf
		[[ -z ${_.logdir} ]] && _.logdir=/var/log/httpd
		[[ -z ${_.owner} ]] && _.owner=webadm
		[[ -z ${_.group} ]] && _.group=staff
	}
	typeset -fh 'Sammelt die Infos (default Einstellungen) zum derzeit installierten Apache package ein' getDefaults

	function setBaseDir {
		_.basedir="${1}"
		_.datadir="${_.basedir}/httpd"		# war ursprünglich mal '/data/sites'
		_.cfgdir="${_.datadir}/conf"
	}
	typeset -fh 'Setzt basedir auf $1 und paßt datadir als auch cfgdir entsprechend an' setBaseDir
)

Man.addFunc copyTempFile '' '[+NAME?copyTempFile - kopiert die Datei ${CFG.tfile} an die angegebene Stelle]
[+DESCRIPTION?Kopiert die Datei ${CFG.tfile} nach \afile\a, ändert den Besitzer nach ${CFG.owner}:${CFG.group} und deren Rechte auf den angegebenen \amode\a. Ist kein mode angegeben, wird \b0644\b stattdessen verwendet.]
\n\n\afile\a [\amode\a]
'
function copyTempFile {
	[[ ! -r ${CFG.tfile} ]] && return
	Log.info "Schreibe $1 ..."
	+ cp ${CFG.tfile} "$1"
	+ chown ${CFG.owner}:${CFG.group} "$1"
	typeset MODE="$2"
	[[ -z ${MODE} ]] && MODE=0644
	+ chmod ${MODE} "$1"
}

Man.addFunc checkMethodPatch '' '[+NAME?checkMethodPatch - SMF method file check]
[+DESCRIPTION?Prüft ob das originale Apache SMF method script bereits gegen unser eigenes ausgetauscht wurde. Falls nicht, wird dies nachgeholt (und das alte mit der Erweiterung .orig gespeichert).]
'
function checkMethodPatch {
	[[ ${OSNAME} == 'SunOS' ]] || return 0
	# Since 11.3 httpd gets started directly, i.e. w/o using stupid apachectl
	# indirections, so basically what we've already done in the last decade ... 
	(( OSREL < 11003 )) || return 0
	typeset SUFFIX=${CFG.vers//.} \
	DST="/lib/svc/method/http-apache${SUFFIX:1}" \
	SRC="${SDIR}/http-apache22"

	if [[ ! -r ${SRC} ]]; then
		Log.warn "${SRC} nicht gefunden. ${DST} ist buggy und führt möglicherweise dazu, daß der httpd nicht gestartet werden kann!"
		return
	fi
	if [[ ! -r ${DST} ]]; then
		Log.warn "Huch: ${DST} kann nicht glesen werden. Ist das Apache package nicht korrekt installiert?"
		return
	fi
	cmp -s "${SRC}" "${DST}" && return
	# files differ
	[[ ! -e ${DST}.orig ]] && + cp -p "${DST}" "${DST}.orig"
	Log.info "Kopiere ${SRC} nach ${DST} ..."
	+ cp "${SRC}" "${DST}"
}

Man.addFunc checkDirs '' '[+NAME?checkDirs - Check wichtiger Verzeichnisse auf Vorhandensein/Besitz/Rechte und ggf. Korrektur]
[+DESCRIPTION?Prüft, ob die für den httpd notwendigen ZFSs und Verzeichnisse existieren, legt selbige ggf. an, prüft und korrigiert bei Bedarf deren Besitzer und Rechte.]
'
function checkDirs {
	(( ${CFG.dirsok} )) && return

	typeset ZFS X DIR
	if [[ -d ${CFG.datadir} ]]; then
		:
	elif [[ ${OSNAME} == 'SunOS' || -x /sbin/zfs ]]; then
		ZFS="${CFG.zfsbase}${CFG.datadir}"
		X=${ zfs list -H -o mountpoint "${ZFS}" 2>/dev/null ; }
		if [[ -z $X ]]; then
			X=${ + zfs create -p -o compression=on -o atime=off \
				-o mountpoint="${CFG.datadir}" "${ZFS}" 2>&1 ; }
			(( $? != 0 )) && Log.fatal "$X" && exit 1
			+ chown ${CFG.owner}:${CFG.group} "${CFG.datadir}"
		else
			CFG.basedir=$X
			X=${ zfs list -H -o compression ${ZFS} 2>/dev/null ; }
			[[ $X == 'off' ]] && + zfs set compression=on "${ZFS}"
		fi
		ZFS+='/log'
		X=${ zfs list -H -o mountpoint "${ZFS}" 2>/dev/null ; }
		if [[ -z $X ]]; then
			X=${ + zfs create -p -o compression=on -o atime=off \
				-o mountpoint="${CFG.logdir}" "${ZFS}" 2>&1 ; }
			(( $? != 0 )) && Log.fatal "$X" && exit 1
		elif [[ $X != ${CFG.logdir} ]]; then
			+ zfs set mountpoint="${CFG.logdir}" "${ZFS}"
		fi
	fi
	typeset -a LSI
	[[ ! -d ${CFG.datadir} ]] && { + mkdir "${CFG.datadir}" || exit 1 ; }
	LSI=( ${ ls -ld "${CFG.datadir}" ; } )
	[[ ${LSI[2]} != ${CFG.owner} ]] && \
	+ chown ${CFG.owner} "${CFG.datadir}"

	for DIR in ${CFG.cfgdir} ${CFG.cfgdir}/extra \
		${CFG.cfgdir}/ssl.key ${CFG.cfgdir}/ssl.crt \
		sites sites/${CFG.fqdn} sites/${CFG.fqdn}/{htdocs,cgi-bin,etc,tmp}
	do
		[[ ${DIR:0:1} != '/' ]] && DIR="${CFG.datadir}/${DIR}"
		if [[ ! -d ${DIR} ]]; then
			+ mkdir "${DIR}"
			+ chown ${CFG.owner} "${DIR}"
		fi
	done
	LSI=( ${ ls -ld "${CFG.cfgdir}/ssl.key" ; } )
	[[ ${LSI[0]} != 'drwxr-x---' ]] && \
		+ chmod 0750 ${CFG.cfgdir}/ssl.key
	[[ ${LSI[2]} != ${CFG.owner} || ${LSI[3]} != 'webservd' ]] && \
		+ chown ${CFG.owner}:webservd ${CFG.cfgdir}/ssl.key
	for DIR in ${CFG.logdir} ${CFG.logdir}/${CFG.fqdn} \
		${CFG.datadir}/sites/${CFG.fqdn}/tmp/uploads
	do
		[[ ! -d $DIR ]] && + mkdir -p "${DIR}"
		LSI=( ${ ls -ld "${DIR}" ; } )
		[[ ${LSI[2]} != 'webservd' ]] && + chown webservd "${DIR}"
	done
	# we wanna find it easier
	[[ ${CFG.logdir} != '/var/log/httpd' && ! -e /var/log/httpd ]] && \
		+ ln -s "${CFG.logdir}" /var/log/httpd
	CFG.dirsok=1
}

function updateSvcLinux {
	typeset X=${ pgrep systemd-udevd 2>/dev/null ; }
	integer USE_SYSTEMD=0
	[[ -n $X ]] && USE_SYSTEMD=1

	if (( USE_SYSTEMD )); then
		+ systemctl disable --now apache2
		+ systemctl disable --now apache24
		+ update-rc.d -f apache2 remove		# weg mit dem Rotz
	else
		+ service apache2 stop
	fi

	typeset P="${CFG.defcfgdir}/envvars" X="${CFG.cfgdir}/envvars"
	[[ -e ${P}.orig ]] || + cp -p "$P" "${P}.orig"
	+ cp -p "${P}.orig" "$X"
	ln -sf "$X" "$P"

	# Dueto the debian brain damaged /etc/init.d/apache2 as well as the
	# /usr/sbin/apachectl we need to duplicate most values. Passing this
	# stuff as Vars to the apache config is unreliable and might impose
	# security problems.
	+ ${SED} -i -e "/^# envvars/ a\\APACHE_CONFDIR='${CFG.cfgdir}'" \
		-e "/APACHE_RUN_USER=/ s,=.*,=webservd," \
		-e "/APACHE_RUN_GROUP=/ s,=.*,=webservd," \
		-e "/APACHE_PID_FILE=/ s,=.*,=${CFG.logdir}/httpd.pid," \
		-e "/APACHE_RUN_DIR=/ s,=.*,=${CFG.logdir}," \
		-e "/APACHE_LOCK_DIR=/ s,=.*,=${CFG.logdir}," \
		-e "/APACHE_LOG_DIR=/ s,=.*,=${CFG.logdir}," \
		"$X"
	# on linux envvars get sourced by bash scripts on startup ... =8-(	
	P='APACHE_ULIMIT_MAX_FILES=`ulimit -H -n`\n'
	print -n "$P" >> "$X"

	+ ln -sf /etc/mime.types ${CFG.defcfgdir}/mime.types
	+ ln -sf html ${CFG.defdatadir}/htdocs

	# per default n/a on linux
	P="${CFG.defsharedir}/cgi-bin"
	[[ -d $P ]] || mkdir "$P"
	P+="/printenv"
	if [[ ! -x $P ]]; then
		print '#!/bin/ksh93
print "Content-type: text/plain; charset=UTF-8\n\n"
set
'			> "$P"
		chmod 0755 "$P"
	fi

	# fix the debian shit
	+ ${SED} -e '/maximum number of file descriptors/ { p; N; N; N ; N; N; s,.*,\[ -n \$ULIMIT_MAX_FILES \] \&\& ulimit -S -n \$ULIMIT_MAX_FILES, ; p; x; P; P; P; }' -i /usr/sbin/apache2ctl

	# damn: and this as well
	[[ -e ${CFG.cfgdir}/apache2.conf ]] || \
		+ ln -s httpd.conf ${CFG.cfgdir}/apache2.conf

	if (( USE_SYSTEMD )); then
		X=${ mktemp /tmp/example.XXXXXX ; }
		[[ -z $X ]] && print -u2 'Unable to create temp file.' && retrurn 1
		cat >$X <<EOF
[Unit]
Description=Apache 2.4 HTTPd Server
After=network.target auditd.service

[Service]
Type=forking

# siehe ${CFG.cfgdir}/httpd.conf - muß das gleiche sein!
PIDFile=${CFG.logdir}/httpd.pid

# Da die Debian/Ubuntu-Volltrottel das apachectl vollkommen verpfuscht haben,
# starten/stoppen/... wir den httpd direkt.
Environment=CFG=${CFG.cfgdir}/httpd.conf

# irgendwann funktioniert's bestimmt ... - Pfuscher
#User=webservd
#Group=webservd
#Capabilities=CAP_NET_BIND_SERVICE
#AmbientCapabilities=CAP_NET_BIND_SERVICE

WorkingDirectory=/
# Die "ulimit -S -n \`ulimit -H -n\`" Alternative. Siehe /etc/systemd/system.conf
LimitNOFILE=64535
ExecStart=/usr/sbin/apache2 -f ${CFG} -k start
ExecReload=/usr/sbin/apache2 -f ${CFG} -k restart
ExecStop=/usr/sbin/apache2 -f ${CFG} -k stop
TimeoutStopSec=30s
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF
		+ cp $X /etc/systemd/system/apache24.service
		+ systemctl daemon-reload
		+ systemctl enable --now apache24
	else
		+ service apache2 start
	fi
}

function updateSvcSolaris {
	# what we want
	typeset KEY VAL B='true'
	(( CFG.bits == 32 )) && B='false'
	typeset -A cfg=(
		['httpd/startup_options']="-f ${CFG.cfgdir}/httpd.conf"

		['start/user']='webservd'
		['start/group']='webservd'
		['start/limit_privileges']=':default'
		['start/privileges']='basic,!proc_session,!proc_info,!file_link_any,net_privaddr'
		['start/use_profile']='false'
		['stop/user']='webservd'
		['stop/group']='webservd'
		['stop/use_profile']='false'
	)
	if (( OSREL < 11003 )); then
		cfg['httpd/server_type']="${CFG.stype}"
		cfg['httpd/status_url']="http://localhost:${CFG.port}/server-status"
		cfg['httpd/enable_64bit']=$B
	else
		cfg['httpd/MPM']="${CFG.stype}"
		cfg['start/privileges']+=",{zone}:/system/volatile/apache2,{zone}:/system/volatile/apache2${CFG.vers},{zone}:/var/log/httpd,{zone}:/var/log/httpd/*"
	fi
	integer CHANGED=0
	for KEY in ${!cfg[@]}; do
		VAL=${ svcprop -p ${KEY} ${CFG.svc} 2>/dev/null; }
		if [[ ${cfg[${KEY}]} != ${VAL} ]]; then
			if [[ ${KEY} == 'httpd/startup_options' ]]; then
				VAL=
				for X in ${cfg['httpd/startup_options']} ; do
					VAL+="\"${X}\" "
				done
   				svccfg -s ${CFG.svc} setprop ${KEY}="( ${VAL} )"
			elif [[ ${KEY} == 'httpd/status_url' ]]; then
				svccfg -s ${CFG.svc} "setprop ${KEY} = astring: ${cfg[${KEY}]}"
			elif [[ -n ${KEY} ]]; then 
				svccfg -s ${CFG.svc} "setprop ${KEY}=${cfg[${KEY}]}"
			fi
			(( CHANGED++ ))
		fi
	done
	X=${ svcprop -p start/environment ${CFG.svc} 2>/dev/null; }
	if [[ $X != 'LD_PRELOAD=libmtmalloc.so' ]]; then
		svccfg -s ${CFG.svc} setenv -m start LD_PRELOAD libmtmalloc.so
		(( CHANGED++ ))
	fi
	if (( CHANGED )); then
		Log.info "Initiiere ${CFG.svc} refresh ..."
		svccfg -s ${CFG.svc} refresh
	fi
}

Man.addFunc updateSvc '' '[+NAME?updateSvc - aktualisiert die SMF bzw. envvars properties für die default httpd Instanz]
[+DESCRIPTION?Aktualisiert die SMF properties unter Solaris, die envvars unter Linux für die default httpd Instanz und refreshed bei Bedarf selbige. Falls die benötigten Verzeichnisse und das SMF method script noch nicht gecheckt wurden, wird dies ebenso erledigt.]
[+SEE ALSO?\bcheckDirs()\b, \bcheckMethodPatch()\b, \bsvccfg\b(1M)]
'
function updateSvc {
	(( ${CFG.svcok} )) && return
	checkDirs
	checkMethodPatch
	[[ ! -f ${CFG.cfgdir}/httpd.conf ]] && createConf
	[[ ${OSNAME} == 'SunOS' ]] && updateSvcSolaris || updateSvcLinux
	CFG.svcok=1
}

Man.addFunc getConf '' '[+NAME?getConf - setzen der Konfig-Datei entsprechend overwrite Parameter]
[+DESCRIPTION?Setzt die Variable \avname\a auf den absoluten Pfad der zu schreibenden Konfig-Datei. Ist ${CFG.overwrite} != 1, wird die entsprechende Datei zusätzlich nach \a${CFG.cfgdir}/old/file\a\b-\b\aTIMESTAMP\a kopiert. Anderenfalls wird nur \avname\a auf \a${CFG.cfgdir}/old/file\a\b-\b\aTIMESTAMP\a gesetzt, die eigentliche config Datei bleibt, wie sie ist.]
[+SEE ALSO?\bcreateConf()\b]
\n\n\avname\a \afile\a
'
function getConf {
	typeset -n CONF=$1
	CONF=${CFG.cfgdir}/$2
	if (( ${CFG.overwrite} )); then
		if [[ -r ${CONF} ]]; then
			[[ -d ${CONF%/*}/old ]] || mkdir ${CONF%/*}/old
			cp -p "${CONF}" "${CONF%/*}/old/${CONF##*/}-${CFG.date}"
		fi
	elif [[ -e ${CONF} ]]; then
		[[ -d ${CONF%/*}/old ]] || mkdir ${CONF%/*}/old
		CONF="${CONF%/*}/old/${CONF##*/}-${CFG.date}"
	fi
}

function addMods {
	typeset -n CFG=$1
	typeset R=$2 D=$3 C M
	shift 3
	while [[ -n $1 ]]; do
		[[ ${1:0:1} == '_' ]] && { C='#';  M=${1:1}; } || { C=''; M=$1; }
		shift
		[[ -e ${R}/${D}/mod_${M}.so ]] || continue
		CFG+="\n${C}LoadModule\t${M}_module\t\t${D}/mod_${M}.so" 
	done
}

Man.addFunc createConf '' '[+NAME?createConf - erstellt httpd config Dateien]
[+DESCRIPTION?Erstellt die default httpd Konfig-Dateien. Ist ${CFG.overwrite} != 0, wird von evtl. vorhandenen Konfig-Dateien eine Sicherungskopie mit einem timestamp als Suffix erstellt, bevor sie überschrieben werden. Ist die Variable == 0, werden die neuen Konfig-Dateien mit einem Timestamp als Suffix gespeichert, die evtl. vorhandenen *.conf Dateien bleiben unverändert. Ebenso wird die Datei zum Erstellen der SSL hash links auf vorhandene SSL-Zertifikate aktualisiert.]
[+?Die httpd.conf enthält Einstellungen die anhand der vorhandenen CPU-Threads automatisch bestimmt werden. Sprich ändert sich deren Anzahl oder andere Parameter, ist möglicherweise ein Update der Konfig-Dateien sinnvoll.]
[+SEE ALSO?\bupdateCertHasher()\b, \bgetConf()\b, \bcopyTempFile()\b, \bpsrinfo\b(1M)]
'
function createConf {
	typeset CONF P MDIR MBASE= MAUTHN= MAUTHZ= MCACHE= MMISC= MUTEX= \
		ROTATELOGS IP M TAIL= I= LOCAL_PORT=${CFG.port} LOG_X=
	typeset -a MPM=( 'prefork' 'worker' 'event' )
	updateCertHasher
	(( ${CFG.config} )) && return

	getConf CONF httpd.conf
	[[ ${CFG.vers} == '/2.2' ]] || MUTEX="Mutex sem default"
	[[ -x ${CFG.root}/bin/rotatelogs ]] && \
		ROTATELOGS=${CFG.root}/bin/rotatelogs || ROTATELOGS=/usr/bin/rotatelogs

	integer X=0 N=0 SSTART=1
	integer MINSPARE=1
	integer MAXSPARE=$((2*MINSPARE))
	# max. number of simultaneous connections excl. proxy pools
	integer MAXCCON=64
	integer MAXPCON=0
	integer MAXTHREADS=128
	(( MAXCCON+=MAXTHREADS ))
	(( MAXTHREADS > MAXPCON )) && MAXPCON=${MAXTHREADS}
	integer MAXPROC=${ [[ ${OSNAME} == 'SunOS' ]] && \
		{ psrinfo | wc -l ;} || nproc ; }
	integer CTHREADS=$((MAXCCON/MAXPROC))
	(( CTHREADS > MINSPARE )) && SSTART=1
	(( MAXSPARE < $((MAXCCON/3)) )) && MAXSPARE=$((MAXCCON/3))
	(( MAXSPARE < MINSPARE )) && MAXSPARE=${MINSPARE}
	(( CTHREADS > MAXSPARE )) && SSTART=1
	typeset TLIMIT=""
	(( CTHREADS > 64 )) && TLIMIT="ThreadLimit  ${CTHREADS}"
	(( MAXPROC < 32 )) && MAXPROC=32	# used for prefork, eigentl. #CPUs

	if [[ ${OSNAME} == 'SunOS' ]]; then
		(( CFG.bits == 64 )) && MDIR='libexec/64'
		(( OSREL >= 11003 )) && MDIR='libexec'
	else
		MDIR='modules'
	fi

	# 2.4
	for M in ${MPM[@]} ; do
		[[ -e ${CFG.root}/${MDIR}/mod_mpm_${M}.so ]] && (( X++ ))
	done
	N=$X
	for M in ${MPM[@]} ; do
		[[ -e ${CFG.root}/${MDIR}/mod_mpm_${M}.so ]] || continue
		(( X-- ))
		(( X > 0 )) && MBASE+="\n${I}<IfDefine ${M}>"
		MBASE+="\n${I}\tLoadModule\tmpm_${M}_module\t\t${MDIR}/mod_mpm_${M}.so"
		if (( X > 0 )); then
			MBASE+="\n${I}</IfDefine>\n${I}<IfDefine !${M}>"
			TAIL="\n${I}</IfDefine>${TAIL}"
			(( X > 1 )) && I+='\t'
		fi
	done
	[[ -n ${TAIL} ]] && MBASE+="${TAIL}"
	if (( N > 1 )); then
		if [[ -e ${CFG.root}/${MDIR}/mod_mpm_prefork.so ]]; then
			MBASE+='\n<IfDefine prefork>'
			MBASE+="\n\tLoadModule\tcgi_module\t\t${MDIR}/mod_cgi.so"
			MBASE+='\n</IfDefine>'
			MBASE+='\n<IfDefine !prefork>'
			MBASE+="\n\tLoadModule\tcgid_module\t\t${MDIR}/mod_cgid.so"
			MBASE+='\n</IfDefine>'
		else
			MBASE+="\n\tLoadModule\tcgid_module\t\t${MDIR}/mod_cgid.so"
		fi
	elif [[ -e ${CFG.root}/${MDIR}/mod_mpm_prefork.so ]]; then
		MBASE+="\n\tLoadModule\tcgi_module\t\t${MDIR}/mod_cgi.so"
	else
		# assume worker
		MBASE+="\n\tLoadModule\tcgid_module\t\t${MDIR}/mod_cgid.so"
	fi

	addMods MBASE "${CFG.root}" "${MDIR}" \
		_access_compat reqtimeout _imagemap log_config logio unixd \
		'alias' _asis autoindex deflate dir _env _expires _filter _headers\
		_include mime_magic mime negotiation rewrite setenvif

	addMods MAUTHN "${CFG.root}" "${MDIR}" \
		_auth_basic _auth_digest \
		authn_core authn_default \
		_authn_file _authn_anon _authn_dbd _authn_dbm _authnz_ldap

	addMods MAUTHZ "${CFG.root}" "${MDIR}" \
		authz_core authz_default authz_host \
		_authz_user _authz_groupfile _authz_dbm _authz_owner

	addMods MCACHE "${CFG.root}" "${MDIR}" \
		_cache _file_cache _ldap \
		_disk_cache _cache_disk _mem_cache

	if [[ -e ${CFG.root}/${MDIR}/mod_auth_gss.so ]]; then
		MMISC+='\n# Kerberos - '
		MMISC+='http://kenai.com/projects/mod-auth-gss/pages/Configuration'
		addMods MMISC "${CFG.root}" "${MDIR}" _auth_gss
	fi
	addMods MMISC "${CFG.root}" "${MDIR}" \
		_actions _cern_meta _dumpio _dbd _ext_filter _log_debug _log_forensic \
		_speling _sed _substitute _suexec _unique_id _usertrack _vhost_alias \
		_version


	[[ -n ${MBASE} ]] && MBASE="${ print ${MBASE:2} ; }"
	[[ -n ${MAUTHN} ]] && MAUTHN="${ print ${MAUTHN:2} ; }"
	[[ -n ${MAUTHZ} ]] && MAUTHZ="${ print ${MAUTHZ:2} ; }"
	[[ -n ${MCACHE} ]] && MCACHE="${ print ${MCACHE:2} ; }"
	[[ -n ${MMISC} ]] && MMISC="${ print ${MMISC:2} ; }"

	typeset DENY_ALL ALLOW_ALL ALLOW_SUBNET IP= REWRITELOG VHOST=
	IP=( ${ getent hosts ${CFG.fqdn} ; } )
	if [[ ${CFG.vers} == '/2.2' ]]; then
		# assume 2.2
		DENY_ALL='Order allow,deny
	Deny from all'
		ALLOW_ALL='Order allow,deny
	Allow from all'
		ALLOW_SUBNET='Order allow,deny
	Allow from 127.0.0.1 10.0.0.0/24'
		P='DefaultType text/plain'
		REWRITELOG='RewriteLogLevel 0
	RewriteLog  "|'"${ROTATELOGS} ${CFG.logdir}"'/@NODENAME@.@DOMAIN@/%Y%m%d-%H%M%S-rewrite.log 86400"'
		VHOST='NameVirtualHost '"${IP[0]}:${CFG.port}"'
'
	else
		# assume 2.4
		DENY_ALL='Require all denied'
		ALLOW_ALL='Require all granted'
		ALLOW_SUBNET='Require ip 127.0.0.1 10.0.0.0/24'
		REWRITELOG='#LogLevel rewrite_module:trace5
	LogLevel rewrite:notice'
		VHOST="Define IP ${IP[0]}"'
Define PORT '"${CFG.port}"'
Define SSL_PORT '"${CFG.sslport}"'
'
		IP[0]='${IP}'
		CFG.port='${PORT}'
		CFG.sslport='${SSL_PORT}'
		LOG_X="-L ${CFG.logdir}/access.log"
	fi

	cat >${CFG.tfile}<<EOF
# Das ist die minimale Konfiguration, die a priori jeder Instanz zur 
# Verfuegung stehen sollte. Weitere fuer alle sites geltende Eintraege sollten
# in conf/extern.conf eingetragen werden, die VirtualServer spezifischen
# in conf/\$FQDN .

ServerRoot	"${CFG.root}"
PidFile		"${CFG.logdir}/httpd.pid"
Listen		127.0.0.1:${LOCAL_PORT}

# Commonly used Modules
${MBASE}

# authentication modules
${MAUTHN}

# authorization modules
${MAUTHZ}

# cache modules
${MCACHE}

# misc modules rarely used
${MMISC}

User		webservd
Group		webservd
ServerAdmin	root@localhost
ServerName	localhost

# StartServers: initial number of server processes to start
# MinSpareThreads: minimum number of worker threads which are kept spare.
# 				   StartServers * MinSpareThreads = initial number of workers.
# MaxSpareThreads: maximum number of worker threads which are kept spare
# ThreadsPerChild: constant number of worker threads in each server process.
# 				   for proxy worker this also implies the max. number of
#				   connections to the real [web] server.
# MaxClients: maximum number of simultaneous client connections
# MaxRequestsPerChild: maximum number of requests a server process serves
# ServerLimit: automatically determined == MaxClients/ThreadsPerChild + 1 
StartServers		${SSTART}
<IfModule !prefork.c>
	${TLIMIT}
	MinSpareThreads		${MINSPARE}
	MaxSpareThreads		${MAXSPARE}
	ThreadsPerChild		${CTHREADS}
	MaxClients			${MAXCCON}
	MaxRequestsPerChild	0
</IfModule>
<IfModule prefork.c>
	MinSpareServers     4
	MaxSpareServers     8
	MaxClients			${MAXPROC}
	MaxRequestsPerChild 10000
</IfModule>

${P}
TypesConfig				${CFG.defcfgdir}/mime.types
MIMEMagicFile			${CFG.defcfgdir}/magic
EnableMMAP				on
EnableSendfile			on
Timeout					300
KeepAlive				On
KeepAliveTimeout		5
MaxKeepAliveRequests	10000
UseCanonicalName		On
ServerTokens			Full
ServerSignature			On
HostnameLookups			On
${MUTEX}

<IfModule reqtimeout_module>
	# Format: time to wait for the 1st byte in seconds, rate in Bytes per second
	RequestReadTimeout header=20-40,minrate=500
	RequestReadTimeout body=10,minrate=500
</IfModule>

<IfModule setenvif_module>
	# all other defaults refer to ancient software no-one should use anymore
	BrowserMatch    " Konqueror/4" redirect-carefully
</IfModule>

<IfModule dir_module>
	DirectoryIndex	index.shtml index.html index.html.var
</IfModule>

<FilesMatch "^\.ht">
	${DENY_ALL}
</FilesMatch>

<Directory />
	Options -FollowSymLinks
	AllowOverride None
	${DENY_ALL}
</Directory>

DocumentRoot "${CFG.defdatadir}/htdocs"
<Directory "${CFG.defdatadir}/htdocs">
	Options +Indexes +MultiViews -FollowSymLinks
	AllowOverride None
	${ALLOW_ALL}
</Directory>

ScriptAlias /cgi-bin/printenv ${CFG.defsharedir}/cgi-bin/printenv
<Location "/cgi-bin/printenv">
	${ALLOW_SUBNET}
</Location>

ScriptAlias /cgi-bin/ "${CFG.defdatadir}/cgi-bin/"
<Directory "${CFG.defdatadir}/cgi-bin">
	AddHandler		cgi-script .cgi
	AllowOverride None
	Options +SymLinksIfOwnerMatch
	${ALLOW_ALL}
</Directory>

<IfModule rewrite_module>
	${REWRITELOG//\"*/\"${CFG.logdir}/rewrite.log\"}
</IfModule>

LogLevel				warn
# We do not pipe this into rotatelogs, since this file usually stays small
# and startup error are easier to detect (no need find the right log file)
ErrorLog				"${CFG.logdir}/error.log"

LogFormat				"%h %{%F %T %z}t %X %I %O %B %D %u %>s \"%r\" \"%{Referer}i\" \"%{User-Agent}i\"" extended
CustomLog				"|${ROTATELOGS} ${LOG_X} ${CFG.logdir}/%Y%m%d-%H%M%S-access.log 2592000" extended env=!SSL_PROTOCOL

<IfModule cgid_module>
	ScriptSock		${CFG.logdir}/cgid.sock
</IfModule>

# Multilang error docs
Alias /error/ "${CFG.defsharedir}/error/"
<Directory "${CFG.defsharedir}/error">
	AllowOverride None
	Options +IncludesNoExec +SymLinksIfOwnerMatch
	AddOutputFilter Includes html
	AddHandler type-map var
	${ALLOW_ALL}
	LanguagePriority de en fr es cs it ja ko nl pl pt-br ro sv tr
	ForceLanguagePriority Prefer Fallback
</Directory>
ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var
ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var
ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var
ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var
ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var
ErrorDocument 410 /error/HTTP_GONE.html.var
ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var
ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var
ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var
ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var
ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var
ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var
ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var
ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var
ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var

# Fancy Auto indexing
Alias /icons/ "${CFG.defsharedir}/icons/"
<Directory "${CFG.defsharedir}/icons">
	Options Indexes MultiViews
	AllowOverride None
	${ALLOW_ALL}
</Directory>
<IfModule autoindex_module>
IndexOptions	FancyIndexing FoldersFirst VersionSort NameWidth=* DescriptionWidth=*
AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
AddIconByType (TXT,/icons/text.gif) text/*
AddIconByType (IMG,/icons/image2.gif) image/*
AddIconByType (SND,/icons/sound2.gif) audio/*
AddIconByType (VID,/icons/movie.gif) video/*
AddIcon /icons/binary.gif .bin .exe
AddIcon /icons/binhex.gif .hqx
AddIcon /icons/tar.gif .tar
AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
AddIcon /icons/a.gif .ps .ai .eps
AddIcon /icons/layout.gif .html .shtml .htm .pdf
AddIcon /icons/text.gif .txt
AddIcon /icons/c.gif .c
AddIcon /icons/p.gif .pl .py
AddIcon /icons/f.gif .for
AddIcon /icons/dvi.gif .dvi
AddIcon /icons/uuencoded.gif .uu
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
AddIcon /icons/tex.gif .tex
AddIcon /icons/bomb.gif core
AddIcon /icons/back.gif ..
AddIcon /icons/hand.right.gif README
AddIcon /icons/folder.gif ^^DIRECTORY^^
AddIcon /icons/blank.gif ^^BLANKICON^^
DefaultIcon /icons/unknown.gif
ReadmeName README.html
HeaderName HEADER.html
IndexIgnore .ht* *~ *# HEADER* RCS CVS *,v *,t
</IfModule>

# Include all files in the given directory
Include ${CFG.cfgdir}/extern.conf

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
EOF
	copyTempFile "${CONF}"

	getConf CONF extern.conf
	if [[ -e ${CFG.root}/${MDIR}/mod_imagemap.so ]]; then
		MMISC='#<IfModule !imagemap_module>
#	LoadModule	imagemap_module		'"${MDIR}/mod_imagemap.so"'
#</IfModule>'
	else
		MMISC=
	fi

	cat >${CFG.tfile}<<EOF
# Secure (SSL/TLS) connections
#Include ${CFG.cfgdir}/extra/ssl.conf

# Real-time info on requests and configuration
Include ${CFG.cfgdir}/extra/info.conf

# Real-time info on requests and configuration
Include ${CFG.cfgdir}/extra/mime.types.extensions

# PhP configuration - provided as an example
#Include ${CFG.cfgdir}/extra/php.conf

<IfModule !include_module>
	LoadModule	include_module		${MDIR}/mod_include.so
</IfModule>
<IfModule !rewrite_module>
	LoadModule	rewrite_module		${MDIR}/mod_rewrite.so
</IfModule>
#<IfModule !asis_module>
#	LoadModule	asis_module			${MDIR}/mod_asis.so
#</IfModule>
<IfModule !expires_module>
	LoadModule	expires_module		${MDIR}/mod_expires.so
</IfModule>
${MMISC}

AddEncoding gzip .gz
ExpiresActive On
ExpiresDefault "access plus 1 month"
ExpiresByType text/javascript "access plus 7 days"
ExpiresByType text/css "access plus 7 days"

# Per default apache deduces 'application/x-gzip' from \.gz$ and unfortunately
# "AddType ${type} ${ext1}.${ext2}" doesn't work. So:
<FilesMatch "\.js\.gz$">
	ForceType text/javascript
</FilesMatch>
<FilesMatch "\.css\.gz$">
	ForceType text/css
</FilesMatch>

<Location ~ "CVS/.*">
	#AllowOverride AuthConfig Limit
	${DENY_ALL}
</Location>
<Location "/cgi-bin/printenv">
	${ALLOW_SUBNET}
</Location>

${VHOST}
Listen ${IP[0]}:${CFG.port}

<IfModule ssl_module>
	SSLEngine Off
</IfModule>
<VirtualHost ${IP[0]}:${CFG.port}>
	Include ${CFG.cfgdir}/${CFG.fqdn}
</VirtualHost>
<IfModule ssl_module>
	Listen ${IP[0]}:${CFG.sslport}
	<VirtualHost ${IP[0]}:${CFG.sslport}>
		SSLEngine on
		Include ${CFG.cfgdir}/${CFG.fqdn}
	</VirtualHost>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
EOF
	copyTempFile "${CONF}"

	getConf CONF extra/manual.conf
	cat >${CFG.tfile}<<EOF
# Manuals - pkg install pkg:/web/server/apache-22/documentation
#           apt-get install apache2-doc
AliasMatch ^/apache/manual(?:/(?:en|de|es|fr|ja|ko|pt-br|ru))?(/.*)?$ "${CFG.defdocdir}/manual\$1"
<Directory "${CFG.defdocdir}/manual">
	Options Indexes
	AllowOverride None
	${ALLOW_ALL}

	<Files *.html>
		SetHandler type-map
	</Files>

	SetEnvIf Request_URI ^/apache/manual/(de|en|es|fr|ja|ko|pt-br|ru)/ prefer-language=\$1
	RedirectMatch 301 ^/apache/manual(?:/(de|en|es|fr|ja|ko|pt-br|ru)){2,}(/.*)?$ /apache/manual/\$1\$2
	LanguagePriority de en es fr ja ko pt-br ru 
	ForceLanguagePriority Prefer Fallback
</Directory>

# vim: ts=4 filetype=apache
EOF
	copyTempFile "${CONF}" 

	CONF=${CFG.cfgdir}/pass
	if [[ ! -e $CONF ]]; then
		cat >${CFG.tfile}<<EOF
#!/bin/sh
case $1 in
	${CFG.fqdn})
		echo 'brauchenWirNich'
		;;
	*)
		echo 'UndDieErstRechtNicht'
		;;
esac
EOF
		copyTempFile "${CONF}" 0750
		+ chgrp webservd ${CONF}
	fi
	[[ ! -x ${CONF} ]] && + chmod 0750 ${CONF}

	if [[ -e ${CFG.root}/${MDIR}/mod_socache_shmcb.so ]]; then
		MMISC='<IfModule !socache_shmcb_module>
	LoadModule	socache_shmcb_module	'"${MDIR}/mod_socache_shmcb.so"'
</IfModule>'
	else
		MMISC=
	fi
	if [[ ${OSNAME} == 'SunOS' ]]; then
		MMISC+='
# Use kernel/hardware accelerated SSL
# see also Sun BluePrints: http://www.oracle.com/technetwork/server-storage/solaris10/documentation/819-5782-150147.pdf
SSLCryptoDevice pkcs11'
	fi

	getConf CONF extra/ssl.conf
	# 2.4 replaced 'SSLMutex' by 'Mutex' (see above)
	[[ -n ${MUTEX} ]] && MUTEX= || MUTEX='SSLMutex				sem'
	cat >${CFG.tfile}<<EOF
# Basic SSL Configuration.
<IfModule !ssl_module>
	LoadModule	ssl_module				${MDIR}/mod_ssl.so
</IfModule>
${MMISC}
SSLRandomSeed startup file:/dev/urandom 512
SSLRandomSeed connect file:/dev/urandom 512
AddType application/x-x509-ca-cert  .crt
AddType application/x-pkcs7-crl     .crl
SSLPassPhraseDialog		exec:${CFG.cfgdir}/pass
SSLSessionCache			shmcb:${CFG.logdir}/ssl_scache(512000)
SSLSessionCacheTimeout	300
${MUTEX}
# check with: openssl ciphers -v '...'
#SSLCipherSuite			ALL:!ADH:!kEDH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCipherSuite			EECDH+AES:AES128-GCM-SHA256:HIGH:!MD5:!aNULL:!EDH
# SSL2 is obsolete
SSLProtocol				all -SSLv2 -SSLv3
SSLHonorCipherOrder on
#SSLVerifyClient require
#SSLVerifyDepth 5

SSLCertificateFile ${CFG.cfgdir}/ssl.crt/server.crt
SSLCertificateKeyFile ${CFG.cfgdir}/ssl.key/server.key
SSLCACertificatePath ${CFG.cfgdir}/ssl.crt
<FilesMatch "\.(cgi|shtml|phtml|php)$">
	SSLOptions +StdEnvVars
</FilesMatch>
<Directory "${CFG.defdatadir}/cgi-bin">
	SSLOptions +StdEnvVars
</Directory>
BrowserMatch "MSIE [2-5]" nokeepalive ssl-unclean-shutdown \
	downgrade-1.0 force-response-1.0
LogFormat   "%h %{%F %T %z}t %X %I %O %B %D %{SSL_PROTOCOL}x %{SSL_CIPHER}x %u %>s \"%r\" \"%{Referer}i\" \"%{User-Agent}i\"" extendedssl
CustomLog	"|${ROTATELOGS} ${LOG_X//access/ssl} ${CFG.logdir}/%Y%m%d-%H%M%S-ssl.log 2592000" extendedssl env=SSL_PROTOCOL

# vim: ts=4 filetype=apache
EOF
	copyTempFile "${CONF}"

	# just for convinience
	typeset X="~admin/etc/server"
	if [[ -r ${X}.key && -r ${X}.crt ]]; then
		+ cp -p ${X}.key ${CFG.cfgdir}/ssl.key/server.key
		cp ${X}.crt ${CFG.cfgdir}/ssl.crt/server.crt
	else
		# gets created autom. by postinst script of ubuntu pkg 'ssl-cert'
		X='ssl-cert-snakeoil'
		if [[ -e /etc/ssl/private/${X}.key && \
			! -e ${CFG.cfgdir}/ssl.crt/server.crt ]]
		then
			# don't symlink - postgres svc on lnx will use those by default too
			+ cp -p /etc/ssl/private/${X}.key ${CFG.cfgdir}/ssl.key/server.key
			cp /etc/ssl/certs/${X}.pem ${CFG.cfgdir}/ssl.crt/server.crt
		fi
	fi
	if [[ -e ${CFG.cfgdir}/ssl.crt/server.crt ]]; then
		+ chown ${CFG.owner}:webservd \
			${CFG.cfgdir}/ssl.{crt/server.crt,key/server.key}
		chmod 0644 ${CFG.cfgdir}/ssl.crt/server.crt
		chmod 0640 ${CFG.cfgdir}/ssl.key/server.key
		${CFG.cfgdir}/ssl.crt/hashCerts
	fi

	getConf CONF extra/proxy.conf
	MMISC=
	addMods MMISC "${CFG.root}" "${MDIR}" \
		proxy proxy_http _proxy_html \
		lbmethod_byrequests slotmem_shm \
		_proxy_balancer _proxy_express _proxy_ajp _proxy_connect _proxy_ftp

	cat >${CFG.tfile}<<EOF
# Basic Proxy configuration example.
<IfModule !proxy_module>
	# reverse proxy stuff
EOF
	print "${MMISC}" >>${CFG.tfile}
	cat >>${CFG.tfile}<<EOF
</IfModule>

ProxyTimeout    10
ProxyRequests   Off

# NOTE:
#  timeout .. max. time to wait for data (response) from the server. Overwrites
#             global ProxyTimeout setting. (important wrt. search queries).
#  connectiontimeout .. max. time allowed to establish a connection to the srver
#  max .. max. number of connections allowed to the server. Since the server
#         does not create more threads on demand, it is pointless to allow more
#         than MAX_THREADS. In so far we let Apache handle these situations.
#ProxyPass /DIRECTORY_TO_PROXY/ http://localhost:PORT/ \\
#	nocanon connectiontimeout=5 timeout=60 max=${MAXTHREADS}

# vim: ts=4 filetype=apache
EOF
	copyTempFile "${CONF}"

	getConf CONF extra/info.conf
	cat >${CFG.tfile}<<EOF
<IfModule !status_module>
	LoadModule	status_module			${MDIR}/mod_status.so
	LoadModule	info_module				${MDIR}/mod_info.so
</IfModule>
ExtendedStatus On
<Location /server-status>
	SetHandler server-status
	${ALLOW_SUBNET}
</Location>
<Location /server-info>
	SetHandler server-info
	${ALLOW_SUBNET}
</Location>

# vim: ts=4 filetype=apache
EOF
	copyTempFile "${CONF}"

	getConf CONF extra/dav.conf
	cat >${CFG.tfile}<<EOF
# DAV Configuration example
<IfModule !dav_module>
	LoadModule	dav_module				${MDIR}/mod_dav.so
	LoadModule	dav_fs_module			${MDIR}/mod_dav_fs.so
</IfModule>
DavLockDB "${CFG.logdir}/${CFG.fqdn}/DavLock"
Alias /uploads "/data/dav/${CFG.fqdn}/uploads"
<Directory "/data/dav/${CFG.fqdn}/uploads">
	Dav On
	AuthType Digest
	AuthName DAV-upload
	# htdigest -c ${CFG.cfgdir}/${CFG.fqdn}-dav.passwd
	AuthUserFile ${CFG.cfgdir}/${CFG.fqdn}-dav.passwd
	<LimitExcept GET POST OPTIONS>
		require user admin
	</LimitExcept>
	BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
	BrowserMatch "MS FrontPage" redirect-carefully
	BrowserMatch "^WebDrive" redirect-carefully
	BrowserMatch "^WebDAVFS/1.[0123]" redirect-carefully
	BrowserMatch "^gnome-vfs/1.0" redirect-carefully
	BrowserMatch "^XML Spy" redirect-carefully
	BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
	BrowserMatch " Konqueror/4" redirect-carefully
</Directory>

# vim: ts=4 filetype=apache
EOF
	copyTempFile "${CONF}"

	getConf CONF extra/mime.types.extensions
	cat >${CFG.tfile}<<EOF
<IfModule mime_module>
AddType text/html .shtml
AddType text/xml .classpath .project .xml
AddType application/x-java-jnlp-file .jnlp
AddType application/x-java-archive-diff .jardiff
AddType application/x-java-archive .jar
AddType application/x-compress .Z
AddType application/x-bzip2 .bz2
AddType application/x-gzip .gz .tgz
AddType application/x-ns-proxy-autoconfig .pac
</IfModule>

# Default icons come from /icons/* 
# usually used by fancy indexing (format: 20x22px)
<IfModule autoindex_module>
AddDescription "Server Side Include file" .shtml

AddDescription "Adobe Portable Document Format" .pdf
AddIcon /icons/pdf.gif .pdf

AddDescription "Eclipse classpath configuration file" .classpath
AddDescription "Eclipse project configuration file" .project
AddDescription "CVS configuration file for pathes to ignore" .cvsignore
AddDescription "Ant build properties customization file" build.properties
AddDescription "Ant build file" build.xml
AddIcon /icons/screw1.gif .classpath .cvsignore .project .properties build.xml

AddDescription "Java Archive" .jar
AddDescription "Java Network Lunch Protocol Application" .jnlp
AddDescription "Java Archive Diff" .jardiff

AddDescription "tar archive" .tar
AddDescription "GZIP compressed archive" .gz
AddDescription "GZIP compressed tar archive" .tgz

AddDescription "Z compressed archive" .Z

AddDescription "Bzip2 compressed archive" .bz2
AddIcon /icons/compressed.gif .bz2

AddDescription "Proxy Auto Configuration file" .pac
AddIcon /icons/world2.gif .pac
</IfModule>

# vim: ts=4 filetype=apache
EOF
	copyTempFile "${CONF}"

	getConf CONF extra/userdir.conf
	cat >${CFG.tfile}<<EOF
<IfModule !userdir_module>
	LoadModule	userdir_module			${MDIR}/mod_userdir.so
</IfModule>
UserDir disabled root
UserDir public_html
<Directory /home/*/public_html>
	AllowOverride FileInfo AuthConfig Limit Indexes
	Options +MultiViews +Indexes +SymLinksIfOwnerMatch +IncludesNoExec
	<Limit GET POST OPTIONS>
		${ALLOW_ALL}
	</Limit>
	<LimitExcept GET POST OPTIONS>
		${DENY_ALL}
	</LimitExcept>
</Directory>

# vim: ts=4 filetype=apache
EOF
	copyTempFile "${CONF}"

	getConf CONF template.conf
	[[ -n ${LOG_X} ]] && LOG_X="-L ${CFG.logdir}/@NODENAME@.@DOMAIN@/access.log"
	[[ -e ${CFG.defdocdir}/manual ]] && P='' || P='#'
	cat >${CFG.tfile}<<EOF
# Generiert von template.conf mittels:
# ${SED} -e "s/@\NODENAME@/@NODENAME@/g" -e "s/@\DOMAIN@/@DOMAIN@/g" template.conf
# 
ServerAdmin webmaster+@NODENAME@@@DOMAIN@
ServerName @NODENAME@.@DOMAIN@
ServerAlias @NODENAME@
ServerAlias @DOMAIN@

# Local access to the Apache HTTP Server Manual
${P}Include ${CFG.cfgdir}/extra/manual.conf

# Proxy configuration - check security notes!
# Example ${CFG.cfgdir}/extra/proxy.conf

# Distributed authoring and versioning (WebDAV)
# Example ${CFG.cfgdir}/extra/dav.conf

#Include ${CFG.cfgdir}/extra/userdir.conf

#AddOutputFilter INCLUDES .shtml
#AddHandler send-as-is asis

# 1 day logfile rotation
CustomLog	"|${ROTATELOGS} ${LOG_X} ${CFG.logdir}/@NODENAME@.@DOMAIN@/%Y%m%d-%H%M%S-access.log 86400" extended env=!SSL_PROTOCOL
<IfModule ssl_module>
CustomLog	"|${ROTATELOGS} ${LOG_X//access/ssl} ${CFG.logdir}/@NODENAME@.@DOMAIN@/%Y%m%d-%H%M%S-ssl.log 86400" extended env=SSL_PROTOCOL
</IfModule>
ErrorLog	"|${ROTATELOGS} ${LOG_X//access/error} ${CFG.logdir}/@NODENAME@.@DOMAIN@/%Y%m%d-%H%M%S-error.log 86400"
<IfModule rewrite_module>
	${REWRITELOG}
</IfModule>

DocumentRoot	${CFG.datadir}/sites/@NODENAME@.@DOMAIN@/htdocs

ScriptAlias	/cgi-bin/printenv ${CFG.defsharedir}/cgi-bin/printenv
ScriptAlias	/cgi-bin/ ${CFG.datadir}/sites/@NODENAME@.@DOMAIN@/cgi-bin/

<IfModule rewrite_module>
	RewriteEngine On
	# this stuff gets usually handled by this httpd instance itself. Avoid redir
	RewriteRule ^/(server-|icons|apache|error)	-	[L]
	
	# Use official hostname/URL
	RewriteCond %{HTTP_HOST} !=@NODENAME@.@DOMAIN@
	RewriteCond %{HTTP_HOST} !=@NODENAME@
	RewriteCond %{HTTP_HOST} !=localhost
	RewriteRule ^/(.*)	%{REQUEST_SCHEME}://@NODENAME@.@DOMAIN@/\$1 [R=301,L]

	# Handled by this instance
	RewriteRule ^/cgi-bin  - [L]
</IfModule>

<Directory "${CFG.datadir}/sites/@NODENAME@.@DOMAIN@/cgi-bin">
	${ALLOW_ALL}
</Directory>

#ScriptAlias /cgi-bin/squid /usr/squid/libexec/cachemgr.cgi
#<Location /cgi-bin/squid>
#	${ALLOW_SUBNET//$'\n'/$'\n#'}
#</Location>

<Directory "${CFG.datadir}/sites/@NODENAME@.@DOMAIN@/htdocs">
	AddType text/html .inc
	SetEnvIf Request_URI \.(en|de)$ prefer-language=$1
	LanguagePriority de en
	ForceLanguagePriority Prefer Fallback
	AllowOverride AuthConfig Limit
	# If rewrite engine is on (default), SymLinksIfOwnerMatch is needed as well
	# @since 2.4 (don't use FollowSymLinks which would also satisfy it)
	Options +Indexes +Includes +MultiViews +SymLinksIfOwnerMatch
	${ALLOW_ALL}
</Directory>

#<Directory "/web">
#	AddType text/plain .sh
#	AddIcon /icons/patch.gif .patch
#</Directory>

#<IfModule ssl_module>
#	SSLCertificateFile ${CFG.cfgdir}/ssl.crt/@NODENAME@.@DOMAIN@.crt
#	SSLCertificateKeyFile ${CFG.cfgdir}/ssl.key/@NODENAME@.@DOMAIN@.key
#</IfModule>

# vim: ts=4 filetype=apache
EOF
	copyTempFile "${CONF}" 0444

	typeset TEMPLATE="${CONF}"
	getConf CONF ${CFG.fqdn}
	NODENAME=${CFG.fqdn%%.*}
	DOMAIN=${CFG.fqdn#*.}
	${SED} -e "s/@NODENAME@/${NODENAME}/g" -e "s/@DOMAIN@/${DOMAIN}/g" \
		${TEMPLATE} > "${CFG.tfile}"
	copyTempFile "${CONF}"

	CFG.config=1
}

Man.addFunc updateCertHasher '' '[+NAME?updateCertHasher - aktuallisiert script zum Anlegen der SSL-Zertifikat-Links]
[+DESCRIPTION?Aktualisiert das script \bssl.crt/hashCerts\b im config Verzeichnis, das für das Aktualisieren/Löschen der Hash-Symlinks auf die jeweiligen SSL-Zertifikate im selben Verzeichnis zuständig ist. Das Script muß jedesmal manuell gestartet werden, wenn sich der Inhalt eines SSL-Zertifikats ändert oder neue hinzugekommen sind.]
[+?Falls die relevanten Verzeichnis noch nicht vorhanden sind, werden diese automatisch erstellt.]
[+SEE ALSO?\bcheckDirs()\b, \bcopyTempFile()\b]
'
function updateCertHasher {
	(( ${CFG.hasher} )) && return
	checkDirs
	typeset FILE="${CFG.cfgdir}/ssl.crt/hashCerts"
	if [[ -f ${SDIR}/${FILE##*/} ]]; then
		+ cp ${SDIR}/${FILE##*/} "${FILE}"
		+ chmod 755 "${FILE}"
	else
		cat >${CFG.tfile}<<EOF
#!/bin/ksh93

OPENSSL=\${ whence openssl; }
[[ -z \${OPENSSL} || ! -x \${OPENSSL} ]] && \\
	print -u2 "openssl program not found - exiting." && exit 1

SDIR=\${.sh.file} && SDIR=\${SDIR%/*} && [[ \${SDIR} == \${.sh.file} ]] && SDIR=\${PWD}

Usage() {
	print -u2 '
Usage: %s [-h] [-d dir]

Remove old openssl hash symbolic links to *.crt files and re-create them in
the target directory.

  -h     .. print this help and exit.
  -d dir .. target directory. Default: Directory, which contains this script.
' \${0##*/}
}

while getopts "hd:" option ; do
	case "\${option}" in
		h) Usage ; exit 0 ;;
		d) SDIR="\${OPTARG}" ;;
	esac
done

cd "\${SDIR}"
(( \$? != 0 )) && exit 1

# remove old stuff
for FILE in [0-9a-fA-F]*.[0-9]*; do
	[[ ! -L \${FILE} ]] && continue
	LSI=( \${ ls -l \${FILE} ; } )
	DST=\${LSI[10]}
	[[ -z \${DST} || \${DST##*.} != 'crt' ]] && continue
	rm -f \${FILE}
done

# re-create links
integer N
FORMAT="%-15s ... %s\n"
for FILE in *.crt; do
	[[ ! -e \${FILE} ]] && continue
	grep -q SKIPME \${FILE}
	(( \$? == 0 )) && printf "\${FORMAT}" "\${FILE}" 'Skipped' && continue
	N=0
	while (( N < 256 )); do
		HASH=\${ \${OPENSSL} x509 -noout -hash < \${FILE}; }
		[[ -r \${HASH}.\$N ]] && (( N++ )) && continue
		printf "\${FORMAT}" "\${FILE}" "\${HASH}.\$N"
		ln -s "./\${FILE}" "\${HASH}.\$N"
		break
	done
done
EOF
		copyTempFile "${FILE}" 0755
	fi
	CFG.hasher=1
}

function showUsage {
	X=${ print ${Man.FUNC[${2:-MAIN}]} ; }
	[[ -n $2 ]] && K='--man' || K='-?'
	getopts -a "$PROG" "$X" OPT $K
}

ApacheEnv_t CFG
CFG.init '/data'

Man.addFunc MAIN '' '[+NAME?'"${PROG}"' - Basiskonfiguration der default HTTP-Instanz einer zone]
[+DESCRIPTION?Mit dem Script kann in einer globalen oder nicht-globalen Zone die default HTTPd-Instanz konfiguriert werden. Es bezieht sich immer auf die Zone, in der dieses Script gestartet wird.]
[+?Sind die notwendigen Verzeichnisse/ZFS oder Konfig-Dateien noch nicht vorhanden, werden sie automatisch von diesem Script erstellt. Dies erfordert u.U. entsprechende SMF-Authorisierung und erweiterte Rechte zum Schreiben der jeweiligen Dateien bzw. ihres Besitzers/Rechte. Falls der diese Script Ausführende keine entsprechende Rolle (z.B. Primary Administator) besitzt, muß dieses Script als user root ausgeführt werden.]
[h:help?Diese Hilfe ausgegeben und Script beenden.]
[F:functions?Liste aller definierten Funktionen im Script ausgeben (\btypeset +f\b).]
[H:usage]:[function?Hilfe für die angegebene Script-Funktion bzw. Objekttyp anzeigen (soweit verfügbar) und Script beenden. Siehe auch Option \b-F\b.]
[T:trace]:[fname_list?Eine Komma- oder Leerzeichen-separierte Liste von Funktionsnamen, die während ihrer Ausführung getracet werden sollen.]
[d:data]:[dir?Ordner, unter dem der sites Daten-Ordner angeleget werden soll (falls noch nicht vorhanden) inkl. Verzeichnisse für die Web-Sites. Default: '"${CFG.basedir}"']
[z:zfsBase]:[name?ZFS name unter dem das data Verzeichnis angelegt werden soll, falls noch nicht vorhanden. Default: in der globalen zone \a$POOL/$HOST\a ('"${CFG.zfsbase}"'), \bpool1\b sonst (was \a$POOL/$ZNAME/\a\bpool1\b in der globalen zone referenzieren sollte).]
[n:name]:[fqdn?Der volle DNS-Name der website. Default: '"${CFG.fqdn}"']
[s:service?SMF service properties aktualisieren.]
[c:config?Konfig-Dateien erstellen/aktualisieren.]
[u:certs?Das \bssl.crt/hashCerts\b Script aktualisieren.]
[o:overwrite?Wenn angegeben, wird von den relevanten httpd *.conf Dateien eine Sicherungskopie mit einem Timestamp als Suffix erstellt, bevor sie überschrieben werden. Falls nicht angegeben, wird keine httpd *.conf Datei überschrieben: stattdessen wird die neue Konfig in einer entsprechenden Datei mit einem Timestamp als Suffix gespeichert.]
[O:owner]:[name?Der zukünftige Besitzer der Konfig-Dateien und website Verzeichnisse. Default: '"${CFG.owner}"']
[G:group]:[name?Name der Gruppe, die dem Daten-Ordner zugeordnet werden soll. Default: '"${CFG.group}"'] 
[p:port]:[num?Port, der für das HTTP-Protokoll verwendet werden soll. Default: '"${CFG.port}"']
[P:sslport]:[num?Port, der für das HTTPS-Protokoll verwendet werden soll. Default: '"${CFG.sslport}"']
[b:bits]:[num?Für Solaris < 11.3 das binary, das genutzt werden soll (32|64), bei allen anderen OS ignoriert. Default: 64] 
[f:fork?httpd server Type auf \bprefork\b setzen. Default ist "event" falls verfügbar (Solaris >= 11.3, Linux), "worker" anderenfalls.]
[+EXAMPLES]{
	['"${PROG}"' -n test.iws.cs.ovgu.de -s -u -o -c -O webadm -G staff]
}
'
integer CMD=0
X="${ print ${Man.FUNC[MAIN]} ; }"
while getopts "${X}" option ; do
	case "${option}" in
		h) showUsage ${PROG} MAIN ; exit 0 ;;
		F) typeset +f ; exit 0 ;;
		H)  if [[ ${OPTARG%_t} != ${OPTARG} ]]; then
				${OPTARG} --man   # self-defined types
			else
				showUsage "${OPTARG}" "${OPTARG}"   # function
			fi
			exit 0
			;;
		T) 
			if [[ ${OPTARG} == 'ALL' ]]; then
				typeset -ft ${ typeset +f ; }
			else
				typeset -ft ${OPTARG//,/ }
			fi
			;;
		d) CFG.setBaseDir "${OPTARG}" ;;
		z) CFG.zfsbase="${OPTARG}" ;;
		n) CFG.fqdn="${OPTARG}" ;;
		o) CFG.overwrite=1 ;;
		x) CMD=ok ;;
		s) (( CMD|=1 )) ;;
		c) (( CMD|=2 )) ;;
		u) (( CMD|=4 )) ;;
		O) CFG.owner="${OPTARG}" ;;
		G) CFG.group="${OPTARG}" ;;
		p) CFG.port=${OPTARG} ;;
		P) CFG.sslport=${OPTARG} ;;
		b) [[ ${OPTARG} == 32 || ${OPTARG} == 64 ]] && CFG.bits=${OPTARG} || \
			{ print "${OPTARG}bit? - Scherzbold." ; exit 1 ; }
			;;
		f) CFG.stype='prefork' ;;
		*) showUsage ${PROG} ; exit 0 ;;
	esac
done
X=$((OPTIND-1))
shift $X

# Motherfucking linux
export POSIXLY_CORRECT=1

(( ! ${CMD} )) && showUsage ${PROG} MAIN && exit 1
CFG.getDefaults

(( $CMD & 1 )) && updateSvc
(( $CMD & 2 )) && createConf
(( $CMD & 4 )) && updateCertHasher
