Junichi Uekawa <[EMAIL PROTECTED]> writes: >Apart from being unhappy about a core component of >Debian dramatically changing at all; to answer your >question: > >> >I have concerns wrt shell quoting, >> >> Could you please explain more detailed? > >The implications of needing quoting means that previous >quoting conventions will need to change. > >Applications which used to pass quoted text to su, and >needs to quote differently now need to change dramatically.
That would be intolerable, indeed. But see below. > su username command A $B "C $D" >used to work, but it will now need to be > su username -c "command A \"$B\" \"C $D\"" No. With Debian's new su one would have to do (suppose one is using a bourne shell or compatible) to achieve the same result: $ (set x command A $B "C $D" && shift && exec su username -c "$*") >and specific semantics of how the contents of $B and $D is expanded is >going to change. No. $B and $D are expanded by the shell invoking su, not by the shell invoked by su. So there will be no change w.r.t. to $B and $D. There will be a change in concatenating: Debian's new su will not concatenate the parameters to make up a command string. So you have to do it yourself. That's what the 'set' command in conjunction with the special parameter "$*" does. But this feature of Debian's old su (i.e. concatenating the command arguments), is an undocumented feature: It is not documented in Debian's old su's manual page. So every invocation of su that adheres to the specification of Debian's old su won't use it anyway but concatenate all command string components by itself. The feature of Debian's old su to implicit pass a "-c" parameter to the shell if there are any arguments following the username, is undocumented, too. So every conforming invocation of su would supply "-c" by itself and not relay on su doing it implicitly. And what about quoting? No. There will be no change in quoting, because old su (like every su) does no quoting by itself, it simply concatenates the arguments. You may call this a bug of su, but it is not: Su does not know anything about quoting for username's shell it is going to start. As there are different shells (sh, bash, csh, tcsh, ksh, ash, some people use even emacs, ...) with different ways to quote, su cannot know how to quote the parameters before constructing a command to be executed by username's shell. So what does Debian's old su do, when it constructs the command to be executed by the username's shell? It does'nt do any quoting. It simply concatenates all the arguments into one string with spaces in between and supplies that string as the command string to the shell to be called. An example may illustrate this. In the following, I assume, that the shell to enter this commands into is a bash and that the username's shell (that will be invoked by su) is a bash, too: Don't do this at home! $ su -- username 'ls' '--' 'white space' 'a fancy name; rm -rf ~' Here, su is called with 6 parameters: '--', 'username', 'ls', '--', 'white space' and 'a fancy name; rm -rf ~'. Note, that the single quotes are not part of the parameters, as seen by su. I write them in this text to indicate the start and the end of each of the parameters (which may contain white space). Su will get the 6 parameters without the quotes as positional parameters. The single quotes in the command line are necessary, to indicate to the bash invoking su what the parameters to pass to su are to be. Debian's old su will notice, that the first parameter after the username (i.e. 'ls') is not a su option (see manual page su), so it assumes, that it is one of the words to be concatenated to make up the command string to pass to username's shell to be invoked. Therfore, Debian's old su will invoke the username's bash as follows (note, that the parameters to su are simply concatenated with spaces in between, no additional level of quoting is done by su): $ bash -c 'ls -- white space a fancy name; rm -rf ~' What will that bash, that is invoked by su, do? To understand, what will happen, take a look at the manual page bash(1): BASH(1) NAME bash - GNU Bourne-Again SHell SYNOPSIS bash [options] [file] [...] OPTIONS In addition to the single-character shell options documented in the description of the set builtin command, bash interprets the following options when it is invoked: -c string If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0. So, username's bash will execute the following two commands (note the semicolon!): $ ls -- white space a fancy name; rm -rf ~ Do I have to comment, what will happen? To achieve the same (bad) result using Debian's both old or new su, Linux Standard Base's su, etc, one could enter the following command, i.e. construct the parameters that su will use to invoke username's bash by oneself and pass them to su. W.r.t. to the command string, that would be: concatenate the arguments by yourself and pass the resulting command string to su: $ su -- username -c 'ls -- white space a fancy name; rm -rf ~' Here, Debian's new su, Linux Standard Base's su, etc, would just pass the remaining (here: two) parameters (if any) following the username to username's shell. Debian's old su would notice, that there are parameters following the username. It assumes, that they should make up a command to be passed to username's shell. As the first parameter is '-c', it takes this as the parameter '-c' to be passed to username's shell, indicating to it, that a command string will follow. Therefore, Debian's old su concatenates all the parameters following the '-c' with spaces in between (here is nothing to concatenate: only one parameter is remaining). Let me summarize: If you construct the command line by yourself and pass to Debian's old su only 2 command parameters: '-c', and the command line, then it will behave like Debian's new su, Linux Standard Base's su, etc. If you pass more than 1 command line fragment, then Debian's old su will concatenate the command line fragments with spaces in between (but without quoting!) to make up the command line. This "concatenating a command to be executed by username's shell" is a misleading feature of Debian's old su: It pretends to do proper command construction (including quoting) whereas it simply concatenates the parameters. Now, what could one do to avoid that mess? (1) Either construct a command string by yourself with proper quoting or (2) use username's shell (here: bash) to handle the unquoted arguments to ls by itself. To do (1), there is AFAIK no utility that does that in an easy way. One could operate with the 'printf' bash-builtin command using the format string '%q', but that's not easy (and would only work, if username's shell is one that accepts bash's way of quoting). To do (2), one can use the shell's "positional parameters". How to use the positional parameters? Again, bash(1) helps: PARAMETERS A parameter is an entity that stores values. It can be a name, a number, or one of the special characters listed below under Special Parameters. [...] Positional Parameters A positional parameter is a parameter denoted by one or more digits, other than the single digit 0. Positional parameters are assigned from the shell’s arguments when it is invoked, and may be reassigned using the set builtin command. Special Parameters The shell treats several parameters specially. [...] @ Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" ... When there are no positional parameters, "$@" and $@ expand to nothing (i.e., they are removed). Now, we can use the shell invocation parameters '-c' 'string': The command $ bash -c 'ls -- "$@"' 'bash' 'white space' 'a fancy name; rm -rf ~' invokes a bash, giving it 5 parameters: '-c', 'ls -- "$@"' 'bash', 'white space' and 'a fancy name; rm -rf ~'. The first parameter, '-c', indicates to bash (see manual page above), that bash should execute a command string (the second parameter 'ls -- "$@"') rather than be an interactive shell. The 3 remaining parameters after the string following '-c', i.e. the parameters 'bash', 'white space' and 'a fancy name; rm -rf ~', are assigned to the bash's positional parameters $0, $1 and $2, i.e. in that bash, executing the commands $ test "$0" = bash $ test "$1" = 'white space' $ test "$2" = 'a fancy name; rm -rf ~' would yield the exit code zero. When executing the command $ ls -- "$@" in that bash, bash expands the expression "$@" to the positional parameters no. 1 and 2: The program ls gets called with the three parameters '--', 'white space' and 'a fancy name; rm -rf ~': $ ls -- 'white space' 'a fancy name; rm -rf ~' To make a long story short: To achieve proper parameter propagation through su, there are two ways to go: Either quote all arguments by yourself (that's not easy!) when constructing the command string or pass all arguments as separate parameters to username's shell and let that shell construct the command by itself. So, clearly the second way is the preferable way to do it. Debian's new su, Linux Standard Base's su, etc, would just pass the parameters given to it unchanged (i.e. not concatenated) to the username's shell it invokes, thus let the user of su pass positional parameters to the shell to be expanded using '"$@"'. With Debian's old su, it is impossible to pass positional parameters to a shell following the parameters '-c' 'ls -- "$@"', because it concatenates all remaining parameters to the command string. Therefore, Debian's old su thwarts the second way to achieve proper parameter passing! That's one of the reasons why I want Debian's su behavior to change to Debian's old su's specification (i.e. manual page) and Linux Standard Base', Fedora's, HPUX's and Solaris' su's semantics and specification. Let me drop some words about (using Debian's old su) > su username command A $B "C $D" and (using Debian's new su) > su username -c "command A \"$B\" \"C $D\"" . As Debian's both old an new su don't do any quoting, there is no way to construct an invocation of su without using the positional parameters or explicit quoting (e.g. using printf ' %q') by simply inserting quotation marks into the command string: For example: $ A="\"':; cd; rm -r .;'; cd; rm -r .;\":; cd; rm -r .;:" With Debian's old su, all four commands $ su username ls "\"$A\"" $ su username ls "'$A'" $ su username ls "$A" $ su username -c "ls \"[EMAIL PROTECTED]"" bash "$A" would empty username's home directory, whereas Debian's new su, Linux Standard Base's su, etc, when invoked by $ su username -c "ls \"[EMAIL PROTECTED]"" bash "$A" would do what it is told to do. Best regards, Helmut -- Wenn Sie mir E-Mail schreiben, stellen | When writing me e-mail, please Sie bitte vor meine E-Mail-Adresse | precede my e-mail address with meinen Vor- und Nachnamen, etwa so: | my full name, like Helmut Waitzmann <[EMAIL PROTECTED]>, (Helmut Waitzmann) [EMAIL PROTECTED]