Fix nasty bug in chmod, plus minor fixes.
[pkgusr] / usr / lib / pkgusr / chown
index 8dfddb4..4fe1671 100755 (executable)
@@ -1,8 +1,13 @@
 #!/bin/bash
+# Original...
 # Copyright (c) 2000,2004 Matthias S. Benkmann <article AT winterdrache DOT de>
 # You may do everything with this code except misrepresent its origin.
 # PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND!
 
+# Copyright (C) 2014 Steve Youngs <steve@steveyoungs.com>
+#  Rewrite, make it a lot more robost and handle most (all?) 
+#  possibilities of chown'ing. --SY.
+
 DAISY_CHAIN=""
 
 for p in $(type -ap chown) ; do
@@ -13,18 +18,81 @@ for p in $(type -ap chown) ; do
 done
 
 if [ ! -n "$DAISY_CHAIN" ]; then
-    echo Cannot find real ${0##*/} command 
+    echo 1>&2 '***' Cannot find real ${0##*/} command 
+    exit 1
+fi
+
+if [ $(id -u) == 0 ]; then
+    echo 1>&2 '***' $(dirname $0) should not be in root\'s \$PATH
+    echo 1>&2 '***' call '"'$DAISY_CHAIN $@'"' directly.
     exit 1
 fi
 
-if [ $UID == 0 ]; then
-    exec $DAISY_CHAIN "$@"
+# An ordinary user cannot change the UID of a file if that UID is
+# not their own, but chown can also be used to change the GID of a
+# file as well so it is feasible that an ordinary user could use
+# chown successfully.
+
+# preseve the command line as we're gonna mess with it.
+cmdline="$@"
+# strip off the options so that $1 becomes the UID:GID arg
+while [ -n "$1" ]; do
+    case "$1" in
+       (-*) shift ;;
+       (*) break ;;
+    esac
+done
+
+# Split USER:GROUP or USER.GROUP into USER and GROUP
+usrgrp="$1"
+usr=${usrgrp/[.:]*/}
+grp=${usrgrp/*[.:]/}
+
+report=0
+
+# Catch the case where USER is somebody else.
+if [ -n "$usr" ]; then
+    printf '%d' "$usr" &>/dev/null
+    if [ $? -eq 0 ]; then
+       if [ $usr -ne $(id -u) ]; then
+           report=1
+       fi
+    else
+       if [ "$usr" != "$(id -un)" ]; then
+           report=1
+       fi
+    fi
+fi
+
+# Catch the case where GROUP isn't in our groups.
+if [ -n "$grp" -a $report -eq 0 ]; then
+    GRP_CHAIN=""
+    printf '%d' "$grp" &>/dev/null
+    if [ $? -eq 0 ]; then
+       GRP_LIST=$(id -G)
+    else
+       GRP_LIST=$(id -Gn)
+    fi
+    for g in ${GRP_LIST}; do
+       if [ "$grp" == "$g" ]; then
+           GRP_CHAIN=$g
+           break
+       fi
+    done
+
+    if [ -z "$GRP_CHAIN" ]; then
+       report=1
+    fi
 fi
 
-if [ "$1" == "root.root" ]; then
-    echo 1>&2 '***' chown "$@"  
+if [ $report -eq 1 ]; then
+    echo 1>&2 '***' chown ${cmdline}
 else
-    $DAISY_CHAIN "$@" || exit $?
+    $DAISY_CHAIN ${cmdline} || exit $?
 fi
 
 exit 0
+
+# Local variables:
+# sh-basic-offset: 4
+# End: