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