From 4aca87515a5083ae0e31ce3177189fd43b6d05ac Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 3 Jan 2015 13:58:15 +0100 Subject: patch to Vanilla Tomato 1.28 --- release/src/router/busybox/coreutils/chmod.c | 200 +++++++++++++++++---------- 1 file changed, 124 insertions(+), 76 deletions(-) (limited to 'release/src/router/busybox/coreutils/chmod.c') diff --git a/release/src/router/busybox/coreutils/chmod.c b/release/src/router/busybox/coreutils/chmod.c index 390cc6d2..40f681fb 100644 --- a/release/src/router/busybox/coreutils/chmod.c +++ b/release/src/router/busybox/coreutils/chmod.c @@ -2,100 +2,113 @@ /* * Mini chmod implementation for busybox * - * Copyright (C) 1999-2003 by Erik Andersen + * Copyright (C) 1999-2004 by Erik Andersen * * Reworked by (C) 2002 Vladimir Oleynik * to correctly parse '-rwxgoa' * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ /* BB_AUDIT SUSv3 compliant */ -/* BB_AUDIT GNU defects - unsupported options -c, -f, -v, and long options. */ +/* BB_AUDIT GNU defects - unsupported long options. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */ -#include -#include -#include -#include -#include -#include "busybox.h" +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + + +#define OPT_RECURSE (option_mask32 & 1) +#define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 2) SKIP_DESKTOP(0)) +#define OPT_CHANGED (USE_DESKTOP(option_mask32 & 4) SKIP_DESKTOP(0)) +#define OPT_QUIET (USE_DESKTOP(option_mask32 & 8) SKIP_DESKTOP(0)) +#define OPT_STR "R" USE_DESKTOP("vcf") -static int fileAction(const char *fileName, struct stat *statbuf, void* junk) +/* coreutils: + * chmod never changes the permissions of symbolic links; the chmod + * system call cannot change their permissions. This is not a problem + * since the permissions of symbolic links are never used. + * However, for each symbolic link listed on the command line, chmod changes + * the permissions of the pointed-to file. In contrast, chmod ignores + * symbolic links encountered during recursive directory traversals. + */ + +static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void* param, int depth) { - if (!bb_parse_mode((char *)junk, &(statbuf->st_mode))) - bb_error_msg_and_die( "invalid mode: %s", (char *)junk); - if (chmod(fileName, statbuf->st_mode) == 0) - return (TRUE); - bb_perror_msg("%s", fileName); /* Avoid multibyte problems. */ - return (FALSE); + mode_t newmode; + + /* match coreutils behavior */ + if (depth == 0) { + /* statbuf holds lstat result, but we need stat (follow link) */ + if (stat(fileName, statbuf)) + goto err; + } else { /* depth > 0: skip links */ + if (S_ISLNK(statbuf->st_mode)) + return TRUE; + } + newmode = statbuf->st_mode; + + if (!bb_parse_mode((char *)param, &newmode)) + bb_error_msg_and_die("invalid mode: %s", (char *)param); + + if (chmod(fileName, newmode) == 0) { + if (OPT_VERBOSE + || (OPT_CHANGED && statbuf->st_mode != newmode) + ) { + printf("mode of '%s' changed to %04o (%s)\n", fileName, + newmode & 07777, bb_mode_string(newmode)+1); + } + return TRUE; + } + err: + if (!OPT_QUIET) + bb_simple_perror_msg(fileName); + return FALSE; } -int chmod_main(int argc, char **argv) +int chmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int chmod_main(int argc UNUSED_PARAM, char **argv) { int retval = EXIT_SUCCESS; - int recursiveFlag = FALSE; - int count; + char *arg, **argp; char *smode; - char **p; - char *p0; - char opt = '-'; - - ++argv; - count = 0; - - for (p = argv ; *p ; p++) { - p0 = p[0]; - if (p0[0] == opt) { - if ((p0[1] == '-') && !p0[2]) { - opt = 0; /* Disable further option processing. */ - continue; - } - if (p0[1] == 'R') { - char *s = p0 + 2; - while (*s == 'R') { - ++s; - } - if (*s) { - bb_show_usage(); - } - recursiveFlag = TRUE; - continue; - } - if (count) { - bb_show_usage(); - } + + /* Convert first encountered -r into ar, -w into aw etc + * so that getopt would not eat it */ + argp = argv; + while ((arg = *++argp)) { + /* Mode spec must be the first arg (sans -R etc) */ + /* (protect against mishandling e.g. "chmod 644 -r") */ + if (arg[0] != '-') { + arg = NULL; + break; + } + /* An option. Not a -- or valid option? */ + if (arg[1] && !strchr("-"OPT_STR, arg[1])) { + arg[0] = 'a'; + break; } - argv[count] = p0; - ++count; } - argv[count] = NULL; + /* Parse options */ + opt_complementary = "-2"; + getopt32(argv, ("-"OPT_STR) + 1); /* Reuse string */ + argv += optind; - if (count < 2) { - bb_show_usage(); - } - - smode = *argv; - ++argv; + /* Restore option-like mode if needed */ + if (arg) arg[0] = '-'; /* Ok, ready to do the deed now */ + smode = *argv++; do { - if (! recursive_action (*argv, recursiveFlag, FALSE, FALSE, - fileAction, fileAction, smode)) { + if (!recursive_action(*argv, + OPT_RECURSE, // recurse + fileAction, // file action + fileAction, // dir action + smode, // user data + 0) // depth + ) { retval = EXIT_FAILURE; } } while (*++argv); @@ -104,9 +117,44 @@ int chmod_main(int argc, char **argv) } /* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: +Security: chmod is too important and too subtle. +This is a test script (busybox chmod versus coreutils). +Run it in empty directory. + +#!/bin/sh +t1="/tmp/busybox chmod" +t2="/usr/bin/chmod" +create() { + rm -rf $1; mkdir $1 + ( + cd $1 || exit 1 + mkdir dir + >up + >file + >dir/file + ln -s dir linkdir + ln -s file linkfile + ln -s ../up dir/up + ) +} +tst() { + (cd test1; $t1 $1) + (cd test2; $t2 $1) + (cd test1; ls -lR) >out1 + (cd test2; ls -lR) >out2 + echo "chmod $1" >out.diff + if ! diff -u out1 out2 >>out.diff; then exit 1; fi + rm out.diff +} +echo "If script produced 'out.diff' file, then at least one testcase failed" +create test1; create test2 +tst "a+w file" +tst "a-w dir" +tst "a+w linkfile" +tst "a-w linkdir" +tst "-R a+w file" +tst "-R a-w dir" +tst "-R a+w linkfile" +tst "-R a-w linkdir" +tst "a-r,a+x linkfile" */ -- cgit v1.2.3-54-g00ecf