1/* $NetBSD: common.c,v 1.8 2015/10/28 07:27:24 shm 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.8 2015/10/28 07:27:24 shm 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 alen = sizeof(ass); 177 if (getpeername(STDIN_FILENO, (struct sockaddr *)&ass, &alen) != -1) { 178 (void)sockaddr_snprintf(assbuf, 179 sizeof(assbuf), "%A (%a)", (void *)&ass); 180 if (have_ss) { 181 char ssbuf[1024]; 182 (void)sockaddr_snprintf(ssbuf, 183 sizeof(ssbuf), "%A(%a)", (void *)&ss); 184 if (memcmp(&ass, &ss, alen) != 0) 185 syslog(LOG_NOTICE, 186 "login %s on tty %s address mismatch " 187 "passed %s != actual %s", username, tty, 188 ssbuf, assbuf); 189 } else 190 ss = ass; 191 remote = 1; 192 } else if (have_ss) { 193 (void)sockaddr_snprintf(assbuf, 194 sizeof(assbuf), "%A(%a)", (void *)&ss); 195 remote = 1; 196 } else if (hostname) { 197 (void)snprintf(assbuf, sizeof(assbuf), "? ?"); 198 remote = 1; 199 } else 200 remote = 0; 201 202 /* If fflag is on, assume caller/authenticator has logged root login. */ 203 if (rootlogin && fflag == 0) { 204 if (remote) 205 syslog(LOG_NOTICE, "ROOT LOGIN (%s) on tty %s from %s /" 206 " %s", username, tty, hname, assbuf); 207 else 208 syslog(LOG_NOTICE, "ROOT LOGIN (%s) on tty %s", 209 username, tty); 210 } else if (nested != NULL) { 211 if (remote) 212 syslog(LOG_NOTICE, "%s to %s on tty %s from %s / " 213 "%s", nested, pwd->pw_name, tty, hname, assbuf); 214 else 215 syslog(LOG_NOTICE, "%s to %s on tty %s", nested, 216 pwd->pw_name, tty); 217 } else { 218 if (remote) 219 syslog(LOG_NOTICE, "%s on tty %s from %s / %s", 220 pwd->pw_name, tty, hname, assbuf); 221 else 222 syslog(LOG_NOTICE, "%s on tty %s", 223 pwd->pw_name, tty); 224 } 225 (void)gettimeofday(&now, NULL); 226#ifdef SUPPORT_UTMPX 227 doutmpx(); 228 dolastlogx(quietlog); 229 quietlog = 1; 230#endif 231#ifdef SUPPORT_UTMP 232 doutmp(); 233 dolastlog(quietlog); 234#endif 235} 236 237#ifdef SUPPORT_UTMPX 238static void 239doutmpx(void) 240{ 241 struct utmpx utmpx; 242 char *t; 243 244 memset((void *)&utmpx, 0, sizeof(utmpx)); 245 utmpx.ut_tv = now; 246 (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name)); 247 if (hostname) { 248 (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host)); 249 utmpx.ut_ss = ss; 250 } 251 (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line)); 252 utmpx.ut_type = USER_PROCESS; 253 utmpx.ut_pid = getpid(); 254 t = tty + strlen(tty); 255 if ((size_t)(t - tty) >= sizeof(utmpx.ut_id)) { 256 (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id), 257 sizeof(utmpx.ut_id)); 258 } else { 259 (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id)); 260 } 261 if (pututxline(&utmpx) == NULL) 262 syslog(LOG_NOTICE, "Cannot update utmpx: %m"); 263 endutxent(); 264 if (updwtmpx(_PATH_WTMPX, &utmpx) != 0) 265 syslog(LOG_NOTICE, "Cannot update wtmpx: %m"); 266} 267 268static void 269dolastlogx(int quiet) 270{ 271 struct lastlogx ll; 272 if (!quiet && getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL) { 273 time_t t = (time_t)ll.ll_tv.tv_sec; 274 (void)printf("Last login: %.24s ", ctime(&t)); 275 if (*ll.ll_host != '\0') 276 (void)printf("from %.*s ", 277 (int)sizeof(ll.ll_host), 278 ll.ll_host); 279 (void)printf("on %.*s\n", 280 (int)sizeof(ll.ll_line), 281 ll.ll_line); 282 } 283 ll.ll_tv = now; 284 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 285 if (hostname) 286 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 287 else 288 (void)memset(ll.ll_host, '\0', sizeof(ll.ll_host)); 289 if (have_ss) 290 ll.ll_ss = ss; 291 else 292 (void)memset(&ll.ll_ss, 0, sizeof(ll.ll_ss)); 293 if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0) 294 syslog(LOG_NOTICE, "Cannot update lastlogx: %m"); 295} 296#endif 297 298#ifdef SUPPORT_UTMP 299static void 300doutmp(void) 301{ 302 struct utmp utmp; 303 304 (void)memset((void *)&utmp, 0, sizeof(utmp)); 305 utmp.ut_time = now.tv_sec; 306 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 307 if (hostname) 308 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 309 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 310 login(&utmp); 311} 312 313static void 314dolastlog(int quiet) 315{ 316 struct lastlog ll; 317 int fd; 318 319 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 320 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET); 321 if (!quiet) { 322 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 323 ll.ll_time != 0) { 324 (void)printf("Last login: %.24s ", 325 ctime(&ll.ll_time)); 326 if (*ll.ll_host != '\0') 327 (void)printf("from %.*s ", 328 (int)sizeof(ll.ll_host), 329 ll.ll_host); 330 (void)printf("on %.*s\n", 331 (int)sizeof(ll.ll_line), ll.ll_line); 332 } 333 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), 334 SEEK_SET); 335 } 336 memset((void *)&ll, 0, sizeof(ll)); 337 ll.ll_time = now.tv_sec; 338 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 339 if (hostname) 340 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 341 (void)write(fd, (char *)&ll, sizeof(ll)); 342 (void)close(fd); 343 } 344} 345#endif 346 347void 348badlogin(const char *name) 349{ 350 351 if (failures == 0) 352 return; 353 if (hostname) { 354 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 355 failures, failures > 1 ? "S" : "", hostname); 356 syslog(LOG_AUTHPRIV|LOG_NOTICE, 357 "%d LOGIN FAILURE%s FROM %s, %s", 358 failures, failures > 1 ? "S" : "", hostname, name); 359 } else { 360 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 361 failures, failures > 1 ? "S" : "", tty); 362 syslog(LOG_AUTHPRIV|LOG_NOTICE, 363 "%d LOGIN FAILURE%s ON %s, %s", 364 failures, failures > 1 ? "S" : "", tty, name); 365 } 366} 367 368const char * 369stypeof(const char *ttyid) 370{ 371 struct ttyent *t; 372 373 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL); 374} 375 376void __dead 377sleepexit(int eval) 378{ 379 380 (void)sleep(5); 381 exit(eval); 382} 383 384void 385decode_ss(const char *arg) 386{ 387 struct sockaddr_storage *ssp; 388 size_t len = strlen(arg); 389 390 if (len > sizeof(*ssp) * 4 + 1 || len < sizeof(*ssp)) 391 errx(EXIT_FAILURE, "Bad argument"); 392 393 if ((ssp = malloc(len + 1)) == NULL) 394 err(EXIT_FAILURE, NULL); 395 396 if (strunvis((char *)ssp, arg) != sizeof(*ssp)) 397 errx(EXIT_FAILURE, "Decoding error"); 398 399 (void)memcpy(&ss, ssp, sizeof(ss)); 400 free(ssp); 401 have_ss = 1; 402} 403