updated on Thu Jan 19 20:01:47 UTC 2012
[aur-mirror.git] / coreutils-acp / coreutils-pam.patch
blobe61908f3f426754aa1ba1f64081f7b849dad1e6c
1 diff -urNp coreutils-8.4-orig/configure.ac coreutils-8.4/configure.ac
2 --- coreutils-8.4-orig/configure.ac 2010-01-11 18:20:42.000000000 +0100
3 +++ coreutils-8.4/configure.ac 2010-02-12 10:17:46.000000000 +0100
4 @@ -126,6 +126,13 @@ if test "$gl_gcc_warnings" = yes; then
5 AC_SUBST([GNULIB_WARN_CFLAGS])
6 fi
8 +dnl Give the chance to enable PAM
9 +AC_ARG_ENABLE(pam, dnl
10 +[ --enable-pam Enable use of the PAM libraries],
11 +[AC_DEFINE(USE_PAM, 1, [Define if you want to use PAM])
12 +LIB_PAM="-ldl -lpam -lpam_misc"
13 +AC_SUBST(LIB_PAM)])
15 AC_FUNC_FORK
17 optional_bin_progs=
18 diff -urNp coreutils-8.4-orig/doc/coreutils.texi coreutils-8.4/doc/coreutils.texi
19 --- coreutils-8.4-orig/doc/coreutils.texi 2010-01-03 18:06:20.000000000 +0100
20 +++ coreutils-8.4/doc/coreutils.texi 2010-02-12 10:17:46.000000000 +0100
21 @@ -15081,8 +15081,11 @@ to certain shells, etc.).
22 @findex syslog
23 @command{su} can optionally be compiled to use @code{syslog} to report
24 failed, and optionally successful, @command{su} attempts. (If the system
25 -supports @code{syslog}.) However, GNU @command{su} does not check if the
26 -user is a member of the @code{wheel} group; see below.
27 +supports @code{syslog}.)
29 +This version of @command{su} has support for using PAM for
30 +authentication. You can edit @file{/etc/pam.d/su} to customize its
31 +behaviour.
33 The program accepts the following options. Also see @ref{Common options}.
35 @@ -15124,6 +15127,8 @@ environment variables except @env{TERM},
36 @env{PATH} to a compiled-in default value. Change to @var{user}'s home
37 directory. Prepend @samp{-} to the shell's name, intended to make it
38 read its login startup file(s).
39 +Additionaly @env{DISPLAY} and @env{XAUTHORITY} environment variables
40 +are preserved as well for PAM functionality.
42 @item -m
43 @itemx -p
44 @@ -15163,33 +15168,6 @@ Exit status:
45 the exit status of the subshell otherwise
46 @end display
48 -@cindex wheel group, not supported
49 -@cindex group wheel, not supported
50 -@cindex fascism
51 -@subsection Why GNU @command{su} does not support the @samp{wheel} group
53 -(This section is by Richard Stallman.)
55 -@cindex Twenex
56 -@cindex MIT AI lab
57 -Sometimes a few of the users try to hold total power over all the
58 -rest. For example, in 1984, a few users at the MIT AI lab decided to
59 -seize power by changing the operator password on the Twenex system and
60 -keeping it secret from everyone else. (I was able to thwart this coup
61 -and give power back to the users by patching the kernel, but I
62 -wouldn't know how to do that in Unix.)
64 -However, occasionally the rulers do tell someone. Under the usual
65 -@command{su} mechanism, once someone learns the root password who
66 -sympathizes with the ordinary users, he or she can tell the rest. The
67 -``wheel group'' feature would make this impossible, and thus cement the
68 -power of the rulers.
70 -I'm on the side of the masses, not that of the rulers. If you are
71 -used to supporting the bosses and sysadmins in whatever they do, you
72 -might find this idea strange at first.
75 @node timeout invocation
76 @section @command{timeout}: Run a command with a time limit
78 diff -urNp coreutils-8.4-orig/src/Makefile.am coreutils-8.4/src/Makefile.am
79 --- coreutils-8.4-orig/src/Makefile.am 2010-01-03 18:06:20.000000000 +0100
80 +++ coreutils-8.4/src/Makefile.am 2010-02-12 10:17:46.000000000 +0100
81 @@ -361,7 +361,7 @@ factor_LDADD += $(LIB_GMP)
82 uptime_LDADD += $(GETLOADAVG_LIBS)
84 # for crypt
85 -su_LDADD += $(LIB_CRYPT)
86 +su_LDADD += $(LIB_CRYPT) @LIB_PAM@
88 # for various ACL functions
89 copy_LDADD += $(LIB_ACL)
90 diff -urNp coreutils-8.4-orig/src/su.c coreutils-8.4/src/su.c
91 --- coreutils-8.4-orig/src/su.c 2010-02-12 10:15:15.000000000 +0100
92 +++ coreutils-8.4/src/su.c 2010-02-12 10:24:29.000000000 +0100
93 @@ -37,6 +37,16 @@
94 restricts who can su to UID 0 accounts. RMS considers that to
95 be fascist.
97 +#ifdef USE_PAM
99 + Actually, with PAM, su has nothing to do with whether or not a
100 + wheel group is enforced by su. RMS tries to restrict your access
101 + to a su which implements the wheel group, but PAM considers that
102 + to be fascist, and gives the user/sysadmin the opportunity to
103 + enforce a wheel group by proper editing of /etc/pam.conf
105 +#endif
107 Compile-time options:
108 -DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog.
109 -DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog.
110 @@ -53,6 +63,15 @@
111 #include <pwd.h>
112 #include <grp.h>
114 +#ifdef USE_PAM
115 +# include <signal.h>
116 +# include <sys/wait.h>
117 +# include <sys/fsuid.h>
118 +# include <unistd.h>
119 +# include <security/pam_appl.h>
120 +# include <security/pam_misc.h>
121 +#endif /* USE_PAM */
123 #include "system.h"
124 #include "getpass.h"
126 @@ -120,10 +139,17 @@
127 /* The user to become if none is specified. */
128 #define DEFAULT_USER "root"
130 +#ifndef USE_PAM
131 char *crypt (char const *key, char const *salt);
132 +#endif
134 -static void run_shell (char const *, char const *, char **, size_t)
135 +static void run_shell (char const *, char const *, char **, size_t,
136 + const struct passwd *)
137 +#ifdef USE_PAM
139 +#else
140 ATTRIBUTE_NORETURN;
141 +#endif
143 /* If true, pass the `-f' option to the subshell. */
144 static bool fast_startup;
145 @@ -209,7 +235,26 @@ log_su (struct passwd const *pw, bool su
147 #endif
149 +#ifdef USE_PAM
150 +static pam_handle_t *pamh = NULL;
151 +static int retval;
152 +static struct pam_conv conv = {
153 + misc_conv,
154 + NULL
157 +#define PAM_BAIL_P if (retval) { \
158 + pam_end(pamh, PAM_SUCCESS); \
159 + return 0; \
161 +#define PAM_BAIL_P_VOID if (retval) { \
162 + pam_end(pamh, PAM_SUCCESS); \
163 +return; \
165 +#endif
167 /* Ask the user for a password.
168 + If PAM is in use, let PAM ask for the password if necessary.
169 Return true if the user gives the correct password for entry PW,
170 false if not. Return true without asking for a password if run by UID 0
171 or if PW has an empty password. */
172 @@ -217,6 +262,44 @@ log_su (struct passwd const *pw, bool su
173 static bool
174 correct_password (const struct passwd *pw)
176 +#ifdef USE_PAM
177 + struct passwd *caller;
178 + char *tty_name, *ttyn;
179 + retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh);
180 + PAM_BAIL_P;
182 + if (getuid() != 0 && !isatty(0)) {
183 + fprintf(stderr, "standard in must be a tty\n");
184 + exit(1);
187 + caller = getpwuid(getuid());
188 + if(caller != NULL && caller->pw_name != NULL) {
189 + retval = pam_set_item(pamh, PAM_RUSER, caller->pw_name);
190 + PAM_BAIL_P;
193 + ttyn = ttyname(0);
194 + if (ttyn) {
195 + if (strncmp(ttyn, "/dev/", 5) == 0)
196 + tty_name = ttyn+5;
197 + else
198 + tty_name = ttyn;
199 + retval = pam_set_item(pamh, PAM_TTY, tty_name);
200 + PAM_BAIL_P;
202 + retval = pam_authenticate(pamh, 0);
203 + PAM_BAIL_P;
204 + retval = pam_acct_mgmt(pamh, 0);
205 + if (retval == PAM_NEW_AUTHTOK_REQD) {
206 + /* password has expired. Offer option to change it. */
207 + retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
208 + PAM_BAIL_P;
210 + PAM_BAIL_P;
211 + /* must be authenticated if this point was reached */
212 + return 1;
213 +#else /* !USE_PAM */
214 char *unencrypted, *encrypted, *correct;
215 #if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
216 /* Shadow passwd stuff for SVR3 and maybe other systems. */
217 @@ -241,6 +324,7 @@ correct_password (const struct passwd *p
218 encrypted = crypt (unencrypted, correct);
219 memset (unencrypted, 0, strlen (unencrypted));
220 return STREQ (encrypted, correct);
221 +#endif /* !USE_PAM */
224 /* Update `environ' for the new shell based on PW, with SHELL being
225 @@ -254,12 +338,18 @@ modify_environment (const struct passwd
226 /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
227 Unset all other environment variables. */
228 char const *term = getenv ("TERM");
229 + char const *display = getenv ("DISPLAY");
230 + char const *xauthority = getenv ("XAUTHORITY");
231 if (term)
232 term = xstrdup (term);
233 environ = xmalloc ((6 + !!term) * sizeof (char *));
234 environ[0] = NULL;
235 if (term)
236 xsetenv ("TERM", term);
237 + if (display)
238 + xsetenv ("DISPLAY", display);
239 + if (xauthority)
240 + xsetenv ("XAUTHORITY", xauthority);
241 xsetenv ("HOME", pw->pw_dir);
242 xsetenv ("SHELL", shell);
243 xsetenv ("USER", pw->pw_name);
244 @@ -292,8 +382,13 @@ change_identity (const struct passwd *pw
246 #ifdef HAVE_INITGROUPS
247 errno = 0;
248 - if (initgroups (pw->pw_name, pw->pw_gid) == -1)
249 + if (initgroups (pw->pw_name, pw->pw_gid) == -1) {
250 +#ifdef USE_PAM
251 + pam_close_session(pamh, 0);
252 + pam_end(pamh, PAM_ABORT);
253 +#endif
254 error (EXIT_CANCELED, errno, _("cannot set groups"));
256 endgrent ();
257 #endif
258 if (setgid (pw->pw_gid))
259 @@ -302,6 +397,31 @@ change_identity (const struct passwd *pw
260 error (EXIT_CANCELED, errno, _("cannot set user id"));
263 +#ifdef USE_PAM
264 +static int caught=0;
265 +/* Signal handler for parent process later */
266 +static void su_catch_sig(int sig)
268 + ++caught;
271 +int
272 +pam_copyenv (pam_handle_t *pamh)
274 + char **env;
276 + env = pam_getenvlist(pamh);
277 + if(env) {
278 + while(*env) {
279 + if (putenv (*env))
280 + xalloc_die ();
281 + env++;
284 + return(0);
286 +#endif
288 /* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
289 If COMMAND is nonzero, pass it to the shell with the -c option.
290 Pass ADDITIONAL_ARGS to the shell as more arguments; there
291 @@ -309,17 +429,49 @@ change_identity (const struct passwd *pw
293 static void
294 run_shell (char const *shell, char const *command, char **additional_args,
295 - size_t n_additional_args)
296 + size_t n_additional_args, const struct passwd *pw)
298 size_t n_args = 1 + fast_startup + 2 * !!command + n_additional_args + 1;
299 char const **args = xnmalloc (n_args, sizeof *args);
300 size_t argno = 1;
301 +#ifdef USE_PAM
302 + int child;
303 + sigset_t ourset;
304 + int status;
306 + retval = pam_open_session(pamh,0);
307 + if (retval != PAM_SUCCESS) {
308 + fprintf (stderr, "could not open session\n");
309 + exit (1);
312 +/* do this at the last possible moment, because environment variables may
313 + be passed even in the session phase
315 + if(pam_copyenv(pamh) != PAM_SUCCESS)
316 + fprintf (stderr, "error copying PAM environment\n");
318 + /* Credentials should be set in the parent */
319 + if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) {
320 + pam_close_session(pamh, 0);
321 + fprintf(stderr, "could not set PAM credentials\n");
322 + exit(1);
325 + child = fork();
326 + if (child == 0) { /* child shell */
327 + change_identity (pw);
328 + pam_end(pamh, 0);
329 +#endif
331 if (simulate_login)
333 char *arg0;
334 char *shell_basename;
336 + if(chdir(pw->pw_dir))
337 + error(0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
339 shell_basename = last_component (shell);
340 arg0 = xmalloc (strlen (shell_basename) + 2);
341 arg0[0] = '-';
342 @@ -344,6 +496,67 @@ run_shell (char const *shell, char const
343 error (0, errno, "%s", shell);
344 exit (exit_status);
346 +#ifdef USE_PAM
347 + } else if (child == -1) {
348 + fprintf(stderr, "can not fork user shell: %s", strerror(errno));
349 + pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
350 + pam_close_session(pamh, 0);
351 + pam_end(pamh, PAM_ABORT);
352 + exit(1);
354 + /* parent only */
355 + sigfillset(&ourset);
356 + if (sigprocmask(SIG_BLOCK, &ourset, NULL)) {
357 + fprintf(stderr, "%s: signal malfunction\n", PROGRAM_NAME);
358 + caught = 1;
360 + if (!caught) {
361 + struct sigaction action;
362 + action.sa_handler = su_catch_sig;
363 + sigemptyset(&action.sa_mask);
364 + action.sa_flags = 0;
365 + sigemptyset(&ourset);
366 + if (sigaddset(&ourset, SIGTERM)
367 + || sigaddset(&ourset, SIGALRM)
368 + || sigaction(SIGTERM, &action, NULL)
369 + || sigprocmask(SIG_UNBLOCK, &ourset, NULL)) {
370 + fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME);
371 + caught = 1;
374 + if (!caught) {
375 + do {
376 + int pid;
378 + pid = waitpid(-1, &status, WUNTRACED);
380 + if (((pid_t)-1 != pid) && (0 != WIFSTOPPED (status))) {
381 + kill(getpid(), WSTOPSIG(status));
382 + /* once we get here, we must have resumed */
383 + kill(pid, SIGCONT);
385 + } while (0 != WIFSTOPPED(status));
388 + if (caught) {
389 + fprintf(stderr, "\nSession terminated, killing shell...");
390 + kill (child, SIGTERM);
392 + /* Not checking retval on this because we need to call close session */
393 + pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
394 + retval = pam_close_session(pamh, 0);
395 + PAM_BAIL_P_VOID;
396 + retval = pam_end(pamh, PAM_SUCCESS);
397 + PAM_BAIL_P_VOID;
398 + if (caught) {
399 + sleep(2);
400 + kill(child, SIGKILL);
401 + fprintf(stderr, " ...killed.\n");
402 + exit(-1);
404 + exit ((0 != WIFEXITED (status)) ? WEXITSTATUS (status)
405 + : WTERMSIG (status) + 128);
406 +#endif /* USE_PAM */
409 /* Return true if SHELL is a restricted shell (one not returned by
410 @@ -511,9 +724,9 @@ main (int argc, char **argv)
411 shell = xstrdup (shell ? shell : pw->pw_shell);
412 modify_environment (pw, shell);
414 +#ifndef USE_PAM
415 change_identity (pw);
416 - if (simulate_login && chdir (pw->pw_dir) != 0)
417 - error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
418 +#endif
420 /* error() flushes stderr, but does not check for write failure.
421 Normally, we would catch this via our atexit() hook of
422 @@ -523,5 +736,5 @@ main (int argc, char **argv)
423 if (ferror (stderr))
424 exit (EXIT_CANCELED);
426 - run_shell (shell, command, argv + optind, MAX (0, argc - optind));
427 + run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw);