1 /* $NetBSD: common.c,v 1.3 2009/12/29 20:15:15 christos 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 2009/12/29 20:15:15 christos 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> 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 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 */ 75 u_int timeout = 300; 76 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; 83 84 void 85 getloginname(void) 86 { 87 int ch; 88 char *p; 89 static char nbuf[NBUFSIZ]; 90 91 for (;;) { 92 (void)printf("login: "); 93 for (p = nbuf; (ch = getchar()) != '\n'; ) { 94 if (ch == EOF) { 95 badlogin(username); 96 exit(EXIT_FAILURE); 97 } 98 if (p < nbuf + (NBUFSIZ - 1)) 99 *p++ = ch; 100 } 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; 109 } 110 } 111 } 112 } 113 114 int 115 rootterm(char *ttyn) 116 { 117 struct ttyent *t; 118 119 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 120 } 121 122 static jmp_buf motdinterrupt; 123 124 void 125 motd(char *fname) 126 { 127 int fd, nchars; 128 sig_t oldint; 129 char tbuf[8192]; 130 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); 139 } 140 141 /* ARGSUSED */ 142 void 143 sigint(int signo) 144 { 145 146 longjmp(motdinterrupt, 1); 147 } 148 149 /* ARGSUSED */ 150 void 151 timedout(int signo) 152 { 153 154 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 155 exit(EXIT_FAILURE); 156 } 157 158 void 159 update_db(int quietlog, int rootlogin, int fflag) 160 { 161 struct sockaddr_storage ass; 162 char assbuf[1024]; 163 socklen_t alen; 164 const char *hname; 165 int remote; 166 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; 192 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); 215 } 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 226 } 227 228 #ifdef SUPPORT_UTMPX 229 static void 230 doutmpx(void) 231 { 232 struct utmpx utmpx; 233 char *t; 234 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; 241 } 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)); 251 } 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"); 257 } 258 259 static void 260 dolastlogx(int quiet) 261 { 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); 273 } 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"); 286 } 287 #endif 288 289 #ifdef SUPPORT_UTMP 290 static void 291 doutmp(void) 292 { 293 struct utmp utmp; 294 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); 302 } 303 304 static void 305 dolastlog(int quiet) 306 { 307 struct lastlog ll; 308 int fd; 309 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); 323 } 324 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), 325 SEEK_SET); 326 } 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); 334 } 335 } 336 #endif 337 338 void 339 badlogin(const char *name) 340 { 341 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); 356 } 357 } 358 359 const char * 360 stypeof(const char *ttyid) 361 { 362 struct ttyent *t; 363 364 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL); 365 } 366 367 void 368 sleepexit(int eval) 369 { 370 371 (void)sleep(5); 372 exit(eval); 373 } 374 375 void 376 decode_ss(const char *arg) 377 { 378 struct sockaddr_storage *ssp; 379 size_t len = strlen(arg); 380 381 if (len > sizeof(*ssp) * 4 + 1 || len < sizeof(*ssp)) 382 errx(EXIT_FAILURE, "Bad argument"); 383 384 if ((ssp = malloc(len)) == NULL) 385 err(EXIT_FAILURE, NULL); 386 387 if (strunvis((char *)ssp, arg) != sizeof(*ssp)) 388 errx(EXIT_FAILURE, "Decoding error"); 389 390 (void)memcpy(&ss, ssp, sizeof(ss)); 391 free(ssp); 392 have_ss = 1; 393 } 394