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