login.c revision 1.66 1 1.66 christos /* $NetBSD: login.c,v 1.66 2002/07/27 20:10:32 christos 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.66 christos __RCSID("$NetBSD: login.c,v 1.66 2002/07/27 20:10:32 christos 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.66 christos #ifdef UPDATE_UTMP
78 1.12 jtc #include <utmp.h>
79 1.66 christos #endif
80 1.66 christos #ifdef UPDATE_UTMPX
81 1.66 christos #include <utmpx.h>
82 1.66 christos #endif
83 1.13 jtc #include <util.h>
84 1.29 mycroft #ifdef SKEY
85 1.29 mycroft #include <skey.h>
86 1.29 mycroft #endif
87 1.25 mycroft #ifdef KERBEROS5
88 1.45 christos #include <krb5/krb5.h>
89 1.54 aidan #include <com_err.h>
90 1.25 mycroft #endif
91 1.48 mjl #ifdef LOGIN_CAP
92 1.48 mjl #include <login_cap.h>
93 1.48 mjl #endif
94 1.25 mycroft
95 1.1 cgd #include "pathnames.h"
96 1.1 cgd
97 1.57 aidan #ifdef KERBEROS5
98 1.57 aidan int login_krb5_get_tickets = 1;
99 1.57 aidan int login_krb4_get_tickets = 0;
100 1.57 aidan int login_krb5_forwardable_tgt = 0;
101 1.57 aidan int login_krb5_retain_ccache = 0;
102 1.57 aidan #endif
103 1.57 aidan
104 1.5 cgd void badlogin __P((char *));
105 1.48 mjl void checknologin __P((char *));
106 1.66 christos #ifdef UPDATE_UTMP
107 1.66 christos static void doutmp __P((void));
108 1.66 christos static void dolastlog __P((int));
109 1.66 christos #endif
110 1.66 christos #ifdef UPDATE_UTMPX
111 1.66 christos static void doutmpx __P((void));
112 1.66 christos static void dolastlogx __P((int));
113 1.66 christos #endif
114 1.66 christos static void update_db __P((int));
115 1.5 cgd void getloginname __P((void));
116 1.24 lukem int main __P((int, char *[]));
117 1.48 mjl void motd __P((char *));
118 1.5 cgd int rootterm __P((char *));
119 1.5 cgd void sigint __P((int));
120 1.5 cgd void sleepexit __P((int));
121 1.39 mycroft const char *stypeof __P((const char *));
122 1.5 cgd void timedout __P((int));
123 1.57 aidan #if defined(KERBEROS)
124 1.5 cgd int klogin __P((struct passwd *, char *, char *, char *));
125 1.12 jtc void kdestroy __P((void));
126 1.5 cgd #endif
127 1.44 aidan #ifdef KERBEROS5
128 1.57 aidan int k5login __P((struct passwd *, char *, char *, char *));
129 1.57 aidan void k5destroy __P((void));
130 1.57 aidan int k5_read_creds __P((char*));
131 1.57 aidan int k5_write_creds __P((void));
132 1.57 aidan #endif
133 1.57 aidan #if defined(KERBEROS) || defined(KERBEROS5)
134 1.57 aidan void dofork __P((void));
135 1.44 aidan #endif
136 1.12 jtc
137 1.1 cgd #define TTYGRPNAME "tty" /* name of group to own ttys */
138 1.1 cgd
139 1.50 mjl #define DEFAULT_BACKOFF 3
140 1.50 mjl #define DEFAULT_RETRIES 10
141 1.48 mjl
142 1.1 cgd /*
143 1.1 cgd * This bounds the time given to login. Not a define so it can
144 1.1 cgd * be patched on machines where it's too small.
145 1.1 cgd */
146 1.12 jtc u_int timeout = 300;
147 1.5 cgd
148 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
149 1.1 cgd int notickets = 1;
150 1.1 cgd char *instance;
151 1.57 aidan int has_ccache = 0;
152 1.57 aidan #endif
153 1.57 aidan #ifdef KERBEROS
154 1.57 aidan extern char *krbtkfile_env;
155 1.60 thorpej extern int krb_configured;
156 1.1 cgd #endif
157 1.25 mycroft #ifdef KERBEROS5
158 1.25 mycroft extern krb5_context kcontext;
159 1.44 aidan extern int have_forward;
160 1.57 aidan extern char *krb5tkfile_env;
161 1.60 thorpej extern int krb5_configured;
162 1.60 thorpej #endif
163 1.60 thorpej
164 1.60 thorpej #if defined(KERBEROS) && defined(KERBEROS5)
165 1.60 thorpej #define KERBEROS_CONFIGURED (krb_configured || krb5_configured)
166 1.60 thorpej #elif defined(KERBEROS)
167 1.60 thorpej #define KERBEROS_CONFIGURED krb_configured
168 1.60 thorpej #elif defined(KERBEROS5)
169 1.60 thorpej #define KERBEROS_CONFIGURED krb5_configured
170 1.25 mycroft #endif
171 1.1 cgd
172 1.1 cgd struct passwd *pwd;
173 1.1 cgd int failures;
174 1.1 cgd char term[64], *envinit[1], *hostname, *username, *tty;
175 1.66 christos struct timeval now;
176 1.66 christos struct sockaddr_storage ss;
177 1.1 cgd
178 1.34 thorpej static const char copyrightstr[] = "\
179 1.65 perry Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002\n\
180 1.55 enami \tThe NetBSD Foundation, Inc. All rights reserved.\n\
181 1.55 enami Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994\n\
182 1.34 thorpej \tThe Regents of the University of California. All rights reserved.\n\n";
183 1.34 thorpej
184 1.5 cgd int
185 1.1 cgd main(argc, argv)
186 1.1 cgd int argc;
187 1.5 cgd char *argv[];
188 1.1 cgd {
189 1.5 cgd extern char **environ;
190 1.5 cgd struct group *gr;
191 1.5 cgd struct stat st;
192 1.29 mycroft int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
193 1.44 aidan int Fflag;
194 1.33 hubertf uid_t uid, saved_uid;
195 1.35 hubertf gid_t saved_gid, saved_gids[NGROUPS_MAX];
196 1.35 hubertf int nsaved_gids;
197 1.39 mycroft char *domain, *p, *ttyn, *pwprompt;
198 1.39 mycroft const char *salt;
199 1.1 cgd char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
200 1.37 mrg char localhost[MAXHOSTNAMELEN + 1];
201 1.29 mycroft int need_chpass, require_chpass;
202 1.48 mjl int login_retries = DEFAULT_RETRIES,
203 1.48 mjl login_backoff = DEFAULT_BACKOFF;
204 1.48 mjl time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY;
205 1.25 mycroft #ifdef KERBEROS5
206 1.25 mycroft krb5_error_code kerror;
207 1.25 mycroft #endif
208 1.57 aidan #if defined(KERBEROS) || defined(KERBEROS5)
209 1.57 aidan int got_tickets = 0;
210 1.57 aidan #endif
211 1.48 mjl #ifdef LOGIN_CAP
212 1.49 mjl char *shell = NULL;
213 1.48 mjl login_cap_t *lc = NULL;
214 1.48 mjl #endif
215 1.1 cgd
216 1.20 lukem tbuf[0] = '\0';
217 1.20 lukem rval = 0;
218 1.20 lukem pwprompt = NULL;
219 1.29 mycroft need_chpass = require_chpass = 0;
220 1.20 lukem
221 1.1 cgd (void)signal(SIGALRM, timedout);
222 1.12 jtc (void)alarm(timeout);
223 1.1 cgd (void)signal(SIGQUIT, SIG_IGN);
224 1.1 cgd (void)signal(SIGINT, SIG_IGN);
225 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, 0);
226 1.1 cgd
227 1.63 lukem openlog("login", 0, LOG_AUTH);
228 1.1 cgd
229 1.1 cgd /*
230 1.1 cgd * -p is used by getty to tell login not to destroy the environment
231 1.5 cgd * -f is used to skip a second login authentication
232 1.66 christos * -h is used by other servers to pass the name of the remote host to
233 1.66 christos * login so that it may be placed in utmp/utmpx and wtmp/wtmpx
234 1.20 lukem * -s is used to force use of S/Key or equivalent.
235 1.1 cgd */
236 1.1 cgd domain = NULL;
237 1.1 cgd if (gethostname(localhost, sizeof(localhost)) < 0)
238 1.1 cgd syslog(LOG_ERR, "couldn't get local hostname: %m");
239 1.1 cgd else
240 1.12 jtc domain = strchr(localhost, '.');
241 1.37 mrg localhost[sizeof(localhost) - 1] = '\0';
242 1.1 cgd
243 1.44 aidan Fflag = fflag = hflag = pflag = sflag = 0;
244 1.44 aidan #ifdef KERBEROS5
245 1.44 aidan have_forward = 0;
246 1.44 aidan #endif
247 1.1 cgd uid = getuid();
248 1.44 aidan while ((ch = getopt(argc, argv, "Ffh:ps")) != -1)
249 1.1 cgd switch (ch) {
250 1.44 aidan case 'F':
251 1.44 aidan Fflag = 1;
252 1.44 aidan /* FALLTHROUGH */
253 1.1 cgd case 'f':
254 1.1 cgd fflag = 1;
255 1.1 cgd break;
256 1.1 cgd case 'h':
257 1.12 jtc if (uid)
258 1.12 jtc errx(1, "-h option: %s", strerror(EPERM));
259 1.1 cgd hflag = 1;
260 1.23 mikel if (domain && (p = strchr(optarg, '.')) != NULL &&
261 1.1 cgd strcasecmp(p, domain) == 0)
262 1.1 cgd *p = 0;
263 1.1 cgd hostname = optarg;
264 1.1 cgd break;
265 1.1 cgd case 'p':
266 1.1 cgd pflag = 1;
267 1.1 cgd break;
268 1.20 lukem case 's':
269 1.29 mycroft sflag = 1;
270 1.20 lukem break;
271 1.29 mycroft default:
272 1.1 cgd case '?':
273 1.1 cgd (void)fprintf(stderr,
274 1.29 mycroft "usage: login [-fps] [-h hostname] [username]\n");
275 1.1 cgd exit(1);
276 1.1 cgd }
277 1.1 cgd argc -= optind;
278 1.1 cgd argv += optind;
279 1.5 cgd
280 1.1 cgd if (*argv) {
281 1.1 cgd username = *argv;
282 1.1 cgd ask = 0;
283 1.1 cgd } else
284 1.1 cgd ask = 1;
285 1.1 cgd
286 1.1 cgd for (cnt = getdtablesize(); cnt > 2; cnt--)
287 1.5 cgd (void)close(cnt);
288 1.1 cgd
289 1.5 cgd ttyn = ttyname(STDIN_FILENO);
290 1.1 cgd if (ttyn == NULL || *ttyn == '\0') {
291 1.5 cgd (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
292 1.1 cgd ttyn = tname;
293 1.1 cgd }
294 1.23 mikel if ((tty = strrchr(ttyn, '/')) != NULL)
295 1.1 cgd ++tty;
296 1.1 cgd else
297 1.1 cgd tty = ttyn;
298 1.25 mycroft
299 1.48 mjl #ifdef LOGIN_CAP
300 1.48 mjl /* Get "login-retries" and "login-backoff" from default class */
301 1.55 enami if ((lc = login_getclass(NULL)) != NULL) {
302 1.55 enami login_retries = (int)login_getcapnum(lc, "login-retries",
303 1.55 enami DEFAULT_RETRIES, DEFAULT_RETRIES);
304 1.55 enami login_backoff = (int)login_getcapnum(lc, "login-backoff",
305 1.55 enami DEFAULT_BACKOFF, DEFAULT_BACKOFF);
306 1.48 mjl login_close(lc);
307 1.48 mjl lc = NULL;
308 1.55 enami }
309 1.48 mjl #endif
310 1.48 mjl
311 1.25 mycroft #ifdef KERBEROS5
312 1.25 mycroft kerror = krb5_init_context(&kcontext);
313 1.25 mycroft if (kerror) {
314 1.61 thorpej /*
315 1.61 thorpej * If Kerberos is not configured, that is, we are
316 1.61 thorpej * not using Kerberos, do not log the error message.
317 1.61 thorpej * However, if Kerberos is configured, and the
318 1.61 thorpej * context init fails for some other reason, we need
319 1.61 thorpej * to issue a no tickets warning to the user when the
320 1.61 thorpej * login succeeds.
321 1.61 thorpej */
322 1.61 thorpej if (kerror != ENXIO) { /* XXX NetBSD-local Heimdal hack */
323 1.61 thorpej syslog(LOG_NOTICE,
324 1.61 thorpej "%s when initializing Kerberos context",
325 1.61 thorpej error_message(kerror));
326 1.61 thorpej krb5_configured = 1;
327 1.61 thorpej }
328 1.57 aidan login_krb5_get_tickets = 0;
329 1.58 aidan }
330 1.64 cgd #endif /* KERBEROS5 */
331 1.1 cgd
332 1.1 cgd for (cnt = 0;; ask = 1) {
333 1.57 aidan #if defined(KERBEROS)
334 1.10 brezak kdestroy();
335 1.10 brezak #endif
336 1.57 aidan #if defined(KERBEROS5)
337 1.57 aidan if (login_krb5_get_tickets)
338 1.57 aidan k5destroy();
339 1.57 aidan #endif
340 1.1 cgd if (ask) {
341 1.1 cgd fflag = 0;
342 1.1 cgd getloginname();
343 1.1 cgd }
344 1.5 cgd rootlogin = 0;
345 1.29 mycroft #ifdef KERBEROS
346 1.29 mycroft if ((instance = strchr(username, '.')) != NULL)
347 1.1 cgd *instance++ = '\0';
348 1.29 mycroft else
349 1.1 cgd instance = "";
350 1.1 cgd #endif
351 1.10 brezak #ifdef KERBEROS5
352 1.29 mycroft if ((instance = strchr(username, '/')) != NULL)
353 1.10 brezak *instance++ = '\0';
354 1.29 mycroft else
355 1.10 brezak instance = "";
356 1.10 brezak #endif
357 1.16 sommerfe if (strlen(username) > MAXLOGNAME)
358 1.16 sommerfe username[MAXLOGNAME] = '\0';
359 1.1 cgd
360 1.1 cgd /*
361 1.1 cgd * Note if trying multiple user names; log failures for
362 1.1 cgd * previous user name, but don't bother logging one failure
363 1.1 cgd * for nonexistent name (mistyped username).
364 1.1 cgd */
365 1.1 cgd if (failures && strcmp(tbuf, username)) {
366 1.1 cgd if (failures > (pwd ? 0 : 1))
367 1.1 cgd badlogin(tbuf);
368 1.1 cgd failures = 0;
369 1.1 cgd }
370 1.17 mrg (void)strncpy(tbuf, username, sizeof(tbuf) - 1);
371 1.38 mrg tbuf[sizeof(tbuf) - 1] = '\0';
372 1.1 cgd
373 1.23 mikel if ((pwd = getpwnam(username)) != NULL)
374 1.1 cgd salt = pwd->pw_passwd;
375 1.1 cgd else
376 1.1 cgd salt = "xx";
377 1.1 cgd
378 1.48 mjl #ifdef LOGIN_CAP
379 1.48 mjl /*
380 1.48 mjl * Establish the class now, before we might goto
381 1.48 mjl * within the next block. pwd can be NULL since it
382 1.52 mjl * falls back to the "default" class if it is.
383 1.52 mjl */
384 1.52 mjl lc = login_getclass(pwd ? pwd->pw_class : NULL);
385 1.48 mjl #endif
386 1.1 cgd /*
387 1.1 cgd * if we have a valid account name, and it doesn't have a
388 1.1 cgd * password, or the -f option was specified and the caller
389 1.1 cgd * is root or the caller isn't changing their uid, don't
390 1.1 cgd * authenticate.
391 1.1 cgd */
392 1.7 mycroft if (pwd) {
393 1.7 mycroft if (pwd->pw_uid == 0)
394 1.7 mycroft rootlogin = 1;
395 1.7 mycroft
396 1.8 mycroft if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
397 1.7 mycroft /* already authenticated */
398 1.44 aidan #ifdef KERBEROS5
399 1.57 aidan if (login_krb5_get_tickets && Fflag)
400 1.44 aidan k5_read_creds(username);
401 1.44 aidan #endif
402 1.7 mycroft break;
403 1.7 mycroft } else if (pwd->pw_passwd[0] == '\0') {
404 1.7 mycroft /* pretend password okay */
405 1.7 mycroft rval = 0;
406 1.7 mycroft goto ttycheck;
407 1.7 mycroft }
408 1.7 mycroft }
409 1.7 mycroft
410 1.1 cgd fflag = 0;
411 1.1 cgd
412 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, -4);
413 1.1 cgd
414 1.27 mycroft #ifdef SKEY
415 1.29 mycroft if (skey_haskey(username) == 0) {
416 1.29 mycroft static char skprompt[80];
417 1.59 thorpej const char *skinfo = skey_keyinfo(username);
418 1.20 lukem
419 1.29 mycroft (void)snprintf(skprompt, sizeof(skprompt)-1,
420 1.29 mycroft "Password [%s]:",
421 1.29 mycroft skinfo ? skinfo : "error getting challenge");
422 1.29 mycroft pwprompt = skprompt;
423 1.29 mycroft } else
424 1.27 mycroft #endif
425 1.29 mycroft pwprompt = "Password:";
426 1.27 mycroft
427 1.29 mycroft p = getpass(pwprompt);
428 1.1 cgd
429 1.29 mycroft if (pwd == NULL) {
430 1.29 mycroft rval = 1;
431 1.29 mycroft goto skip;
432 1.29 mycroft }
433 1.29 mycroft #ifdef KERBEROS
434 1.57 aidan if (
435 1.57 aidan #ifdef KERBEROS5
436 1.57 aidan /* allow a user to get both krb4 and krb5 tickets, if
437 1.57 aidan * desired. If krb5 is compiled in, the default action
438 1.57 aidan * is to ignore krb4 and get krb5 tickets, but the user
439 1.57 aidan * can override this in the krb5.conf. */
440 1.57 aidan login_krb4_get_tickets &&
441 1.57 aidan #endif
442 1.57 aidan klogin(pwd, instance, localhost, p) == 0) {
443 1.29 mycroft rval = 0;
444 1.57 aidan got_tickets = 1;
445 1.29 mycroft }
446 1.1 cgd #endif
447 1.29 mycroft #ifdef KERBEROS5
448 1.57 aidan if (login_krb5_get_tickets &&
449 1.57 aidan k5login(pwd, instance, localhost, p) == 0) {
450 1.29 mycroft rval = 0;
451 1.57 aidan got_tickets = 1;
452 1.57 aidan }
453 1.57 aidan #endif
454 1.57 aidan #if defined(KERBEROS) || defined(KERBEROS5)
455 1.57 aidan if (got_tickets)
456 1.29 mycroft goto skip;
457 1.29 mycroft #endif
458 1.20 lukem #ifdef SKEY
459 1.29 mycroft if (skey_haskey(username) == 0 &&
460 1.29 mycroft skey_passcheck(username, p) != -1) {
461 1.29 mycroft rval = 0;
462 1.29 mycroft goto skip;
463 1.29 mycroft }
464 1.20 lukem #endif
465 1.29 mycroft if (!sflag && *pwd->pw_passwd != '\0' &&
466 1.29 mycroft !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
467 1.29 mycroft rval = 0;
468 1.29 mycroft require_chpass = 1;
469 1.29 mycroft goto skip;
470 1.29 mycroft }
471 1.29 mycroft rval = 1;
472 1.29 mycroft
473 1.29 mycroft skip:
474 1.29 mycroft memset(p, 0, strlen(p));
475 1.1 cgd
476 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, 0);
477 1.1 cgd
478 1.7 mycroft ttycheck:
479 1.1 cgd /*
480 1.1 cgd * If trying to log in as root without Kerberos,
481 1.1 cgd * but with insecure terminal, refuse the login attempt.
482 1.1 cgd */
483 1.7 mycroft if (pwd && !rval && rootlogin && !rootterm(tty)) {
484 1.1 cgd (void)fprintf(stderr,
485 1.1 cgd "%s login refused on this terminal.\n",
486 1.1 cgd pwd->pw_name);
487 1.1 cgd if (hostname)
488 1.1 cgd syslog(LOG_NOTICE,
489 1.1 cgd "LOGIN %s REFUSED FROM %s ON TTY %s",
490 1.1 cgd pwd->pw_name, hostname, tty);
491 1.1 cgd else
492 1.1 cgd syslog(LOG_NOTICE,
493 1.1 cgd "LOGIN %s REFUSED ON TTY %s",
494 1.1 cgd pwd->pw_name, tty);
495 1.1 cgd continue;
496 1.1 cgd }
497 1.1 cgd
498 1.1 cgd if (pwd && !rval)
499 1.1 cgd break;
500 1.1 cgd
501 1.1 cgd (void)printf("Login incorrect\n");
502 1.1 cgd failures++;
503 1.48 mjl cnt++;
504 1.1 cgd /* we allow 10 tries, but after 3 we start backing off */
505 1.50 mjl if (cnt > login_backoff) {
506 1.48 mjl if (cnt >= login_retries) {
507 1.1 cgd badlogin(username);
508 1.1 cgd sleepexit(1);
509 1.1 cgd }
510 1.1 cgd sleep((u_int)((cnt - 3) * 5));
511 1.1 cgd }
512 1.1 cgd }
513 1.1 cgd
514 1.1 cgd /* committed to login -- turn off timeout */
515 1.1 cgd (void)alarm((u_int)0);
516 1.1 cgd
517 1.1 cgd endpwent();
518 1.1 cgd
519 1.1 cgd /* if user not super-user, check for disabled logins */
520 1.48 mjl #ifdef LOGIN_CAP
521 1.56 enami if (!login_getcapbool(lc, "ignorenologin", rootlogin))
522 1.52 mjl checknologin(login_getcapstr(lc, "nologin", NULL, NULL));
523 1.48 mjl #else
524 1.48 mjl if (!rootlogin)
525 1.48 mjl checknologin(NULL);
526 1.48 mjl #endif
527 1.1 cgd
528 1.48 mjl #ifdef LOGIN_CAP
529 1.48 mjl quietlog = login_getcapbool(lc, "hushlogin", 0);
530 1.48 mjl #else
531 1.48 mjl quietlog = 0;
532 1.48 mjl #endif
533 1.33 hubertf /* Temporarily give up special privileges so we can change */
534 1.33 hubertf /* into NFS-mounted homes that are exported for non-root */
535 1.33 hubertf /* access and have mode 7x0 */
536 1.33 hubertf saved_uid = geteuid();
537 1.35 hubertf saved_gid = getegid();
538 1.35 hubertf nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
539 1.35 hubertf
540 1.35 hubertf (void)setegid(pwd->pw_gid);
541 1.35 hubertf initgroups(username, pwd->pw_gid);
542 1.35 hubertf (void)seteuid(pwd->pw_uid);
543 1.33 hubertf
544 1.1 cgd if (chdir(pwd->pw_dir) < 0) {
545 1.48 mjl #ifdef LOGIN_CAP
546 1.48 mjl if (login_getcapbool(lc, "requirehome", 0)) {
547 1.55 enami (void)printf("Home directory %s required\n",
548 1.55 enami pwd->pw_dir);
549 1.48 mjl sleepexit(1);
550 1.48 mjl }
551 1.48 mjl #endif
552 1.1 cgd (void)printf("No home directory %s!\n", pwd->pw_dir);
553 1.1 cgd if (chdir("/"))
554 1.1 cgd exit(0);
555 1.1 cgd pwd->pw_dir = "/";
556 1.1 cgd (void)printf("Logging in with home = \"/\".\n");
557 1.1 cgd }
558 1.1 cgd
559 1.55 enami if (!quietlog)
560 1.48 mjl quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
561 1.33 hubertf
562 1.33 hubertf /* regain special privileges */
563 1.33 hubertf (void)seteuid(saved_uid);
564 1.35 hubertf setgroups(nsaved_gids, saved_gids);
565 1.35 hubertf (void)setegid(saved_gid);
566 1.1 cgd
567 1.48 mjl #ifdef LOGIN_CAP
568 1.48 mjl pw_warntime = login_getcaptime(lc, "password-warn",
569 1.55 enami _PASSWORD_WARNDAYS * SECSPERDAY,
570 1.55 enami _PASSWORD_WARNDAYS * SECSPERDAY);
571 1.48 mjl #endif
572 1.48 mjl
573 1.66 christos (void)gettimeofday(&now, (struct timezone *)NULL);
574 1.40 ross if (pwd->pw_expire) {
575 1.66 christos if (now.tv_sec >= pwd->pw_expire) {
576 1.1 cgd (void)printf("Sorry -- your account has expired.\n");
577 1.1 cgd sleepexit(1);
578 1.66 christos } else if (pwd->pw_expire - now.tv_sec < pw_warntime &&
579 1.55 enami !quietlog)
580 1.1 cgd (void)printf("Warning: your account expires on %s",
581 1.1 cgd ctime(&pwd->pw_expire));
582 1.40 ross }
583 1.40 ross if (pwd->pw_change) {
584 1.30 mycroft if (pwd->pw_change == _PASSWORD_CHGNOW)
585 1.30 mycroft need_chpass = 1;
586 1.66 christos else if (now.tv_sec >= pwd->pw_change) {
587 1.31 mycroft (void)printf("Sorry -- your password has expired.\n");
588 1.31 mycroft sleepexit(1);
589 1.66 christos } else if (pwd->pw_change - now.tv_sec < pw_warntime &&
590 1.55 enami !quietlog)
591 1.30 mycroft (void)printf("Warning: your password expires on %s",
592 1.30 mycroft ctime(&pwd->pw_change));
593 1.1 cgd
594 1.40 ross }
595 1.5 cgd /* Nothing else left to fail -- really log in. */
596 1.66 christos update_db(quietlog);
597 1.1 cgd
598 1.1 cgd (void)chown(ttyn, pwd->pw_uid,
599 1.1 cgd (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
600 1.15 gwr
601 1.15 gwr if (ttyaction(ttyn, "login", pwd->pw_name))
602 1.15 gwr (void)printf("Warning: ttyaction failed.\n");
603 1.15 gwr
604 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
605 1.10 brezak /* Fork so that we can call kdestroy */
606 1.57 aidan if (
607 1.57 aidan #ifdef KERBEROS5
608 1.57 aidan ! login_krb5_retain_ccache &&
609 1.57 aidan #endif
610 1.57 aidan has_ccache)
611 1.29 mycroft dofork();
612 1.10 brezak #endif
613 1.53 mjl
614 1.53 mjl /* Destroy environment unless user has requested its preservation. */
615 1.53 mjl if (!pflag)
616 1.53 mjl environ = envinit;
617 1.53 mjl
618 1.48 mjl #ifdef LOGIN_CAP
619 1.52 mjl if (setusercontext(lc, pwd, pwd->pw_uid,
620 1.52 mjl LOGIN_SETALL & ~LOGIN_SETPATH) != 0) {
621 1.52 mjl syslog(LOG_ERR, "setusercontext failed");
622 1.52 mjl exit(1);
623 1.48 mjl }
624 1.52 mjl #else
625 1.1 cgd (void)setgid(pwd->pw_gid);
626 1.1 cgd
627 1.1 cgd initgroups(username, pwd->pw_gid);
628 1.48 mjl
629 1.48 mjl if (setlogin(pwd->pw_name) < 0)
630 1.48 mjl syslog(LOG_ERR, "setlogin() failure: %m");
631 1.48 mjl
632 1.48 mjl /* Discard permissions last so can't get killed and drop core. */
633 1.48 mjl if (rootlogin)
634 1.48 mjl (void)setuid(0);
635 1.48 mjl else
636 1.48 mjl (void)setuid(pwd->pw_uid);
637 1.52 mjl #endif
638 1.1 cgd
639 1.1 cgd if (*pwd->pw_shell == '\0')
640 1.1 cgd pwd->pw_shell = _PATH_BSHELL;
641 1.48 mjl #ifdef LOGIN_CAP
642 1.55 enami if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) {
643 1.55 enami if ((shell = strdup(shell)) == NULL) {
644 1.63 lukem syslog(LOG_ERR, "Cannot alloc mem");
645 1.48 mjl sleepexit(1);
646 1.48 mjl }
647 1.48 mjl pwd->pw_shell = shell;
648 1.48 mjl }
649 1.48 mjl #endif
650 1.48 mjl
651 1.1 cgd (void)setenv("HOME", pwd->pw_dir, 1);
652 1.1 cgd (void)setenv("SHELL", pwd->pw_shell, 1);
653 1.48 mjl if (term[0] == '\0') {
654 1.55 enami char *tt = (char *)stypeof(tty);
655 1.48 mjl #ifdef LOGIN_CAP
656 1.55 enami if (tt == NULL)
657 1.48 mjl tt = login_getcapstr(lc, "term", NULL, NULL);
658 1.48 mjl #endif
659 1.48 mjl /* unknown term -> "su" */
660 1.55 enami (void)strncpy(term, tt != NULL ? tt : "su", sizeof(term));
661 1.55 enami }
662 1.1 cgd (void)setenv("TERM", term, 0);
663 1.1 cgd (void)setenv("LOGNAME", pwd->pw_name, 1);
664 1.1 cgd (void)setenv("USER", pwd->pw_name, 1);
665 1.51 mjl
666 1.48 mjl #ifdef LOGIN_CAP
667 1.52 mjl setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
668 1.48 mjl #else
669 1.1 cgd (void)setenv("PATH", _PATH_DEFPATH, 0);
670 1.48 mjl #endif
671 1.51 mjl
672 1.1 cgd #ifdef KERBEROS
673 1.1 cgd if (krbtkfile_env)
674 1.1 cgd (void)setenv("KRBTKFILE", krbtkfile_env, 1);
675 1.1 cgd #endif
676 1.10 brezak #ifdef KERBEROS5
677 1.57 aidan if (krb5tkfile_env)
678 1.57 aidan (void)setenv("KRB5CCNAME", krb5tkfile_env, 1);
679 1.10 brezak #endif
680 1.1 cgd
681 1.12 jtc if (tty[sizeof("tty")-1] == 'd')
682 1.12 jtc syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
683 1.12 jtc
684 1.5 cgd /* If fflag is on, assume caller/authenticator has logged root login. */
685 1.40 ross if (rootlogin && fflag == 0) {
686 1.1 cgd if (hostname)
687 1.1 cgd syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
688 1.1 cgd username, tty, hostname);
689 1.1 cgd else
690 1.55 enami syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
691 1.55 enami username, tty);
692 1.40 ross }
693 1.1 cgd
694 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
695 1.60 thorpej if (KERBEROS_CONFIGURED && !quietlog && notickets == 1)
696 1.1 cgd (void)printf("Warning: no Kerberos tickets issued.\n");
697 1.1 cgd #endif
698 1.1 cgd
699 1.1 cgd if (!quietlog) {
700 1.51 mjl char *fname;
701 1.48 mjl #ifdef LOGIN_CAP
702 1.48 mjl fname = login_getcapstr(lc, "copyright", NULL, NULL);
703 1.55 enami if (fname != NULL && access(fname, F_OK) == 0)
704 1.48 mjl motd(fname);
705 1.48 mjl else
706 1.55 enami #endif
707 1.51 mjl (void)printf(copyrightstr);
708 1.48 mjl
709 1.48 mjl #ifdef LOGIN_CAP
710 1.48 mjl fname = login_getcapstr(lc, "welcome", NULL, NULL);
711 1.48 mjl if (fname == NULL || access(fname, F_OK) != 0)
712 1.48 mjl #endif
713 1.48 mjl fname = _PATH_MOTDFILE;
714 1.48 mjl motd(fname);
715 1.48 mjl
716 1.5 cgd (void)snprintf(tbuf,
717 1.5 cgd sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
718 1.1 cgd if (stat(tbuf, &st) == 0 && st.st_size != 0)
719 1.1 cgd (void)printf("You have %smail.\n",
720 1.1 cgd (st.st_mtime > st.st_atime) ? "new " : "");
721 1.1 cgd }
722 1.1 cgd
723 1.48 mjl #ifdef LOGIN_CAP
724 1.48 mjl login_close(lc);
725 1.48 mjl #endif
726 1.48 mjl
727 1.1 cgd (void)signal(SIGALRM, SIG_DFL);
728 1.1 cgd (void)signal(SIGQUIT, SIG_DFL);
729 1.1 cgd (void)signal(SIGINT, SIG_DFL);
730 1.1 cgd (void)signal(SIGTSTP, SIG_IGN);
731 1.1 cgd
732 1.1 cgd tbuf[0] = '-';
733 1.17 mrg (void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
734 1.17 mrg p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
735 1.1 cgd
736 1.24 lukem /* Wait to change password until we're unprivileged */
737 1.24 lukem if (need_chpass) {
738 1.29 mycroft if (!require_chpass)
739 1.24 lukem (void)printf(
740 1.24 lukem "Warning: your password has expired. Please change it as soon as possible.\n");
741 1.29 mycroft else {
742 1.38 mrg int status;
743 1.38 mrg
744 1.29 mycroft (void)printf(
745 1.24 lukem "Your password has expired. Please choose a new one.\n");
746 1.38 mrg switch (fork()) {
747 1.38 mrg case -1:
748 1.38 mrg warn("fork");
749 1.29 mycroft sleepexit(1);
750 1.38 mrg case 0:
751 1.38 mrg execl(_PATH_BINPASSWD, "passwd", 0);
752 1.38 mrg _exit(1);
753 1.38 mrg default:
754 1.38 mrg if (wait(&status) == -1 ||
755 1.38 mrg WEXITSTATUS(status))
756 1.38 mrg sleepexit(1);
757 1.38 mrg }
758 1.29 mycroft }
759 1.24 lukem }
760 1.1 cgd
761 1.44 aidan #ifdef KERBEROS5
762 1.57 aidan if (login_krb5_get_tickets)
763 1.57 aidan k5_write_creds();
764 1.44 aidan #endif
765 1.1 cgd execlp(pwd->pw_shell, tbuf, 0);
766 1.12 jtc err(1, "%s", pwd->pw_shell);
767 1.1 cgd }
768 1.57 aidan
769 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
770 1.16 sommerfe #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
771 1.1 cgd #else
772 1.16 sommerfe #define NBUFSIZ (MAXLOGNAME + 1)
773 1.10 brezak #endif
774 1.10 brezak
775 1.10 brezak #if defined(KERBEROS) || defined(KERBEROS5)
776 1.10 brezak /*
777 1.10 brezak * This routine handles cleanup stuff, and the like.
778 1.10 brezak * It exists only in the child process.
779 1.10 brezak */
780 1.10 brezak #include <sys/wait.h>
781 1.10 brezak void
782 1.10 brezak dofork()
783 1.10 brezak {
784 1.38 mrg int child;
785 1.38 mrg
786 1.38 mrg if (!(child = fork()))
787 1.38 mrg return; /* Child process */
788 1.38 mrg
789 1.55 enami /*
790 1.55 enami * Setup stuff? This would be things we could do in parallel
791 1.55 enami * with login
792 1.55 enami */
793 1.55 enami (void)chdir("/"); /* Let's not keep the fs busy... */
794 1.10 brezak
795 1.38 mrg /* If we're the parent, watch the child until it dies */
796 1.38 mrg while (wait(0) != child)
797 1.38 mrg ;
798 1.10 brezak
799 1.38 mrg /* Cleanup stuff */
800 1.38 mrg /* Run kdestroy to destroy tickets */
801 1.57 aidan #ifdef KERBEROS
802 1.38 mrg kdestroy();
803 1.57 aidan #endif
804 1.57 aidan #ifdef KERBEROS5
805 1.57 aidan if (login_krb5_get_tickets)
806 1.57 aidan k5destroy();
807 1.57 aidan #endif
808 1.10 brezak
809 1.38 mrg /* Leave */
810 1.38 mrg exit(0);
811 1.10 brezak }
812 1.1 cgd #endif
813 1.1 cgd
814 1.5 cgd void
815 1.1 cgd getloginname()
816 1.1 cgd {
817 1.12 jtc int ch;
818 1.12 jtc char *p;
819 1.1 cgd static char nbuf[NBUFSIZ];
820 1.1 cgd
821 1.1 cgd for (;;) {
822 1.1 cgd (void)printf("login: ");
823 1.1 cgd for (p = nbuf; (ch = getchar()) != '\n'; ) {
824 1.1 cgd if (ch == EOF) {
825 1.1 cgd badlogin(username);
826 1.1 cgd exit(0);
827 1.1 cgd }
828 1.1 cgd if (p < nbuf + (NBUFSIZ - 1))
829 1.1 cgd *p++ = ch;
830 1.1 cgd }
831 1.40 ross if (p > nbuf) {
832 1.1 cgd if (nbuf[0] == '-')
833 1.1 cgd (void)fprintf(stderr,
834 1.1 cgd "login names may not start with '-'.\n");
835 1.1 cgd else {
836 1.1 cgd *p = '\0';
837 1.1 cgd username = nbuf;
838 1.1 cgd break;
839 1.1 cgd }
840 1.40 ross }
841 1.1 cgd }
842 1.1 cgd }
843 1.1 cgd
844 1.5 cgd int
845 1.1 cgd rootterm(ttyn)
846 1.1 cgd char *ttyn;
847 1.1 cgd {
848 1.1 cgd struct ttyent *t;
849 1.1 cgd
850 1.12 jtc return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
851 1.1 cgd }
852 1.1 cgd
853 1.1 cgd jmp_buf motdinterrupt;
854 1.1 cgd
855 1.5 cgd void
856 1.48 mjl motd(fname)
857 1.48 mjl char *fname;
858 1.1 cgd {
859 1.12 jtc int fd, nchars;
860 1.1 cgd sig_t oldint;
861 1.1 cgd char tbuf[8192];
862 1.1 cgd
863 1.48 mjl if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
864 1.1 cgd return;
865 1.1 cgd oldint = signal(SIGINT, sigint);
866 1.1 cgd if (setjmp(motdinterrupt) == 0)
867 1.1 cgd while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
868 1.1 cgd (void)write(fileno(stdout), tbuf, nchars);
869 1.1 cgd (void)signal(SIGINT, oldint);
870 1.1 cgd (void)close(fd);
871 1.1 cgd }
872 1.1 cgd
873 1.5 cgd /* ARGSUSED */
874 1.1 cgd void
875 1.5 cgd sigint(signo)
876 1.5 cgd int signo;
877 1.1 cgd {
878 1.38 mrg
879 1.1 cgd longjmp(motdinterrupt, 1);
880 1.1 cgd }
881 1.1 cgd
882 1.5 cgd /* ARGSUSED */
883 1.5 cgd void
884 1.5 cgd timedout(signo)
885 1.5 cgd int signo;
886 1.5 cgd {
887 1.38 mrg
888 1.5 cgd (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
889 1.5 cgd exit(0);
890 1.5 cgd }
891 1.5 cgd
892 1.5 cgd void
893 1.48 mjl checknologin(fname)
894 1.48 mjl char *fname;
895 1.1 cgd {
896 1.12 jtc int fd, nchars;
897 1.1 cgd char tbuf[8192];
898 1.1 cgd
899 1.48 mjl if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
900 1.1 cgd while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
901 1.1 cgd (void)write(fileno(stdout), tbuf, nchars);
902 1.1 cgd sleepexit(0);
903 1.1 cgd }
904 1.1 cgd }
905 1.1 cgd
906 1.66 christos static void
907 1.66 christos update_db(int quietlog)
908 1.66 christos {
909 1.66 christos if (hostname != NULL) {
910 1.66 christos socklen_t len = sizeof(ss);
911 1.66 christos (void)getpeername(STDIN_FILENO, (struct sockaddr *)&ss, &len);
912 1.66 christos }
913 1.66 christos (void)gettimeofday(&now, NULL);
914 1.66 christos #ifdef UPDATE_UTMPX
915 1.66 christos doutmpx();
916 1.66 christos dolastlogx(quietlog);
917 1.66 christos quietlog = 1;
918 1.66 christos #endif
919 1.66 christos #ifdef UPDATE_UTMP
920 1.66 christos doutmp();
921 1.66 christos dolastlog(quietlog);
922 1.66 christos #endif
923 1.66 christos }
924 1.66 christos
925 1.66 christos #ifdef UPDATE_UTMPX
926 1.66 christos static void
927 1.66 christos doutmpx()
928 1.66 christos {
929 1.66 christos struct utmpx utmpx;
930 1.66 christos char *t;
931 1.66 christos
932 1.66 christos memset((void *)&utmpx, 0, sizeof(utmpx));
933 1.66 christos utmpx.ut_tv = now;
934 1.66 christos (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name));
935 1.66 christos if (hostname) {
936 1.66 christos (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host));
937 1.66 christos utmpx.ut_ss = ss;
938 1.66 christos }
939 1.66 christos (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line));
940 1.66 christos utmpx.ut_type = USER_PROCESS;
941 1.66 christos utmpx.ut_pid = getpid();
942 1.66 christos t = tty + strlen(tty);
943 1.66 christos if (t - tty >= sizeof(utmpx.ut_id)) {
944 1.66 christos (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id),
945 1.66 christos sizeof(utmpx.ut_id));
946 1.66 christos } else {
947 1.66 christos (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id));
948 1.66 christos }
949 1.66 christos if (pututxline(&utmpx) == NULL)
950 1.66 christos syslog(LOG_NOTICE, "Cannot update utmpx %m");
951 1.66 christos endutxent();
952 1.66 christos if (updwtmpx(_PATH_WTMPX, &utmpx) != 0)
953 1.66 christos syslog(LOG_NOTICE, "Cannot update wtmpx %m");
954 1.66 christos }
955 1.66 christos
956 1.66 christos static void
957 1.66 christos dolastlogx(quiet)
958 1.66 christos int quiet;
959 1.66 christos {
960 1.66 christos struct lastlogx ll;
961 1.66 christos if (getlastlogx(pwd->pw_uid, &ll) != NULL) {
962 1.66 christos time_t t = (time_t)ll.ll_tv.tv_sec;
963 1.66 christos (void)printf("Last login: %.24s ", ctime(&t));
964 1.66 christos if (*ll.ll_host != '\0')
965 1.66 christos (void)printf("from %.*s ",
966 1.66 christos (int)sizeof(ll.ll_host),
967 1.66 christos ll.ll_host);
968 1.66 christos (void)printf("on %.*s\n",
969 1.66 christos (int)sizeof(ll.ll_line),
970 1.66 christos ll.ll_line);
971 1.66 christos }
972 1.66 christos ll.ll_tv = now;
973 1.66 christos (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
974 1.66 christos if (hostname) {
975 1.66 christos (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
976 1.66 christos ll.ll_ss = ss;
977 1.66 christos }
978 1.66 christos if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0)
979 1.66 christos syslog(LOG_NOTICE, "Cannot update lastlogx %m");
980 1.66 christos }
981 1.66 christos #endif
982 1.66 christos
983 1.66 christos #ifdef UPDATE_UTMP
984 1.66 christos static void
985 1.66 christos doutmp()
986 1.66 christos {
987 1.66 christos struct utmp utmp;
988 1.66 christos
989 1.66 christos (void)memset((void *)&utmp, 0, sizeof(utmp));
990 1.66 christos utmp.ut_time = now.tv_sec;
991 1.66 christos (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
992 1.66 christos if (hostname)
993 1.66 christos (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
994 1.66 christos (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
995 1.66 christos login(&utmp);
996 1.66 christos }
997 1.66 christos
998 1.66 christos static void
999 1.1 cgd dolastlog(quiet)
1000 1.1 cgd int quiet;
1001 1.1 cgd {
1002 1.1 cgd struct lastlog ll;
1003 1.1 cgd int fd;
1004 1.1 cgd
1005 1.1 cgd if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
1006 1.26 kleink (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
1007 1.1 cgd if (!quiet) {
1008 1.1 cgd if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
1009 1.1 cgd ll.ll_time != 0) {
1010 1.66 christos (void)printf("Last login: %.24s ",
1011 1.66 christos ctime(&ll.ll_time));
1012 1.1 cgd if (*ll.ll_host != '\0')
1013 1.66 christos (void)printf("from %.*s ",
1014 1.5 cgd (int)sizeof(ll.ll_host),
1015 1.5 cgd ll.ll_host);
1016 1.66 christos (void)printf("on %.*s\n",
1017 1.66 christos (int)sizeof(ll.ll_line), ll.ll_line);
1018 1.1 cgd }
1019 1.26 kleink (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
1020 1.26 kleink SEEK_SET);
1021 1.1 cgd }
1022 1.12 jtc memset((void *)&ll, 0, sizeof(ll));
1023 1.66 christos ll.ll_time = now.tv_sec;
1024 1.5 cgd (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
1025 1.1 cgd if (hostname)
1026 1.5 cgd (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1027 1.1 cgd (void)write(fd, (char *)&ll, sizeof(ll));
1028 1.1 cgd (void)close(fd);
1029 1.1 cgd }
1030 1.1 cgd }
1031 1.66 christos #endif
1032 1.1 cgd
1033 1.5 cgd void
1034 1.1 cgd badlogin(name)
1035 1.1 cgd char *name;
1036 1.1 cgd {
1037 1.55 enami
1038 1.1 cgd if (failures == 0)
1039 1.1 cgd return;
1040 1.1 cgd if (hostname) {
1041 1.1 cgd syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
1042 1.1 cgd failures, failures > 1 ? "S" : "", hostname);
1043 1.1 cgd syslog(LOG_AUTHPRIV|LOG_NOTICE,
1044 1.1 cgd "%d LOGIN FAILURE%s FROM %s, %s",
1045 1.1 cgd failures, failures > 1 ? "S" : "", hostname, name);
1046 1.1 cgd } else {
1047 1.1 cgd syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
1048 1.1 cgd failures, failures > 1 ? "S" : "", tty);
1049 1.1 cgd syslog(LOG_AUTHPRIV|LOG_NOTICE,
1050 1.1 cgd "%d LOGIN FAILURE%s ON %s, %s",
1051 1.1 cgd failures, failures > 1 ? "S" : "", tty, name);
1052 1.1 cgd }
1053 1.1 cgd }
1054 1.1 cgd
1055 1.39 mycroft const char *
1056 1.1 cgd stypeof(ttyid)
1057 1.39 mycroft const char *ttyid;
1058 1.1 cgd {
1059 1.1 cgd struct ttyent *t;
1060 1.1 cgd
1061 1.48 mjl return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
1062 1.1 cgd }
1063 1.1 cgd
1064 1.5 cgd void
1065 1.1 cgd sleepexit(eval)
1066 1.1 cgd int eval;
1067 1.1 cgd {
1068 1.38 mrg
1069 1.12 jtc (void)sleep(5);
1070 1.1 cgd exit(eval);
1071 1.1 cgd }
1072