1/* $NetBSD: common.c,v 1.3.8.2 2012/05/18 17:02:31 riz Exp $ */ 2 3/*- 4 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 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. 18 * 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. 30 */ 31#include <sys/cdefs.h> 32__RCSID("$NetBSD: common.c,v 1.3.8.2 2012/05/18 17:02:31 riz Exp $"); 33 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> 50 51#include "pathnames.h" 52#include "common.h" 53 54#if defined(KERBEROS5) 55#define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */ 56#else 57#define NBUFSIZ (MAXLOGNAME + 1) 58#endif 59 60#ifdef SUPPORT_UTMP 61#include <utmp.h> 62static void doutmp(void); 63static void dolastlog(int); 64#endif 65#ifdef SUPPORT_UTMPX 66#include <utmpx.h> 67static void doutmpx(void); 68static void dolastlogx(int); 69#endif 70 71/* 72 * This bounds the time given to login. Not a define so it can 73 * be patched on machines where it's too small. 74 */ 75u_int timeout = 300; 76 77void decode_ss(const char *); 78struct passwd *pwd; 79int failures, have_ss; 80char term[64], *envinit[1], *hostname, *tty, *nested; 81const char *username; 82struct timeval now; 83struct sockaddr_storage ss; 84 85char * 86trimloginname(char *u) 87{ 88 if (strlen(u) > MAXLOGNAME) 89 u[MAXLOGNAME] = '\0'; 90 return u; 91} 92 93char * 94getloginname(void) 95{ 96 int ch; 97 char *p; 98 static char nbuf[NBUFSIZ]; 99 100 for (;;) { 101 (void)printf("login: "); 102 for (p = nbuf; (ch = getchar()) != '\n'; ) { 103 if (ch == EOF) { 104 badlogin(username); 105 exit(EXIT_FAILURE); 106 } 107 if (p < nbuf + (NBUFSIZ - 1)) 108 *p++ = ch; 109 } 110 if (p > nbuf) { 111 if (nbuf[0] == '-') 112 (void)fprintf(stderr, 113 "login names may not start with '-'.\n"); 114 else { 115 *p = '\0'; 116 return nbuf; 117 } 118 } 119 } 120} 121 122int 123rootterm(char *ttyn) 124{ 125 struct ttyent *t; 126 127 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 128} 129 130static jmp_buf motdinterrupt; 131 132void 133motd(const char *fname) 134{ 135 int fd, nchars; 136 sig_t oldint; 137 char tbuf[8192]; 138 139 if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0) 140 return; 141 oldint = signal(SIGINT, sigint); 142 if (setjmp(motdinterrupt) == 0) 143 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 144 (void)write(fileno(stdout), tbuf, nchars); 145 (void)signal(SIGINT, oldint); 146 (void)close(fd); 147} 148 149/* ARGSUSED */ 150void __dead 151sigint(int signo) 152{ 153 154 longjmp(motdinterrupt, 1); 155} 156 157/* ARGSUSED */ 158void __dead 159timedout(int signo) 160{ 161 162 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 163 exit(EXIT_FAILURE); 164} 165 166void 167update_db(int quietlog, int rootlogin, int fflag) 168{ 169 struct sockaddr_storage ass; 170 char assbuf[1024]; 171 socklen_t alen; 172 const char *hname; 173 int remote; 174 175 hname = (hostname == NULL) ? "?" : hostname; 176 if (getpeername(STDIN_FILENO, (struct sockaddr *)&ass, &alen) != -1) { 177 (void)sockaddr_snprintf(assbuf, 178 sizeof(assbuf), "%A (%a)", (void *)&ass); 179 if (have_ss) { 180 char ssbuf[1024]; 181 (void)sockaddr_snprintf(ssbuf, 182 sizeof(ssbuf), "%A(%a)", (void *)&ss); 183 if (memcmp(&ass, &ss, alen) != 0) 184 syslog(LOG_NOTICE, 185 "login %s on tty %s address mismatch " 186 "passed %s != actual %s", username, tty, 187 ssbuf, assbuf); 188 } else 189 ss = ass; 190 remote = 1; 191 } else if (have_ss) { 192 (void)sockaddr_snprintf(assbuf, 193 sizeof(assbuf), "%A(%a)", (void *)&ss); 194 remote = 1; 195 } else if (hostname) { 196 (void)snprintf(assbuf, sizeof(assbuf), "? ?"); 197 remote = 1; 198 } else 199 remote = 0; 200 201 /* If fflag is on, assume caller/authenticator has logged root login. */ 202 if (rootlogin && fflag == 0) { 203 if (remote) 204 syslog(LOG_NOTICE, "ROOT LOGIN (%s) on tty %s from %s /" 205 " %s", username, tty, hname, assbuf); 206 else 207 syslog(LOG_NOTICE, "ROOT LOGIN (%s) on tty %s", 208 username, tty); 209 } else if (nested != NULL) { 210 if (remote) 211 syslog(LOG_NOTICE, "%s to %s on tty %s from %s / " 212 "%s", nested, pwd->pw_name, tty, hname, assbuf); 213 else 214 syslog(LOG_NOTICE, "%s to %s on tty %s", nested, 215 pwd->pw_name, tty); 216 } else { 217 if (remote) 218 syslog(LOG_NOTICE, "%s on tty %s from %s / %s", 219 pwd->pw_name, tty, hname, assbuf); 220 else 221 syslog(LOG_NOTICE, "%s on tty %s", 222 pwd->pw_name, tty); 223 } 224 (void)gettimeofday(&now, NULL); 225#ifdef SUPPORT_UTMPX 226 doutmpx(); 227 dolastlogx(quietlog); 228 quietlog = 1; 229#endif 230#ifdef SUPPORT_UTMP 231 doutmp(); 232 dolastlog(quietlog); 233#endif 234} 235 236#ifdef SUPPORT_UTMPX 237static void 238doutmpx(void) 239{ 240 struct utmpx utmpx; 241 char *t; 242 243 memset((void *)&utmpx, 0, sizeof(utmpx)); 244 utmpx.ut_tv = now; 245 (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name)); 246 if (hostname) { 247 (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host)); 248 utmpx.ut_ss = ss; 249 } 250 (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line)); 251 utmpx.ut_type = USER_PROCESS; 252 utmpx.ut_pid = getpid(); 253 t = tty + strlen(tty); 254 if ((size_t)(t - tty) >= sizeof(utmpx.ut_id)) { 255 (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id), 256 sizeof(utmpx.ut_id)); 257 } else { 258 (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id)); 259 } 260 if (pututxline(&utmpx) == NULL) 261 syslog(LOG_NOTICE, "Cannot update utmpx: %m"); 262 endutxent(); 263 if (updwtmpx(_PATH_WTMPX, &utmpx) != 0) 264 syslog(LOG_NOTICE, "Cannot update wtmpx: %m"); 265} 266 267static void 268dolastlogx(int quiet) 269{ 270 struct lastlogx ll; 271 if (!quiet && getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL) { 272 time_t t = (time_t)ll.ll_tv.tv_sec; 273 (void)printf("Last login: %.24s ", ctime(&t)); 274 if (*ll.ll_host != '\0') 275 (void)printf("from %.*s ", 276 (int)sizeof(ll.ll_host), 277 ll.ll_host); 278 (void)printf("on %.*s\n", 279 (int)sizeof(ll.ll_line), 280 ll.ll_line); 281 } 282 ll.ll_tv = now; 283 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 284 if (hostname) 285 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 286 else 287 (void)memset(ll.ll_host, '\0', sizeof(ll.ll_host)); 288 if (have_ss) 289 ll.ll_ss = ss; 290 else 291 (void)memset(&ll.ll_ss, 0, sizeof(ll.ll_ss)); 292 if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0) 293 syslog(LOG_NOTICE, "Cannot update lastlogx: %m"); 294} 295#endif 296 297#ifdef SUPPORT_UTMP 298static void 299doutmp(void) 300{ 301 struct utmp utmp; 302 303 (void)memset((void *)&utmp, 0, sizeof(utmp)); 304 utmp.ut_time = now.tv_sec; 305 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 306 if (hostname) 307 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 308 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 309 login(&utmp); 310} 311 312static void 313dolastlog(int quiet) 314{ 315 struct lastlog ll; 316 int fd; 317 318 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 319 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET); 320 if (!quiet) { 321 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 322 ll.ll_time != 0) { 323 (void)printf("Last login: %.24s ", 324 ctime(&ll.ll_time)); 325 if (*ll.ll_host != '\0') 326 (void)printf("from %.*s ", 327 (int)sizeof(ll.ll_host), 328 ll.ll_host); 329 (void)printf("on %.*s\n", 330 (int)sizeof(ll.ll_line), ll.ll_line); 331 } 332 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), 333 SEEK_SET); 334 } 335 memset((void *)&ll, 0, sizeof(ll)); 336 ll.ll_time = now.tv_sec; 337 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 338 if (hostname) 339 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 340 (void)write(fd, (char *)&ll, sizeof(ll)); 341 (void)close(fd); 342 } 343} 344#endif 345 346void 347badlogin(const char *name) 348{ 349 350 if (failures == 0) 351 return; 352 if (hostname) { 353 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 354 failures, failures > 1 ? "S" : "", hostname); 355 syslog(LOG_AUTHPRIV|LOG_NOTICE, 356 "%d LOGIN FAILURE%s FROM %s, %s", 357 failures, failures > 1 ? "S" : "", hostname, name); 358 } else { 359 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 360 failures, failures > 1 ? "S" : "", tty); 361 syslog(LOG_AUTHPRIV|LOG_NOTICE, 362 "%d LOGIN FAILURE%s ON %s, %s", 363 failures, failures > 1 ? "S" : "", tty, name); 364 } 365} 366 367const char * 368stypeof(const char *ttyid) 369{ 370 struct ttyent *t; 371 372 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL); 373} 374 375void __dead 376sleepexit(int eval) 377{ 378 379 (void)sleep(5); 380 exit(eval); 381} 382 383void 384decode_ss(const char *arg) 385{ 386 struct sockaddr_storage *ssp; 387 size_t len = strlen(arg); 388 389 if (len > sizeof(*ssp) * 4 + 1 || len < sizeof(*ssp)) 390 errx(EXIT_FAILURE, "Bad argument"); 391 392 if ((ssp = malloc(len)) == NULL) 393 err(EXIT_FAILURE, NULL); 394 395 if (strunvis((char *)ssp, arg) != sizeof(*ssp)) 396 errx(EXIT_FAILURE, "Decoding error"); 397 398 (void)memcpy(&ss, ssp, sizeof(ss)); 399 free(ssp); 400 have_ss = 1; 401} 402