zeek/src/RSH.cc
Robin Sommer bd2e30f521 Merge remote-tracking branch 'origin/topic/dist-cleanup'
* origin/topic/dist-cleanup:
  Updating INSTALL
  Updating README
  Remove $Id$ tags
  Remove policy.old directory, adresses #511
2011-09-18 16:17:42 -07:00

191 lines
4.1 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#include "config.h"
#include "NetVar.h"
#include "Event.h"
#include "RSH.h"
// FIXME: this code should probably be merged with Rlogin.cc.
Contents_Rsh_Analyzer::Contents_Rsh_Analyzer(Connection* conn, bool orig,
Rsh_Analyzer* arg_analyzer)
: ContentLine_Analyzer(AnalyzerTag::Contents_Rsh, conn, orig)
{
num_bytes_to_scan = 0;
analyzer = arg_analyzer;
if ( orig )
state = save_state = RSH_FIRST_NULL;
else
state = RSH_LINE_MODE;
}
Contents_Rsh_Analyzer::~Contents_Rsh_Analyzer()
{
}
void Contents_Rsh_Analyzer::DoDeliver(int len, const u_char* data)
{
TCP_Analyzer* tcp = static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
assert(tcp);
int endp_state = IsOrig() ? tcp->OrigState() : tcp->RespState();
for ( ; len > 0; --len, ++data )
{
if ( offset >= buf_len )
InitBuffer(buf_len * 2);
unsigned int c = data[0];
switch ( state ) {
case RSH_FIRST_NULL:
if ( endp_state == TCP_ENDPOINT_PARTIAL ||
// We can be in closed if the data's due to
// a dataful FIN being the first thing we see.
endp_state == TCP_ENDPOINT_CLOSED )
{
state = RSH_UNKNOWN;
++len, --data; // put back c and reprocess
continue;
}
if ( c >= '0' && c <= '9' )
; // skip stderr port number
else if ( c == '\0' )
state = RSH_CLIENT_USER_NAME;
else
BadProlog();
break;
case RSH_CLIENT_USER_NAME:
case RSH_SERVER_USER_NAME:
buf[offset++] = c;
if ( c == '\0' )
{
if ( state == RSH_CLIENT_USER_NAME )
{
analyzer->ClientUserName((const char*) buf);
state = RSH_SERVER_USER_NAME;
}
else if ( state == RSH_SERVER_USER_NAME &&
offset > 1 )
{
analyzer->ServerUserName((const char*) buf);
save_state = state;
state = RSH_LINE_MODE;
}
offset = 0;
}
break;
case RSH_LINE_MODE:
case RSH_UNKNOWN:
case RSH_PRESUMED_REJECTED:
if ( state == RSH_LINE_MODE &&
state == RSH_PRESUMED_REJECTED )
{
Conn()->Weird("rsh_text_after_rejected");
state = RSH_UNKNOWN;
}
if ( c == '\n' || c == '\r' )
{ // CR or LF (RFC 1282)
if ( c == '\n' && last_char == '\r' )
// Compress CRLF to just 1 termination.
;
else
{
buf[offset] = '\0';
ForwardStream(offset, buf, IsOrig()); \
save_state = RSH_LINE_MODE;
offset = 0;
break;
}
}
if ( c == '\0' )
{
buf[offset] = '\0';
ForwardStream(offset, buf, IsOrig()); \
save_state = RSH_LINE_MODE;
offset = 0;
break;
}
else
buf[offset++] = c;
last_char = c;
break;
default:
reporter->InternalError("bad state in Contents_Rsh_Analyzer::DoDeliver");
break;
}
}
}
void Contents_Rsh_Analyzer::BadProlog()
{
Conn()->Weird("bad_rsh_prolog");
state = RSH_UNKNOWN;
}
Rsh_Analyzer::Rsh_Analyzer(Connection* conn)
: Login_Analyzer(AnalyzerTag::Rsh, conn)
{
contents_orig = new Contents_Rsh_Analyzer(conn, true, this);
contents_resp = new Contents_Rsh_Analyzer(conn, false, this);
AddSupportAnalyzer(contents_orig);
AddSupportAnalyzer(contents_resp);
}
void Rsh_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
{
Login_Analyzer::DeliverStream(len, data, orig);
const char* line = (const char*) data;
val_list* vl = new val_list;
line = skip_whitespace(line);
vl->append(BuildConnVal());
vl->append(client_name ? client_name->Ref() : new StringVal("<none>"));
vl->append(username ? username->Ref() : new StringVal("<none>"));
vl->append(new StringVal(line));
if ( orig && rsh_request )
{
if ( contents_orig->RshSaveState() == RSH_SERVER_USER_NAME )
// First input
vl->append(new Val(true, TYPE_BOOL));
else
vl->append(new Val(false, TYPE_BOOL));
ConnectionEvent(rsh_request, vl);
}
else if ( rsh_reply )
ConnectionEvent(rsh_reply, vl);
}
void Rsh_Analyzer::ClientUserName(const char* s)
{
if ( client_name )
reporter->InternalError("multiple rsh client names");
client_name = new StringVal(s);
}
void Rsh_Analyzer::ServerUserName(const char* s)
{
if ( username )
reporter->InternalError("multiple rsh initial client names");
username = new StringVal(s);
}