blob: 8836584329633c9491241282165b0fba3882480d [file] [log] [blame]
#!/bin/bash
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header$
#
# Miscellaneous shell functions that make use of the ebuild env but don't need
# to be included directly in ebuild.sh.
#
# We're sourcing ebuild.sh here so that we inherit all of it's goodness,
# including bashrc trickery. This approach allows us to do our miscellaneous
# shell work withing the same env that ebuild.sh has, but without polluting
# ebuild.sh itself with unneeded logic and shell code.
#
# XXX hack: clear the args so ebuild.sh doesn't see them
MISC_FUNCTIONS_ARGS="$@"
shift $#
source /usr/lib/portage/bin/ebuild.sh
install_qa_check() {
prepall
cd "${D}"
declare -i UNSAFE=0
for i in $(find "${D}/" -type f -perm -2002); do
((UNSAFE++))
echo "UNSAFE SetGID: $i"
chmod -s,o-w "$i"
done
for i in $(find "${D}/" -type f -perm -4002); do
((UNSAFE++))
echo "UNSAFE SetUID: $i"
chmod -s,o-w "$i"
done
# Now we look for all world writable files.
for i in $(find "${D}/" -type f -perm -2); do
echo -ne '\a'
echo "QA Security Notice:"
echo "- ${i:${#D}:${#i}} will be a world writable file."
echo "- This may or may not be a security problem, most of the time it is one."
echo "- Please double check that $PF really needs a world writeable bit and file bugs accordingly."
sleep 1
done
if type -p scanelf > /dev/null ; then
local qa_var insecure_rpath=0
# Make sure we disallow insecure RUNPATH/RPATH's
# Don't want paths that point to the tree where the package was built
# (older, broken libtools would do this). Also check for null paths
# because the loader will search $PWD when it finds null paths.
f=$(scanelf -qyRF '%r %p' "${D}" | grep -E "(${PORTAGE_BUILDDIR}|: |::|^:|^ )")
if [[ -n ${f} ]] ; then
echo -ne '\a\n'
echo "QA Notice: the following files contain insecure RUNPATH's"
echo " Please file a bug about this at http://bugs.gentoo.org/"
echo " with the maintaining herd of the package."
echo " Summary: $CATEGORY/$PN: insecure RPATH ${f}"
echo "${f}"
echo -ne '\a\n'
if has stricter ${FEATURES}; then
insecure_rpath=1
else
echo "Auto fixing rpaths for ${f}"
TMPDIR=${PORTAGE_BUILDDIR} scanelf -BXr ${f} -o /dev/null
fi
fi
# Check for setid binaries but are not built with BIND_NOW
f=$(scanelf -qyRF '%b %p' "${D}")
if [[ -n ${f} ]] ; then
echo -ne '\a\n'
echo "QA Notice: the following files are setXid, dyn linked, and using lazy bindings"
echo " This combination is generally discouraged. Try re-emerging the package:"
echo " LDFLAGS='-Wl,-z,now' emerge ${PN}"
echo "${f}"
echo -ne '\a\n'
die_msg="${die_msg} setXid lazy bindings,"
sleep 1
fi
# TEXTREL's are baaaaaaaad
# Allow devs to mark things as ignorable ... e.g. things that are
# binary-only and upstream isn't cooperating (nvidia-glx) ... we
# allow ebuild authors to set QA_TEXTRELS_arch and QA_TEXTRELS ...
# the former overrides the latter ... regexes allowed ! :)
qa_var="QA_TEXTRELS_${ARCH}"
[[ -n ${!qa_var} ]] && QA_TEXTRELS=${!qa_var}
[[ -n ${QA_STRICT_TEXTRELS} ]] && QA_TEXTRELS=""
f=$(scanelf -qyRF '%t %p' "${D}" | grep -v ' usr/lib/debug/' | \
gawk '
BEGIN { split("'"${QA_TEXTRELS}"'", ignore); }
{ for (idx in ignore)
if ($NF ~ "^"ignore[idx]"$")
next;
print;
}')
if [[ -n ${f} ]] ; then
scanelf -qyRF '%T %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-textrel.log
echo -ne '\a\n'
echo "QA Notice: the following files contain runtime text relocations"
echo " Text relocations force the dynamic linker to perform extra"
echo " work at startup, waste system resources, and may pose a security"
echo " risk. On some architectures, the code may not even function"
echo " properly, if at all."
echo " For more information, see http://hardened.gentoo.org/pic-fix-guide.xml"
echo " Please include this file in your report:"
echo " ${T}/scanelf-textrel.log"
echo "${f}"
echo -ne '\a\n'
die_msg="${die_msg} textrels,"
sleep 1
fi
# Also, executable stacks only matter on linux (and just glibc atm ...)
case ${CTARGET:-${CHOST}} in
*-linux-gnu*)
# Check for files with executable stacks, but only on arches which
# are supported at the moment. Keep this list in sync with
# http://hardened.gentoo.org/gnu-stack.xml (Arch Status)
case ${CTARGET:-${CHOST}} in
i?86*|ia64*|m68k*|s390*|x86_64*)
# Allow devs to mark things as ignorable ... e.g. things
# that are binary-only and upstream isn't cooperating ...
# we allow ebuild authors to set QA_EXECSTACK_arch and
# QA_EXECSTACK ... the former overrides the latter ...
# regexes allowed ! :)
qa_var="QA_EXECSTACK_${ARCH}"
[[ -n ${!qa_var} ]] && QA_EXECSTACK=${!qa_var}
[[ -n ${QA_STRICT_EXECSTACK} ]] && QA_EXECSTACK=""
f=$(scanelf -qyRF '%e %p' "${D}" | grep -v ' usr/lib/debug/' | \
gawk '
BEGIN { split("'"${QA_EXECSTACK}"'", ignore); }
{ for (idx in ignore)
if ($NF ~ "^"ignore[idx]"$")
next;
print;
}')
;;
*) f="" ;;
esac
;;
esac
if [[ -n ${f} ]] ; then
# One more pass to help devs track down the source
scanelf -qyRF '%e %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-execstack.log
echo -ne '\a\n'
echo "QA Notice: the following files contain executable stacks"
echo " Files with executable stacks will not work properly (or at all!)"
echo " on some architectures/operating systems. A bug should be filed"
echo " at http://bugs.gentoo.org/ to make sure the file is fixed."
echo " For more information, see http://hardened.gentoo.org/gnu-stack.xml"
echo " Please include this file in your report:"
echo " ${T}/scanelf-execstack.log"
echo "${f}"
echo -ne '\a\n'
die_msg="${die_msg} execstacks"
sleep 1
fi
# Save NEEDED information
scanelf -qyRF '%p %n' "${D}" | sed -e 's:^:/:' > "${PORTAGE_BUILDDIR}"/build-info/NEEDED
if [[ ${insecure_rpath} -eq 1 ]] ; then
die "Aborting due to serious QA concerns with RUNPATH/RPATH"
elif [[ ${die_msg} != "" ]] && has stricter ${FEATURES} && ! has stricter ${RESTRICT} ; then
die "Aborting due to QA concerns: ${die_msg}"
fi
fi
if [[ ${UNSAFE} > 0 ]] ; then
die "There are ${UNSAFE} unsafe files. Portage will not install them."
fi
if [[ -d ${D}/${D} ]] ; then
declare -i INSTALLTOD=0
for i in $(find "${D}/${D}/"); do
echo "QA Notice: /${i##${D}/${D}} installed in \${D}/\${D}"
((INSTALLTOD++))
done
die "Aborting due to QA concerns: ${INSTALLTOD} files installed in ${D}/${D}"
unset INSTALLTOD
fi
# dumps perms to stdout. if error, no perms dumped.
function stat_perms() {
local f
# only define do_stat if it hasn't been already
if ! type -p do_stat &> /dev/null; then
if ! type -p stat &>/dev/null; then
do_stat() {
# Generic version -- Octal result
python -c "import os,stat; print '%o' % os.stat('$1')[stat.ST_MODE]"
}
else
if [ "${USERLAND}" == "BSD" ] || [ "${USERLAND}" == "Darwin" ]; then
do_stat() {
# BSD version -- Octal result
$(type -p stat) -f '%p' "$1"
}
else
do_stat() {
# Linux version -- Hex result converted to Octal
f=$($(type -p stat) -c '%f' "$1") || return $?
printf '%o' "0x$f"
}
fi
fi
fi
f=$(do_stat "$@") || return
f="${f:2:4}"
echo $f
}
local file s
local count=0
find "${D}/" -user portage | while read file; do
count=$(( $count + 1 ))
if [ -L "${file}" ]; then
lchown ${PORTAGE_INST_UID:-0} "${file}"
else
s=$(stat_perms "$file")
if [ -z "${s}" ]; then
ewarn "failed stat_perm'ing $file. User intervention during install isn't wise..."
continue
fi
chown ${PORTAGE_INST_UID:-0} "$file"
chmod "$s" "$file"
fi
done
if (( $count > 0 )); then
ewarn "$count files were installed with user portage!"
fi
count=0
find "${D}/" -group portage | while read file; do
count=$(( $count + 1 ))
if [ -L "${file}" ]; then
lchgrp ${PORTAGE_INST_GID:-0} "${file}"
else
s=$(stat_perms "$file")
if [ -z "${s}" ]; then
echo "failed stat_perm'ing '$file' . User intervention during install isn't wise..."
continue
fi
chgrp ${PORTAGE_INST_GID:-0} "$file"
chmod "$s" "$file"
fi
done
if (( $count > 0 )); then
ewarn "$count files were installed with group portage!"
fi
unset -f stat_perms
# Portage regenerates this on the installed system.
if [ -f "${D}/usr/share/info/dir.gz" ]; then
rm -f "${D}/usr/share/info/dir.gz"
fi
if hasq multilib-strict ${FEATURES} && [ -x /usr/bin/file -a -x /usr/bin/find -a \
-n "${MULTILIB_STRICT_DIRS}" -a -n "${MULTILIB_STRICT_DENY}" ]; then
MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT:-"(perl5|gcc|gcc-lib|debug|portage)"} | sed -e 's:\([(|)]\):\\\1:g')
for dir in ${MULTILIB_STRICT_DIRS}; do
[ -d "${D}/${dir}" ] || continue
for file in $(find ${D}/${dir} -type f | grep -v "^${D}/${dir}/${MULTILIB_STRICT_EXEMPT}"); do
file ${file} | egrep -q "${MULTILIB_STRICT_DENY}" && die "File ${file} matches a file type that is not allowed in ${dir}"
done
done
fi
}
install_mask() {
local root="$1"
shift
local install_mask="$*"
# we don't want globbing for initial expansion, but afterwards, we do
local shopts=$-
set -o noglob
for no_inst in ${install_mask}; do
set +o noglob
einfo "Removing ${no_inst}"
# normal stuff
rm -Rf ${root}/${no_inst} >&/dev/null
# we also need to handle globs (*.a, *.h, etc)
find "${root}" -path ${no_inst} -exec rm -fR {} \; >/dev/null
done
# set everything back the way we found it
set +o noglob
set -${shopts}
}
preinst_mask() {
if [ -z "$IMAGE" ]; then
eerror "${FUNCNAME}: IMAGE is unset"
return 1
fi
# remove man pages, info pages, docs if requested
for f in man info doc; do
if hasq no${f} $FEATURES; then
INSTALL_MASK="${INSTALL_MASK} /usr/share/${f}"
fi
done
install_mask "${IMAGE}" ${INSTALL_MASK}
# remove share dir if unnessesary
if hasq nodoc $FEATURES -o hasq noman $FEATURES -o hasq noinfo $FEATURES; then
rmdir "${IMAGE}/usr/share" &> /dev/null
fi
}
preinst_sfperms() {
if [ -z "$IMAGE" ]; then
eerror "${FUNCNAME}: IMAGE is unset"
return 1
fi
# Smart FileSystem Permissions
if hasq sfperms $FEATURES; then
for i in $(find ${IMAGE}/ -type f -perm -4000); do
ebegin ">>> SetUID: [chmod go-r] $i "
chmod go-r "$i"
eend $?
done
for i in $(find ${IMAGE}/ -type f -perm -2000); do
ebegin ">>> SetGID: [chmod o-r] $i "
chmod o-r "$i"
eend $?
done
fi
}
preinst_suid_scan() {
if [ -z "$IMAGE" ]; then
eerror "${FUNCNAME}: IMAGE is unset"
return 1
fi
# total suid control.
if hasq suidctl $FEATURES; then
sfconf=/etc/portage/suidctl.conf
echo ">>> Preforming suid scan in ${IMAGE}"
for i in $(find ${IMAGE}/ -type f \( -perm -4000 -o -perm -2000 \) ); do
if [ -s "${sfconf}" ]; then
suid="`grep ^${i/${IMAGE}/}$ ${sfconf}`"
if [ "${suid}" = "${i/${IMAGE}/}" ]; then
echo "- ${i/${IMAGE}/} is an approved suid file"
else
echo ">>> Removing sbit on non registered ${i/${IMAGE}/}"
for x in 5 4 3 2 1 0; do echo -ne "\a"; sleep 0.25 ; done
echo -ne "\a"
chmod ugo-s "${i}"
grep ^#${i/${IMAGE}/}$ ${sfconf} > /dev/null || {
# sandbox prevents us from writing directly
# to files outside of the sandbox, but this
# can easly be bypassed using the addwrite() function
addwrite "${sfconf}"
echo ">>> Appending commented out entry to ${sfconf} for ${PF}"
ls_ret=`ls -ldh "${i}"`
echo "## ${ls_ret%${IMAGE}*}${ls_ret#*${IMAGE}}" >> ${sfconf}
echo "#${i/${IMAGE}/}" >> ${sfconf}
# no delwrite() eh?
# delwrite ${sconf}
}
fi
else
echo "suidctl feature set but you are lacking a ${sfconf}"
fi
done
fi
}
preinst_selinux_labels() {
if [ -z "$IMAGE" ]; then
eerror "${FUNCNAME}: IMAGE is unset"
return 1
fi
if hasq selinux ${FEATURES}; then
# SELinux file labeling (needs to always be last in dyn_preinst)
# only attempt to label if setfiles is executable
# and 'context' is available on selinuxfs.
if [ -f /selinux/context -a -x /usr/sbin/setfiles -a -x /usr/sbin/selinuxconfig ]; then
echo ">>> Setting SELinux security labels"
(
eval "$(/usr/sbin/selinuxconfig)" || \
die "Failed to determine SELinux policy paths.";
addwrite /selinux/context;
/usr/sbin/setfiles "${file_contexts_path}" -r "${IMAGE}" "${IMAGE}";
) || die "Failed to set SELinux security labels."
else
# nonfatal, since merging can happen outside a SE kernel
# like during a recovery situation
echo "!!! Unable to set SELinux security labels"
fi
fi
}
dyn_package() {
cd "${PORTAGE_BUILDDIR}/image"
install_mask "${PORTAGE_BUILDDIR}/image" ${PKG_INSTALL_MASK}
local pkg_dest="${PKGDIR}/All/${PF}.tbz2"
local pkg_tmp="${PKGDIR}/All/${PF}.tbz2.$$"
addwrite "${PKGDIR}"
tar cpvf - ./ | bzip2 -f > "${pkg_tmp}" || die "Failed to create tarball"
cd ..
python -c "import xpak; t=xpak.tbz2('${pkg_tmp}'); t.recompose('${PORTAGE_BUILDDIR}/build-info')"
if [ $? -ne 0 ]; then
rm -f "${pkg_tmp}"
die "Failed to append metadata to the tbz2 file"
fi
mv -f "${pkg_tmp}" "${pkg_dest}" || die "Failed to move tbz2 to ${pkg_dest}"
ln -sf "../All/${PF}.tbz2" "${PKGDIR}/${CATEGORY}/${PF}.tbz2" || die "Failed to create symlink in ${PKGDIR}/${CATEGORY}"
echo ">>> Done."
cd "${PORTAGE_BUILDDIR}"
touch .packaged || die "Failed to 'touch .packaged' in ${PORTAGE_BUILDDIR}"
}
dyn_spec() {
tar czf "/usr/src/redhat/SOURCES/${PF}.tar.gz" "${O}/${PF}.ebuild" "${O}/files" || die "Failed to create base rpm tarball."
cat <<__END1__ > ${PF}.spec
Summary: ${DESCRIPTION}
Name: ${PN}
Version: ${PV}
Release: ${PR}
Copyright: GPL
Group: portage/${CATEGORY}
Source: ${PF}.tar.gz
Buildroot: ${D}
%description
${DESCRIPTION}
${HOMEPAGE}
%prep
%setup -c
%build
%install
%clean
%files
/
__END1__
}
dyn_rpm() {
addwrite /usr/src/redhat/
addwrite ${RPMDIR}
dyn_spec
rpmbuild -bb "${PF}.spec" || die "Failed to integrate rpm spec file"
install -D "/usr/src/redhat/RPMS/i386/${PN}-${PV}-${PR}.i386.rpm" "${RPMDIR}/${CATEGORY}/${PN}-${PV}-${PR}.rpm" || die "Failed to move rpm"
}
if [ -n "${MISC_FUNCTIONS_ARGS}" ]; then
[ "$PORTAGE_DEBUG" == "1" ] && set -x
for x in ${MISC_FUNCTIONS_ARGS}; do
${x}
done
fi
true