Tizen 2.0 Release
[external/tizen-coreutils.git] / packaging / coreutils-pam.patch
1 Enable PAM support
2
3 Based on Fedora's patch, modified for MeeGo by Yan Li
4
5 Sign-off-by: Yan Li <yan.i.li@intel.com>
6 ---
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
10 @@ -41,6 +41,13 @@
11  
12  AC_FUNC_FORK
13  
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"
19 +AC_SUBST(LIB_PAM)])
20 +
21  AC_CHECK_FUNCS(uname,
22         OPTIONAL_BIN_PROGS="$OPTIONAL_BIN_PROGS uname\$(EXEEXT)"
23         MAN="$MAN uname.1")
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 @@
28  @findex syslog
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}.)
34 +
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
37 +behaviour.
38  
39  The program accepts the following options.  Also see @ref{Common options}.
40  
41 @@ -13593,33 +13596,6 @@
42  the exit status of the subshell otherwise
43  @end display
44  
45 -@cindex wheel group, not supported
46 -@cindex group wheel, not supported
47 -@cindex fascism
48 -@subsection Why GNU @command{su} does not support the @samp{wheel} group
49 -
50 -(This section is by Richard Stallman.)
51 -
52 -@cindex Twenex
53 -@cindex MIT AI lab
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.)
60 -
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
65 -power of the rulers.
66 -
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.
70 -
71 -
72  @node Process control
73  @chapter Process control
74  
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
78 @@ -102,7 +102,7 @@
79  # If necessary, add -lm to resolve use of pow in lib/strtod.c.
80  uptime_LDADD = $(LDADD) $(POW_LIB) $(GETLOADAVG_LIBS)
81  
82 -su_LDADD = $(LDADD) $(LIB_CRYPT)
83 +su_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@
84  
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
90 @@ -1070,7 +1070,7 @@
91  
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
96  SUFFIXES = .sh
97  
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
102 @@ -38,6 +38,16 @@
103     restricts who can su to UID 0 accounts.  RMS considers that to
104     be fascist.
105  
106 +#ifdef USE_PAM
107 +
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
113 +
114 +#endif
115 +
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.
119 @@ -59,6 +69,15 @@
120     prototype (returning `int') in <unistd.h>.  */
121  #define getusershell _getusershell_sys_proto_
122  
123 +#ifdef USE_PAM
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 */
131 +
132  #include "system.h"
133  #include "getpass.h"
134  
135 @@ -119,15 +138,22 @@
136  /* The user to become if none is specified.  */
137  #define DEFAULT_USER "root"
138  
139 +#ifndef USE_PAM
140  char *crypt ();
141 +#endif
142  char *getusershell ();
143  void endusershell ();
144  void setusershell ();
145  
146  extern char **environ;
147  
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 *)
151 +#ifdef USE_PAM
152 +       ;
153 +#else
154       ATTRIBUTE_NORETURN;
155 +#endif
156  
157  /* The name this program was run with.  */
158  char *program_name;
159 @@ -216,7 +242,26 @@
160  }
161  #endif
162  
163 +#ifdef USE_PAM
164 +static pam_handle_t *pamh = NULL;
165 +static int retval;
166 +static struct pam_conv conv = {
167 +  misc_conv,
168 +  NULL
169 +};
170 +
171 +#define PAM_BAIL_P if (retval) { \
172 +  pam_end(pamh, PAM_SUCCESS); \
173 +  return 0; \
174 +}
175 +#define PAM_BAIL_P_VOID if (retval) {          \
176 +  pam_end(pamh, PAM_SUCCESS);                  \
177 +return;                                                \
178 +}
179 +#endif
180 +
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.  */
186 @@ -224,6 +269,44 @@
187  static bool
188  correct_password (const struct passwd *pw)
189  {
190 +#ifdef USE_PAM
191 +  struct passwd *caller;
192 +  char *tty_name, *ttyn;
193 +  retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh);
194 +  PAM_BAIL_P;
195 +
196 +  if (getuid() != 0 && !isatty(0)) {
197 +       fprintf(stderr, "standard in must be a tty\n");
198 +       exit(1);
199 +  }
200 +
201 +  caller = getpwuid(getuid());
202 +  if(caller != NULL && caller->pw_name != NULL) {
203 +         retval = pam_set_item(pamh, PAM_RUSER, caller->pw_name);
204 +         PAM_BAIL_P;
205 +  }
206 +
207 +  ttyn = ttyname(0);
208 +  if (ttyn) {
209 +    if (strncmp(ttyn, "/dev/", 5) == 0)
210 +       tty_name = ttyn+5;
211 +    else
212 +       tty_name = ttyn;
213 +    retval = pam_set_item(pamh, PAM_TTY, tty_name);
214 +    PAM_BAIL_P;
215 +  }
216 +  retval = pam_authenticate(pamh, 0);
217 +  PAM_BAIL_P;
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);
222 +    PAM_BAIL_P;
223 +  }
224 +  PAM_BAIL_P;
225 +  /* must be authenticated if this point was reached */
226 +  return 1;
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.  */
231 @@ -248,6 +331,7 @@
232    encrypted = crypt (unencrypted, correct);
233    memset (unencrypted, 0, strlen (unencrypted));
234    return STREQ (encrypted, correct);
235 +#endif /* !USE_PAM */
236  }
237  
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");
245        if (term)
246         term = xstrdup (term);
247        environ = xmalloc ((6 + !!term) * sizeof (char *));
248        environ[0] = NULL;
249        if (term)
250         xsetenv ("TERM", term);
251 +      if (display)
252 +       xsetenv ("DISPLAY", display);
253 +      if (xauthority)
254 +       xsetenv ("XAUTHORITY", xauthority);
255        xsetenv ("HOME", pw->pw_dir);
256        xsetenv ("SHELL", shell);
257        xsetenv ("USER", pw->pw_name);
258 @@ -299,8 +389,13 @@
259  {
260  #ifdef HAVE_INITGROUPS
261    errno = 0;
262 -  if (initgroups (pw->pw_name, pw->pw_gid) == -1)
263 +  if (initgroups (pw->pw_name, pw->pw_gid) == -1) {
264 +#ifdef USE_PAM
265 +    pam_close_session(pamh, 0);
266 +    pam_end(pamh, PAM_ABORT);
267 +#endif
268      error (EXIT_FAIL, errno, _("cannot set groups"));
269 +  }
270    endgrent ();
271  #endif
272    if (setgid (pw->pw_gid))
273 @@ -309,6 +404,31 @@
274      error (EXIT_FAIL, errno, _("cannot set user id"));
275  }
276  
277 +#ifdef USE_PAM
278 +static int caught=0;
279 +/* Signal handler for parent process later */
280 +static void su_catch_sig(int sig)
281 +{
282 +  ++caught;
283 +}
284 +
285 +int
286 +pam_copyenv (pam_handle_t *pamh)
287 +{
288 +  char **env;
289 +
290 +  env = pam_getenvlist(pamh);
291 +  if(env) {
292 +    while(*env) {
293 +       if (putenv (*env))
294 +         xalloc_die ();
295 +       env++;
296 +    }
297 +  }
298 +  return(0);
299 +}
300 +#endif
301 +
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 @@
306  
307  static void
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)
311  {
312    size_t n_args = 1 + fast_startup + 2 * !!command + n_additional_args + 1;
313    char const **args = xnmalloc (n_args, sizeof *args);
314    size_t argno = 1;
315 +#ifdef USE_PAM
316 +  int child;
317 +  sigset_t ourset;
318 +  int status;
319 +
320 +  retval = pam_open_session(pamh,0);
321 +  if (retval != PAM_SUCCESS) {
322 +    fprintf (stderr, "could not open session\n");
323 +    exit (1);
324 +  }
325 +
326 +/* do this at the last possible moment, because environment variables may
327 +   be passed even in the session phase
328 +*/
329 +  if(pam_copyenv(pamh) != PAM_SUCCESS)
330 +     fprintf (stderr, "error copying PAM environment\n");
331 +  
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");
336 +    exit(1);
337 +  }
338 +
339 +  child = fork();
340 +  if (child == 0) {  /* child shell */
341 +  change_identity (pw);
342 +  pam_end(pamh, 0);
343 +#endif
344  
345    if (simulate_login)
346      {
347        char *arg0;
348        char *shell_basename;
349  
350 +      if(chdir(pw->pw_dir))
351 +             error(0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
352 +
353        shell_basename = last_component (shell);
354        arg0 = xmalloc (strlen (shell_basename) + 2);
355        arg0[0] = '-';
356 @@ -351,6 +503,66 @@
357      error (0, errno, "%s", shell);
358      exit (exit_status);
359    }
360 +#ifdef USE_PAM
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);
366 +      exit(1);
367 +  }
368 +  /* parent only */
369 +  sigfillset(&ourset);
370 +  if (sigprocmask(SIG_BLOCK, &ourset, NULL)) {
371 +    fprintf(stderr, "%s: signal malfunction\n", PROGRAM_NAME);
372 +    caught = 1;
373 +  }
374 +  if (!caught) {
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);
385 +      caught = 1;
386 +    }
387 +  }
388 +  if (!caught) {
389 +    do {
390 +      int pid;
391 +
392 +      pid = waitpid(-1, &status, WUNTRACED);
393 +
394 +      if (WIFSTOPPED(status)) {
395 +          kill(getpid(), SIGSTOP);
396 +          /* once we get here, we must have resumed */
397 +          kill(pid, SIGCONT);
398 +      }
399 +    } while (WIFSTOPPED(status));
400 +  }
401 +
402 +  if (caught) {
403 +    fprintf(stderr, "\nSession terminated, killing shell...");
404 +    kill (child, SIGTERM);
405 +  }
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);
409 +  PAM_BAIL_P_VOID;
410 +  retval = pam_end(pamh, PAM_SUCCESS);
411 +  PAM_BAIL_P_VOID;
412 +  if (caught) {
413 +    sleep(2);
414 +    kill(child, SIGKILL);
415 +    fprintf(stderr, " ...killed.\n");
416 +    exit(-1);
417 +  }
418 +  exit (WEXITSTATUS(status));
419 +#endif /* USE_PAM */
420  }
421  
422  /* Return true if SHELL is a restricted shell (one not returned by
423 @@ -518,9 +730,9 @@
424    shell = xstrdup (shell ? shell : pw->pw_shell);
425    modify_environment (pw, shell);
426  
427 +#ifndef USE_PAM
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);
431 +#endif
432  
433 -  run_shell (shell, command, argv + optind, MAX (0, argc - optind));
434 +  run_shell (shell, command, argv + optind, MAX (0, argc - optind), pw);
435  }