Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / usr.bin / login / common.c
blob77fef42e3f9afa3daa0e0a6a5f70633ffea15e0e
1 /* $NetBSD: common.c,v 1.2 2009/12/29 19:27:43 christos Exp $ */
3 /*-
4 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: common.c,v 1.2 2009/12/29 19:27:43 christos Exp $");
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/socket.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <syslog.h>
42 #include <fcntl.h>
43 #include <ttyent.h>
44 #include <setjmp.h>
45 #include <time.h>
46 #include <pwd.h>
47 #include <err.h>
48 #include <vis.h>
49 #include <util.h>
51 #include "pathnames.h"
52 #include "common.h"
54 #if defined(KERBEROS5)
55 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
56 #else
57 #define NBUFSIZ (MAXLOGNAME + 1)
58 #endif
60 #ifdef SUPPORT_UTMP
61 #include <utmp.h>
62 static void doutmp(void);
63 static void dolastlog(int);
64 #endif
65 #ifdef SUPPORT_UTMPX
66 #include <utmpx.h>
67 static void doutmpx(void);
68 static void dolastlogx(int);
69 #endif
72 * This bounds the time given to login. Not a define so it can
73 * be patched on machines where it's too small.
75 u_int timeout = 300;
77 void decode_ss(const char *);
78 struct passwd *pwd;
79 int failures, have_ss;
80 char term[64], *envinit[1], *hostname, *username, *tty, *nested;
81 struct timeval now;
82 struct sockaddr_storage ss;
84 void
85 getloginname(void)
87 int ch;
88 char *p;
89 static char nbuf[NBUFSIZ];
91 for (;;) {
92 (void)printf("login: ");
93 for (p = nbuf; (ch = getchar()) != '\n'; ) {
94 if (ch == EOF) {
95 badlogin(username);
96 exit(EXIT_FAILURE);
98 if (p < nbuf + (NBUFSIZ - 1))
99 *p++ = ch;
101 if (p > nbuf) {
102 if (nbuf[0] == '-')
103 (void)fprintf(stderr,
104 "login names may not start with '-'.\n");
105 else {
106 *p = '\0';
107 username = nbuf;
108 break;
115 rootterm(char *ttyn)
117 struct ttyent *t;
119 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
122 static jmp_buf motdinterrupt;
124 void
125 motd(char *fname)
127 int fd, nchars;
128 sig_t oldint;
129 char tbuf[8192];
131 if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
132 return;
133 oldint = signal(SIGINT, sigint);
134 if (setjmp(motdinterrupt) == 0)
135 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
136 (void)write(fileno(stdout), tbuf, nchars);
137 (void)signal(SIGINT, oldint);
138 (void)close(fd);
141 /* ARGSUSED */
142 void
143 sigint(int signo)
146 longjmp(motdinterrupt, 1);
149 /* ARGSUSED */
150 void
151 timedout(int signo)
154 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
155 exit(EXIT_FAILURE);
158 void
159 update_db(int quietlog, int rootlogin, int fflag)
161 struct sockaddr_storage ass;
162 char assbuf[1024];
163 socklen_t alen;
164 const char *hname;
165 int remote;
167 hname = (hostname == NULL) ? "?" : hostname;
168 if (getpeername(STDIN_FILENO, (struct sockaddr *)&ass, &alen) != -1) {
169 (void)sockaddr_snprintf(assbuf,
170 sizeof(assbuf), "%A (%a)", (void *)&ass);
171 if (have_ss) {
172 char ssbuf[1024];
173 (void)sockaddr_snprintf(ssbuf,
174 sizeof(ssbuf), "%A(%a)", (void *)&ss);
175 if (memcmp(&ass, &ss, alen) != 0)
176 syslog(LOG_NOTICE,
177 "login %s on tty %s address mismatch "
178 "passed %s != actual %s", username, tty,
179 ssbuf, assbuf);
180 } else
181 ss = ass;
182 remote = 1;
183 } else if (have_ss) {
184 (void)sockaddr_snprintf(assbuf,
185 sizeof(assbuf), "%A(%a)", (void *)&ss);
186 remote = 1;
187 } else if (hostname) {
188 (void)snprintf(assbuf, sizeof(assbuf), "? ?");
189 remote = 1;
190 } else
191 remote = 0;
193 /* If fflag is on, assume caller/authenticator has logged root login. */
194 if (rootlogin && fflag == 0) {
195 if (remote)
196 syslog(LOG_NOTICE, "ROOT LOGIN (%s) on tty %s from %s /"
197 " %s", username, tty, hname, assbuf);
198 else
199 syslog(LOG_NOTICE, "ROOT LOGIN (%s) on tty %s",
200 username, tty);
201 } else if (nested != NULL) {
202 if (remote)
203 syslog(LOG_NOTICE, "%s to %s on tty %s from %s / "
204 "%s", nested, pwd->pw_name, tty, hname, assbuf);
205 else
206 syslog(LOG_NOTICE, "%s to %s on tty %s", nested,
207 pwd->pw_name, tty);
208 } else {
209 if (remote)
210 syslog(LOG_NOTICE, "%s on tty %s from %s / %s",
211 pwd->pw_name, tty, hname, assbuf);
212 else
213 syslog(LOG_NOTICE, "%s on tty %s",
214 pwd->pw_name, tty);
216 (void)gettimeofday(&now, NULL);
217 #ifdef SUPPORT_UTMPX
218 doutmpx();
219 dolastlogx(quietlog);
220 quietlog = 1;
221 #endif
222 #ifdef SUPPORT_UTMP
223 doutmp();
224 dolastlog(quietlog);
225 #endif
228 #ifdef SUPPORT_UTMPX
229 static void
230 doutmpx(void)
232 struct utmpx utmpx;
233 char *t;
235 memset((void *)&utmpx, 0, sizeof(utmpx));
236 utmpx.ut_tv = now;
237 (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name));
238 if (hostname) {
239 (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host));
240 utmpx.ut_ss = ss;
242 (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line));
243 utmpx.ut_type = USER_PROCESS;
244 utmpx.ut_pid = getpid();
245 t = tty + strlen(tty);
246 if (t - tty >= sizeof(utmpx.ut_id)) {
247 (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id),
248 sizeof(utmpx.ut_id));
249 } else {
250 (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id));
252 if (pututxline(&utmpx) == NULL)
253 syslog(LOG_NOTICE, "Cannot update utmpx: %m");
254 endutxent();
255 if (updwtmpx(_PATH_WTMPX, &utmpx) != 0)
256 syslog(LOG_NOTICE, "Cannot update wtmpx: %m");
259 static void
260 dolastlogx(int quiet)
262 struct lastlogx ll;
263 if (!quiet && getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL) {
264 time_t t = (time_t)ll.ll_tv.tv_sec;
265 (void)printf("Last login: %.24s ", ctime(&t));
266 if (*ll.ll_host != '\0')
267 (void)printf("from %.*s ",
268 (int)sizeof(ll.ll_host),
269 ll.ll_host);
270 (void)printf("on %.*s\n",
271 (int)sizeof(ll.ll_line),
272 ll.ll_line);
274 ll.ll_tv = now;
275 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
276 if (hostname)
277 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
278 else
279 (void)memset(ll.ll_host, '\0', sizeof(ll.ll_host));
280 if (have_ss)
281 ll.ll_ss = ss;
282 else
283 (void)memset(&ll.ll_ss, 0, sizeof(ll.ll_ss));
284 if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0)
285 syslog(LOG_NOTICE, "Cannot update lastlogx: %m");
287 #endif
289 #ifdef SUPPORT_UTMP
290 static void
291 doutmp(void)
293 struct utmp utmp;
295 (void)memset((void *)&utmp, 0, sizeof(utmp));
296 utmp.ut_time = now.tv_sec;
297 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
298 if (hostname)
299 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
300 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
301 login(&utmp);
304 static void
305 dolastlog(int quiet)
307 struct lastlog ll;
308 int fd;
310 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
311 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
312 if (!quiet) {
313 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
314 ll.ll_time != 0) {
315 (void)printf("Last login: %.24s ",
316 ctime(&ll.ll_time));
317 if (*ll.ll_host != '\0')
318 (void)printf("from %.*s ",
319 (int)sizeof(ll.ll_host),
320 ll.ll_host);
321 (void)printf("on %.*s\n",
322 (int)sizeof(ll.ll_line), ll.ll_line);
324 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
325 SEEK_SET);
327 memset((void *)&ll, 0, sizeof(ll));
328 ll.ll_time = now.tv_sec;
329 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
330 if (hostname)
331 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
332 (void)write(fd, (char *)&ll, sizeof(ll));
333 (void)close(fd);
336 #endif
338 void
339 badlogin(const char *name)
342 if (failures == 0)
343 return;
344 if (hostname) {
345 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
346 failures, failures > 1 ? "S" : "", hostname);
347 syslog(LOG_AUTHPRIV|LOG_NOTICE,
348 "%d LOGIN FAILURE%s FROM %s, %s",
349 failures, failures > 1 ? "S" : "", hostname, name);
350 } else {
351 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
352 failures, failures > 1 ? "S" : "", tty);
353 syslog(LOG_AUTHPRIV|LOG_NOTICE,
354 "%d LOGIN FAILURE%s ON %s, %s",
355 failures, failures > 1 ? "S" : "", tty, name);
359 const char *
360 stypeof(const char *ttyid)
362 struct ttyent *t;
364 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
367 void
368 sleepexit(int eval)
371 (void)sleep(5);
372 exit(eval);
375 void
376 decode_ss(const char *arg)
378 struct sockaddr_storage *ssp;
379 size_t len = strlen(arg);
381 if (len > sizeof(*ssp) * 4 + 1 || len < sizeof(*ssp))
382 errx(EXIT_FAILURE, "Bad argument");
384 if ((ssp = malloc(len)) == NULL)
385 err(EXIT_FAILURE, NULL);
387 if (strunvis((char *)ssp, arg) != sizeof(*ssp))
388 errx(EXIT_FAILURE, "Decoding error");
390 (void)memcpy(&ss, ssp, sizeof(ss));
391 free(ssp);
392 have_ss = 1;