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