# Copyright (c) 2017 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by Johnny C. Lam. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # NAME # permissions.subr -- check and set modes and permissions for packages # # SYNOPSIS # task_check_permissions path mode [owner [group]] # task_set_permissions path mode [owner [group]] # # task_permissions [-s] add # task_permissions check-add # # DESCRIPTION # The task_check_permissions function checks the mode, owner, and # group of the path. # # The task_set_permissions function sets the mode, owner, and group of # the path. # # The task_permissions function supports two actions: "check-add" and # "add". # # The available options are as follows: # # -s Silent; don't write to standard output. # # The task_permissions function reads standard input line by line and # looks for lines of the form: # # # PERMS: [] [] # # If the path is relative, then it is assumed to be relative to # ${PKG_PREFIX}. # # The "check-add" action checks whether the path has the correct mode # and permissions or otherwise writes a message to standard output # noting the path has incorrect permissions. # # The "add" action sets the special modes and permissions on the path. # # RETURN VALUES # The task_check_permissions function returns 0 if the mode and # permissions match, and >0 otherwise. # # The task_set_permissions and task_permissions functions return 0 on # success, and >0 if an error occurs. # # ENVIRONMENT # The following variables are used if they are set: # # CHMOD The name or path to the chmod(1) utility. # # CHOWN The name or path to the chown(8) utility. # # LS The name or path to the ls(1) utility. # # PKGNAME # The name of the package. # # PKG_DESTDIR # A "destdir" prefix that is prepended to all filesystem # paths. The default value is the empty string. This # variable is only used by task_permissions. # # PKG_PREFIX # The installation prefix of the package. The default is # "/usr/pkg". # # TASK_MSG # String prepended to all normal message written to # standard output. # __task_permissions__="yes" task_load echo task_set_permissions() { : ${CHMOD:=chmod} : ${CHOWN:=chown} local path="$1"; shift local mode="$1"; shift local owner="$1"; [ $# -eq 0 ] || shift local group="$1"; [ $# -eq 0 ] || shift local result=0 case $owner:$group in :) ;; *) ${CHOWN} "$owner:$group" "$path" || result=1 ;; esac case $mode in "") ;; *) ${CHMOD} "$mode" "$path" || result=1 ;; esac return $result } task_check_permissions() { : ${LS:=ls} local path="$1"; shift local mode="$1"; shift local owner="$1"; [ $# -eq 0 ] || shift local group="$1"; [ $# -eq 0 ] || shift ${LS} -dl "$path" 2>/dev/null | ( read lsmode __ lsowner lsgroup __ [ -z "$owner" -o "$owner" = "$lsowner" ] || return 1 [ -z "$group" -o "$group" = "$lsgroup" ] || return 1 # Parse the ls(1) long file mode format. nummode=0 case $lsmode in ?r????????) nummode="$nummode + 400" ;; esac case $lsmode in ??w???????) nummode="$nummode + 200" ;; esac case $lsmode in ???x??????) nummode="$nummode + 100" ;; esac case $lsmode in ???S??????) nummode="$nummode + 4000" ;; esac case $lsmode in ???s??????) nummode="$nummode + 4100" ;; esac case $lsmode in ????r?????) nummode="$nummode + 40" ;; esac case $lsmode in ?????w????) nummode="$nummode + 20" ;; esac case $lsmode in ??????x???) nummode="$nummode + 10" ;; esac case $lsmode in ??????S???) nummode="$nummode + 2000" ;; esac case $lsmode in ??????s???) nummode="$nummode + 2010" ;; esac case $lsmode in ???????r??) nummode="$nummode + 4" ;; esac case $lsmode in ????????w?) nummode="$nummode + 2" ;; esac case $lsmode in ?????????x) nummode="$nummode + 1" ;; esac case $lsmode in ?????????T) nummode="$nummode + 1000" ;; esac case $lsmode in ?????????t) nummode="$nummode + 1001" ;; esac [ $(( $nummode )) -eq $mode ] ) } task_permissions() { : ${PKG_PREFIX:=/usr/pkg} : ${PKGNAME:=${0##*/}} : ${TASK_MSG=""} local arg local echo="task_echo" local OPTIND=1 while getopts ":s" arg "$@"; do case $arg in s) echo=":" ;; *) return 127 ;; esac done shift $(( ${OPTIND} - 1 )) [ $# -gt 0 ] || return 127 local action="$1"; shift case $action in add|check-add) : "valid options" ;; *) return 0 ;; esac # Guard against ${PKG_PREFIX} == "/". local prefix case ${PKG_PREFIX}/ in //) prefix= ;; *) prefix=${PKG_PREFIX} ;; esac local result local msg result=0 local hash tag path mode user group while read hash tag path mode user group; do # Filter for "# PERMS:" case $hash/$tag in "#/PERMS:") : "use this line" ;; *) continue ;; esac # Canonicalize paths. case $path in "") # skip lines without required args continue ;; [!/]*) path="$prefix/$path" ;; esac path="${PKG_DESTDIR}$path" msg= case $mode/$user/$group in //) msg="$path" ;; [!/]*//) msg="$path (m=$mode)" ;; [!/]*/[!/]*/) msg="$path (o=$user, m=$mode)" ;; [!/]*/[!/]*/[!/]*) msg="$path (o=$user, g=$group, m=$mode)" ;; esac case "$action" in add) if [ ! -e "$path" ]; then $echo "${TASK_MSG}! permissions not set on missing: $path" result=1 elif task_set_permissions "$path" "$mode" "$user" "$group"; then $echo "${TASK_MSG}> permissions set: $msg" else $echo "${TASK_MSG}! permissions not set: $msg" result=1 fi ;; check-add) if [ -e "$path" ] && task_check_permissions "$path" "$mode" "$user" "$group"; then : "permissions already correct" else task_echo "!!! INFO: ${PKGNAME}: Set permissions: $msg" result=1 fi ;; esac done return $result }