1*34455Sbostic #ifndef lint 2*34455Sbostic static char RCSid[] = "$Header: gap2d.c,v 2.0 85/11/21 07:23:00 jqj Exp $"; 3*34455Sbostic #endif 4*34455Sbostic /* 5*34455Sbostic * server for GAP-style (TransportObject=server,teletype) telnet connections 6*34455Sbostic * Note that we support only GAP version 2, although a server for version 3 7*34455Sbostic * exists. The version 2 server has not been tested as thoroughly as has the 8*34455Sbostic * version 3; it does NOT support RESERVE functionality. 9*34455Sbostic */ 10*34455Sbostic 11*34455Sbostic /* $Log: gap2d.c,v $ 12*34455Sbostic * Revision 2.0 85/11/21 07:23:00 jqj 13*34455Sbostic * 4.3BSD standard release 14*34455Sbostic * 15*34455Sbostic * Revision 1.2 85/05/23 06:22:18 jqj 16*34455Sbostic * *** empty log message *** 17*34455Sbostic * 18*34455Sbostic * Revision 1.2 85/05/23 06:22:18 jqj 19*34455Sbostic * *** empty log message *** 20*34455Sbostic * 21*34455Sbostic * Revision 1.1 85/05/22 09:46:52 jqj 22*34455Sbostic * Initial revision 23*34455Sbostic */ 24*34455Sbostic #include <stdio.h> 25*34455Sbostic #include <signal.h> 26*34455Sbostic #include <sgtty.h> 27*34455Sbostic #include <sys/types.h> 28*34455Sbostic #include <sys/time.h> 29*34455Sbostic #include <sys/uio.h> 30*34455Sbostic #include <sys/socket.h> 31*34455Sbostic #include <netns/ns.h> 32*34455Sbostic #include <netns/idp.h> 33*34455Sbostic #include <netns/sp.h> 34*34455Sbostic #include <sys/wait.h> 35*34455Sbostic #include <xnscourier/realcourierconnection.h> 36*34455Sbostic #include "GAP2.h" 37*34455Sbostic #include "gapcontrols.h" 38*34455Sbostic #include <xnscourier/except.h> 39*34455Sbostic #include <errno.h> 40*34455Sbostic 41*34455Sbostic #define BELL '\07' 42*34455Sbostic #define BANNER "\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r%s" 43*34455Sbostic 44*34455Sbostic int pty, net; 45*34455Sbostic extern CourierConnection *_serverConnection; 46*34455Sbostic char buf[sizeof(struct sphdr)+SPPMAXDATA]; 47*34455Sbostic struct sphdr our_sphdr; 48*34455Sbostic struct iovec our_iovec[2] = {{((caddr_t)&our_sphdr), sizeof(our_sphdr)}}; 49*34455Sbostic /* 50*34455Sbostic * I/O data buffers, pointers, and counters. 51*34455Sbostic */ 52*34455Sbostic char ptyibuf[512], *ptyip = ptyibuf; 53*34455Sbostic char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf; 54*34455Sbostic char *netip = buf; 55*34455Sbostic char netobuf[512], *nfrontp = netobuf, *nbackp = netobuf; 56*34455Sbostic int pcc, ncc; 57*34455Sbostic char line[12]; 58*34455Sbostic extern char **environ; 59*34455Sbostic extern int errno; 60*34455Sbostic 61*34455Sbostic char *envinit[3]; 62*34455Sbostic char wsenv[50]; 63*34455Sbostic 64*34455Sbostic /* 65*34455Sbostic * session parameters 66*34455Sbostic */ 67*34455Sbostic Cardinal frametimeout; /* 0 or time in seconds to wait */ 68*34455Sbostic 69*34455Sbostic 70*34455Sbostic /* 71*34455Sbostic * This modified version of the server is necessary since GAP specifies 72*34455Sbostic * that the telnet data-transfer session occurs after the RPC to create 73*34455Sbostic * it has returned! 74*34455Sbostic */ 75*34455Sbostic Server(skipcount,skippedwords) 76*34455Sbostic int skipcount; 77*34455Sbostic Unspecified skippedwords[]; 78*34455Sbostic { 79*34455Sbostic Cardinal _procedure; 80*34455Sbostic register Unspecified *_buf; 81*34455Sbostic LongCardinal programnum; 82*34455Sbostic Cardinal versionnum; 83*34455Sbostic Cardinal _n; 84*34455Sbostic 85*34455Sbostic #ifdef DEBUG 86*34455Sbostic BUGOUT("Server: %d %d",skipcount,skippedwords); 87*34455Sbostic #endif 88*34455Sbostic for (;;) { 89*34455Sbostic _buf = ReceiveCallMessage(&_procedure, skipcount, skippedwords); 90*34455Sbostic DURING switch (_procedure) { 91*34455Sbostic case 3: 92*34455Sbostic server_GAP2_Delete(_buf); 93*34455Sbostic break; 94*34455Sbostic case 2: 95*34455Sbostic server_GAP2_Create(_buf); 96*34455Sbostic net = _serverConnection->fd; 97*34455Sbostic gaptelnet(); /* returns on connection close */ 98*34455Sbostic break; 99*34455Sbostic case 0: 100*34455Sbostic server_GAP2_Reset(_buf); 101*34455Sbostic break; 102*34455Sbostic default: 103*34455Sbostic NoSuchProcedureValue("GAP", _procedure); 104*34455Sbostic break; 105*34455Sbostic } HANDLER { 106*34455Sbostic Deallocate(_buf); 107*34455Sbostic switch (Exception.Code) { 108*34455Sbostic case GAP2_terminalAddressInvalid: 109*34455Sbostic case GAP2_terminalAddressInUse: 110*34455Sbostic case GAP2_controllerDoesNotExist: 111*34455Sbostic case GAP2_controllerAlreadyExists: 112*34455Sbostic case GAP2_gapCommunicationError: 113*34455Sbostic case GAP2_gapNotExported: 114*34455Sbostic case GAP2_bugInGAPCode: 115*34455Sbostic case GAP2_tooManyGateStreams: 116*34455Sbostic case GAP2_inconsistentParams: 117*34455Sbostic case GAP2_transmissionMediumUnavailable: 118*34455Sbostic case GAP2_dialingHardwareProblem: 119*34455Sbostic case GAP2_noDialingHardware: 120*34455Sbostic case GAP2_badAddressFormat: 121*34455Sbostic case GAP2_mediumConnectFailed: 122*34455Sbostic case GAP2_illegalTransport: 123*34455Sbostic case GAP2_noCommunicationHardware: 124*34455Sbostic case GAP2_unimplemented: 125*34455Sbostic _buf = Allocate(0); 126*34455Sbostic SendAbortMessage(Exception.Code-ERROR_OFFSET, 0, _buf); 127*34455Sbostic break; 128*34455Sbostic default: 129*34455Sbostic _buf = Allocate(0); 130*34455Sbostic SendRejectMessage(unspecifiedError, 0, _buf); 131*34455Sbostic break; 132*34455Sbostic } 133*34455Sbostic } END_HANDLER; 134*34455Sbostic Deallocate(_buf); 135*34455Sbostic for (;;) { 136*34455Sbostic skipcount = LookAheadCallMsg(&programnum, &versionnum, 137*34455Sbostic skippedwords); 138*34455Sbostic if (skipcount < 0) return(0); /* timed out */ 139*34455Sbostic if (programnum != 3 || versionnum != 2) 140*34455Sbostic ExecCourierProgram(programnum, versionnum, 141*34455Sbostic skipcount, skippedwords); 142*34455Sbostic } /* loop if can't exec that program */ 143*34455Sbostic } 144*34455Sbostic } 145*34455Sbostic 146*34455Sbostic void 147*34455Sbostic GAP2_Delete(session) 148*34455Sbostic GAP2_SessionHandle session; 149*34455Sbostic { 150*34455Sbostic } 151*34455Sbostic 152*34455Sbostic void 153*34455Sbostic GAP2_Reset() 154*34455Sbostic { 155*34455Sbostic } 156*34455Sbostic 157*34455Sbostic GAP2_CreateResults 158*34455Sbostic GAP2_Create(conn, BDTproc, sessionparams, transports, 159*34455Sbostic createTimeout) 160*34455Sbostic CourierConnection *conn; 161*34455Sbostic int BDTproc; 162*34455Sbostic GAP2_SessionParameterObject sessionparams; 163*34455Sbostic struct {Cardinal length; 164*34455Sbostic GAP2_TransportObject *sequence; 165*34455Sbostic } transports; 166*34455Sbostic GAP2_WaitTime createTimeout; 167*34455Sbostic { 168*34455Sbostic GAP2_CreateResults result; 169*34455Sbostic char *c1, *c2, *host; 170*34455Sbostic int t, pid; 171*34455Sbostic struct sgttyb b; 172*34455Sbostic char *xntoa(), *wsname(); 173*34455Sbostic struct sockaddr_ns who; 174*34455Sbostic int whosize = sizeof(who); 175*34455Sbostic LongCardinal servicetype; 176*34455Sbostic GAP2_CommParamObject *cp; 177*34455Sbostic GAP2_Duplexity duplexity; /* fullDuplex, halfDuplex */ 178*34455Sbostic 179*34455Sbostic #ifdef DEBUG 180*34455Sbostic BUGOUT("CREATE"); 181*34455Sbostic #endif 182*34455Sbostic switch (sessionparams.designator) { 183*34455Sbostic case ttyHost: 184*34455Sbostic frametimeout = sessionparams.ttyHost_case.frameTimeout/1000; 185*34455Sbostic /* could set other parameters here */ 186*34455Sbostic break; 187*34455Sbostic default: 188*34455Sbostic raise(GAP2_unimplemented, 0); 189*34455Sbostic /*NOTREACHED*/ 190*34455Sbostic } 191*34455Sbostic if (transports.length != 2) { 192*34455Sbostic raise(GAP2_illegalTransport); 193*34455Sbostic /*NOTREACHED*/ 194*34455Sbostic } 195*34455Sbostic switch (transports.sequence[0].designator) { 196*34455Sbostic case rs232c: /* maybe some day */ 197*34455Sbostic cp = &transports.sequence[0].rs232c_case.commParams; 198*34455Sbostic if (cp->accessDetail.designator == directConn) { 199*34455Sbostic duplexity = cp->duplex; 200*34455Sbostic servicetype = 0; /* fake it */ 201*34455Sbostic break; 202*34455Sbostic } 203*34455Sbostic raise(GAP2_noCommunicationHardware, 0); 204*34455Sbostic /*NOTREACHED*/ 205*34455Sbostic default: 206*34455Sbostic raise(GAP2_illegalTransport, 0); 207*34455Sbostic /*NOTREACHED*/ 208*34455Sbostic } 209*34455Sbostic if (transports.sequence[1].designator != teletype) 210*34455Sbostic raise(GAP2_illegalTransport, 0); 211*34455Sbostic /* ignore createTimeout */ 212*34455Sbostic /* ignore credentials and verifier */ 213*34455Sbostic 214*34455Sbostic for (c1 = "pq"; *c1 != 0; c1++) 215*34455Sbostic for (c2 = "0123456789abcdef"; *c2 != 0; c2++) { 216*34455Sbostic sprintf(line, "/dev/pty%c%c", *c1, *c2); 217*34455Sbostic pty = open(line, 2); 218*34455Sbostic if (pty < 0) continue; 219*34455Sbostic line[strlen("/dev/")] = 't'; 220*34455Sbostic t = open(line, 2); 221*34455Sbostic if (t > 0) goto gotpty; 222*34455Sbostic close(pty); 223*34455Sbostic } 224*34455Sbostic raise(GAP2_tooManyGateStreams, 0); 225*34455Sbostic /*NOTREACHED*/ 226*34455Sbostic gotpty: 227*34455Sbostic getpeername(_serverConnection->fd, &who, &whosize); 228*34455Sbostic host = wsname(who.sns_addr); 229*34455Sbostic #ifdef DEBUG 230*34455Sbostic BUGOUT("gotpty <%s> %d <%s>",line, pty, host); 231*34455Sbostic #endif 232*34455Sbostic ioctl(t, TIOCGETP, &b); 233*34455Sbostic b.sg_flags = CRMOD|XTABS|ANYP; 234*34455Sbostic ioctl(t, TIOCSETP, &b); 235*34455Sbostic ioctl(pty, TIOCGETP, &b); 236*34455Sbostic if (duplexity == fullduplex) 237*34455Sbostic b.sg_flags |= ECHO; 238*34455Sbostic else 239*34455Sbostic b.sg_flags &= ~ECHO; 240*34455Sbostic ioctl(pty, TIOCSETP, &b); 241*34455Sbostic /* we do the fork now so we can return failures as REPORTS */ 242*34455Sbostic pid = fork(); 243*34455Sbostic if (pid < 0) { 244*34455Sbostic close(pty); close(t); 245*34455Sbostic raise(GAP2_tooManyGateStreams, 0); 246*34455Sbostic /*NOTREACHED*/ 247*34455Sbostic } 248*34455Sbostic else if (pid == 0) { /* in the execed fork */ 249*34455Sbostic sleep(1); /* let parent get ready for us */ 250*34455Sbostic close(_serverConnection->fd); /* close net */ 251*34455Sbostic close(pty); 252*34455Sbostic dup2(t, 0); 253*34455Sbostic dup2(t, 1); 254*34455Sbostic dup2(t, 2); 255*34455Sbostic if (t > 2) close(t); 256*34455Sbostic envinit[0] = "TERM=network"; 257*34455Sbostic envinit[1] = sprintf(wsenv, "WORKSTATION=%s", 258*34455Sbostic xntoa(who.sns_addr)); 259*34455Sbostic envinit[2] = (char*) 0; 260*34455Sbostic #ifdef DEBUG 261*34455Sbostic BUGOUT("about to exec /bin/login"); 262*34455Sbostic #endif 263*34455Sbostic execl("/bin/login","login", "-h", host, 0); 264*34455Sbostic #ifdef DEBUG 265*34455Sbostic BUGOUT("exec of /bin/login failed"); 266*34455Sbostic #endif 267*34455Sbostic perror("/bin/login"); 268*34455Sbostic exit(1); 269*34455Sbostic /*NOTREACHED*/ 270*34455Sbostic } 271*34455Sbostic close(t); 272*34455Sbostic #ifdef DEBUG 273*34455Sbostic BUGOUT("fork successful"); 274*34455Sbostic #endif 275*34455Sbostic result.session[0] = pid; 276*34455Sbostic return(result); 277*34455Sbostic } 278*34455Sbostic 279*34455Sbostic jmp_buf childdiedbuf; 280*34455Sbostic 281*34455Sbostic /* 282*34455Sbostic * Main loop. Select from pty and network, and 283*34455Sbostic * hand data to telnet receiver finite state machine. 284*34455Sbostic * Returns 0 on orderly shutdown, 1 on abnormal shutdown. 285*34455Sbostic */ 286*34455Sbostic gaptelnet() 287*34455Sbostic { 288*34455Sbostic int on = 1; 289*34455Sbostic char hostname[32]; 290*34455Sbostic int childdied(); 291*34455Sbostic int ibits = 0, obits = 0; 292*34455Sbostic register int c; 293*34455Sbostic struct sphdr *si = (struct sphdr *)buf; 294*34455Sbostic static struct timeval timeout = {600,0}; 295*34455Sbostic int keepalives = 0; 296*34455Sbostic int i; 297*34455Sbostic 298*34455Sbostic #ifdef DEBUG 299*34455Sbostic BUGOUT("gaptelnet net=%d,pty=%d",net,pty); 300*34455Sbostic #endif 301*34455Sbostic if (setjmp(childdiedbuf) != 0) 302*34455Sbostic return(0); /* child died */ 303*34455Sbostic signal(SIGCHLD, childdied); 304*34455Sbostic signal(SIGTSTP, SIG_IGN); 305*34455Sbostic ioctl(net, FIONBIO, &on); 306*34455Sbostic ioctl(pty, FIONBIO, &on); 307*34455Sbostic 308*34455Sbostic 309*34455Sbostic /* 310*34455Sbostic * Show banner that getty never gave. 311*34455Sbostic */ 312*34455Sbostic gethostname(hostname, sizeof (hostname)); 313*34455Sbostic sprintf(nfrontp, BANNER, hostname, ""); 314*34455Sbostic nfrontp += strlen(nfrontp); 315*34455Sbostic /* 316*34455Sbostic * Send status message indicating we're ready to go 317*34455Sbostic */ 318*34455Sbostic changeSPPopts(net, GAPCTLnone, 1); 319*34455Sbostic sendoobdata(GAPCTLmediumUp); 320*34455Sbostic for (;;) { 321*34455Sbostic #ifdef DEBUG 322*34455Sbostic BUGOUT("looping in gaptelnet"); 323*34455Sbostic #endif 324*34455Sbostic ibits = obits = 0; 325*34455Sbostic /* 326*34455Sbostic * Never look for input if there's still 327*34455Sbostic * stuff in the corresponding output buffer 328*34455Sbostic */ 329*34455Sbostic if (nfrontp - nbackp || pcc > 0) 330*34455Sbostic obits |= (1 << net); 331*34455Sbostic else 332*34455Sbostic ibits |= (1 << pty); 333*34455Sbostic if (pfrontp - pbackp || ncc > 0) 334*34455Sbostic obits |= (1 << pty); 335*34455Sbostic else 336*34455Sbostic ibits |= (1 << net); 337*34455Sbostic if (ncc < 0 && pcc < 0) 338*34455Sbostic break; 339*34455Sbostic timeout.tv_sec = 600; 340*34455Sbostic timeout.tv_usec = 0; 341*34455Sbostic select(16, &ibits, &obits, 0, &timeout); 342*34455Sbostic if (ibits == 0 && obits == 0) { 343*34455Sbostic /* timeout means no activity for a long time */ 344*34455Sbostic #ifdef DEBUG 345*34455Sbostic BUGOUT("timeout from select"); 346*34455Sbostic #endif 347*34455Sbostic if (keepalives++ < 2) { 348*34455Sbostic /* first 2 times through send warning */ 349*34455Sbostic if (nfrontp == nbackp && pcc == 0) { 350*34455Sbostic /* but only if not blocked on output */ 351*34455Sbostic #define WARNING "\r\nYou've been idle much too long. Respond or log off.\r\n" 352*34455Sbostic strcpy(nfrontp, WARNING); 353*34455Sbostic nfrontp += sizeof(WARNING); 354*34455Sbostic } 355*34455Sbostic sleep(5); 356*34455Sbostic continue; 357*34455Sbostic } 358*34455Sbostic #ifdef DEBUG 359*34455Sbostic BUGOUT("keepalive expired -- calling cleanup"); 360*34455Sbostic #endif 361*34455Sbostic /* keepalive count has expired */ 362*34455Sbostic cleanup(); 363*34455Sbostic return(1); 364*34455Sbostic } 365*34455Sbostic 366*34455Sbostic /* 367*34455Sbostic * Something to read from the network... 368*34455Sbostic */ 369*34455Sbostic if (ibits & (1 << net)) { 370*34455Sbostic ncc = read(net, buf, sizeof(buf)); 371*34455Sbostic #ifdef DEBUG 372*34455Sbostic BUGOUT("read from net %d",ncc); 373*34455Sbostic #endif 374*34455Sbostic if (ncc < 0 && errno == EWOULDBLOCK) 375*34455Sbostic ncc = 0; 376*34455Sbostic else if (ncc < sizeof(struct sphdr)) { 377*34455Sbostic #ifdef DEBUG 378*34455Sbostic BUGOUT("short read, %d. calling cleanup",ncc); 379*34455Sbostic #endif 380*34455Sbostic cleanup(); /* will probably fail or block */ 381*34455Sbostic return(1); 382*34455Sbostic } 383*34455Sbostic else if (si->sp_cc & SP_OB) { 384*34455Sbostic /* a status or OOB control */ 385*34455Sbostic switch (buf[sizeof(struct sphdr)]) { 386*34455Sbostic case GAPCTLinterrupt: 387*34455Sbostic /* shove interrupt char in buffer */ 388*34455Sbostic interrupt(); 389*34455Sbostic break; /* from switch */ 390*34455Sbostic case GAPCTLareYouThere: 391*34455Sbostic sendoobdata(GAPCTLiAmHere); 392*34455Sbostic break; /* from switch */ 393*34455Sbostic default: 394*34455Sbostic /* Ignore other controls instead of: 395*34455Sbostic * sendoobdata( 396*34455Sbostic * GAPCTLunexpectedRemoteBehavior); 397*34455Sbostic */ 398*34455Sbostic break; /* from switch */ 399*34455Sbostic } 400*34455Sbostic ncc = 0; /* no chars here */ 401*34455Sbostic } 402*34455Sbostic else if (si->sp_dt==GAPCTLnone) { 403*34455Sbostic /* the normal case */ 404*34455Sbostic ncc -= sizeof(struct sphdr); 405*34455Sbostic netip = buf + sizeof(struct sphdr); 406*34455Sbostic keepalives = 0; 407*34455Sbostic } 408*34455Sbostic else if(si->sp_dt==GAPCTLcleanup) { 409*34455Sbostic #ifdef DEBUG 410*34455Sbostic BUGOUT("got CLEANUP packet. Done"); 411*34455Sbostic #endif 412*34455Sbostic cleanup(); /* normal termination */ 413*34455Sbostic return(0); 414*34455Sbostic } 415*34455Sbostic else if (si->sp_dt==SPPSST_END) { 416*34455Sbostic /* got premature termination */ 417*34455Sbostic quitquit(net, pty); 418*34455Sbostic return(1); 419*34455Sbostic } 420*34455Sbostic } 421*34455Sbostic 422*34455Sbostic /* 423*34455Sbostic * Something to read from the pty... 424*34455Sbostic */ 425*34455Sbostic if (ibits & (1 << pty)) { 426*34455Sbostic if (frametimeout > 0) sleep(frametimeout); 427*34455Sbostic pcc = read(pty, ptyibuf, sizeof(ptyibuf)); 428*34455Sbostic #ifdef DEBUG 429*34455Sbostic BUGOUT("read from pty %d",pcc); 430*34455Sbostic #endif 431*34455Sbostic if (pcc < 0 && errno == EWOULDBLOCK) 432*34455Sbostic pcc = 0; 433*34455Sbostic else if (pcc <= 0) { 434*34455Sbostic #ifdef DEBUG 435*34455Sbostic BUGOUT("short read from pty. Calling cleanup"); 436*34455Sbostic #endif 437*34455Sbostic cleanup(); 438*34455Sbostic return(1); /* ?? abnormal termination */ 439*34455Sbostic } 440*34455Sbostic ptyip = ptyibuf; 441*34455Sbostic } 442*34455Sbostic 443*34455Sbostic while (pcc > 0) { 444*34455Sbostic if ((&netobuf[sizeof(netobuf)] - nfrontp) < 2) 445*34455Sbostic break; 446*34455Sbostic *nfrontp++ = *ptyip++ & 0377; pcc--; 447*34455Sbostic } 448*34455Sbostic if ((obits & (1 << net)) && (nfrontp - nbackp) > 0) 449*34455Sbostic netflush(); 450*34455Sbostic while (ncc > 0) { 451*34455Sbostic if ((&ptyobuf[sizeof(ptyobuf)] - pfrontp) < 2) break; 452*34455Sbostic *pfrontp++ = *netip++ & 0377; 453*34455Sbostic ncc--; 454*34455Sbostic } 455*34455Sbostic if ((obits & (1 << pty)) && (pfrontp - pbackp) > 0) 456*34455Sbostic ptyflush(); 457*34455Sbostic } 458*34455Sbostic /* we should never get to here */ 459*34455Sbostic #ifdef DEBUG 460*34455Sbostic BUGOUT("broke out of for(;;) somehow. calling cleanup"); 461*34455Sbostic #endif 462*34455Sbostic cleanup(); 463*34455Sbostic return(0); 464*34455Sbostic } 465*34455Sbostic 466*34455Sbostic /* 467*34455Sbostic * Send out of band data to other end of network 468*34455Sbostic */ 469*34455Sbostic sendoobdata(value) 470*34455Sbostic u_char value; 471*34455Sbostic { 472*34455Sbostic struct { 473*34455Sbostic struct sphdr hdr; 474*34455Sbostic char val; 475*34455Sbostic } oob; 476*34455Sbostic oob.hdr = our_sphdr; 477*34455Sbostic oob.val = value; 478*34455Sbostic #ifdef DEBUG 479*34455Sbostic BUGOUT("sendoobdata 0%o",value); 480*34455Sbostic #endif 481*34455Sbostic send(net, &oob, sizeof(oob), MSG_OOB); 482*34455Sbostic } 483*34455Sbostic 484*34455Sbostic /* 485*34455Sbostic * Send interrupt to process on other side of pty. 486*34455Sbostic * If it is in raw mode, just write NULL; 487*34455Sbostic * otherwise, write intr char. 488*34455Sbostic */ 489*34455Sbostic interrupt() 490*34455Sbostic { 491*34455Sbostic struct sgttyb b; 492*34455Sbostic struct tchars tchars; 493*34455Sbostic 494*34455Sbostic ptyflush(); /* half-hearted */ 495*34455Sbostic ioctl(pty, TIOCGETP, &b); 496*34455Sbostic if (b.sg_flags & RAW) { 497*34455Sbostic *pfrontp++ = '\0'; 498*34455Sbostic return; 499*34455Sbostic } 500*34455Sbostic *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? 501*34455Sbostic '\177' : tchars.t_intrc; 502*34455Sbostic } 503*34455Sbostic 504*34455Sbostic ptyflush() 505*34455Sbostic { 506*34455Sbostic register int n; 507*34455Sbostic 508*34455Sbostic if ((n = pfrontp - pbackp) > 0) 509*34455Sbostic n = write(pty, pbackp, n); 510*34455Sbostic #ifdef DEBUG 511*34455Sbostic BUGOUT("ptyflush wrote %d",n); 512*34455Sbostic #endif 513*34455Sbostic if (n < 0) 514*34455Sbostic return; 515*34455Sbostic pbackp += n; 516*34455Sbostic if (pbackp >= pfrontp) /* actually, > is an error */ 517*34455Sbostic pbackp = pfrontp = ptyobuf; 518*34455Sbostic } 519*34455Sbostic 520*34455Sbostic netflush() 521*34455Sbostic { 522*34455Sbostic register int n; 523*34455Sbostic 524*34455Sbostic if ((n = nfrontp - nbackp) > 0) { 525*34455Sbostic our_iovec[1].iov_len = ((n > SPPMAXDATA) ? SPPMAXDATA : n); 526*34455Sbostic our_iovec[1].iov_base = nbackp; 527*34455Sbostic n = writev(net, our_iovec, 2) - sizeof(struct sphdr); 528*34455Sbostic } 529*34455Sbostic #ifdef DEBUG 530*34455Sbostic BUGOUT("netflush wrote %d",n); 531*34455Sbostic if (our_iovec[0].iov_base != (char*)&our_sphdr) 532*34455Sbostic BUGOUT("Oops: our_iovec clobbered"); 533*34455Sbostic BUGOUT("header: %d %d, %d %d %d %d %d %d", 534*34455Sbostic our_sphdr.sp_cc, our_sphdr.sp_dt, 535*34455Sbostic our_sphdr.sp_sid, our_sphdr.sp_did, our_sphdr.sp_seq, 536*34455Sbostic our_sphdr.sp_ack, our_sphdr.sp_alo); 537*34455Sbostic #endif 538*34455Sbostic if (n < 0) { 539*34455Sbostic if (errno == EWOULDBLOCK) 540*34455Sbostic return; 541*34455Sbostic /* should blow this guy away... */ 542*34455Sbostic return; 543*34455Sbostic } 544*34455Sbostic nbackp += n; 545*34455Sbostic if (nbackp >= nfrontp) /* actually , > is an error */ 546*34455Sbostic nbackp = nfrontp = netobuf; 547*34455Sbostic } 548*34455Sbostic 549*34455Sbostic /* 550*34455Sbostic * handle receipt of an SPPSST_END packet 551*34455Sbostic * This is currently an error, since client didn't send "cleanup" first 552*34455Sbostic */ 553*34455Sbostic quitquit() 554*34455Sbostic { 555*34455Sbostic changeSPPopts(net, SPPSST_ENDREPLY, 1); 556*34455Sbostic write(net, &our_sphdr, sizeof(our_sphdr)); 557*34455Sbostic sleep(3); 558*34455Sbostic 559*34455Sbostic rmut(); 560*34455Sbostic vhangup(); /* XXX */ 561*34455Sbostic shutdown(net, 1); 562*34455Sbostic close(net); 563*34455Sbostic } 564*34455Sbostic 565*34455Sbostic /* 566*34455Sbostic * shut down the data connection for one reason or another 567*34455Sbostic */ 568*34455Sbostic cleanup() 569*34455Sbostic { 570*34455Sbostic int fdmask; 571*34455Sbostic struct timeval timeout; 572*34455Sbostic struct sphdr *si = (struct sphdr *)buf; 573*34455Sbostic int off = 0; 574*34455Sbostic 575*34455Sbostic signal(SIGCHLD, SIG_IGN); 576*34455Sbostic sendoobdata(GAPCTLcleanup); 577*34455Sbostic changeSPPopts(net, SPPSST_END, 1); 578*34455Sbostic if (write(net, &our_sphdr, sizeof(our_sphdr)) < 0) { 579*34455Sbostic fdmask = 1<<net; 580*34455Sbostic timeout.tv_sec = 10; 581*34455Sbostic while (select(net+1,&fdmask,(int*)0, (int*)0, &timeout) > 0 && 582*34455Sbostic read(net,buf,sizeof(buf)) >= sizeof(struct sphdr)) { 583*34455Sbostic #ifdef DEBUG 584*34455Sbostic BUGOUT("cleanup -- got packet"); 585*34455Sbostic #endif 586*34455Sbostic if ((si->sp_cc & SP_OB) 587*34455Sbostic && si->sp_dt == SPPSST_ENDREPLY) { 588*34455Sbostic changeSPPopts(net, SPPSST_ENDREPLY, 1); 589*34455Sbostic write(net, &our_sphdr, sizeof(our_sphdr)); 590*34455Sbostic #ifdef DEBUG 591*34455Sbostic BUGOUT("cleanup -- wrote ENDREPLY"); 592*34455Sbostic #endif 593*34455Sbostic sleep(1); 594*34455Sbostic changeSPPopts(net,0,0); 595*34455Sbostic ioctl(net, FIONBIO, &off); 596*34455Sbostic rmut(); 597*34455Sbostic vhangup(); /* XXX */ 598*34455Sbostic return; 599*34455Sbostic } 600*34455Sbostic /* loop: ignore everything except ENDREPLY */ 601*34455Sbostic fdmask = 1<<net; 602*34455Sbostic timeout.tv_sec = 10; 603*34455Sbostic } 604*34455Sbostic /* timed out or read failed */ 605*34455Sbostic changeSPPopts(net, SPPSST_ENDREPLY, 1); 606*34455Sbostic write(net, &our_sphdr, sizeof(our_sphdr)); 607*34455Sbostic sleep(1); 608*34455Sbostic } 609*34455Sbostic shutdown(net, 1); 610*34455Sbostic close(net); 611*34455Sbostic rmut(); 612*34455Sbostic vhangup(); /* XXX */ 613*34455Sbostic } 614*34455Sbostic 615*34455Sbostic /* 616*34455Sbostic * SIGCHLD interrupt handler 617*34455Sbostic */ 618*34455Sbostic childdied() 619*34455Sbostic { 620*34455Sbostic #ifdef DEBUG 621*34455Sbostic BUGOUT("child died"); 622*34455Sbostic #endif 623*34455Sbostic cleanup(); 624*34455Sbostic longjmp(childdiedbuf, -1); 625*34455Sbostic } 626*34455Sbostic 627*34455Sbostic changeSPPopts(s, stream, eom) 628*34455Sbostic int s; /* SPP socket */ 629*34455Sbostic u_char stream; /* datastream type */ 630*34455Sbostic char eom; /* Boolean EOM */ 631*34455Sbostic { 632*34455Sbostic our_sphdr.sp_dt = stream; 633*34455Sbostic our_sphdr.sp_cc = (eom ? SP_EM : 0); 634*34455Sbostic } 635*34455Sbostic 636*34455Sbostic 637*34455Sbostic #include <utmp.h> 638*34455Sbostic 639*34455Sbostic struct utmp wtmp; 640*34455Sbostic char wtmpf[] = "/usr/adm/wtmp"; 641*34455Sbostic char utmp[] = "/etc/utmp"; 642*34455Sbostic #define SCPYN(a, b) strncpy(a, b, sizeof (a)) 643*34455Sbostic #define SCMPN(a, b) strncmp(a, b, sizeof (a)) 644*34455Sbostic 645*34455Sbostic rmut() 646*34455Sbostic { 647*34455Sbostic register f; 648*34455Sbostic int found = 0; 649*34455Sbostic 650*34455Sbostic f = open(utmp, 2); 651*34455Sbostic if (f >= 0) { 652*34455Sbostic while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) { 653*34455Sbostic if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) 654*34455Sbostic continue; 655*34455Sbostic lseek(f, -(long)sizeof (wtmp), 1); 656*34455Sbostic SCPYN(wtmp.ut_name, ""); 657*34455Sbostic SCPYN(wtmp.ut_host, ""); 658*34455Sbostic time(&wtmp.ut_time); 659*34455Sbostic write(f, (char *)&wtmp, sizeof (wtmp)); 660*34455Sbostic found++; 661*34455Sbostic } 662*34455Sbostic close(f); 663*34455Sbostic } 664*34455Sbostic if (found) { 665*34455Sbostic f = open(wtmpf, 1); 666*34455Sbostic if (f >= 0) { 667*34455Sbostic SCPYN(wtmp.ut_line, line+5); 668*34455Sbostic SCPYN(wtmp.ut_name, ""); 669*34455Sbostic SCPYN(wtmp.ut_host, ""); 670*34455Sbostic time(&wtmp.ut_time); 671*34455Sbostic lseek(f, (long)0, 2); 672*34455Sbostic write(f, (char *)&wtmp, sizeof (wtmp)); 673*34455Sbostic close(f); 674*34455Sbostic } 675*34455Sbostic } 676*34455Sbostic chmod(line, 0666); 677*34455Sbostic chown(line, 0, 0); 678*34455Sbostic line[strlen("/dev/")] = 'p'; 679*34455Sbostic chmod(line, 0666); 680*34455Sbostic chown(line, 0, 0); 681*34455Sbostic } 682*34455Sbostic 683*34455Sbostic /* 684*34455Sbostic * Convert network-format xns address 685*34455Sbostic * to ascii 686*34455Sbostic * --Replace this with a clearinghouse name lookup someday. 687*34455Sbostic */ 688*34455Sbostic char * 689*34455Sbostic wsname(addr) 690*34455Sbostic struct ns_addr addr; 691*34455Sbostic { 692*34455Sbostic static char b[50]; 693*34455Sbostic char temp[10]; 694*34455Sbostic int i; 695*34455Sbostic 696*34455Sbostic /* net */ 697*34455Sbostic sprintf(b, "%D.", ntohl(ns_netof(addr))); 698*34455Sbostic /* skip leading zeros */ 699*34455Sbostic for(i=0; (addr.x_host.c_host[i] == (char) 0); i++) ; 700*34455Sbostic /* print the rest */ 701*34455Sbostic for(; i < 6; i++) { 702*34455Sbostic sprintf(temp,"%x", addr.x_host.c_host[i]); 703*34455Sbostic strcat(b, temp); 704*34455Sbostic if(i != 5) strcat(b, ":"); 705*34455Sbostic } 706*34455Sbostic return (b); 707*34455Sbostic } 708*34455Sbostic 709*34455Sbostic /* 710*34455Sbostic * generate an xns address that "DE" can parse. 711*34455Sbostic * This goes in the environment. Should be the same as above 712*34455Sbostic */ 713*34455Sbostic char * 714*34455Sbostic xntoa(addr) 715*34455Sbostic struct ns_addr addr; 716*34455Sbostic { 717*34455Sbostic static char b[50]; 718*34455Sbostic char temp[10]; 719*34455Sbostic int i; 720*34455Sbostic 721*34455Sbostic /* net */ 722*34455Sbostic sprintf(b, "%X#", ntohl(ns_netof(addr))); 723*34455Sbostic /* print the rest */ 724*34455Sbostic for(i=0; i < 6; i++) { 725*34455Sbostic sprintf(temp,"%x", addr.x_host.c_host[i]); 726*34455Sbostic strcat(b, temp); 727*34455Sbostic if(i != 5) strcat(b, "."); 728*34455Sbostic } 729*34455Sbostic return (b); 730*34455Sbostic } 731*34455Sbostic 732*34455Sbostic #ifdef DEBUG 733*34455Sbostic BUGOUT(str,a,b,c,d,e,f,g,h) 734*34455Sbostic char *str; 735*34455Sbostic { 736*34455Sbostic FILE *fd; 737*34455Sbostic fd = fopen("/tmp/GAP2d.log","a"); 738*34455Sbostic fprintf(fd,str,a,b,c,d,e,f,g,h); 739*34455Sbostic putc('\n',fd); 740*34455Sbostic fclose(fd); 741*34455Sbostic } 742*34455Sbostic #endif 743