login.c revision 1.46 1 1.46 aidan /* $NetBSD: login.c,v 1.46 1999/12/05 23:39:11 aidan 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.46 aidan __RCSID("$NetBSD: login.c,v 1.46 1999/12/05 23:39:11 aidan 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.38 mrg #include <sys/wait.h>
62 1.1 cgd
63 1.12 jtc #include <err.h>
64 1.5 cgd #include <errno.h>
65 1.1 cgd #include <grp.h>
66 1.1 cgd #include <pwd.h>
67 1.12 jtc #include <setjmp.h>
68 1.12 jtc #include <signal.h>
69 1.19 veego #include <stdio.h>
70 1.5 cgd #include <stdlib.h>
71 1.1 cgd #include <string.h>
72 1.12 jtc #include <syslog.h>
73 1.36 kleink #include <time.h>
74 1.12 jtc #include <ttyent.h>
75 1.12 jtc #include <tzfile.h>
76 1.12 jtc #include <unistd.h>
77 1.12 jtc #include <utmp.h>
78 1.13 jtc #include <util.h>
79 1.29 mycroft #ifdef SKEY
80 1.29 mycroft #include <skey.h>
81 1.29 mycroft #endif
82 1.25 mycroft #ifdef KERBEROS5
83 1.45 christos #include <krb5/krb5.h>
84 1.45 christos #include <kerberosIV/com_err.h>
85 1.25 mycroft #endif
86 1.25 mycroft
87 1.1 cgd #include "pathnames.h"
88 1.1 cgd
89 1.5 cgd void badlogin __P((char *));
90 1.5 cgd void checknologin __P((void));
91 1.5 cgd void dolastlog __P((int));
92 1.5 cgd void getloginname __P((void));
93 1.24 lukem int main __P((int, char *[]));
94 1.5 cgd void motd __P((void));
95 1.5 cgd int rootterm __P((char *));
96 1.5 cgd void sigint __P((int));
97 1.5 cgd void sleepexit __P((int));
98 1.39 mycroft const char *stypeof __P((const char *));
99 1.5 cgd void timedout __P((int));
100 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
101 1.5 cgd int klogin __P((struct passwd *, char *, char *, char *));
102 1.12 jtc void kdestroy __P((void));
103 1.12 jtc void dofork __P((void));
104 1.5 cgd #endif
105 1.44 aidan #ifdef KERBEROS5
106 1.44 aidan int k5_read_creds __P((char*));
107 1.44 aidan int k5_write_creds __P((void));
108 1.44 aidan #endif
109 1.12 jtc
110 1.1 cgd #define TTYGRPNAME "tty" /* name of group to own ttys */
111 1.1 cgd
112 1.1 cgd /*
113 1.1 cgd * This bounds the time given to login. Not a define so it can
114 1.1 cgd * be patched on machines where it's too small.
115 1.1 cgd */
116 1.12 jtc u_int timeout = 300;
117 1.5 cgd
118 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
119 1.1 cgd int notickets = 1;
120 1.1 cgd char *instance;
121 1.12 jtc char *krbtkfile_env;
122 1.1 cgd #endif
123 1.25 mycroft #ifdef KERBEROS5
124 1.25 mycroft extern krb5_context kcontext;
125 1.44 aidan extern int have_forward;
126 1.46 aidan extern int use_krb5;
127 1.25 mycroft #endif
128 1.1 cgd
129 1.1 cgd struct passwd *pwd;
130 1.1 cgd int failures;
131 1.1 cgd char term[64], *envinit[1], *hostname, *username, *tty;
132 1.1 cgd
133 1.34 thorpej static const char copyrightstr[] = "\
134 1.41 lukem Copyright (c) 1996, 1997, 1998, 1999
135 1.34 thorpej \tThe NetBSD Foundation, Inc. All rights reserved.
136 1.34 thorpej Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
137 1.34 thorpej \tThe Regents of the University of California. All rights reserved.\n\n";
138 1.34 thorpej
139 1.5 cgd int
140 1.1 cgd main(argc, argv)
141 1.1 cgd int argc;
142 1.5 cgd char *argv[];
143 1.1 cgd {
144 1.5 cgd extern char **environ;
145 1.5 cgd struct group *gr;
146 1.5 cgd struct stat st;
147 1.5 cgd struct timeval tp;
148 1.5 cgd struct utmp utmp;
149 1.29 mycroft int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
150 1.44 aidan int Fflag;
151 1.33 hubertf uid_t uid, saved_uid;
152 1.35 hubertf gid_t saved_gid, saved_gids[NGROUPS_MAX];
153 1.35 hubertf int nsaved_gids;
154 1.39 mycroft char *domain, *p, *ttyn, *pwprompt;
155 1.39 mycroft const char *salt;
156 1.1 cgd char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
157 1.37 mrg char localhost[MAXHOSTNAMELEN + 1];
158 1.29 mycroft int need_chpass, require_chpass;
159 1.25 mycroft #ifdef KERBEROS5
160 1.25 mycroft krb5_error_code kerror;
161 1.25 mycroft #endif
162 1.1 cgd
163 1.20 lukem tbuf[0] = '\0';
164 1.20 lukem rval = 0;
165 1.20 lukem pwprompt = NULL;
166 1.29 mycroft need_chpass = require_chpass = 0;
167 1.20 lukem
168 1.1 cgd (void)signal(SIGALRM, timedout);
169 1.12 jtc (void)alarm(timeout);
170 1.1 cgd (void)signal(SIGQUIT, SIG_IGN);
171 1.1 cgd (void)signal(SIGINT, SIG_IGN);
172 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, 0);
173 1.1 cgd
174 1.1 cgd openlog("login", LOG_ODELAY, LOG_AUTH);
175 1.1 cgd
176 1.1 cgd /*
177 1.1 cgd * -p is used by getty to tell login not to destroy the environment
178 1.5 cgd * -f is used to skip a second login authentication
179 1.1 cgd * -h is used by other servers to pass the name of the remote
180 1.1 cgd * host to login so that it may be placed in utmp and wtmp
181 1.20 lukem * -s is used to force use of S/Key or equivalent.
182 1.1 cgd */
183 1.1 cgd domain = NULL;
184 1.1 cgd if (gethostname(localhost, sizeof(localhost)) < 0)
185 1.1 cgd syslog(LOG_ERR, "couldn't get local hostname: %m");
186 1.1 cgd else
187 1.12 jtc domain = strchr(localhost, '.');
188 1.37 mrg localhost[sizeof(localhost) - 1] = '\0';
189 1.1 cgd
190 1.44 aidan Fflag = fflag = hflag = pflag = sflag = 0;
191 1.44 aidan #ifdef KERBEROS5
192 1.44 aidan have_forward = 0;
193 1.46 aidan use_krb5 = 1;
194 1.44 aidan #endif
195 1.1 cgd uid = getuid();
196 1.44 aidan while ((ch = getopt(argc, argv, "Ffh:ps")) != -1)
197 1.1 cgd switch (ch) {
198 1.44 aidan case 'F':
199 1.44 aidan Fflag = 1;
200 1.44 aidan /* FALLTHROUGH */
201 1.1 cgd case 'f':
202 1.1 cgd fflag = 1;
203 1.1 cgd break;
204 1.1 cgd case 'h':
205 1.12 jtc if (uid)
206 1.12 jtc errx(1, "-h option: %s", strerror(EPERM));
207 1.1 cgd hflag = 1;
208 1.23 mikel if (domain && (p = strchr(optarg, '.')) != NULL &&
209 1.1 cgd strcasecmp(p, domain) == 0)
210 1.1 cgd *p = 0;
211 1.1 cgd hostname = optarg;
212 1.1 cgd break;
213 1.1 cgd case 'p':
214 1.1 cgd pflag = 1;
215 1.1 cgd break;
216 1.20 lukem case 's':
217 1.29 mycroft sflag = 1;
218 1.20 lukem break;
219 1.29 mycroft default:
220 1.1 cgd case '?':
221 1.1 cgd (void)fprintf(stderr,
222 1.29 mycroft "usage: login [-fps] [-h hostname] [username]\n");
223 1.1 cgd exit(1);
224 1.1 cgd }
225 1.1 cgd argc -= optind;
226 1.1 cgd argv += optind;
227 1.5 cgd
228 1.1 cgd if (*argv) {
229 1.1 cgd username = *argv;
230 1.1 cgd ask = 0;
231 1.1 cgd } else
232 1.1 cgd ask = 1;
233 1.1 cgd
234 1.1 cgd for (cnt = getdtablesize(); cnt > 2; cnt--)
235 1.5 cgd (void)close(cnt);
236 1.1 cgd
237 1.5 cgd ttyn = ttyname(STDIN_FILENO);
238 1.1 cgd if (ttyn == NULL || *ttyn == '\0') {
239 1.5 cgd (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
240 1.1 cgd ttyn = tname;
241 1.1 cgd }
242 1.23 mikel if ((tty = strrchr(ttyn, '/')) != NULL)
243 1.1 cgd ++tty;
244 1.1 cgd else
245 1.1 cgd tty = ttyn;
246 1.25 mycroft
247 1.25 mycroft #ifdef KERBEROS5
248 1.25 mycroft kerror = krb5_init_context(&kcontext);
249 1.25 mycroft if (kerror) {
250 1.25 mycroft syslog(LOG_NOTICE, "%s when initializing Kerberos context",
251 1.25 mycroft error_message(kerror));
252 1.46 aidan use_krb5 = 0;
253 1.25 mycroft }
254 1.25 mycroft #endif KERBEROS5
255 1.1 cgd
256 1.1 cgd for (cnt = 0;; ask = 1) {
257 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
258 1.10 brezak kdestroy();
259 1.10 brezak #endif
260 1.1 cgd if (ask) {
261 1.1 cgd fflag = 0;
262 1.1 cgd getloginname();
263 1.1 cgd }
264 1.5 cgd rootlogin = 0;
265 1.29 mycroft #ifdef KERBEROS
266 1.29 mycroft if ((instance = strchr(username, '.')) != NULL)
267 1.1 cgd *instance++ = '\0';
268 1.29 mycroft else
269 1.1 cgd instance = "";
270 1.1 cgd #endif
271 1.10 brezak #ifdef KERBEROS5
272 1.29 mycroft if ((instance = strchr(username, '/')) != NULL)
273 1.10 brezak *instance++ = '\0';
274 1.29 mycroft else
275 1.10 brezak instance = "";
276 1.10 brezak #endif
277 1.16 sommerfe if (strlen(username) > MAXLOGNAME)
278 1.16 sommerfe username[MAXLOGNAME] = '\0';
279 1.1 cgd
280 1.1 cgd /*
281 1.1 cgd * Note if trying multiple user names; log failures for
282 1.1 cgd * previous user name, but don't bother logging one failure
283 1.1 cgd * for nonexistent name (mistyped username).
284 1.1 cgd */
285 1.1 cgd if (failures && strcmp(tbuf, username)) {
286 1.1 cgd if (failures > (pwd ? 0 : 1))
287 1.1 cgd badlogin(tbuf);
288 1.1 cgd failures = 0;
289 1.1 cgd }
290 1.17 mrg (void)strncpy(tbuf, username, sizeof(tbuf) - 1);
291 1.38 mrg tbuf[sizeof(tbuf) - 1] = '\0';
292 1.1 cgd
293 1.23 mikel if ((pwd = getpwnam(username)) != NULL)
294 1.1 cgd salt = pwd->pw_passwd;
295 1.1 cgd else
296 1.1 cgd salt = "xx";
297 1.1 cgd
298 1.1 cgd /*
299 1.1 cgd * if we have a valid account name, and it doesn't have a
300 1.1 cgd * password, or the -f option was specified and the caller
301 1.1 cgd * is root or the caller isn't changing their uid, don't
302 1.1 cgd * authenticate.
303 1.1 cgd */
304 1.7 mycroft if (pwd) {
305 1.7 mycroft if (pwd->pw_uid == 0)
306 1.7 mycroft rootlogin = 1;
307 1.7 mycroft
308 1.8 mycroft if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
309 1.7 mycroft /* already authenticated */
310 1.44 aidan #ifdef KERBEROS5
311 1.44 aidan if (Fflag)
312 1.44 aidan k5_read_creds(username);
313 1.44 aidan #endif
314 1.7 mycroft break;
315 1.7 mycroft } else if (pwd->pw_passwd[0] == '\0') {
316 1.7 mycroft /* pretend password okay */
317 1.7 mycroft rval = 0;
318 1.7 mycroft goto ttycheck;
319 1.7 mycroft }
320 1.7 mycroft }
321 1.7 mycroft
322 1.1 cgd fflag = 0;
323 1.1 cgd
324 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, -4);
325 1.1 cgd
326 1.27 mycroft #ifdef SKEY
327 1.29 mycroft if (skey_haskey(username) == 0) {
328 1.29 mycroft static char skprompt[80];
329 1.29 mycroft char *skinfo = skey_keyinfo(username);
330 1.20 lukem
331 1.29 mycroft (void)snprintf(skprompt, sizeof(skprompt)-1,
332 1.29 mycroft "Password [%s]:",
333 1.29 mycroft skinfo ? skinfo : "error getting challenge");
334 1.29 mycroft pwprompt = skprompt;
335 1.29 mycroft } else
336 1.27 mycroft #endif
337 1.29 mycroft pwprompt = "Password:";
338 1.27 mycroft
339 1.29 mycroft p = getpass(pwprompt);
340 1.1 cgd
341 1.29 mycroft if (pwd == NULL) {
342 1.29 mycroft rval = 1;
343 1.29 mycroft goto skip;
344 1.29 mycroft }
345 1.29 mycroft #ifdef KERBEROS
346 1.29 mycroft if (klogin(pwd, instance, localhost, p) == 0) {
347 1.29 mycroft rval = 0;
348 1.29 mycroft goto skip;
349 1.29 mycroft }
350 1.1 cgd #endif
351 1.29 mycroft #ifdef KERBEROS5
352 1.29 mycroft if (klogin(pwd, instance, localhost, p) == 0) {
353 1.29 mycroft rval = 0;
354 1.29 mycroft goto skip;
355 1.1 cgd }
356 1.29 mycroft #endif
357 1.20 lukem #ifdef SKEY
358 1.29 mycroft if (skey_haskey(username) == 0 &&
359 1.29 mycroft skey_passcheck(username, p) != -1) {
360 1.29 mycroft rval = 0;
361 1.29 mycroft goto skip;
362 1.29 mycroft }
363 1.20 lukem #endif
364 1.29 mycroft if (!sflag && *pwd->pw_passwd != '\0' &&
365 1.29 mycroft !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
366 1.29 mycroft rval = 0;
367 1.29 mycroft require_chpass = 1;
368 1.29 mycroft goto skip;
369 1.29 mycroft }
370 1.29 mycroft rval = 1;
371 1.29 mycroft
372 1.29 mycroft skip:
373 1.29 mycroft memset(p, 0, strlen(p));
374 1.1 cgd
375 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, 0);
376 1.1 cgd
377 1.7 mycroft ttycheck:
378 1.1 cgd /*
379 1.1 cgd * If trying to log in as root without Kerberos,
380 1.1 cgd * but with insecure terminal, refuse the login attempt.
381 1.1 cgd */
382 1.7 mycroft if (pwd && !rval && rootlogin && !rootterm(tty)) {
383 1.1 cgd (void)fprintf(stderr,
384 1.1 cgd "%s login refused on this terminal.\n",
385 1.1 cgd pwd->pw_name);
386 1.1 cgd if (hostname)
387 1.1 cgd syslog(LOG_NOTICE,
388 1.1 cgd "LOGIN %s REFUSED FROM %s ON TTY %s",
389 1.1 cgd pwd->pw_name, hostname, tty);
390 1.1 cgd else
391 1.1 cgd syslog(LOG_NOTICE,
392 1.1 cgd "LOGIN %s REFUSED ON TTY %s",
393 1.1 cgd pwd->pw_name, tty);
394 1.1 cgd continue;
395 1.1 cgd }
396 1.1 cgd
397 1.1 cgd if (pwd && !rval)
398 1.1 cgd break;
399 1.1 cgd
400 1.1 cgd (void)printf("Login incorrect\n");
401 1.1 cgd failures++;
402 1.1 cgd /* we allow 10 tries, but after 3 we start backing off */
403 1.1 cgd if (++cnt > 3) {
404 1.1 cgd if (cnt >= 10) {
405 1.1 cgd badlogin(username);
406 1.1 cgd sleepexit(1);
407 1.1 cgd }
408 1.1 cgd sleep((u_int)((cnt - 3) * 5));
409 1.1 cgd }
410 1.1 cgd }
411 1.1 cgd
412 1.1 cgd /* committed to login -- turn off timeout */
413 1.1 cgd (void)alarm((u_int)0);
414 1.1 cgd
415 1.1 cgd endpwent();
416 1.1 cgd
417 1.1 cgd /* if user not super-user, check for disabled logins */
418 1.1 cgd if (!rootlogin)
419 1.1 cgd checknologin();
420 1.1 cgd
421 1.33 hubertf /* Temporarily give up special privileges so we can change */
422 1.33 hubertf /* into NFS-mounted homes that are exported for non-root */
423 1.33 hubertf /* access and have mode 7x0 */
424 1.33 hubertf saved_uid = geteuid();
425 1.35 hubertf saved_gid = getegid();
426 1.35 hubertf nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
427 1.35 hubertf
428 1.35 hubertf (void)setegid(pwd->pw_gid);
429 1.35 hubertf initgroups(username, pwd->pw_gid);
430 1.35 hubertf (void)seteuid(pwd->pw_uid);
431 1.33 hubertf
432 1.1 cgd if (chdir(pwd->pw_dir) < 0) {
433 1.1 cgd (void)printf("No home directory %s!\n", pwd->pw_dir);
434 1.1 cgd if (chdir("/"))
435 1.1 cgd exit(0);
436 1.1 cgd pwd->pw_dir = "/";
437 1.1 cgd (void)printf("Logging in with home = \"/\".\n");
438 1.1 cgd }
439 1.1 cgd
440 1.1 cgd quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
441 1.33 hubertf
442 1.33 hubertf /* regain special privileges */
443 1.33 hubertf (void)seteuid(saved_uid);
444 1.35 hubertf setgroups(nsaved_gids, saved_gids);
445 1.35 hubertf (void)setegid(saved_gid);
446 1.1 cgd
447 1.1 cgd if (pwd->pw_change || pwd->pw_expire)
448 1.1 cgd (void)gettimeofday(&tp, (struct timezone *)NULL);
449 1.40 ross if (pwd->pw_expire) {
450 1.1 cgd if (tp.tv_sec >= pwd->pw_expire) {
451 1.1 cgd (void)printf("Sorry -- your account has expired.\n");
452 1.1 cgd sleepexit(1);
453 1.1 cgd } else if (pwd->pw_expire - tp.tv_sec <
454 1.21 lukem _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
455 1.1 cgd (void)printf("Warning: your account expires on %s",
456 1.1 cgd ctime(&pwd->pw_expire));
457 1.40 ross }
458 1.40 ross if (pwd->pw_change) {
459 1.30 mycroft if (pwd->pw_change == _PASSWORD_CHGNOW)
460 1.30 mycroft need_chpass = 1;
461 1.31 mycroft else if (tp.tv_sec >= pwd->pw_change) {
462 1.31 mycroft (void)printf("Sorry -- your password has expired.\n");
463 1.31 mycroft sleepexit(1);
464 1.31 mycroft } else if (pwd->pw_change - tp.tv_sec <
465 1.30 mycroft _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
466 1.30 mycroft (void)printf("Warning: your password expires on %s",
467 1.30 mycroft ctime(&pwd->pw_change));
468 1.1 cgd
469 1.40 ross }
470 1.5 cgd /* Nothing else left to fail -- really log in. */
471 1.12 jtc memset((void *)&utmp, 0, sizeof(utmp));
472 1.5 cgd (void)time(&utmp.ut_time);
473 1.5 cgd (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
474 1.5 cgd if (hostname)
475 1.5 cgd (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
476 1.5 cgd (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
477 1.5 cgd login(&utmp);
478 1.1 cgd
479 1.1 cgd dolastlog(quietlog);
480 1.1 cgd
481 1.1 cgd (void)chown(ttyn, pwd->pw_uid,
482 1.1 cgd (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
483 1.15 gwr
484 1.15 gwr if (ttyaction(ttyn, "login", pwd->pw_name))
485 1.15 gwr (void)printf("Warning: ttyaction failed.\n");
486 1.15 gwr
487 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
488 1.10 brezak /* Fork so that we can call kdestroy */
489 1.10 brezak if (krbtkfile_env)
490 1.29 mycroft dofork();
491 1.10 brezak #endif
492 1.1 cgd (void)setgid(pwd->pw_gid);
493 1.1 cgd
494 1.1 cgd initgroups(username, pwd->pw_gid);
495 1.1 cgd
496 1.1 cgd if (*pwd->pw_shell == '\0')
497 1.1 cgd pwd->pw_shell = _PATH_BSHELL;
498 1.1 cgd
499 1.5 cgd /* Destroy environment unless user has requested its preservation. */
500 1.1 cgd if (!pflag)
501 1.1 cgd environ = envinit;
502 1.1 cgd (void)setenv("HOME", pwd->pw_dir, 1);
503 1.1 cgd (void)setenv("SHELL", pwd->pw_shell, 1);
504 1.1 cgd if (term[0] == '\0')
505 1.5 cgd (void)strncpy(term, stypeof(tty), sizeof(term));
506 1.1 cgd (void)setenv("TERM", term, 0);
507 1.1 cgd (void)setenv("LOGNAME", pwd->pw_name, 1);
508 1.1 cgd (void)setenv("USER", pwd->pw_name, 1);
509 1.1 cgd (void)setenv("PATH", _PATH_DEFPATH, 0);
510 1.1 cgd #ifdef KERBEROS
511 1.1 cgd if (krbtkfile_env)
512 1.1 cgd (void)setenv("KRBTKFILE", krbtkfile_env, 1);
513 1.1 cgd #endif
514 1.10 brezak #ifdef KERBEROS5
515 1.10 brezak if (krbtkfile_env)
516 1.10 brezak (void)setenv("KRB5CCNAME", krbtkfile_env, 1);
517 1.10 brezak #endif
518 1.1 cgd
519 1.12 jtc if (tty[sizeof("tty")-1] == 'd')
520 1.12 jtc syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
521 1.12 jtc
522 1.5 cgd /* If fflag is on, assume caller/authenticator has logged root login. */
523 1.40 ross if (rootlogin && fflag == 0) {
524 1.1 cgd if (hostname)
525 1.1 cgd syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
526 1.1 cgd username, tty, hostname);
527 1.1 cgd else
528 1.40 ross syslog(LOG_NOTICE,
529 1.40 ross "ROOT LOGIN (%s) ON %s", username, tty);
530 1.40 ross }
531 1.1 cgd
532 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
533 1.1 cgd if (!quietlog && notickets == 1)
534 1.1 cgd (void)printf("Warning: no Kerberos tickets issued.\n");
535 1.1 cgd #endif
536 1.1 cgd
537 1.1 cgd if (!quietlog) {
538 1.34 thorpej (void)printf(copyrightstr);
539 1.1 cgd motd();
540 1.5 cgd (void)snprintf(tbuf,
541 1.5 cgd sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
542 1.1 cgd if (stat(tbuf, &st) == 0 && st.st_size != 0)
543 1.1 cgd (void)printf("You have %smail.\n",
544 1.1 cgd (st.st_mtime > st.st_atime) ? "new " : "");
545 1.1 cgd }
546 1.1 cgd
547 1.1 cgd (void)signal(SIGALRM, SIG_DFL);
548 1.1 cgd (void)signal(SIGQUIT, SIG_DFL);
549 1.1 cgd (void)signal(SIGINT, SIG_DFL);
550 1.1 cgd (void)signal(SIGTSTP, SIG_IGN);
551 1.1 cgd
552 1.1 cgd tbuf[0] = '-';
553 1.17 mrg (void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
554 1.17 mrg p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
555 1.1 cgd
556 1.1 cgd if (setlogin(pwd->pw_name) < 0)
557 1.1 cgd syslog(LOG_ERR, "setlogin() failure: %m");
558 1.1 cgd
559 1.5 cgd /* Discard permissions last so can't get killed and drop core. */
560 1.1 cgd if (rootlogin)
561 1.24 lukem (void)setuid(0);
562 1.1 cgd else
563 1.24 lukem (void)setuid(pwd->pw_uid);
564 1.24 lukem
565 1.24 lukem /* Wait to change password until we're unprivileged */
566 1.24 lukem if (need_chpass) {
567 1.29 mycroft if (!require_chpass)
568 1.24 lukem (void)printf(
569 1.24 lukem "Warning: your password has expired. Please change it as soon as possible.\n");
570 1.29 mycroft else {
571 1.38 mrg int status;
572 1.38 mrg
573 1.29 mycroft (void)printf(
574 1.24 lukem "Your password has expired. Please choose a new one.\n");
575 1.38 mrg switch (fork()) {
576 1.38 mrg case -1:
577 1.38 mrg warn("fork");
578 1.29 mycroft sleepexit(1);
579 1.38 mrg case 0:
580 1.38 mrg execl(_PATH_BINPASSWD, "passwd", 0);
581 1.38 mrg _exit(1);
582 1.38 mrg default:
583 1.38 mrg if (wait(&status) == -1 ||
584 1.38 mrg WEXITSTATUS(status))
585 1.38 mrg sleepexit(1);
586 1.38 mrg }
587 1.29 mycroft }
588 1.24 lukem }
589 1.1 cgd
590 1.44 aidan #ifdef KERBEROS5
591 1.44 aidan k5_write_creds();
592 1.44 aidan #endif
593 1.1 cgd execlp(pwd->pw_shell, tbuf, 0);
594 1.12 jtc err(1, "%s", pwd->pw_shell);
595 1.1 cgd }
596 1.1 cgd
597 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
598 1.16 sommerfe #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
599 1.1 cgd #else
600 1.16 sommerfe #define NBUFSIZ (MAXLOGNAME + 1)
601 1.10 brezak #endif
602 1.10 brezak
603 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
604 1.10 brezak /*
605 1.10 brezak * This routine handles cleanup stuff, and the like.
606 1.10 brezak * It exists only in the child process.
607 1.10 brezak */
608 1.10 brezak #include <sys/wait.h>
609 1.10 brezak void
610 1.10 brezak dofork()
611 1.10 brezak {
612 1.38 mrg int child;
613 1.38 mrg
614 1.38 mrg if (!(child = fork()))
615 1.38 mrg return; /* Child process */
616 1.38 mrg
617 1.38 mrg /* Setup stuff? This would be things we could do in parallel with login */
618 1.38 mrg (void) chdir("/"); /* Let's not keep the fs busy... */
619 1.10 brezak
620 1.38 mrg /* If we're the parent, watch the child until it dies */
621 1.38 mrg while (wait(0) != child)
622 1.38 mrg ;
623 1.10 brezak
624 1.38 mrg /* Cleanup stuff */
625 1.38 mrg /* Run kdestroy to destroy tickets */
626 1.38 mrg kdestroy();
627 1.10 brezak
628 1.38 mrg /* Leave */
629 1.38 mrg exit(0);
630 1.10 brezak }
631 1.1 cgd #endif
632 1.1 cgd
633 1.5 cgd void
634 1.1 cgd getloginname()
635 1.1 cgd {
636 1.12 jtc int ch;
637 1.12 jtc char *p;
638 1.1 cgd static char nbuf[NBUFSIZ];
639 1.1 cgd
640 1.1 cgd for (;;) {
641 1.1 cgd (void)printf("login: ");
642 1.1 cgd for (p = nbuf; (ch = getchar()) != '\n'; ) {
643 1.1 cgd if (ch == EOF) {
644 1.1 cgd badlogin(username);
645 1.1 cgd exit(0);
646 1.1 cgd }
647 1.1 cgd if (p < nbuf + (NBUFSIZ - 1))
648 1.1 cgd *p++ = ch;
649 1.1 cgd }
650 1.40 ross if (p > nbuf) {
651 1.1 cgd if (nbuf[0] == '-')
652 1.1 cgd (void)fprintf(stderr,
653 1.1 cgd "login names may not start with '-'.\n");
654 1.1 cgd else {
655 1.1 cgd *p = '\0';
656 1.1 cgd username = nbuf;
657 1.1 cgd break;
658 1.1 cgd }
659 1.40 ross }
660 1.1 cgd }
661 1.1 cgd }
662 1.1 cgd
663 1.5 cgd int
664 1.1 cgd rootterm(ttyn)
665 1.1 cgd char *ttyn;
666 1.1 cgd {
667 1.1 cgd struct ttyent *t;
668 1.1 cgd
669 1.12 jtc return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
670 1.1 cgd }
671 1.1 cgd
672 1.1 cgd jmp_buf motdinterrupt;
673 1.1 cgd
674 1.5 cgd void
675 1.1 cgd motd()
676 1.1 cgd {
677 1.12 jtc int fd, nchars;
678 1.1 cgd sig_t oldint;
679 1.1 cgd char tbuf[8192];
680 1.1 cgd
681 1.1 cgd if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
682 1.1 cgd return;
683 1.1 cgd oldint = signal(SIGINT, sigint);
684 1.1 cgd if (setjmp(motdinterrupt) == 0)
685 1.1 cgd while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
686 1.1 cgd (void)write(fileno(stdout), tbuf, nchars);
687 1.1 cgd (void)signal(SIGINT, oldint);
688 1.1 cgd (void)close(fd);
689 1.1 cgd }
690 1.1 cgd
691 1.5 cgd /* ARGSUSED */
692 1.1 cgd void
693 1.5 cgd sigint(signo)
694 1.5 cgd int signo;
695 1.1 cgd {
696 1.38 mrg
697 1.1 cgd longjmp(motdinterrupt, 1);
698 1.1 cgd }
699 1.1 cgd
700 1.5 cgd /* ARGSUSED */
701 1.5 cgd void
702 1.5 cgd timedout(signo)
703 1.5 cgd int signo;
704 1.5 cgd {
705 1.38 mrg
706 1.5 cgd (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
707 1.5 cgd exit(0);
708 1.5 cgd }
709 1.5 cgd
710 1.5 cgd void
711 1.1 cgd checknologin()
712 1.1 cgd {
713 1.12 jtc int fd, nchars;
714 1.1 cgd char tbuf[8192];
715 1.1 cgd
716 1.1 cgd if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
717 1.1 cgd while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
718 1.1 cgd (void)write(fileno(stdout), tbuf, nchars);
719 1.1 cgd sleepexit(0);
720 1.1 cgd }
721 1.1 cgd }
722 1.1 cgd
723 1.5 cgd void
724 1.1 cgd dolastlog(quiet)
725 1.1 cgd int quiet;
726 1.1 cgd {
727 1.1 cgd struct lastlog ll;
728 1.1 cgd int fd;
729 1.1 cgd
730 1.1 cgd if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
731 1.26 kleink (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
732 1.1 cgd if (!quiet) {
733 1.1 cgd if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
734 1.1 cgd ll.ll_time != 0) {
735 1.1 cgd (void)printf("Last login: %.*s ",
736 1.42 kim 24, (char *)ctime(&ll.ll_time));
737 1.1 cgd if (*ll.ll_host != '\0')
738 1.1 cgd (void)printf("from %.*s\n",
739 1.5 cgd (int)sizeof(ll.ll_host),
740 1.5 cgd ll.ll_host);
741 1.1 cgd else
742 1.1 cgd (void)printf("on %.*s\n",
743 1.5 cgd (int)sizeof(ll.ll_line),
744 1.5 cgd ll.ll_line);
745 1.1 cgd }
746 1.26 kleink (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
747 1.26 kleink SEEK_SET);
748 1.1 cgd }
749 1.12 jtc memset((void *)&ll, 0, sizeof(ll));
750 1.1 cgd (void)time(&ll.ll_time);
751 1.5 cgd (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
752 1.1 cgd if (hostname)
753 1.5 cgd (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
754 1.1 cgd (void)write(fd, (char *)&ll, sizeof(ll));
755 1.1 cgd (void)close(fd);
756 1.1 cgd }
757 1.1 cgd }
758 1.1 cgd
759 1.5 cgd void
760 1.1 cgd badlogin(name)
761 1.1 cgd char *name;
762 1.1 cgd {
763 1.1 cgd if (failures == 0)
764 1.1 cgd return;
765 1.1 cgd if (hostname) {
766 1.1 cgd syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
767 1.1 cgd failures, failures > 1 ? "S" : "", hostname);
768 1.1 cgd syslog(LOG_AUTHPRIV|LOG_NOTICE,
769 1.1 cgd "%d LOGIN FAILURE%s FROM %s, %s",
770 1.1 cgd failures, failures > 1 ? "S" : "", hostname, name);
771 1.1 cgd } else {
772 1.1 cgd syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
773 1.1 cgd failures, failures > 1 ? "S" : "", tty);
774 1.1 cgd syslog(LOG_AUTHPRIV|LOG_NOTICE,
775 1.1 cgd "%d LOGIN FAILURE%s ON %s, %s",
776 1.1 cgd failures, failures > 1 ? "S" : "", tty, name);
777 1.1 cgd }
778 1.1 cgd }
779 1.1 cgd
780 1.1 cgd #undef UNKNOWN
781 1.1 cgd #define UNKNOWN "su"
782 1.1 cgd
783 1.39 mycroft const char *
784 1.1 cgd stypeof(ttyid)
785 1.39 mycroft const char *ttyid;
786 1.1 cgd {
787 1.1 cgd struct ttyent *t;
788 1.1 cgd
789 1.12 jtc return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
790 1.1 cgd }
791 1.1 cgd
792 1.5 cgd void
793 1.1 cgd sleepexit(eval)
794 1.1 cgd int eval;
795 1.1 cgd {
796 1.38 mrg
797 1.12 jtc (void)sleep(5);
798 1.1 cgd exit(eval);
799 1.1 cgd }
800