/[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.6 - (show annotations) (download) (as text)
Mon Jun 9 02:21:53 2003 UTC (16 years, 4 months ago) by stdarg
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +0 -0 lines
File MIME type: text/x-chdr
FILE REMOVED
* Cleanups and a bit of multi-channel partyline support

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23