Bug#504027: postfix: Some chroot issues in init.d script (+ patch)
Patch update concerning the creation of the chroot: 1. Made copying of files other than regular files possible, this is useful for links and files like /dev/urandom. Directories are still skipped. 2. Made sure that the postfix user is able to read files in the chroot that are not group readable on their original location. As the default group ownership is postfix, I just added chmod g+r on the chroot file. 3. If files were world-writable on their original location, make it also writable for the postfix group in the chroot. Durk --- postfix-2.5.5-orig/debian/init.d 2008-10-31 13:59:26.0 +0100 +++ postfix-2.5.5/debian/init.d 2008-12-12 11:45:58.0 +0100 @@ -25,6 +25,8 @@ # Defaults - don't touch, edit /etc/default/postfix SYNC_CHROOT="y" +CHROOT_FILES="etc/localtime etc/services etc/resolv.conf etc/hosts \ + etc/nsswitch.conf etc/nss_mdns.config" test -f /etc/default/postfix && . /etc/default/postfix @@ -45,6 +47,60 @@ fi } +update_chroot() { +# see if anything is running chrooted. +NEED_CHROOT=$(awk '/^[0-9a-z]/ && ($5 ~ "[-yY]") { print "y"; exit}' /etc/postfix/master.cf) + +if [ -n "$NEED_CHROOT" ] && [ -n "$SYNC_CHROOT" ]; then + # Make sure that the chroot environment is set up correctly. + oldumask=$(umask) + umask 027 + cd $(postconf -h queue_directory) + + # if we're using tls, then we need to add etc/ssl/certs/ca-certificates.crt. + smtp_tls_security_level=$(postconf -h smtp_tls_security_level) + smtp_use_tls=$(postconf -h smtp_use_tls) + smtpd_tls_security_level=$(postconf -h smtpd_tls_security_level) + smtpd_use_tls=$(postconf -h smtpd_use_tls) + if [ "X$smtp_use_tls" = "Xyes" -o "X$smtpd_use_tls" = "Xyes" \ + -o "X$smtp_tls_security_level" != "X" -a "X$smtp_tls_security_level" != "Xnone" \ + -o "X$smtpd_tls_security_level" != "X" -a "X$smtpd_tls_security_level" != "Xnone" ]; then + if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then + mkdir -p etc/ssl/certs + cp /etc/ssl/certs/ca-certificates.crt etc/ssl/certs/ + chgrp -R postfix etc +chmod g+r etc/ssl/certs/ca-certificates.crt + fi + fi + + # if we're using unix:passwd.byname, then we need to add etc/passwd. + local_maps=$(postconf -h local_recipient_maps) + if [ "X$local_maps" != "X${local_maps#*unix:passwd.byname}" ]; then + if [ "X$local_maps" = "X${local_maps#*proxy:unix:passwd.byname}" ]; then + sed 's/^\([^:]*\):[^:]*/\1:x/' /etc/passwd > etc/passwd + chgrp postfix etc/passwd + fi + fi + + for file in $CHROOT_FILES; do + if [ ! -d ${file%/*} ]; then mkdir -p ${file%/*} && chgrp -R postfix ${file%%/*}; fi + if [ -e /${file} ] && [ ! -d ${file} ]; then rm -f ${file} && cp -r /${file} ${file}; fi + if [ -e ${file} ] && [ ! -L ${file} ]; then + chgrp postfix ${file} + chmod g+rX ${file} + if ( stat -c%A /${file} | grep -q 'w.$' ) ; then chmod g+w ${file} ; fi + fi + done + rm -f usr/lib/zoneinfo/localtime + mkdir -p usr/lib/zoneinfo + ln -sf /etc/localtime usr/lib/zoneinfo/localtime + rm -f lib/libnss_*so* + tar cf - /lib/libnss_*so* 2>/dev/null |tar xf - + umask $oldumask +fi +} + + case "$1" in start) log_daemon_msg "Starting Postfix Mail Transport Agent" postfix @@ -65,48 +121,7 @@ exit 1 fi - # see if anything is running chrooted. - NEED_CHROOT=$(awk '/^[0-9a-z]/ && ($5 ~ "[-yY]") { print "y"; exit}' /etc/postfix/master.cf) - - if [ -n "$NEED_CHROOT" ] && [ -n "$SYNC_CHROOT" ]; then - # Make sure that the chroot environment is set up correctly. - oldumask=$(umask) - umask 022 - cd $(postconf -h queue_directory) - - # if we're using tls, then we need to add etc/ssl/certs/ca-certificates.crt. - smtp_use_tls=$(postconf -h smtp_use_tls) - smtpd_use_tls=$(postconf -h smtpd_use_tls) - if [ "X$smtp_use_tls" = "Xyes" -o "X$smtpd_use_tls" = "Xyes" ]; then - if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then - mkdir -p etc/ssl/certs - cp /etc/ssl/certs/ca-certificates.crt etc/ssl/certs/ - fi - fi - - # if we're using unix:passwd.byname, then we need to add etc/passwd. - local_maps=$(postconf -h local_recipient_maps) - if [ "X$local_maps" != "X${local_maps#*unix:passwd.byname}" ]; then - if [ "X$local_maps" = "X${local_maps#*proxy:unix:passwd.byname}" ]; then - sed 's/^\([^:]*\):[^:]*/\1:x/' /etc/passwd > etc/passwd - chmod a+r etc/passwd - fi - fi - - FILES="etc/localtime etc/services etc/resolv.conf etc/hosts \ - etc/nsswitch.conf etc/nss_mdns.config" - for file in $FILES; do - [ -d ${file%/*} ] || mkdir -p ${file%/*} - if [ -f /${file} ]; then rm -f ${file} && cp /${file} ${file}; fi - if [ -f ${file} ]; then chmod a+rX ${file}; fi - done - rm -f usr/lib/zoneinfo/localtime - mkdir -p usr/lib/zoneinfo - ln -sf /etc/localtime usr/lib/zoneinfo/localtime - rm -f lib/libnss_*so* - tar cf - /lib/libnss_*so* 2>/dev/null |tar xf - - umask $oldumask - fi + update_chroot if start-stop-daemon --start --ex
Bug#504027: postfix: Some chroot issues in init.d script (+ patch)
Regarding issue 5, I forgot to take care of directories in the patch. Fixed in the attached patch. Sorry for the mess! --- postfix-2.5.5-orig/debian/init.d 2008-10-31 13:59:26.0 +0100 +++ postfix-2.5.5/debian/init.d 2008-10-31 14:47:54.0 +0100 @@ -25,6 +25,8 @@ # Defaults - don't touch, edit /etc/default/postfix SYNC_CHROOT="y" +CHROOT_FILES="etc/localtime etc/services etc/resolv.conf etc/hosts \ + etc/nsswitch.conf etc/nss_mdns.config" test -f /etc/default/postfix && . /etc/default/postfix @@ -45,6 +47,55 @@ fi } +update_chroot() { +# see if anything is running chrooted. +NEED_CHROOT=$(awk '/^[0-9a-z]/ && ($5 ~ "[-yY]") { print "y"; exit}' /etc/postfix/master.cf) + +if [ -n "$NEED_CHROOT" ] && [ -n "$SYNC_CHROOT" ]; then + # Make sure that the chroot environment is set up correctly. + oldumask=$(umask) + umask 027 + cd $(postconf -h queue_directory) + + # if we're using tls, then we need to add etc/ssl/certs/ca-certificates.crt. + smtp_tls_security_level=$(postconf -h smtp_tls_security_level) + smtp_use_tls=$(postconf -h smtp_use_tls) + smtpd_tls_security_level=$(postconf -h smtpd_tls_security_level) + smtpd_use_tls=$(postconf -h smtpd_use_tls) + if [ "X$smtp_use_tls" = "Xyes" -o "X$smtpd_use_tls" = "Xyes" \ + -o "X$smtp_tls_security_level" != "X" -a "X$smtp_tls_security_level" != "Xnone" \ + -o "X$smtpd_tls_security_level" != "X" -a "X$smtpd_tls_security_level" != "Xnone" ]; then + if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then + mkdir -p etc/ssl/certs + cp /etc/ssl/certs/ca-certificates.crt etc/ssl/certs/ + chgrp -R postfix etc + fi + fi + + # if we're using unix:passwd.byname, then we need to add etc/passwd. + local_maps=$(postconf -h local_recipient_maps) + if [ "X$local_maps" != "X${local_maps#*unix:passwd.byname}" ]; then + if [ "X$local_maps" = "X${local_maps#*proxy:unix:passwd.byname}" ]; then + sed 's/^\([^:]*\):[^:]*/\1:x/' /etc/passwd > etc/passwd + chgrp postfix etc/passwd + fi + fi + + for file in $CHROOT_FILES; do + if [ ! -d ${file%/*} ]; then mkdir -p ${file%/*} && chgrp -R postfix ${file%%/*}; fi + if [ -f /${file} ]; then rm -f ${file} && cp /${file} ${file}; fi + if [ -f ${file} ]; then chgrp postfix ${file}; fi + done + rm -f usr/lib/zoneinfo/localtime + mkdir -p usr/lib/zoneinfo + ln -sf /etc/localtime usr/lib/zoneinfo/localtime + rm -f lib/libnss_*so* + tar cf - /lib/libnss_*so* 2>/dev/null |tar xf - + umask $oldumask +fi +} + + case "$1" in start) log_daemon_msg "Starting Postfix Mail Transport Agent" postfix @@ -65,48 +116,7 @@ exit 1 fi - # see if anything is running chrooted. - NEED_CHROOT=$(awk '/^[0-9a-z]/ && ($5 ~ "[-yY]") { print "y"; exit}' /etc/postfix/master.cf) - - if [ -n "$NEED_CHROOT" ] && [ -n "$SYNC_CHROOT" ]; then - # Make sure that the chroot environment is set up correctly. - oldumask=$(umask) - umask 022 - cd $(postconf -h queue_directory) - - # if we're using tls, then we need to add etc/ssl/certs/ca-certificates.crt. - smtp_use_tls=$(postconf -h smtp_use_tls) - smtpd_use_tls=$(postconf -h smtpd_use_tls) - if [ "X$smtp_use_tls" = "Xyes" -o "X$smtpd_use_tls" = "Xyes" ]; then - if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then - mkdir -p etc/ssl/certs - cp /etc/ssl/certs/ca-certificates.crt etc/ssl/certs/ - fi - fi - - # if we're using unix:passwd.byname, then we need to add etc/passwd. - local_maps=$(postconf -h local_recipient_maps) - if [ "X$local_maps" != "X${local_maps#*unix:passwd.byname}" ]; then - if [ "X$local_maps" = "X${local_maps#*proxy:unix:passwd.byname}" ]; then - sed 's/^\([^:]*\):[^:]*/\1:x/' /etc/passwd > etc/passwd - chmod a+r etc/passwd - fi - fi - - FILES="etc/localtime etc/services etc/resolv.conf etc/hosts \ - etc/nsswitch.conf etc/nss_mdns.config" - for file in $FILES; do - [ -d ${file%/*} ] || mkdir -p ${file%/*} - if [ -f /${file} ]; then rm -f ${file} && cp /${file} ${file}; fi - if [ -f ${file} ]; then chmod a+rX ${file}; fi - done - rm -f usr/lib/zoneinfo/localtime - mkdir -p usr/lib/zoneinfo - ln -sf /etc/localtime usr/lib/zoneinfo/localtime - rm -f lib/libnss_*so* - tar cf - /lib/libnss_*so* 2>/dev/null |tar xf - - umask $oldumask - fi + update_chroot if start-stop-daemon --start --exec ${DAEMON} -- quiet-quick-start; then log_end_msg 0 @@ -159,8 +169,14 @@ ${DAEMON} $1 ;; +update-chroot) + log_action_begin_msg "Updating the Postfix chroot" + update_chroot + log_action_end_msg 0 +;; + *) - log_action_msg "Usage: /etc/init.d/postfix {start|stop|restart|reload|flush|check|abort|force-reload}" + log_action_msg "Usage: /etc/init.d/postfix {start|stop|restart|reload|flush|check|abort|force-reload|update-chroot}" exit 1 ;; esac
Bug#504027: postfix: Some chroot issues in init.d script (+ patch)
Update: I found another issue: 5. Files copied by the init.d script will be world-readable, sometimes in contrast to the original files. This a problem for some files that people might want to add to the chroot, like /etc/sasldb, which has clear-text passwords. In my updated patch I changed the umask to 027 to prevent files from being created as world-readable and made them in stead group-readable by the postfix user. I think this is "open" enough. Please correct me if I'm wrong. I updated the previous patch to resolve this issue (init.d-chroot-new.patch). All the comments in the original bug post still apply. --- postfix-2.5.5-orig/debian/init.d 2008-10-31 13:59:26.0 +0100 +++ postfix-2.5.5/debian/init.d 2008-10-31 14:01:08.0 +0100 @@ -25,6 +25,8 @@ # Defaults - don't touch, edit /etc/default/postfix SYNC_CHROOT="y" +CHROOT_FILES="etc/localtime etc/services etc/resolv.conf etc/hosts \ + etc/nsswitch.conf etc/nss_mdns.config" test -f /etc/default/postfix && . /etc/default/postfix @@ -45,6 +47,55 @@ fi } +update_chroot() { +# see if anything is running chrooted. +NEED_CHROOT=$(awk '/^[0-9a-z]/ && ($5 ~ "[-yY]") { print "y"; exit}' /etc/postfix/master.cf) + +if [ -n "$NEED_CHROOT" ] && [ -n "$SYNC_CHROOT" ]; then + # Make sure that the chroot environment is set up correctly. + oldumask=$(umask) + umask 027 + cd $(postconf -h queue_directory) + + # if we're using tls, then we need to add etc/ssl/certs/ca-certificates.crt. + smtp_tls_security_level=$(postconf -h smtp_tls_security_level) + smtp_use_tls=$(postconf -h smtp_use_tls) + smtpd_tls_security_level=$(postconf -h smtpd_tls_security_level) + smtpd_use_tls=$(postconf -h smtpd_use_tls) + if [ "X$smtp_use_tls" = "Xyes" -o "X$smtpd_use_tls" = "Xyes" \ + -o "X$smtp_tls_security_level" != "X" -a "X$smtp_tls_security_level" != "Xnone" \ + -o "X$smtpd_tls_security_level" != "X" -a "X$smtpd_tls_security_level" != "Xnone" ]; then + if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then + mkdir -p etc/ssl/certs + cp /etc/ssl/certs/ca-certificates.crt etc/ssl/certs/ + chgrp postfix etc/ssl/certs/ca-certificates.crt + fi + fi + + # if we're using unix:passwd.byname, then we need to add etc/passwd. + local_maps=$(postconf -h local_recipient_maps) + if [ "X$local_maps" != "X${local_maps#*unix:passwd.byname}" ]; then + if [ "X$local_maps" = "X${local_maps#*proxy:unix:passwd.byname}" ]; then + sed 's/^\([^:]*\):[^:]*/\1:x/' /etc/passwd > etc/passwd + chgrp postfix etc/passwd + fi + fi + + for file in $CHROOT_FILES; do + [ -d ${file%/*} ] || mkdir -p ${file%/*} + if [ -f /${file} ]; then rm -f ${file} && cp /${file} ${file}; fi + if [ -f ${file} ]; then chgrp postfix ${file}; fi + done + rm -f usr/lib/zoneinfo/localtime + mkdir -p usr/lib/zoneinfo + ln -sf /etc/localtime usr/lib/zoneinfo/localtime + rm -f lib/libnss_*so* + tar cf - /lib/libnss_*so* 2>/dev/null |tar xf - + umask $oldumask +fi +} + + case "$1" in start) log_daemon_msg "Starting Postfix Mail Transport Agent" postfix @@ -65,48 +116,7 @@ exit 1 fi - # see if anything is running chrooted. - NEED_CHROOT=$(awk '/^[0-9a-z]/ && ($5 ~ "[-yY]") { print "y"; exit}' /etc/postfix/master.cf) - - if [ -n "$NEED_CHROOT" ] && [ -n "$SYNC_CHROOT" ]; then - # Make sure that the chroot environment is set up correctly. - oldumask=$(umask) - umask 022 - cd $(postconf -h queue_directory) - - # if we're using tls, then we need to add etc/ssl/certs/ca-certificates.crt. - smtp_use_tls=$(postconf -h smtp_use_tls) - smtpd_use_tls=$(postconf -h smtpd_use_tls) - if [ "X$smtp_use_tls" = "Xyes" -o "X$smtpd_use_tls" = "Xyes" ]; then - if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then - mkdir -p etc/ssl/certs - cp /etc/ssl/certs/ca-certificates.crt etc/ssl/certs/ - fi - fi - - # if we're using unix:passwd.byname, then we need to add etc/passwd. - local_maps=$(postconf -h local_recipient_maps) - if [ "X$local_maps" != "X${local_maps#*unix:passwd.byname}" ]; then - if [ "X$local_maps" = "X${local_maps#*proxy:unix:passwd.byname}" ]; then - sed 's/^\([^:]*\):[^:]*/\1:x/' /etc/passwd > etc/passwd - chmod a+r etc/passwd - fi - fi - - FILES="etc/localtime etc/services etc/resolv.conf etc/hosts \ - etc/nsswitch.conf etc/nss_mdns.config" - for file in $FILES; do - [ -d ${file%/*} ] || mkdir -p ${file%/*} - if [ -f /${file} ]; then rm -f ${file} && cp /${file} ${file}; fi - if [ -f ${file} ]; then chmod a+rX ${file}; fi - done - rm -f usr/lib/zoneinfo/localtime - mkdir -p usr/lib/zoneinfo - ln -sf /etc/localtime usr/lib/zoneinfo/localtime - rm -f lib/libnss_*so* - tar cf - /lib/libnss_*so* 2>/dev/null |tar xf - - umask $oldumask - fi + update_chroot if start-stop-daemon --start --exec ${DAEMON} -- quiet-quick-start; then log_end_msg 0 @@ -159,8 +169,14 @@ ${DAEMON} $1 ;; +update-chroot) + log_action_beg
Bug#504027: postfix: Some chroot issues in init.d script (+ patch)
Package: postfix Version: 2.5.5-1.1 Severity: normal Tags: patch I found some issues in the postfix init.d script regarding the chroot setup. 1. There are more options in Postfix besides smtp_use_tls and smtpd_use_tls to enable TLS. In the other cases /etc/ssl/certs/ca-certificates.crt should be copied as well. In my patch I added checks for: * smtp_tls_security_level * smtpd_tls_security_level This is probably still not perfect, because there is also smtp_tls_per_site and smtp_tls_policy_maps. But these seem much more difficult to check (and are probably much less used). 2. The FILES variable can't be overridden by /etc/default/postfix. This could be a very neat way to expand the files that need to be copied to the chroot. In my patch I renamed the FILES variable to CHROOT_FILES and moved it before sourcing of /etc/default/postfix. 3. There is no way to update the chroot without restarting the postfix daemon. I can imagine people want to avoid restarting postfix in production environments and prefer reloading it in stead after configuration changes. However, if a configuration change needs an extra file in the chroot, reloading is not enough. Now, people have the choice between manually copying the file the chroot (before reloading) or restarting postfix (after modifying the FILES variable). In my patch I added a third option, a new argument (update-chroot) can be called to update the chroot. To realise this I've put all chroot logic in a function (update_chroot()). 4. Another issue seems that files that don't have to be put in the chroot anymore, due to configuration changes, will never get removed from the chroot. People have to remove them manually. This might be intentionally and I didn't try to fix it in the patch, 'cause it seems a bit complicated as not all the files in the chroot were created by the init.d script. So you can't simply remove all files before copying the files again. Please review the attached patch (init.d-chroot.patch) and consider applying it. I saw that a patch to the init.d script in bug #433660 is still waiting to be included. Obviously, my patch won't work if it the other one get applied. -- System Information: Debian Release: lenny/sid APT prefers testing APT policy: (500, 'testing') Architecture: i386 (i686) Kernel: Linux 2.6.26-1-686 (SMP w/1 CPU core) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/bash --- postfix-2.5.5-orig/debian/init.d2008-10-30 15:51:43.0 +0100 +++ postfix-2.5.5/debian/init.d 2008-10-30 17:44:39.0 +0100 @@ -25,6 +25,8 @@ # Defaults - don't touch, edit /etc/default/postfix SYNC_CHROOT="y" +CHROOT_FILES="etc/localtime etc/services etc/resolv.conf etc/hosts \ + etc/nsswitch.conf etc/nss_mdns.config" test -f /etc/default/postfix && . /etc/default/postfix @@ -45,6 +47,54 @@ fi } +update_chroot() { +# see if anything is running chrooted. +NEED_CHROOT=$(awk '/^[0-9a-z]/ && ($5 ~ "[-yY]") { print "y"; exit}' /etc/postfix/master.cf) + +if [ -n "$NEED_CHROOT" ] && [ -n "$SYNC_CHROOT" ]; then + # Make sure that the chroot environment is set up correctly. + oldumask=$(umask) + umask 022 + cd $(postconf -h queue_directory) + + # if we're using tls, then we need to add etc/ssl/certs/ca-certificates.crt. + smtp_tls_security_level=$(postconf -h smtp_tls_security_level) + smtp_use_tls=$(postconf -h smtp_use_tls) + smtpd_tls_security_level=$(postconf -h smtpd_tls_security_level) + smtpd_use_tls=$(postconf -h smtpd_use_tls) + if [ "X$smtp_use_tls" = "Xyes" -o "X$smtpd_use_tls" = "Xyes" \ + -o "X$smtp_tls_security_level" != "X" -a "X$smtp_tls_security_level" != "Xnone" \ + -o "X$smtpd_tls_security_level" != "X" -a "X$smtpd_tls_security_level" != "Xnone" ]; then + if [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then + mkdir -p etc/ssl/certs + cp /etc/ssl/certs/ca-certificates.crt etc/ssl/certs/ + fi + fi + + # if we're using unix:passwd.byname, then we need to add etc/passwd. + local_maps=$(postconf -h local_recipient_maps) + if [ "X$local_maps" != "X${local_maps#*unix:passwd.byname}" ]; then + if [ "X$local_maps" = "X${local_maps#*proxy:unix:passwd.byname}" ]; then + sed 's/^\([^:]*\):[^:]*/\1:x/' /etc/passwd > etc/passwd + chmod a+r etc/passwd + fi + fi + + for file in $CHROOT_FILES; do + [ -d ${file%/*} ] || mkdir -p ${file%/*} + if [ -f /${file} ]; then rm -f ${file} && cp /${file} ${file}; fi + if [ -f ${file} ]; then chmod a+rX ${file}; fi + done + rm -f usr/lib/zoneinfo/localtime + mkdir -p usr/lib/zoneinfo + ln -sf /etc/localtime usr/lib/zoneinfo/localtime + rm -f lib/libnss_*so* +