3 Based on Fedora's patch, modified for MeeGo by Yan Li
5 Sign-off-by: Yan Li <yan.i.li@intel.com>
7 diff -Nur coreutils-6.9.orig/configure.ac coreutils-6.9/configure.ac
8 --- coreutils-6.9.orig/configure.ac 2007-03-23 05:19:37.000000000 +0800
9 +++ coreutils-6.9/configure.ac 2010-07-03 17:37:43.000000000 +0800
14 +dnl Give the chance to enable PAM
15 +AC_ARG_ENABLE(pam, dnl
16 +[ --enable-pam Enable use of the PAM libraries],
17 +[AC_DEFINE(USE_PAM, 1, [Define if you want to use PAM])
18 +LIB_PAM="-ldl -lpam -lpam_misc"
22 OPTIONAL_BIN_PROGS="$OPTIONAL_BIN_PROGS uname\$(EXEEXT)"
24 diff -Nur coreutils-6.9.orig/doc/coreutils.texi coreutils-6.9/doc/coreutils.texi
25 --- coreutils-6.9.orig/doc/coreutils.texi 2007-03-23 04:45:46.000000000 +0800
26 +++ coreutils-6.9/doc/coreutils.texi 2010-07-03 17:37:43.000000000 +0800
27 @@ -13511,8 +13511,11 @@
29 @command{su} can optionally be compiled to use @code{syslog} to report
30 failed, and optionally successful, @command{su} attempts. (If the system
31 -supports @code{syslog}.) However, GNU @command{su} does not check if the
32 -user is a member of the @code{wheel} group; see below.
33 +supports @code{syslog}.)
35 +This version of @command{su} has support for using PAM for
36 +authentication. You can edit @file{/etc/pam.d/su} to customize its
39 The program accepts the following options. Also see @ref{Common options}.
41 @@ -13593,33 +13596,6 @@
42 the exit status of the subshell otherwise
45 -@cindex wheel group, not supported
46 -@cindex group wheel, not supported
48 -@subsection Why GNU @command{su} does not support the @samp{wheel} group
50 -(This section is by Richard Stallman.)
54 -Sometimes a few of the users try to hold total power over all the
55 -rest. For example, in 1984, a few users at the MIT AI lab decided to
56 -seize power by changing the operator password on the Twenex system and
57 -keeping it secret from everyone else. (I was able to thwart this coup
58 -and give power back to the users by patching the kernel, but I
59 -wouldn't know how to do that in Unix.)
61 -However, occasionally the rulers do tell someone. Under the usual
62 -@command{su} mechanism, once someone learns the root password who
63 -sympathizes with the ordinary users, he or she can tell the rest. The
64 -``wheel group'' feature would make this impossible, and thus cement the
67 -I'm on the side of the masses, not that of the rulers. If you are
68 -used to supporting the bosses and sysadmins in whatever they do, you
69 -might find this idea strange at first.
73 @chapter Process control
75 diff -Nur coreutils-6.9.orig/src/Makefile.am coreutils-6.9/src/Makefile.am
76 --- coreutils-6.9.orig/src/Makefile.am 2007-03-20 15:24:27.000000000 +0800
77 +++ coreutils-6.9/src/Makefile.am 2010-07-03 17:37:43.000000000 +0800
79 # If necessary, add -lm to resolve use of pow in lib/strtod.c.
80 uptime_LDADD = $(LDADD) $(POW_LIB) $(GETLOADAVG_LIBS)
82 -su_LDADD = $(LDADD) $(LIB_CRYPT)
83 +su_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@
85 dir_LDADD += $(LIB_ACL_TRIVIAL) $(LIB_ACL)
86 ls_LDADD += $(LIB_ACL_TRIVIAL) $(LIB_ACL)
87 diff -Nur coreutils-6.9.orig/src/Makefile.in coreutils-6.9/src/Makefile.in
88 --- coreutils-6.9.orig/src/Makefile.in 2007-03-23 05:23:20.000000000 +0800
89 +++ coreutils-6.9/src/Makefile.in 2010-07-03 17:39:10.000000000 +0800
92 # If necessary, add -lm to resolve use of pow in lib/strtod.c.
93 uptime_LDADD = $(LDADD) $(POW_LIB) $(GETLOADAVG_LIBS)
94 -su_LDADD = $(LDADD) $(LIB_CRYPT)
95 +su_LDADD = $(LDADD) $(LIB_CRYPT) -ldl -lpam -lpam_misc
98 # Get the release year from ../lib/version-etc.c.
99 diff -Nur coreutils-6.9.orig/src/su.c coreutils-6.9/src/su.c
100 --- coreutils-6.9.orig/src/su.c 2007-03-19 05:36:43.000000000 +0800
101 +++ coreutils-6.9/src/su.c 2010-07-03 17:37:43.000000000 +0800
103 restricts who can su to UID 0 accounts. RMS considers that to
108 + Actually, with PAM, su has nothing to do with whether or not a
109 + wheel group is enforced by su. RMS tries to restrict your access
110 + to a su which implements the wheel group, but PAM considers that
111 + to be fascist, and gives the user/sysadmin the opportunity to
112 + enforce a wheel group by proper editing of /etc/pam.conf
116 Compile-time options:
117 -DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog.
118 -DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog.
120 prototype (returning `int') in <unistd.h>. */
121 #define getusershell _getusershell_sys_proto_
124 +# include <signal.h>
125 +# include <sys/wait.h>
126 +# include <sys/fsuid.h>
127 +# include <unistd.h>
128 +# include <security/pam_appl.h>
129 +# include <security/pam_misc.h>
130 +#endif /* USE_PAM */
135 @@ -119,15 +138,22 @@
136 /* The user to become if none is specified. */
137 #define DEFAULT_USER "root"
142 char *getusershell ();
143 void endusershell ();
144 void setusershell ();
146 extern char **environ;
148 -static void run_shell (char const *, char const *, char **, size_t)
149 +static void run_shell (char const *, char const *, char **, size_t,
150 + const struct passwd *)
157 /* The name this program was run with. */
164 +static pam_handle_t *pamh = NULL;
166 +static struct pam_conv conv = {
171 +#define PAM_BAIL_P if (retval) { \
172 + pam_end(pamh, PAM_SUCCESS); \
175 +#define PAM_BAIL_P_VOID if (retval) { \
176 + pam_end(pamh, PAM_SUCCESS); \
181 /* Ask the user for a password.
182 + If PAM is in use, let PAM ask for the password if necessary.
183 Return true if the user gives the correct password for entry PW,
184 false if not. Return true without asking for a password if run by UID 0
185 or if PW has an empty password. */
188 correct_password (const struct passwd *pw)
191 + struct passwd *caller;
192 + char *tty_name, *ttyn;
193 + retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh);
196 + if (getuid() != 0 && !isatty(0)) {
197 + fprintf(stderr, "standard in must be a tty\n");
201 + caller = getpwuid(getuid());
202 + if(caller != NULL && caller->pw_name != NULL) {
203 + retval = pam_set_item(pamh, PAM_RUSER, caller->pw_name);
209 + if (strncmp(ttyn, "/dev/", 5) == 0)
213 + retval = pam_set_item(pamh, PAM_TTY, tty_name);
216 + retval = pam_authenticate(pamh, 0);
218 + retval = pam_acct_mgmt(pamh, 0);
219 + if (retval == PAM_NEW_AUTHTOK_REQD) {
220 + /* password has expired. Offer option to change it. */
221 + retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
225 + /* must be authenticated if this point was reached */
227 +#else /* !USE_PAM */
228 char *unencrypted, *encrypted, *correct;
229 #if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
230 /* Shadow passwd stuff for SVR3 and maybe other systems. */
232 encrypted = crypt (unencrypted, correct);
233 memset (unencrypted, 0, strlen (unencrypted));
234 return STREQ (encrypted, correct);
235 +#endif /* !USE_PAM */
238 /* Update `environ' for the new shell based on PW, with SHELL being
239 @@ -261,12 +345,18 @@
240 /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
241 Unset all other environment variables. */
242 char const *term = getenv ("TERM");
243 + char const *display = getenv ("DISPLAY");
244 + char const *xauthority = getenv ("XAUTHORITY");
246 term = xstrdup (term);
247 environ = xmalloc ((6 + !!term) * sizeof (char *));
250 xsetenv ("TERM", term);
252 + xsetenv ("DISPLAY", display);
254 + xsetenv ("XAUTHORITY", xauthority);
255 xsetenv ("HOME", pw->pw_dir);
256 xsetenv ("SHELL", shell);
257 xsetenv ("USER", pw->pw_name);
260 #ifdef HAVE_INITGROUPS
262 - if (initgroups (pw->pw_name, pw->pw_gid) == -1)
263 + if (initgroups (pw->pw_name, pw->pw_gid) == -1) {
265 + pam_close_session(pamh, 0);
266 + pam_end(pamh, PAM_ABORT);
268 error (EXIT_FAIL, errno, _("cannot set groups"));
272 if (setgid (pw->pw_gid))
274 error (EXIT_FAIL, errno, _("cannot set user id"));
278 +static int caught=0;
279 +/* Signal handler for parent process later */
280 +static void su_catch_sig(int sig)
286 +pam_copyenv (pam_handle_t *pamh)
290 + env = pam_getenvlist(pamh);
302 /* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
303 If COMMAND is nonzero, pass it to the shell with the -c option.
304 Pass ADDITIONAL_ARGS to the shell as more arguments; there
305 @@ -316,17 +436,49 @@
308 run_shell (char const *shell, char const *command, char **additional_args,
309 - size_t n_additional_args)
310 + size_t n_additional_args, const struct passwd *pw)
312 size_t n_args = 1 + fast_startup + 2 * !!command + n_additional_args + 1;
313 char const **args = xnmalloc (n_args, sizeof *args);
320 + retval = pam_open_session(pamh,0);
321 + if (retval != PAM_SUCCESS) {
322 + fprintf (stderr, "could not open session\n");
326 +/* do this at the last possible moment, because environment variables may
327 + be passed even in the session phase
329 + if(pam_copyenv(pamh) != PAM_SUCCESS)
330 + fprintf (stderr, "error copying PAM environment\n");
332 + /* Credentials should be set in the parent */
333 + if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) {
334 + pam_close_session(pamh, 0);
335 + fprintf(stderr, "could not set PAM credentials\n");
340 + if (child == 0) { /* child shell */
341 + change_identity (pw);
348 char *shell_basename;
350 + if(chdir(pw->pw_dir))
351 + error(0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
353 shell_basename = last_component (shell);
354 arg0 = xmalloc (strlen (shell_basename) + 2);
357 error (0, errno, "%s", shell);
361 + } else if (child == -1) {
362 + fprintf(stderr, "can not fork user shell: %s", strerror(errno));
363 + pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
364 + pam_close_session(pamh, 0);
365 + pam_end(pamh, PAM_ABORT);
369 + sigfillset(&ourset);
370 + if (sigprocmask(SIG_BLOCK, &ourset, NULL)) {
371 + fprintf(stderr, "%s: signal malfunction\n", PROGRAM_NAME);
375 + struct sigaction action;
376 + action.sa_handler = su_catch_sig;
377 + sigemptyset(&action.sa_mask);
378 + action.sa_flags = 0;
379 + sigemptyset(&ourset);
380 + if (sigaddset(&ourset, SIGTERM)
381 + || sigaddset(&ourset, SIGALRM)
382 + || sigaction(SIGTERM, &action, NULL)
383 + || sigprocmask(SIG_UNBLOCK, &ourset, NULL)) {
384 + fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME);
392 + pid = waitpid(-1, &status, WUNTRACED);
394 + if (WIFSTOPPED(status)) {
395 + kill(getpid(), SIGSTOP);
396 + /* once we get here, we must have resumed */
397 + kill(pid, SIGCONT);
399 + } while (WIFSTOPPED(status));
403 + fprintf(stderr, "\nSession terminated, killing shell...");
404 + kill (child, SIGTERM);
406 + /* Not checking retval on this because we need to call close session */
407 + pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
408 + retval = pam_close_session(pamh, 0);
410 + retval = pam_end(pamh, PAM_SUCCESS);
414 + kill(child, SIGKILL);
415 + fprintf(stderr, " ...killed.\n");
418 + exit (WEXITSTATUS(status));
419 +#endif /* USE_PAM */
422 /* Return true if SHELL is a restricted shell (one not returned by
424 shell = xstrdup (shell ? shell : pw->pw_shell);
425 modify_environment (pw, shell);
428 change_identity (pw);
429 - if (simulate_login && chdir (pw->pw_dir) != 0)
430 - error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
433 - run_shell (shell, command, argv + optind, MAX (0, argc - optind));
434 + run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw);