1*45223Ssklower /* 2*45223Ssklower * X.29 server 3*45223Ssklower * 4*45223Ssklower * Frank Pronk (...!ubc-vision!pronk) 5*45223Ssklower * April, September 1984 6*45223Ssklower * 7*45223Ssklower * Laboratory for Computational Vision 8*45223Ssklower * University of British Columbia 9*45223Ssklower * Copyright (c) 10*45223Ssklower */ 11*45223Ssklower 12*45223Ssklower #include <sys/param.h> 13*45223Ssklower #include <sys/socket.h> 14*45223Ssklower #include <sys/stat.h> 15*45223Ssklower #include <sys/wait.h> 16*45223Ssklower 17*45223Ssklower #include <netccitt/x25.h> 18*45223Ssklower 19*45223Ssklower #include <errno.h> 20*45223Ssklower #include <netdb.h> 21*45223Ssklower #include <sgtty.h> 22*45223Ssklower #include <signal.h> 23*45223Ssklower 24*45223Ssklower #include "../h/x29.h" 25*45223Ssklower 26*45223Ssklower #define BUFSIZ 1024 27*45223Ssklower #define MAXARGS 10 /* maximum size of server argument list */ 28*45223Ssklower 29*45223Ssklower #define X25NET 0 /* no ITI parameters */ 30*45223Ssklower #define CCITT1978 1 /* 1978 CCITT standard parameter set */ 31*45223Ssklower #define CCITT1980 2 /* 1980 CCITT standard parameter set */ 32*45223Ssklower 33*45223Ssklower 34*45223Ssklower char pibuf[BUFSIZ], fibuf[BUFSIZ]; 35*45223Ssklower int pty, net; 36*45223Ssklower extern char **environ; 37*45223Ssklower extern int errno; 38*45223Ssklower char line[sizeof("/dev/ptyp0")]; 39*45223Ssklower char console[] = "/dev/console"; 40*45223Ssklower short packet_size; 41*45223Ssklower char *tracefn; /* trace file name */ 42*45223Ssklower char *server; 43*45223Ssklower short send_banner; 44*45223Ssklower struct sockaddr_x25 sock; 45*45223Ssklower 46*45223Ssklower int reapchild(); 47*45223Ssklower struct net *lookup (); 48*45223Ssklower 49*45223Ssklower char ccitt1978_prof[] = { /* initial profile */ 50*45223Ssklower Q_BIT, X29_SET_AND_READ_PARMS, 51*45223Ssklower X29_ECHO_CODE, 1, /* echo on */ 52*45223Ssklower X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */ 53*45223Ssklower X29_IDLE_TIMER_CODE, 0, /* off */ 54*45223Ssklower X29_AUX_DEV_CONTROL_CODE, 0, /* off */ 55*45223Ssklower X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */ 56*45223Ssklower X29_BREAK_PROCEDURE_CODE, 21, 57*45223Ssklower X29_PADDING_CODE, 0, /* off */ 58*45223Ssklower X29_LINE_FOLDING_CODE, 0, /* off */ 59*45223Ssklower X29_TRANSMISSION_SPEED_CODE, 0, 60*45223Ssklower X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */ 61*45223Ssklower }; 62*45223Ssklower 63*45223Ssklower char ccitt1980_prof[] = { /* initial profile */ 64*45223Ssklower Q_BIT, X29_SET_AND_READ_PARMS, 65*45223Ssklower X29_ECHO_CODE, 1, /* echo on */ 66*45223Ssklower X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */ 67*45223Ssklower X29_IDLE_TIMER_CODE, 0, /* off */ 68*45223Ssklower X29_AUX_DEV_CONTROL_CODE, 0, /* off */ 69*45223Ssklower X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */ 70*45223Ssklower X29_BREAK_PROCEDURE_CODE, 21, 71*45223Ssklower X29_PADDING_CODE, 0, /* off */ 72*45223Ssklower X29_LINE_FOLDING_CODE, 0, /* off */ 73*45223Ssklower X29_TRANSMISSION_SPEED_CODE, 0, 74*45223Ssklower X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */ 75*45223Ssklower 76*45223Ssklower X29_LF_AFTER_CR, 4, /* lf after cr from terminal */ 77*45223Ssklower X29_EDITING, 1, /* on */ 78*45223Ssklower X29_CHARACTER_DELETE, CERASE, 79*45223Ssklower X29_LINE_DELETE, CKILL, 80*45223Ssklower X29_LINE_DISPLAY, CRPRNT, 81*45223Ssklower }; 82*45223Ssklower 83*45223Ssklower char datapac_prof[] = { /* Canadian X.25 network */ 84*45223Ssklower Q_BIT, X29_SET_AND_READ_PARMS, 85*45223Ssklower X29_ECHO_CODE, 1, /* echo on */ 86*45223Ssklower X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */ 87*45223Ssklower X29_IDLE_TIMER_CODE, 0, /* off */ 88*45223Ssklower X29_AUX_DEV_CONTROL_CODE, 0, /* off */ 89*45223Ssklower X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */ 90*45223Ssklower X29_BREAK_PROCEDURE_CODE, 21, 91*45223Ssklower X29_PADDING_CODE, 0, /* off */ 92*45223Ssklower X29_LINE_FOLDING_CODE, 0, /* off */ 93*45223Ssklower X29_TRANSMISSION_SPEED_CODE, 0, 94*45223Ssklower X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */ 95*45223Ssklower 96*45223Ssklower X29_LF_AFTER_CR, 4, /* lf after cr from terminal */ 97*45223Ssklower X29_EDITING, 1, /* on */ 98*45223Ssklower X29_CHARACTER_DELETE, CERASE, 99*45223Ssklower X29_LINE_DELETE, CKILL, 100*45223Ssklower X29_LINE_DISPLAY, CRPRNT, 101*45223Ssklower 102*45223Ssklower /* 103*45223Ssklower * This rubbish can be removed when Datapac 104*45223Ssklower * adopts the 1980 standard parameter set. 105*45223Ssklower */ 106*45223Ssklower 107*45223Ssklower 0, 0, /* national parameter marker */ 108*45223Ssklower 123, 0, /* parity off */ 109*45223Ssklower }; 110*45223Ssklower 111*45223Ssklower struct net { 112*45223Ssklower char *n_name; /* generic name */ 113*45223Ssklower short n_type; /* see defines above */ 114*45223Ssklower char *n_profile; /* initial profile */ 115*45223Ssklower short n_proflen; /* length of n_profile */ 116*45223Ssklower } *netp, nets[] = { 117*45223Ssklower "x.25", X25NET, 0, 0, 118*45223Ssklower "1978", CCITT1978, ccitt1978_prof, sizeof(ccitt1978_prof), 119*45223Ssklower "ccitt1978", CCITT1978, ccitt1978_prof, sizeof(ccitt1978_prof), 120*45223Ssklower "1980", CCITT1980, ccitt1980_prof, sizeof(ccitt1980_prof), 121*45223Ssklower "ccitt1980", CCITT1980, ccitt1980_prof, sizeof(ccitt1980_prof), 122*45223Ssklower "datapac", CCITT1980, datapac_prof, sizeof(datapac_prof), 123*45223Ssklower 0, 0, 0, 0 124*45223Ssklower }; 125*45223Ssklower 126*45223Ssklower main(argc, argv) 127*45223Ssklower register char **argv; 128*45223Ssklower { 129*45223Ssklower register int s, pid; 130*45223Ssklower register char *p; 131*45223Ssklower 132*45223Ssklower #ifdef waterloo 133*45223Ssklower /* 134*45223Ssklower * If this host doesn't support X.25, give up. 135*45223Ssklower */ 136*45223Ssklower s = socket(AF_CCITT, SOCK_STREAM, 0); 137*45223Ssklower if (s < 0 && errno == EPROTONOSUPPORT) 138*45223Ssklower fatal(2, "X.25 is not supported on this machine"); 139*45223Ssklower close(s); 140*45223Ssklower #endif 141*45223Ssklower netp = lookup ("ccitt1978"); 142*45223Ssklower sock.x25_family = AF_CCITT; 143*45223Ssklower sock.x25_opts.op_flags = X25_MQBIT; 144*45223Ssklower sock.x25_udata[0] = ITI_CALL; 145*45223Ssklower sock.x25_udlen = 4; 146*45223Ssklower 147*45223Ssklower for (argv++; argc > 1; argc--, argv++) 148*45223Ssklower if (**argv == '-') 149*45223Ssklower for (p = *argv+1; *p; p++) 150*45223Ssklower switch (*p) { 151*45223Ssklower case 'b': 152*45223Ssklower send_banner++; 153*45223Ssklower break; 154*45223Ssklower 155*45223Ssklower case 'c': 156*45223Ssklower if (argc > 1) { 157*45223Ssklower argc--; argv++; 158*45223Ssklower if ((netp = lookup (*argv)) == 0) 159*45223Ssklower fatal(1, "Unknown network type"); 160*45223Ssklower } 161*45223Ssklower break; 162*45223Ssklower 163*45223Ssklower case 'p': 164*45223Ssklower if (argc > 1) { 165*45223Ssklower argc--; argv++; 166*45223Ssklower strcpy (sock.x25_udata, *argv); 167*45223Ssklower } 168*45223Ssklower break; 169*45223Ssklower 170*45223Ssklower case 'r': 171*45223Ssklower sock.x25_opts.op_flags |= X25_REVERSE_CHARGE; 172*45223Ssklower break; 173*45223Ssklower 174*45223Ssklower case 't': 175*45223Ssklower if (argc > 1) { 176*45223Ssklower argc--; argv++; 177*45223Ssklower tracefn = *argv; 178*45223Ssklower } 179*45223Ssklower else fatal(1, "missing trace file"); 180*45223Ssklower break; 181*45223Ssklower 182*45223Ssklower default: 183*45223Ssklower fatal (1, "usage: x29d -b -c nettype -p protocol -r -t trace_file server"); 184*45223Ssklower } 185*45223Ssklower else 186*45223Ssklower server = *argv; 187*45223Ssklower if (server == 0) 188*45223Ssklower fatal (1, "no server specified"); 189*45223Ssklower if (fork()) 190*45223Ssklower exit(0); 191*45223Ssklower for (s = 0; s < 10; s++) 192*45223Ssklower (void) close(s); 193*45223Ssklower (void) open("/", 0); 194*45223Ssklower (void) dup2(0, 1); 195*45223Ssklower (void) dup2(0, 2); 196*45223Ssklower { int tt = open("/dev/tty", 2); 197*45223Ssklower if (tt > 0) { 198*45223Ssklower ioctl(tt, TIOCNOTTY, (char *)0); 199*45223Ssklower close(tt); 200*45223Ssklower } 201*45223Ssklower } 202*45223Ssklower 203*45223Ssklower while((s = socket(AF_CCITT, SOCK_STREAM, 0)) < 0) 204*45223Ssklower sleep(60); 205*45223Ssklower while (bind(s, (caddr_t)&sock, sizeof (sock)) < 0) 206*45223Ssklower sleep(60); 207*45223Ssklower signal(SIGCHLD, reapchild); 208*45223Ssklower listen(s, 5); 209*45223Ssklower 210*45223Ssklower for (;;) { 211*45223Ssklower struct sockaddr_x25 from; 212*45223Ssklower int fromlen = sizeof (from); 213*45223Ssklower 214*45223Ssklower if ((net = accept(s, (caddr_t)&from, &fromlen)) < 0) { 215*45223Ssklower if (errno != EINTR) 216*45223Ssklower sleep (60); 217*45223Ssklower continue; 218*45223Ssklower } 219*45223Ssklower while ((pid = fork()) < 0) 220*45223Ssklower sleep(60); 221*45223Ssklower if (pid == 0) { 222*45223Ssklower signal(SIGCHLD, SIG_DFL); 223*45223Ssklower doit(&from); 224*45223Ssklower } 225*45223Ssklower close(net); 226*45223Ssklower } 227*45223Ssklower /*NOTREACHED*/ 228*45223Ssklower } 229*45223Ssklower 230*45223Ssklower struct net * 231*45223Ssklower lookup (name) 232*45223Ssklower char *name; 233*45223Ssklower { 234*45223Ssklower register struct net *np; 235*45223Ssklower 236*45223Ssklower for (np = nets; np->n_name; np++) 237*45223Ssklower if (strcmp (np->n_name, name) == 0) 238*45223Ssklower return (np); 239*45223Ssklower return (0); 240*45223Ssklower } 241*45223Ssklower 242*45223Ssklower reapchild() 243*45223Ssklower { 244*45223Ssklower union wait status; 245*45223Ssklower 246*45223Ssklower while (wait3(&status, WNOHANG, 0) > 0) 247*45223Ssklower ; 248*45223Ssklower } 249*45223Ssklower 250*45223Ssklower char *envinit[] = { "TERM=ccitt", 0 }; 251*45223Ssklower int cleanup(); 252*45223Ssklower 253*45223Ssklower /* 254*45223Ssklower * Get a pty, scan input lines. 255*45223Ssklower */ 256*45223Ssklower doit(who) 257*45223Ssklower struct sockaddr_x25 *who; 258*45223Ssklower { 259*45223Ssklower register char *cp; 260*45223Ssklower register int i, p, t; 261*45223Ssklower struct sgttyb b; 262*45223Ssklower struct stat sb; 263*45223Ssklower 264*45223Ssklower strcpy(line, "/dev/ptyp0"); 265*45223Ssklower cp = line; 266*45223Ssklower for (t = 'p'; ; t++) { 267*45223Ssklower cp[strlen("/dev/pty")] = t; 268*45223Ssklower if (stat(line, &sb) < 0) 269*45223Ssklower break; 270*45223Ssklower for (i = 0; i < 16; i++) { 271*45223Ssklower cp[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 272*45223Ssklower p = open(cp, 2); 273*45223Ssklower if (p > 0) 274*45223Ssklower goto gotpty; 275*45223Ssklower } 276*45223Ssklower } 277*45223Ssklower fatal(net, "All pty ports in use"); 278*45223Ssklower /*NOTREACHED*/ 279*45223Ssklower gotpty: 280*45223Ssklower pty = p; 281*45223Ssklower (void) dup2(net, 0); 282*45223Ssklower cp[strlen("/dev/")] = 't'; 283*45223Ssklower t = open("/dev/tty", 2); 284*45223Ssklower if (t >= 0) { 285*45223Ssklower ioctl(t, TIOCNOTTY, (char *)0); 286*45223Ssklower close(t); 287*45223Ssklower } 288*45223Ssklower t = open(cp, 2); /* slave side of pty */ 289*45223Ssklower if (t < 0) 290*45223Ssklower fatalperror(cp, errno); 291*45223Ssklower ioctl(t, TIOCGETP, (char *)&b); 292*45223Ssklower b.sg_flags = CRMOD|XTABS|ANYP|ECHO; 293*45223Ssklower ioctl(t, TIOCSETP, &b); 294*45223Ssklower packet_size = 1 << who->x25_opts.op_psize; 295*45223Ssklower if ((i = fork()) < 0) 296*45223Ssklower fatalperror("fork", errno); 297*45223Ssklower if (i) 298*45223Ssklower x29d(); 299*45223Ssklower close(net); 300*45223Ssklower close(p); 301*45223Ssklower (void) dup2(t, 0); 302*45223Ssklower (void) dup2(t, 1); 303*45223Ssklower (void) dup2(t, 2); 304*45223Ssklower close(t); 305*45223Ssklower environ = envinit; 306*45223Ssklower call_server (who); 307*45223Ssklower /*NOTREACHED*/ 308*45223Ssklower } 309*45223Ssklower 310*45223Ssklower call_server (who) 311*45223Ssklower struct sockaddr_x25 *who; 312*45223Ssklower { 313*45223Ssklower register struct hostent *hp = 0; 314*45223Ssklower register char *p, **ap; 315*45223Ssklower char *args[MAXARGS]; 316*45223Ssklower struct stat st; 317*45223Ssklower struct hostent *getx25hostbyaddr(); 318*45223Ssklower int ccitt = 0; 319*45223Ssklower 320*45223Ssklower p = server; 321*45223Ssklower while (*p && *p != ' ' && *p != '\t') /* split program from args */ 322*45223Ssklower p++; 323*45223Ssklower if (*p) 324*45223Ssklower *p++ = '\0'; 325*45223Ssklower ap = args; 326*45223Ssklower while (*p) { 327*45223Ssklower while (*p == ' ' || *p == '\t') 328*45223Ssklower p++; 329*45223Ssklower if (ap < &args[MAXARGS-2]) 330*45223Ssklower *ap++ = p; 331*45223Ssklower if (strcmp(p, "-ccitt") == 0) 332*45223Ssklower ccitt = 1; 333*45223Ssklower while (*p && *p != ' ' && *p != '\t') 334*45223Ssklower p++; 335*45223Ssklower if (*p) 336*45223Ssklower *p++ = '\0'; 337*45223Ssklower } 338*45223Ssklower if (stat (server, &st) < 0) 339*45223Ssklower fatalperror (server, errno); 340*45223Ssklower /* 341*45223Ssklower * For security: if running as root, switch to user 342*45223Ssklower * and group id of server. This prevents privately 343*45223Ssklower * maintainted or bogus servers from getting super- 344*45223Ssklower * user permissions. 345*45223Ssklower */ 346*45223Ssklower if (getuid() == 0) { 347*45223Ssklower setgid (st.st_gid); 348*45223Ssklower setuid (st.st_uid); 349*45223Ssklower } 350*45223Ssklower if (hp = getx25hostbyaddr (who->x25_addr)) 351*45223Ssklower *ap++ = hp->h_name; 352*45223Ssklower else 353*45223Ssklower *ap++ = (char *)who->x25_addr; 354*45223Ssklower /* 355*45223Ssklower * If the -ccitt flag was given, add another argument 356*45223Ssklower * to tell login if charging is being reversed or not. 357*45223Ssklower */ 358*45223Ssklower if (ccitt) 359*45223Ssklower *ap++ = (who->x25_opts.op_flags & X25_REVERSE_CHARGE) ? "y" : "n"; 360*45223Ssklower *ap = 0; 361*45223Ssklower execv (server, args); 362*45223Ssklower fatalperror (server, errno); 363*45223Ssklower /*NOTREACHED*/ 364*45223Ssklower } 365*45223Ssklower 366*45223Ssklower fatal(f, msg) 367*45223Ssklower int f; 368*45223Ssklower char *msg; 369*45223Ssklower { 370*45223Ssklower register char *p; 371*45223Ssklower char buf[BUFSIZ], *index(); 372*45223Ssklower 373*45223Ssklower p = buf; 374*45223Ssklower if (f == net) 375*45223Ssklower *p++ = 0; 376*45223Ssklower strcpy(p, "x29d: "); 377*45223Ssklower strcat(p, msg); 378*45223Ssklower strcat(p, "\n"); 379*45223Ssklower (void) write(f, p, (index(p, '\n')-p)+1); 380*45223Ssklower exit(1); 381*45223Ssklower } 382*45223Ssklower 383*45223Ssklower fatalperror(msg, err) 384*45223Ssklower char *msg; 385*45223Ssklower { 386*45223Ssklower char buf[BUFSIZ]; 387*45223Ssklower extern char *sys_errlist[]; 388*45223Ssklower 389*45223Ssklower strcpy(buf, msg); 390*45223Ssklower strcat(buf, ": "); 391*45223Ssklower strcat(buf, sys_errlist[err]); 392*45223Ssklower fatal(net, buf); 393*45223Ssklower } 394*45223Ssklower 395*45223Ssklower /* 396*45223Ssklower * Main loop. Select from pty and network, and 397*45223Ssklower * hand data to iti receiver. 398*45223Ssklower */ 399*45223Ssklower x29d() 400*45223Ssklower { 401*45223Ssklower register int pcc, fcc, cc; 402*45223Ssklower register char *fbp; 403*45223Ssklower int pgrp, x25_interrupt(), on = 1; 404*45223Ssklower char hostname[32]; 405*45223Ssklower 406*45223Ssklower ioctl(net, FIONBIO, (char *)&on); 407*45223Ssklower ioctl(pty, FIONBIO, (char *)&on); 408*45223Ssklower ioctl(pty, TIOCPKT, (char *)&on); 409*45223Ssklower ioctl(pty, TIOCREMECHO, (char *)&on); /* enable special pty mode */ 410*45223Ssklower signal(SIGPIPE, SIG_IGN); /* why not cleanup? --kwl */ 411*45223Ssklower signal(SIGTSTP, SIG_IGN); 412*45223Ssklower signal(SIGCHLD, cleanup); 413*45223Ssklower signal(SIGHUP, cleanup); 414*45223Ssklower 415*45223Ssklower signal(SIGTTOU, SIG_IGN); 416*45223Ssklower signal(SIGURG, x25_interrupt); /* for out-of-band data */ 417*45223Ssklower pgrp = -getpgrp(0); 418*45223Ssklower ioctl(net, SIOCSPGRP, (char *)&pgrp); 419*45223Ssklower 420*45223Ssklower if (netp->n_proflen) 421*45223Ssklower (void) write(net, netp->n_profile, netp->n_proflen); 422*45223Ssklower 423*45223Ssklower /* 424*45223Ssklower * Show banner that getty never gave. 425*45223Ssklower */ 426*45223Ssklower if (send_banner) { 427*45223Ssklower gethostname(hostname, sizeof (hostname)); 428*45223Ssklower #ifdef BSD4_3 429*45223Ssklower strcpy(pibuf+1, "\r\n\r\n4.3 BSD UNIX ("); 430*45223Ssklower #else 431*45223Ssklower strcpy(pibuf+1, "\r\n\r\n4.2 BSD UNIX ("); 432*45223Ssklower #endif 433*45223Ssklower strcat(pibuf+1, hostname); 434*45223Ssklower strcat(pibuf+1, ")\r\n\r\n"); 435*45223Ssklower pcc = strlen(pibuf+1) + 1; 436*45223Ssklower } else 437*45223Ssklower pcc = 0; 438*45223Ssklower 439*45223Ssklower fcc = 0; 440*45223Ssklower for (;;) { 441*45223Ssklower int ibits, obits; 442*45223Ssklower 443*45223Ssklower ibits = obits = 0; 444*45223Ssklower /* 445*45223Ssklower * Never look for input if there's still 446*45223Ssklower * stuff in the corresponding output buffer 447*45223Ssklower */ 448*45223Ssklower if (fcc >= 0) /* net connection alive? */ 449*45223Ssklower if (fcc && pcc >= 0) /* output pending? */ 450*45223Ssklower obits |= (1 << pty); 451*45223Ssklower else 452*45223Ssklower if (pcc >= 0) /* pty still alive? */ 453*45223Ssklower ibits |= (1 << net); 454*45223Ssklower if (pcc >= 0) /* pty connection alive? */ 455*45223Ssklower if (pcc && fcc >= 0) /* output pending? */ 456*45223Ssklower obits |= (1 << net); 457*45223Ssklower else 458*45223Ssklower if (fcc >= 0) /* net still alive? */ 459*45223Ssklower ibits |= (1 << pty); 460*45223Ssklower if(ibits == 0 && obits == 0) 461*45223Ssklower break; 462*45223Ssklower (void) select(16, &ibits, &obits, (int *)0, 0); 463*45223Ssklower if (ibits == 0 && obits == 0) { 464*45223Ssklower sleep(5); 465*45223Ssklower continue; 466*45223Ssklower } 467*45223Ssklower 468*45223Ssklower /* 469*45223Ssklower * Something to read from the network... 470*45223Ssklower */ 471*45223Ssklower if (ibits & (1 << net)) { 472*45223Ssklower fcc = read(net, fibuf, BUFSIZ); 473*45223Ssklower fbp = fibuf+1; 474*45223Ssklower if (fcc < 0 && errno == EWOULDBLOCK) 475*45223Ssklower fcc = 0; 476*45223Ssklower else if(fcc <= 0) 477*45223Ssklower fcc = -1; 478*45223Ssklower else { 479*45223Ssklower if (tracefn) 480*45223Ssklower x29d_trace("netread", fibuf, fcc); 481*45223Ssklower if(fibuf[0] & Q_BIT) { 482*45223Ssklower x29_qbit(fcc); 483*45223Ssklower fcc = 0; 484*45223Ssklower } else 485*45223Ssklower fcc--; 486*45223Ssklower } 487*45223Ssklower } 488*45223Ssklower 489*45223Ssklower /* 490*45223Ssklower * Something to read from the pty... 491*45223Ssklower */ 492*45223Ssklower if (ibits & (1 << pty)) { 493*45223Ssklower pcc = read(pty, pibuf, packet_size+1); 494*45223Ssklower if (pcc < 0 && errno == EWOULDBLOCK) 495*45223Ssklower pcc = 0; 496*45223Ssklower else if (pcc <= 0) 497*45223Ssklower pcc = -1; 498*45223Ssklower else if(pibuf[0] != 0) { /* non-data packet */ 499*45223Ssklower if (pibuf[0] & TIOCPKT_IOCTL) 500*45223Ssklower pcc = set_x29_parameters(); 501*45223Ssklower else 502*45223Ssklower pcc = 0; 503*45223Ssklower } else /* data packet */ 504*45223Ssklower pibuf[0] = 0; 505*45223Ssklower } 506*45223Ssklower 507*45223Ssklower if ((obits & (1<<net)) && pcc > 0) 508*45223Ssklower if((cc = write(net, pibuf, pcc)) == pcc) { 509*45223Ssklower if(tracefn) 510*45223Ssklower x29d_trace("netwrite", pibuf, pcc); 511*45223Ssklower pcc = 0; 512*45223Ssklower } else { 513*45223Ssklower extern char *sys_errlist[]; 514*45223Ssklower 515*45223Ssklower if(tracefn) 516*45223Ssklower x29d_trace("netwrite", 517*45223Ssklower sys_errlist[errno], 518*45223Ssklower strlen(sys_errlist[errno])); 519*45223Ssklower 520*45223Ssklower } 521*45223Ssklower 522*45223Ssklower if ((obits & (1 << pty)) && fcc > 0) { 523*45223Ssklower cc = write(pty, fbp, fcc); 524*45223Ssklower if (cc > 0) { 525*45223Ssklower fcc -= cc; 526*45223Ssklower fbp += cc; 527*45223Ssklower } 528*45223Ssklower } 529*45223Ssklower } 530*45223Ssklower cleanup(); 531*45223Ssklower } 532*45223Ssklower 533*45223Ssklower 534*45223Ssklower /* 535*45223Ssklower * Send interrupt to process on other side of pty. 536*45223Ssklower * If it is in raw mode, just write NULL; 537*45223Ssklower * otherwise, write intr char. 538*45223Ssklower */ 539*45223Ssklower 540*45223Ssklower x25_interrupt() 541*45223Ssklower { 542*45223Ssklower struct sgttyb b; 543*45223Ssklower struct tchars tchars; 544*45223Ssklower int zero = 0; 545*45223Ssklower 546*45223Ssklower signal(SIGURG, x25_interrupt); 547*45223Ssklower ioctl(pty, TIOCGETP, (char *)&b); 548*45223Ssklower if (b.sg_flags & RAW) 549*45223Ssklower (void) write(pty, "\0", 1); 550*45223Ssklower else { 551*45223Ssklower ioctl(pty, TIOCFLUSH, (char *)&zero); 552*45223Ssklower ioctl(pty, TIOCGETC, (char *)&tchars); 553*45223Ssklower (void) write(pty, &tchars.t_intrc, 1); 554*45223Ssklower } 555*45223Ssklower } 556*45223Ssklower 557*45223Ssklower cleanup() 558*45223Ssklower { 559*45223Ssklower struct sgttyb sg; 560*45223Ssklower struct stat st; 561*45223Ssklower 562*45223Ssklower ioctl(pty, TIOCGETP, (char *)&sg); /* flushes output buffer */ 563*45223Ssklower ioctl(pty, TIOCSETP, (char *)&sg); 564*45223Ssklower (void) stat(line, &st); 565*45223Ssklower rmut(); 566*45223Ssklower vhangup(); /* XXX */ 567*45223Ssklower setuid(st.st_uid); 568*45223Ssklower exit(1); 569*45223Ssklower } 570*45223Ssklower 571*45223Ssklower /* 572*45223Ssklower * Map unix tty modes and special characters 573*45223Ssklower * into x29 parameters. 574*45223Ssklower */ 575*45223Ssklower 576*45223Ssklower set_x29_parameters() 577*45223Ssklower { 578*45223Ssklower register char *p; 579*45223Ssklower register int f; 580*45223Ssklower struct sgttyb b; 581*45223Ssklower 582*45223Ssklower if (netp->n_type == X25NET) 583*45223Ssklower return (0); 584*45223Ssklower ioctl(pty, TIOCGETP, (char *)&b); 585*45223Ssklower f = b.sg_flags; 586*45223Ssklower p = pibuf; 587*45223Ssklower *p++ = Q_BIT; 588*45223Ssklower *p++ = X29_SET_PARMS; 589*45223Ssklower *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (f & (RAW|CBREAK)) == 0; 590*45223Ssklower *p++ = X29_ECHO_CODE; *p++ = (f & ECHO) != 0; 591*45223Ssklower *p++ = X29_FORWARDING_SIGNAL_CODE; *p++ = (f & (RAW|CBREAK)) ? 0 : 126; 592*45223Ssklower 593*45223Ssklower /* 594*45223Ssklower * The value of 10 (0.5 seconds) for the idle timer when 595*45223Ssklower * in raw or cbreak mode is a compromise value. For good 596*45223Ssklower * interactive response this value should be as low as 597*45223Ssklower * possible; for reasonable efficiency with file transfers 598*45223Ssklower * this value should be at fairly high. This number should 599*45223Ssklower * be changed to suit local requirements. 600*45223Ssklower */ 601*45223Ssklower 602*45223Ssklower *p++ = X29_IDLE_TIMER_CODE; *p++ = (f & (RAW|CBREAK)) ? 10 : 0; 603*45223Ssklower *p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (f & TANDEM) != 0; 604*45223Ssklower *p++ = X29_XON_XOFF_CODE; *p++ = (f & RAW) == 0; 605*45223Ssklower if(netp->n_type == CCITT1980) { 606*45223Ssklower struct ltchars ltc; 607*45223Ssklower 608*45223Ssklower ioctl(pty, TIOCGLTC, (char *)<c); 609*45223Ssklower *p++ = X29_LF_AFTER_CR; 610*45223Ssklower *p++ = (f & (RAW|CBREAK) || (f & ECHO) == 0) ? 0 : 4; 611*45223Ssklower *p++ = X29_EDITING; 612*45223Ssklower *p++ = (f & (RAW|CBREAK)) == 0; 613*45223Ssklower *p++ = X29_CHARACTER_DELETE; 614*45223Ssklower *p++ = (f & (RAW|CBREAK)) || b.sg_erase & 0200 ? 615*45223Ssklower 0 : b.sg_erase; 616*45223Ssklower *p++ = X29_LINE_DELETE; 617*45223Ssklower *p++ = (f & (RAW|CBREAK)) || b.sg_kill & 0200 ? 618*45223Ssklower 0 : b.sg_kill; 619*45223Ssklower *p++ = X29_LINE_DISPLAY; 620*45223Ssklower *p++ = (f & (RAW|CBREAK)) || ltc.t_rprntc & 0200 ? 621*45223Ssklower 0 : ltc.t_rprntc; 622*45223Ssklower } 623*45223Ssklower return (p - pibuf); 624*45223Ssklower } 625*45223Ssklower 626*45223Ssklower /* 627*45223Ssklower * Process Q BIT (control) packets from the net. 628*45223Ssklower * The only message that we are interested in are 629*45223Ssklower * those indicating output is being discarded. 630*45223Ssklower */ 631*45223Ssklower 632*45223Ssklower x29_qbit(n) 633*45223Ssklower { 634*45223Ssklower register char *p; 635*45223Ssklower 636*45223Ssklower switch (fibuf[1]) { 637*45223Ssklower case X29_SET_PARMS: 638*45223Ssklower case X29_SET_AND_READ_PARMS: 639*45223Ssklower case X29_PARAMETER_INDICATION: 640*45223Ssklower case X29_INDICATION_OF_BREAK: 641*45223Ssklower for(p = &fibuf[2]; p < fibuf+n; p++) { 642*45223Ssklower if(*p == X29_TRANSMISSION_SPEED_CODE) { 643*45223Ssklower static char speeds[] = { 644*45223Ssklower B110, B0, B300, B1200, B600, 645*45223Ssklower B0, B0, B0, B0, B0, B0, B0, 646*45223Ssklower B2400, B4800, B9600, EXTA }; 647*45223Ssklower struct sgttyb b; 648*45223Ssklower 649*45223Ssklower if(*++p >= 0 && *p < sizeof(speeds)) { 650*45223Ssklower ioctl(pty, TIOCGETP, (char *)&b); 651*45223Ssklower b.sg_ispeed = b.sg_ospeed = speeds[*p]; 652*45223Ssklower ioctl(pty, TIOCSETN, (char *)&b); 653*45223Ssklower } 654*45223Ssklower } else if(*p == X29_DISCARD_OUTPUT_CODE && *++p != 0) { 655*45223Ssklower char message[4]; 656*45223Ssklower 657*45223Ssklower /* 658*45223Ssklower * Always re-enable normal output 659*45223Ssklower */ 660*45223Ssklower message[0] = Q_BIT; 661*45223Ssklower message[1] = X29_SET_PARMS; 662*45223Ssklower message[2] = X29_DISCARD_OUTPUT_CODE; 663*45223Ssklower message[3] = 0; 664*45223Ssklower (void) write(net, message, sizeof(message)); 665*45223Ssklower if(tracefn) 666*45223Ssklower x29d_trace("netwrite", message, 4); 667*45223Ssklower } 668*45223Ssklower } 669*45223Ssklower return; 670*45223Ssklower 671*45223Ssklower default: { 672*45223Ssklower register char *p2; 673*45223Ssklower char buf[BUFSIZ*4]; 674*45223Ssklower static int fd; 675*45223Ssklower 676*45223Ssklower /* 677*45223Ssklower * Bad news - we received an x29 error message or 678*45223Ssklower * some other unknown packet. Dump the contents 679*45223Ssklower * of the packet on the console. 680*45223Ssklower */ 681*45223Ssklower p = buf; 682*45223Ssklower for(p2 = "x29d: unknown q-bit packet: "; *p++ = *p2++; ); 683*45223Ssklower for(p2 = fibuf+1; p2 < fibuf+n; p2++) 684*45223Ssklower if(*p2 >= ' ' && *p2 < 0177) 685*45223Ssklower *p++ = *p2; 686*45223Ssklower else { 687*45223Ssklower *p++ = '\\'; 688*45223Ssklower *p++ = ((*p2 & 0300) >> 6) + '0'; 689*45223Ssklower *p++ = ((*p2 & 070) >> 3) + '0'; 690*45223Ssklower *p++ = (*p2 & 07) + '0'; 691*45223Ssklower } 692*45223Ssklower *p++ = '\n'; 693*45223Ssklower if(fd <= 0) 694*45223Ssklower fd = open(console, 1); 695*45223Ssklower (void) write(fd, buf, p-buf); 696*45223Ssklower } 697*45223Ssklower } 698*45223Ssklower } 699*45223Ssklower 700*45223Ssklower /* 701*45223Ssklower * HACK! 702*45223Ssklower * This program does not use or need any stdio routines. 703*45223Ssklower * Defining this procedure prevents all of the stdio 704*45223Ssklower * code from being loaded. 705*45223Ssklower */ 706*45223Ssklower 707*45223Ssklower exit(code) 708*45223Ssklower { 709*45223Ssklower _exit(code); 710*45223Ssklower } 711*45223Ssklower 712*45223Ssklower #include <utmp.h> 713*45223Ssklower 714*45223Ssklower struct utmp wtmp; 715*45223Ssklower char wtmpf[] = "/usr/adm/wtmp"; 716*45223Ssklower char utmp[] = "/etc/utmp"; 717*45223Ssklower #define SCPYN(a, b) strncpy(a, b, sizeof (a)) 718*45223Ssklower #define SCMPN(a, b) strncmp(a, b, sizeof (a)) 719*45223Ssklower 720*45223Ssklower rmut() 721*45223Ssklower { 722*45223Ssklower register int f, found = 0; 723*45223Ssklower 724*45223Ssklower f = open(utmp, 2); 725*45223Ssklower if (f >= 0) { 726*45223Ssklower while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) { 727*45223Ssklower if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) 728*45223Ssklower continue; 729*45223Ssklower (void) lseek(f, -(long)sizeof (wtmp), 1); 730*45223Ssklower SCPYN(wtmp.ut_name, ""); 731*45223Ssklower SCPYN(wtmp.ut_host, ""); 732*45223Ssklower time(&wtmp.ut_time); 733*45223Ssklower (void) write(f, (char *)&wtmp, sizeof (wtmp)); 734*45223Ssklower found++; 735*45223Ssklower } 736*45223Ssklower close(f); 737*45223Ssklower } 738*45223Ssklower if (found) { 739*45223Ssklower f = open(wtmpf, 1); 740*45223Ssklower if (f >= 0) { 741*45223Ssklower SCPYN(wtmp.ut_line, line+5); 742*45223Ssklower SCPYN(wtmp.ut_name, ""); 743*45223Ssklower SCPYN(wtmp.ut_host, ""); 744*45223Ssklower time(&wtmp.ut_time); 745*45223Ssklower (void) lseek(f, (long)0, 2); 746*45223Ssklower (void) write(f, (char *)&wtmp, sizeof (wtmp)); 747*45223Ssklower close(f); 748*45223Ssklower } 749*45223Ssklower } 750*45223Ssklower chmod(line, 0666); 751*45223Ssklower chown(line, 0, 0); 752*45223Ssklower line[strlen("/dev/")] = 'p'; 753*45223Ssklower chmod(line, 0666); 754*45223Ssklower chown(line, 0, 0); 755*45223Ssklower } 756*45223Ssklower 757*45223Ssklower x29d_trace(s, bp, n) 758*45223Ssklower char *s, *bp; 759*45223Ssklower { 760*45223Ssklower static int fd; 761*45223Ssklower char buf[BUFSIZ*4]; 762*45223Ssklower register char *p1, *p2; 763*45223Ssklower 764*45223Ssklower for(p1 = buf; *s; *p1++ = *s++); 765*45223Ssklower *p1++ = ':'; 766*45223Ssklower *p1++ = ' '; 767*45223Ssklower for(p2=bp; p2 < bp+n; p2++) 768*45223Ssklower if(*p2 >= ' ' && *p2 < 0177) 769*45223Ssklower *p1++ = *p2; 770*45223Ssklower else { 771*45223Ssklower *p1++ = '\\'; 772*45223Ssklower *p1++ = ((*p2 & 0300) >> 6) + '0'; 773*45223Ssklower *p1++ = ((*p2 & 070) >> 3) + '0'; 774*45223Ssklower *p1++ = (*p2 & 07) + '0'; 775*45223Ssklower } 776*45223Ssklower *p1++ = '\n'; 777*45223Ssklower if(fd <= 0) 778*45223Ssklower fd = creat(tracefn, 0666); 779*45223Ssklower (void) write(fd, buf, p1-buf); 780*45223Ssklower } 781