logo

overlay

My (experimental) gentoo overlay

fcaps.eclass (6037B)


      1 # Copyright 1999-2015 Gentoo Foundation
      2 # Distributed under the terms of the GNU General Public License v2
      3 # $Id$
      4 
      5 # @ECLASS: fcaps.eclass
      6 # @MAINTAINER:
      7 # Constanze Hausner <constanze@gentoo.org>
      8 # base-system@gentoo.org
      9 # @BLURB: function to set POSIX file-based capabilities
     10 # @DESCRIPTION:
     11 # This eclass provides a function to set file-based capabilities on binaries.
     12 # This is not the same as USE=caps which controls runtime capability changes,
     13 # often via packages like libcap.
     14 #
     15 # Due to probable capability-loss on moving or copying, this happens in
     16 # pkg_postinst-phase (at least for now).
     17 #
     18 # @EXAMPLE:
     19 # You can manually set the caps on ping and ping6 by doing:
     20 # @CODE
     21 # pkg_postinst() {
     22 # 	fcaps cap_net_raw bin/ping bin/ping6
     23 # }
     24 # @CODE
     25 #
     26 # Or set it via the global ebuild var FILECAPS:
     27 # @CODE
     28 # FILECAPS=(
     29 # 	cap_net_raw bin/ping bin/ping6
     30 # )
     31 # @CODE
     32 
     33 if [[ -z ${_FCAPS_ECLASS} ]]; then
     34 _FCAPS_ECLASS=1
     35 
     36 IUSE="+filecaps"
     37 
     38 # We can't use libcap-ng atm due to #471414.
     39 DEPEND="filecaps? ( sys-libs/libcap )"
     40 
     41 # @ECLASS-VARIABLE: FILECAPS
     42 # @DEFAULT_UNSET
     43 # @DESCRIPTION:
     44 # An array of fcap arguments to use to automatically execute fcaps.  See that
     45 # function for more details.
     46 #
     47 # All args are consumed until the '--' marker is found.  So if you have:
     48 # @CODE
     49 # 	FILECAPS=( moo cow -- fat cat -- chubby penguin )
     50 # @CODE
     51 #
     52 # This will end up executing:
     53 # @CODE
     54 # 	fcaps moo cow
     55 # 	fcaps fat cat
     56 # 	fcaps chubby penguin
     57 # @CODE
     58 #
     59 # Note: If you override pkg_postinst, you must call fcaps_pkg_postinst yourself.
     60 
     61 # @FUNCTION: fcaps
     62 # @USAGE: [-o <owner>] [-g <group>] [-m <mode>] [-M <caps mode>] <capabilities> <file[s]>
     63 # @DESCRIPTION:
     64 # Sets the specified capabilities on the specified files.
     65 #
     66 # The caps option takes the form as expected by the cap_from_text(3) man page.
     67 # If no action is specified, then "=ep" will be used as a default.
     68 #
     69 # If the file is a relative path (e.g. bin/foo rather than /bin/foo), then the
     70 # appropriate path var ($D/$ROOT/etc...) will be prefixed based on the current
     71 # ebuild phase.
     72 #
     73 # The caps mode (default 711) is used to set the permission on the file if
     74 # capabilities were properly set on the file.
     75 #
     76 # If the system is unable to set capabilities, it will use the specified user,
     77 # group, and mode (presumably to make the binary set*id).  The defaults there
     78 # are 0:0 and 4711.  Otherwise, the ownership and permissions will be
     79 # unchanged.
     80 fcaps() {
     81 	debug-print-function ${FUNCNAME} "$@"
     82 
     83 	# Process the user options first.
     84 	local owner='0'
     85 	local group='0'
     86 	local mode='4711'
     87 	local caps_mode='711'
     88 
     89 	while [[ $# -gt 0 ]] ; do
     90 		case $1 in
     91 		-o) owner=$2; shift;;
     92 		-g) group=$2; shift;;
     93 		-m) mode=$2; shift;;
     94 		-M) caps_mode=$2; shift;;
     95 		*) break;;
     96 		esac
     97 		shift
     98 	done
     99 
    100 	[[ $# -lt 2 ]] && die "${FUNCNAME}: wrong arg count"
    101 
    102 	local caps=$1
    103 	[[ ${caps} == *[-=+]* ]] || caps+="=ep"
    104 	shift
    105 
    106 	local root
    107 	case ${EBUILD_PHASE} in
    108 	compile|install|preinst)
    109 		root=${ED:-${D}}
    110 		;;
    111 	postinst)
    112 		root=${EROOT:-${ROOT}}
    113 		;;
    114 	esac
    115 
    116 	# Process every file!
    117 	local file
    118 	for file ; do
    119 		[[ ${file} != /* ]] && file="${root}${file}"
    120 
    121 		if use filecaps ; then
    122 			# Try to set capabilities.  Ignore errors when the
    123 			# fs doesn't support it, but abort on all others.
    124 			debug-print "${FUNCNAME}: setting caps '${caps}' on '${file}'"
    125 
    126 			# If everything goes well, we don't want the file to be readable
    127 			# by people.
    128 			chmod ${caps_mode} "${file}" || die
    129 
    130 			# Set/verify funcs for sys-libs/libcap.
    131 			_libcap()        { setcap "${caps}" "${file}" ; }
    132 			_libcap_verify() { setcap -v "${caps}" "${file}" >/dev/null ; }
    133 
    134 			# Set/verify funcs for sys-libs/libcap-ng.
    135 			# Note: filecap only supports =ep mode.
    136 			# It also expects a different form:
    137 			#  setcap cap_foo,cap_bar
    138 			#  filecap foo bar
    139 			_libcap_ng() {
    140 				local caps=",${caps%=ep}"
    141 				filecap "${file}" "${caps//,cap_}"
    142 			}
    143 			_libcap_ng_verify() {
    144 				# libcap-ng has a crappy interface
    145 				local rcaps icaps caps=",${caps%=ep}"
    146 				rcaps=$(filecap "${file}" | \
    147 					sed -nr \
    148 						-e "s:^.{${#file}} +::" \
    149 						-e 's:, +:\n:g' \
    150 						-e 2p | \
    151 					LC_ALL=C sort)
    152 				[[ ${PIPESTATUS[0]} -eq 0 ]] || return 1
    153 				icaps=$(echo "${caps//,cap_}" | LC_ALL=C sort)
    154 				[[ ${rcaps} == ${icaps} ]]
    155 			}
    156 
    157 			local out cmd notfound=0
    158 			for cmd in _libcap _libcap_ng ; do
    159 				if ! out=$(LC_ALL=C ${cmd} 2>&1) ; then
    160 					case ${out} in
    161 					*"command not found"*)
    162 						: $(( ++notfound ))
    163 						continue
    164 						;;
    165 					# ENOTSUP and EOPNOTSUPP might be the same value which means
    166 					# strerror() on them is unstable -- we can get both. #559608
    167 					*"Not supported"*|\
    168 					*"Operation not supported"*)
    169 						local fstype=$(stat -f -c %T "${file}")
    170 						ewarn "Could not set caps on '${file}' due to missing filesystem support:"
    171 						ewarn "* enable XATTR support for '${fstype}' in your kernel (if configurable)"
    172 						ewarn "* mount the fs with the user_xattr option (if not the default)"
    173 						ewarn "* enable the relevant FS_SECURITY option (if configurable)"
    174 						break
    175 						;;
    176 					*)
    177 						eerror "Setting caps '${caps}' on file '${file}' failed:"
    178 						eerror "${out}"
    179 						die "could not set caps"
    180 						;;
    181 					esac
    182 				else
    183 					# Sanity check that everything took.
    184 					${cmd}_verify || die "Checking caps '${caps}' on '${file}' failed"
    185 
    186 					# Everything worked.  Move on to the next file.
    187 					continue 2
    188 				fi
    189 			done
    190 			if [[ ${notfound} -eq 2 ]] && [[ -z ${_FCAPS_WARNED} ]] ; then
    191 				_FCAPS_WARNED="true"
    192 				ewarn "Could not find cap utils; make sure libcap or libcap-ng is available."
    193 			fi
    194 		fi
    195 
    196 		# If we're still here, setcaps failed.
    197 		debug-print "${FUNCNAME}: setting owner/mode on '${file}'"
    198 		chown "${owner}:${group}" "${file}" || die
    199 		chmod ${mode} "${file}" || die
    200 	done
    201 }
    202 
    203 # @FUNCTION: fcaps_pkg_postinst
    204 # @DESCRIPTION:
    205 # Process the FILECAPS array.
    206 fcaps_pkg_postinst() {
    207 	local arg args=()
    208 	for arg in "${FILECAPS[@]}" "--" ; do
    209 		if [[ ${arg} == "--" ]] ; then
    210 			fcaps "${args[@]}"
    211 			args=()
    212 		else
    213 			args+=( "${arg}" )
    214 		fi
    215 	done
    216 }
    217 
    218 EXPORT_FUNCTIONS pkg_postinst
    219 
    220 fi