# The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License") # (see http://www.opensource.org/licenses/CDDL-1.0). # # Copyright (c) 2011-2013 Jens Elkner. All rights reserved. # Use is subject to license terms. ############################################################################## # zone post-install customization stuff ############################################################################## Man.addFunc adjustSSH '' '[+NAME?adjustSSH - adjust sshd settings and SMF dependencies] [+DESCRIPTION?Enables root login, adjusts Ciphers settings and restricts ssh logins to user \broot\b and \badmin\b, only. Finally it removes the SMF dependency on \bautofs\b.] [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ZPATH ZNAME; }" '} [+SEE ALSO?\bzlogin\b(1), \bsshd_config\b(4), \bsvccfg\b(1M)i, \bsvcadm\b(1M)]' function adjustSSH { Log.info "Adjusting sshd config ..." gsed -i -e '/^PermitRootLogin/ s,no,yes,' \ $ZPATH/root/etc/ssh/sshd_config print 'AllowUsers root admin Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour128,arcfour256,arcfour,aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc,blowfish-cbc ' >> $ZPATH/root/etc/ssh/sshd_config # a damn stupid idea, to make ssh depend on autofs (NFS) zlogin $ZNAME svccfg -s ssh delpg fs-autofs; \ svccfg -s ssh:default refresh; svcadm refresh ssh } Man.addVar NOIPv6 'If != 0 disable IPv6 for all NICs in the zone as well as sendmail. See \bfixSendmail()\b, \bdisableIPv6()\b. Default: \b1\b.' typeset -i NOIPv6=1 Man.addFunc fixSendmail '' '[+NAME?fixSendmail - fix sendmail settings and SMF dependencies] [+DESCRIPTION?Adjust sendmail SMF settings to not depend on \bautofs\b, to automatically regenerate \bsendmail.cf\b and \bsubmit.cf\b if \b/etc/mail/sendmail.mc\b or \b/etc/mail/submit.mc\b have been changed. It also fixes the related startup scripts to work properly and avoid unnecessary rebuilds of the *.mc files. Finally and if \a$NOIPv6\a IPv6 features are removed from the \bsendmail.mc\b file.] [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ZPATH ZNAME SDIR NOIPv6; }" '} [+SEE ALSO?\bzlogin\b(1), \bsvccfg\b(1M)i, \bsvcadm\b(1M), \bsendmail\b(1M)]' function fixSendmail { Log.info "Adjusting sendmail ..." # SMTP notify should work, even if autofs/nfs hangs. However, on real # mail servers dep to autofs would be ok. cp -p $ZPATH/root/lib/svc/share/sendmail_include.sh \ $ZPATH/root/lib/svc/share/sendmail_include.sh.orig cp $SDIR/files/mail/sendmail_include.sh $ZPATH/root/lib/svc/share/ cp $SDIR/files/mail/submit.mc $ZPATH/root/etc/mail/ cp $SDIR/files/mail/sendmail.mc $ZPATH/root/etc/mail/ (( $NOIPv6 )) && gsed -i -e '/_NETINET6_/ s,^.*undef,undef,' \ $ZPATH/root/etc/mail/sendmail.mc zlogin $ZNAME svccfg -s smtp:sendmail -f - <>${FILE} zlogin ${ZNAME} ksh /var/tmp/vnic2.sh } Man.addFunc disableIPv6 '' '[+NAME?disableIPv6 - disables IPv6 usage in the zone] [+DESCRIPTION?If \a$NOIPv6\a==\b0\b this function does nothing. Otherwise the IPv6 looback address and IPv6 support gets disabled, the default IP version set to IPv4 and the precedence to IPv4 destinations set to the highest value (60).] [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ZPATH ZNAME NOIPv6; }" '} [+SEE ALSO?\bzlogin\b(1), \bipadm\b(1M), \bipaddrsel\b(1M)]' function disableIPv6 { (( $NOIPv6 == 0 )) && return Log.info "Disabling IPv6 ..." zlogin $ZNAME ipadm delete-addr lo0/v6 gsed -i -e '/_family=26;/ d' $ZPATH/root/etc/ipadm/ipadm.conf # per default nur IPv4 infos anzeigen (siehe inet_type(4) ) print 'DEFAULT_IP=IP_VERSION4' >$ZPATH/root/etc/default/inet_type #change default adress selection policy: prefer IPv4 gsed -i -e '/^::ffff:0.0.0.0/ s,10,60,' $ZPATH/root/etc/inet/ipaddrsel.conf gsed -i -e '/::1/ s,^,#,' $ZPATH/root/etc/inet/hosts zlogin $ZNAME ipaddrsel -f /etc/inet/ipaddrsel.conf zlogin ${ZNAME} svcadm restart zones-proxy-client } Man.addVar ADMINUID 'UID to use for the admin account within the new zone. Default: 101. (read-only)' typeset -ri ADMINUID=101 Man.addVar ADMINGID 'GID to use for the admin account within the new zone. Default: 10. (read-only)' typeset -ri ADMINGID=10 Man.addVar ADM_SKEL 'The directory whoses content should be copied into the admin home of the new zone. Default: \a$SDIR/admin\a. See \bsetupAdminHome()\b.' typeset ADM_SKEL="$SDIR/admin" Man.addFunc setupAdminHome '' '[+NAME?setupAdminHome - add local files to the admin home of the zone] [+DESCRIPTION?If the default admin home exists (\a$ZPATH\a\b/root/local/home/admin) and \a$ADM_SKEL\a refers to a directory, the content of that directory gets copied to the admin home of the zone. Also the passwd home entry for user \badmin\b gets changed to \b/local/home/admin\b to avoid dependencies on autofs (possible cause of login problems).] [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ZPATH ADM_SKEL ADMINUID ADMINGID; }" '} [+SEE ALSO?\bcpio\b(1)]' function setupAdminHome { typeset ADM_HOME=${ZPATH}/root/local/home/admin if [[ -d ${ADM_HOME} ]]; then if [[ -n ${ADM_SKEL} && -d ${ADM_SKEL} ]]; then Log.info "Copying admin skeleton directory ${ADM_SKEL} ..." ( cd "${ADM_SKEL}" && pax -rwL . ${ADM_HOME} ) chown -R ${ADMINUID}:${ADMINGID} ${ADM_HOME} chmod 0600 ${ADM_HOME}/.ssh/authorized_keys2 ${ADM_HOME}/.history chmod 0700 ${ADM_HOME}/.ssh gsed -i -e 's,:/home/admin,:/local/home/admin,' \ ${ZPATH}/root/etc/passwd typeset CHECK="${ZHNAME}.${ZDOMAIN} ${ZHNAME} ${ZDOMAIN}" typeset FILE=${ADM_HOME}/.ssh/authorized_keys2 X for X in ${CHECK} ' '; do [[ $X == ' ' ]] && X='' || X="@$X" if [[ -n ${MTYPE} && -r ${FILE}${X}@${MTYPE} ]]; then cp -p ${FILE} ${FILE}.orig cp -p ${FILE}${X}@${MTYPE} ${FILE} break fi if [[ -n $X && -r ${FILE}$X ]]; then cp -p ${FILE} ${FILE}.orig cp -p ${FILE}${X} ${FILE} break; fi done else Log.warn "admin skeleton directory '${ADM_SKEL}' not found " \ "- skipping admin home adjustments!" fi else Log.warn "The directory ${ZPATH}/root/local/home/admin does not exist" \ " - skipping admin home adjustments!" fi } Man.addVar MTYPE 'An arbitrary ASCII alphanum string without spaces used to further qualify config files. E.g. if one has certain rules for pure desktops one may set it to "desktop" and \bipfilterFinal()\b will use e.g. a ipf.conf template with the name \bipf.conf@\b\a$ZDOMAIN\a\b@desktop\b if available.' Man.addVar IPFCONF 'IP filter configuration template to use to populate \b/etc/ipf/ipf.conf\b of the zone. Default: best match of \a$SDIR\a\b/files/ipf.conf\b[{\b@\b\a$ZHNAME\a[\b.\b\a$ZDOMAIN\a]]|\b@\b\a$ZDOMAIN\a}]][\b@\b\a$MTYPE\a]].' Man.addFunc ipfilterFinal '' '[+NAME?ipfilterFinal - make final adjustments to the ipfilter service] [+DESCRIPTION?Setup ipmon sys logging to use \b/var/log/ipmon.log\b and instruct logadm to rotate this file every day, keep at most 30 files and compress all ipmon.log files older than 3 days.] [+?If an ipf.conf template (\a$IPFCONF\a) exists and is readable, it gets copied to \b/etc/ipf/ipf.conf\b of the zone. Also the ipfilter svcs gets enabled when this function returns.] [+?If the directory which contains the ipf.conf template also contains a file named \bippool\b or \bipnat\b with the same suffix as the template (per default \b.conf\b | \b.conf@\b\a$ZHNAME\a | \b.conf@\b\a$ZDOMAIN\a), it gets copied to the zone its /etc/ipf/ as well.] [+?For all mentioned files the following replacements are made on the fly:]{ [+VNIC0 variable?gets set to \a$ZVNIC\a.] [+@DNS_SERVER@?replaced with the configured DNS servers or "any" if unset] [+@HTTP_SERVER@?replaced with the list of IP addresses of HTTP based pkg publishers, with "!any" if there are none and the corresponding ipf list would be otherwise empty, with an empty string incl. leading comma (,) or semicolon (;) otherwise.] [+@NFS_SERVER@?replaced with the list of IP addresses of NFS based pkg publishers, with "!any" if there are none and the corresponding ipf list would be otherwise empty, with an empty string incl. leading comma (,) or semicolon (;) otherwise.] [+@SMTP_SERVER@?replaced with the list of IP addresses of mail and smart hosts configured in the /etc/mail/sendmail.cf, with "!any" if there are none and the corresponding ipf list would be otherwise empty, with an empty string incl. leading comma (,) or semicolon (;) otherwise.] } [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage TMPDIR IPFCONF MTYPE ZVNIC ZIP GW ZPATH ZNAME; }" '} [+SEE ALSO?\bipf\b(4), \bresolv.conf\b(4), \bpkg\b(1), \bzlogin\b(1), \bipmon\b(1M), \bsyslog.conf\b(4), \blogadm\b(1M), \bsvcadm\b(1M)]' function ipfilterFinal { Log.info 'Customizing IP filter ...' # no matter whether ipf.conf is available, we prepare proper logging touch ${ZPATH}/root/var/log/ipmon.log gsed -i -e '/^\*.emerg/ a\local0.debug\t/var/log/ipmon.log' \ ${ZPATH}/root/etc/syslog.conf zlogin ${ZNAME} "logadm -w ipmon -s 1b -p 1d -C 30 -z 3 \ -t '/var/log/old/\$basename.%F' \ -a 'kill -HUP \`cat /var/run/syslog.pid\`' /var/log/ipmon.log" # we do not touch originals if [[ -z ${IPFCONF} ]]; then IPFCONF=${SDIR}/files/ipf.conf typeset TOCHECK="${ZHNAME}.${ZDOMAIN} ${ZHNAME} ${ZDOMAIN}" for X in ${TOCHECK} ' '; do [[ $X == ' ' ]] && X='' || X="@$X" [[ -n ${MTYPE} && -r ${IPFCONF}${X}@${MTYPE} ]] && \ IPFCONF=${IPFCONF}${X}@${MTYPE} && break [[ -r ${IPFCONF}$X ]] && IPFCONF=${IPFCONF}$X && break done fi if [[ -z ${IPFCONF} || ! -r ${IPFCONF} ]]; then Log.info 'No suitable ipf.conf template found. Skipping ipf.conf setup.' return fi Log.info "Using ipf.conf template ${IPFCONF} ..." typeset -A ADD_NICS=( ) for OBJ in "${!ADD_ZVNICS[@]}"; do X=${OBJ%/*} [[ -n $X ]] && ADD_NICS[${X}]=1 done typeset NICS="print \"VNIC0='${ZVNIC}';\";" X Y if (( ${#ADD_NICS[@]} )) ; then integer OFFSET=0 Y=${ print "${!ADD_NICS[@]}" | tr ' ' '\n' | sort ; } for X in $Y; do (( OFFSET++ )) NICS+="print \"VNIC${OFFSET}='${X}';\";" done fi # determine DNS servers typeset DNS='' typeset -a NS=( $( awk '/^nameserver/ { print $2 }' \ ${ZPATH}/root/etc/resolv.conf ) ) for ((i=0; i < ${#NS[@]}; i++)); do X=${ getIP ${NS[$i]}; } [[ -n $X ]] && DNS+="${X}, " done [[ -n "$DNS" ]] && DNS=${DNS%, } || DNS='any' # determine HTTP and NFS servers typeset URI PROXY NFS='' HTTP='' zlogin ${ZNAME} pkg publisher -H -F tsv | \ while read X X X X X X URI PROXY ; do [[ ${PROXY} == '-' ]] && Y="${URI}" || Y="${PROXY}" X=${Y#*:} Y=${.sh.match%:} [[ $Y == 'file' ]] && X=${X##*(/)?(net/)} || X=${X##*(/)} X=${X%%:*} X=${X%%/*} [[ $X == 'localhost' || ${X:0:4} == '127.' ]] && continue X=${ getIP $X ; } if [[ -n "$X" ]]; then case "$Y" in 'http'|'https') HTTP+="${X}, " ;; 'file') NFS+="${X}, " ;; esac fi done [[ -n "${HTTP}" ]] && HTTP=${HTTP%, } || HTTP='!any' [[ -n "${NFS}" ]] && NFS=${NFS%, } || NFS='!any' # determine mail servers typeset SMTP='' egrep '^(DS|DH)' $ZPATH/root/etc/mail/sendmail.cf | while read X Y ; do Y=${X#DS} [[ $Y == $X ]] && Y=${X#DH} X=${ getIP $Y ; } [[ -n $X ]] && SMTP+="${X}, " done [[ -n "${SMTP}" ]] && SMTP=${SMTP%, } || SMTP='!any' # finally copy over and replace ipfilter configs typeset SUFFIX=${IPFCONF##*/} SUFFIX=${SUFFIX#*.} typeset -a DST=( ipf.conf ippool.conf ipnat.conf ) typeset -a SRC=( "${IPFCONF}" "${IPFCONF%/*}/ippool.$SUFFIX" "${IPFCONF%/*}/ipnat.${SUFFIX}" ) integer IDX=-1 for (( ; IDX < 3 ; IDX++ )); do [[ ! -r ${SRC[$IDX]} ]] && continue cat ${SRC[$IDX]} | /usr/xpg4/bin/awk -v "VNIC=${ZVNIC}" \ -v "DNS=${DNS}" -v "NFS=${NFS}" -v "HTTP=${HTTP}" -v "SMTP=${SMTP}"\ -v POOL=${ ((IDX==1)) ; } \ ' function replace(TOKEN, WITH, ISPOOL) { if ( WITH == "any" || WITH == "!any" ) { REPL=""; if (ISPOOL == 1) sub("any", "0/0", WITH); } else { REPL=WITH } gsub("[[:space:]]*" TOKEN, " " REPL ); gsub("[;,]([[:space:]]*[;,][[:space:]]*)*", "; "); if (ISPOOL == 1) { LSTART = "\{" ; LEND = "\}"; } else { LSTART = "\(" ; LEND = "\)"; } if ( REPL == "" ) { gsub(LSTART "[[:space:]]*[;,]?[[:space:]]*" LEND, LSTART " " WITH " " LEND); } } /^[[:space:]]*VNIC0=/ { '"${NICS}"'; next } /@DNS_SERVER@/ { replace("@DNS_SERVER@", DNS, POOL); print; next } /@HTTP_SERVER@/ { replace("@HTTP_SERVER@", HTTP, POOL); print; next } /@NFS_SERVER@/ { replace("@NFS_SERVER@", NFS, POOL); print; next } /@SMTP_SERVER@/ { replace("@SMTP_SERVER@", SMTP, POOL); print; next } { print; } ' >${ZPATH}/root/etc/ipf/${DST[$IDX]} done zlogin ${ZNAME} svcadm enable ipfilter } Man.addFunc fixDhcpSMF '' '[+NAME?fixDhcpSMF - fix /lib/svc/method/isc-dhcp] [+DESCRIPTION?Removes the "-q" from the OPTIONS variable in the zones \b/lib/svc/method/isc-dhcp\b SMF method file, so that possible config file parse errors get logged to the service log file and are not sent into a black hole. If this file does not exist, this function does nothing.] ' function fixDhcpSMF { [[ ! -r $ZPATH/root/lib/svc/method/isc-dhcp ]] && return cp -p $ZPATH/root/lib/svc/method/isc-dhcp \ $ZPATH/root/lib/svc/method/isc-dhcp.orig gsed -i -e '/OPTIONS/ s,-q,,' $ZPATH/root/lib/svc/method/isc-dhcp } function fixKshProfile { [[ ! -f ${SDIR}/files/ksh.kshrc ]] && return cp -p $ZPATH/root/etc/ksh.kshrc $ZPATH/root/etc/ksh.kshrc.orig cp ${SDIR}/files/ksh.kshrc $ZPATH/root/etc/ } Man.addVar ADDSERVICE 'File to append to the \b/etc/services\b of the new zone. If it is not set or does not exit, it is ignored. Default: \a$SDIR/files/services\a.' typeset ADDSERVICE=$SDIR/files/services Man.addVar GW 'The IP address of the defaultrouter of the running zone. Gets set in \bcustomizeRunningZone()\b, but might be empty.' Man.addFunc customizeRunningZone '' '[+NAME?customizeRunningZone - "standard" customization of a running zone] [+DESCRIPTION?Executes common actions usually required for every zone to customize it, adjust settings. This includes fixing bugs, adjusting service parameters and dependencies, populating the admin home and fixing configuration files.] [+?The following environment variables are refreshed to match the current settings of the zone: \bZHNAME\b, \bZIP\b, \bZDOMAIN\b, \bGW\b.] [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ZNAME ZHNAME GW ZIP ZVNIC ZDOMAIN ZPATH ADDSERVICE; }" '} [+SEE ALSO?\bzlogin\b(1), \bhostname\b(1), \bsvccfg\b(1M), \badjustSSH()\b, \bfixSendmail()\b, \bdisableIPv6()\b, \bsetupAdminHome()\b, \bipfilterFinal()\b]' function customizeRunningZone { Log.info "Customizing zone $ZNAME ..." addAddVnics typeset NZIP X # Refresh vars to match the running zone. ZHNAME=${ zlogin $ZNAME hostname; } NZIP=${ zlogin $ZNAME ipadm show-addr -p -o ADDR $ZVNIC/ | grep -v :: ; } NZIP=${ZIP%%/*} # if setup of the primary NIC failed, we assume, that $ZIP is still correct [[ -n $NZIP ]] && ZIP=$NZIP ZDOMAIN=${ zlogin $ZNAME svccfg -s nis/domain listprop config/domainname; } ZDOMAIN=${ZDOMAIN##*+(\s)} if [[ -z $ZDOMAIN && -r $ZPATH/root/etc/resolv.conf ]]; then ZDOMAIN=$( awk '/^(search|domain)/ { print $2; exit }' \ $ZPATH/root/etc/resolv.conf ) fi ZDOMAIN=${ZDOMAIN%%.} # Sun sendmail tries to determine its DNS domainname by getting it from # nis or ldap settings. That's awefully stupid in case those services are # not available/disabled, since it does NOT fallback to look it up using # the DNS service (as a normal sendmail does by default). So the Fully # Qualified Domain Name of this host must be included in /etc/inet/hosts # to circumvent this odd behavior and avoids the need to replace the # Sun sendmail package with a posssibly unsupported thirdparty package. if [[ -n $ZIP ]]; then Log.info 'Adjusting /etc/inet/hosts ...' X="::1\tlocalhost\n127.0.0.1\tlocalhost loghost\n$ZIP\t" [[ -n $ZDOMAIN ]] && X+="${ZHNAME}.${ZDOMAIN}" cp -p $ZPATH/root/etc/inet/hosts $ZPATH/root/etc/inet/hosts.orig print "$X ${ZHNAME}" >$ZPATH/root/etc/inet/hosts else Log.warn '/etc/inet/hosts was not adjusted! $ZIP is empty.' fi GW=$( zlogin $ZNAME route -n get default | awk '/gateway:/ {print $2}' ) if [[ -n $GW ]]; then Log.info "Putting $GW into /etc/defaultrouter ..." print $GW >$ZPATH/root/etc/defaultrouter fi # We need a stable reliable system - so get rid of pretty stupid deps. # Just unbelievable ... zlogin $ZNAME svccfg -s system-log delpg autofs; \ svccfg -s system-log:default refresh zlogin $ZNAME svccfg -s zones-proxy-client 'setprop stop/timeout_seconds = 1' zlogin $ZNAME svccfg -s zones-proxy-client:default refresh fixKshProfile adjustSSH fixSendmail disableIPv6 setupAdminHome fixDhcpSMF [[ -n $ADDSERVICE && -r $ADDSERVICE ]] && \ cat $ADDSERVICE >> $ZPATH/root/etc/inet/services ipfilterFinal } # vim:ts=4 filetype=sh