1/* $NetBSD: sliplogin.c,v 1.22 2008/07/21 13:36:59 lukem Exp $ */ 2 3/*- 4 * Copyright (c) 1990, 1993 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 32#include <sys/cdefs.h> 33#ifndef lint 34__COPYRIGHT("@(#) Copyright (c) 1990, 1993\ 35 The Regents of the University of California. All rights reserved."); 36#endif /* not lint */ 37 38#ifndef lint 39#if 0 40static char sccsid[] = "@(#)sliplogin.c 8.2 (Berkeley) 2/1/94"; 41#else 42__RCSID("$NetBSD: sliplogin.c,v 1.22 2008/07/21 13:36:59 lukem Exp $"); 43#endif 44#endif /* not lint */ 45 46/* 47 * sliplogin.c 48 * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!] 49 * 50 * This program initializes its own tty port to be an async TCP/IP interface. 51 * It sets the line discipline to slip, invokes a shell script to initialize 52 * the network interface, then pauses forever waiting for hangup. 53 * 54 * It is a remote descendant of several similar programs with incestuous ties: 55 * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL. 56 * - slattach, probably by Rick Adams but touched by countless hordes. 57 * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it. 58 * 59 * There are two forms of usage: 60 * 61 * "sliplogin" 62 * Invoked simply as "sliplogin", the program looks up the username 63 * in the file /etc/slip.hosts. 64 * If an entry is found, the line on fd0 is configured for SLIP operation 65 * as specified in the file. 66 * 67 * "sliplogin IPhostlogin </dev/ttyb" 68 * Invoked by root with a username, the name is looked up in the 69 * /etc/slip.hosts file and if found fd0 is configured as in case 1. 70 */ 71 72#include <sys/types.h> 73#include <sys/file.h> 74#include <sys/param.h> 75#include <sys/socket.h> 76#include <sys/stat.h> 77#include <sys/syslog.h> 78 79#if BSD >= 199006 80#define POSIX 81#endif 82#ifdef POSIX 83#include <termios.h> 84#include <sys/ioctl.h> 85#include <ttyent.h> 86#else 87#include <sgtty.h> 88#endif 89#include <net/slip.h> 90 91#include <ctype.h> 92#include <err.h> 93#include <errno.h> 94#include <netdb.h> 95#include <signal.h> 96#include <stdio.h> 97#include <stdlib.h> 98#include <string.h> 99#include <unistd.h> 100 101#include "pathnames.h" 102 103static int unit; 104static int speed; 105static int uid; 106static char loginargs[BUFSIZ]; 107static char loginfile[MAXPATHLEN]; 108static char loginname[BUFSIZ]; 109 110static void findid(const char *); 111__dead static void hup_handler(int); 112static const char *sigstr(int); 113 114static void 115findid(const char *name) 116{ 117 FILE *fp; 118 static char slopt[5][16]; 119 static char laddr[16]; 120 static char raddr[16]; 121 static char mask[16]; 122 char user[16]; 123 int n; 124 125 (void)strlcpy(loginname, name, sizeof(loginname)); 126 if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) { 127 syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS); 128 err(1, "%s", _PATH_ACCESS); 129 } 130 while (fgets(loginargs, sizeof(loginargs) - 1, fp)) { 131 if (ferror(fp)) 132 break; 133 n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n", 134 user, laddr, raddr, mask, slopt[0], slopt[1], 135 slopt[2], slopt[3], slopt[4]); 136 if (user[0] == '#' || isspace((unsigned char)user[0])) 137 continue; 138 if (strcmp(user, name) != 0) 139 continue; 140 141 /* 142 * we've found the guy we're looking for -- see if 143 * there's a login file we can use. First check for 144 * one specific to this host. If none found, try for 145 * a generic one. 146 */ 147 (void)snprintf(loginfile, sizeof loginfile, "%s.%s", 148 _PATH_LOGIN, name); 149 if (access(loginfile, R_OK|X_OK) != 0) { 150 (void)strlcpy(loginfile, _PATH_LOGIN, sizeof(loginfile)); 151 if (access(loginfile, R_OK|X_OK)) { 152 fputs("access denied - no login file\n", 153 stderr); 154 syslog(LOG_ERR, 155 "access denied for %s - no %s\n", 156 name, _PATH_LOGIN); 157 exit(5); 158 } 159 } 160 161 (void)fclose(fp); 162 return; 163 } 164 syslog(LOG_ERR, "SLIP access denied for %s\n", name); 165 errx(1, "SLIP access denied for %s", name); 166 /* NOTREACHED */ 167} 168 169static const char * 170sigstr(int s) 171{ 172 173 if (s > 0 && s < NSIG) 174 return (sys_signame[s]); 175 else { 176 static char buf[32]; 177 178 (void)snprintf(buf, sizeof buf, "sig %d", s); 179 return (buf); 180 } 181} 182 183static void 184hup_handler(int s) 185{ 186 char logoutfile[MAXPATHLEN]; 187 188 (void)snprintf(logoutfile, sizeof logoutfile, "%s.%s", _PATH_LOGOUT, 189 loginname); 190 if (access(logoutfile, R_OK|X_OK) != 0) 191 (void)strlcpy(logoutfile, _PATH_LOGOUT, sizeof(logoutfile)); 192 if (access(logoutfile, R_OK|X_OK) == 0) { 193 char logincmd[2*MAXPATHLEN+32]; 194 195 (void)snprintf(logincmd, sizeof logincmd, "%s %d %d %s", 196 logoutfile, unit, speed, loginargs); 197 (void)system(logincmd); 198 } 199 (void)close(0); 200 syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit, 201 sigstr(s)); 202 exit(1); 203 /* NOTREACHED */ 204} 205 206int 207main(int argc, char *argv[]) 208{ 209 int fd, s, ldisc, odisc; 210 char *name; 211#ifdef POSIX 212 struct termios tios, otios; 213#else 214 struct sgttyb tty, otty; 215#endif 216 char logincmd[2*BUFSIZ+32]; 217 218 if (strlen(argv[0]) > MAXLOGNAME) 219 errx(1, "login %s too long", argv[0]); 220 if ((name = strrchr(argv[0], '/')) == NULL) 221 name = argv[0]; 222 else 223 name++; 224 s = getdtablesize(); 225 for (fd = 3 ; fd < s ; fd++) 226 (void)close(fd); 227 openlog(name, LOG_PID, LOG_DAEMON); 228 uid = getuid(); 229 if (argc > 1) { 230 findid(argv[1]); 231 232 /* 233 * Disassociate from current controlling terminal, if any, 234 * and ensure that the slip line is our controlling terminal. 235 */ 236#ifdef POSIX 237 switch (fork()) { 238 case -1: 239 perror("fork"); 240 syslog(LOG_ERR, "could not fork: %m"); 241 exit(1); 242 case 0: 243 break; 244 default: 245 exit(0); 246 } 247 if (setsid() < 0) 248 perror("setsid"); 249#else 250 if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { 251 extern char *ttyname(); 252 253 (void)ioctl(fd, TIOCNOTTY, (caddr_t)0); 254 (void)close(fd); 255 /* open slip tty again to acquire as controlling tty? */ 256 fd = open(ttyname(0), O_RDWR, 0); 257 if (fd >= 0) 258 (void)close(fd); 259 } 260 (void)setpgrp(0, getpid()); 261#endif 262 if (argc > 2) { 263 if ((fd = open(argv[2], O_RDWR)) == -1) { 264 perror(argv[2]); 265 exit(2); 266 } 267 (void)dup2(fd, 0); 268 if (fd > 2) 269 close(fd); 270 } 271#ifdef TIOCSCTTY 272 if (ioctl(STDIN_FILENO, TIOCSCTTY, (caddr_t)0) != 0) 273 perror("ioctl (TIOCSCTTY)"); 274#endif 275 } else { 276 if ((name = getlogin()) == NULL) { 277 syslog(LOG_ERR, 278 "access denied - getlogin returned 0\n"); 279 errx(1, "access denied - no username"); 280 } 281 findid(name); 282 } 283 if (!isatty(STDIN_FILENO)) { 284 syslog(LOG_ERR, "stdin not a tty"); 285 errx(1, "stdin not a tty"); 286 } 287 (void)fchmod(STDIN_FILENO, 0600); 288 warnx("starting slip login for %s", loginname); 289#ifdef POSIX 290 /* set up the line parameters */ 291 if (tcgetattr(STDIN_FILENO, &tios) < 0) { 292 syslog(LOG_ERR, "tcgetattr: %m"); 293 exit(1); 294 } 295 otios = tios; 296 cfmakeraw(&tios); 297 tios.c_iflag &= ~IMAXBEL; 298 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios) < 0) { 299 syslog(LOG_ERR, "tcsetattr: %m"); 300 exit(1); 301 } 302 speed = cfgetispeed(&tios); 303#else 304 /* set up the line parameters */ 305 if (ioctl(STDIN_FILENO, TIOCGETP, (caddr_t)&tty) < 0) { 306 syslog(LOG_ERR, "ioctl (TIOCGETP): %m"); 307 exit(1); 308 } 309 otty = tty; 310 speed = tty.sg_ispeed; 311 tty.sg_flags = RAW | ANYP; 312 if (ioctl(STDIN_FILENO, TIOCSETP, (caddr_t)&tty) < 0) { 313 syslog(LOG_ERR, "ioctl (TIOCSETP): %m"); 314 exit(1); 315 } 316#endif 317 /* find out what ldisc we started with */ 318 if (ioctl(STDIN_FILENO, TIOCGETD, (caddr_t)&odisc) < 0) { 319 syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m"); 320 exit(1); 321 } 322 ldisc = SLIPDISC; 323 if (ioctl(STDIN_FILENO, TIOCSETD, (caddr_t)&ldisc) < 0) { 324 syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); 325 exit(1); 326 } 327 /* find out what unit number we were assigned */ 328 if (ioctl(STDIN_FILENO, SLIOCGUNIT, (caddr_t)&unit) < 0) { 329 syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m"); 330 exit(1); 331 } 332 (void)signal(SIGHUP, hup_handler); 333 (void)signal(SIGTERM, hup_handler); 334 335 syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname); 336 (void)snprintf(logincmd, sizeof logincmd, "%s %d %d %s", loginfile, 337 unit, speed, loginargs); 338 /* 339 * aim stdout and errout at /dev/null so logincmd output won't 340 * babble into the slip tty line. 341 */ 342 (void)close(1); 343 if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != 1) { 344 if (fd < 0) { 345 syslog(LOG_ERR, "open /dev/null: %m"); 346 exit(1); 347 } 348 (void)dup2(fd, 1); 349 (void)close(fd); 350 } 351 (void)dup2(1, 2); 352 353 /* 354 * Run login and logout scripts as root (real and effective); 355 * current route(8) is setuid root, and checks the real uid 356 * to see whether changes are allowed (or just "route get"). 357 */ 358 (void)setuid(0); 359 if ((s = system(logincmd)) != 0) { 360 syslog(LOG_ERR, "%s login failed: exit status %d from %s", 361 loginname, s, loginfile); 362 (void)ioctl(STDIN_FILENO, TIOCSETD, (caddr_t)&odisc); 363#ifdef POSIX 364 (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &otios); 365#else 366 (void)ioctl(STDIN_FILENO, TIOCSETP, (caddr_t)&otty); 367#endif 368 exit(6); 369 } 370 371 /* twiddle thumbs until we get a signal */ 372 while (1) 373 sigpause(0); 374 375 /* NOTREACHED */ 376} 377