/[cvs]/eggdrop1.9/src/telnet.c
ViewVC logotype

Contents of /eggdrop1.9/src/telnet.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Mon Feb 3 01:01:07 2003 UTC (16 years, 5 months ago) by stdarg
Branch: MAIN
Changes since 1.1: +14 -7 lines
File MIME type: text/x-chdr
* Let me know if there are any missing files!

1 #include <eggdrop/eggdrop.h>
2
3 /* Possible states of the connection. */
4 #define STATE_RESOLVE 0
5 #define STATE_NICKNAME 1
6 #define STATE_PASSWORD 2
7 #define STATE_PARTYLINE 3
8
9 /* Telnet strings for controlling echo behavior. */
10 #define TELNET_ECHO 1
11 #define TELNET_AYT 246
12 #define TELNET_WILL 251
13 #define TELNET_WONT 252
14 #define TELNET_DO 253
15 #define TELNET_DONT 254
16 #define TELNET_CMD 255
17
18 #define TELNET_ECHO_OFF "\377\373\001"
19 #define TELNET_ECHO_ON "\377\374\001"
20
21 #define TFLAG_ECHO 1
22
23 /* Flags for sessions. */
24 #define STEALTH_LOGIN 1
25
26 typedef struct {
27 char *host;
28 int port;
29 int stealth_logins;
30 int max_retries;
31 } telnet_config_t;
32
33 typedef struct {
34 /* Who we're connected to. */
35 user_t *user;
36 char *nick, *ident, *host, *ip;
37 int port;
38 int idx;
39 int pid;
40
41 /* Flags for this connection. */
42 int flags;
43
44 /* Connection state we're in. */
45 int state, count;
46 } telnet_session_t;
47
48 static telnet_config_t telnet_config = {
49 NULL, /* vhost */
50 3141, /* port */
51 0, /* stealth logins */
52 3 /* max retries */
53 };
54
55 static int telnet_idx = -1;
56 static int telnet_port = 0;
57
58 static void kill_session(telnet_session_t *session);
59
60 static int telnet_on_newclient(void *client_data, int idx, int newidx, const char *peer_ip, int peer_port);
61 static int telnet_on_read(void *client_data, int idx, char *data, int len);
62 static int telnet_on_eof(void *client_data, int idx, int err, const char *errmsg);
63 static int telnet_filter_read(void *client_data, int idx, char *data, int len);
64 static int telnet_filter_write(void *client_data, int idx, const char *data, int len);
65 static int telnet_filter_delete(void *client_data, int idx);
66
67 static int ident_result(void *client_data, const char *ip, int port, const char *reply);
68 static int dns_result(void *client_data, const char *ip, const char *host);
69 static int process_results(telnet_session_t *session);
70
71 static sockbuf_handler_t server_handler = {
72 "telnet server",
73 NULL, NULL, telnet_on_newclient,
74 NULL, NULL
75 };
76
77 #define TELNET_FILTER_LEVEL SOCKBUF_LEVEL_TEXT_ALTERATION
78
79 static sockbuf_filter_t telnet_filter = {
80 "telnet filter", TELNET_FILTER_LEVEL,
81 NULL, NULL, NULL,
82 telnet_filter_read, telnet_filter_write, NULL,
83 NULL, telnet_filter_delete
84 };
85
86 static sockbuf_handler_t client_handler = {
87 "telnet",
88 NULL, telnet_on_eof, NULL,
89 telnet_on_read, NULL
90 };
91
92 int telnet_init()
93 {
94 /* Open our listening socket. */
95 telnet_idx = egg_server(telnet_config.host, telnet_config.port, &telnet_port);
96 sockbuf_set_handler(telnet_idx, &server_handler, NULL);
97 return(0);
98 }
99
100 static void kill_session(telnet_session_t *session)
101 {
102 sockbuf_delete(session->idx);
103 if (session->ip) free(session->ip);
104 if (session->host) free(session->host);
105 if (session->ident) free(session->ident);
106 if (session->nick) free(session->nick);
107 free(session);
108 }
109
110 static int telnet_on_newclient(void *client_data, int idx, int newidx, const char *peer_ip, int peer_port)
111 {
112 telnet_session_t *session;
113 int *flags;
114
115 session = calloc(1, sizeof(*session));
116 session->ip = strdup(peer_ip);
117 session->port = peer_port;
118 session->idx = newidx;
119
120 sockbuf_set_handler(newidx, &client_handler, session);
121 flags = calloc(1, sizeof(*flags));
122 sockbuf_attach_filter(newidx, &telnet_filter, flags);
123 linemode_on(newidx);
124
125 /* Stealth logins are where we don't say anything until we know they
126 * are a valid user. */
127 if (telnet_config.stealth_logins) {
128 session->state = STATE_RESOLVE;
129 }
130 else {
131 sockbuf_write(newidx, "\r\nPlease enter your nickname.\r\n", -1);
132 session->state = STATE_NICKNAME;
133 session->count = 0;
134 }
135
136 /* Start lookups. */
137 egg_ident_lookup(peer_ip, peer_port, telnet_config.port, -1, ident_result, session);
138 egg_dns_reverse(peer_ip, -1, dns_result, session);
139
140 return(0);
141 }
142
143 static int ident_result(void *client_data, const char *ip, int port, const char *reply)
144 {
145 telnet_session_t *session = client_data;
146
147 if (reply) session->ident = strdup(reply);
148 else session->ident = strdup("~telnet");
149 process_results(session);
150 return(0);
151 }
152
153 static int dns_result(void *client_data, const char *ip, const char *host)
154 {
155 telnet_session_t *session = client_data;
156
157 session->host = strdup(host);
158 process_results(session);
159 return(0);
160 }
161
162 static int process_results(telnet_session_t *session)
163 {
164 char *fakehost;
165
166 if (!session->ident || !session->host) return(0);
167
168 if (session->state == STATE_PARTYLINE) {
169 partyline_update_info(session->pid, session->ident, session->host);
170 return(0);
171 }
172 if (session->flags & STEALTH_LOGIN) {
173 fakehost = msprintf("-telnet!%s@%s", session->ident, session->host);
174 if (!user_lookup_by_irchost(fakehost)) {
175 kill_session(session);
176 return(0);
177 }
178 sockbuf_write(session->idx, "\r\nPlease enter your nickname.\r\n", -1);
179 session->state = STATE_NICKNAME;
180 }
181 return(0);
182 }
183
184 static int telnet_on_read(void *client_data, int idx, char *data, int len)
185 {
186 telnet_session_t *session = client_data;
187
188 switch (session->state) {
189 case STATE_PARTYLINE:
190 partyline_on_input(session->pid, data, len);
191 break;
192 case STATE_NICKNAME:
193 session->nick = strdup(data);
194 session->state = STATE_PASSWORD;
195 sockbuf_write(session->idx, TELNET_ECHO_OFF, -1);
196 sockbuf_write(session->idx, "Please enter your password.\r\n", -1);
197 break;
198 case STATE_PASSWORD:
199 sockbuf_write(session->idx, TELNET_ECHO_ON, -1);
200 session->user = user_lookup_authed(session->nick, data);
201 if (!session->user) {
202 sockbuf_write(session->idx, "Invalid username/password.\r\n\r\n", -1);
203 session->count++;
204 if (session->count > telnet_config.max_retries) {
205 kill_session(session);
206 break;
207 }
208 free(session->nick);
209 session->nick = NULL;
210 sockbuf_write(session->idx, "Please enter your nickname.\r\n", -1);
211 session->state = STATE_NICKNAME;
212 }
213 else {
214 session->pid = partyline_connect(session->idx, -1, session->user, session->nick, session->ident ? session->ident : "~telnet", session->host ? session->host : session->ip);
215 session->state = STATE_PARTYLINE;
216 egg_iprintf(idx, "\r\nWelcome to the telnet partyline interface!\r\n");
217 if (session->ident) egg_iprintf(idx, "Your ident is: %s\r\n", session->ident);
218 if (session->host) egg_iprintf(idx, "Your hostname is: %s\r\n", session->host);
219 }
220 break;
221 }
222 return(0);
223 }
224
225 static int telnet_on_eof(void *client_data, int idx, int err, const char *errmsg)
226 {
227 telnet_session_t *session = client_data;
228
229 if (session->state == STATE_PARTYLINE) partyline_disconnect(session->pid, err ? errmsg : NULL);
230 kill_session(session);
231 return(0);
232 }
233
234 static int telnet_filter_read(void *client_data, int idx, char *data, int len)
235 {
236 char *cmd;
237 int type, arg, remove, flags;
238
239 flags = *(int *)client_data;
240 cmd = data;
241 while ((cmd = memchr(cmd, TELNET_CMD, len))) {
242 type = *(unsigned char *)(cmd+1);
243 if (type == TELNET_CMD) remove = 1;
244 else if (type == TELNET_DO) {
245 arg = *(cmd+2);
246 if (arg == TELNET_ECHO) flags |= TFLAG_ECHO;
247 remove = 3;
248 }
249 else if (type == TELNET_DONT) {
250 arg = *(cmd+2);
251 if (arg == TELNET_ECHO) flags &= ~TFLAG_ECHO;
252 remove = 3;
253 }
254 else if (type == TELNET_WILL || type == TELNET_WONT) {
255 remove = 3;
256 }
257 else {
258 remove = 2;
259 }
260 memmove(cmd, cmd+remove, len - (cmd - data) - remove + 1);
261 len -= remove;
262 }
263 if (len) {
264 if (flags & TFLAG_ECHO) sockbuf_on_write(idx, TELNET_FILTER_LEVEL, data, len);
265 sockbuf_on_read(idx, TELNET_FILTER_LEVEL, data, len);
266 }
267 return(0);
268 }
269
270 /* We replace \n with \r\n and \255 with \255\255. */
271 static int telnet_filter_write(void *client_data, int idx, const char *data, int len)
272 {
273 const char *newline;
274 int left, linelen, r, r2;
275
276 newline = data;
277 r = 0;
278 left = len;
279 while ((newline = memchr(newline, '\n', left))) {
280 linelen = newline - data;
281 if (linelen > 0 && newline[-1] == '\r') {
282 newline++;
283 left = len - linelen - 1;
284 continue;
285 }
286
287 r2 = sockbuf_on_write(idx, TELNET_FILTER_LEVEL, data, linelen);
288 if (r2 < 0) return(r2);
289 r += r2;
290 r2 = sockbuf_on_write(idx, TELNET_FILTER_LEVEL, "\r\n", 2);
291 if (r2 < 0) return(r2);
292 r += r2;
293 data = newline+1;
294 newline = data;
295 len -= linelen+1;
296 left = len;
297 }
298 if (len > 0) {
299 r2 = sockbuf_on_write(idx, TELNET_FILTER_LEVEL, data, len);
300 if (r2 < 0) return(r2);
301 r += r2;
302 }
303 return(r);
304 }
305
306 static int telnet_filter_delete(void *client_data, int idx)
307 {
308 free(client_data);
309 return(0);
310 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23