1/* $NetBSD: sliplogin.c,v 1.23 2011/08/30 20:42:22 joerg 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.23 2011/08/30 20:42:22 joerg 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 124 (void)strlcpy(loginname, name, sizeof(loginname)); 125 if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) { 126 syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS); 127 err(1, "%s", _PATH_ACCESS); 128 } 129 while (fgets(loginargs, sizeof(loginargs) - 1, fp)) { 130 if (ferror(fp)) 131 break; 132 (void)sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]" 133 "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s" 134 "%*[ \t]%15s\n", 135 user, laddr, raddr, mask, slopt[0], slopt[1], 136 slopt[2], slopt[3], slopt[4]); 137 if (user[0] == '#' || isspace((unsigned char)user[0])) 138 continue; 139 if (strcmp(user, name) != 0) 140 continue; 141 142 /* 143 * we've found the guy we're looking for -- see if 144 * there's a login file we can use. First check for 145 * one specific to this host. If none found, try for 146 * a generic one. 147 */ 148 (void)snprintf(loginfile, sizeof loginfile, "%s.%s", 149 _PATH_LOGIN, name); 150 if (access(loginfile, R_OK|X_OK) != 0) { 151 (void)strlcpy(loginfile, _PATH_LOGIN, sizeof(loginfile)); 152 if (access(loginfile, R_OK|X_OK)) { 153 fputs("access denied - no login file\n", 154 stderr); 155 syslog(LOG_ERR, 156 "access denied for %s - no %s\n", 157 name, _PATH_LOGIN); 158 exit(5); 159 } 160 } 161 162 (void)fclose(fp); 163 return; 164 } 165 syslog(LOG_ERR, "SLIP access denied for %s\n", name); 166 errx(1, "SLIP access denied for %s", name); 167 /* NOTREACHED */ 168} 169 170static const char * 171sigstr(int s) 172{ 173 174 if (s > 0 && s < NSIG) 175 return (sys_signame[s]); 176 else { 177 static char buf[32]; 178 179 (void)snprintf(buf, sizeof buf, "sig %d", s); 180 return (buf); 181 } 182} 183 184static void 185hup_handler(int s) 186{ 187 char logoutfile[MAXPATHLEN]; 188 189 (void)snprintf(logoutfile, sizeof logoutfile, "%s.%s", _PATH_LOGOUT, 190 loginname); 191 if (access(logoutfile, R_OK|X_OK) != 0) 192 (void)strlcpy(logoutfile, _PATH_LOGOUT, sizeof(logoutfile)); 193 if (access(logoutfile, R_OK|X_OK) == 0) { 194 char logincmd[2*MAXPATHLEN+32]; 195 196 (void)snprintf(logincmd, sizeof logincmd, "%s %d %d %s", 197 logoutfile, unit, speed, loginargs); 198 (void)system(logincmd); 199 } 200 (void)close(0); 201 syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit, 202 sigstr(s)); 203 exit(1); 204 /* NOTREACHED */ 205} 206 207int 208main(int argc, char *argv[]) 209{ 210 int fd, s, ldisc, odisc; 211 char *name; 212#ifdef POSIX 213 struct termios tios, otios; 214#else 215 struct sgttyb tty, otty; 216#endif 217 char logincmd[2*BUFSIZ+32]; 218 219 if (strlen(argv[0]) > MAXLOGNAME) 220 errx(1, "login %s too long", argv[0]); 221 if ((name = strrchr(argv[0], '/')) == NULL) 222 name = argv[0]; 223 else 224 name++; 225 s = getdtablesize(); 226 for (fd = 3 ; fd < s ; fd++) 227 (void)close(fd); 228 openlog(name, LOG_PID, LOG_DAEMON); 229 uid = getuid(); 230 if (argc > 1) { 231 findid(argv[1]); 232 233 /* 234 * Disassociate from current controlling terminal, if any, 235 * and ensure that the slip line is our controlling terminal. 236 */ 237#ifdef POSIX 238 switch (fork()) { 239 case -1: 240 perror("fork"); 241 syslog(LOG_ERR, "could not fork: %m"); 242 exit(1); 243 case 0: 244 break; 245 default: 246 exit(0); 247 } 248 if (setsid() < 0) 249 perror("setsid"); 250#else 251 if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { 252 extern char *ttyname(); 253 254 (void)ioctl(fd, TIOCNOTTY, (caddr_t)0); 255 (void)close(fd); 256 /* open slip tty again to acquire as controlling tty? */ 257 fd = open(ttyname(0), O_RDWR, 0); 258 if (fd >= 0) 259 (void)close(fd); 260 } 261 (void)setpgrp(0, getpid()); 262#endif 263 if (argc > 2) { 264 if ((fd = open(argv[2], O_RDWR)) == -1) { 265 perror(argv[2]); 266 exit(2); 267 } 268 (void)dup2(fd, 0); 269 if (fd > 2) 270 close(fd); 271 } 272#ifdef TIOCSCTTY 273 if (ioctl(STDIN_FILENO, TIOCSCTTY, (caddr_t)0) != 0) 274 perror("ioctl (TIOCSCTTY)"); 275#endif 276 } else { 277 if ((name = getlogin()) == NULL) { 278 syslog(LOG_ERR, 279 "access denied - getlogin returned 0\n"); 280 errx(1, "access denied - no username"); 281 } 282 findid(name); 283 } 284 if (!isatty(STDIN_FILENO)) { 285 syslog(LOG_ERR, "stdin not a tty"); 286 errx(1, "stdin not a tty"); 287 } 288 (void)fchmod(STDIN_FILENO, 0600); 289 warnx("starting slip login for %s", loginname); 290#ifdef POSIX 291 /* set up the line parameters */ 292 if (tcgetattr(STDIN_FILENO, &tios) < 0) { 293 syslog(LOG_ERR, "tcgetattr: %m"); 294 exit(1); 295 } 296 otios = tios; 297 cfmakeraw(&tios); 298 tios.c_iflag &= ~IMAXBEL; 299 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios) < 0) { 300 syslog(LOG_ERR, "tcsetattr: %m"); 301 exit(1); 302 } 303 speed = cfgetispeed(&tios); 304#else 305 /* set up the line parameters */ 306 if (ioctl(STDIN_FILENO, TIOCGETP, (caddr_t)&tty) < 0) { 307 syslog(LOG_ERR, "ioctl (TIOCGETP): %m"); 308 exit(1); 309 } 310 otty = tty; 311 speed = tty.sg_ispeed; 312 tty.sg_flags = RAW | ANYP; 313 if (ioctl(STDIN_FILENO, TIOCSETP, (caddr_t)&tty) < 0) { 314 syslog(LOG_ERR, "ioctl (TIOCSETP): %m"); 315 exit(1); 316 } 317#endif 318 /* find out what ldisc we started with */ 319 if (ioctl(STDIN_FILENO, TIOCGETD, (caddr_t)&odisc) < 0) { 320 syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m"); 321 exit(1); 322 } 323 ldisc = SLIPDISC; 324 if (ioctl(STDIN_FILENO, TIOCSETD, (caddr_t)&ldisc) < 0) { 325 syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); 326 exit(1); 327 } 328 /* find out what unit number we were assigned */ 329 if (ioctl(STDIN_FILENO, SLIOCGUNIT, (caddr_t)&unit) < 0) { 330 syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m"); 331 exit(1); 332 } 333 (void)signal(SIGHUP, hup_handler); 334 (void)signal(SIGTERM, hup_handler); 335 336 syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname); 337 (void)snprintf(logincmd, sizeof logincmd, "%s %d %d %s", loginfile, 338 unit, speed, loginargs); 339 /* 340 * aim stdout and errout at /dev/null so logincmd output won't 341 * babble into the slip tty line. 342 */ 343 (void)close(1); 344 if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != 1) { 345 if (fd < 0) { 346 syslog(LOG_ERR, "open /dev/null: %m"); 347 exit(1); 348 } 349 (void)dup2(fd, 1); 350 (void)close(fd); 351 } 352 (void)dup2(1, 2); 353 354 /* 355 * Run login and logout scripts as root (real and effective); 356 * current route(8) is setuid root, and checks the real uid 357 * to see whether changes are allowed (or just "route get"). 358 */ 359 (void)setuid(0); 360 if ((s = system(logincmd)) != 0) { 361 syslog(LOG_ERR, "%s login failed: exit status %d from %s", 362 loginname, s, loginfile); 363 (void)ioctl(STDIN_FILENO, TIOCSETD, (caddr_t)&odisc); 364#ifdef POSIX 365 (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &otios); 366#else 367 (void)ioctl(STDIN_FILENO, TIOCSETP, (caddr_t)&otty); 368#endif 369 exit(6); 370 } 371 372 /* twiddle thumbs until we get a signal */ 373 while (1) 374 sigpause(0); 375 376 /* NOTREACHED */ 377} 378