Branch data Line data Source code
1 : : // $Id: Rlogin.cc 6219 2008-10-01 05:39:07Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include "NetVar.h"
8 : : #include "Event.h"
9 : : #include "Rlogin.h"
10 : :
11 : :
12 : 0 : Contents_Rlogin_Analyzer::Contents_Rlogin_Analyzer(Connection* conn, bool orig, Rlogin_Analyzer* arg_analyzer)
13 : 0 : : ContentLine_Analyzer(AnalyzerTag::Contents_Rlogin, conn, orig)
14 : : {
15 : 0 : num_bytes_to_scan = num_bytes_to_scan = 0;
16 : 0 : analyzer = arg_analyzer;
17 : 0 : peer = 0;
18 : :
19 [ # # # # ]: 0 : if ( orig )
20 : 0 : state = save_state = RLOGIN_FIRST_NULL;
21 : : else
22 : 0 : state = save_state = RLOGIN_SERVER_ACK;
23 : 0 : }
24 : :
25 : 0 : Contents_Rlogin_Analyzer::~Contents_Rlogin_Analyzer()
26 : : {
27 [ # # ][ # # ]: 0 : }
[ # # ]
28 : :
29 : 0 : void Contents_Rlogin_Analyzer::DoDeliver(int len, const u_char* data)
30 : : {
31 : 0 : TCP_Analyzer* tcp = static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
32 [ # # ]: 0 : assert(tcp);
33 : :
34 [ # # ]: 0 : int endp_state = IsOrig() ? tcp->OrigState() : tcp->RespState();
35 : :
36 [ # # ]: 0 : for ( ; len > 0; --len, ++data )
37 : : {
38 [ # # ]: 0 : if ( offset >= buf_len )
39 : 0 : InitBuffer(buf_len * 2);
40 : :
41 : 0 : unsigned int c = data[0];
42 : :
43 [ # # # # # : 0 : switch ( state ) {
# # # ]
44 : : case RLOGIN_FIRST_NULL:
45 [ # # ][ # # ]: 0 : if ( endp_state == TCP_ENDPOINT_PARTIAL ||
46 : : // We can be in closed if the data's due to
47 : : // a dataful FIN being the first thing we see.
48 : : endp_state == TCP_ENDPOINT_CLOSED )
49 : : {
50 : 0 : state = RLOGIN_UNKNOWN;
51 : 0 : ++len, --data; // put back c and reprocess
52 : 0 : continue;
53 : : }
54 : :
55 [ # # ]: 0 : if ( c == '\0' )
56 : 0 : state = RLOGIN_CLIENT_USER_NAME;
57 : : else
58 : 0 : BadProlog();
59 : 0 : break;
60 : :
61 : : case RLOGIN_CLIENT_USER_NAME:
62 : : case RLOGIN_SERVER_USER_NAME:
63 : : case RLOGIN_TERMINAL_TYPE:
64 : 0 : buf[offset++] = c;
65 [ # # ]: 0 : if ( c == '\0' )
66 : : {
67 [ # # ]: 0 : if ( state == RLOGIN_CLIENT_USER_NAME )
68 : : {
69 : 0 : analyzer->ClientUserName((const char*) buf);
70 : 0 : state = RLOGIN_SERVER_USER_NAME;
71 : : }
72 : :
73 [ # # ]: 0 : else if ( state == RLOGIN_SERVER_USER_NAME )
74 : : {
75 : 0 : analyzer->ServerUserName((const char*) buf);
76 : 0 : state = RLOGIN_TERMINAL_TYPE;
77 : : }
78 : :
79 [ # # ]: 0 : else if ( state == RLOGIN_TERMINAL_TYPE )
80 : : {
81 : 0 : analyzer->TerminalType((const char*) buf);
82 : 0 : state = RLOGIN_LINE_MODE;
83 : : }
84 : :
85 : 0 : offset = 0;
86 : : }
87 : 0 : break;
88 : :
89 : : case RLOGIN_SERVER_ACK:
90 [ # # ][ # # ]: 0 : if ( endp_state == TCP_ENDPOINT_PARTIAL ||
91 : : // We can be in closed if the data's due to
92 : : // a dataful FIN being the first thing we see.
93 : : endp_state == TCP_ENDPOINT_CLOSED )
94 : : {
95 : 0 : state = RLOGIN_UNKNOWN;
96 : 0 : ++len, --data; // put back c and reprocess
97 : 0 : continue;
98 : : }
99 : :
100 [ # # ]: 0 : if ( c == '\0' )
101 : 0 : state = RLOGIN_LINE_MODE;
102 : : else
103 : 0 : state = RLOGIN_PRESUMED_REJECTED;
104 : 0 : break;
105 : :
106 : : case RLOGIN_IN_BAND_CONTROL_FF2:
107 [ # # ]: 0 : if ( c == 255 )
108 : 0 : state = RLOGIN_WINDOW_CHANGE_S1;
109 : : else
110 : : {
111 : : // Put back the \ff that took us into
112 : : // this state.
113 : 0 : buf[offset++] = 255;
114 : 0 : state = save_state;
115 : 0 : ++len, --data; // put back c and reprocess
116 : 0 : continue;
117 : : }
118 : 0 : break;
119 : :
120 : : case RLOGIN_WINDOW_CHANGE_S1:
121 : : case RLOGIN_WINDOW_CHANGE_S2:
122 [ # # ]: 0 : if ( c == 's' )
123 : : {
124 [ # # ]: 0 : if ( state == RLOGIN_WINDOW_CHANGE_S1 )
125 : 0 : state = RLOGIN_WINDOW_CHANGE_S2;
126 : : else
127 : : {
128 : 0 : state = RLOGIN_WINDOW_CHANGE_REMAINDER;
129 : 0 : num_bytes_to_scan = 8;
130 : : }
131 : : }
132 : : else
133 : : {
134 : : // Unknown control, or we're confused.
135 : : // Put back what we've consumed.
136 : : unsigned char buf[64];
137 : 0 : int n = 0;
138 : 0 : buf[n++] = '\xff';
139 : 0 : buf[n++] = '\xff';
140 : :
141 [ # # ]: 0 : if ( state == RLOGIN_WINDOW_CHANGE_S2 )
142 : 0 : buf[n++] = 's';
143 : :
144 : 0 : state = RLOGIN_UNKNOWN;
145 : :
146 : 0 : DoDeliver(n, buf);
147 : : }
148 : 0 : break;
149 : :
150 : : case RLOGIN_WINDOW_CHANGE_REMAINDER:
151 [ # # ]: 0 : if ( --num_bytes_to_scan == 0 )
152 : 0 : state = save_state;
153 : 0 : break;
154 : :
155 : : case RLOGIN_LINE_MODE:
156 : : case RLOGIN_UNKNOWN:
157 : : case RLOGIN_PRESUMED_REJECTED:
158 [ # # ]: 0 : assert(peer);
159 [ # # ][ # # ]: 0 : if ( state == RLOGIN_LINE_MODE &&
160 : : peer->state == RLOGIN_PRESUMED_REJECTED )
161 : : {
162 : 0 : Conn()->Weird("rlogin_text_after_rejected");
163 : 0 : state = RLOGIN_UNKNOWN;
164 : : }
165 : :
166 [ # # ][ # # ]: 0 : if ( c == '\n' || c == '\r' ) // CR or LF (RFC 1282)
167 : : {
168 [ # # ][ # # ]: 0 : if ( c == '\n' && last_char == '\r' )
169 : : // Compress CRLF to just 1 termination.
170 : : ;
171 : : else
172 : : {
173 : 0 : buf[offset] = '\0';
174 : 0 : ForwardStream(offset, buf, IsOrig()); \
175 : : offset = 0;
176 : 0 : break;
177 : : }
178 : : }
179 : :
180 [ # # ][ # # ]: 0 : else if ( c == 255 && IsOrig() &&
[ # # ][ # # ]
[ # # ]
181 : : state != RLOGIN_PRESUMED_REJECTED &&
182 : : state != RLOGIN_UNKNOWN )
183 : : {
184 : 0 : save_state = state;
185 : 0 : state = RLOGIN_IN_BAND_CONTROL_FF2;
186 : : }
187 : :
188 : : else
189 : 0 : buf[offset++] = c;
190 : :
191 : 0 : last_char = c;
192 : 0 : break;
193 : :
194 : : default:
195 : 0 : internal_error("bad state in Contents_Rlogin_Analyzer::DoDeliver");
196 : : break;
197 : : }
198 : : }
199 : 0 : }
200 : :
201 : 0 : void Contents_Rlogin_Analyzer::BadProlog()
202 : : {
203 : 0 : Conn()->Weird("bad_rlogin_prolog");
204 : 0 : state = RLOGIN_UNKNOWN;
205 : 0 : }
206 : :
207 : :
208 : 0 : Rlogin_Analyzer::Rlogin_Analyzer(Connection* conn)
209 : 0 : : Login_Analyzer(AnalyzerTag::Rlogin, conn)
210 : : {
211 : : Contents_Rlogin_Analyzer* orig =
212 : 0 : new Contents_Rlogin_Analyzer(conn, true, this);
213 : : Contents_Rlogin_Analyzer* resp =
214 : 0 : new Contents_Rlogin_Analyzer(conn, false, this);
215 : :
216 : 0 : orig->SetPeer(resp);
217 : 0 : resp->SetPeer(orig);
218 : :
219 : 0 : AddSupportAnalyzer(orig);
220 : 0 : AddSupportAnalyzer(resp);
221 : 0 : }
222 : :
223 : 0 : void Rlogin_Analyzer::ClientUserName(const char* s)
224 : : {
225 [ # # ]: 0 : if ( client_name )
226 : 0 : internal_error("multiple rlogin client names");
227 : :
228 : 0 : client_name = new StringVal(s);
229 : 0 : }
230 : :
231 : 0 : void Rlogin_Analyzer::ServerUserName(const char* s)
232 : : {
233 : 0 : ++num_user_lines_seen;
234 : 0 : ++login_prompt_line;
235 : 0 : AddUserText(s);
236 : 0 : }
237 : :
238 : 0 : void Rlogin_Analyzer::TerminalType(const char* s)
239 : : {
240 [ # # ]: 0 : if ( login_terminal )
241 : : {
242 : 0 : val_list* vl = new val_list;
243 : :
244 : 0 : vl->append(BuildConnVal());
245 : 0 : vl->append(new StringVal(s));
246 : :
247 : 0 : ConnectionEvent(login_terminal, vl);
248 : : }
249 [ + - ][ + - ]: 6 : }
|