Deleted Added
full compact
login.c (2532) login.c (3205)
1/*-
2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
42#endif /* not lint */
43
44/*
45 * login [ name ]
46 * login -h hostname (for telnetd, etc.)
47 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
48 */
49
50#include <sys/param.h>
51#include <sys/stat.h>
52#include <sys/time.h>
53#include <sys/resource.h>
54#include <sys/file.h>
55
56#include <err.h>
57#include <errno.h>
58#include <grp.h>
59#include <pwd.h>
60#include <setjmp.h>
61#include <signal.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <syslog.h>
66#include <ttyent.h>
67#include <tzfile.h>
68#include <unistd.h>
69#include <utmp.h>
70
71#include "pathnames.h"
72
73void badlogin __P((char *));
74void checknologin __P((void));
75void dolastlog __P((int));
76void getloginname __P((void));
77void motd __P((void));
78void change_passwd __P((void));
79int rootterm __P((char *));
80void sigint __P((int));
81void sleepexit __P((int));
82char *stypeof __P((char *));
83void timedout __P((int));
84void login_fbtab __P((char *, uid_t, gid_t));
85#ifdef KERBEROS
86int klogin __P((struct passwd *, char *, char *, char *));
87#endif
88
89extern void login __P((struct utmp *));
90
91#define TTYGRPNAME "tty" /* name of group to own ttys */
92
93/*
94 * This bounds the time given to login. Not a define so it can
95 * be patched on machines where it's too small.
96 */
97u_int timeout = 300;
98
99#ifdef KERBEROS
100int notickets = 1;
101char *instance;
102char *krbtkfile_env;
103int authok;
104#endif
105
106struct passwd *pwd;
107int failures;
108char term[64], *envinit[1], *hostname, *username, *tty;
109
110int
111main(argc, argv)
112 int argc;
113 char *argv[];
114{
115 extern char **environ;
116 struct group *gr;
117 struct stat st;
118 struct timeval tp;
119 struct utmp utmp;
120 int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
121 uid_t uid;
1/*-
2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
42#endif /* not lint */
43
44/*
45 * login [ name ]
46 * login -h hostname (for telnetd, etc.)
47 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
48 */
49
50#include <sys/param.h>
51#include <sys/stat.h>
52#include <sys/time.h>
53#include <sys/resource.h>
54#include <sys/file.h>
55
56#include <err.h>
57#include <errno.h>
58#include <grp.h>
59#include <pwd.h>
60#include <setjmp.h>
61#include <signal.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <syslog.h>
66#include <ttyent.h>
67#include <tzfile.h>
68#include <unistd.h>
69#include <utmp.h>
70
71#include "pathnames.h"
72
73void badlogin __P((char *));
74void checknologin __P((void));
75void dolastlog __P((int));
76void getloginname __P((void));
77void motd __P((void));
78void change_passwd __P((void));
79int rootterm __P((char *));
80void sigint __P((int));
81void sleepexit __P((int));
82char *stypeof __P((char *));
83void timedout __P((int));
84void login_fbtab __P((char *, uid_t, gid_t));
85#ifdef KERBEROS
86int klogin __P((struct passwd *, char *, char *, char *));
87#endif
88
89extern void login __P((struct utmp *));
90
91#define TTYGRPNAME "tty" /* name of group to own ttys */
92
93/*
94 * This bounds the time given to login. Not a define so it can
95 * be patched on machines where it's too small.
96 */
97u_int timeout = 300;
98
99#ifdef KERBEROS
100int notickets = 1;
101char *instance;
102char *krbtkfile_env;
103int authok;
104#endif
105
106struct passwd *pwd;
107int failures;
108char term[64], *envinit[1], *hostname, *username, *tty;
109
110int
111main(argc, argv)
112 int argc;
113 char *argv[];
114{
115 extern char **environ;
116 struct group *gr;
117 struct stat st;
118 struct timeval tp;
119 struct utmp utmp;
120 int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
121 uid_t uid;
122 char *domain, *p, *salt, *ttyn;
122 char *domain, *p, *ep, *salt, *ttyn;
123 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
124 char localhost[MAXHOSTNAMELEN];
123 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
124 char localhost[MAXHOSTNAMELEN];
125 char full_hostname[MAXHOSTNAMELEN];
126#ifdef SKEY
127 int permit_passwd = 0;
128 char *skey_getpass(), *skey_crypt();
129#endif
125
126 (void)signal(SIGALRM, timedout);
127 (void)alarm(timeout);
128 (void)signal(SIGQUIT, SIG_IGN);
129 (void)signal(SIGINT, SIG_IGN);
130 (void)setpriority(PRIO_PROCESS, 0, 0);
131
132 openlog("login", LOG_ODELAY, LOG_AUTH);
133
134 /*
135 * -p is used by getty to tell login not to destroy the environment
136 * -f is used to skip a second login authentication
137 * -h is used by other servers to pass the name of the remote
138 * host to login so that it may be placed in utmp and wtmp
139 */
130
131 (void)signal(SIGALRM, timedout);
132 (void)alarm(timeout);
133 (void)signal(SIGQUIT, SIG_IGN);
134 (void)signal(SIGINT, SIG_IGN);
135 (void)setpriority(PRIO_PROCESS, 0, 0);
136
137 openlog("login", LOG_ODELAY, LOG_AUTH);
138
139 /*
140 * -p is used by getty to tell login not to destroy the environment
141 * -f is used to skip a second login authentication
142 * -h is used by other servers to pass the name of the remote
143 * host to login so that it may be placed in utmp and wtmp
144 */
145 *full_hostname = '\0';
140 domain = NULL;
141 if (gethostname(localhost, sizeof(localhost)) < 0)
142 syslog(LOG_ERR, "couldn't get local hostname: %m");
143 else
144 domain = strchr(localhost, '.');
145
146 fflag = hflag = pflag = 0;
147 uid = getuid();
148 while ((ch = getopt(argc, argv, "fh:p")) != EOF)
149 switch (ch) {
150 case 'f':
151 fflag = 1;
152 break;
153 case 'h':
154 if (uid)
155 errx(1, "-h option: %s", strerror(EPERM));
156 hflag = 1;
146 domain = NULL;
147 if (gethostname(localhost, sizeof(localhost)) < 0)
148 syslog(LOG_ERR, "couldn't get local hostname: %m");
149 else
150 domain = strchr(localhost, '.');
151
152 fflag = hflag = pflag = 0;
153 uid = getuid();
154 while ((ch = getopt(argc, argv, "fh:p")) != EOF)
155 switch (ch) {
156 case 'f':
157 fflag = 1;
158 break;
159 case 'h':
160 if (uid)
161 errx(1, "-h option: %s", strerror(EPERM));
162 hflag = 1;
163 strncpy(full_hostname, optarg, sizeof(full_hostname)-1);
157 if (domain && (p = strchr(optarg, '.')) &&
158 strcasecmp(p, domain) == 0)
159 *p = 0;
160 hostname = optarg;
161 break;
162 case 'p':
163 pflag = 1;
164 break;
165 case '?':
166 default:
167 if (!uid)
168 syslog(LOG_ERR, "invalid flag %c", ch);
169 (void)fprintf(stderr,
170 "usage: login [-fp] [-h hostname] [username]\n");
171 exit(1);
172 }
173 argc -= optind;
174 argv += optind;
175
176 if (*argv) {
177 username = *argv;
178 ask = 0;
179 } else
180 ask = 1;
181
182 for (cnt = getdtablesize(); cnt > 2; cnt--)
183 (void)close(cnt);
184
185 ttyn = ttyname(STDIN_FILENO);
186 if (ttyn == NULL || *ttyn == '\0') {
187 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
188 ttyn = tname;
189 }
190 if (tty = strrchr(ttyn, '/'))
191 ++tty;
192 else
193 tty = ttyn;
194
195 for (cnt = 0;; ask = 1) {
196 if (ask) {
197 fflag = 0;
198 getloginname();
199 }
200 rootlogin = 0;
201#ifdef KERBEROS
202 if ((instance = strchr(username, '.')) != NULL) {
203 if (strncmp(instance, ".root", 5) == 0)
204 rootlogin = 1;
205 *instance++ = '\0';
206 } else
207 instance = "";
208#endif
209 if (strlen(username) > UT_NAMESIZE)
210 username[UT_NAMESIZE] = '\0';
211
212 /*
213 * Note if trying multiple user names; log failures for
214 * previous user name, but don't bother logging one failure
215 * for nonexistent name (mistyped username).
216 */
217 if (failures && strcmp(tbuf, username)) {
218 if (failures > (pwd ? 0 : 1))
219 badlogin(tbuf);
220 failures = 0;
221 }
222 (void)strcpy(tbuf, username);
223
224 if (pwd = getpwnam(username))
225 salt = pwd->pw_passwd;
226 else
227 salt = "xx";
228
229 /*
230 * if we have a valid account name, and it doesn't have a
231 * password, or the -f option was specified and the caller
232 * is root or the caller isn't changing their uid, don't
233 * authenticate.
234 */
164 if (domain && (p = strchr(optarg, '.')) &&
165 strcasecmp(p, domain) == 0)
166 *p = 0;
167 hostname = optarg;
168 break;
169 case 'p':
170 pflag = 1;
171 break;
172 case '?':
173 default:
174 if (!uid)
175 syslog(LOG_ERR, "invalid flag %c", ch);
176 (void)fprintf(stderr,
177 "usage: login [-fp] [-h hostname] [username]\n");
178 exit(1);
179 }
180 argc -= optind;
181 argv += optind;
182
183 if (*argv) {
184 username = *argv;
185 ask = 0;
186 } else
187 ask = 1;
188
189 for (cnt = getdtablesize(); cnt > 2; cnt--)
190 (void)close(cnt);
191
192 ttyn = ttyname(STDIN_FILENO);
193 if (ttyn == NULL || *ttyn == '\0') {
194 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
195 ttyn = tname;
196 }
197 if (tty = strrchr(ttyn, '/'))
198 ++tty;
199 else
200 tty = ttyn;
201
202 for (cnt = 0;; ask = 1) {
203 if (ask) {
204 fflag = 0;
205 getloginname();
206 }
207 rootlogin = 0;
208#ifdef KERBEROS
209 if ((instance = strchr(username, '.')) != NULL) {
210 if (strncmp(instance, ".root", 5) == 0)
211 rootlogin = 1;
212 *instance++ = '\0';
213 } else
214 instance = "";
215#endif
216 if (strlen(username) > UT_NAMESIZE)
217 username[UT_NAMESIZE] = '\0';
218
219 /*
220 * Note if trying multiple user names; log failures for
221 * previous user name, but don't bother logging one failure
222 * for nonexistent name (mistyped username).
223 */
224 if (failures && strcmp(tbuf, username)) {
225 if (failures > (pwd ? 0 : 1))
226 badlogin(tbuf);
227 failures = 0;
228 }
229 (void)strcpy(tbuf, username);
230
231 if (pwd = getpwnam(username))
232 salt = pwd->pw_passwd;
233 else
234 salt = "xx";
235
236 /*
237 * if we have a valid account name, and it doesn't have a
238 * password, or the -f option was specified and the caller
239 * is root or the caller isn't changing their uid, don't
240 * authenticate.
241 */
235 if (pwd && (*pwd->pw_passwd == '\0' ||
236 fflag && (uid == 0 || uid == pwd->pw_uid)))
237 break;
242 if (pwd) {
243 if (pwd->pw_uid == 0)
244 rootlogin = 1;
245
246 if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
247 /* already authenticated */
248 break;
249 } else if (pwd->pw_passwd[0] == '\0') {
250 /* pretend password okay */
251 rval = 0;
252 goto ttycheck;
253 }
254 }
255
238 fflag = 0;
256 fflag = 0;
239 if (pwd && pwd->pw_uid == 0)
240 rootlogin = 1;
241
242 (void)setpriority(PRIO_PROCESS, 0, -4);
243
257
258 (void)setpriority(PRIO_PROCESS, 0, -4);
259
260#ifdef SKEY
261 permit_passwd = skeyaccess(username, tty,
262 hostname ? full_hostname : NULL);
263 p = skey_getpass("Password:", pwd, permit_passwd);
264 ep = skey_crypt(p, salt, pwd, permit_passwd);
265#else
244 p = getpass("Password:");
266 p = getpass("Password:");
267 ep = crypt(p, salt);
268#endif
245
246 if (pwd) {
247#ifdef KERBEROS
248 rval = klogin(pwd, instance, localhost, p);
249 if (rval != 0 && rootlogin && pwd->pw_uid != 0)
250 rootlogin = 0;
251 if (rval == 0)
252 authok = 1;
253 else if (rval == 1)
269
270 if (pwd) {
271#ifdef KERBEROS
272 rval = klogin(pwd, instance, localhost, p);
273 if (rval != 0 && rootlogin && pwd->pw_uid != 0)
274 rootlogin = 0;
275 if (rval == 0)
276 authok = 1;
277 else if (rval == 1)
254 rval = strcmp(crypt(p, salt), pwd->pw_passwd);
278 rval = strcmp(ep, pwd->pw_passwd);
255#else
279#else
256 rval = strcmp(crypt(p, salt), pwd->pw_passwd);
280 rval = strcmp(ep, pwd->pw_passwd);
257#endif
258 }
259 memset(p, 0, strlen(p));
260
261 (void)setpriority(PRIO_PROCESS, 0, 0);
262
281#endif
282 }
283 memset(p, 0, strlen(p));
284
285 (void)setpriority(PRIO_PROCESS, 0, 0);
286
287 ttycheck:
263 /*
264 * If trying to log in as root without Kerberos,
265 * but with insecure terminal, refuse the login attempt.
266 */
267#ifdef KERBEROS
268 if (authok == 0)
269#endif
288 /*
289 * If trying to log in as root without Kerberos,
290 * but with insecure terminal, refuse the login attempt.
291 */
292#ifdef KERBEROS
293 if (authok == 0)
294#endif
270 if (pwd && rootlogin && !rootterm(tty)) {
295 if (pwd && !rval && rootlogin && !rootterm(tty)) {
271 (void)fprintf(stderr,
272 "%s login refused on this terminal.\n",
273 pwd->pw_name);
274 if (hostname)
275 syslog(LOG_NOTICE,
276 "LOGIN %s REFUSED FROM %s ON TTY %s",
277 pwd->pw_name, hostname, tty);
278 else
279 syslog(LOG_NOTICE,
280 "LOGIN %s REFUSED ON TTY %s",
281 pwd->pw_name, tty);
282 continue;
283 }
284
285 if (pwd && !rval)
286 break;
287
288 (void)printf("Login incorrect\n");
289 failures++;
290 /* we allow 10 tries, but after 3 we start backing off */
291 if (++cnt > 3) {
292 if (cnt >= 10) {
293 badlogin(username);
294 sleepexit(1);
295 }
296 sleep((u_int)((cnt - 3) * 5));
297 }
298 }
299
300 /* committed to login -- turn off timeout */
301 (void)alarm((u_int)0);
302
303 endpwent();
304
305 /* if user not super-user, check for disabled logins */
306 if (!rootlogin)
307 checknologin();
308
309 if (chdir(pwd->pw_dir) < 0) {
310 (void)printf("No home directory %s!\n", pwd->pw_dir);
311 if (chdir("/"))
312 exit(0);
313 pwd->pw_dir = "/";
314 (void)printf("Logging in with home = \"/\".\n");
315 }
316
317 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
318
319 if (pwd->pw_change || pwd->pw_expire)
320 (void)gettimeofday(&tp, (struct timezone *)NULL);
321
322 if (pwd->pw_change)
323 if (tp.tv_sec >= pwd->pw_change) {
324 (void)printf("Sorry -- your password has expired.\n");
325 change_passwd();
326 } else if (pwd->pw_change - tp.tv_sec <
327 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
328 (void)printf("Warning: your password expires on %s",
329 ctime(&pwd->pw_change));
330 if (pwd->pw_expire)
331 if (tp.tv_sec >= pwd->pw_expire) {
332 (void)printf("Sorry -- your account has expired.\n");
333 sleepexit(1);
334 } else if (pwd->pw_expire - tp.tv_sec <
335 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
336 (void)printf("Warning: your account expires on %s",
337 ctime(&pwd->pw_expire));
338
339 /* Nothing else left to fail -- really log in. */
340 memset((void *)&utmp, 0, sizeof(utmp));
341 (void)time(&utmp.ut_time);
342 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
343 if (hostname)
344 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
345 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
346 login(&utmp);
347
348 dolastlog(quietlog);
349
350 /*
351 * Set device protections, depending on what terminal the
352 * user is logged in. This feature is used on Suns to give
353 * console users better privacy.
354 */
355 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
356
357 (void)chown(ttyn, pwd->pw_uid,
358 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
359 (void)setgid(pwd->pw_gid);
360
361 initgroups(username, pwd->pw_gid);
362
363 if (*pwd->pw_shell == '\0')
364 pwd->pw_shell = _PATH_BSHELL;
365
366 /* Destroy environment unless user has requested its preservation. */
367 if (!pflag)
368 environ = envinit;
369 (void)setenv("HOME", pwd->pw_dir, 1);
370 (void)setenv("SHELL", pwd->pw_shell, 1);
371 if (term[0] == '\0')
372 (void)strncpy(term, stypeof(tty), sizeof(term));
373 (void)setenv("TERM", term, 0);
374 (void)setenv("LOGNAME", pwd->pw_name, 1);
375 (void)setenv("USER", pwd->pw_name, 1);
376 (void)setenv("PATH", _PATH_DEFPATH, 0);
377#ifdef KERBEROS
378 if (krbtkfile_env)
379 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
380#endif
381
382 if (tty[sizeof("tty")-1] == 'd')
383 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
384
385 /* If fflag is on, assume caller/authenticator has logged root login. */
386 if (rootlogin && fflag == 0)
387 if (hostname)
388 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
389 username, tty, hostname);
390 else
391 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
392
393#ifdef KERBEROS
394 if (!quietlog && notickets == 1)
395 (void)printf("Warning: no Kerberos tickets issued.\n");
396#endif
397
296 (void)fprintf(stderr,
297 "%s login refused on this terminal.\n",
298 pwd->pw_name);
299 if (hostname)
300 syslog(LOG_NOTICE,
301 "LOGIN %s REFUSED FROM %s ON TTY %s",
302 pwd->pw_name, hostname, tty);
303 else
304 syslog(LOG_NOTICE,
305 "LOGIN %s REFUSED ON TTY %s",
306 pwd->pw_name, tty);
307 continue;
308 }
309
310 if (pwd && !rval)
311 break;
312
313 (void)printf("Login incorrect\n");
314 failures++;
315 /* we allow 10 tries, but after 3 we start backing off */
316 if (++cnt > 3) {
317 if (cnt >= 10) {
318 badlogin(username);
319 sleepexit(1);
320 }
321 sleep((u_int)((cnt - 3) * 5));
322 }
323 }
324
325 /* committed to login -- turn off timeout */
326 (void)alarm((u_int)0);
327
328 endpwent();
329
330 /* if user not super-user, check for disabled logins */
331 if (!rootlogin)
332 checknologin();
333
334 if (chdir(pwd->pw_dir) < 0) {
335 (void)printf("No home directory %s!\n", pwd->pw_dir);
336 if (chdir("/"))
337 exit(0);
338 pwd->pw_dir = "/";
339 (void)printf("Logging in with home = \"/\".\n");
340 }
341
342 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
343
344 if (pwd->pw_change || pwd->pw_expire)
345 (void)gettimeofday(&tp, (struct timezone *)NULL);
346
347 if (pwd->pw_change)
348 if (tp.tv_sec >= pwd->pw_change) {
349 (void)printf("Sorry -- your password has expired.\n");
350 change_passwd();
351 } else if (pwd->pw_change - tp.tv_sec <
352 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
353 (void)printf("Warning: your password expires on %s",
354 ctime(&pwd->pw_change));
355 if (pwd->pw_expire)
356 if (tp.tv_sec >= pwd->pw_expire) {
357 (void)printf("Sorry -- your account has expired.\n");
358 sleepexit(1);
359 } else if (pwd->pw_expire - tp.tv_sec <
360 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
361 (void)printf("Warning: your account expires on %s",
362 ctime(&pwd->pw_expire));
363
364 /* Nothing else left to fail -- really log in. */
365 memset((void *)&utmp, 0, sizeof(utmp));
366 (void)time(&utmp.ut_time);
367 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
368 if (hostname)
369 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
370 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
371 login(&utmp);
372
373 dolastlog(quietlog);
374
375 /*
376 * Set device protections, depending on what terminal the
377 * user is logged in. This feature is used on Suns to give
378 * console users better privacy.
379 */
380 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
381
382 (void)chown(ttyn, pwd->pw_uid,
383 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
384 (void)setgid(pwd->pw_gid);
385
386 initgroups(username, pwd->pw_gid);
387
388 if (*pwd->pw_shell == '\0')
389 pwd->pw_shell = _PATH_BSHELL;
390
391 /* Destroy environment unless user has requested its preservation. */
392 if (!pflag)
393 environ = envinit;
394 (void)setenv("HOME", pwd->pw_dir, 1);
395 (void)setenv("SHELL", pwd->pw_shell, 1);
396 if (term[0] == '\0')
397 (void)strncpy(term, stypeof(tty), sizeof(term));
398 (void)setenv("TERM", term, 0);
399 (void)setenv("LOGNAME", pwd->pw_name, 1);
400 (void)setenv("USER", pwd->pw_name, 1);
401 (void)setenv("PATH", _PATH_DEFPATH, 0);
402#ifdef KERBEROS
403 if (krbtkfile_env)
404 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
405#endif
406
407 if (tty[sizeof("tty")-1] == 'd')
408 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
409
410 /* If fflag is on, assume caller/authenticator has logged root login. */
411 if (rootlogin && fflag == 0)
412 if (hostname)
413 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
414 username, tty, hostname);
415 else
416 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
417
418#ifdef KERBEROS
419 if (!quietlog && notickets == 1)
420 (void)printf("Warning: no Kerberos tickets issued.\n");
421#endif
422
423#ifdef LOGALL
424 /*
425 * Syslog each successful login, so we don't have to watch hundreds
426 * of wtmp or lastlogin files.
427 */
428 if (hostname) {
429 syslog(LOG_INFO, "login from %s as %s", hostname, pwd->pw_name);
430 } else {
431 syslog(LOG_INFO, "login on %s as %s", tty, pwd->pw_name);
432 }
433#endif
434
398 if (!quietlog) {
399 (void)printf("%s\n\t%s %s\n\n",
400 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
401 "The Regents of the University of California. ",
402 "All rights reserved.");
403 motd();
404 (void)snprintf(tbuf,
405 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
406 if (stat(tbuf, &st) == 0 && st.st_size != 0)
407 (void)printf("You have %smail.\n",
408 (st.st_mtime > st.st_atime) ? "new " : "");
409 }
410
435 if (!quietlog) {
436 (void)printf("%s\n\t%s %s\n\n",
437 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
438 "The Regents of the University of California. ",
439 "All rights reserved.");
440 motd();
441 (void)snprintf(tbuf,
442 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
443 if (stat(tbuf, &st) == 0 && st.st_size != 0)
444 (void)printf("You have %smail.\n",
445 (st.st_mtime > st.st_atime) ? "new " : "");
446 }
447
448#ifdef LOGIN_ACCESS
449 if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) {
450 printf("Permission denied\n");
451 if (hostname)
452 syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s",
453 pwd->pw_name, hostname);
454 else
455 syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s",
456 pwd->pw_name, tty);
457 sleepexit(1);
458 }
459#endif
460
411 (void)signal(SIGALRM, SIG_DFL);
412 (void)signal(SIGQUIT, SIG_DFL);
413 (void)signal(SIGINT, SIG_DFL);
414 (void)signal(SIGTSTP, SIG_IGN);
415
416 tbuf[0] = '-';
417 (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
418 p + 1 : pwd->pw_shell);
419
420 if (setlogin(pwd->pw_name) < 0)
421 syslog(LOG_ERR, "setlogin() failure: %m");
422
423 /* Discard permissions last so can't get killed and drop core. */
424 if (rootlogin)
425 (void) setuid(0);
426 else
427 (void) setuid(pwd->pw_uid);
428
429 execlp(pwd->pw_shell, tbuf, 0);
430 err(1, "%s", pwd->pw_shell);
431}
432
433#ifdef KERBEROS
434#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */
435#else
436#define NBUFSIZ (UT_NAMESIZE + 1)
437#endif
438
439void
440getloginname()
441{
442 int ch;
443 char *p;
444 static char nbuf[NBUFSIZ];
445
446 for (;;) {
447 (void)printf("login: ");
448 for (p = nbuf; (ch = getchar()) != '\n'; ) {
449 if (ch == EOF) {
450 badlogin(username);
451 exit(0);
452 }
453 if (p < nbuf + (NBUFSIZ - 1))
454 *p++ = ch;
455 }
456 if (p > nbuf)
457 if (nbuf[0] == '-')
458 (void)fprintf(stderr,
459 "login names may not start with '-'.\n");
460 else {
461 *p = '\0';
462 username = nbuf;
463 break;
464 }
465 }
466}
467
468int
469rootterm(ttyn)
470 char *ttyn;
471{
472 struct ttyent *t;
473
474 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
475}
476
477jmp_buf motdinterrupt;
478
479void
480motd()
481{
482 int fd, nchars;
483 sig_t oldint;
484 char tbuf[8192];
485
486 if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
487 return;
488 oldint = signal(SIGINT, sigint);
489 if (setjmp(motdinterrupt) == 0)
490 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
491 (void)write(fileno(stdout), tbuf, nchars);
492 (void)signal(SIGINT, oldint);
493 (void)close(fd);
494}
495
496/* ARGSUSED */
497void
498sigint(signo)
499 int signo;
500{
501
502 longjmp(motdinterrupt, 1);
503}
504
505/* ARGSUSED */
506void
507timedout(signo)
508 int signo;
509{
510
511 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
512 exit(0);
513}
514
515void
516checknologin()
517{
518 int fd, nchars;
519 char tbuf[8192];
520
521 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
522 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
523 (void)write(fileno(stdout), tbuf, nchars);
524 sleepexit(0);
525 }
526}
527
528void
529dolastlog(quiet)
530 int quiet;
531{
532 struct lastlog ll;
533 int fd;
534
535 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
536 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
537 if (!quiet) {
538 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
539 ll.ll_time != 0) {
540 (void)printf("Last login: %.*s ",
541 24-5, (char *)ctime(&ll.ll_time));
542 if (*ll.ll_host != '\0')
543 (void)printf("from %.*s\n",
544 (int)sizeof(ll.ll_host),
545 ll.ll_host);
546 else
547 (void)printf("on %.*s\n",
548 (int)sizeof(ll.ll_line),
549 ll.ll_line);
550 }
551 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
552 }
553 memset((void *)&ll, 0, sizeof(ll));
554 (void)time(&ll.ll_time);
555 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
556 if (hostname)
557 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
558 (void)write(fd, (char *)&ll, sizeof(ll));
559 (void)close(fd);
560 }
561}
562
563void
564badlogin(name)
565 char *name;
566{
567
568 if (failures == 0)
569 return;
570 if (hostname) {
571 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
572 failures, failures > 1 ? "S" : "", hostname);
573 syslog(LOG_AUTHPRIV|LOG_NOTICE,
574 "%d LOGIN FAILURE%s FROM %s, %s",
575 failures, failures > 1 ? "S" : "", hostname, name);
576 } else {
577 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
578 failures, failures > 1 ? "S" : "", tty);
579 syslog(LOG_AUTHPRIV|LOG_NOTICE,
580 "%d LOGIN FAILURE%s ON %s, %s",
581 failures, failures > 1 ? "S" : "", tty, name);
582 }
583}
584
585#undef UNKNOWN
586#define UNKNOWN "su"
587
588char *
589stypeof(ttyid)
590 char *ttyid;
591{
592 struct ttyent *t;
593
594 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
595}
596
597void
598sleepexit(eval)
599 int eval;
600{
601
602 (void)sleep(5);
603 exit(eval);
604}
605
606void
607change_passwd()
608{
609 int pid, status, w;
610 register void (*istat)(), (*qstat)();
611
612 if (( pid=fork() ) == 0)
613 {
614 execl( "/usr/bin/passwd", "passwd", NULL );
615 fprintf( stderr, "ERROR: Can't execute passwd!\n" );
616 sleepexit( 1 );
617 }
618
619 istat = signal( SIGINT, SIG_IGN );
620 qstat = signal( SIGQUIT, SIG_IGN );
621
622 while ((w = wait( &status )) != pid && w != -1)
623 ;
624
625 signal( SIGINT, istat );
626 signal( SIGQUIT, qstat );
627}
628
461 (void)signal(SIGALRM, SIG_DFL);
462 (void)signal(SIGQUIT, SIG_DFL);
463 (void)signal(SIGINT, SIG_DFL);
464 (void)signal(SIGTSTP, SIG_IGN);
465
466 tbuf[0] = '-';
467 (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
468 p + 1 : pwd->pw_shell);
469
470 if (setlogin(pwd->pw_name) < 0)
471 syslog(LOG_ERR, "setlogin() failure: %m");
472
473 /* Discard permissions last so can't get killed and drop core. */
474 if (rootlogin)
475 (void) setuid(0);
476 else
477 (void) setuid(pwd->pw_uid);
478
479 execlp(pwd->pw_shell, tbuf, 0);
480 err(1, "%s", pwd->pw_shell);
481}
482
483#ifdef KERBEROS
484#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */
485#else
486#define NBUFSIZ (UT_NAMESIZE + 1)
487#endif
488
489void
490getloginname()
491{
492 int ch;
493 char *p;
494 static char nbuf[NBUFSIZ];
495
496 for (;;) {
497 (void)printf("login: ");
498 for (p = nbuf; (ch = getchar()) != '\n'; ) {
499 if (ch == EOF) {
500 badlogin(username);
501 exit(0);
502 }
503 if (p < nbuf + (NBUFSIZ - 1))
504 *p++ = ch;
505 }
506 if (p > nbuf)
507 if (nbuf[0] == '-')
508 (void)fprintf(stderr,
509 "login names may not start with '-'.\n");
510 else {
511 *p = '\0';
512 username = nbuf;
513 break;
514 }
515 }
516}
517
518int
519rootterm(ttyn)
520 char *ttyn;
521{
522 struct ttyent *t;
523
524 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
525}
526
527jmp_buf motdinterrupt;
528
529void
530motd()
531{
532 int fd, nchars;
533 sig_t oldint;
534 char tbuf[8192];
535
536 if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
537 return;
538 oldint = signal(SIGINT, sigint);
539 if (setjmp(motdinterrupt) == 0)
540 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
541 (void)write(fileno(stdout), tbuf, nchars);
542 (void)signal(SIGINT, oldint);
543 (void)close(fd);
544}
545
546/* ARGSUSED */
547void
548sigint(signo)
549 int signo;
550{
551
552 longjmp(motdinterrupt, 1);
553}
554
555/* ARGSUSED */
556void
557timedout(signo)
558 int signo;
559{
560
561 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
562 exit(0);
563}
564
565void
566checknologin()
567{
568 int fd, nchars;
569 char tbuf[8192];
570
571 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
572 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
573 (void)write(fileno(stdout), tbuf, nchars);
574 sleepexit(0);
575 }
576}
577
578void
579dolastlog(quiet)
580 int quiet;
581{
582 struct lastlog ll;
583 int fd;
584
585 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
586 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
587 if (!quiet) {
588 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
589 ll.ll_time != 0) {
590 (void)printf("Last login: %.*s ",
591 24-5, (char *)ctime(&ll.ll_time));
592 if (*ll.ll_host != '\0')
593 (void)printf("from %.*s\n",
594 (int)sizeof(ll.ll_host),
595 ll.ll_host);
596 else
597 (void)printf("on %.*s\n",
598 (int)sizeof(ll.ll_line),
599 ll.ll_line);
600 }
601 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
602 }
603 memset((void *)&ll, 0, sizeof(ll));
604 (void)time(&ll.ll_time);
605 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
606 if (hostname)
607 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
608 (void)write(fd, (char *)&ll, sizeof(ll));
609 (void)close(fd);
610 }
611}
612
613void
614badlogin(name)
615 char *name;
616{
617
618 if (failures == 0)
619 return;
620 if (hostname) {
621 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
622 failures, failures > 1 ? "S" : "", hostname);
623 syslog(LOG_AUTHPRIV|LOG_NOTICE,
624 "%d LOGIN FAILURE%s FROM %s, %s",
625 failures, failures > 1 ? "S" : "", hostname, name);
626 } else {
627 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
628 failures, failures > 1 ? "S" : "", tty);
629 syslog(LOG_AUTHPRIV|LOG_NOTICE,
630 "%d LOGIN FAILURE%s ON %s, %s",
631 failures, failures > 1 ? "S" : "", tty, name);
632 }
633}
634
635#undef UNKNOWN
636#define UNKNOWN "su"
637
638char *
639stypeof(ttyid)
640 char *ttyid;
641{
642 struct ttyent *t;
643
644 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
645}
646
647void
648sleepexit(eval)
649 int eval;
650{
651
652 (void)sleep(5);
653 exit(eval);
654}
655
656void
657change_passwd()
658{
659 int pid, status, w;
660 register void (*istat)(), (*qstat)();
661
662 if (( pid=fork() ) == 0)
663 {
664 execl( "/usr/bin/passwd", "passwd", NULL );
665 fprintf( stderr, "ERROR: Can't execute passwd!\n" );
666 sleepexit( 1 );
667 }
668
669 istat = signal( SIGINT, SIG_IGN );
670 qstat = signal( SIGQUIT, SIG_IGN );
671
672 while ((w = wait( &status )) != pid && w != -1)
673 ;
674
675 signal( SIGINT, istat );
676 signal( SIGQUIT, qstat );
677}
678