View | Details | Raw Unified | Return to bug 57238
Collapse All | Expand All

(-)coreutils-5.2.0/src/Makefile.am.pam (-1 / +1 lines)
Lines 66-72 Link Here
66
66
67
uptime_LDADD = $(LDADD) $(GETLOADAVG_LIBS)
67
uptime_LDADD = $(LDADD) $(GETLOADAVG_LIBS)
68
68
69
su_LDADD = $(LDADD) $(LIB_CRYPT)
69
su_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@
70
70
71
$(PROGRAMS): ../lib/libfetish.a
71
$(PROGRAMS): ../lib/libfetish.a
72
72
(-)coreutils-5.2.0/src/su.c (-6 / +192 lines)
Lines 38-43 Link Here
38
   restricts who can su to UID 0 accounts.  RMS considers that to
38
   restricts who can su to UID 0 accounts.  RMS considers that to
39
   be fascist.
39
   be fascist.
40
40
41
#ifdef USE_PAM
42
43
   Actually, with PAM, su has nothing to do with whether or not a
44
   wheel group is enforced by su.  RMS tries to restrict your access
45
   to a su which implements the wheel group, but PAM considers that
46
   to be fascist, and gives the user/sysadmin the opportunity to
47
   enforce a wheel group by proper editing of /etc/pam.conf
48
49
#endif
50
41
   Options:
51
   Options:
42
   -, -l, --login	Make the subshell a login shell.
52
   -, -l, --login	Make the subshell a login shell.
43
			Unset all environment variables except
53
			Unset all environment variables except
Lines 81-86 Link Here
81
   prototype (returning `int') in <unistd.h>.  */
91
   prototype (returning `int') in <unistd.h>.  */
82
#define getusershell _getusershell_sys_proto_
92
#define getusershell _getusershell_sys_proto_
83
93
94
#ifdef USE_PAM
95
# include <security/pam_appl.h>
96
# include <security/pam_misc.h>
97
# include <signal.h>
98
# include <sys/wait.h>
99
# include <sys/fsuid.h>
100
#endif /* USE_PAM */
101
84
#include "system.h"
102
#include "system.h"
85
#include "dirname.h"
103
#include "dirname.h"
86
104
Lines 150-156 Link Here
150
/* The user to become if none is specified.  */
168
/* The user to become if none is specified.  */
151
#define DEFAULT_USER "root"
169
#define DEFAULT_USER "root"
152
170
171
#ifndef USE_PAM
153
char *crypt ();
172
char *crypt ();
173
#endif
154
char *getpass ();
174
char *getpass ();
155
char *getusershell ();
175
char *getusershell ();
156
void endusershell ();
176
void endusershell ();
Lines 158-165 Link Here
158
178
159
extern char **environ;
179
extern char **environ;
160
180
161
static void run_shell (const char *, const char *, char **)
181
static void run_shell (const char *, const char *, char **, const struct passwd *)
182
#ifdef USE_PAM
183
     ;
184
#else
162
     ATTRIBUTE_NORETURN;
185
     ATTRIBUTE_NORETURN;
186
#endif
163
187
164
/* The name this program was run with.  */
188
/* The name this program was run with.  */
165
char *program_name;
189
char *program_name;
Lines 271-277 Link Here
271
}
295
}
272
#endif
296
#endif
273
297
298
#ifdef USE_PAM
299
static pam_handle_t *pamh = NULL;
300
static int retval;
301
static struct pam_conv conv = {
302
  misc_conv,
303
  NULL
304
};
305
306
#define PAM_BAIL_P if (retval) { \
307
  pam_end(pamh, PAM_SUCCESS); \
308
  return 0; \
309
}
310
#endif
311
274
/* Ask the user for a password.
312
/* Ask the user for a password.
313
   If PAM is in use, let PAM ask for the password if necessary.
275
   Return 1 if the user gives the correct password for entry PW,
314
   Return 1 if the user gives the correct password for entry PW,
276
   0 if not.  Return 1 without asking for a password if run by UID 0
315
   0 if not.  Return 1 without asking for a password if run by UID 0
277
   or if PW has an empty password.  */
316
   or if PW has an empty password.  */
Lines 279-284 Link Here
279
static int
318
static int
280
correct_password (const struct passwd *pw)
319
correct_password (const struct passwd *pw)
281
{
320
{
321
#ifdef USE_PAM
322
  struct passwd *caller;
323
  retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh);
324
  PAM_BAIL_P;
325
326
  if (getuid() != 0 && !isatty(0)) {
327
	fprintf(stderr, "standard in must be a tty\n");
328
	exit(1);
329
  }
330
331
  caller = getpwuid(getuid());
332
  if(caller != NULL && caller->pw_name != NULL) {
333
	  retval = pam_set_item(pamh, PAM_RUSER, caller->pw_name);
334
	  PAM_BAIL_P;
335
  }
336
337
  retval = pam_authenticate(pamh, 0);
338
  PAM_BAIL_P;
339
  retval = pam_acct_mgmt(pamh, 0);
340
  if (retval == PAM_NEW_AUTHTOK_REQD) {
341
    /* password has expired.  Offer option to change it. */
342
    retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
343
    PAM_BAIL_P;
344
  }
345
  PAM_BAIL_P;
346
  /* must be authenticated if this point was reached */
347
  return 1;
348
#else /* !USE_PAM */
282
  char *unencrypted, *encrypted, *correct;
349
  char *unencrypted, *encrypted, *correct;
283
#if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
350
#if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
284
  /* Shadow passwd stuff for SVR3 and maybe other systems.  */
351
  /* Shadow passwd stuff for SVR3 and maybe other systems.  */
Lines 303-308 Link Here
303
  encrypted = crypt (unencrypted, correct);
370
  encrypted = crypt (unencrypted, correct);
304
  memset (unencrypted, 0, strlen (unencrypted));
371
  memset (unencrypted, 0, strlen (unencrypted));
305
  return strcmp (encrypted, correct) == 0;
372
  return strcmp (encrypted, correct) == 0;
373
#endif /* !USE_PAM */
306
}
374
}
307
375
308
/* Update `environ' for the new shell based on PW, with SHELL being
376
/* Update `environ' for the new shell based on PW, with SHELL being
Lines 312-327 Link Here
312
modify_environment (const struct passwd *pw, const char *shell)
380
modify_environment (const struct passwd *pw, const char *shell)
313
{
381
{
314
  char *term;
382
  char *term;
383
  char *display;
384
  char *xauthority;
315
385
316
  if (simulate_login)
386
  if (simulate_login)
317
    {
387
    {
318
      /* Leave TERM unchanged.  Set HOME, SHELL, USER, LOGNAME, PATH.
388
      /* Leave TERM, DISPLAY, XAUTHORITY unchanged.  Set HOME, SHELL, USER, LOGNAME, PATH.
319
         Unset all other environment variables.  */
389
         Unset all other environment variables.  */
320
      term = getenv ("TERM");
390
      term = getenv ("TERM");
391
      display = getenv ("DISPLAY");
392
      xauthority = getenv ("XAUTHORITY");
321
      environ = xmalloc (2 * sizeof (char *));
393
      environ = xmalloc (2 * sizeof (char *));
322
      environ[0] = 0;
394
      environ[0] = 0;
323
      if (term)
395
      if (term)
324
	xputenv (concat ("TERM", "=", term));
396
	xputenv (concat ("TERM", "=", term));
397
      if (display)
398
	xputenv (concat ("DISPLAY", "=", display));
399
      if (xauthority)
400
	xputenv (concat ("XAUTHORITY", "=", xauthority));
325
      xputenv (concat ("HOME", "=", pw->pw_dir));
401
      xputenv (concat ("HOME", "=", pw->pw_dir));
326
      xputenv (concat ("SHELL", "=", shell));
402
      xputenv (concat ("SHELL", "=", shell));
327
      xputenv (concat ("USER", "=", pw->pw_name));
403
      xputenv (concat ("USER", "=", pw->pw_name));
Lines 358-379 Link Here
358
    error (EXIT_FAIL, errno, _("cannot set groups"));
434
    error (EXIT_FAIL, errno, _("cannot set groups"));
359
  endgrent ();
435
  endgrent ();
360
#endif
436
#endif
437
#ifdef USE_PAM
438
  retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
439
  if (retval != PAM_SUCCESS)
440
    error (1, 0, pam_strerror(pamh, retval));
441
#endif /* USE_PAM */
361
  if (setgid (pw->pw_gid))
442
  if (setgid (pw->pw_gid))
362
    error (EXIT_FAIL, errno, _("cannot set group id"));
443
    error (EXIT_FAIL, errno, _("cannot set group id"));
363
  if (setuid (pw->pw_uid))
444
  if (setuid (pw->pw_uid))
364
    error (EXIT_FAIL, errno, _("cannot set user id"));
445
    error (EXIT_FAIL, errno, _("cannot set user id"));
365
}
446
}
366
447
448
#ifdef USE_PAM
449
static int caught=0;
450
/* Signal handler for parent process later */
451
static void su_catch_sig(int sig)
452
{
453
  ++caught;
454
}
455
456
int
457
pam_copyenv (pam_handle_t *pamh)
458
{
459
  char **env;
460
461
  env = pam_getenvlist(pamh);
462
  if(env) {
463
    while(*env) {
464
	xputenv(*env);
465
	env++;
466
    }
467
  }
468
  return(0);
469
}
470
#endif
471
367
/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
472
/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
368
   If COMMAND is nonzero, pass it to the shell with the -c option.
473
   If COMMAND is nonzero, pass it to the shell with the -c option.
369
   If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
474
   If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
370
   arguments.  */
475
   arguments.  */
371
476
372
static void
477
static void
373
run_shell (const char *shell, const char *command, char **additional_args)
478
run_shell (const char *shell, const char *command, char **additional_args, const struct passwd *pw)
374
{
479
{
375
  const char **args;
480
  const char **args;
376
  int argno = 1;
481
  int argno = 1;
482
#ifdef USE_PAM
483
  int child;
484
  sigset_t ourset;
485
  int status;
486
487
  retval = pam_open_session(pamh,0);
488
  if (retval != PAM_SUCCESS) {
489
    fprintf (stderr, "could not open session\n");
490
    exit (1);
491
  }
492
493
/* do this at the last possible moment, because environment variables may
494
   be passed even in the session phase
495
*/
496
  if(pam_copyenv(pamh) != PAM_SUCCESS)
497
     fprintf (stderr, "error copying PAM environment\n");
498
  
499
  child = fork();
500
  if (child == 0) {  /* child shell */
501
  change_identity (pw);
502
  pam_end(pamh, 0);
503
#endif
377
504
378
  if (additional_args)
505
  if (additional_args)
379
    args = xmalloc (sizeof (char *)
506
    args = xmalloc (sizeof (char *)
Lines 385-390 Link Here
385
      char *arg0;
512
      char *arg0;
386
      char *shell_basename;
513
      char *shell_basename;
387
514
515
      if(chdir(pw->pw_dir))
516
	      error(0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
517
388
      shell_basename = base_name (shell);
518
      shell_basename = base_name (shell);
389
      arg0 = xmalloc (strlen (shell_basename) + 2);
519
      arg0 = xmalloc (strlen (shell_basename) + 2);
390
      arg0[0] = '-';
520
      arg0[0] = '-';
Lines 411-416 Link Here
411
    error (0, errno, "%s", shell);
541
    error (0, errno, "%s", shell);
412
    exit (exit_status);
542
    exit (exit_status);
413
  }
543
  }
544
#ifdef USE_PAM
545
  } else if (child == -1) {
546
      fprintf(stderr, "can not fork user shell: %s", strerror(errno));
547
      exit(1);
548
  }
549
  /* parent only */
550
  sigfillset(&ourset);
551
  if (sigprocmask(SIG_BLOCK, &ourset, NULL)) {
552
    fprintf(stderr, "%s: signal malfunction\n", PROGRAM_NAME);
553
    caught = 1;
554
  }
555
  if (!caught) {
556
    struct sigaction action;
557
    action.sa_handler = su_catch_sig;
558
    sigemptyset(&action.sa_mask);
559
    action.sa_flags = 0;
560
    sigemptyset(&ourset);
561
    if (sigaddset(&ourset, SIGTERM)
562
        || sigaddset(&ourset, SIGALRM)
563
        || sigaction(SIGTERM, &action, NULL)
564
        || sigprocmask(SIG_UNBLOCK, &ourset, NULL)) {
565
      fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME);
566
      caught = 1;
567
    }
568
  }
569
  if (!caught) {
570
    do {
571
      int pid;
572
573
      pid = waitpid(-1, &status, WUNTRACED);
574
575
      if (WIFSTOPPED(status)) {
576
          kill(getpid(), SIGSTOP);
577
          /* once we get here, we must have resumed */
578
          kill(pid, SIGCONT);
579
      }
580
    } while (WIFSTOPPED(status));
581
  }
582
583
  if (caught) {
584
    fprintf(stderr, "\nSession terminated, killing shell...");
585
    kill (child, SIGTERM);
586
  }
587
  retval = pam_close_session(pamh, 0);
588
  PAM_BAIL_P;
589
  retval = pam_end(pamh, PAM_SUCCESS);
590
  PAM_BAIL_P;
591
  if (caught) {
592
    sleep(2);
593
    kill(child, SIGKILL);
594
    fprintf(stderr, " ...killed.\n");
595
    exit(-1);
596
  }
597
  exit (WEXITSTATUS(status));
598
#endif /* USE_PAM */
414
}
599
}
415
600
416
/* Return 1 if SHELL is a restricted shell (one not returned by
601
/* Return 1 if SHELL is a restricted shell (one not returned by
Lines 588-594 Link Here
588
773
774
775
#ifndef USE_PAM
589
  change_identity (pw);
776
  change_identity (pw);
590
  if (simulate_login && chdir (pw->pw_dir))
777
#endif
591
    error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
592
778
593
  run_shell (shell, command, additional_args);
779
  run_shell (shell, command, additional_args, pw);
594
}
780
}
(-)coreutils-5.2.0/configure.ac.pam (+7 lines)
Lines 7-12 Link Here
7
7
8
AM_INIT_AUTOMAKE([1.8 gnits dist-bzip2])
8
AM_INIT_AUTOMAKE([1.8 gnits dist-bzip2])
9
9
10
dnl Give the chance to enable PAM
11
AC_ARG_ENABLE(pam, dnl
12
[  --enable-pam              Enable use of the PAM libraries],
13
[AC_DEFINE(USE_PAM, 1, [Define if you want to use PAM])
14
LIB_PAM="-ldl -lpam -lpam_misc"
15
AC_SUBST(LIB_PAM)])
16
10
gl_DEFAULT_POSIX2_VERSION
17
gl_DEFAULT_POSIX2_VERSION
11
gl_USE_SYSTEM_EXTENSIONS
18
gl_USE_SYSTEM_EXTENSIONS
12
jm_PERL
19
jm_PERL
(-)coreutils-5.2.0/config.hin.pam (+3 lines)
Lines 1365-1370 Link Here
1365
/* Define if you want access control list support. */
1365
/* Define if you want access control list support. */
1366
#undef USE_ACL
1366
#undef USE_ACL
1367
1367
1368
/* Define if you want to use PAM */
1369
#undef USE_PAM
1370
1368
/* Version number of package */
1371
/* Version number of package */
1369
#undef VERSION
1372
#undef VERSION
1370
1373
(-)coreutils-5.2.1/doc/coreutils.texi.pam (-29 / +5 lines)
Lines 11855-11862 Link Here
11855
@findex syslog
11855
@findex syslog
11856
@command{su} can optionally be compiled to use @code{syslog} to report
11856
@command{su} can optionally be compiled to use @code{syslog} to report
11857
failed, and optionally successful, @command{su} attempts.  (If the system
11857
failed, and optionally successful, @command{su} attempts.  (If the system
11858
supports @code{syslog}.)  However, GNU @command{su} does not check if the
11858
supports @code{syslog}.)
11859
user is a member of the @code{wheel} group; see below.
11859
11860
This version of @command{su} has support for using PAM for
11861
authentication.  You can edit @file{/etc/pam.d/su} to customize its
11862
behaviour.
11860
11863
11861
The program accepts the following options.  Also see @ref{Common options}.
11864
The program accepts the following options.  Also see @ref{Common options}.
11862
11865
Lines 11937-11969 Link Here
11937
the exit status of the subshell otherwise
11940
the exit status of the subshell otherwise
11938
@end display
11941
@end display
11939
11942
11940
@cindex wheel group, not supported
11941
@cindex group wheel, not supported
11942
@cindex fascism
11943
@subsection Why GNU @command{su} does not support the @samp{wheel} group
11944
11945
(This section is by Richard Stallman.)
11946
11947
@cindex Twenex
11948
@cindex MIT AI lab
11949
Sometimes a few of the users try to hold total power over all the
11950
rest.  For example, in 1984, a few users at the MIT AI lab decided to
11951
seize power by changing the operator password on the Twenex system and
11952
keeping it secret from everyone else.  (I was able to thwart this coup
11953
and give power back to the users by patching the kernel, but I
11954
wouldn't know how to do that in Unix.)
11955
11956
However, occasionally the rulers do tell someone.  Under the usual
11957
@command{su} mechanism, once someone learns the root password who
11958
sympathizes with the ordinary users, he or she can tell the rest.  The
11959
``wheel group'' feature would make this impossible, and thus cement the
11960
power of the rulers.
11961
11962
I'm on the side of the masses, not that of the rulers.  If you are
11963
used to supporting the bosses and sysadmins in whatever they do, you
11964
might find this idea strange at first.
11965
11966
11967
@node Process control
11943
@node Process control
11968
@chapter Process control
11944
@chapter Process control
11969
11945

Return to bug 57238