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