]>
Commit | Line | Data |
---|---|---|
f774849c | 1 | diff -Nur sh-utils-2.0.12.orig/configure.ac sh-utils-2.0.12/configure.ac |
2 | --- sh-utils-2.0.12.orig/configure.ac Sun Apr 28 11:29:18 2002 | |
3 | +++ sh-utils-2.0.12/configure.ac Mon May 27 23:10:36 2002 | |
4 | @@ -8,6 +8,13 @@ | |
5 | ||
6 | AM_INIT_AUTOMAKE([1.6b gnits dist-bzip2]) | |
7 | ||
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,,[Use PAM?]) | |
12 | +LIB_PAM="-ldl -lpam -lpam_misc" | |
13 | +) | |
14 | + | |
15 | AC_GNU_SOURCE | |
16 | jm_PERL | |
17 | AC_PROG_CC | |
18 | @@ -238,6 +245,9 @@ | |
19 | ||
20 | AM_GNU_GETTEXT([external]) | |
21 | ||
22 | +# just in case we want PAM | |
23 | +AC_SUBST(LIB_PAM) | |
24 | + | |
25 | AC_CONFIG_FILES( | |
26 | Makefile | |
27 | doc/Makefile | |
28 | diff -Nur sh-utils-2.0.12.orig/doc/coreutils.texi sh-utils-2.0.12/doc/coreutils.texi | |
29 | --- sh-utils-2.0.12.orig/doc/coreutils.texi Sun Apr 28 23:55:31 2002 | |
30 | +++ sh-utils-2.0.12/doc/coreutils.texi Mon May 27 23:11:49 2002 | |
31 | @@ -10898,32 +10898,6 @@ | |
32 | ||
33 | @end table | |
34 | ||
35 | -@cindex wheel group, not supported | |
36 | -@cindex group wheel, not supported | |
37 | -@cindex fascism | |
38 | -@heading Why GNU @command{su} does not support the @samp{wheel} group | |
39 | - | |
40 | -(This section is by Richard Stallman.) | |
41 | - | |
42 | -@cindex Twenex | |
43 | -@cindex MIT AI lab | |
44 | -Sometimes a few of the users try to hold total power over all the | |
45 | -rest. For example, in 1984, a few users at the MIT AI lab decided to | |
46 | -seize power by changing the operator password on the Twenex system and | |
47 | -keeping it secret from everyone else. (I was able to thwart this coup | |
48 | -and give power back to the users by patching the kernel, but I | |
49 | -wouldn't know how to do that in Unix.) | |
50 | - | |
51 | -However, occasionally the rulers do tell someone. Under the usual | |
52 | -@command{su} mechanism, once someone learns the root password who | |
53 | -sympathizes with the ordinary users, he or she can tell the rest. The | |
54 | -``wheel group'' feature would make this impossible, and thus cement the | |
55 | -power of the rulers. | |
56 | - | |
57 | -I'm on the side of the masses, not that of the rulers. If you are | |
58 | -used to supporting the bosses and sysadmins in whatever they do, you | |
59 | -might find this idea strange at first. | |
60 | - | |
61 | ||
62 | @node Process control | |
63 | @chapter Process control | |
64 | diff -Nur sh-utils-2.0.12.orig/src/Makefile.am sh-utils-2.0.12/src/Makefile.am | |
65 | --- sh-utils-2.0.12.orig/src/Makefile.am Mon May 27 23:06:24 2002 | |
66 | +++ sh-utils-2.0.12/src/Makefile.am Mon May 27 23:09:22 2002 | |
67 | @@ -47,7 +47,7 @@ | |
68 | ||
69 | uptime_LDADD = $(LDADD) @GETLOADAVG_LIBS@ | |
70 | ||
71 | -su_LDADD = $(LDADD) @LIB_CRYPT@ | |
72 | +su_LDADD = $(LDADD) @LIB_CRYPT@ @LIB_PAM@ | |
73 | ||
74 | $(PROGRAMS): ../lib/libfetish.a | |
75 | ||
76 | diff -Nur sh-utils-2.0.12.orig/src/su.c sh-utils-2.0.12/src/su.c | |
77 | --- sh-utils-2.0.12.orig/src/su.c Mon May 27 23:06:24 2002 | |
78 | +++ sh-utils-2.0.12/src/su.c Mon May 27 23:08:28 2002 | |
79 | @@ -38,6 +38,16 @@ | |
80 | restricts who can su to UID 0 accounts. RMS considers that to | |
81 | be fascist. | |
82 | ||
83 | +#ifdef USE_PAM | |
84 | + | |
85 | + Actually, with PAM, su has nothing to do with whether or not a | |
86 | + wheel group is enforced by su. RMS tries to restrict your access | |
87 | + to a su which implements the wheel group, but PAM considers that | |
88 | + to be fascist, and gives the user/sysadmin the opportunity to | |
89 | + enforce a wheel group by proper editing of /etc/pam.conf | |
90 | + | |
91 | +#endif | |
92 | + | |
93 | Options: | |
94 | -, -l, --login Make the subshell a login shell. | |
95 | Unset all environment variables except | |
96 | @@ -81,6 +91,14 @@ | |
97 | prototype (returning `int') in <unistd.h>. */ | |
98 | #define getusershell _getusershell_sys_proto_ | |
99 | ||
100 | +#ifdef USE_PAM | |
101 | +# include <security/pam_appl.h> | |
102 | +# include <security/pam_misc.h> | |
103 | +# include <signal.h> | |
104 | +# include <sys/wait.h> | |
105 | +# include <sys/fsuid.h> | |
106 | +#endif /* USE_PAM */ | |
107 | + | |
108 | #include "system.h" | |
109 | #include "closeout.h" | |
110 | #include "dirname.h" | |
111 | @@ -151,7 +169,9 @@ | |
112 | /* The user to become if none is specified. */ | |
113 | #define DEFAULT_USER "root" | |
114 | ||
115 | +#ifndef USE_PAM | |
116 | char *crypt (); | |
117 | +#endif | |
118 | char *getpass (); | |
119 | char *getusershell (); | |
120 | void endusershell (); | |
121 | @@ -159,7 +179,7 @@ | |
122 | ||
123 | extern char **environ; | |
124 | ||
125 | -static void run_shell (const char *, const char *, char **) | |
126 | +static void run_shell (const char *, const char *, char **, const struct passwd *) | |
127 | ATTRIBUTE_NORETURN; | |
128 | ||
129 | /* The name this program was run with. */ | |
130 | @@ -272,7 +292,22 @@ | |
131 | } | |
132 | #endif | |
133 | ||
134 | +#ifdef USE_PAM | |
135 | +static pam_handle_t *pamh = NULL; | |
136 | +static int retval; | |
137 | +static struct pam_conv conv = { | |
138 | + misc_conv, | |
139 | + NULL | |
140 | +}; | |
141 | + | |
142 | +#define PAM_BAIL_P if (retval) { \ | |
143 | + pam_end(pamh, PAM_SUCCESS); \ | |
144 | + return 0; \ | |
145 | +} | |
146 | +#endif | |
147 | + | |
148 | /* Ask the user for a password. | |
149 | + If PAM is in use, let PAM ask for the password if necessary. | |
150 | Return 1 if the user gives the correct password for entry PW, | |
151 | 0 if not. Return 1 without asking for a password if run by UID 0 | |
152 | or if PW has an empty password. */ | |
153 | @@ -280,6 +315,29 @@ | |
154 | static int | |
155 | correct_password (const struct passwd *pw) | |
156 | { | |
157 | +#ifdef USE_PAM | |
158 | + /* root always succeeds; this isn't an authentication question (no | |
159 | + * extra privs are being granted) so it shouldn't authenticate with PAM. | |
160 | + * However, we want to create the pam_handle so that proper credentials | |
161 | + * are created later with pam_setcred(). */ | |
162 | + retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh); | |
163 | + PAM_BAIL_P; | |
164 | + | |
165 | + retval = pam_authenticate(pamh, 0); | |
166 | + PAM_BAIL_P; | |
167 | + | |
168 | + retval = pam_acct_mgmt(pamh, 0); | |
169 | + if (retval == PAM_NEW_AUTHTOK_REQD) { | |
170 | + /* password has expired. Offer option to change it. */ | |
171 | + if (getuid()) { | |
172 | + retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); | |
173 | + PAM_BAIL_P; | |
174 | + } else retval = PAM_SUCCESS; | |
175 | + } | |
176 | + PAM_BAIL_P; | |
177 | + /* must be authenticated if this point was reached */ | |
178 | + return 1; | |
179 | +#else /* !USE_PAM */ | |
180 | char *unencrypted, *encrypted, *correct; | |
181 | #if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP | |
182 | /* Shadow passwd stuff for SVR3 and maybe other systems. */ | |
183 | @@ -304,6 +362,7 @@ | |
184 | encrypted = crypt (unencrypted, correct); | |
185 | memset (unencrypted, 0, strlen (unencrypted)); | |
186 | return strcmp (encrypted, correct) == 0; | |
187 | +#endif /* !USE_PAM */ | |
188 | } | |
189 | ||
190 | /* Update `environ' for the new shell based on PW, with SHELL being | |
191 | @@ -313,16 +372,20 @@ | |
192 | modify_environment (const struct passwd *pw, const char *shell) | |
193 | { | |
194 | char *term; | |
195 | + char *display; | |
196 | ||
197 | if (simulate_login) | |
198 | { | |
199 | - /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. | |
200 | + /* Leave TERM, DISPLAY unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. | |
201 | Unset all other environment variables. */ | |
202 | term = getenv ("TERM"); | |
203 | + display = getenv ("DISPLAY"); | |
204 | environ = (char **) xmalloc (2 * sizeof (char *)); | |
205 | environ[0] = 0; | |
206 | if (term) | |
207 | xputenv (concat ("TERM", "=", term)); | |
208 | + if (display) | |
209 | + xputenv (concat ("DISPLAY", "=", display)); | |
210 | xputenv (concat ("HOME", "=", pw->pw_dir)); | |
211 | xputenv (concat ("SHELL", "=", shell)); | |
212 | xputenv (concat ("USER", "=", pw->pw_name)); | |
213 | @@ -359,23 +422,73 @@ | |
214 | error (EXIT_FAILURE, errno, _("cannot set groups")); | |
215 | endgrent (); | |
216 | #endif | |
217 | +#ifdef USE_PAM | |
218 | + retval = pam_setcred(pamh, PAM_ESTABLISH_CRED); | |
219 | + if (retval != PAM_SUCCESS) | |
220 | + error (1, 0, pam_strerror(pamh, retval)); | |
221 | +#endif /* USE_PAM */ | |
222 | if (setgid (pw->pw_gid)) | |
223 | error (EXIT_FAILURE, errno, _("cannot set group id")); | |
224 | if (setuid (pw->pw_uid)) | |
225 | error (EXIT_FAILURE, errno, _("cannot set user id")); | |
226 | } | |
227 | ||
228 | +#ifdef USE_PAM | |
229 | +static int caught=0; | |
230 | +/* Signal handler for parent process later */ | |
231 | +static void su_catch_sig(int sig) | |
232 | +{ | |
233 | + ++caught; | |
234 | +} | |
235 | + | |
236 | +int | |
237 | +pam_copyenv (pam_handle_t *pamh) | |
238 | +{ | |
239 | + char **env; | |
240 | + | |
241 | + env = pam_getenvlist(pamh); | |
242 | + if(env) { | |
243 | + while(*env) { | |
244 | + xputenv(*env); | |
245 | + env++; | |
246 | + } | |
247 | + } | |
248 | + return(0); | |
249 | +} | |
250 | +#endif | |
251 | + | |
252 | /* Run SHELL, or DEFAULT_SHELL if SHELL is empty. | |
253 | If COMMAND is nonzero, pass it to the shell with the -c option. | |
254 | If ADDITIONAL_ARGS is nonzero, pass it to the shell as more | |
255 | arguments. */ | |
256 | ||
257 | static void | |
258 | -run_shell (const char *shell, const char *command, char **additional_args) | |
259 | +run_shell (const char *shell, const char *command, char **additional_args, const struct passwd *pw) | |
260 | { | |
261 | const char **args; | |
262 | int argno = 1; | |
263 | +#ifdef USE_PAM | |
264 | + int child; | |
265 | + sigset_t ourset; | |
266 | + int status; | |
267 | + | |
268 | + retval = pam_open_session(pamh,0); | |
269 | + if (retval != PAM_SUCCESS) { | |
270 | + fprintf (stderr, "could not open session\n"); | |
271 | + exit (1); | |
272 | + } | |
273 | + | |
274 | +/* do this at the last possible moment, because environment variables may | |
275 | + be passed even in the session phase | |
276 | +*/ | |
277 | + if(pam_copyenv(pamh) != PAM_SUCCESS) | |
278 | + fprintf (stderr, "error copying PAM environment\n"); | |
279 | ||
280 | + child = fork(); | |
281 | + if (child == 0) { /* child shell */ | |
282 | + change_identity (pw); | |
283 | + pam_end(pamh, 0); | |
284 | +#endif | |
285 | if (additional_args) | |
286 | args = (const char **) xmalloc (sizeof (char *) | |
287 | * (10 + elements (additional_args))); | |
288 | @@ -408,6 +521,61 @@ | |
289 | error (0, errno, "%s", shell); | |
290 | exit (exit_status); | |
291 | } | |
292 | +#ifdef USE_PAM | |
293 | + } else if (child == -1) { | |
294 | + fprintf(stderr, "can not fork user shell: %s", strerror(errno)); | |
295 | + exit(1); | |
296 | + } | |
297 | + /* parent only */ | |
298 | + sigfillset(&ourset); | |
299 | + if (sigprocmask(SIG_BLOCK, &ourset, NULL)) { | |
300 | + fprintf(stderr, "%s: signal malfunction\n", PROGRAM_NAME); | |
301 | + caught = 1; | |
302 | + } | |
303 | + if (!caught) { | |
304 | + struct sigaction action; | |
305 | + action.sa_handler = su_catch_sig; | |
306 | + sigemptyset(&action.sa_mask); | |
307 | + action.sa_flags = 0; | |
308 | + sigemptyset(&ourset); | |
309 | + if (sigaddset(&ourset, SIGTERM) | |
310 | + || sigaddset(&ourset, SIGALRM) | |
311 | + || sigaction(SIGTERM, &action, NULL) | |
312 | + || sigprocmask(SIG_UNBLOCK, &ourset, NULL)) { | |
313 | + fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME); | |
314 | + caught = 1; | |
315 | + } | |
316 | + } | |
317 | + if (!caught) { | |
318 | + do { | |
319 | + int pid; | |
320 | + | |
321 | + pid = waitpid(-1, &status, WUNTRACED); | |
322 | + | |
323 | + if (WIFSTOPPED(status)) { | |
324 | + kill(getpid(), SIGSTOP); | |
325 | + /* once we get here, we must have resumed */ | |
326 | + kill(pid, SIGCONT); | |
327 | + } | |
328 | + } while (WIFSTOPPED(status)); | |
329 | + } | |
330 | + | |
331 | + if (caught) { | |
332 | + fprintf(stderr, "\nSession terminated, killing shell..."); | |
333 | + kill (child, SIGTERM); | |
334 | + } | |
335 | + retval = pam_close_session(pamh, 0); | |
336 | + PAM_BAIL_P; | |
337 | + retval = pam_end(pamh, PAM_SUCCESS); | |
338 | + PAM_BAIL_P; | |
339 | + if (caught) { | |
340 | + sleep(2); | |
341 | + kill(child, SIGKILL); | |
342 | + fprintf(stderr, " ...killed.\n"); | |
343 | + exit(-1); | |
344 | + } | |
345 | + exit (WEXITSTATUS(status)); | |
346 | +#endif /* USE_PAM */ | |
347 | } | |
348 | ||
349 | /* Return 1 if SHELL is a restricted shell (one not returned by | |
350 | @@ -580,9 +748,14 @@ | |
351 | } | |
352 | modify_environment (pw, shell); | |
353 | ||
354 | + | |
355 | +#ifdef USE_PAM | |
356 | + setfsuid(pw->pw_uid); | |
357 | +#else | |
358 | change_identity (pw); | |
359 | +#endif | |
360 | if (simulate_login && chdir (pw->pw_dir)) | |
361 | error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir); | |
362 | ||
363 | - run_shell (shell, command, additional_args); | |
364 | + run_shell (shell, command, additional_args, pw); | |
365 | } |