1 1.51 andvar /* $NetBSD: sys_term.c,v 1.51 2025/06/27 21:36:23 andvar Exp $ */ 2 1.8 thorpej 3 1.1 cgd /* 4 1.3 cgd * Copyright (c) 1989, 1993 5 1.3 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.39 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.11 mrg #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.8 thorpej #if 0 35 1.8 thorpej static char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; 36 1.8 thorpej #else 37 1.51 andvar __RCSID("$NetBSD: sys_term.c,v 1.51 2025/06/27 21:36:23 andvar Exp $"); 38 1.8 thorpej #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #include "telnetd.h" 42 1.1 cgd #include "pathnames.h" 43 1.1 cgd 44 1.11 mrg #include <util.h> 45 1.41 christos #include <vis.h> 46 1.11 mrg 47 1.46 christos #ifdef SUPPORT_UTMP 48 1.31 wiz #include <utmp.h> 49 1.46 christos #endif 50 1.46 christos #ifdef SUPPORT_UTMPX 51 1.46 christos #include <utmpx.h> 52 1.46 christos #endif 53 1.1 cgd 54 1.1 cgd struct termios termbuf, termbuf2; /* pty control structure */ 55 1.1 cgd 56 1.42 perry void getptyslave(void); 57 1.42 perry int cleanopen(char *); 58 1.45 christos char **addarg(char **, const char *); 59 1.42 perry void scrub_env(void); 60 1.42 perry int getent(char *, char *); 61 1.42 perry char *getstr(const char *, char **); 62 1.16 aidan #ifdef KRB5 63 1.42 perry extern void kerberos5_cleanup(void); 64 1.16 aidan #endif 65 1.11 mrg 66 1.1 cgd /* 67 1.1 cgd * init_termbuf() 68 1.1 cgd * copy_termbuf(cp) 69 1.1 cgd * set_termbuf() 70 1.1 cgd * 71 1.1 cgd * These three routines are used to get and set the "termbuf" structure 72 1.1 cgd * to and from the kernel. init_termbuf() gets the current settings. 73 1.1 cgd * copy_termbuf() hands in a new "termbuf" to write to the kernel, and 74 1.1 cgd * set_termbuf() writes the structure into the kernel. 75 1.1 cgd */ 76 1.1 cgd 77 1.36 itojun void 78 1.42 perry init_termbuf(void) 79 1.1 cgd { 80 1.1 cgd (void) tcgetattr(pty, &termbuf); 81 1.1 cgd termbuf2 = termbuf; 82 1.1 cgd } 83 1.1 cgd 84 1.1 cgd #if defined(LINEMODE) && defined(TIOCPKT_IOCTL) 85 1.36 itojun void 86 1.42 perry copy_termbuf(char *cp, int len) 87 1.1 cgd { 88 1.45 christos if ((size_t)len > sizeof(termbuf)) 89 1.1 cgd len = sizeof(termbuf); 90 1.6 jtk memmove((char *)&termbuf, cp, len); 91 1.1 cgd termbuf2 = termbuf; 92 1.1 cgd } 93 1.1 cgd #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ 94 1.1 cgd 95 1.36 itojun void 96 1.42 perry set_termbuf(void) 97 1.1 cgd { 98 1.1 cgd /* 99 1.1 cgd * Only make the necessary changes. 100 1.1 cgd */ 101 1.6 jtk if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) 102 1.1 cgd (void) tcsetattr(pty, TCSANOW, &termbuf); 103 1.1 cgd } 104 1.1 cgd 105 1.1 cgd 106 1.1 cgd /* 107 1.1 cgd * spcset(func, valp, valpp) 108 1.1 cgd * 109 1.1 cgd * This function takes various special characters (func), and 110 1.1 cgd * sets *valp to the current value of that character, and 111 1.1 cgd * *valpp to point to where in the "termbuf" structure that 112 1.1 cgd * value is kept. 113 1.1 cgd * 114 1.1 cgd * It returns the SLC_ level of support for this function. 115 1.1 cgd */ 116 1.1 cgd 117 1.1 cgd 118 1.36 itojun int 119 1.42 perry spcset(int func, cc_t *valp, cc_t **valpp) 120 1.1 cgd { 121 1.1 cgd 122 1.1 cgd #define setval(a, b) *valp = termbuf.c_cc[a]; \ 123 1.1 cgd *valpp = &termbuf.c_cc[a]; \ 124 1.1 cgd return(b); 125 1.1 cgd #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); 126 1.1 cgd 127 1.1 cgd switch(func) { 128 1.1 cgd case SLC_EOF: 129 1.1 cgd setval(VEOF, SLC_VARIABLE); 130 1.1 cgd case SLC_EC: 131 1.1 cgd setval(VERASE, SLC_VARIABLE); 132 1.1 cgd case SLC_EL: 133 1.1 cgd setval(VKILL, SLC_VARIABLE); 134 1.1 cgd case SLC_IP: 135 1.1 cgd setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 136 1.1 cgd case SLC_ABORT: 137 1.1 cgd setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 138 1.1 cgd case SLC_XON: 139 1.1 cgd setval(VSTART, SLC_VARIABLE); 140 1.1 cgd case SLC_XOFF: 141 1.1 cgd setval(VSTOP, SLC_VARIABLE); 142 1.1 cgd case SLC_EW: 143 1.1 cgd setval(VWERASE, SLC_VARIABLE); 144 1.1 cgd case SLC_RP: 145 1.1 cgd setval(VREPRINT, SLC_VARIABLE); 146 1.1 cgd case SLC_LNEXT: 147 1.1 cgd setval(VLNEXT, SLC_VARIABLE); 148 1.1 cgd case SLC_AO: 149 1.1 cgd setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); 150 1.1 cgd case SLC_SUSP: 151 1.1 cgd setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); 152 1.1 cgd case SLC_FORW1: 153 1.1 cgd setval(VEOL, SLC_VARIABLE); 154 1.1 cgd case SLC_FORW2: 155 1.1 cgd setval(VEOL2, SLC_VARIABLE); 156 1.1 cgd case SLC_AYT: 157 1.1 cgd setval(VSTATUS, SLC_VARIABLE); 158 1.1 cgd 159 1.1 cgd case SLC_BRK: 160 1.1 cgd case SLC_SYNCH: 161 1.1 cgd case SLC_EOR: 162 1.1 cgd defval(0); 163 1.1 cgd 164 1.1 cgd default: 165 1.1 cgd *valp = 0; 166 1.1 cgd *valpp = 0; 167 1.1 cgd return(SLC_NOSUPPORT); 168 1.1 cgd } 169 1.1 cgd } 170 1.1 cgd 171 1.1 cgd 172 1.1 cgd /* 173 1.1 cgd * getpty() 174 1.1 cgd * 175 1.1 cgd * Allocate a pty. As a side effect, the external character 176 1.1 cgd * array "line" contains the name of the slave side. 177 1.1 cgd * 178 1.1 cgd * Returns the file descriptor of the opened pty. 179 1.1 cgd */ 180 1.13 perry 181 1.13 perry static int ptyslavefd; /* for cleanopen() */ 182 1.13 perry 183 1.13 perry int 184 1.42 perry getpty(int *ptynum) 185 1.44 hubertf { 186 1.13 perry int ptyfd; 187 1.13 perry 188 1.13 perry ptyfd = openpty(ptynum, &ptyslavefd, line, NULL, NULL); 189 1.13 perry if (ptyfd == 0) 190 1.13 perry return *ptynum; 191 1.13 perry ptyslavefd = -1; 192 1.13 perry return (-1); 193 1.13 perry } 194 1.1 cgd 195 1.1 cgd #ifdef LINEMODE 196 1.1 cgd /* 197 1.1 cgd * tty_flowmode() Find out if flow control is enabled or disabled. 198 1.1 cgd * tty_linemode() Find out if linemode (external processing) is enabled. 199 1.1 cgd * tty_setlinemod(on) Turn on/off linemode. 200 1.1 cgd * tty_isecho() Find out if echoing is turned on. 201 1.1 cgd * tty_setecho(on) Enable/disable character echoing. 202 1.1 cgd * tty_israw() Find out if terminal is in RAW mode. 203 1.1 cgd * tty_binaryin(on) Turn on/off BINARY on input. 204 1.1 cgd * tty_binaryout(on) Turn on/off BINARY on output. 205 1.1 cgd * tty_isediting() Find out if line editing is enabled. 206 1.1 cgd * tty_istrapsig() Find out if signal trapping is enabled. 207 1.1 cgd * tty_setedit(on) Turn on/off line editing. 208 1.1 cgd * tty_setsig(on) Turn on/off signal trapping. 209 1.1 cgd * tty_issofttab() Find out if tab expansion is enabled. 210 1.1 cgd * tty_setsofttab(on) Turn on/off soft tab expansion. 211 1.1 cgd * tty_islitecho() Find out if typed control chars are echoed literally 212 1.1 cgd * tty_setlitecho() Turn on/off literal echo of control chars 213 1.1 cgd * tty_tspeed(val) Set transmit speed to val. 214 1.1 cgd * tty_rspeed(val) Set receive speed to val. 215 1.1 cgd */ 216 1.1 cgd 217 1.1 cgd 218 1.36 itojun int 219 1.42 perry tty_linemode(void) 220 1.1 cgd { 221 1.1 cgd return(termbuf.c_lflag & EXTPROC); 222 1.1 cgd } 223 1.1 cgd 224 1.36 itojun void 225 1.42 perry tty_setlinemode(int on) 226 1.1 cgd { 227 1.1 cgd set_termbuf(); 228 1.1 cgd (void) ioctl(pty, TIOCEXT, (char *)&on); 229 1.1 cgd init_termbuf(); 230 1.1 cgd } 231 1.3 cgd #endif /* LINEMODE */ 232 1.1 cgd 233 1.36 itojun int 234 1.42 perry tty_isecho(void) 235 1.1 cgd { 236 1.1 cgd return (termbuf.c_lflag & ECHO); 237 1.1 cgd } 238 1.3 cgd 239 1.36 itojun int 240 1.42 perry tty_flowmode(void) 241 1.3 cgd { 242 1.3 cgd return((termbuf.c_iflag & IXON) ? 1 : 0); 243 1.3 cgd } 244 1.3 cgd 245 1.36 itojun int 246 1.42 perry tty_restartany(void) 247 1.3 cgd { 248 1.3 cgd return((termbuf.c_iflag & IXANY) ? 1 : 0); 249 1.3 cgd } 250 1.1 cgd 251 1.36 itojun void 252 1.42 perry tty_setecho(int on) 253 1.1 cgd { 254 1.1 cgd if (on) 255 1.1 cgd termbuf.c_lflag |= ECHO; 256 1.1 cgd else 257 1.1 cgd termbuf.c_lflag &= ~ECHO; 258 1.1 cgd } 259 1.1 cgd 260 1.36 itojun int 261 1.42 perry tty_israw(void) 262 1.1 cgd { 263 1.1 cgd return(!(termbuf.c_lflag & ICANON)); 264 1.1 cgd } 265 1.3 cgd 266 1.36 itojun void 267 1.42 perry tty_binaryin(int on) 268 1.1 cgd { 269 1.1 cgd if (on) { 270 1.1 cgd termbuf.c_iflag &= ~ISTRIP; 271 1.1 cgd } else { 272 1.1 cgd termbuf.c_iflag |= ISTRIP; 273 1.1 cgd } 274 1.1 cgd } 275 1.1 cgd 276 1.36 itojun void 277 1.42 perry tty_binaryout(int on) 278 1.1 cgd { 279 1.1 cgd if (on) { 280 1.1 cgd termbuf.c_cflag &= ~(CSIZE|PARENB); 281 1.1 cgd termbuf.c_cflag |= CS8; 282 1.1 cgd termbuf.c_oflag &= ~OPOST; 283 1.1 cgd } else { 284 1.1 cgd termbuf.c_cflag &= ~CSIZE; 285 1.1 cgd termbuf.c_cflag |= CS7|PARENB; 286 1.1 cgd termbuf.c_oflag |= OPOST; 287 1.1 cgd } 288 1.1 cgd } 289 1.1 cgd 290 1.36 itojun int 291 1.42 perry tty_isbinaryin(void) 292 1.1 cgd { 293 1.1 cgd return(!(termbuf.c_iflag & ISTRIP)); 294 1.1 cgd } 295 1.1 cgd 296 1.36 itojun int 297 1.42 perry tty_isbinaryout(void) 298 1.1 cgd { 299 1.1 cgd return(!(termbuf.c_oflag&OPOST)); 300 1.1 cgd } 301 1.1 cgd 302 1.1 cgd #ifdef LINEMODE 303 1.36 itojun int 304 1.42 perry tty_isediting(void) 305 1.1 cgd { 306 1.1 cgd return(termbuf.c_lflag & ICANON); 307 1.1 cgd } 308 1.1 cgd 309 1.36 itojun int 310 1.42 perry tty_istrapsig(void) 311 1.1 cgd { 312 1.1 cgd return(termbuf.c_lflag & ISIG); 313 1.1 cgd } 314 1.1 cgd 315 1.36 itojun void 316 1.42 perry tty_setedit(int on) 317 1.1 cgd { 318 1.1 cgd if (on) 319 1.1 cgd termbuf.c_lflag |= ICANON; 320 1.1 cgd else 321 1.1 cgd termbuf.c_lflag &= ~ICANON; 322 1.1 cgd } 323 1.1 cgd 324 1.36 itojun void 325 1.42 perry tty_setsig(int on) 326 1.1 cgd { 327 1.1 cgd if (on) 328 1.1 cgd termbuf.c_lflag |= ISIG; 329 1.1 cgd else 330 1.1 cgd termbuf.c_lflag &= ~ISIG; 331 1.1 cgd } 332 1.1 cgd #endif /* LINEMODE */ 333 1.1 cgd 334 1.36 itojun int 335 1.42 perry tty_issofttab(void) 336 1.1 cgd { 337 1.1 cgd # ifdef OXTABS 338 1.1 cgd return (termbuf.c_oflag & OXTABS); 339 1.1 cgd # endif 340 1.1 cgd # ifdef TABDLY 341 1.1 cgd return ((termbuf.c_oflag & TABDLY) == TAB3); 342 1.1 cgd # endif 343 1.1 cgd } 344 1.1 cgd 345 1.36 itojun void 346 1.42 perry tty_setsofttab(int on) 347 1.1 cgd { 348 1.1 cgd if (on) { 349 1.1 cgd # ifdef OXTABS 350 1.1 cgd termbuf.c_oflag |= OXTABS; 351 1.1 cgd # endif 352 1.1 cgd # ifdef TABDLY 353 1.1 cgd termbuf.c_oflag &= ~TABDLY; 354 1.1 cgd termbuf.c_oflag |= TAB3; 355 1.1 cgd # endif 356 1.1 cgd } else { 357 1.1 cgd # ifdef OXTABS 358 1.1 cgd termbuf.c_oflag &= ~OXTABS; 359 1.1 cgd # endif 360 1.1 cgd # ifdef TABDLY 361 1.1 cgd termbuf.c_oflag &= ~TABDLY; 362 1.1 cgd termbuf.c_oflag |= TAB0; 363 1.1 cgd # endif 364 1.1 cgd } 365 1.1 cgd } 366 1.1 cgd 367 1.36 itojun int 368 1.42 perry tty_islitecho(void) 369 1.1 cgd { 370 1.1 cgd # ifdef ECHOCTL 371 1.1 cgd return (!(termbuf.c_lflag & ECHOCTL)); 372 1.1 cgd # endif 373 1.1 cgd # ifdef TCTLECH 374 1.1 cgd return (!(termbuf.c_lflag & TCTLECH)); 375 1.1 cgd # endif 376 1.1 cgd # if !defined(ECHOCTL) && !defined(TCTLECH) 377 1.1 cgd return (0); /* assumes ctl chars are echoed '^x' */ 378 1.1 cgd # endif 379 1.1 cgd } 380 1.1 cgd 381 1.36 itojun void 382 1.42 perry tty_setlitecho(int on) 383 1.1 cgd { 384 1.1 cgd # ifdef ECHOCTL 385 1.1 cgd if (on) 386 1.1 cgd termbuf.c_lflag &= ~ECHOCTL; 387 1.1 cgd else 388 1.1 cgd termbuf.c_lflag |= ECHOCTL; 389 1.1 cgd # endif 390 1.1 cgd # ifdef TCTLECH 391 1.1 cgd if (on) 392 1.1 cgd termbuf.c_lflag &= ~TCTLECH; 393 1.1 cgd else 394 1.1 cgd termbuf.c_lflag |= TCTLECH; 395 1.1 cgd # endif 396 1.1 cgd } 397 1.1 cgd 398 1.36 itojun int 399 1.42 perry tty_iscrnl(void) 400 1.1 cgd { 401 1.1 cgd return (termbuf.c_iflag & ICRNL); 402 1.1 cgd } 403 1.1 cgd 404 1.36 itojun void 405 1.42 perry tty_tspeed(int val) 406 1.1 cgd { 407 1.6 jtk cfsetospeed(&termbuf, val); 408 1.1 cgd } 409 1.1 cgd 410 1.36 itojun void 411 1.42 perry tty_rspeed(int val) 412 1.1 cgd { 413 1.6 jtk cfsetispeed(&termbuf, val); 414 1.1 cgd } 415 1.1 cgd 416 1.1 cgd 417 1.1 cgd 418 1.1 cgd 419 1.1 cgd /* 420 1.1 cgd * getptyslave() 421 1.1 cgd * 422 1.1 cgd * Open the slave side of the pty, and do any initialization 423 1.1 cgd * that is necessary. The return value is a file descriptor 424 1.1 cgd * for the slave side. 425 1.1 cgd */ 426 1.22 christos extern int def_tspeed, def_rspeed; 427 1.22 christos extern int def_row, def_col; 428 1.22 christos 429 1.42 perry void 430 1.42 perry getptyslave(void) 431 1.1 cgd { 432 1.42 perry int t = -1; 433 1.1 cgd 434 1.31 wiz #ifdef LINEMODE 435 1.1 cgd int waslm; 436 1.31 wiz #endif 437 1.1 cgd struct winsize ws; 438 1.1 cgd /* 439 1.51 andvar * Opening the slave side may cause initialization of the 440 1.1 cgd * kernel tty structure. We need remember the state of 441 1.1 cgd * if linemode was turned on 442 1.1 cgd * terminal window size 443 1.1 cgd * terminal speed 444 1.1 cgd * so that we can re-set them if we need to. 445 1.1 cgd */ 446 1.31 wiz #ifdef LINEMODE 447 1.1 cgd waslm = tty_linemode(); 448 1.31 wiz #endif 449 1.1 cgd 450 1.1 cgd /* 451 1.1 cgd * Make sure that we don't have a controlling tty, and 452 1.1 cgd * that we are the session (process group) leader. 453 1.1 cgd */ 454 1.1 cgd t = open(_PATH_TTY, O_RDWR); 455 1.1 cgd if (t >= 0) { 456 1.1 cgd (void) ioctl(t, TIOCNOTTY, (char *)0); 457 1.1 cgd (void) close(t); 458 1.1 cgd } 459 1.1 cgd 460 1.1 cgd 461 1.1 cgd 462 1.1 cgd t = cleanopen(line); 463 1.1 cgd if (t < 0) 464 1.1 cgd fatalperror(net, line); 465 1.1 cgd 466 1.3 cgd 467 1.1 cgd /* 468 1.1 cgd * set up the tty modes as we like them to be. 469 1.1 cgd */ 470 1.1 cgd init_termbuf(); 471 1.1 cgd if (def_row || def_col) { 472 1.6 jtk memset((char *)&ws, 0, sizeof(ws)); 473 1.1 cgd ws.ws_col = def_col; 474 1.1 cgd ws.ws_row = def_row; 475 1.1 cgd (void)ioctl(t, TIOCSWINSZ, (char *)&ws); 476 1.1 cgd } 477 1.1 cgd 478 1.1 cgd /* 479 1.1 cgd * Settings for sgtty based systems 480 1.1 cgd */ 481 1.1 cgd 482 1.1 cgd /* 483 1.1 cgd * Settings for all other termios/termio based 484 1.1 cgd * systems, other than 4.4BSD. In 4.4BSD the 485 1.1 cgd * kernel does the initial terminal setup. 486 1.1 cgd */ 487 1.1 cgd tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); 488 1.1 cgd tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); 489 1.31 wiz #ifdef LINEMODE 490 1.1 cgd if (waslm) 491 1.1 cgd tty_setlinemode(1); 492 1.31 wiz #endif /* LINEMODE */ 493 1.1 cgd 494 1.1 cgd /* 495 1.1 cgd * Set the tty modes, and make this our controlling tty. 496 1.1 cgd */ 497 1.1 cgd set_termbuf(); 498 1.1 cgd if (login_tty(t) == -1) 499 1.1 cgd fatalperror(net, "login_tty"); 500 1.1 cgd if (net > 2) 501 1.1 cgd (void) close(net); 502 1.3 cgd if (pty > 2) { 503 1.1 cgd (void) close(pty); 504 1.3 cgd pty = -1; 505 1.3 cgd } 506 1.1 cgd } 507 1.1 cgd 508 1.1 cgd /* 509 1.1 cgd * Open the specified slave side of the pty, 510 1.1 cgd * making sure that we have a clean tty. 511 1.1 cgd */ 512 1.36 itojun int 513 1.42 perry cleanopen(char *ttyline) 514 1.1 cgd { 515 1.13 perry return ptyslavefd; 516 1.1 cgd } 517 1.1 cgd 518 1.1 cgd /* 519 1.1 cgd * startslave(host) 520 1.1 cgd * 521 1.1 cgd * Given a hostname, do whatever 522 1.1 cgd * is necessary to startup the login process on the slave side of the pty. 523 1.1 cgd */ 524 1.1 cgd 525 1.1 cgd /* ARGSUSED */ 526 1.36 itojun void 527 1.42 perry startslave(char *host, int autologin, char *autoname) 528 1.1 cgd { 529 1.42 perry int i; 530 1.1 cgd 531 1.36 itojun #ifdef AUTHENTICATION 532 1.1 cgd if (!autoname || !autoname[0]) 533 1.1 cgd autologin = 0; 534 1.1 cgd 535 1.1 cgd if (autologin < auth_level) { 536 1.1 cgd fatal(net, "Authorization failed"); 537 1.1 cgd exit(1); 538 1.1 cgd } 539 1.1 cgd #endif 540 1.1 cgd 541 1.1 cgd 542 1.1 cgd if ((i = fork()) < 0) 543 1.1 cgd fatalperror(net, "fork"); 544 1.1 cgd if (i) { 545 1.1 cgd } else { 546 1.11 mrg getptyslave(); 547 1.1 cgd start_login(host, autologin, autoname); 548 1.1 cgd /*NOTREACHED*/ 549 1.1 cgd } 550 1.1 cgd } 551 1.1 cgd 552 1.1 cgd char *envinit[3]; 553 1.1 cgd 554 1.36 itojun void 555 1.42 perry init_env(void) 556 1.1 cgd { 557 1.1 cgd char **envp; 558 1.1 cgd 559 1.1 cgd envp = envinit; 560 1.11 mrg if ((*envp = getenv("TZ"))) 561 1.1 cgd *envp++ -= 3; 562 1.1 cgd *envp = 0; 563 1.1 cgd environ = envinit; 564 1.1 cgd } 565 1.1 cgd 566 1.1 cgd 567 1.1 cgd /* 568 1.1 cgd * start_login(host) 569 1.1 cgd * 570 1.1 cgd * Assuming that we are now running as a child processes, this 571 1.1 cgd * function will turn us into the login process. 572 1.1 cgd */ 573 1.22 christos extern char *gettyname; 574 1.1 cgd 575 1.36 itojun void 576 1.42 perry start_login(char *host, int autologin, char *name) 577 1.1 cgd { 578 1.42 perry char **argv; 579 1.9 tls #define TABBUFSIZ 512 580 1.9 tls char defent[TABBUFSIZ]; 581 1.9 tls char defstrs[TABBUFSIZ]; 582 1.9 tls #undef TABBUFSIZ 583 1.23 itojun const char *loginprog = NULL; 584 1.41 christos extern struct sockaddr_storage from; 585 1.41 christos char buf[sizeof(from) * 4 + 1]; 586 1.50 kre char *user; 587 1.50 kre 588 1.50 kre user = getenv("USER"); 589 1.50 kre user = (user != NULL) ? strdup(user) : NULL; 590 1.1 cgd 591 1.6 jtk scrub_env(); 592 1.6 jtk 593 1.1 cgd /* 594 1.41 christos * -a : pass on the address of the host. 595 1.1 cgd * -h : pass on name of host. 596 1.41 christos * WARNING: -h and -a are accepted by login 597 1.41 christos * if and only if getuid() == 0. 598 1.1 cgd * -p : don't clobber the environment (so terminal type stays set). 599 1.1 cgd * 600 1.1 cgd * -f : force this login, he has already been authenticated 601 1.1 cgd */ 602 1.1 cgd argv = addarg(0, "login"); 603 1.3 cgd 604 1.41 christos argv = addarg(argv, "-a"); 605 1.41 christos (void)strvisx(buf, (const char *)(const void *)&from, sizeof(from), 606 1.41 christos VIS_WHITE); 607 1.41 christos argv = addarg(argv, buf); 608 1.41 christos 609 1.41 christos argv = addarg(argv, "-h"); 610 1.41 christos argv = addarg(argv, host); 611 1.41 christos 612 1.1 cgd argv = addarg(argv, "-p"); 613 1.6 jtk #ifdef LINEMODE 614 1.6 jtk /* 615 1.6 jtk * Set the environment variable "LINEMODE" to either 616 1.6 jtk * "real" or "kludge" if we are operating in either 617 1.6 jtk * real or kludge linemode. 618 1.6 jtk */ 619 1.6 jtk if (lmodetype == REAL_LINEMODE) 620 1.6 jtk setenv("LINEMODE", "real", 1); 621 1.6 jtk # ifdef KLUDGELINEMODE 622 1.6 jtk else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) 623 1.6 jtk setenv("LINEMODE", "kludge", 1); 624 1.6 jtk # endif 625 1.6 jtk #endif 626 1.36 itojun #ifdef SECURELOGIN 627 1.1 cgd /* 628 1.1 cgd * don't worry about the -f that might get sent. 629 1.1 cgd * A -s is supposed to override it anyhow. 630 1.1 cgd */ 631 1.15 dean if (require_secure_login) 632 1.1 cgd argv = addarg(argv, "-s"); 633 1.1 cgd #endif 634 1.36 itojun #ifdef AUTHENTICATION 635 1.1 cgd if (auth_level >= 0 && autologin == AUTH_VALID) { 636 1.1 cgd argv = addarg(argv, "-f"); 637 1.5 mycroft argv = addarg(argv, "--"); 638 1.3 cgd argv = addarg(argv, name); 639 1.1 cgd } else 640 1.1 cgd #endif 641 1.50 kre if (user != NULL) { 642 1.5 mycroft argv = addarg(argv, "--"); 643 1.50 kre argv = addarg(argv, user); 644 1.3 cgd /* 645 1.3 cgd * Assume that login will set the USER variable 646 1.3 cgd * correctly. For SysV systems, this means that 647 1.3 cgd * USER will no longer be set, just LOGNAME by 648 1.3 cgd * login. (The problem is that if the auto-login 649 1.3 cgd * fails, and the user then specifies a different 650 1.3 cgd * account name, he can get logged in with both 651 1.3 cgd * LOGNAME and USER in his environment, but the 652 1.3 cgd * USER value will be wrong. 653 1.3 cgd */ 654 1.3 cgd unsetenv("USER"); 655 1.1 cgd } 656 1.9 tls if (getent(defent, gettyname) == 1) { 657 1.9 tls char *cp = defstrs; 658 1.9 tls 659 1.9 tls loginprog = getstr("lo", &cp); 660 1.9 tls } 661 1.9 tls if (loginprog == NULL) 662 1.9 tls loginprog = _PATH_LOGIN; 663 1.1 cgd closelog(); 664 1.6 jtk /* 665 1.6 jtk * This sleep(1) is in here so that telnetd can 666 1.6 jtk * finish up with the tty. There's a race condition 667 1.6 jtk * the login banner message gets lost... 668 1.6 jtk */ 669 1.6 jtk sleep(1); 670 1.9 tls execv(loginprog, argv); 671 1.1 cgd 672 1.25 wiz syslog(LOG_ERR, "%s: %m", loginprog); 673 1.9 tls fatalperror(net, loginprog); 674 1.1 cgd /*NOTREACHED*/ 675 1.1 cgd } 676 1.1 cgd 677 1.42 perry char ** 678 1.45 christos addarg(char **argv, const char *val) 679 1.1 cgd { 680 1.42 perry char **cpp; 681 1.40 itojun char **nargv; 682 1.1 cgd 683 1.1 cgd if (argv == NULL) { 684 1.1 cgd /* 685 1.1 cgd * 10 entries, a leading length, and a null 686 1.1 cgd */ 687 1.47 christos argv = malloc(sizeof(*argv) * 12); 688 1.1 cgd if (argv == NULL) 689 1.1 cgd return(NULL); 690 1.1 cgd *argv++ = (char *)10; 691 1.1 cgd *argv = (char *)0; 692 1.1 cgd } 693 1.1 cgd for (cpp = argv; *cpp; cpp++) 694 1.1 cgd ; 695 1.7 jtk if (cpp == &argv[(long)argv[-1]]) { 696 1.1 cgd --argv; 697 1.47 christos nargv = realloc(argv, sizeof(*argv) * ((long)(*argv) + 10 + 2)); 698 1.47 christos if (nargv == NULL) { 699 1.18 tron fatal(net, "not enough memory"); 700 1.18 tron /*NOTREACHED*/ 701 1.18 tron } 702 1.40 itojun argv = nargv; 703 1.40 itojun *argv = (char *)((long)(*argv) + 10); 704 1.1 cgd argv++; 705 1.7 jtk cpp = &argv[(long)argv[-1] - 10]; 706 1.1 cgd } 707 1.45 christos *cpp++ = __UNCONST(val); 708 1.1 cgd *cpp = 0; 709 1.1 cgd return(argv); 710 1.1 cgd } 711 1.1 cgd 712 1.1 cgd /* 713 1.6 jtk * scrub_env() 714 1.6 jtk * 715 1.20 assar * We only accept the environment variables listed below. 716 1.6 jtk */ 717 1.20 assar 718 1.11 mrg void 719 1.42 perry scrub_env(void) 720 1.6 jtk { 721 1.20 assar static const char *reject[] = { 722 1.20 assar "TERMCAP=/", 723 1.20 assar NULL 724 1.20 assar }; 725 1.20 assar 726 1.27 wiz static const char *acceptstr[] = { 727 1.20 assar "XAUTH=", "XAUTHORITY=", "DISPLAY=", 728 1.20 assar "TERM=", 729 1.20 assar "EDITOR=", 730 1.20 assar "PAGER=", 731 1.20 assar "LOGNAME=", 732 1.20 assar "POSIXLY_CORRECT=", 733 1.20 assar "TERMCAP=", 734 1.20 assar "PRINTER=", 735 1.20 assar NULL 736 1.20 assar }; 737 1.20 assar 738 1.20 assar char **cpp, **cpp2; 739 1.20 assar const char **p; 740 1.6 jtk 741 1.6 jtk for (cpp2 = cpp = environ; *cpp; cpp++) { 742 1.20 assar int reject_it = 0; 743 1.20 assar 744 1.20 assar for(p = reject; *p; p++) 745 1.20 assar if(strncmp(*cpp, *p, strlen(*p)) == 0) { 746 1.20 assar reject_it = 1; 747 1.20 assar break; 748 1.20 assar } 749 1.20 assar if (reject_it) 750 1.20 assar continue; 751 1.20 assar 752 1.27 wiz for(p = acceptstr; *p; p++) 753 1.20 assar if(strncmp(*cpp, *p, strlen(*p)) == 0) 754 1.20 assar break; 755 1.20 assar if(*p != NULL) 756 1.6 jtk *cpp2++ = *cpp; 757 1.6 jtk } 758 1.20 assar *cpp2 = NULL; 759 1.6 jtk } 760 1.6 jtk 761 1.6 jtk /* 762 1.1 cgd * cleanup() 763 1.1 cgd * 764 1.1 cgd * This is the routine to call when we are all through, to 765 1.1 cgd * clean up anything that needs to be cleaned up. 766 1.1 cgd */ 767 1.36 itojun /* ARGSUSED */ 768 1.36 itojun void 769 1.42 perry cleanup(int sig) 770 1.1 cgd { 771 1.14 tsarna char *p, c; 772 1.1 cgd 773 1.43 lukem p = line + sizeof(_PATH_DEV) - 1; 774 1.32 christos #ifdef SUPPORT_UTMP 775 1.1 cgd if (logout(p)) 776 1.1 cgd logwtmp(p, "", ""); 777 1.32 christos #endif 778 1.32 christos #ifdef SUPPORT_UTMPX 779 1.32 christos if (logoutx(p, 0, DEAD_PROCESS)) 780 1.32 christos logwtmpx(p, "", "", 0, DEAD_PROCESS); 781 1.32 christos #endif 782 1.1 cgd (void)chmod(line, 0666); 783 1.1 cgd (void)chown(line, 0, 0); 784 1.14 tsarna c = *p; *p = 'p'; 785 1.1 cgd (void)chmod(line, 0666); 786 1.1 cgd (void)chown(line, 0, 0); 787 1.14 tsarna *p = c; 788 1.14 tsarna if (ttyaction(line, "telnetd", "root")) 789 1.14 tsarna syslog(LOG_ERR, "%s: ttyaction failed", line); 790 1.1 cgd (void) shutdown(net, 2); 791 1.1 cgd exit(1); 792 1.1 cgd } 793