Deleted Added
full compact
login.c (33332) login.c (35557)
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#if 0
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
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
43#endif
44static const char rcsid[] =
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#if 0
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
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
43#endif
44static const char rcsid[] =
45 "$Id: login.c,v 1.31 1998/02/05 18:37:02 guido Exp $";
45 "$Id: login.c,v 1.32 1998/02/13 21:02:53 ache Exp $";
46#endif /* not lint */
47
48/*
49 * login [ name ]
50 * login -h hostname (for telnetd, etc.)
51 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
52 */
53
54#include <sys/copyright.h>
55#include <sys/param.h>
56#include <sys/stat.h>
57#include <sys/time.h>
58#include <sys/resource.h>
59#include <sys/file.h>
60#include <netinet/in.h>
61#include <arpa/inet.h>
62
63#include <err.h>
64#include <errno.h>
65#include <grp.h>
66#include <netdb.h>
67#include <pwd.h>
68#include <setjmp.h>
69#include <signal.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <syslog.h>
74#include <ttyent.h>
75#include <unistd.h>
76#include <utmp.h>
77
78#ifdef LOGIN_CAP
79#include <login_cap.h>
80#else /* Undef AUTH as well */
81#undef LOGIN_CAP_AUTH
82#endif
83
84/*
85 * If LOGIN_CAP_AUTH is activated:
86 * kerberose & skey logins are runtime selected via login
87 * login_getstyle() and authentication types for login classes
88 * The actual login itself is handled via /usr/libexec/login_<style>
89 * Valid styles are determined by the auth-type=style,style entries
90 * in the login class.
91 */
92#ifdef LOGIN_CAP_AUTH
93#undef KERBEROS
94#undef SKEY
95#endif /* LOGIN_CAP_AUTH */
96
97#ifdef SKEY
98#include <skey.h>
99#endif /* SKEY */
100
101#include "pathnames.h"
102
103void badlogin __P((char *));
104void checknologin __P((void));
105void dolastlog __P((int));
106void getloginname __P((void));
107void motd __P((char *));
108int rootterm __P((char *));
109void sigint __P((int));
110void sleepexit __P((int));
111void refused __P((char *,char *,int));
112char *stypeof __P((char *));
113void timedout __P((int));
114int login_access __P((char *, char *));
115void login_fbtab __P((char *, uid_t, gid_t));
116#ifdef KERBEROS
117int klogin __P((struct passwd *, char *, char *, char *));
118#endif
119
120extern void login __P((struct utmp *));
121static void usage __P((void));
122
123#define TTYGRPNAME "tty" /* name of group to own ttys */
124#define DEFAULT_BACKOFF 3
125#define DEFAULT_RETRIES 10
126
127/*
128 * This bounds the time given to login. Not a define so it can
129 * be patched on machines where it's too small.
130 */
131u_int timeout = 300;
132
133#ifdef KERBEROS
134int notickets = 1;
135int noticketsdontcomplain = 1;
136char *instance;
137char *krbtkfile_env;
138int authok;
139#endif
140
141struct passwd *pwd;
142int failures;
143char *term, *envinit[1], *hostname, *username, *tty;
144char full_hostname[MAXHOSTNAMELEN];
145
146int
147main(argc, argv)
148 int argc;
149 char *argv[];
150{
151 extern char **environ;
152 struct group *gr;
153 struct stat st;
154 struct timeval tp;
155 struct utmp utmp;
156 int rootok, retries, backoff;
157 int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
158 int changepass;
159 time_t warntime;
46#endif /* not lint */
47
48/*
49 * login [ name ]
50 * login -h hostname (for telnetd, etc.)
51 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
52 */
53
54#include <sys/copyright.h>
55#include <sys/param.h>
56#include <sys/stat.h>
57#include <sys/time.h>
58#include <sys/resource.h>
59#include <sys/file.h>
60#include <netinet/in.h>
61#include <arpa/inet.h>
62
63#include <err.h>
64#include <errno.h>
65#include <grp.h>
66#include <netdb.h>
67#include <pwd.h>
68#include <setjmp.h>
69#include <signal.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <syslog.h>
74#include <ttyent.h>
75#include <unistd.h>
76#include <utmp.h>
77
78#ifdef LOGIN_CAP
79#include <login_cap.h>
80#else /* Undef AUTH as well */
81#undef LOGIN_CAP_AUTH
82#endif
83
84/*
85 * If LOGIN_CAP_AUTH is activated:
86 * kerberose & skey logins are runtime selected via login
87 * login_getstyle() and authentication types for login classes
88 * The actual login itself is handled via /usr/libexec/login_<style>
89 * Valid styles are determined by the auth-type=style,style entries
90 * in the login class.
91 */
92#ifdef LOGIN_CAP_AUTH
93#undef KERBEROS
94#undef SKEY
95#endif /* LOGIN_CAP_AUTH */
96
97#ifdef SKEY
98#include <skey.h>
99#endif /* SKEY */
100
101#include "pathnames.h"
102
103void badlogin __P((char *));
104void checknologin __P((void));
105void dolastlog __P((int));
106void getloginname __P((void));
107void motd __P((char *));
108int rootterm __P((char *));
109void sigint __P((int));
110void sleepexit __P((int));
111void refused __P((char *,char *,int));
112char *stypeof __P((char *));
113void timedout __P((int));
114int login_access __P((char *, char *));
115void login_fbtab __P((char *, uid_t, gid_t));
116#ifdef KERBEROS
117int klogin __P((struct passwd *, char *, char *, char *));
118#endif
119
120extern void login __P((struct utmp *));
121static void usage __P((void));
122
123#define TTYGRPNAME "tty" /* name of group to own ttys */
124#define DEFAULT_BACKOFF 3
125#define DEFAULT_RETRIES 10
126
127/*
128 * This bounds the time given to login. Not a define so it can
129 * be patched on machines where it's too small.
130 */
131u_int timeout = 300;
132
133#ifdef KERBEROS
134int notickets = 1;
135int noticketsdontcomplain = 1;
136char *instance;
137char *krbtkfile_env;
138int authok;
139#endif
140
141struct passwd *pwd;
142int failures;
143char *term, *envinit[1], *hostname, *username, *tty;
144char full_hostname[MAXHOSTNAMELEN];
145
146int
147main(argc, argv)
148 int argc;
149 char *argv[];
150{
151 extern char **environ;
152 struct group *gr;
153 struct stat st;
154 struct timeval tp;
155 struct utmp utmp;
156 int rootok, retries, backoff;
157 int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
158 int changepass;
159 time_t warntime;
160 uid_t uid;
160 uid_t uid, eiud;
161 char *domain, *p, *ep, *salt, *ttyn;
162 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
163 char localhost[MAXHOSTNAMELEN];
164 char *shell = NULL;
165#ifdef LOGIN_CAP
166 login_cap_t *lc = NULL;
167#ifdef LOGIN_CAP_AUTH
168 char *style, *authtype;
169 char *auth_method = NULL;
170 char *instance = NULL;
171 int authok;
172#endif /* LOGIN_CAP_AUTH */
173#endif /* LOGIN_CAP */
174#ifdef SKEY
175 int permit_passwd = 0;
176#endif /* SKEY */
177
178 (void)signal(SIGALRM, timedout);
179 (void)alarm(timeout);
180 (void)signal(SIGQUIT, SIG_IGN);
181 (void)signal(SIGINT, SIG_IGN);
182 (void)setpriority(PRIO_PROCESS, 0, 0);
183
184 openlog("login", LOG_ODELAY, LOG_AUTH);
185
186 /*
187 * -p is used by getty to tell login not to destroy the environment
188 * -f is used to skip a second login authentication
189 * -h is used by other servers to pass the name of the remote
190 * host to login so that it may be placed in utmp and wtmp
191 */
192 *full_hostname = '\0';
193 domain = NULL;
194 term = NULL;
195 if (gethostname(localhost, sizeof(localhost)) < 0)
196 syslog(LOG_ERR, "couldn't get local hostname: %m");
197 else
198 domain = strchr(localhost, '.');
199
200 fflag = hflag = pflag = 0;
201 uid = getuid();
161 char *domain, *p, *ep, *salt, *ttyn;
162 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
163 char localhost[MAXHOSTNAMELEN];
164 char *shell = NULL;
165#ifdef LOGIN_CAP
166 login_cap_t *lc = NULL;
167#ifdef LOGIN_CAP_AUTH
168 char *style, *authtype;
169 char *auth_method = NULL;
170 char *instance = NULL;
171 int authok;
172#endif /* LOGIN_CAP_AUTH */
173#endif /* LOGIN_CAP */
174#ifdef SKEY
175 int permit_passwd = 0;
176#endif /* SKEY */
177
178 (void)signal(SIGALRM, timedout);
179 (void)alarm(timeout);
180 (void)signal(SIGQUIT, SIG_IGN);
181 (void)signal(SIGINT, SIG_IGN);
182 (void)setpriority(PRIO_PROCESS, 0, 0);
183
184 openlog("login", LOG_ODELAY, LOG_AUTH);
185
186 /*
187 * -p is used by getty to tell login not to destroy the environment
188 * -f is used to skip a second login authentication
189 * -h is used by other servers to pass the name of the remote
190 * host to login so that it may be placed in utmp and wtmp
191 */
192 *full_hostname = '\0';
193 domain = NULL;
194 term = NULL;
195 if (gethostname(localhost, sizeof(localhost)) < 0)
196 syslog(LOG_ERR, "couldn't get local hostname: %m");
197 else
198 domain = strchr(localhost, '.');
199
200 fflag = hflag = pflag = 0;
201 uid = getuid();
202 euid = geteuid();
202 while ((ch = getopt(argc, argv, "fh:p")) != -1)
203 switch (ch) {
204 case 'f':
205 fflag = 1;
206 break;
207 case 'h':
208 if (uid)
209 errx(1, "-h option: %s", strerror(EPERM));
210 hflag = 1;
211 strncpy(full_hostname, optarg, sizeof(full_hostname)-1);
212 if (domain && (p = strchr(optarg, '.')) &&
213 strcasecmp(p, domain) == 0)
214 *p = 0;
215 if (strlen(optarg) > UT_HOSTSIZE) {
216 struct hostent *hp = gethostbyname(optarg);
217
218 if (hp != NULL) {
219 struct in_addr in;
220
221 memmove(&in, hp->h_addr, sizeof(in));
222 optarg = strdup(inet_ntoa(in));
223 } else
224 optarg = "invalid hostname";
225 }
226 hostname = optarg;
227 break;
228 case 'p':
229 pflag = 1;
230 break;
231 case '?':
232 default:
233 if (!uid)
234 syslog(LOG_ERR, "invalid flag %c", ch);
235 usage();
236 }
237 argc -= optind;
238 argv += optind;
239
240 if (*argv) {
241 username = *argv;
242 ask = 0;
243 } else
244 ask = 1;
245
246 for (cnt = getdtablesize(); cnt > 2; cnt--)
247 (void)close(cnt);
248
249 ttyn = ttyname(STDIN_FILENO);
250 if (ttyn == NULL || *ttyn == '\0') {
251 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
252 ttyn = tname;
253 }
254 if ((tty = strrchr(ttyn, '/')) != NULL)
255 ++tty;
256 else
257 tty = ttyn;
258
259#ifdef LOGIN_CAP_AUTH
260 authtype = hostname ? "rlogin" : "login";
261#endif
262#ifdef LOGIN_CAP
263 /*
264 * Get "login-retries" & "login-backoff" from default class
265 */
266 lc = login_getclass(NULL);
267 retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, DEFAULT_RETRIES);
268 backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, DEFAULT_BACKOFF);
269 login_close(lc);
270 lc = NULL;
271#else
272 retries = DEFAULT_RETRIES;
273 backoff = DEFAULT_BACKOFF;
274#endif
275
276 for (cnt = 0;; ask = 1) {
277 if (ask) {
278 fflag = 0;
279 getloginname();
280 }
281 rootlogin = 0;
282 rootok = rootterm(tty); /* Default (auth may change) */
283#ifdef LOGIN_CAP_AUTH
284 authok = 0;
285 if (auth_method = strchr(username, ':')) {
286 *auth_method = '\0';
287 auth_method++;
288 if (*auth_method == '\0')
289 auth_method = NULL;
290 }
291 /*
292 * We need to do this regardless of whether
293 * kerberos is available.
294 */
295 if ((instance = strchr(username, '.')) != NULL) {
296 if (strncmp(instance, ".root", 5) == 0)
297 rootlogin = 1;
298 *instance++ = '\0';
299 } else
300 instance = "";
301#else /* !LOGIN_CAP_AUTH */
302#ifdef KERBEROS
303 if ((instance = strchr(username, '.')) != NULL) {
304 if (strncmp(instance, ".root", 5) == 0)
305 rootlogin = 1;
306 *instance++ = '\0';
307 } else
308 instance = "";
309#endif /* KERBEROS */
310#endif /* LOGIN_CAP_AUTH */
311
312 if (strlen(username) > UT_NAMESIZE)
313 username[UT_NAMESIZE] = '\0';
314
315 /*
316 * Note if trying multiple user names; log failures for
317 * previous user name, but don't bother logging one failure
318 * for nonexistent name (mistyped username).
319 */
320 if (failures && strcmp(tbuf, username)) {
321 if (failures > (pwd ? 0 : 1))
322 badlogin(tbuf);
323 failures = 0;
324 }
325 (void)strncpy(tbuf, username, sizeof tbuf-1);
326 tbuf[sizeof tbuf-1] = '\0';
327
328 if ((pwd = getpwnam(username)) != NULL)
329 salt = pwd->pw_passwd;
330 else
331 salt = "xx";
332
333#ifdef LOGIN_CAP
334 /*
335 * Establish the class now, before we might goto
336 * within the next block. pwd can be NULL since it
337 * falls back to the "default" class if it is.
338 */
203 while ((ch = getopt(argc, argv, "fh:p")) != -1)
204 switch (ch) {
205 case 'f':
206 fflag = 1;
207 break;
208 case 'h':
209 if (uid)
210 errx(1, "-h option: %s", strerror(EPERM));
211 hflag = 1;
212 strncpy(full_hostname, optarg, sizeof(full_hostname)-1);
213 if (domain && (p = strchr(optarg, '.')) &&
214 strcasecmp(p, domain) == 0)
215 *p = 0;
216 if (strlen(optarg) > UT_HOSTSIZE) {
217 struct hostent *hp = gethostbyname(optarg);
218
219 if (hp != NULL) {
220 struct in_addr in;
221
222 memmove(&in, hp->h_addr, sizeof(in));
223 optarg = strdup(inet_ntoa(in));
224 } else
225 optarg = "invalid hostname";
226 }
227 hostname = optarg;
228 break;
229 case 'p':
230 pflag = 1;
231 break;
232 case '?':
233 default:
234 if (!uid)
235 syslog(LOG_ERR, "invalid flag %c", ch);
236 usage();
237 }
238 argc -= optind;
239 argv += optind;
240
241 if (*argv) {
242 username = *argv;
243 ask = 0;
244 } else
245 ask = 1;
246
247 for (cnt = getdtablesize(); cnt > 2; cnt--)
248 (void)close(cnt);
249
250 ttyn = ttyname(STDIN_FILENO);
251 if (ttyn == NULL || *ttyn == '\0') {
252 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
253 ttyn = tname;
254 }
255 if ((tty = strrchr(ttyn, '/')) != NULL)
256 ++tty;
257 else
258 tty = ttyn;
259
260#ifdef LOGIN_CAP_AUTH
261 authtype = hostname ? "rlogin" : "login";
262#endif
263#ifdef LOGIN_CAP
264 /*
265 * Get "login-retries" & "login-backoff" from default class
266 */
267 lc = login_getclass(NULL);
268 retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, DEFAULT_RETRIES);
269 backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, DEFAULT_BACKOFF);
270 login_close(lc);
271 lc = NULL;
272#else
273 retries = DEFAULT_RETRIES;
274 backoff = DEFAULT_BACKOFF;
275#endif
276
277 for (cnt = 0;; ask = 1) {
278 if (ask) {
279 fflag = 0;
280 getloginname();
281 }
282 rootlogin = 0;
283 rootok = rootterm(tty); /* Default (auth may change) */
284#ifdef LOGIN_CAP_AUTH
285 authok = 0;
286 if (auth_method = strchr(username, ':')) {
287 *auth_method = '\0';
288 auth_method++;
289 if (*auth_method == '\0')
290 auth_method = NULL;
291 }
292 /*
293 * We need to do this regardless of whether
294 * kerberos is available.
295 */
296 if ((instance = strchr(username, '.')) != NULL) {
297 if (strncmp(instance, ".root", 5) == 0)
298 rootlogin = 1;
299 *instance++ = '\0';
300 } else
301 instance = "";
302#else /* !LOGIN_CAP_AUTH */
303#ifdef KERBEROS
304 if ((instance = strchr(username, '.')) != NULL) {
305 if (strncmp(instance, ".root", 5) == 0)
306 rootlogin = 1;
307 *instance++ = '\0';
308 } else
309 instance = "";
310#endif /* KERBEROS */
311#endif /* LOGIN_CAP_AUTH */
312
313 if (strlen(username) > UT_NAMESIZE)
314 username[UT_NAMESIZE] = '\0';
315
316 /*
317 * Note if trying multiple user names; log failures for
318 * previous user name, but don't bother logging one failure
319 * for nonexistent name (mistyped username).
320 */
321 if (failures && strcmp(tbuf, username)) {
322 if (failures > (pwd ? 0 : 1))
323 badlogin(tbuf);
324 failures = 0;
325 }
326 (void)strncpy(tbuf, username, sizeof tbuf-1);
327 tbuf[sizeof tbuf-1] = '\0';
328
329 if ((pwd = getpwnam(username)) != NULL)
330 salt = pwd->pw_passwd;
331 else
332 salt = "xx";
333
334#ifdef LOGIN_CAP
335 /*
336 * Establish the class now, before we might goto
337 * within the next block. pwd can be NULL since it
338 * falls back to the "default" class if it is.
339 */
340 if (pwd != NULL)
341 (void)seteuid(rootlogin ? 0 : pwd->pw_uid);
339 lc = login_getpwclass(pwd);
342 lc = login_getpwclass(pwd);
343 seteuid(euid);
340#endif /* LOGIN_CAP */
341
342 /*
343 * if we have a valid account name, and it doesn't have a
344 * password, or the -f option was specified and the caller
345 * is root or the caller isn't changing their uid, don't
346 * authenticate.
347 */
348 rval = 1;
349 if (pwd != NULL) {
350 if (pwd->pw_uid == 0)
351 rootlogin = 1;
352
353 if (fflag && (uid == (uid_t)0 ||
354 uid == (uid_t)pwd->pw_uid)) {
355 /* already authenticated */
356 break;
357 } else if (pwd->pw_passwd[0] == '\0') {
358 if (!rootlogin || rootok) {
359 /* pretend password okay */
360 rval = 0;
361 goto ttycheck;
362 }
363 }
364 }
365
366 fflag = 0;
367
368 (void)setpriority(PRIO_PROCESS, 0, -4);
369
370#ifdef LOGIN_CAP_AUTH
371 /*
372 * This hands off authorization to an authorization program,
373 * depending on the styles available for the "auth-login",
374 * auth-rlogin (or default) authorization styles.
375 * We do this regardless of whether an account exists so that
376 * the remote user cannot tell a "real" from an invented
377 * account name. If we don't have an account we just fall
378 * back to the first method for the "default" class.
379 */
380 if (!(style = login_getstyle(lc, auth_method, authtype))) {
381
382 /*
383 * No available authorization method
384 */
385 rval = 1;
386 (void)printf("No auth method available for %s.\n",
387 authtype);
388 } else {
389
390 /*
391 * Put back the kerberos instance, if any was given.
392 * Don't worry about the non-kerberos case here, since
393 * if kerberos is not available or not selected and an
394 * instance is given at the login prompt, su or rlogin -l,
395 * then anything else should fail as well.
396 */
397 if (*instance)
398 *(instance - 1) = '.';
399
400 rval = authenticate(username,
401 lc ? lc->lc_class : "default",
402 style, authtype);
403 /* Junk it again */
404 if (*instance)
405 *(instance - 1) = '\0';
406 }
407
408 if (!rval) {
409 char * approvp;
410
411 /*
412 * If authentication succeeds, run any approval
413 * program, if applicable for this class.
414 */
415 approvep = login_getcapstr(lc, "approve", NULL, NULL);
416 rval = 1; /* Assume bad login again */
417
418 if (approvep==NULL ||
419 auth_script(approvep, approvep, username,
420 lc->lc_class, 0) == 0) {
421 int r;
422
423 r = auth_scan(AUTH_OKAY);
424 /*
425 * See what the authorize program says
426 */
427 if (r != AUTH_NONE) {
428 rval = 0;
429
430 if (!rootok && (r & AUTH_ROOTOKAY))
431 rootok = 1; /* root approved */
432 else
433 rootlogin = 0;
434
435 if (!authok && (r & AUTH_SECURE))
436 authok = 1; /* secure */
437 }
438 }
439 }
440#else /* !LOGIN_CAP_AUTH */
441 (void)signal(SIGINT, SIG_DFL);
442 (void)signal(SIGQUIT, SIG_DFL);
443#ifdef SKEY
444 permit_passwd = skeyaccess(username, tty,
445 hostname ? full_hostname : NULL,
446 NULL);
447 p = skey_getpass("Password:", pwd, permit_passwd);
448 ep = skey_crypt(p, salt, pwd, permit_passwd);
449#else /* !SKEY */
450 p = getpass("Password:");
451 ep = crypt(p, salt);
452#endif/* SKEY */
453 (void)signal(SIGINT, SIG_IGN);
454 (void)signal(SIGQUIT, SIG_IGN);
455
456 if (pwd) {
457 if (!p[0] && pwd->pw_passwd[0])
458 ep = ":";
459#ifdef KERBEROS
460#ifdef SKEY
461 /*
462 * Do not allow user to type in kerberos password
463 * over the net (actually, this is ok for encrypted
464 * links, but we have no way of determining if the
465 * link is encrypted.
466 */
467 if (!permit_passwd) {
468 rval = 1; /* failed */
469 } else
470#endif /* SKEY */
471 rval = klogin(pwd, instance, localhost, p);
472 if (rval != 0 && rootlogin && pwd->pw_uid != 0)
473 rootlogin = 0;
474 if (rval == 0)
475 authok = 1; /* kerberos authenticated ok */
476 else if (rval == 1) /* fallback to unix passwd */
477 rval = strcmp(ep, pwd->pw_passwd);
478#else /* !KERBEROS */
479 rval = strcmp(ep, pwd->pw_passwd);
480#endif /* KERBEROS */
481 }
482
483 /* clear entered password */
484 memset(p, 0, strlen(p));
485#endif /* LOGIN_CAP_AUTH */
486
487 (void)setpriority(PRIO_PROCESS, 0, 0);
488
489#ifdef LOGIN_CAP_AUTH
490 if (rval)
491 auth_rmfiles();
492#endif
493 ttycheck:
494 /*
495 * If trying to log in as root without Kerberos,
496 * but with insecure terminal, refuse the login attempt.
497 */
498 if (pwd && !rval) {
499#if defined(KERBEROS) || defined(LOGIN_CAP_AUTH)
500 if (authok == 0 && rootlogin && !rootok)
501#else
502 if (rootlogin && !rootok)
503#endif
504 refused(NULL, "NOROOT", 0);
505 else /* valid password & authenticated */
506 break;
507 }
508
509 (void)printf("Login incorrect\n");
510 failures++;
511
512 /*
513 * we allow up to 'retry' (10) tries,
514 * but after 'backoff' (3) we start backing off
515 */
516 if (++cnt > backoff) {
517 if (cnt >= retries) {
518 badlogin(username);
519 sleepexit(1);
520 }
521 sleep((u_int)((cnt - 3) * 5));
522 }
523 }
524
525 /* committed to login -- turn off timeout */
526 (void)alarm((u_int)0);
527
528 endpwent();
529
530 /* if user not super-user, check for disabled logins */
531#ifdef LOGIN_CAP
532 if (!rootlogin)
533 auth_checknologin(lc);
534#else
535 if (!rootlogin)
536 checknologin();
537#endif
538
539#ifdef LOGIN_CAP
540 quietlog = login_getcapbool(lc, "hushlogin", 0);
541#else
542 quietlog = 0;
543#endif
344#endif /* LOGIN_CAP */
345
346 /*
347 * if we have a valid account name, and it doesn't have a
348 * password, or the -f option was specified and the caller
349 * is root or the caller isn't changing their uid, don't
350 * authenticate.
351 */
352 rval = 1;
353 if (pwd != NULL) {
354 if (pwd->pw_uid == 0)
355 rootlogin = 1;
356
357 if (fflag && (uid == (uid_t)0 ||
358 uid == (uid_t)pwd->pw_uid)) {
359 /* already authenticated */
360 break;
361 } else if (pwd->pw_passwd[0] == '\0') {
362 if (!rootlogin || rootok) {
363 /* pretend password okay */
364 rval = 0;
365 goto ttycheck;
366 }
367 }
368 }
369
370 fflag = 0;
371
372 (void)setpriority(PRIO_PROCESS, 0, -4);
373
374#ifdef LOGIN_CAP_AUTH
375 /*
376 * This hands off authorization to an authorization program,
377 * depending on the styles available for the "auth-login",
378 * auth-rlogin (or default) authorization styles.
379 * We do this regardless of whether an account exists so that
380 * the remote user cannot tell a "real" from an invented
381 * account name. If we don't have an account we just fall
382 * back to the first method for the "default" class.
383 */
384 if (!(style = login_getstyle(lc, auth_method, authtype))) {
385
386 /*
387 * No available authorization method
388 */
389 rval = 1;
390 (void)printf("No auth method available for %s.\n",
391 authtype);
392 } else {
393
394 /*
395 * Put back the kerberos instance, if any was given.
396 * Don't worry about the non-kerberos case here, since
397 * if kerberos is not available or not selected and an
398 * instance is given at the login prompt, su or rlogin -l,
399 * then anything else should fail as well.
400 */
401 if (*instance)
402 *(instance - 1) = '.';
403
404 rval = authenticate(username,
405 lc ? lc->lc_class : "default",
406 style, authtype);
407 /* Junk it again */
408 if (*instance)
409 *(instance - 1) = '\0';
410 }
411
412 if (!rval) {
413 char * approvp;
414
415 /*
416 * If authentication succeeds, run any approval
417 * program, if applicable for this class.
418 */
419 approvep = login_getcapstr(lc, "approve", NULL, NULL);
420 rval = 1; /* Assume bad login again */
421
422 if (approvep==NULL ||
423 auth_script(approvep, approvep, username,
424 lc->lc_class, 0) == 0) {
425 int r;
426
427 r = auth_scan(AUTH_OKAY);
428 /*
429 * See what the authorize program says
430 */
431 if (r != AUTH_NONE) {
432 rval = 0;
433
434 if (!rootok && (r & AUTH_ROOTOKAY))
435 rootok = 1; /* root approved */
436 else
437 rootlogin = 0;
438
439 if (!authok && (r & AUTH_SECURE))
440 authok = 1; /* secure */
441 }
442 }
443 }
444#else /* !LOGIN_CAP_AUTH */
445 (void)signal(SIGINT, SIG_DFL);
446 (void)signal(SIGQUIT, SIG_DFL);
447#ifdef SKEY
448 permit_passwd = skeyaccess(username, tty,
449 hostname ? full_hostname : NULL,
450 NULL);
451 p = skey_getpass("Password:", pwd, permit_passwd);
452 ep = skey_crypt(p, salt, pwd, permit_passwd);
453#else /* !SKEY */
454 p = getpass("Password:");
455 ep = crypt(p, salt);
456#endif/* SKEY */
457 (void)signal(SIGINT, SIG_IGN);
458 (void)signal(SIGQUIT, SIG_IGN);
459
460 if (pwd) {
461 if (!p[0] && pwd->pw_passwd[0])
462 ep = ":";
463#ifdef KERBEROS
464#ifdef SKEY
465 /*
466 * Do not allow user to type in kerberos password
467 * over the net (actually, this is ok for encrypted
468 * links, but we have no way of determining if the
469 * link is encrypted.
470 */
471 if (!permit_passwd) {
472 rval = 1; /* failed */
473 } else
474#endif /* SKEY */
475 rval = klogin(pwd, instance, localhost, p);
476 if (rval != 0 && rootlogin && pwd->pw_uid != 0)
477 rootlogin = 0;
478 if (rval == 0)
479 authok = 1; /* kerberos authenticated ok */
480 else if (rval == 1) /* fallback to unix passwd */
481 rval = strcmp(ep, pwd->pw_passwd);
482#else /* !KERBEROS */
483 rval = strcmp(ep, pwd->pw_passwd);
484#endif /* KERBEROS */
485 }
486
487 /* clear entered password */
488 memset(p, 0, strlen(p));
489#endif /* LOGIN_CAP_AUTH */
490
491 (void)setpriority(PRIO_PROCESS, 0, 0);
492
493#ifdef LOGIN_CAP_AUTH
494 if (rval)
495 auth_rmfiles();
496#endif
497 ttycheck:
498 /*
499 * If trying to log in as root without Kerberos,
500 * but with insecure terminal, refuse the login attempt.
501 */
502 if (pwd && !rval) {
503#if defined(KERBEROS) || defined(LOGIN_CAP_AUTH)
504 if (authok == 0 && rootlogin && !rootok)
505#else
506 if (rootlogin && !rootok)
507#endif
508 refused(NULL, "NOROOT", 0);
509 else /* valid password & authenticated */
510 break;
511 }
512
513 (void)printf("Login incorrect\n");
514 failures++;
515
516 /*
517 * we allow up to 'retry' (10) tries,
518 * but after 'backoff' (3) we start backing off
519 */
520 if (++cnt > backoff) {
521 if (cnt >= retries) {
522 badlogin(username);
523 sleepexit(1);
524 }
525 sleep((u_int)((cnt - 3) * 5));
526 }
527 }
528
529 /* committed to login -- turn off timeout */
530 (void)alarm((u_int)0);
531
532 endpwent();
533
534 /* if user not super-user, check for disabled logins */
535#ifdef LOGIN_CAP
536 if (!rootlogin)
537 auth_checknologin(lc);
538#else
539 if (!rootlogin)
540 checknologin();
541#endif
542
543#ifdef LOGIN_CAP
544 quietlog = login_getcapbool(lc, "hushlogin", 0);
545#else
546 quietlog = 0;
547#endif
548 (void)seteuid(rootlogin ? 0 : pwd->pw_uid);
544 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
545#ifdef LOGIN_CAP
546 if (login_getcapbool(lc, "requirehome", 0))
547 refused("Home directory not available", "HOMEDIR", 1);
548#endif
549 if (chdir("/") < 0)
550 refused("Cannot find root directory", "ROOTDIR", 1);
551 pwd->pw_dir = "/";
552 if (!quietlog || *pwd->pw_dir)
553 printf("No home directory.\nLogging in with home = \"/\".\n");
554 }
549 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
550#ifdef LOGIN_CAP
551 if (login_getcapbool(lc, "requirehome", 0))
552 refused("Home directory not available", "HOMEDIR", 1);
553#endif
554 if (chdir("/") < 0)
555 refused("Cannot find root directory", "ROOTDIR", 1);
556 pwd->pw_dir = "/";
557 if (!quietlog || *pwd->pw_dir)
558 printf("No home directory.\nLogging in with home = \"/\".\n");
559 }
560 (void)seteuid(euid);
555 if (!quietlog)
556 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
557
558 if (pwd->pw_change || pwd->pw_expire)
559 (void)gettimeofday(&tp, (struct timezone *)NULL);
560
561#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
562
563#ifdef LOGIN_CAP
564 warntime = login_getcaptime(lc, "warnpassword",
565 DEFAULT_WARN, DEFAULT_WARN);
566#else
567 warntime = DEFAULT_WARN;
568#endif
569
570 changepass=0;
571 if (pwd->pw_change) {
572 if (tp.tv_sec >= pwd->pw_change) {
573 (void)printf("Sorry -- your password has expired.\n");
574 changepass=1;
575 syslog(LOG_INFO,
576 "%s Password expired - forcing change",
577 pwd->pw_name);
578 } else if (pwd->pw_change - tp.tv_sec < warntime && !quietlog)
579 (void)printf("Warning: your password expires on %s",
580 ctime(&pwd->pw_change));
581 }
582
583#ifdef LOGIN_CAP
584 warntime = login_getcaptime(lc, "warnexpire",
585 DEFAULT_WARN, DEFAULT_WARN);
586#else
587 warntime = DEFAULT_WARN;
588#endif
589
590 if (pwd->pw_expire) {
591 if (tp.tv_sec >= pwd->pw_expire) {
592 refused("Sorry -- your account has expired",
593 "EXPIRED", 1);
594 } else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog)
595 (void)printf("Warning: your account expires on %s",
596 ctime(&pwd->pw_expire));
597 }
598
599#ifdef LOGIN_CAP
600 if (lc != NULL) {
601 if (hostname) {
602 struct hostent *hp = gethostbyname(full_hostname);
603
604 if (hp == NULL)
605 optarg = NULL;
606 else {
607 struct in_addr in;
608 memmove(&in, hp->h_addr, sizeof(in));
609 optarg = strdup(inet_ntoa(in));
610 }
611 if (!auth_hostok(lc, full_hostname, optarg))
612 refused("Permission denied", "HOST", 1);
613 }
614
615 if (!auth_ttyok(lc, tty))
616 refused("Permission denied", "TTY", 1);
617
618 if (!auth_timeok(lc, time(NULL)))
619 refused("Logins not available right now", "TIME", 1);
620 }
621 shell=login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
622#else /* !LOGIN_CAP */
623 shell=pwd->pw_shell;
624#endif /* LOGIN_CAP */
625 if (*pwd->pw_shell == '\0')
626 pwd->pw_shell = _PATH_BSHELL;
627 if (*shell == '\0') /* Not overridden */
628 shell = pwd->pw_shell;
629 if ((shell = strdup(shell)) == NULL) {
630 syslog(LOG_NOTICE, "memory allocation error");
631 sleepexit(1);
632 }
633
634#ifdef LOGIN_ACCESS
635 if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0)
636 refused("Permission denied", "ACCESS", 1);
637#endif /* LOGIN_ACCESS */
638
639 /* Nothing else left to fail -- really log in. */
640 memset((void *)&utmp, 0, sizeof(utmp));
641 (void)time(&utmp.ut_time);
642 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
643 if (hostname)
644 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
645 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
646 login(&utmp);
647
648 dolastlog(quietlog);
649
650 /*
651 * Set device protections, depending on what terminal the
652 * user is logged in. This feature is used on Suns to give
653 * console users better privacy.
654 */
655 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
656
657 (void)chown(ttyn, pwd->pw_uid,
658 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
659
660 /*
661 * Preserve TERM if it happens to be already set.
662 */
663 if ((term = getenv("TERM")) != NULL)
664 term = strdup(term);
665
666 /*
667 * Exclude cons/vt/ptys only, assume dialup otherwise
668 * TODO: Make dialup tty determination a library call
669 * for consistency (finger etc.)
670 */
671 if (hostname==NULL && isdialuptty(tty))
672 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
673
674#ifdef KERBEROS
675 if (!quietlog && notickets == 1 && !noticketsdontcomplain)
676 (void)printf("Warning: no Kerberos tickets issued.\n");
677#endif
678
679#ifdef LOGALL
680 /*
681 * Syslog each successful login, so we don't have to watch hundreds
682 * of wtmp or lastlogin files.
683 */
684 if (hostname)
685 syslog(LOG_INFO, "login from %s on %s as %s",
686 full_hostname, tty, pwd->pw_name);
687 else
688 syslog(LOG_INFO, "login on %s as %s",
689 tty, pwd->pw_name);
690#endif
691
692 /*
693 * If fflag is on, assume caller/authenticator has logged root login.
694 */
695 if (rootlogin && fflag == 0)
696 {
697 if (hostname)
698 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
699 username, tty, full_hostname);
700 else
701 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
702 username, tty);
703 }
704
705 /*
706 * Destroy environment unless user has requested its preservation.
707 * We need to do this before setusercontext() because that may
708 * set or reset some environment variables.
709 */
710 if (!pflag)
711 environ = envinit;
712
713 /*
714 * We don't need to be root anymore, so
715 * set the user and session context
716 */
717#ifdef LOGIN_CAP
718 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) {
719 syslog(LOG_ERR, "setusercontext() failed - exiting");
720 exit(1);
721 }
722#else
723 if (setlogin(pwd->pw_name) < 0)
724 syslog(LOG_ERR, "setlogin() failure: %m");
725
726 (void)setgid(pwd->pw_gid);
727 initgroups(username, pwd->pw_gid);
728 (void)setuid(rootlogin ? 0 : pwd->pw_uid);
729#endif
730
731 (void)setenv("SHELL", pwd->pw_shell, 1);
732 (void)setenv("HOME", pwd->pw_dir, 1);
733 if (term != NULL && *term != '\0')
734 (void)setenv("TERM", term, 1); /* Preset overrides */
735 else {
736 (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */
737 }
738 (void)setenv("LOGNAME", pwd->pw_name, 1);
739 (void)setenv("USER", pwd->pw_name, 1);
740 (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
741#ifdef KERBEROS
742 if (krbtkfile_env)
743 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
744#endif
745#if LOGIN_CAP_AUTH
746 auth_env();
747#endif
748
749#ifdef LOGIN_CAP
750 if (!quietlog) {
751 char *cw;
752
753 cw = login_getcapstr(lc, "copyright", NULL, NULL);
754 if (cw != NULL && access(cw, F_OK) == 0)
755 motd(cw);
756 else
757 (void)printf("%s\n\t%s %s\n",
758 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
759 "The Regents of the University of California. ",
760 "All rights reserved.");
761
762 (void)printf("\n");
763
764 cw = login_getcapstr(lc, "welcome", NULL, NULL);
765 if (cw == NULL || access(cw, F_OK) != 0)
766 cw = _PATH_MOTDFILE;
767 motd(cw);
768
769 cw = getenv("MAIL"); /* $MAIL may have been set by class */
770 if (cw != NULL) {
771 strncpy(tbuf, cw, sizeof(tbuf));
772 tbuf[sizeof(tbuf)-1] = '\0';
773 } else
774 snprintf(tbuf, sizeof(tbuf), "%s/%s",
775 _PATH_MAILDIR, pwd->pw_name);
776#else
777 if (!quietlog) {
778 (void)printf("%s\n\t%s %s\n",
779 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
780 "The Regents of the University of California. ",
781 "All rights reserved.");
782 motd(_PATH_MOTDFILE);
783 snprintf(tbuf, sizeof(tbuf), "%s/%s",
784 _PATH_MAILDIR, pwd->pw_name);
785#endif
786 if (stat(tbuf, &st) == 0 && st.st_size != 0)
787 (void)printf("You have %smail.\n",
788 (st.st_mtime > st.st_atime) ? "new " : "");
789 }
790
791#ifdef LOGIN_CAP
792 login_close(lc);
793#endif
794
795 (void)signal(SIGALRM, SIG_DFL);
796 (void)signal(SIGQUIT, SIG_DFL);
797 (void)signal(SIGINT, SIG_DFL);
798 (void)signal(SIGTSTP, SIG_IGN);
799
800 if (changepass) {
801 if (system(_PATH_CHPASS) != 0)
802 sleepexit(1);
803 }
804
805 /*
806 * Login shells have a leading '-' in front of argv[0]
807 */
808 tbuf[0] = '-';
809 (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell);
810
811 execlp(shell, tbuf, 0);
812 err(1, "%s", shell);
813}
814
815static void
816usage()
817{
818 (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
819 exit(1);
820}
821
822/*
823 * Allow for authentication style and/or kerberos instance
824 * */
825
826#define NBUFSIZ UT_NAMESIZE + 64
827
828void
829getloginname()
830{
831 int ch;
832 char *p;
833 static char nbuf[NBUFSIZ];
834
835 for (;;) {
836 (void)printf("login: ");
837 for (p = nbuf; (ch = getchar()) != '\n'; ) {
838 if (ch == EOF) {
839 badlogin(username);
840 exit(0);
841 }
842 if (p < nbuf + (NBUFSIZ - 1))
843 *p++ = ch;
844 }
845 if (p > nbuf)
846 if (nbuf[0] == '-')
847 (void)fprintf(stderr,
848 "login names may not start with '-'.\n");
849 else {
850 *p = '\0';
851 username = nbuf;
852 break;
853 }
854 }
855}
856
857int
858rootterm(ttyn)
859 char *ttyn;
860{
861 struct ttyent *t;
862
863 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
864}
865
866volatile int motdinterrupt;
867
868/* ARGSUSED */
869void
870sigint(signo)
871 int signo;
872{
873 motdinterrupt = 1;
874}
875
876void
877motd(motdfile)
878 char *motdfile;
879{
880 int fd, nchars;
881 sig_t oldint;
882 char tbuf[256];
883
884 if ((fd = open(motdfile, O_RDONLY, 0)) < 0)
885 return;
886 motdinterrupt = 0;
887 oldint = signal(SIGINT, sigint);
888 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt)
889 (void)write(fileno(stdout), tbuf, nchars);
890 (void)signal(SIGINT, oldint);
891 (void)close(fd);
892}
893
894/* ARGSUSED */
895void
896timedout(signo)
897 int signo;
898{
899 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
900 exit(0);
901}
902
903#ifndef LOGIN_CAP
904void
905checknologin()
906{
907 int fd, nchars;
908 char tbuf[8192];
909
910 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
911 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
912 (void)write(fileno(stdout), tbuf, nchars);
913 sleepexit(0);
914 }
915}
916#endif
917
918void
919dolastlog(quiet)
920 int quiet;
921{
922 struct lastlog ll;
923 int fd;
924
925 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
926 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
927 if (!quiet) {
928 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
929 ll.ll_time != 0) {
930 (void)printf("Last login: %.*s ",
931 24-5, (char *)ctime(&ll.ll_time));
932 if (*ll.ll_host != '\0')
933 (void)printf("from %.*s\n",
934 (int)sizeof(ll.ll_host),
935 ll.ll_host);
936 else
937 (void)printf("on %.*s\n",
938 (int)sizeof(ll.ll_line),
939 ll.ll_line);
940 }
941 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
942 }
943 memset((void *)&ll, 0, sizeof(ll));
944 (void)time(&ll.ll_time);
945 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
946 if (hostname)
947 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
948 (void)write(fd, (char *)&ll, sizeof(ll));
949 (void)close(fd);
950 }
951}
952
953void
954badlogin(name)
955 char *name;
956{
957
958 if (failures == 0)
959 return;
960 if (hostname) {
961 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
962 failures, failures > 1 ? "S" : "", full_hostname);
963 syslog(LOG_AUTHPRIV|LOG_NOTICE,
964 "%d LOGIN FAILURE%s FROM %s, %s",
965 failures, failures > 1 ? "S" : "", full_hostname, name);
966 } else {
967 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
968 failures, failures > 1 ? "S" : "", tty);
969 syslog(LOG_AUTHPRIV|LOG_NOTICE,
970 "%d LOGIN FAILURE%s ON %s, %s",
971 failures, failures > 1 ? "S" : "", tty, name);
972 }
973}
974
975#undef UNKNOWN
976#define UNKNOWN "su"
977
978char *
979stypeof(ttyid)
980 char *ttyid;
981{
982
983 struct ttyent *t;
984
985 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
986}
987
988void
989refused(msg, rtype, lout)
990 char *msg;
991 char *rtype;
992 int lout;
993{
994
995 if (msg != NULL)
996 printf("%s.\n", msg);
997 if (hostname)
998 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
999 pwd->pw_name, rtype, full_hostname, tty);
1000 else
1001 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
1002 pwd->pw_name, rtype, tty);
1003 if (lout)
1004 sleepexit(1);
1005}
1006
1007void
1008sleepexit(eval)
1009 int eval;
1010{
1011
1012 (void)sleep(5);
1013 exit(eval);
1014}
561 if (!quietlog)
562 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
563
564 if (pwd->pw_change || pwd->pw_expire)
565 (void)gettimeofday(&tp, (struct timezone *)NULL);
566
567#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
568
569#ifdef LOGIN_CAP
570 warntime = login_getcaptime(lc, "warnpassword",
571 DEFAULT_WARN, DEFAULT_WARN);
572#else
573 warntime = DEFAULT_WARN;
574#endif
575
576 changepass=0;
577 if (pwd->pw_change) {
578 if (tp.tv_sec >= pwd->pw_change) {
579 (void)printf("Sorry -- your password has expired.\n");
580 changepass=1;
581 syslog(LOG_INFO,
582 "%s Password expired - forcing change",
583 pwd->pw_name);
584 } else if (pwd->pw_change - tp.tv_sec < warntime && !quietlog)
585 (void)printf("Warning: your password expires on %s",
586 ctime(&pwd->pw_change));
587 }
588
589#ifdef LOGIN_CAP
590 warntime = login_getcaptime(lc, "warnexpire",
591 DEFAULT_WARN, DEFAULT_WARN);
592#else
593 warntime = DEFAULT_WARN;
594#endif
595
596 if (pwd->pw_expire) {
597 if (tp.tv_sec >= pwd->pw_expire) {
598 refused("Sorry -- your account has expired",
599 "EXPIRED", 1);
600 } else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog)
601 (void)printf("Warning: your account expires on %s",
602 ctime(&pwd->pw_expire));
603 }
604
605#ifdef LOGIN_CAP
606 if (lc != NULL) {
607 if (hostname) {
608 struct hostent *hp = gethostbyname(full_hostname);
609
610 if (hp == NULL)
611 optarg = NULL;
612 else {
613 struct in_addr in;
614 memmove(&in, hp->h_addr, sizeof(in));
615 optarg = strdup(inet_ntoa(in));
616 }
617 if (!auth_hostok(lc, full_hostname, optarg))
618 refused("Permission denied", "HOST", 1);
619 }
620
621 if (!auth_ttyok(lc, tty))
622 refused("Permission denied", "TTY", 1);
623
624 if (!auth_timeok(lc, time(NULL)))
625 refused("Logins not available right now", "TIME", 1);
626 }
627 shell=login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
628#else /* !LOGIN_CAP */
629 shell=pwd->pw_shell;
630#endif /* LOGIN_CAP */
631 if (*pwd->pw_shell == '\0')
632 pwd->pw_shell = _PATH_BSHELL;
633 if (*shell == '\0') /* Not overridden */
634 shell = pwd->pw_shell;
635 if ((shell = strdup(shell)) == NULL) {
636 syslog(LOG_NOTICE, "memory allocation error");
637 sleepexit(1);
638 }
639
640#ifdef LOGIN_ACCESS
641 if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0)
642 refused("Permission denied", "ACCESS", 1);
643#endif /* LOGIN_ACCESS */
644
645 /* Nothing else left to fail -- really log in. */
646 memset((void *)&utmp, 0, sizeof(utmp));
647 (void)time(&utmp.ut_time);
648 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
649 if (hostname)
650 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
651 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
652 login(&utmp);
653
654 dolastlog(quietlog);
655
656 /*
657 * Set device protections, depending on what terminal the
658 * user is logged in. This feature is used on Suns to give
659 * console users better privacy.
660 */
661 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
662
663 (void)chown(ttyn, pwd->pw_uid,
664 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
665
666 /*
667 * Preserve TERM if it happens to be already set.
668 */
669 if ((term = getenv("TERM")) != NULL)
670 term = strdup(term);
671
672 /*
673 * Exclude cons/vt/ptys only, assume dialup otherwise
674 * TODO: Make dialup tty determination a library call
675 * for consistency (finger etc.)
676 */
677 if (hostname==NULL && isdialuptty(tty))
678 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
679
680#ifdef KERBEROS
681 if (!quietlog && notickets == 1 && !noticketsdontcomplain)
682 (void)printf("Warning: no Kerberos tickets issued.\n");
683#endif
684
685#ifdef LOGALL
686 /*
687 * Syslog each successful login, so we don't have to watch hundreds
688 * of wtmp or lastlogin files.
689 */
690 if (hostname)
691 syslog(LOG_INFO, "login from %s on %s as %s",
692 full_hostname, tty, pwd->pw_name);
693 else
694 syslog(LOG_INFO, "login on %s as %s",
695 tty, pwd->pw_name);
696#endif
697
698 /*
699 * If fflag is on, assume caller/authenticator has logged root login.
700 */
701 if (rootlogin && fflag == 0)
702 {
703 if (hostname)
704 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
705 username, tty, full_hostname);
706 else
707 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
708 username, tty);
709 }
710
711 /*
712 * Destroy environment unless user has requested its preservation.
713 * We need to do this before setusercontext() because that may
714 * set or reset some environment variables.
715 */
716 if (!pflag)
717 environ = envinit;
718
719 /*
720 * We don't need to be root anymore, so
721 * set the user and session context
722 */
723#ifdef LOGIN_CAP
724 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) {
725 syslog(LOG_ERR, "setusercontext() failed - exiting");
726 exit(1);
727 }
728#else
729 if (setlogin(pwd->pw_name) < 0)
730 syslog(LOG_ERR, "setlogin() failure: %m");
731
732 (void)setgid(pwd->pw_gid);
733 initgroups(username, pwd->pw_gid);
734 (void)setuid(rootlogin ? 0 : pwd->pw_uid);
735#endif
736
737 (void)setenv("SHELL", pwd->pw_shell, 1);
738 (void)setenv("HOME", pwd->pw_dir, 1);
739 if (term != NULL && *term != '\0')
740 (void)setenv("TERM", term, 1); /* Preset overrides */
741 else {
742 (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */
743 }
744 (void)setenv("LOGNAME", pwd->pw_name, 1);
745 (void)setenv("USER", pwd->pw_name, 1);
746 (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
747#ifdef KERBEROS
748 if (krbtkfile_env)
749 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
750#endif
751#if LOGIN_CAP_AUTH
752 auth_env();
753#endif
754
755#ifdef LOGIN_CAP
756 if (!quietlog) {
757 char *cw;
758
759 cw = login_getcapstr(lc, "copyright", NULL, NULL);
760 if (cw != NULL && access(cw, F_OK) == 0)
761 motd(cw);
762 else
763 (void)printf("%s\n\t%s %s\n",
764 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
765 "The Regents of the University of California. ",
766 "All rights reserved.");
767
768 (void)printf("\n");
769
770 cw = login_getcapstr(lc, "welcome", NULL, NULL);
771 if (cw == NULL || access(cw, F_OK) != 0)
772 cw = _PATH_MOTDFILE;
773 motd(cw);
774
775 cw = getenv("MAIL"); /* $MAIL may have been set by class */
776 if (cw != NULL) {
777 strncpy(tbuf, cw, sizeof(tbuf));
778 tbuf[sizeof(tbuf)-1] = '\0';
779 } else
780 snprintf(tbuf, sizeof(tbuf), "%s/%s",
781 _PATH_MAILDIR, pwd->pw_name);
782#else
783 if (!quietlog) {
784 (void)printf("%s\n\t%s %s\n",
785 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
786 "The Regents of the University of California. ",
787 "All rights reserved.");
788 motd(_PATH_MOTDFILE);
789 snprintf(tbuf, sizeof(tbuf), "%s/%s",
790 _PATH_MAILDIR, pwd->pw_name);
791#endif
792 if (stat(tbuf, &st) == 0 && st.st_size != 0)
793 (void)printf("You have %smail.\n",
794 (st.st_mtime > st.st_atime) ? "new " : "");
795 }
796
797#ifdef LOGIN_CAP
798 login_close(lc);
799#endif
800
801 (void)signal(SIGALRM, SIG_DFL);
802 (void)signal(SIGQUIT, SIG_DFL);
803 (void)signal(SIGINT, SIG_DFL);
804 (void)signal(SIGTSTP, SIG_IGN);
805
806 if (changepass) {
807 if (system(_PATH_CHPASS) != 0)
808 sleepexit(1);
809 }
810
811 /*
812 * Login shells have a leading '-' in front of argv[0]
813 */
814 tbuf[0] = '-';
815 (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell);
816
817 execlp(shell, tbuf, 0);
818 err(1, "%s", shell);
819}
820
821static void
822usage()
823{
824 (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
825 exit(1);
826}
827
828/*
829 * Allow for authentication style and/or kerberos instance
830 * */
831
832#define NBUFSIZ UT_NAMESIZE + 64
833
834void
835getloginname()
836{
837 int ch;
838 char *p;
839 static char nbuf[NBUFSIZ];
840
841 for (;;) {
842 (void)printf("login: ");
843 for (p = nbuf; (ch = getchar()) != '\n'; ) {
844 if (ch == EOF) {
845 badlogin(username);
846 exit(0);
847 }
848 if (p < nbuf + (NBUFSIZ - 1))
849 *p++ = ch;
850 }
851 if (p > nbuf)
852 if (nbuf[0] == '-')
853 (void)fprintf(stderr,
854 "login names may not start with '-'.\n");
855 else {
856 *p = '\0';
857 username = nbuf;
858 break;
859 }
860 }
861}
862
863int
864rootterm(ttyn)
865 char *ttyn;
866{
867 struct ttyent *t;
868
869 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
870}
871
872volatile int motdinterrupt;
873
874/* ARGSUSED */
875void
876sigint(signo)
877 int signo;
878{
879 motdinterrupt = 1;
880}
881
882void
883motd(motdfile)
884 char *motdfile;
885{
886 int fd, nchars;
887 sig_t oldint;
888 char tbuf[256];
889
890 if ((fd = open(motdfile, O_RDONLY, 0)) < 0)
891 return;
892 motdinterrupt = 0;
893 oldint = signal(SIGINT, sigint);
894 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt)
895 (void)write(fileno(stdout), tbuf, nchars);
896 (void)signal(SIGINT, oldint);
897 (void)close(fd);
898}
899
900/* ARGSUSED */
901void
902timedout(signo)
903 int signo;
904{
905 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
906 exit(0);
907}
908
909#ifndef LOGIN_CAP
910void
911checknologin()
912{
913 int fd, nchars;
914 char tbuf[8192];
915
916 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
917 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
918 (void)write(fileno(stdout), tbuf, nchars);
919 sleepexit(0);
920 }
921}
922#endif
923
924void
925dolastlog(quiet)
926 int quiet;
927{
928 struct lastlog ll;
929 int fd;
930
931 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
932 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
933 if (!quiet) {
934 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
935 ll.ll_time != 0) {
936 (void)printf("Last login: %.*s ",
937 24-5, (char *)ctime(&ll.ll_time));
938 if (*ll.ll_host != '\0')
939 (void)printf("from %.*s\n",
940 (int)sizeof(ll.ll_host),
941 ll.ll_host);
942 else
943 (void)printf("on %.*s\n",
944 (int)sizeof(ll.ll_line),
945 ll.ll_line);
946 }
947 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
948 }
949 memset((void *)&ll, 0, sizeof(ll));
950 (void)time(&ll.ll_time);
951 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
952 if (hostname)
953 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
954 (void)write(fd, (char *)&ll, sizeof(ll));
955 (void)close(fd);
956 }
957}
958
959void
960badlogin(name)
961 char *name;
962{
963
964 if (failures == 0)
965 return;
966 if (hostname) {
967 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
968 failures, failures > 1 ? "S" : "", full_hostname);
969 syslog(LOG_AUTHPRIV|LOG_NOTICE,
970 "%d LOGIN FAILURE%s FROM %s, %s",
971 failures, failures > 1 ? "S" : "", full_hostname, name);
972 } else {
973 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
974 failures, failures > 1 ? "S" : "", tty);
975 syslog(LOG_AUTHPRIV|LOG_NOTICE,
976 "%d LOGIN FAILURE%s ON %s, %s",
977 failures, failures > 1 ? "S" : "", tty, name);
978 }
979}
980
981#undef UNKNOWN
982#define UNKNOWN "su"
983
984char *
985stypeof(ttyid)
986 char *ttyid;
987{
988
989 struct ttyent *t;
990
991 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
992}
993
994void
995refused(msg, rtype, lout)
996 char *msg;
997 char *rtype;
998 int lout;
999{
1000
1001 if (msg != NULL)
1002 printf("%s.\n", msg);
1003 if (hostname)
1004 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
1005 pwd->pw_name, rtype, full_hostname, tty);
1006 else
1007 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
1008 pwd->pw_name, rtype, tty);
1009 if (lout)
1010 sleepexit(1);
1011}
1012
1013void
1014sleepexit(eval)
1015 int eval;
1016{
1017
1018 (void)sleep(5);
1019 exit(eval);
1020}