void DisconnBid( USHORT uBid ) { pWaitForSingleObject( hThreadMutex, INFINITE ); int k = FindConn( uBid ); if ( k != -1 ) { ThreadConnection Conn = Connections[ k ]; Connections[ k ].thread_s = INVALID_SOCKET; if ( Conn.thread_s != INVALID_SOCKET ) { pshutdown( Conn.thread_s, FD_READ ); pshutdown( Conn.thread_s, SD_SEND ); pclosesocket( Conn.thread_s ); } dwConnections--; if ( dwConnections ) { Connections[ k ] = Connections[ dwConnections ]; } } pReleaseMutex( hThreadMutex ); }
/* ** BootDone -- free up memory allocated for a connection. ** ** Parameters: ** rconn - incoming boot complete packet. ** ** Returns: ** 1 on success, 0 on failure. ** ** Side Effects: ** none. */ int BootDone(RMPCONN *rconn) { RMPCONN *oldconn; struct rmp_packet *rpl; /* * If we cant find the connection, ignore the request. */ if ((oldconn = FindConn(rconn)) == NULL) { syslog(LOG_ERR, "BootDone: no existing connection (%s)", EnetStr(rconn)); return(0); } rpl = &oldconn->rmp; /* cache ptr to RMP packet */ /* * Make sure Session ID's match. */ if (ntohs(rconn->rmp.r_rrq.rmp_session) != ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session): ntohs(rpl->r_rrpl.rmp_session))) { syslog(LOG_ERR, "BootDone: bad session id (%s)", EnetStr(rconn)); return(0); } RemoveConn(oldconn); /* remove connection */ syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn)); return(1); }
void SessionWork( SOCKET Socket ) { PCONNECTIONS pConnect = (PCONNECTIONS)MemAlloc( sizeof( PCONNECTIONS ) ); m_memset( pConnect, 0, sizeof( PCONNECTIONS ) ); char *Data = NULL; while ( 1 ) { if ( !WaitRecv( Socket, 60*60 ) ) { break; } TPkt tPacket; if ( !NetRecv( Socket, (char*)&tPacket, sizeof( tPacket ) ) ) { break; } if ( tPacket.QType == 0x63 ) { if ( tPacket.dwLen != 6 ) { break; } if ( Data ) { MemFree( Data ); } Data = (char *)MemAlloc( tPacket.dwLen + 1 ); if ( Data == NULL ) { break; } if ( !NetRecv( Socket, Data, tPacket.dwLen ) ) { break; } ManageNewConnection( Socket, *(ULONG*)Data, (USHORT)tPacket.dwReserved, *(USHORT*)&Data[4] ); } else if ( tPacket.QType == 0x73 ) { if ( Data ) { MemFree( Data ); } Data = (char *)MemAlloc( tPacket.dwLen + 1 ); if ( Data == NULL ) { break; } if ( !NetRecv( Socket, Data, tPacket.dwLen ) ) { break; } BcDecrypt( Data, tPacket.dwLen ); ThreadConnection Conn; pWaitForSingleObject( hThreadMutex, INFINITE ); int k = FindConn( (USHORT)tPacket.dwReserved ); if ( k != -1 ) { Conn = Connections[ k ]; NetSend( Conn.thread_s, Data, tPacket.dwLen ); } pReleaseMutex( hThreadMutex ); } else if ( tPacket.QType == 0x77 ) { DisconnBid( tPacket.dwReserved ); } else if ( tPacket.QType == 0x64 ) { pclosesocket(Socket); KillAllConnections(); pExitThread( 1 ); break; } else if ( tPacket.QType == 0x65 ) { } else { break; } } if ( Data ) { MemFree( Data ); } pConnect->dwStatus = 1; }
DWORD WINAPI ConnectionThread( LPVOID lpData ) { int bid = (int)lpData; ThreadConnection Conn; pWaitForSingleObject( hThreadMutex, INFINITE ); int k = FindConn( bid ); if ( k != -1 ) { Conn = Connections[ k ]; } pReleaseMutex(hThreadMutex); if ( k != -1 ) { if ( Conn.thread_s != INVALID_SOCKET ) { pWaitForSingleObject( hThreadMutex, INFINITE ); k = FindConn( bid ); if ( k != -1 ) { Connections[ k ].thread_s = Conn.thread_s; } pReleaseMutex( hThreadMutex ); pWaitForSingleObject( hSockMutex, INFINITE ); SendStatus( Conn.s, bid, Conn.cid, TRUE ); pReleaseMutex( hSockMutex ); char data[1024]; while ( 1 ) { int r = (int)precv( Conn.thread_s, data, 1024, 0 ); if ( r == 0 || r == SOCKET_ERROR ) { pWaitForSingleObject( hSockMutex, INFINITE ); TPkt tPacket; tPacket.dwLen = 0; tPacket.QType = 0x77; tPacket.dwReserved = bid; NetSend( Conn.s, (char*)&tPacket, sizeof( tPacket ) ); pReleaseMutex( hSockMutex ); break; } pWaitForSingleObject( hSockMutex, INFINITE ); TPkt tPacket; tPacket.dwLen = r; tPacket.QType = 0x73; tPacket.dwReserved = bid; NetSend( Conn.s, (char*)&tPacket, sizeof( tPacket ) ); BcDecrypt( data, r ); if ( !NetSend( Conn.s, data, r ) ) { pReleaseMutex( hSockMutex ); break; } pReleaseMutex( hSockMutex ); } } else { SendStatus( Conn.s, bid, Conn.cid, FALSE ); } } DisconnBid( bid ); return 0; }
/* ** SendReadRepl -- send a portion of the boot file to the requester. ** ** Parameters: ** rconn - the reply packet to be formatted. ** ** Returns: ** 1 on success, 0 on failure. ** ** Side Effects: ** none. */ int SendReadRepl(RMPCONN *rconn) { int retval = 0; RMPCONN *oldconn; struct rmp_packet *rpl, *req; int size = 0; int madeconn = 0; /* * Find the old connection. If one doesnt exist, create one only * to return the error code. */ if ((oldconn = FindConn(rconn)) == NULL) { if ((oldconn = NewConn(rconn)) == NULL) return(0); syslog(LOG_ERR, "SendReadRepl: no active connection (%s)", EnetStr(rconn)); madeconn++; } req = &rconn->rmp; /* cache ptr to request packet */ rpl = &oldconn->rmp; /* cache ptr to reply packet */ if (madeconn) { /* no active connection above; abort */ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; retval = 1; goto sendpkt; } /* * Make sure Session ID's match. */ if (ntohs(req->r_rrq.rmp_session) != ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session): ntohs(rpl->r_rrpl.rmp_session))) { syslog(LOG_ERR, "SendReadRepl: bad session id (%s)", EnetStr(rconn)); rpl->r_rrpl.rmp_retcode = RMP_E_BADSID; retval = 1; goto sendpkt; } /* * If the requester asks for more data than we can fit, * silently clamp the request size down to RMPREADDATA. * * N.B. I do not know if this is "legal", however it seems * to work. This is necessary for bpfwrite() on machines * with MCLBYTES less than 1514. */ if (ntohs(req->r_rrq.rmp_size) > RMPREADDATA) req->r_rrq.rmp_size = htons(RMPREADDATA); /* * Position read head on file according to info in request packet. */ GETWORD(req->r_rrq.rmp_offset, size); if (lseek(oldconn->bootfd, (off_t)size, SEEK_SET) < 0) { syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)", EnetStr(rconn)); rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; retval = 1; goto sendpkt; } /* * Read data directly into reply packet. */ if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data, (int) ntohs(req->r_rrq.rmp_size))) <= 0) { if (size < 0) { syslog(LOG_ERR, "SendReadRepl: read: %m (%s)", EnetStr(rconn)); rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; } else { rpl->r_rrpl.rmp_retcode = RMP_E_EOF; } retval = 1; goto sendpkt; } /* * Set success indication. */ rpl->r_rrpl.rmp_retcode = RMP_E_OKAY; sendpkt: /* * Set up assorted fields in reply packet. */ rpl->r_rrpl.rmp_type = RMP_READ_REPL; COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset); rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session; oldconn->rmplen = RMPREADSIZE(size); /* set size of packet */ retval &= SendPacket(oldconn); /* send packet */ if (madeconn) /* clean up after ourself */ FreeConn(oldconn); return (retval); }
/* ** SendBootRepl -- open boot file and respond to boot request. ** ** Parameters: ** req - RMP BOOT packet containing the request. ** rconn - the reply packet to be formatted. ** filelist - list of files available to the requester. ** ** Returns: ** 1 on success, 0 on failure. ** ** Side Effects: ** none. */ int SendBootRepl(struct rmp_packet *req, RMPCONN *rconn, char *filelist[]) { int retval; char *filename, filepath[RMPBOOTDATA+1]; RMPCONN *oldconn; struct rmp_packet *rpl; char *src, *dst1, *dst2; u_int8_t i; /* * If another connection already exists, delete it since we * are obviously starting again. */ if ((oldconn = FindConn(rconn)) != NULL) { syslog(LOG_WARNING, "%s: dropping existing connection", EnetStr(oldconn)); RemoveConn(oldconn); } rpl = &rconn->rmp; /* cache ptr to RMP packet */ /* * Set up assorted fields in reply packet. */ rpl->r_brpl.rmp_type = RMP_BOOT_REPL; COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno); rpl->r_brpl.rmp_session = htons(GenSessID()); rpl->r_brpl.rmp_version = htons(RMP_VERSION); rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize; /* * Copy file name to `filepath' string, and into reply packet. */ src = &req->r_brq.rmp_flnm; dst1 = filepath; dst2 = &rpl->r_brpl.rmp_flnm; for (i = 0; i < req->r_brq.rmp_flnmsize; i++) *dst1++ = *dst2++ = *src++; *dst1 = '\0'; /* * If we are booting HP-UX machines, their secondary loader will * ask for files like "/hp-ux". As a security measure, we do not * allow boot files to lay outside the boot directory (unless they * are purposely link'd out. So, make `filename' become the path- * stripped file name and spoof the client into thinking that it * really got what it wanted. */ filename = (filename = strrchr(filepath,'/'))? ++filename: filepath; /* * Check that this is a valid boot file name. */ for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++) if (STREQN(filename, filelist[i])) goto match; /* * Invalid boot file name, set error and send reply packet. */ rpl->r_brpl.rmp_retcode = RMP_E_NOFILE; retval = 0; goto sendpkt; match: /* * This is a valid boot file. Open the file and save the file * descriptor associated with this connection and set success * indication. If the file couldnt be opened, set error: * "no such file or dir" - RMP_E_NOFILE * "file table overflow" - RMP_E_BUSY * "too many open files" - RMP_E_BUSY * anything else - RMP_E_OPENFILE */ if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) { rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE: (errno == EMFILE || errno == ENFILE)? RMP_E_BUSY: RMP_E_OPENFILE; retval = 0; } else { rpl->r_brpl.rmp_retcode = RMP_E_OKAY; retval = 1; } sendpkt: syslog(LOG_INFO, "%s: request to boot %s (%s)", EnetStr(rconn), filename, retval? "granted": "denied"); rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize); return (retval & SendPacket(rconn)); }