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