/[packages]/cauldron/coreutils/current/SOURCES/coreutils-8.7-pam.patch
ViewVC logotype

Contents of /cauldron/coreutils/current/SOURCES/coreutils-8.7-pam.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 128 - (show annotations) (download)
Tue Jan 4 18:25:29 2011 UTC (13 years, 3 months ago) by tmb
File size: 11737 byte(s)
imported package coreutils
1 From ea2d050b1952feb99f86c98255280beb6e589d8c Mon Sep 17 00:00:00 2001
2 From: Ludwig Nussel <ludwig.nussel@suse.de>
3 Date: Tue, 17 Aug 2010 13:21:44 +0200
4 Subject: [PATCH 1/7] pam support for su
5
6 ---
7 configure.ac | 14 +++
8 src/Makefile.am | 4 +-
9 src/su.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
10 3 files changed, 278 insertions(+), 6 deletions(-)
11
12 diff --git a/configure.ac b/configure.ac
13 index b07a52b..1fb5839 100644
14 --- a/configure.ac
15 +++ b/configure.ac
16 @@ -128,6 +128,20 @@ fi
17
18 AC_FUNC_FORK
19
20 +AC_ARG_ENABLE(pam, AS_HELP_STRING([--disable-pam],
21 + [Disable PAM support in su (default=auto)]), , [enable_pam=yes])
22 +if test "x$enable_pam" != xno; then
23 + AC_CHECK_LIB([pam], [pam_start], [enable_pam=yes], [enable_pam=no])
24 + AC_CHECK_LIB([pam_misc], [misc_conv], [:], [enable_pam=no])
25 + if test "x$enable_pam" != xno; then
26 + AC_DEFINE(USE_PAM, 1, [Define if you want to use PAM])
27 + PAM_LIBS="-lpam -lpam_misc"
28 + AC_SUBST(PAM_LIBS)
29 + fi
30 +fi
31 +AC_MSG_CHECKING([whether to enable PAM support in su])
32 +AC_MSG_RESULT([$enable_pam])
33 +
34 optional_bin_progs=
35 AC_CHECK_FUNCS([chroot],
36 gl_ADD_PROG([optional_bin_progs], [chroot]))
37 diff --git a/src/Makefile.am b/src/Makefile.am
38 index db5359b..154a5ed 100644
39 --- a/src/Makefile.am
40 +++ b/src/Makefile.am
41 @@ -363,8 +363,8 @@ factor_LDADD += $(LIB_GMP)
42 # for getloadavg
43 uptime_LDADD += $(GETLOADAVG_LIBS)
44
45 -# for crypt
46 -su_LDADD += $(LIB_CRYPT)
47 +# for crypt and pam
48 +su_LDADD += $(LIB_CRYPT) $(PAM_LIBS)
49
50 # for various ACL functions
51 copy_LDADD += $(LIB_ACL)
52 diff --git a/src/su.c b/src/su.c
53 index f8f5b61..811aad7 100644
54 --- a/src/su.c
55 +++ b/src/su.c
56 @@ -37,6 +37,16 @@
57 restricts who can su to UID 0 accounts. RMS considers that to
58 be fascist.
59
60 +#ifdef USE_PAM
61 +
62 + Actually, with PAM, su has nothing to do with whether or not a
63 + wheel group is enforced by su. RMS tries to restrict your access
64 + to a su which implements the wheel group, but PAM considers that
65 + to be fascist, and gives the user/sysadmin the opportunity to
66 + enforce a wheel group by proper editing of /etc/pam.d/su
67 +
68 +#endif
69 +
70 Compile-time options:
71 -DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog.
72 -DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog.
73 @@ -52,6 +62,13 @@
74 #include <sys/types.h>
75 #include <pwd.h>
76 #include <grp.h>
77 +#ifdef USE_PAM
78 +#include <security/pam_appl.h>
79 +#include <security/pam_misc.h>
80 +#include <signal.h>
81 +#include <sys/wait.h>
82 +#include <sys/fsuid.h>
83 +#endif
84
85 #include "system.h"
86 #include "getpass.h"
87 @@ -111,7 +128,9 @@
88 /* The user to become if none is specified. */
89 #define DEFAULT_USER "root"
90
91 +#ifndef USE_PAM
92 char *crypt (char const *key, char const *salt);
93 +#endif
94
95 static void run_shell (char const *, char const *, char **, size_t)
96 ATTRIBUTE_NORETURN;
97 @@ -125,6 +144,11 @@ static bool simulate_login;
98 /* If true, change some environment vars to indicate the user su'd to. */
99 static bool change_environment;
100
101 +#ifdef USE_PAM
102 +static bool _pam_session_opened;
103 +static bool _pam_cred_established;
104 +#endif
105 +
106 static struct option const longopts[] =
107 {
108 {"command", required_argument, NULL, 'c'},
109 @@ -200,7 +224,164 @@ log_su (struct passwd const *pw, bool successful)
110 }
111 #endif
112
113 +#ifdef USE_PAM
114 +#define PAM_SERVICE_NAME PROGRAM_NAME
115 +#define PAM_SERVICE_NAME_L PROGRAM_NAME "-l"
116 +static sig_atomic_t volatile caught_signal = false;
117 +static pam_handle_t *pamh = NULL;
118 +static int retval;
119 +static struct pam_conv conv =
120 +{
121 + misc_conv,
122 + NULL
123 +};
124 +
125 +#define PAM_BAIL_P(a) \
126 + if (retval) \
127 + { \
128 + pam_end (pamh, retval); \
129 + a; \
130 + }
131 +
132 +static void
133 +cleanup_pam (int retcode)
134 +{
135 + if (_pam_session_opened)
136 + pam_close_session (pamh, 0);
137 +
138 + if (_pam_cred_established)
139 + pam_setcred (pamh, PAM_DELETE_CRED | PAM_SILENT);
140 +
141 + pam_end(pamh, retcode);
142 +}
143 +
144 +/* Signal handler for parent process. */
145 +static void
146 +su_catch_sig (int sig)
147 +{
148 + caught_signal = true;
149 +}
150 +
151 +/* Export env variables declared by PAM modules. */
152 +static void
153 +export_pamenv (void)
154 +{
155 + char **env;
156 +
157 + /* This is a copy but don't care to free as we exec later anyways. */
158 + env = pam_getenvlist (pamh);
159 + while (env && *env)
160 + {
161 + if (putenv (*env) != 0)
162 + xalloc_die ();
163 + env++;
164 + }
165 +}
166 +
167 +static void
168 +create_watching_parent (void)
169 +{
170 + pid_t child;
171 + sigset_t ourset;
172 + int status = 0;
173 +
174 + retval = pam_open_session (pamh, 0);
175 + if (retval != PAM_SUCCESS)
176 + {
177 + cleanup_pam (retval);
178 + error (EXIT_FAILURE, 0, _("cannot not open session: %s"),
179 + pam_strerror (pamh, retval));
180 + }
181 + else
182 + _pam_session_opened = 1;
183 +
184 + child = fork ();
185 + if (child == (pid_t) -1)
186 + {
187 + cleanup_pam (PAM_ABORT);
188 + error (EXIT_FAILURE, errno, _("cannot create child process"));
189 + }
190 +
191 + /* the child proceeds to run the shell */
192 + if (child == 0)
193 + return;
194 +
195 + /* In the parent watch the child. */
196 +
197 + /* su without pam support does not have a helper that keeps
198 + sitting on any directory so let's go to /. */
199 + if (chdir ("/") != 0)
200 + error (0, errno, _("warning: cannot change directory to %s"), "/");
201 +
202 + sigfillset (&ourset);
203 + if (sigprocmask (SIG_BLOCK, &ourset, NULL))
204 + {
205 + error (0, errno, _("cannot block signals"));
206 + caught_signal = true;
207 + }
208 + if (!caught_signal)
209 + {
210 + struct sigaction action;
211 + action.sa_handler = su_catch_sig;
212 + sigemptyset (&action.sa_mask);
213 + action.sa_flags = 0;
214 + sigemptyset (&ourset);
215 + if (sigaddset (&ourset, SIGTERM)
216 + || sigaddset (&ourset, SIGALRM)
217 + || sigaction (SIGTERM, &action, NULL)
218 + || sigprocmask (SIG_UNBLOCK, &ourset, NULL))
219 + {
220 + error (0, errno, _("cannot set signal handler"));
221 + caught_signal = true;
222 + }
223 + }
224 + if (!caught_signal)
225 + {
226 + pid_t pid;
227 + for (;;)
228 + {
229 + pid = waitpid (child, &status, WUNTRACED);
230 +
231 + if (pid != (pid_t)-1 && WIFSTOPPED (status))
232 + {
233 + kill (getpid (), SIGSTOP);
234 + /* once we get here, we must have resumed */
235 + kill (pid, SIGCONT);
236 + }
237 + else
238 + break;
239 + }
240 + if (pid != (pid_t)-1)
241 + if (WIFSIGNALED (status))
242 + status = WTERMSIG (status) + 128;
243 + else
244 + status = WEXITSTATUS (status);
245 + else
246 + status = 1;
247 + }
248 + else
249 + status = 1;
250 +
251 + if (caught_signal)
252 + {
253 + fprintf (stderr, _("\nSession terminated, killing shell..."));
254 + kill (child, SIGTERM);
255 + }
256 +
257 + cleanup_pam (PAM_SUCCESS);
258 +
259 + if (caught_signal)
260 + {
261 + sleep (2);
262 + kill (child, SIGKILL);
263 + fprintf (stderr, _(" ...killed.\n"));
264 + }
265 + exit (status);
266 +}
267 +#endif
268 +
269 /* Ask the user for a password.
270 + If PAM is in use, let PAM ask for the password if necessary.
271 Return true if the user gives the correct password for entry PW,
272 false if not. Return true without asking for a password if run by UID 0
273 or if PW has an empty password. */
274 @@ -208,10 +389,52 @@ log_su (struct passwd const *pw, bool successful)
275 static bool
276 correct_password (const struct passwd *pw)
277 {
278 +#ifdef USE_PAM
279 + const struct passwd *lpw;
280 + const char *cp;
281 +
282 + retval = pam_start (simulate_login ? PAM_SERVICE_NAME_L : PAM_SERVICE_NAME,
283 + pw->pw_name, &conv, &pamh);
284 + PAM_BAIL_P (return false);
285 +
286 + if (isatty (0) && (cp = ttyname (0)) != NULL)
287 + {
288 + const char *tty;
289 +
290 + if (strncmp (cp, "/dev/", 5) == 0)
291 + tty = cp + 5;
292 + else
293 + tty = cp;
294 + retval = pam_set_item (pamh, PAM_TTY, tty);
295 + PAM_BAIL_P (return false);
296 + }
297 +#if 0 /* Manpage discourages use of getlogin. */
298 + cp = getlogin ();
299 + if (!(cp && *cp && (lpw = getpwnam (cp)) != NULL && lpw->pw_uid == getuid ()))
300 +#endif
301 + lpw = getpwuid (getuid ());
302 + if (lpw && lpw->pw_name)
303 + {
304 + retval = pam_set_item (pamh, PAM_RUSER, (const void *) lpw->pw_name);
305 + PAM_BAIL_P (return false);
306 + }
307 + retval = pam_authenticate (pamh, 0);
308 + PAM_BAIL_P (return false);
309 + retval = pam_acct_mgmt (pamh, 0);
310 + if (retval == PAM_NEW_AUTHTOK_REQD)
311 + {
312 + /* Password has expired. Offer option to change it. */
313 + retval = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
314 + PAM_BAIL_P (return false);
315 + }
316 + PAM_BAIL_P (return false);
317 + /* Must be authenticated if this point was reached. */
318 + return true;
319 +#else /* !USE_PAM */
320 char *unencrypted, *encrypted, *correct;
321 #if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
322 /* Shadow passwd stuff for SVR3 and maybe other systems. */
323 - struct spwd *sp = getspnam (pw->pw_name);
324 + const struct spwd *sp = getspnam (pw->pw_name);
325
326 endspent ();
327 if (sp)
328 @@ -232,6 +455,7 @@ correct_password (const struct passwd *pw)
329 encrypted = crypt (unencrypted, correct);
330 memset (unencrypted, 0, strlen (unencrypted));
331 return STREQ (encrypted, correct);
332 +#endif /* !USE_PAM */
333 }
334
335 /* Update `environ' for the new shell based on PW, with SHELL being
336 @@ -274,19 +498,41 @@ modify_environment (const struct passwd *pw, const char *shell)
337 }
338 }
339 }
340 +
341 +#ifdef USE_PAM
342 + export_pamenv ();
343 +#endif
344 }
345
346 /* Become the user and group(s) specified by PW. */
347
348 static void
349 -change_identity (const struct passwd *pw)
350 +init_groups (const struct passwd *pw)
351 {
352 #ifdef HAVE_INITGROUPS
353 errno = 0;
354 if (initgroups (pw->pw_name, pw->pw_gid) == -1)
355 - error (EXIT_CANCELED, errno, _("cannot set groups"));
356 + {
357 +#ifdef USE_PAM
358 + cleanup_pam (PAM_ABORT);
359 +#endif
360 + error (EXIT_FAILURE, errno, _("cannot set groups"));
361 + }
362 endgrent ();
363 #endif
364 +
365 +#ifdef USE_PAM
366 + retval = pam_setcred (pamh, PAM_ESTABLISH_CRED);
367 + if (retval != PAM_SUCCESS)
368 + error (EXIT_FAILURE, 0, "%s", pam_strerror (pamh, retval));
369 + else
370 + _pam_cred_established = 1;
371 +#endif
372 +}
373 +
374 +static void
375 +change_identity (const struct passwd *pw)
376 +{
377 if (setgid (pw->pw_gid))
378 error (EXIT_CANCELED, errno, _("cannot set group id"));
379 if (setuid (pw->pw_uid))
380 @@ -500,9 +746,21 @@ main (int argc, char **argv)
381 shell = NULL;
382 }
383 shell = xstrdup (shell ? shell : pw->pw_shell);
384 - modify_environment (pw, shell);
385 +
386 + init_groups (pw);
387 +
388 +#ifdef USE_PAM
389 + create_watching_parent ();
390 + /* Now we're in the child. */
391 +#endif
392
393 change_identity (pw);
394 +
395 + /* Set environment after pam_open_session, which may put KRB5CCNAME
396 + into the pam_env, etc. */
397 +
398 + modify_environment (pw, shell);
399 +
400 if (simulate_login && chdir (pw->pw_dir) != 0)
401 error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
402
403 --
404 1.7.1
405 diff -urNp coreutils-8.7-orig/doc/coreutils.texi coreutils-8.7/doc/coreutils.texi
406 --- coreutils-8.7-orig/doc/coreutils.texi 2010-11-15 12:47:03.529922880 +0100
407 +++ coreutils-8.7/doc/coreutils.texi 2010-11-15 12:49:55.945171380 +0100
408 @@ -15180,7 +15180,9 @@ the exit status of @var{command} otherwi
409
410 @command{su} allows one user to temporarily become another user. It runs a
411 command (often an interactive shell) with the real and effective user
412 -ID, group ID, and supplemental groups of a given @var{user}. Synopsis:
413 +ID, group ID, and supplemental groups of a given @var{user}. When the -l
414 +option is given, the su-l PAM file is used instead of the default su PAM file.
415 +Synopsis:
416
417 @example
418 su [@var{option}]@dots{} [@var{user} [@var{arg}]@dots{}]
419 @@ -15259,7 +15261,8 @@ environment variables except @env{TERM},
420 (which are set, even for the super-user, as described above), and set
421 @env{PATH} to a compiled-in default value. Change to @var{user}'s home
422 directory. Prepend @samp{-} to the shell's name, intended to make it
423 -read its login startup file(s).
424 +read its login startup file(s). When this option is given, /etc/pam.d/su-l
425 +PAM file is used instead of the default one.
426
427 @item -m
428 @itemx -p

  ViewVC Help
Powered by ViewVC 1.1.30