sys_term.c revision 29088
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; 36#endif /* not lint */ 37 38#include "telnetd.h" 39#include "pathnames.h" 40 41#if defined(AUTHENTICATION) 42#include <libtelnet/auth.h> 43#endif 44 45#if defined(CRAY) || defined(__hpux) 46# define PARENT_DOES_UTMP 47#endif 48 49#ifdef NEWINIT 50#include <initreq.h> 51int utmp_len = MAXHOSTNAMELEN; /* sizeof(init_request.host) */ 52#else /* NEWINIT*/ 53# ifdef UTMPX 54# include <utmpx.h> 55struct utmpx wtmp; 56# else 57# include <utmp.h> 58struct utmp wtmp; 59# endif /* UTMPX */ 60 61int utmp_len = sizeof(wtmp.ut_host); 62# ifndef PARENT_DOES_UTMP 63char wtmpf[] = "/usr/adm/wtmp"; 64char utmpf[] = "/etc/utmp"; 65# else /* PARENT_DOES_UTMP */ 66char wtmpf[] = "/etc/wtmp"; 67# endif /* PARENT_DOES_UTMP */ 68 69# ifdef CRAY 70#include <tmpdir.h> 71#include <sys/wait.h> 72# if (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1') 73# define UNICOS7x 74# endif 75 76# ifdef UNICOS7x 77#include <sys/sysv.h> 78#include <sys/secstat.h> 79extern int secflag; 80extern struct sysv sysv; 81# endif /* UNICOS7x */ 82# endif /* CRAY */ 83#endif /* NEWINIT */ 84 85#ifdef STREAMSPTY 86#include <sac.h> 87#include <sys/stropts.h> 88#endif 89 90#define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) 91#define SCMPN(a, b) strncmp(a, b, sizeof(a)) 92 93#ifdef STREAMS 94#include <sys/stream.h> 95#endif 96#ifdef __hpux 97#include <sys/resource.h> 98#include <sys/proc.h> 99#endif 100#include <sys/tty.h> 101#ifdef t_erase 102#undef t_erase 103#undef t_kill 104#undef t_intrc 105#undef t_quitc 106#undef t_startc 107#undef t_stopc 108#undef t_eofc 109#undef t_brkc 110#undef t_suspc 111#undef t_dsuspc 112#undef t_rprntc 113#undef t_flushc 114#undef t_werasc 115#undef t_lnextc 116#endif 117 118#if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC) 119# define EXTPROC 0400 120#endif 121 122#ifndef USE_TERMIO 123struct termbuf { 124 struct sgttyb sg; 125 struct tchars tc; 126 struct ltchars ltc; 127 int state; 128 int lflags; 129} termbuf, termbuf2; 130# define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val) 131# define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val) 132# define cfgetospeed(tp) (tp)->sg.sg_ospeed 133# define cfgetispeed(tp) (tp)->sg.sg_ispeed 134#else /* USE_TERMIO */ 135# ifdef SYSV_TERMIO 136# define termios termio 137# endif 138# ifndef TCSANOW 139# ifdef TCSETS 140# define TCSANOW TCSETS 141# define TCSADRAIN TCSETSW 142# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) 143# else 144# ifdef TCSETA 145# define TCSANOW TCSETA 146# define TCSADRAIN TCSETAW 147# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) 148# else 149# define TCSANOW TIOCSETA 150# define TCSADRAIN TIOCSETAW 151# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) 152# endif 153# endif 154# define tcsetattr(f, a, t) ioctl(f, a, t) 155# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 156 (tp)->c_cflag |= (val) 157# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD) 158# ifdef CIBAUD 159# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \ 160 (tp)->c_cflag |= ((val)<<IBSHIFT) 161# define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT) 162# else 163# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 164 (tp)->c_cflag |= (val) 165# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) 166# endif 167# endif /* TCSANOW */ 168struct termios termbuf, termbuf2; /* pty control structure */ 169# ifdef STREAMSPTY 170int ttyfd = -1; 171# endif 172#endif /* USE_TERMIO */ 173 174/* 175 * init_termbuf() 176 * copy_termbuf(cp) 177 * set_termbuf() 178 * 179 * These three routines are used to get and set the "termbuf" structure 180 * to and from the kernel. init_termbuf() gets the current settings. 181 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and 182 * set_termbuf() writes the structure into the kernel. 183 */ 184 185 void 186init_termbuf() 187{ 188#ifndef USE_TERMIO 189 (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg); 190 (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc); 191 (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc); 192# ifdef TIOCGSTATE 193 (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state); 194# endif 195#else 196# ifdef STREAMSPTY 197 (void) tcgetattr(ttyfd, &termbuf); 198# else 199 (void) tcgetattr(pty, &termbuf); 200# endif 201#endif 202 termbuf2 = termbuf; 203} 204 205#if defined(LINEMODE) && defined(TIOCPKT_IOCTL) 206 void 207copy_termbuf(cp, len) 208 char *cp; 209 int len; 210{ 211 if (len > sizeof(termbuf)) 212 len = sizeof(termbuf); 213 memmove((char *)&termbuf, cp, len); 214 termbuf2 = termbuf; 215} 216#endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ 217 218 void 219set_termbuf() 220{ 221 /* 222 * Only make the necessary changes. 223 */ 224#ifndef USE_TERMIO 225 if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, 226 sizeof(termbuf.sg))) 227 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg); 228 if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, 229 sizeof(termbuf.tc))) 230 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc); 231 if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc, 232 sizeof(termbuf.ltc))) 233 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc); 234 if (termbuf.lflags != termbuf2.lflags) 235 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags); 236#else /* USE_TERMIO */ 237 if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) 238# ifdef STREAMSPTY 239 (void) tcsetattr(ttyfd, TCSANOW, &termbuf); 240# else 241 (void) tcsetattr(pty, TCSANOW, &termbuf); 242# endif 243# if defined(CRAY2) && defined(UNICOS5) 244 needtermstat = 1; 245# endif 246#endif /* USE_TERMIO */ 247} 248 249 250/* 251 * spcset(func, valp, valpp) 252 * 253 * This function takes various special characters (func), and 254 * sets *valp to the current value of that character, and 255 * *valpp to point to where in the "termbuf" structure that 256 * value is kept. 257 * 258 * It returns the SLC_ level of support for this function. 259 */ 260 261#ifndef USE_TERMIO 262 int 263spcset(func, valp, valpp) 264 int func; 265 cc_t *valp; 266 cc_t **valpp; 267{ 268 switch(func) { 269 case SLC_EOF: 270 *valp = termbuf.tc.t_eofc; 271 *valpp = (cc_t *)&termbuf.tc.t_eofc; 272 return(SLC_VARIABLE); 273 case SLC_EC: 274 *valp = termbuf.sg.sg_erase; 275 *valpp = (cc_t *)&termbuf.sg.sg_erase; 276 return(SLC_VARIABLE); 277 case SLC_EL: 278 *valp = termbuf.sg.sg_kill; 279 *valpp = (cc_t *)&termbuf.sg.sg_kill; 280 return(SLC_VARIABLE); 281 case SLC_IP: 282 *valp = termbuf.tc.t_intrc; 283 *valpp = (cc_t *)&termbuf.tc.t_intrc; 284 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 285 case SLC_ABORT: 286 *valp = termbuf.tc.t_quitc; 287 *valpp = (cc_t *)&termbuf.tc.t_quitc; 288 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 289 case SLC_XON: 290 *valp = termbuf.tc.t_startc; 291 *valpp = (cc_t *)&termbuf.tc.t_startc; 292 return(SLC_VARIABLE); 293 case SLC_XOFF: 294 *valp = termbuf.tc.t_stopc; 295 *valpp = (cc_t *)&termbuf.tc.t_stopc; 296 return(SLC_VARIABLE); 297 case SLC_AO: 298 *valp = termbuf.ltc.t_flushc; 299 *valpp = (cc_t *)&termbuf.ltc.t_flushc; 300 return(SLC_VARIABLE); 301 case SLC_SUSP: 302 *valp = termbuf.ltc.t_suspc; 303 *valpp = (cc_t *)&termbuf.ltc.t_suspc; 304 return(SLC_VARIABLE); 305 case SLC_EW: 306 *valp = termbuf.ltc.t_werasc; 307 *valpp = (cc_t *)&termbuf.ltc.t_werasc; 308 return(SLC_VARIABLE); 309 case SLC_RP: 310 *valp = termbuf.ltc.t_rprntc; 311 *valpp = (cc_t *)&termbuf.ltc.t_rprntc; 312 return(SLC_VARIABLE); 313 case SLC_LNEXT: 314 *valp = termbuf.ltc.t_lnextc; 315 *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 316 return(SLC_VARIABLE); 317 case SLC_FORW1: 318 *valp = termbuf.tc.t_brkc; 319 *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 320 return(SLC_VARIABLE); 321 case SLC_BRK: 322 case SLC_SYNCH: 323 case SLC_AYT: 324 case SLC_EOR: 325 *valp = (cc_t)0; 326 *valpp = (cc_t *)0; 327 return(SLC_DEFAULT); 328 default: 329 *valp = (cc_t)0; 330 *valpp = (cc_t *)0; 331 return(SLC_NOSUPPORT); 332 } 333} 334 335#else /* USE_TERMIO */ 336 337 int 338spcset(func, valp, valpp) 339 int func; 340 cc_t *valp; 341 cc_t **valpp; 342{ 343 344#define setval(a, b) *valp = termbuf.c_cc[a]; \ 345 *valpp = &termbuf.c_cc[a]; \ 346 return(b); 347#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); 348 349 switch(func) { 350 case SLC_EOF: 351 setval(VEOF, SLC_VARIABLE); 352 case SLC_EC: 353 setval(VERASE, SLC_VARIABLE); 354 case SLC_EL: 355 setval(VKILL, SLC_VARIABLE); 356 case SLC_IP: 357 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 358 case SLC_ABORT: 359 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 360 case SLC_XON: 361#ifdef VSTART 362 setval(VSTART, SLC_VARIABLE); 363#else 364 defval(0x13); 365#endif 366 case SLC_XOFF: 367#ifdef VSTOP 368 setval(VSTOP, SLC_VARIABLE); 369#else 370 defval(0x11); 371#endif 372 case SLC_EW: 373#ifdef VWERASE 374 setval(VWERASE, SLC_VARIABLE); 375#else 376 defval(0); 377#endif 378 case SLC_RP: 379#ifdef VREPRINT 380 setval(VREPRINT, SLC_VARIABLE); 381#else 382 defval(0); 383#endif 384 case SLC_LNEXT: 385#ifdef VLNEXT 386 setval(VLNEXT, SLC_VARIABLE); 387#else 388 defval(0); 389#endif 390 case SLC_AO: 391#if !defined(VDISCARD) && defined(VFLUSHO) 392# define VDISCARD VFLUSHO 393#endif 394#ifdef VDISCARD 395 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); 396#else 397 defval(0); 398#endif 399 case SLC_SUSP: 400#ifdef VSUSP 401 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); 402#else 403 defval(0); 404#endif 405#ifdef VEOL 406 case SLC_FORW1: 407 setval(VEOL, SLC_VARIABLE); 408#endif 409#ifdef VEOL2 410 case SLC_FORW2: 411 setval(VEOL2, SLC_VARIABLE); 412#endif 413 case SLC_AYT: 414#ifdef VSTATUS 415 setval(VSTATUS, SLC_VARIABLE); 416#else 417 defval(0); 418#endif 419 420 case SLC_BRK: 421 case SLC_SYNCH: 422 case SLC_EOR: 423 defval(0); 424 425 default: 426 *valp = 0; 427 *valpp = 0; 428 return(SLC_NOSUPPORT); 429 } 430} 431#endif /* USE_TERMIO */ 432 433#ifdef CRAY 434/* 435 * getnpty() 436 * 437 * Return the number of pty's configured into the system. 438 */ 439 int 440getnpty() 441{ 442#ifdef _SC_CRAY_NPTY 443 int numptys; 444 445 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) 446 return numptys; 447 else 448#endif /* _SC_CRAY_NPTY */ 449 return 128; 450} 451#endif /* CRAY */ 452 453#ifndef convex 454/* 455 * getpty() 456 * 457 * Allocate a pty. As a side effect, the external character 458 * array "line" contains the name of the slave side. 459 * 460 * Returns the file descriptor of the opened pty. 461 */ 462#ifndef __GNUC__ 463char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 464#else 465static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 466char *line = Xline; 467#endif 468#ifdef CRAY 469char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 470#endif /* CRAY */ 471 472 int 473getpty(ptynum) 474int *ptynum; 475{ 476 register int p; 477#ifdef STREAMSPTY 478 int t; 479 char *ptsname(); 480 481 p = open("/dev/ptmx", 2); 482 if (p > 0) { 483 grantpt(p); 484 unlockpt(p); 485 strcpy(line, ptsname(p)); 486 return(p); 487 } 488 489#else /* ! STREAMSPTY */ 490#ifndef CRAY 491 register char *cp, *p1, *p2; 492 register int i; 493#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207 494 int dummy; 495#endif 496 497#ifndef __hpux 498 (void) sprintf(line, "/dev/ptyXX"); 499 p1 = &line[8]; 500 p2 = &line[9]; 501#else 502 (void) sprintf(line, "/dev/ptym/ptyXX"); 503 p1 = &line[13]; 504 p2 = &line[14]; 505#endif 506 507 for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) { 508 struct stat stb; 509 510 *p1 = *cp; 511 *p2 = '0'; 512 /* 513 * This stat() check is just to keep us from 514 * looping through all 256 combinations if there 515 * aren't that many ptys available. 516 */ 517 if (stat(line, &stb) < 0) 518 break; 519 for (i = 0; i < 16; i++) { 520 *p2 = "0123456789abcdef"[i]; 521 p = open(line, 2); 522 if (p > 0) { 523#ifndef __hpux 524 line[5] = 't'; 525#else 526 for (p1 = &line[8]; *p1; p1++) 527 *p1 = *(p1+1); 528 line[9] = 't'; 529#endif 530 chown(line, 0, 0); 531 chmod(line, 0600); 532#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207 533 if (ioctl(p, TIOCGPGRP, &dummy) == 0 534 || errno != EIO) { 535 chmod(line, 0666); 536 close(p); 537 line[5] = 'p'; 538 } else 539#endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */ 540 return(p); 541 } 542 } 543 } 544#else /* CRAY */ 545 extern lowpty, highpty; 546 struct stat sb; 547 548 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) { 549 (void) sprintf(myline, "/dev/pty/%03d", *ptynum); 550 p = open(myline, 2); 551 if (p < 0) 552 continue; 553 (void) sprintf(line, "/dev/ttyp%03d", *ptynum); 554 /* 555 * Here are some shenanigans to make sure that there 556 * are no listeners lurking on the line. 557 */ 558 if(stat(line, &sb) < 0) { 559 (void) close(p); 560 continue; 561 } 562 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) { 563 chown(line, 0, 0); 564 chmod(line, 0600); 565 (void)close(p); 566 p = open(myline, 2); 567 if (p < 0) 568 continue; 569 } 570 /* 571 * Now it should be safe...check for accessability. 572 */ 573 if (access(line, 6) == 0) 574 return(p); 575 else { 576 /* no tty side to pty so skip it */ 577 (void) close(p); 578 } 579 } 580#endif /* CRAY */ 581#endif /* STREAMSPTY */ 582 return(-1); 583} 584#endif /* convex */ 585 586#ifdef LINEMODE 587/* 588 * tty_flowmode() Find out if flow control is enabled or disabled. 589 * tty_linemode() Find out if linemode (external processing) is enabled. 590 * tty_setlinemod(on) Turn on/off linemode. 591 * tty_isecho() Find out if echoing is turned on. 592 * tty_setecho(on) Enable/disable character echoing. 593 * tty_israw() Find out if terminal is in RAW mode. 594 * tty_binaryin(on) Turn on/off BINARY on input. 595 * tty_binaryout(on) Turn on/off BINARY on output. 596 * tty_isediting() Find out if line editing is enabled. 597 * tty_istrapsig() Find out if signal trapping is enabled. 598 * tty_setedit(on) Turn on/off line editing. 599 * tty_setsig(on) Turn on/off signal trapping. 600 * tty_issofttab() Find out if tab expansion is enabled. 601 * tty_setsofttab(on) Turn on/off soft tab expansion. 602 * tty_islitecho() Find out if typed control chars are echoed literally 603 * tty_setlitecho() Turn on/off literal echo of control chars 604 * tty_tspeed(val) Set transmit speed to val. 605 * tty_rspeed(val) Set receive speed to val. 606 */ 607 608#ifdef convex 609static int linestate; 610#endif 611 612 int 613tty_linemode() 614{ 615#ifndef convex 616#ifndef USE_TERMIO 617 return(termbuf.state & TS_EXTPROC); 618#else 619 return(termbuf.c_lflag & EXTPROC); 620#endif 621#else 622 return(linestate); 623#endif 624} 625 626 void 627tty_setlinemode(on) 628 int on; 629{ 630#ifdef TIOCEXT 631# ifndef convex 632 set_termbuf(); 633# else 634 linestate = on; 635# endif 636 (void) ioctl(pty, TIOCEXT, (char *)&on); 637# ifndef convex 638 init_termbuf(); 639# endif 640#else /* !TIOCEXT */ 641# ifdef EXTPROC 642 if (on) 643 termbuf.c_lflag |= EXTPROC; 644 else 645 termbuf.c_lflag &= ~EXTPROC; 646# endif 647#endif /* TIOCEXT */ 648} 649#endif /* LINEMODE */ 650 651 int 652tty_isecho() 653{ 654#ifndef USE_TERMIO 655 return (termbuf.sg.sg_flags & ECHO); 656#else 657 return (termbuf.c_lflag & ECHO); 658#endif 659} 660 661 int 662tty_flowmode() 663{ 664#ifndef USE_TERMIO 665 return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0); 666#else 667 return((termbuf.c_iflag & IXON) ? 1 : 0); 668#endif 669} 670 671 int 672tty_restartany() 673{ 674#ifndef USE_TERMIO 675# ifdef DECCTQ 676 return((termbuf.lflags & DECCTQ) ? 0 : 1); 677# else 678 return(-1); 679# endif 680#else 681 return((termbuf.c_iflag & IXANY) ? 1 : 0); 682#endif 683} 684 685 void 686tty_setecho(on) 687 int on; 688{ 689#ifndef USE_TERMIO 690 if (on) 691 termbuf.sg.sg_flags |= ECHO|CRMOD; 692 else 693 termbuf.sg.sg_flags &= ~(ECHO|CRMOD); 694#else 695 if (on) 696 termbuf.c_lflag |= ECHO; 697 else 698 termbuf.c_lflag &= ~ECHO; 699#endif 700} 701 702 int 703tty_israw() 704{ 705#ifndef USE_TERMIO 706 return(termbuf.sg.sg_flags & RAW); 707#else 708 return(!(termbuf.c_lflag & ICANON)); 709#endif 710} 711 712#if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) 713 int 714tty_setraw(on) 715{ 716# ifndef USE_TERMIO 717 if (on) 718 termbuf.sg.sg_flags |= RAW; 719 else 720 termbuf.sg.sg_flags &= ~RAW; 721# else 722 if (on) 723 termbuf.c_lflag &= ~ICANON; 724 else 725 termbuf.c_lflag |= ICANON; 726# endif 727} 728#endif 729 730 void 731tty_binaryin(on) 732 int on; 733{ 734#ifndef USE_TERMIO 735 if (on) 736 termbuf.lflags |= LPASS8; 737 else 738 termbuf.lflags &= ~LPASS8; 739#else 740 if (on) { 741 termbuf.c_iflag &= ~ISTRIP; 742 } else { 743 termbuf.c_iflag |= ISTRIP; 744 } 745#endif 746} 747 748 void 749tty_binaryout(on) 750 int on; 751{ 752#ifndef USE_TERMIO 753 if (on) 754 termbuf.lflags |= LLITOUT; 755 else 756 termbuf.lflags &= ~LLITOUT; 757#else 758 if (on) { 759 termbuf.c_cflag &= ~(CSIZE|PARENB); 760 termbuf.c_cflag |= CS8; 761 termbuf.c_oflag &= ~OPOST; 762 } else { 763 termbuf.c_cflag &= ~CSIZE; 764 termbuf.c_cflag |= CS7|PARENB; 765 termbuf.c_oflag |= OPOST; 766 } 767#endif 768} 769 770 int 771tty_isbinaryin() 772{ 773#ifndef USE_TERMIO 774 return(termbuf.lflags & LPASS8); 775#else 776 return(!(termbuf.c_iflag & ISTRIP)); 777#endif 778} 779 780 int 781tty_isbinaryout() 782{ 783#ifndef USE_TERMIO 784 return(termbuf.lflags & LLITOUT); 785#else 786 return(!(termbuf.c_oflag&OPOST)); 787#endif 788} 789 790#ifdef LINEMODE 791 int 792tty_isediting() 793{ 794#ifndef USE_TERMIO 795 return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); 796#else 797 return(termbuf.c_lflag & ICANON); 798#endif 799} 800 801 int 802tty_istrapsig() 803{ 804#ifndef USE_TERMIO 805 return(!(termbuf.sg.sg_flags&RAW)); 806#else 807 return(termbuf.c_lflag & ISIG); 808#endif 809} 810 811 void 812tty_setedit(on) 813 int on; 814{ 815#ifndef USE_TERMIO 816 if (on) 817 termbuf.sg.sg_flags &= ~CBREAK; 818 else 819 termbuf.sg.sg_flags |= CBREAK; 820#else 821 if (on) 822 termbuf.c_lflag |= ICANON; 823 else 824 termbuf.c_lflag &= ~ICANON; 825#endif 826} 827 828 void 829tty_setsig(on) 830 int on; 831{ 832#ifndef USE_TERMIO 833 if (on) 834 ; 835#else 836 if (on) 837 termbuf.c_lflag |= ISIG; 838 else 839 termbuf.c_lflag &= ~ISIG; 840#endif 841} 842#endif /* LINEMODE */ 843 844 int 845tty_issofttab() 846{ 847#ifndef USE_TERMIO 848 return (termbuf.sg.sg_flags & XTABS); 849#else 850# ifdef OXTABS 851 return (termbuf.c_oflag & OXTABS); 852# endif 853# ifdef TABDLY 854 return ((termbuf.c_oflag & TABDLY) == TAB3); 855# endif 856#endif 857} 858 859 void 860tty_setsofttab(on) 861 int on; 862{ 863#ifndef USE_TERMIO 864 if (on) 865 termbuf.sg.sg_flags |= XTABS; 866 else 867 termbuf.sg.sg_flags &= ~XTABS; 868#else 869 if (on) { 870# ifdef OXTABS 871 termbuf.c_oflag |= OXTABS; 872# endif 873# ifdef TABDLY 874 termbuf.c_oflag &= ~TABDLY; 875 termbuf.c_oflag |= TAB3; 876# endif 877 } else { 878# ifdef OXTABS 879 termbuf.c_oflag &= ~OXTABS; 880# endif 881# ifdef TABDLY 882 termbuf.c_oflag &= ~TABDLY; 883 termbuf.c_oflag |= TAB0; 884# endif 885 } 886#endif 887} 888 889 int 890tty_islitecho() 891{ 892#ifndef USE_TERMIO 893 return (!(termbuf.lflags & LCTLECH)); 894#else 895# ifdef ECHOCTL 896 return (!(termbuf.c_lflag & ECHOCTL)); 897# endif 898# ifdef TCTLECH 899 return (!(termbuf.c_lflag & TCTLECH)); 900# endif 901# if !defined(ECHOCTL) && !defined(TCTLECH) 902 return (0); /* assumes ctl chars are echoed '^x' */ 903# endif 904#endif 905} 906 907 void 908tty_setlitecho(on) 909 int on; 910{ 911#ifndef USE_TERMIO 912 if (on) 913 termbuf.lflags &= ~LCTLECH; 914 else 915 termbuf.lflags |= LCTLECH; 916#else 917# ifdef ECHOCTL 918 if (on) 919 termbuf.c_lflag &= ~ECHOCTL; 920 else 921 termbuf.c_lflag |= ECHOCTL; 922# endif 923# ifdef TCTLECH 924 if (on) 925 termbuf.c_lflag &= ~TCTLECH; 926 else 927 termbuf.c_lflag |= TCTLECH; 928# endif 929#endif 930} 931 932 int 933tty_iscrnl() 934{ 935#ifndef USE_TERMIO 936 return (termbuf.sg.sg_flags & CRMOD); 937#else 938 return (termbuf.c_iflag & ICRNL); 939#endif 940} 941 942/* 943 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 944 */ 945#if B4800 != 4800 946#define DECODE_BAUD 947#endif 948 949#ifdef DECODE_BAUD 950 951/* 952 * A table of available terminal speeds 953 */ 954struct termspeeds { 955 int speed; 956 int value; 957} termspeeds[] = { 958 { 0, B0 }, { 50, B50 }, { 75, B75 }, 959 { 110, B110 }, { 134, B134 }, { 150, B150 }, 960 { 200, B200 }, { 300, B300 }, { 600, B600 }, 961 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 962 { 4800, B4800 }, 963#ifdef B7200 964 { 7200, B7200 }, 965#endif 966 { 9600, B9600 }, 967#ifdef B14400 968 { 14400, B14400 }, 969#endif 970#ifdef B19200 971 { 19200, B19200 }, 972#endif 973#ifdef B28800 974 { 28800, B28800 }, 975#endif 976#ifdef B38400 977 { 38400, B38400 }, 978#endif 979#ifdef B57600 980 { 57600, B57600 }, 981#endif 982#ifdef B115200 983 { 115200, B115200 }, 984#endif 985#ifdef B230400 986 { 230400, B230400 }, 987#endif 988 { -1, 0 } 989}; 990#endif /* DECODE_BUAD */ 991 992 void 993tty_tspeed(val) 994 int val; 995{ 996#ifdef DECODE_BAUD 997 register struct termspeeds *tp; 998 999 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 1000 ; 1001 if (tp->speed == -1) /* back up to last valid value */ 1002 --tp; 1003 cfsetospeed(&termbuf, tp->value); 1004#else /* DECODE_BUAD */ 1005 cfsetospeed(&termbuf, val); 1006#endif /* DECODE_BUAD */ 1007} 1008 1009 void 1010tty_rspeed(val) 1011 int val; 1012{ 1013#ifdef DECODE_BAUD 1014 register struct termspeeds *tp; 1015 1016 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 1017 ; 1018 if (tp->speed == -1) /* back up to last valid value */ 1019 --tp; 1020 cfsetispeed(&termbuf, tp->value); 1021#else /* DECODE_BAUD */ 1022 cfsetispeed(&termbuf, val); 1023#endif /* DECODE_BAUD */ 1024} 1025 1026#if defined(CRAY2) && defined(UNICOS5) 1027 int 1028tty_isnewmap() 1029{ 1030 return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) && 1031 !(termbuf.c_oflag & ONLRET)); 1032} 1033#endif 1034 1035#ifdef PARENT_DOES_UTMP 1036# ifndef NEWINIT 1037extern struct utmp wtmp; 1038extern char wtmpf[]; 1039# else /* NEWINIT */ 1040int gotalarm; 1041 1042 /* ARGSUSED */ 1043 void 1044nologinproc(sig) 1045 int sig; 1046{ 1047 gotalarm++; 1048} 1049# endif /* NEWINIT */ 1050#endif /* PARENT_DOES_UTMP */ 1051 1052#ifndef NEWINIT 1053# ifdef PARENT_DOES_UTMP 1054extern void utmp_sig_init P((void)); 1055extern void utmp_sig_reset P((void)); 1056extern void utmp_sig_wait P((void)); 1057extern void utmp_sig_notify P((int)); 1058# endif /* PARENT_DOES_UTMP */ 1059#endif 1060 1061/* 1062 * getptyslave() 1063 * 1064 * Open the slave side of the pty, and do any initialization 1065 * that is necessary. The return value is a file descriptor 1066 * for the slave side. 1067 */ 1068 int 1069getptyslave() 1070{ 1071 register int t = -1; 1072 1073#if !defined(CRAY) || !defined(NEWINIT) 1074# ifdef LINEMODE 1075 int waslm; 1076# endif 1077# ifdef TIOCGWINSZ 1078 struct winsize ws; 1079 extern int def_row, def_col; 1080# endif 1081 extern int def_tspeed, def_rspeed; 1082 /* 1083 * Opening the slave side may cause initilization of the 1084 * kernel tty structure. We need remember the state of 1085 * if linemode was turned on 1086 * terminal window size 1087 * terminal speed 1088 * so that we can re-set them if we need to. 1089 */ 1090# ifdef LINEMODE 1091 waslm = tty_linemode(); 1092# endif 1093 1094 1095 /* 1096 * Make sure that we don't have a controlling tty, and 1097 * that we are the session (process group) leader. 1098 */ 1099# ifdef TIOCNOTTY 1100 t = open(_PATH_TTY, O_RDWR); 1101 if (t >= 0) { 1102 (void) ioctl(t, TIOCNOTTY, (char *)0); 1103 (void) close(t); 1104 } 1105# endif 1106 1107 1108# ifdef PARENT_DOES_UTMP 1109 /* 1110 * Wait for our parent to get the utmp stuff to get done. 1111 */ 1112 utmp_sig_wait(); 1113# endif 1114 1115 t = cleanopen(line); 1116 if (t < 0) 1117 fatalperror(net, line); 1118 1119#ifdef STREAMSPTY 1120#ifdef USE_TERMIO 1121 ttyfd = t; 1122#endif 1123 if (ioctl(t, I_PUSH, "ptem") < 0) 1124 fatal(net, "I_PUSH ptem"); 1125 if (ioctl(t, I_PUSH, "ldterm") < 0) 1126 fatal(net, "I_PUSH ldterm"); 1127 if (ioctl(t, I_PUSH, "ttcompat") < 0) 1128 fatal(net, "I_PUSH ttcompat"); 1129 if (ioctl(pty, I_PUSH, "pckt") < 0) 1130 fatal(net, "I_PUSH pckt"); 1131#endif 1132 1133 /* 1134 * set up the tty modes as we like them to be. 1135 */ 1136 init_termbuf(); 1137# ifdef TIOCGWINSZ 1138 if (def_row || def_col) { 1139 memset((char *)&ws, 0, sizeof(ws)); 1140 ws.ws_col = def_col; 1141 ws.ws_row = def_row; 1142 (void)ioctl(t, TIOCSWINSZ, (char *)&ws); 1143 } 1144# endif 1145 1146 /* 1147 * Settings for sgtty based systems 1148 */ 1149# ifndef USE_TERMIO 1150 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS; 1151# endif /* USE_TERMIO */ 1152 1153 /* 1154 * Settings for UNICOS (and HPUX) 1155 */ 1156# if defined(CRAY) || defined(__hpux) 1157 termbuf.c_oflag = OPOST|ONLCR|TAB3; 1158 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; 1159 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; 1160 termbuf.c_cflag = EXTB|HUPCL|CS8; 1161# endif 1162 1163 /* 1164 * Settings for all other termios/termio based 1165 * systems, other than 4.4BSD. In 4.4BSD the 1166 * kernel does the initial terminal setup. 1167 */ 1168# if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) 1169# ifndef OXTABS 1170# define OXTABS 0 1171# endif 1172 termbuf.c_lflag |= ECHO; 1173 termbuf.c_oflag |= ONLCR|OXTABS; 1174 termbuf.c_iflag |= ICRNL; 1175 termbuf.c_iflag &= ~IXOFF; 1176# endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */ 1177 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); 1178 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); 1179# ifdef LINEMODE 1180 if (waslm) 1181 tty_setlinemode(1); 1182# endif /* LINEMODE */ 1183 1184 /* 1185 * Set the tty modes, and make this our controlling tty. 1186 */ 1187 set_termbuf(); 1188 if (login_tty(t) == -1) 1189 fatalperror(net, "login_tty"); 1190#endif /* !defined(CRAY) || !defined(NEWINIT) */ 1191 if (net > 2) 1192 (void) close(net); 1193#if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) 1194 /* 1195 * Leave the pty open so that we can write out the rlogin 1196 * protocol for /bin/login, if the authentication works. 1197 */ 1198#else 1199 if (pty > 2) { 1200 (void) close(pty); 1201 pty = -1; 1202 } 1203#endif 1204} 1205 1206#if !defined(CRAY) || !defined(NEWINIT) 1207#ifndef O_NOCTTY 1208#define O_NOCTTY 0 1209#endif 1210/* 1211 * Open the specified slave side of the pty, 1212 * making sure that we have a clean tty. 1213 */ 1214 int 1215cleanopen(line) 1216 char *line; 1217{ 1218 register int t; 1219#ifdef UNICOS7x 1220 struct secstat secbuf; 1221#endif /* UNICOS7x */ 1222 1223#ifndef STREAMSPTY 1224 /* 1225 * Make sure that other people can't open the 1226 * slave side of the connection. 1227 */ 1228 (void) chown(line, 0, 0); 1229 (void) chmod(line, 0600); 1230#endif 1231 1232# if !defined(CRAY) && (BSD > 43) 1233 (void) revoke(line); 1234# endif 1235#ifdef UNICOS7x 1236 if (secflag) { 1237 if (secstat(line, &secbuf) < 0) 1238 return(-1); 1239 if (setulvl(secbuf.st_slevel) < 0) 1240 return(-1); 1241 if (setucmp(secbuf.st_compart) < 0) 1242 return(-1); 1243 } 1244#endif /* UNICOS7x */ 1245 1246 t = open(line, O_RDWR|O_NOCTTY); 1247 1248#ifdef UNICOS7x 1249 if (secflag) { 1250 if (setulvl(sysv.sy_minlvl) < 0) 1251 return(-1); 1252 if (setucmp(0) < 0) 1253 return(-1); 1254 } 1255#endif /* UNICOS7x */ 1256 1257 if (t < 0) 1258 return(-1); 1259 1260 /* 1261 * Hangup anybody else using this ttyp, then reopen it for 1262 * ourselves. 1263 */ 1264# if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY) 1265 (void) signal(SIGHUP, SIG_IGN); 1266 vhangup(); 1267 (void) signal(SIGHUP, SIG_DFL); 1268 t = open(line, O_RDWR|O_NOCTTY); 1269 if (t < 0) 1270 return(-1); 1271# endif 1272# if defined(CRAY) && defined(TCVHUP) 1273 { 1274 register int i; 1275 (void) signal(SIGHUP, SIG_IGN); 1276 (void) ioctl(t, TCVHUP, (char *)0); 1277 (void) signal(SIGHUP, SIG_DFL); 1278 1279#ifdef UNICOS7x 1280 if (secflag) { 1281 if (secstat(line, &secbuf) < 0) 1282 return(-1); 1283 if (setulvl(secbuf.st_slevel) < 0) 1284 return(-1); 1285 if (setucmp(secbuf.st_compart) < 0) 1286 return(-1); 1287 } 1288#endif /* UNICOS7x */ 1289 1290 i = open(line, O_RDWR); 1291 1292#ifdef UNICOS7x 1293 if (secflag) { 1294 if (setulvl(sysv.sy_minlvl) < 0) 1295 return(-1); 1296 if (setucmp(0) < 0) 1297 return(-1); 1298 } 1299#endif /* UNICOS7x */ 1300 1301 if (i < 0) 1302 return(-1); 1303 (void) close(t); 1304 t = i; 1305 } 1306# endif /* defined(CRAY) && defined(TCVHUP) */ 1307 return(t); 1308} 1309#endif /* !defined(CRAY) || !defined(NEWINIT) */ 1310 1311#if BSD <= 43 1312 1313 int 1314login_tty(t) 1315 int t; 1316{ 1317 if (setsid() < 0) { 1318#ifdef ultrix 1319 /* 1320 * The setsid() may have failed because we 1321 * already have a pgrp == pid. Zero out 1322 * our pgrp and try again... 1323 */ 1324 if ((setpgrp(0, 0) < 0) || (setsid() < 0)) 1325#endif 1326 fatalperror(net, "setsid()"); 1327 } 1328# ifdef TIOCSCTTY 1329 if (ioctl(t, TIOCSCTTY, (char *)0) < 0) 1330 fatalperror(net, "ioctl(sctty)"); 1331# if defined(CRAY) 1332 /* 1333 * Close the hard fd to /dev/ttypXXX, and re-open through 1334 * the indirect /dev/tty interface. 1335 */ 1336 close(t); 1337 if ((t = open("/dev/tty", O_RDWR)) < 0) 1338 fatalperror(net, "open(/dev/tty)"); 1339# endif 1340# else 1341 /* 1342 * We get our controlling tty assigned as a side-effect 1343 * of opening up a tty device. But on BSD based systems, 1344 * this only happens if our process group is zero. The 1345 * setsid() call above may have set our pgrp, so clear 1346 * it out before opening the tty... 1347 */ 1348# ifndef SOLARIS 1349 (void) setpgrp(0, 0); 1350# else 1351 (void) setpgrp(); 1352# endif 1353 close(open(line, O_RDWR)); 1354# endif 1355 if (t != 0) 1356 (void) dup2(t, 0); 1357 if (t != 1) 1358 (void) dup2(t, 1); 1359 if (t != 2) 1360 (void) dup2(t, 2); 1361 if (t > 2) 1362 close(t); 1363 return(0); 1364} 1365#endif /* BSD <= 43 */ 1366 1367#ifdef NEWINIT 1368char *gen_id = "fe"; 1369#endif 1370 1371/* 1372 * startslave(host) 1373 * 1374 * Given a hostname, do whatever 1375 * is necessary to startup the login process on the slave side of the pty. 1376 */ 1377 1378/* ARGSUSED */ 1379 void 1380startslave(host, autologin, autoname) 1381 char *host; 1382 int autologin; 1383 char *autoname; 1384{ 1385 register int i; 1386 long time(); 1387 char name[256]; 1388#ifdef NEWINIT 1389 extern char *ptyip; 1390 struct init_request request; 1391 void nologinproc(); 1392 register int n; 1393#endif /* NEWINIT */ 1394 1395#if defined(AUTHENTICATION) 1396 if (!autoname || !autoname[0]) 1397 autologin = 0; 1398 1399 if (autologin < auth_level) { 1400 fatal(net, "Authorization failed"); 1401 exit(1); 1402 } 1403#endif 1404 1405#ifndef NEWINIT 1406# ifdef PARENT_DOES_UTMP 1407 utmp_sig_init(); 1408# endif /* PARENT_DOES_UTMP */ 1409 1410 if ((i = fork()) < 0) 1411 fatalperror(net, "fork"); 1412 if (i) { 1413# ifdef PARENT_DOES_UTMP 1414 /* 1415 * Cray parent will create utmp entry for child and send 1416 * signal to child to tell when done. Child waits for signal 1417 * before doing anything important. 1418 */ 1419 register int pid = i; 1420 void sigjob P((int)); 1421 1422 setpgrp(); 1423 utmp_sig_reset(); /* reset handler to default */ 1424 /* 1425 * Create utmp entry for child 1426 */ 1427 (void) time(&wtmp.ut_time); 1428 wtmp.ut_type = LOGIN_PROCESS; 1429 wtmp.ut_pid = pid; 1430 SCPYN(wtmp.ut_user, "LOGIN"); 1431 SCPYN(wtmp.ut_host, host); 1432 SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1); 1433#ifndef __hpux 1434 SCPYN(wtmp.ut_id, wtmp.ut_line+3); 1435#else 1436 SCPYN(wtmp.ut_id, wtmp.ut_line+7); 1437#endif 1438 pututline(&wtmp); 1439 endutent(); 1440 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { 1441 (void) write(i, (char *)&wtmp, sizeof(struct utmp)); 1442 (void) close(i); 1443 } 1444#ifdef CRAY 1445 (void) signal(WJSIGNAL, sigjob); 1446#endif 1447 utmp_sig_notify(pid); 1448# endif /* PARENT_DOES_UTMP */ 1449 } else { 1450 getptyslave(autologin); 1451 start_login(host, autologin, autoname); 1452 /*NOTREACHED*/ 1453 } 1454#else /* NEWINIT */ 1455 1456 /* 1457 * Init will start up login process if we ask nicely. We only wait 1458 * for it to start up and begin normal telnet operation. 1459 */ 1460 if ((i = open(INIT_FIFO, O_WRONLY)) < 0) { 1461 char tbuf[128]; 1462 (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO); 1463 fatalperror(net, tbuf); 1464 } 1465 memset((char *)&request, 0, sizeof(request)); 1466 request.magic = INIT_MAGIC; 1467 SCPYN(request.gen_id, gen_id); 1468 SCPYN(request.tty_id, &line[8]); 1469 SCPYN(request.host, host); 1470 SCPYN(request.term_type, terminaltype ? terminaltype : "network"); 1471#if !defined(UNICOS5) 1472 request.signal = SIGCLD; 1473 request.pid = getpid(); 1474#endif 1475#ifdef BFTPDAEMON 1476 /* 1477 * Are we working as the bftp daemon? 1478 */ 1479 if (bftpd) { 1480 SCPYN(request.exec_name, BFTPPATH); 1481 } 1482#endif /* BFTPDAEMON */ 1483 if (write(i, (char *)&request, sizeof(request)) < 0) { 1484 char tbuf[128]; 1485 (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO); 1486 fatalperror(net, tbuf); 1487 } 1488 (void) close(i); 1489 (void) signal(SIGALRM, nologinproc); 1490 for (i = 0; ; i++) { 1491 char tbuf[128]; 1492 alarm(15); 1493 n = read(pty, ptyip, BUFSIZ); 1494 if (i == 3 || n >= 0 || !gotalarm) 1495 break; 1496 gotalarm = 0; 1497 sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line); 1498 (void) write(net, tbuf, strlen(tbuf)); 1499 } 1500 if (n < 0 && gotalarm) 1501 fatal(net, "/etc/init didn't start login process"); 1502 pcc += n; 1503 alarm(0); 1504 (void) signal(SIGALRM, SIG_DFL); 1505 1506 return; 1507#endif /* NEWINIT */ 1508} 1509 1510char *envinit[3]; 1511extern char **environ; 1512 1513 void 1514init_env() 1515{ 1516 extern char *getenv(); 1517 char **envp; 1518 1519 envp = envinit; 1520 if (*envp = getenv("TZ")) 1521 *envp++ -= 3; 1522#if defined(CRAY) || defined(__hpux) 1523 else 1524 *envp++ = "TZ=GMT0"; 1525#endif 1526 *envp = 0; 1527 environ = envinit; 1528} 1529 1530#ifndef NEWINIT 1531 1532/* 1533 * start_login(host) 1534 * 1535 * Assuming that we are now running as a child processes, this 1536 * function will turn us into the login process. 1537 */ 1538 1539 void 1540start_login(host, autologin, name) 1541 char *host; 1542 int autologin; 1543 char *name; 1544{ 1545 register char *cp; 1546 register char **argv; 1547 char **addarg(); 1548 extern char *getenv(); 1549#ifdef UTMPX 1550 register int pid = getpid(); 1551 struct utmpx utmpx; 1552#endif 1553#ifdef SOLARIS 1554 char *term; 1555 char termbuf[64]; 1556#endif 1557 1558#ifdef UTMPX 1559 /* 1560 * Create utmp entry for child 1561 */ 1562 1563 memset(&utmpx, 0, sizeof(utmpx)); 1564 SCPYN(utmpx.ut_user, ".telnet"); 1565 SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1); 1566 utmpx.ut_pid = pid; 1567 utmpx.ut_id[0] = 't'; 1568 utmpx.ut_id[1] = 'n'; 1569 utmpx.ut_id[2] = SC_WILDC; 1570 utmpx.ut_id[3] = SC_WILDC; 1571 utmpx.ut_type = LOGIN_PROCESS; 1572 (void) time(&utmpx.ut_tv.tv_sec); 1573 if (makeutx(&utmpx) == NULL) 1574 fatal(net, "makeutx failed"); 1575#endif 1576 1577 scrub_env(); 1578 1579 /* 1580 * -h : pass on name of host. 1581 * WARNING: -h is accepted by login if and only if 1582 * getuid() == 0. 1583 * -p : don't clobber the environment (so terminal type stays set). 1584 * 1585 * -f : force this login, he has already been authenticated 1586 */ 1587 argv = addarg(0, "login"); 1588 1589#if !defined(NO_LOGIN_H) 1590 1591# if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) 1592 /* 1593 * Don't add the "-h host" option if we are going 1594 * to be adding the "-r host" option down below... 1595 */ 1596 if ((auth_level < 0) || (autologin != AUTH_VALID)) 1597# endif 1598 { 1599 argv = addarg(argv, "-h"); 1600 argv = addarg(argv, host); 1601#ifdef SOLARIS 1602 /* 1603 * SVR4 version of -h takes TERM= as second arg, or - 1604 */ 1605 term = getenv("TERM"); 1606 if (term == NULL || term[0] == 0) { 1607 term = "-"; 1608 } else { 1609 strcpy(termbuf, "TERM="); 1610 strncat(termbuf, term, sizeof(termbuf) - 6); 1611 term = termbuf; 1612 } 1613 argv = addarg(argv, term); 1614#endif 1615 } 1616#endif 1617#if !defined(NO_LOGIN_P) 1618 argv = addarg(argv, "-p"); 1619#endif 1620#ifdef LINEMODE 1621 /* 1622 * Set the environment variable "LINEMODE" to either 1623 * "real" or "kludge" if we are operating in either 1624 * real or kludge linemode. 1625 */ 1626 if (lmodetype == REAL_LINEMODE) 1627 setenv("LINEMODE", "real", 1); 1628# ifdef KLUDGELINEMODE 1629 else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) 1630 setenv("LINEMODE", "kludge", 1); 1631# endif 1632#endif 1633#ifdef BFTPDAEMON 1634 /* 1635 * Are we working as the bftp daemon? If so, then ask login 1636 * to start bftp instead of shell. 1637 */ 1638 if (bftpd) { 1639 argv = addarg(argv, "-e"); 1640 argv = addarg(argv, BFTPPATH); 1641 } else 1642#endif 1643#if defined (SecurID) 1644 /* 1645 * don't worry about the -f that might get sent. 1646 * A -s is supposed to override it anyhow. 1647 */ 1648 if (require_SecurID) 1649 argv = addarg(argv, "-s"); 1650#endif 1651#if defined (AUTHENTICATION) 1652 if (auth_level >= 0 && autologin == AUTH_VALID) { 1653# if !defined(NO_LOGIN_F) 1654 argv = addarg(argv, "-f"); 1655 argv = addarg(argv, name); 1656# else 1657# if defined(LOGIN_R) 1658 /* 1659 * We don't have support for "login -f", but we 1660 * can fool /bin/login into thinking that we are 1661 * rlogind, and allow us to log in without a 1662 * password. The rlogin protocol expects 1663 * local-user\0remote-user\0term/speed\0 1664 */ 1665 1666 if (pty > 2) { 1667 register char *cp; 1668 char speed[128]; 1669 int isecho, israw, xpty, len; 1670 extern int def_rspeed; 1671# ifndef LOGIN_HOST 1672 /* 1673 * Tell login that we are coming from "localhost". 1674 * If we passed in the real host name, then the 1675 * user would have to allow .rhost access from 1676 * every machine that they want authenticated 1677 * access to work from, which sort of defeats 1678 * the purpose of an authenticated login... 1679 * So, we tell login that the session is coming 1680 * from "localhost", and the user will only have 1681 * to have "localhost" in their .rhost file. 1682 */ 1683# define LOGIN_HOST "localhost" 1684# endif 1685 argv = addarg(argv, "-r"); 1686 argv = addarg(argv, LOGIN_HOST); 1687 1688 xpty = pty; 1689# ifndef STREAMSPTY 1690 pty = 0; 1691# else 1692 ttyfd = 0; 1693# endif 1694 init_termbuf(); 1695 isecho = tty_isecho(); 1696 israw = tty_israw(); 1697 if (isecho || !israw) { 1698 tty_setecho(0); /* Turn off echo */ 1699 tty_setraw(1); /* Turn on raw */ 1700 set_termbuf(); 1701 } 1702 len = strlen(name)+1; 1703 write(xpty, name, len); 1704 write(xpty, name, len); 1705 sprintf(speed, "%s/%d", (cp = getenv("TERM")) ? cp : "", 1706 (def_rspeed > 0) ? def_rspeed : 9600); 1707 len = strlen(speed)+1; 1708 write(xpty, speed, len); 1709 1710 if (isecho || !israw) { 1711 init_termbuf(); 1712 tty_setecho(isecho); 1713 tty_setraw(israw); 1714 set_termbuf(); 1715 if (!israw) { 1716 /* 1717 * Write a newline to ensure 1718 * that login will be able to 1719 * read the line... 1720 */ 1721 write(xpty, "\n", 1); 1722 } 1723 } 1724 pty = xpty; 1725 } 1726# else 1727 argv = addarg(argv, name); 1728# endif 1729# endif 1730 } else 1731#endif 1732 if (getenv("USER")) { 1733 argv = addarg(argv, getenv("USER")); 1734#if defined(LOGIN_ARGS) && defined(NO_LOGIN_P) 1735 { 1736 register char **cpp; 1737 for (cpp = environ; *cpp; cpp++) 1738 argv = addarg(argv, *cpp); 1739 } 1740#endif 1741 /* 1742 * Assume that login will set the USER variable 1743 * correctly. For SysV systems, this means that 1744 * USER will no longer be set, just LOGNAME by 1745 * login. (The problem is that if the auto-login 1746 * fails, and the user then specifies a different 1747 * account name, he can get logged in with both 1748 * LOGNAME and USER in his environment, but the 1749 * USER value will be wrong. 1750 */ 1751 unsetenv("USER"); 1752 } 1753#ifdef SOLARIS 1754 else { 1755 char **p; 1756 1757 argv = addarg(argv, ""); /* no login name */ 1758 for (p = environ; *p; p++) { 1759 argv = addarg(argv, *p); 1760 } 1761 } 1762#endif /* SOLARIS */ 1763#if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) 1764 if (pty > 2) 1765 close(pty); 1766#endif 1767 closelog(); 1768 /* 1769 * This sleep(1) is in here so that telnetd can 1770 * finish up with the tty. There's a race condition 1771 * the login banner message gets lost... 1772 */ 1773 sleep(1); 1774 execv(_PATH_LOGIN, argv); 1775 1776 syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN); 1777 fatalperror(net, _PATH_LOGIN); 1778 /*NOTREACHED*/ 1779} 1780 1781 char ** 1782addarg(argv, val) 1783 register char **argv; 1784 register char *val; 1785{ 1786 register char **cpp; 1787 1788 if (argv == NULL) { 1789 /* 1790 * 10 entries, a leading length, and a null 1791 */ 1792 argv = (char **)malloc(sizeof(*argv) * 12); 1793 if (argv == NULL) 1794 return(NULL); 1795 *argv++ = (char *)10; 1796 *argv = (char *)0; 1797 } 1798 for (cpp = argv; *cpp; cpp++) 1799 ; 1800 if (cpp == &argv[(int)argv[-1]]) { 1801 --argv; 1802 *argv = (char *)((int)(*argv) + 10); 1803 argv = (char **)realloc(argv, sizeof(*argv)*((int)(*argv) + 2)); 1804 if (argv == NULL) 1805 return(NULL); 1806 argv++; 1807 cpp = &argv[(int)argv[-1] - 10]; 1808 } 1809 *cpp++ = val; 1810 *cpp = 0; 1811 return(argv); 1812} 1813#endif /* NEWINIT */ 1814 1815/* 1816 * scrub_env() 1817 * 1818 * Remove a few things from the environment that 1819 * don't need to be there. 1820 */ 1821scrub_env() 1822{ 1823 register char **cpp, **cpp2; 1824 1825 for (cpp2 = cpp = environ; *cpp; cpp++) { 1826 if (strncmp(*cpp, "LD_", 3) && 1827 strncmp(*cpp, "_RLD_", 5) && 1828 strncmp(*cpp, "LIBPATH=", 8) && 1829 strncmp(*cpp, "IFS=", 4)) 1830 *cpp2++ = *cpp; 1831 } 1832 *cpp2 = 0; 1833} 1834 1835/* 1836 * cleanup() 1837 * 1838 * This is the routine to call when we are all through, to 1839 * clean up anything that needs to be cleaned up. 1840 */ 1841 /* ARGSUSED */ 1842 void 1843cleanup(sig) 1844 int sig; 1845{ 1846#ifndef PARENT_DOES_UTMP 1847# if (BSD > 43) || defined(convex) 1848 char *p; 1849 1850 p = line + sizeof("/dev/") - 1; 1851 if (logout(p)) 1852 logwtmp(p, "", ""); 1853 (void)chmod(line, 0666); 1854 (void)chown(line, 0, 0); 1855 *p = 'p'; 1856 (void)chmod(line, 0666); 1857 (void)chown(line, 0, 0); 1858 (void) shutdown(net, 2); 1859 exit(1); 1860# else 1861 void rmut(); 1862 1863 rmut(); 1864 vhangup(); /* XXX */ 1865 (void) shutdown(net, 2); 1866 exit(1); 1867# endif 1868#else /* PARENT_DOES_UTMP */ 1869# ifdef NEWINIT 1870 (void) shutdown(net, 2); 1871 exit(1); 1872# else /* NEWINIT */ 1873# ifdef CRAY 1874 static int incleanup = 0; 1875 register int t; 1876 int child_status; /* status of child process as returned by waitpid */ 1877 int flags = WNOHANG|WUNTRACED; 1878 1879 /* 1880 * 1: Pick up the zombie, if we are being called 1881 * as the signal handler. 1882 * 2: If we are a nested cleanup(), return. 1883 * 3: Try to clean up TMPDIR. 1884 * 4: Fill in utmp with shutdown of process. 1885 * 5: Close down the network and pty connections. 1886 * 6: Finish up the TMPDIR cleanup, if needed. 1887 */ 1888 if (sig == SIGCHLD) { 1889 while (waitpid(-1, &child_status, flags) > 0) 1890 ; /* VOID */ 1891 /* Check if the child process was stopped 1892 * rather than exited. We want cleanup only if 1893 * the child has died. 1894 */ 1895 if (WIFSTOPPED(child_status)) { 1896 return; 1897 } 1898 } 1899 t = sigblock(sigmask(SIGCHLD)); 1900 if (incleanup) { 1901 sigsetmask(t); 1902 return; 1903 } 1904 incleanup = 1; 1905 sigsetmask(t); 1906#ifdef UNICOS7x 1907 if (secflag) { 1908 /* 1909 * We need to set ourselves back to a null 1910 * label to clean up. 1911 */ 1912 1913 setulvl(sysv.sy_minlvl); 1914 setucmp((long)0); 1915 } 1916#endif /* UNICOS7x */ 1917 1918 t = cleantmp(&wtmp); 1919 setutent(); /* just to make sure */ 1920# endif /* CRAY */ 1921 rmut(line); 1922 close(pty); 1923 (void) shutdown(net, 2); 1924# ifdef CRAY 1925 if (t == 0) 1926 cleantmp(&wtmp); 1927# endif /* CRAY */ 1928 exit(1); 1929# endif /* NEWINT */ 1930#endif /* PARENT_DOES_UTMP */ 1931} 1932 1933#if defined(PARENT_DOES_UTMP) && !defined(NEWINIT) 1934/* 1935 * _utmp_sig_rcv 1936 * utmp_sig_init 1937 * utmp_sig_wait 1938 * These three functions are used to coordinate the handling of 1939 * the utmp file between the server and the soon-to-be-login shell. 1940 * The server actually creates the utmp structure, the child calls 1941 * utmp_sig_wait(), until the server calls utmp_sig_notify() and 1942 * signals the future-login shell to proceed. 1943 */ 1944static int caught=0; /* NZ when signal intercepted */ 1945static void (*func)(); /* address of previous handler */ 1946 1947 void 1948_utmp_sig_rcv(sig) 1949 int sig; 1950{ 1951 caught = 1; 1952 (void) signal(SIGUSR1, func); 1953} 1954 1955 void 1956utmp_sig_init() 1957{ 1958 /* 1959 * register signal handler for UTMP creation 1960 */ 1961 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) 1962 fatalperror(net, "telnetd/signal"); 1963} 1964 1965 void 1966utmp_sig_reset() 1967{ 1968 (void) signal(SIGUSR1, func); /* reset handler to default */ 1969} 1970 1971# ifdef __hpux 1972# define sigoff() /* do nothing */ 1973# define sigon() /* do nothing */ 1974# endif 1975 1976 void 1977utmp_sig_wait() 1978{ 1979 /* 1980 * Wait for parent to write our utmp entry. 1981 */ 1982 sigoff(); 1983 while (caught == 0) { 1984 pause(); /* wait until we get a signal (sigon) */ 1985 sigoff(); /* turn off signals while we check caught */ 1986 } 1987 sigon(); /* turn on signals again */ 1988} 1989 1990 void 1991utmp_sig_notify(pid) 1992{ 1993 kill(pid, SIGUSR1); 1994} 1995 1996# ifdef CRAY 1997static int gotsigjob = 0; 1998 1999 /*ARGSUSED*/ 2000 void 2001sigjob(sig) 2002 int sig; 2003{ 2004 register int jid; 2005 register struct jobtemp *jp; 2006 2007 while ((jid = waitjob(NULL)) != -1) { 2008 if (jid == 0) { 2009 return; 2010 } 2011 gotsigjob++; 2012 jobend(jid, NULL, NULL); 2013 } 2014} 2015 2016/* 2017 * jid_getutid: 2018 * called by jobend() before calling cleantmp() 2019 * to find the correct $TMPDIR to cleanup. 2020 */ 2021 2022 struct utmp * 2023jid_getutid(jid) 2024 int jid; 2025{ 2026 struct utmp *cur = NULL; 2027 2028 setutent(); /* just to make sure */ 2029 while (cur = getutent()) { 2030 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { 2031 return(cur); 2032 } 2033 } 2034 2035 return(0); 2036} 2037 2038/* 2039 * Clean up the TMPDIR that login created. 2040 * The first time this is called we pick up the info 2041 * from the utmp. If the job has already gone away, 2042 * then we'll clean up and be done. If not, then 2043 * when this is called the second time it will wait 2044 * for the signal that the job is done. 2045 */ 2046 int 2047cleantmp(wtp) 2048 register struct utmp *wtp; 2049{ 2050 struct utmp *utp; 2051 static int first = 1; 2052 register int mask, omask, ret; 2053 extern struct utmp *getutid P((const struct utmp *_Id)); 2054 2055 2056 mask = sigmask(WJSIGNAL); 2057 2058 if (first == 0) { 2059 omask = sigblock(mask); 2060 while (gotsigjob == 0) 2061 sigpause(omask); 2062 return(1); 2063 } 2064 first = 0; 2065 setutent(); /* just to make sure */ 2066 2067 utp = getutid(wtp); 2068 if (utp == 0) { 2069 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 2070 return(-1); 2071 } 2072 /* 2073 * Nothing to clean up if the user shell was never started. 2074 */ 2075 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0) 2076 return(1); 2077 2078 /* 2079 * Block the WJSIGNAL while we are in jobend(). 2080 */ 2081 omask = sigblock(mask); 2082 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user); 2083 sigsetmask(omask); 2084 return(ret); 2085} 2086 2087 int 2088jobend(jid, path, user) 2089 register int jid; 2090 register char *path; 2091 register char *user; 2092{ 2093 static int saved_jid = 0; 2094 static int pty_saved_jid = 0; 2095 static char saved_path[sizeof(wtmp.ut_tpath)+1]; 2096 static char saved_user[sizeof(wtmp.ut_user)+1]; 2097 2098 /* 2099 * this little piece of code comes into play 2100 * only when ptyreconnect is used to reconnect 2101 * to an previous session. 2102 * 2103 * this is the only time when the 2104 * "saved_jid != jid" code is executed. 2105 */ 2106 2107 if ( saved_jid && saved_jid != jid ) { 2108 if (!path) { /* called from signal handler */ 2109 pty_saved_jid = jid; 2110 } else { 2111 pty_saved_jid = saved_jid; 2112 } 2113 } 2114 2115 if (path) { 2116 strncpy(saved_path, path, sizeof(wtmp.ut_tpath)); 2117 strncpy(saved_user, user, sizeof(wtmp.ut_user)); 2118 saved_path[sizeof(saved_path)] = '\0'; 2119 saved_user[sizeof(saved_user)] = '\0'; 2120 } 2121 if (saved_jid == 0) { 2122 saved_jid = jid; 2123 return(0); 2124 } 2125 2126 /* if the jid has changed, get the correct entry from the utmp file */ 2127 2128 if ( saved_jid != jid ) { 2129 struct utmp *utp = NULL; 2130 struct utmp *jid_getutid(); 2131 2132 utp = jid_getutid(pty_saved_jid); 2133 2134 if (utp == 0) { 2135 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 2136 return(-1); 2137 } 2138 2139 cleantmpdir(jid, utp->ut_tpath, utp->ut_user); 2140 return(1); 2141 } 2142 2143 cleantmpdir(jid, saved_path, saved_user); 2144 return(1); 2145} 2146 2147/* 2148 * Fork a child process to clean up the TMPDIR 2149 */ 2150cleantmpdir(jid, tpath, user) 2151 register int jid; 2152 register char *tpath; 2153 register char *user; 2154{ 2155 switch(fork()) { 2156 case -1: 2157 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n", 2158 tpath); 2159 break; 2160 case 0: 2161 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0); 2162 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n", 2163 tpath, CLEANTMPCMD); 2164 exit(1); 2165 default: 2166 /* 2167 * Forget about child. We will exit, and 2168 * /etc/init will pick it up. 2169 */ 2170 break; 2171 } 2172} 2173# endif /* CRAY */ 2174#endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */ 2175 2176/* 2177 * rmut() 2178 * 2179 * This is the function called by cleanup() to 2180 * remove the utmp entry for this person. 2181 */ 2182 2183#ifdef UTMPX 2184 void 2185rmut() 2186{ 2187 register f; 2188 int found = 0; 2189 struct utmp *u, *utmp; 2190 int nutmp; 2191 struct stat statbf; 2192 2193 struct utmpx *utxp, utmpx; 2194 2195 /* 2196 * This updates the utmpx and utmp entries and make a wtmp/x entry 2197 */ 2198 2199 SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1); 2200 utxp = getutxline(&utmpx); 2201 if (utxp) { 2202 utxp->ut_type = DEAD_PROCESS; 2203 utxp->ut_exit.e_termination = 0; 2204 utxp->ut_exit.e_exit = 0; 2205 (void) time(&utmpx.ut_tv.tv_sec); 2206 utmpx.ut_tv.tv_usec = 0; 2207 modutx(utxp); 2208 } 2209 endutxent(); 2210} /* end of rmut */ 2211#endif 2212 2213#if !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43 2214 void 2215rmut() 2216{ 2217 register f; 2218 int found = 0; 2219 struct utmp *u, *utmp; 2220 int nutmp; 2221 struct stat statbf; 2222 2223 f = open(utmpf, O_RDWR); 2224 if (f >= 0) { 2225 (void) fstat(f, &statbf); 2226 utmp = (struct utmp *)malloc((unsigned)statbf.st_size); 2227 if (!utmp) 2228 syslog(LOG_ERR, "utmp malloc failed"); 2229 if (statbf.st_size && utmp) { 2230 nutmp = read(f, (char *)utmp, (int)statbf.st_size); 2231 nutmp /= sizeof(struct utmp); 2232 2233 for (u = utmp ; u < &utmp[nutmp] ; u++) { 2234 if (SCMPN(u->ut_line, line+5) || 2235 u->ut_name[0]==0) 2236 continue; 2237 (void) lseek(f, ((long)u)-((long)utmp), L_SET); 2238 SCPYN(u->ut_name, ""); 2239 SCPYN(u->ut_host, ""); 2240 (void) time(&u->ut_time); 2241 (void) write(f, (char *)u, sizeof(wtmp)); 2242 found++; 2243 } 2244 } 2245 (void) close(f); 2246 } 2247 if (found) { 2248 f = open(wtmpf, O_WRONLY|O_APPEND); 2249 if (f >= 0) { 2250 SCPYN(wtmp.ut_line, line+5); 2251 SCPYN(wtmp.ut_name, ""); 2252 SCPYN(wtmp.ut_host, ""); 2253 (void) time(&wtmp.ut_time); 2254 (void) write(f, (char *)&wtmp, sizeof(wtmp)); 2255 (void) close(f); 2256 } 2257 } 2258 (void) chmod(line, 0666); 2259 (void) chown(line, 0, 0); 2260 line[strlen("/dev/")] = 'p'; 2261 (void) chmod(line, 0666); 2262 (void) chown(line, 0, 0); 2263} /* end of rmut */ 2264#endif /* CRAY */ 2265 2266#ifdef __hpux 2267rmut (line) 2268char *line; 2269{ 2270 struct utmp utmp; 2271 struct utmp *utptr; 2272 int fd; /* for /etc/wtmp */ 2273 2274 utmp.ut_type = USER_PROCESS; 2275 (void) strncpy(utmp.ut_id, line+12, sizeof(utmp.ut_id)); 2276 (void) setutent(); 2277 utptr = getutid(&utmp); 2278 /* write it out only if it exists */ 2279 if (utptr) { 2280 utptr->ut_type = DEAD_PROCESS; 2281 utptr->ut_time = time((long *) 0); 2282 (void) pututline(utptr); 2283 /* set wtmp entry if wtmp file exists */ 2284 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { 2285 (void) write(fd, utptr, sizeof(utmp)); 2286 (void) close(fd); 2287 } 2288 } 2289 (void) endutent(); 2290 2291 (void) chmod(line, 0666); 2292 (void) chown(line, 0, 0); 2293 line[14] = line[13]; 2294 line[13] = line[12]; 2295 line[8] = 'm'; 2296 line[9] = '/'; 2297 line[10] = 'p'; 2298 line[11] = 't'; 2299 line[12] = 'y'; 2300 (void) chmod(line, 0666); 2301 (void) chown(line, 0, 0); 2302} 2303#endif 2304