[Pkg-shadow-devel] patch for su (needed by the switch to getopt
in 4.0.14)
Nicolas François
nicolas.francois at centraliens.net
Tue Dec 13 22:02:29 UTC 2005
Hello Tomasz,
Thanks for having commited the previous patches.
The attached patch contains:
* update for the su.1 man page
* some various fixes for su.c (in the patch chunk order; feel free to
only apply some of these):
+ Fix a comment about su options
+ add '-' at the first position of the options string.
This permits to stop getopt at the first non-su option.
+ add a comment to the --preserve-environment option
+ a tag to exit getopt (see above) when the first non-su option is
encoutered
+ Simplify the --preserve-environment:
change_environment was always used with:
"(change_environment || restricted_shell (pwent.pw_shell))"
so OR it earlier.
I also permit root to use --preserve-environment, even if the target
user has a restricted shell (this was already the case at some place,
but not everywere).
This way, documenting (and understanding) -p is much easier.
So there is a little difference with the way Debian currently behave,
but I think this is better this way.
+ I replaced getuid () by !amroot
This removes a system call, and is easier to read.
This getuid () was added by one of my previous patches.
+ Some other change_environment simplifications (see earlier
+ (In the same patch chunk as the previous point) set pwent.pw_shell to
shellstr because setup_env uses pw_shell to set the SHELL environment
variable
(This is a bug in the current version in Debian)
+ (Also in the same patch chunk as the previous point)Add LOGNAME to
the variables always exported (unless -p). This mimic setup_env.
I think this is right. When the user uses "su", or "su -", she
doesn't want to have USER or LOGNAME to point to her previous login
name.
+ Fix a comment: the shell is no more always the one specified in
/etc/passwd
* Fix a commment in useradd.c
I plan to write another section in the su manpage (maybe login will also
need it): to describe the environment the user will have after calling su.
It is currently very complicated. I will try to make some modification to
simplify it.
Currently:
The environment is clean (sanitize_env; but not in Debian):
* Some environment variables are removed (see the forbid array in
libmisc/env.c), and the languages variables (LANG, LANGUAGE, LC_*) wich
contain a '/' are removed (probably for a security reason)
* in the case of a login su (su -), a new environment is built with only TERM
otherwise, all the current sanitized environment is used for the new
environment
The new environment is later changed this way:
* PATH is always set/replaced (ENV_PATH, ENV_SUPATH, or defaut)
* If IFS was set, it is reset to a safe value
(There may be a difference here between a su compiled with USE_PAM or
not)
(I'm not sure it is needed, because IFS is removed by sanitize_env)
* the PAM environment are copied
* Some variable are set to sane defaut to reflect the change of user,
shell etc. (HOME, SHELL, USER, LOGNAME). This is done either by
setup_env (login su, or separately otherwise; this is the reason I
added LOGNAME in the attached patch)
Then, if -p was not specified (and the target user do not have a restricted
shell or if su is run by root), this new environment is used (and is
trashed otherwise)
Thus, with -p, the environment is not entirely preserved (sanitize_env).
This is still a little bit confusing. I will try to make just a couple of
sentences.
Cheers,
--
Nekral
-------------- next part --------------
Index: man/su.1.xml
===================================================================
RCS file: /cvsroot/shadow/man/su.1.xml,v
retrieving revision 1.16
diff -u -r1.16 su.1.xml
--- man/su.1.xml 5 Nov 2005 17:17:30 -0000 1.16
+++ man/su.1.xml 13 Dec 2005 22:01:49 -0000
@@ -15,6 +15,9 @@
<refsynopsisdiv id='synopsis'>
<cmdsynopsis>
<command>su</command>
+ <arg choice='opt'>
+ <replaceable>options</replaceable>
+ </arg>
<arg choice='opt'>- </arg>
<arg choice='opt'>
<arg choice='plain'>
@@ -46,6 +49,11 @@
for the target user.
</para>
+ <para>
+ You can use the <option>--</option> argument to separate
+ <command>su</command> options from the arguments supplied to the shell.
+ </para>
+
<para>The user will be prompted for a password, if appropriate. Invalid
passwords will produce an error message. All attempts, both valid and
invalid, are logged to detect abuses of the system.
@@ -68,6 +76,86 @@
</para>
</refsect1>
+ <refsect1 id='options'>
+ <title>OPTIONS</title>
+ <para>The options which apply to the <command>su</command> command are:
+ </para>
+ <variablelist remap='IP'>
+ <varlistentry>
+ <term>
+ <option>-</option>, <option>-l</option>, <option>--login</option>
+ </term>
+ <listitem>
+ <para>
+ Provide an environment similar to what the user would expect had
+ the user logged in directly.
+ </para>
+ <para>
+ When <option>-</option> is used, it must be specified as the last
+ <command>su</command> option.
+ The other forms (<option>-l</option> and <option>--login</option>)
+ do not have this restriction.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>-s</option>, <option>--shell</option>
+ </term>
+ <listitem>
+ <para>The shell that will be invoked.</para>
+ <para>
+ The invoked shell is choosen among (higest priority first):
+ <itemizedlist>
+ <listitem>
+ <para>The shell specified with --shell</para>
+ </listitem>
+ <listitem>
+ <para>
+ If <option>--preserve-environment</option> is used, the
+ shell specified by the <envar>SHELL</envar> environment
+ variable.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The shell indicated in the /etc/passwd entry for the target
+ user.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ /bin/sh if a shell could not be found by any above method.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ If the target user has a restricted shell (i.e. the shell field of
+ this user's entry in <filename>/etc/passwd</filename> is not
+ specified in <filename>/etc/shell</filename>), then the
+ <option>--shell</option> option or the <envar>SHELL</envar>
+ environment variable won't be taken into account unless
+ <command>su</command> is called by the root.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>-m</option>, <option>-p</option>,
+ <option>--preserve-environment</option>
+ </term>
+ <listitem>
+ <para>Preserve the current environment.</para>
+ <para>
+ If the target user has a restricted shell, this option has no
+ effect (unless <command>su</command> is called by root).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
<refsect1 id='caveats'>
<title>CAVEATS</title>
<para>
@@ -104,10 +192,7 @@
</citerefentry>,
<citerefentry>
<refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum>
- </citerefentry>,
- <citerefentry>
- <refentrytitle>suauth</refentrytitle><manvolnum>5</manvolnum>
- </citerefentry>.
+ </citerefentry>
</para>
</refsect1>
</refentry>
Index: src/su.c
===================================================================
RCS file: /cvsroot/shadow/src/su.c,v
retrieving revision 1.55
diff -u -r1.55 su.c
--- src/su.c 13 Dec 2005 14:03:05 -0000 1.55
+++ src/su.c 13 Dec 2005 22:01:49 -0000
@@ -271,9 +271,6 @@
* su changes the user's ids to the values for the specified user. if
* no new user name is specified, "root" is used by default.
*
- * The only valid option is a "-" character, which is interpreted as
- * requiring a new login session to be simulated.
- *
* Any additional arguments are passed to the user's shell. In
* particular, the argument "-c" will cause the next argument to be
* interpreted as a command by the common shell programs.
@@ -339,9 +336,17 @@
};
while ((c =
- getopt_long (argc, argv, "hlmps:", long_options,
+ getopt_long (argc, argv, "-hlmps:", long_options,
&option_index)) != -1) {
switch (c) {
+ case 1:
+ /* This is not an su option */
+ /* The next arguments are either '-', the target name, or
+ * arguments to be passed to the shell.
+ */
+ optind--; /* rewind the current (not yet handled) option */
+ goto end_su_options;
+ break;
case 'h':
usage ();
break;
@@ -350,6 +355,10 @@
break;
case 'm':
case 'p':
+ /* This will only have an effect if the target
+ * user do not have a restricted shell, or if
+ * su is called by root.
+ */
change_environment = 0;
break;
case 's':
@@ -359,6 +368,7 @@
usage ();
}
}
+end_su_options:
if (optind < argc && !strcmp (argv[optind], "-")) {
fakelogin = 1;
optind++;
@@ -473,14 +483,18 @@
#endif /* !USE_PAM */
pwent = *pw;
+ /* If su is not called by root, and the target user has a restricted
+ * shell, the environment must be changed.
+ */
+ change_environment |= (restricted_shell(pwent.pw_shell) && !amroot);
+
/*
* If a new login is being set up, the old environment will be
* ignored and a new one created later on.
* (note: in the case of a subsystem, the shell will be restricted,
* and this won't be executed on the first pass)
*/
- if (fakelogin &&
- (change_environment || restricted_shell (pwent.pw_shell))) {
+ if (fakelogin && change_environment) {
/*
* The terminal type will be left alone if it is present in
* the environment already.
@@ -566,7 +580,7 @@
/* For users with non null UID, if this user has a restricted
* shell, the shell must be the one specified in /etc/passwd
*/
- if (shellstr != NULL && getuid () && restricted_shell (pwent.pw_shell))
+ if (shellstr != NULL && !amroot && restricted_shell (pwent.pw_shell))
shellstr = NULL;
/* If the shell is not set at this time, use the shell specified
* in /etc/passwd.
@@ -739,7 +753,7 @@
exit (1);
}
- if (change_environment || restricted_shell (pwent.pw_shell)) {
+ if (change_environment) {
/* we need to setup the environment *after* pam_open_session(),
* else the UID is changed before stuff like pam_xauth could
* run, and we cannot access /etc/shadow and co
@@ -770,12 +784,15 @@
exit (1);
#endif /* !USE_PAM */
- if (change_environment || restricted_shell (pwent.pw_shell)) {
- if (fakelogin)
+ if (change_environment) {
+ /* set some environment variables */
+ if (fakelogin) {
+ pwent.pw_shell = shellstr;
setup_env (&pwent);
- else {
+ } else {
addenv ("HOME", pwent.pw_dir);
addenv ("USER", pwent.pw_name);
+ addenv ("LOGNAME", pwent.pw_name);
addenv ("SHELL", shellstr);
}
}
@@ -811,7 +828,7 @@
/* Position argv to the remaining arguments */
argv += optind;
/*
- * Use new user's shell from /etc/passwd and create an argv
+ * Use the shell and create an argv
* with the rest of the command line included.
*/
argv[-1] = shellstr;
Index: src/useradd.c
===================================================================
RCS file: /cvsroot/shadow/src/useradd.c,v
retrieving revision 1.88
diff -u -r1.88 useradd.c
--- src/useradd.c 6 Dec 2005 20:22:00 -0000 1.88
+++ src/useradd.c 13 Dec 2005 22:01:49 -0000
@@ -1400,9 +1400,9 @@
/*
- * grp_update - add new group file entries
+ * grp_add - add new group file entries
*
- * grp_update() writes the new records to the group files.
+ * grp_add() writes the new records to the group files.
*/
static void grp_add (void)
More information about the Pkg-shadow-devel
mailing list