#!/bin/sh ########################################################################### # Variables ########################################################################### JAILNAME="$1" JAILDIR="/usr/jails/$JAILNAME" ZFSNAME="pool/jails/$JAILNAME" HOSTNAME="$JAILNAME" USERNAME="amdmi3" # derived JAILNAME_UC=`echo $JAILNAME | tr '[a-z]' '[A-Z]'` JAILDIR_SAFE="/usr/jails/$JAILNAME/" #OBJDIR="$JAILDIR/usr/obj" [ "x${OBJDIR}" = "x" ] && OBJDIR="/usr/jails/obj" [ "x${SRCDIR}" = "x" ] && SRCDIR="/usr/src" #WITHOUT="ATM AUDIT AUTHPF BIND CALENDAR CDDL DICT GAMES GCOV OPX NCP NIS PROFILE RESCUE SENDMAIL SSP TCSH" USERFILES=".zshrc .vimrc .cshrc .login .profile" ROOTFILES=".zshrc .vimrc" ROMOUNTS="ports" RWMOUNTS="distfiles shared" LOGFILE="/tmp/mkjail.log" ########################################################################### # Subs ########################################################################### cleanup_and_exit() { if [ "$1" -ne 0 ]; then message "Logfile is $LOGFILE" tail -10 "$LOGFILE" else rm -f "$LOGFILE" fi exit $1 } message() { echo "===> $*" } fatal() { echo "Error: $*" cleanup_and_exit 1 } ask() { echo -n "$* [y/n]? " answer= while [ "X$answer" != "Xy" -a "X$answer" != "XY" ]; do read answer if [ "X$answer" = "Xn" -o "X$answer" = "XN" ]; then return 1 fi done return 0 } ########################################################################### # Sanity checks ########################################################################### touch "$LOGFILE" if [ -z "$JAILNAME" ]; then fatal "Jail name required" fi if jls | grep -q "$JAILDIR\$"; then message "Stopping jail" /etc/rc.d/jail stop $JAILNAME >$LOGFILE 2>&1 || fatal "Cannot stop jail" fi if jls | grep -q "$JAILDIR\$"; then fatal "Jail is still running, please stop it" fi ########################################################################### # Final question ########################################################################### echo " Jail name: $JAILNAME" echo " Directory: $JAILDIR" echo "Zfs filesystem: $ZFSNAME" echo " Hostname: $HOSTNAME" echo " Source dir: $SRCDIR" echo " Object dir: $OBJDIR" ask "Continue?" || cleanup_and_exit 0 ########################################################################### # Parts ########################################################################### create_zfs_filesystem() { message "Creating ZFS filesystem for the jail" if zfs list -H -o name | grep -q -x $ZFSNAME; then num=1 while zfs list -H -o name | grep -q -x $ZFSNAME.old$num; do num=$((num+1)) done zfs rename $ZFSNAME $ZFSNAME.old$num >$LOGFILE 2>&1 || fatal "Cannot rename old filesystem" fi zfs create $ZFSNAME >$LOGFILE 2>&1 || fatal "Cannot create filesystem" } clean_jail_directory() { message "Cleaning jail directory" rm -rf "$JAILDIR/*" "$JAILDIR/.*" >$LOGFILE 2>&1 find "$JAILDIR" -mindepth 1 | grep -q '' && fatal "Could not clean jail directory" } build_world() { message "Making world" mkdir -p "$OBJDIR" >$LOGFILE 2>&1 || fatal "Cannot create OBJDIR" cd "$SRCDIR" && DESTDIR="$JAILDIR" MAKEOBJDIRPREFIX="$OBJDIR" make buildworld -j3 >$LOGFILE 2>&1 || fatal "Buildworld failed" } install_custom_world() { message "Installing sudoers" mkdir -p "${JAILDIR_SAFE}usr/local/etc" cat > "${JAILDIR_SAFE}usr/local/etc/sudoers" << _END Defaults timestamp_timeout=60 root ALL=(ALL) SETENV: ALL $USERNAME ALL=(ALL) ALL _END chmod 440 "${JAILDIR_SAFE}usr/local/etc/sudoers" message "Installing symlinks" if [ ! -e "${JAILDIR_SAFE}usr/ports" ]; then ln -s ../pool/ports "${JAILDIR_SAFE}usr/ports" fi if [ ! -e "${JAILDIR_SAFE}usr/distfiles" ]; then ln -s ../pool/distfiles "${JAILDIR_SAFE}usr/distfiles" fi message "Installing pool" mkdir -p "${JAILDIR_SAFE}pool" for dir in `ls /pool`; do mkdir -p "${JAILDIR_SAFE}pool/$dir" done } install_users() { message "Installing root" for file in $ROOTFILES; do cp -pP /root/${file} ${JAILDIR_SAFE}root done message "Installing $USERNAME" if [ ! -e "${JAILDIR_SAFE}home" ]; then ln -s usr/home "${JAILDIR_SAFE}home" fi mkdir -p "${JAILDIR_SAFE}usr/home/$USERNAME/.ssh" chmod 700 "${JAILDIR_SAFE}usr/home/$USERNAME/.ssh" for file in $USERFILES; do cp -pP "/home/$USERNAME/${file}" "${JAILDIR_SAFE}home/$USERNAME" done chown -R $USERNAME:$USERNAME "${JAILDIR_SAFE}usr/home/$USERNAME" for l in docs incoming music shared software; do if [ ! -e "${JAILDIR_SAFE}usr/home/$USERNAME/$l" ]; then ln -s /pool/$l "${JAILDIR_SAFE}usr/home/$USERNAME/$l" fi done mkdir -p "${JAILDIR_SAFE}usr/home/$USERNAME/video" for l in amv anime cartoons clips homevideo movies series; do if [ ! -e "${JAILDIR_SAFE}usr/home/$USERNAME/video/$l" ]; then ln -s /pool/$l "${JAILDIR_SAFE}usr/home/$USERNAME/video/$l" fi done } install_world() { message "Installing world" cd "$SRCDIR" && DESTDIR="$JAILDIR" MAKEOBJDIRPREFIX="$OBJDIR" NO_FSCHG="yes" make installworld >$LOGFILE 2>&1 || fatal "Installworld failed" install_custom_world install_users } install_custom_etc() { message "Installing SSH config" cat > "${JAILDIR_SAFE}etc/ssh/sshd_config" << _END VersionAddendum $JAILNAME_UC AddressFamily inet AllowUsers $USERNAME HostKey /etc/ssh/ssh_host_dsa_key PrintMotd no ClientAliveInterval 120 UseDNS no MaxStartups 1 _END message "Installing make.conf" cat > "${JAILDIR_SAFE}etc/make.conf" << _END # Global (c args, arch, processor, optimizations) CPUTYPE= `cat /etc/make.conf | grep CPUTYPE | awk '{print $NF}'` # Port options PORTSEARCH_DISPLAY_FIELDS= name,path,info WRKDIRPREFIX?= /usr/work DISTDIR?= /usr/distfiles PACKAGES?= /usr/packages DISABLE_VULNERABILITIES= yes #FETCH_CMD?= /usr/local/bin/wget #FETCH_BEFORE_ARGS= -c --timeout=1 #DISABLE_SIZE= yes # Port build opts WITHOUT_PRINT= true WITHOUT_JAVA= true WITHOUT_X11= true _END message "Installing rc.conf" cat > "${JAILDIR_SAFE}etc/rc.conf" << _END sshd_enable="YES" syslogd_enable="NO" sendmail_enable="NONE" cron_enable="NO" _END message "Installing resolv.conf" cat > "${JAILDIR_SAFE}etc/resolv.conf" << _END search panopticon nameserver 192.168.0.1 _END message "Updating crontab" sed -i.bak -e 's|^[0-9*]|#&|' "${JAILDIR_SAFE}etc/crontab" sed -i.bak -e '/^PATH=/ s|$|:/usr/local/bin|' "${JAILDIR_SAFE}etc/crontab" sed -i.bak -e '/^HOME=/ a\ MAILTO=""' "${JAILDIR_SAFE}etc/crontab" message "Updating login.conf" sed -i.bak -e '/:lang=ru_RU.KOI8-R:/ a\ \ :setenv=LC_MESSAGES=C,LC_TIME=C,NLSPATH=/nonexistent:\\' "${JAILDIR_SAFE}etc/login.conf" sed -i.bak -e 's|KOI8-R|UTF-8|' "${JAILDIR_SAFE}etc/login.conf" message "Updating localtime" cp /etc/localtime "${JAILDIR_SAFE}etc/localtime" message "Updating passwd/groups" echo "$USERNAME:*:1000:" >> "${JAILDIR_SAFE}etc/group" sed -i.bak -e '/^wheel:/ s|$|,'$USERNAME'|' "${JAILDIR_SAFE}etc/group" echo "$USERNAME:*:1000:1000:russian:0:0:Dmitry Marakasov:/home/$USERNAME:/bin/sh" >> "${JAILDIR_SAFE}etc/master.passwd" sed -i.bak -e '/^root:/ s|Charlie .|'$JAILNAME_UC'|' "${JAILDIR_SAFE}etc/master.passwd" message "Updating databases" chroot "$JAILDIR" cap_mkdb /etc/login.conf chroot "$JAILDIR" pwd_mkdb -p /etc/master.passwd message "Updating users password" chroot "$JAILDIR" passwd $USERNAME message "Cleaning up /etc" rm -f ${JAILDIR_SAFE}etc/*.bak } install_etc() { message "Installing /etc" cd "$SRCDIR/etc" && DESTDIR="$JAILDIR" MAKEOBJDIRPREFIX="$OBJDIR" make distribution >$LOGFILE 2>&1 || fatal "make distribution in etc/ failed" install_custom_etc } install_host_entry() { message "Installing jail fstab to host /etc" echo "/pool $JAILDIR/pool nullfs rw,noatime,noexec 0 1" > /etc/fstab.$JAILNAME for m in $RWMOUNTS; do echo "/pool/$m $JAILDIR/pool/$m nullfs rw,noatime,noexec 0 2" >> /etc/fstab.$JAILNAME done for m in $ROMOUNTS; do echo "/pool/$m $JAILDIR/pool/$m nullfs ro,noatime,noexec 0 2" >> /etc/fstab.$JAILNAME done message "Installing entry to host /etc/rc.conf" cat >>/etc/rc.conf <<_END jail_${JAILNAME}_rootdir="$JAILDIR" jail_${JAILNAME}_hostname="$JAILNAME.panopticon" jail_${JAILNAME}_ip="?" # `host $JAILNAME 2>&1` jail_${JAILNAME}_interface="panopticon" jail_${JAILNAME}_devfs_enable="YES" jail_${JAILNAME}_mount_enable="YES" jail_${JAILNAME}_fstab="/etc/fstab.$JAILNAME" _END $EDITOR /etc/rc.conf } # install_port(origin, pkgglob) install_port() { if ! chroot "${JAILDIR}" pkg_info '$2' >/dev/null 2>&1; then message "Installing $1 into jail" chroot "${JAILDIR}" sh -c "cd /usr/ports/$1 && BATCH=1 FETCH_CMD=/bin/false make install" >$LOGFILE 2>&1 || fatal "Cannot install port" return 0 fi return 1 } install_default_packages() { if install_port "shells/zsh" "zsh-[0-9]*"; then message "Updating shells" chroot "${JAILDIR}" pw usermod root -s /usr/local/bin/zsh chroot "${JAILDIR}" pw usermod $USERNAME -s /usr/local/bin/zsh fi install_port "security/sudo" "sudo-[0-9]*" message "Cleaning workdir" rm -rf "${JAILDIR_SAFE}usr/work" } ########################################################################### # Main ########################################################################### if [ ! -d "$JAILDIR" ]; then create_zfs_filesystem else if ask "Create new ZFS filesystem for the jail?"; then create_zfs_filesystem elif ask "Clean existing jail directory?"; then clean_jail_directory else message "Using existing jail directory" fi fi really_installworld() { if [ -d "$OBJDIR" ]; then if ask "Use existing objdir for installworld?"; then message "Using existing OBJDIR" else rm -rf "$OBJDIR" >$LOGFILE 2>&1 || fatal "Could not remove old OBJDIR" build_world fi else build_world fi install_world } if [ -e "$JAILDIR/bin/sh" ]; then if ask "Install new world over existing jail?"; then really_installworld else message "Using existing world" fi else really_installworld fi if [ -e "$JAILDIR/etc/crontab" ]; then if ask "Install default /etc over existing?"; then install_etc else message "Leaving existing /etc untouched" fi else install_etc fi if [ -e "/etc/fstab.$JAILNAME" ]; then if ask "Reinstall entries in host /etc?"; then install_host_entry else message "Not updating host /etc" fi else install_host_entry fi if ! ask "Start jail now?"; then message "Not starting jail; all done" cleanup_and_exit 0 fi /etc/rc.d/jail start $JAILNAME >$LOGFILE 2>&1 || fatal "Cannot start jail" if ask "Install default packages?"; then install_default_packages fi cleanup_and_exit 0