/[cvs]/eggdrop1.9/modules/oldbotnet/oldbotnet.c
ViewVC logotype

Contents of /eggdrop1.9/modules/oldbotnet/oldbotnet.c

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


Revision 1.25 - (show annotations) (download) (as text)
Tue Nov 6 00:05:40 2007 UTC (11 years, 7 months ago) by sven
Branch: MAIN
CVS Tags: HEAD
Changes since 1.24: +17 -1 lines
File MIME type: text/x-chdr
 * Added a new socketfilter that provides a per socket timer for easy
   implementation of various timeouts.
 * All sockets that expect user logins now have a 60 second timeout for
   the user to supply a valid login.
 * All botnet sockets now have a 30 second timeout for the bot to do a
   successful login. After that it has a 90 second timeout after which
   a ping will be sent. After another 90 seconds the socket is closed.

1 /* oldbotnet.c: support for linking with pre-1.9 bots
2 *
3 * Copyright (C) 2003, 2004 Eggheads Development Team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #ifndef lint
21 static const char rcsid[] = "$Id: oldbotnet.c,v 1.24 2007-09-13 22:20:56 sven Exp $";
22 #endif
23
24 #include <eggdrop/eggdrop.h>
25
26 #include "oldbotnet.h"
27
28 EXPORT_SCOPE int oldbotnet_LTX_start(egg_module_t *modinfo);
29 static int oldbotnet_close(int why);
30 static int do_link(user_t *u, const char *text);
31 static int bot_on_delete(event_owner_t *owner, void *client_data);
32 static int anonymous_on_delete(event_owner_t *owner, void *client_data);
33 //static int sock_on_delete(event_owner_t *owner, void *client_data);
34
35 /* Partyline commands. */
36 static int party_plus_obot(partymember_t *p, char *nick, user_t *u, char *cmd, char *text);
37 static int party_minus_obot(partymember_t *p, char *nick, user_t *u, char *cmd, char *text);
38
39 /* Oldbotnet commands. */
40 static int got_actchan(botnet_bot_t *bot, const char *cmd, const char *next);
41 static int got_away(botnet_bot_t *bot, const char *cmd, const char *next);
42 static int got_bcast(botnet_bot_t *bot, const char *cmd, const char *next);
43 static int got_botmsg(botnet_bot_t *bot, const char *cmd, const char *next);
44 static int got_botbroadcast(botnet_bot_t *bot, const char *cmd, const char *next);
45 static int got_bye(botnet_bot_t *bot, const char *cmd, const char *text);
46 static int got_chat(botnet_bot_t *bot, const char *cmd, const char *next);
47 static int got_endlink(botnet_bot_t *bot, const char *cmd, const char *next);
48 static int got_handshake(botnet_bot_t *bot, const char *cmd, const char *next);
49 static int got_idle(botnet_bot_t *bot, const char *cmd, const char *next);
50 static int got_join(botnet_bot_t *bot, const char *cmd, const char *next);
51 static int got_motd(botnet_bot_t *bot, const char *cmd, const char *next);
52 static int got_nickchange(botnet_bot_t *bot, const char *cmd, const char *next);
53 static int got_part(botnet_bot_t *bot, const char *cmd, const char *next);
54 static int got_ping(botnet_bot_t *bot, const char *cmd, const char *next);
55 static int got_pong(botnet_bot_t *bot, const char *cmd, const char *next);
56 static int got_link(botnet_bot_t *bot, const char *cmd, const char *next);
57 static int got_nlinked(botnet_bot_t *bot, const char *cmd, const char *next);
58 static int got_unlink(botnet_bot_t *bot, const char *cmd, const char *next);
59 static int got_unlinked(botnet_bot_t *bot, const char *cmd, const char *next);
60 static int got_versions(botnet_bot_t *bot, const char *cmd, const char *next);
61 static int got_thisbot(botnet_bot_t *bot, const char *cmd, const char *next);
62 static int got_privmsg(botnet_bot_t *bot, const char *cmd, const char *next);
63 static int got_who(botnet_bot_t *bot, const char *cmd, const char *next);
64
65 /* Sockbuf handler. */
66 static int oldbotnet_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port);
67 static int oldbotnet_on_read(void *client_data, int idx, char *data, int len);
68 static int oldbotnet_on_eof(void *client_data, int idx, int err, const char *errmsg);
69 static int oldbotnet_on_delete(event_owner_t *owner, void *client_data);
70
71 static event_owner_t bot_owner = {
72 "oldbotnet", NULL,
73 NULL, NULL,
74 bot_on_delete
75 };
76
77 static event_owner_t anonymous_owner = {
78 "oldbotnet", NULL,
79 NULL, NULL,
80 anonymous_on_delete
81 };
82
83 static event_owner_t generic_owner = {
84 "oldbotnet", NULL,
85 NULL, NULL,
86 NULL
87 };
88
89 static event_owner_t sock_owner = {
90 "oldbotnet", NULL,
91 NULL, NULL,
92 oldbotnet_on_delete
93 };
94
95 typedef struct assoc {
96 char *name;
97 int id;
98 int dynamic;
99 time_t last_bounced;
100 struct assoc *next;
101 } assoc_t;
102
103 static assoc_t assocs = {
104 "*",
105 0,
106 0,
107 0,
108 NULL
109 };
110
111 static bind_list_t party_binds[] = {
112 {"n", "+obot", party_plus_obot},
113 {"n", "-obot", party_minus_obot},
114 {0}
115 };
116
117 static bind_list_t obot_binds[] = {
118 {NULL, "a", got_actchan},
119 {NULL, "actchan", got_actchan},
120
121 {NULL, "aw", got_away},
122 {NULL, "away", got_away},
123 {NULL, "unaway", got_away},
124
125 {NULL, "bye", got_bye},
126
127 {NULL, "c", got_chat},
128 {NULL, "chan", got_chat},
129
130 {NULL, "ct", got_bcast},
131 {NULL, "chat", got_bcast},
132
133 {NULL, "el", got_endlink},
134
135 {NULL, "h", got_handshake},
136 {NULL, "handshake", got_handshake},
137
138 {NULL, "i", got_idle},
139 {NULL, "idle", got_idle},
140
141 {NULL, "j", got_join},
142 {NULL, "join", got_join},
143
144 {NULL, "l", got_link},
145 {NULL, "link", got_link},
146
147 {NULL, "m", got_motd},
148 {NULL, "motd", got_motd},
149
150 {NULL, "n", got_nlinked},
151 {NULL, "nlinked", got_nlinked},
152
153 {NULL, "nc", got_nickchange},
154
155 {NULL, "p", got_privmsg},
156 {NULL, "priv", got_privmsg},
157
158 {NULL, "pi", got_ping},
159 {NULL, "ping", got_ping},
160
161 {NULL, "po", got_pong},
162 {NULL, "pong", got_pong},
163
164 {NULL, "pt", got_part},
165 {NULL, "part", got_part},
166
167 {NULL, "tb", got_thisbot},
168 {NULL, "thisbot", got_thisbot},
169
170 {NULL, "ul", got_unlink},
171 {NULL, "unlink", got_unlink},
172
173 {NULL, "v", got_versions},
174
175 {NULL, "un", got_unlinked},
176 {NULL, "unlinked", got_unlinked},
177
178 {NULL, "w", got_who},
179 {NULL, "who", got_who},
180
181 {NULL, "z", got_botmsg},
182 {NULL, "zapf", got_botmsg},
183
184 {NULL, "zb", got_botbroadcast},
185 {NULL, "zapf-broad", got_botbroadcast},
186 {0}
187 };
188
189 static sockbuf_handler_t oldbotnet_handler = {
190 "oldbotnet",
191 oldbotnet_on_connect, oldbotnet_on_eof, NULL,
192 oldbotnet_on_read, NULL
193 };
194
195 static bind_table_t *BT_obot = NULL;
196
197 const char *assoc_get_name(int id)
198 {
199 int try = 0;
200 assoc_t *a;
201
202 for (a = &assocs; a; a = a->next) {
203 if (a->id == id) break;
204 }
205 if (a) return a->name;
206
207 a = malloc(sizeof(*a));
208 do {
209 if (!try) {
210 a->name = egg_mprintf("%d", id);
211 } else {
212 free(a->name);
213 a->name = egg_mprintf("%d_%d", id, try + 1);
214 }
215 ++try;
216 } while (partychan_lookup_name(a->name));
217 a->id = id;
218 a->next = assocs.next;
219 a->dynamic = 1;
220 a->last_bounced = 0;
221 assocs.next = a;
222 return a->name;
223 }
224
225 int assoc_get_id(const char *name)
226 {
227 int highest_id = 0;
228 assoc_t *a;
229
230 for (a = &assocs; a; a = a->next) {
231 if (!strcmp(a->name, name)) break;
232 if (a->id > highest_id) highest_id = a->id;
233 }
234 if (a) return a->id;
235
236 a = malloc(sizeof(*a));
237 a->name = strdup(name);
238 a->id = highest_id + 1;
239 a->last_bounced = 0;
240 a->dynamic = 0;
241 a->next = assocs.next;
242 assocs.next = a;
243 return a->id;
244 }
245
246 static int get_entity(botnet_bot_t *bot, botnet_entity_t *src, char *word)
247 {
248 oldbotnet_t *obot = bot->client_data;
249
250 if (!strchr(word, '@')) {
251 botnet_bot_t *b = botnet_lookup(word);
252 if (botnet_check_direction(bot, b)) return -1;
253 set_bot_entity(src, b);
254 return 0;
255 }
256
257 partymember_t *p = partymember_lookup(word, NULL, -1);
258 if (p) {
259 set_user_entity(src, p);
260 return 0;
261 }
262
263 int id = -1;
264 char *nick = word, *ptr = strchr(word, '@');
265 botnet_bot_t *srcbot = botnet_lookup(ptr + 1);
266
267 if (botnet_check_direction(bot, srcbot)) return -1;
268 *ptr = 0;
269 ptr = strchr(word, ':');
270 if (ptr) {
271 *ptr = 0;
272 id = atoi(word);
273 nick = ptr + 1;
274 }
275 if (obot->anonymous) partymember_delete(obot->anonymous, NULL, "Temp user expired");
276 obot->anonymous = p = partymember_new(id, NULL, srcbot, nick, "temp", "user.on.an.old.bot", NULL, obot, &anonymous_owner);
277 if (!p) return 0;
278 set_user_entity(src, p);
279 return 1;
280 }
281
282 /* +obot <obot> <host> <port> [username] [password] */
283 static int party_plus_obot(partymember_t *p, char *nick, user_t *u, char *cmd, char *text)
284 {
285 char *name, *host, *port, *username, *password;
286 user_t *obot;
287
288 egg_get_words(text, NULL, &name, &host, &port, &username, &password, NULL);
289 if (!port) {
290 partymember_printf(p, _("Syntax: +obot <obot> <host> <port> [username] [password]"));
291 goto done;
292 }
293
294 obot = user_new(name);
295 if (!obot) {
296 partymember_printf(p, _("Could not create obot '%s'."), name);
297 goto done;
298 }
299
300 user_set_flags_str(obot, NULL, "+b");
301 user_set_setting(obot, "bot", "type", "old-eggdrop");
302 user_set_setting(obot, "bot", "host", host);
303 user_set_setting(obot, "bot", "port", port);
304 if (username) user_set_setting(obot, "bot", "username", username);
305 if (password) user_set_setting(obot, "bot", "password", password);
306
307 done:
308 if (name) free(name);
309 if (host) free(host);
310 if (port) free(port);
311 if (username) free(username);
312 if (password) free(password);
313 return 0;
314 }
315
316 /* -obot <obot> */
317 static int party_minus_obot(partymember_t *p, char *nick, user_t *u, char *cmd, char *text)
318 {
319 char *host;
320 user_t *obot;
321
322 while (isspace(*text)) text++;
323
324 if (!text || !*text) {
325 partymember_printf(p, "Syntax: -obot <obot>");
326 return(0);
327 }
328
329 obot = user_lookup_by_handle(text);
330 if (!obot) {
331 partymember_printf(p, _("Could not find user '%s'."), text);
332 return(0);
333 }
334
335 user_get_setting(obot, "oldbotnet", "host", &host);
336 if (!host) {
337 partymember_printf(p, _("Error: '%s' is not an obot."), obot->handle);
338 return(0);
339 }
340
341 partymember_printf(p, _("Deleting user '%s'."), obot->handle);
342 user_delete(obot);
343 return(BIND_RET_LOG);
344 }
345
346 static int do_link(user_t *user, const char *type)
347 {
348 char *host = NULL, *portstr = NULL, *un = NULL, *password = NULL;
349 const char *username;
350 int port;
351 oldbotnet_t *data;
352
353 user_get_setting(user, NULL, "bot.host", &host);
354 user_get_setting(user, NULL, "bot.port", &portstr);
355 user_get_setting(user, NULL, "bot.username", &un);
356 user_get_setting(user, NULL, "bot.password", &password);
357 if (un) username = un;
358 else username = botnet_get_name();
359 if (portstr) port = atoi(portstr);
360 if (!host || !portstr || port < 0 || port > 65535) {
361 putlog(LOG_MISC, "*", _("Error linking %s: Invalid telnet address:port stored."), user->handle);
362 return BIND_RET_BREAK;
363 }
364
365 data = malloc(sizeof(*data));
366 data->bot = NULL;
367 data->user = user;
368 data->name = strdup(username);
369 if (password) data->password = strdup(password);
370 else data->password = NULL;
371 data->idx = egg_connect(host, port, -1);
372 data->idle = 0;
373 data->anonymous = NULL;
374
375 sockbuf_set_handler(data->idx, &oldbotnet_handler, data, &sock_owner);
376 linemode_on(data->idx);
377 socktimer_on(data->idx, 30, 0, NULL, NULL, &generic_owner);
378
379 putlog(LOG_MISC, "*", _("Linking to %s (%s %d) on idx %d as %s."), user->handle, host, port, data->idx, data->name);
380 return BIND_RET_BREAK;
381 }
382
383 static void do_ping(int idx, void *client_data)
384 {
385 oldbotnet_t *obot = client_data;
386
387 if (obot->idle == -1) {
388 botnet_delete(obot->bot, _("Ping timeout"));
389 } else if (obot->idle == 0) {
390 obot->idle = 1;
391 } else {
392 obot->idle = -1;
393 egg_iprintf(obot->idx, "pi\n");
394 }
395 }
396
397 /*!
398 * \brief Send a password for login.
399 *
400 * The other bot has sent us a pseudorandom string. We append the plaintext
401 * password to this string and encode the whole thing with MD5. This way the
402 * actual password isn't send over the internet.
403 *
404 * \param bot We're not yet linked, so this is the ::oldbotnet_t struct.
405 * \param next The challenge string the other bot has sent.
406 */
407
408 static void got_passreq(oldbotnet_t *bot, const char *next)
409 {
410 if (!bot->password) {
411 putlog(LOG_MISC, "*", _("oldbotnet error: password on %s needs to be reset."), bot->user->handle);
412 sockbuf_delete(bot->idx);
413 return;
414 }
415
416 if (next && *next == '<') {
417 MD5_CTX md5;
418 unsigned char hash[16];
419 char hex[33];
420
421 MD5_Init(&md5);
422 MD5_Update(&md5, next, strlen(next));
423 MD5_Update(&md5, bot->password, strlen(bot->password));
424 MD5_Final(hash, &md5);
425 MD5_Hex(hash, hex);
426 putlog(LOG_MISC, "*", _("Received challenge from %s... sending response ..."), bot->user->handle);
427 egg_iprintf(bot->idx, "digest %s\n", hex);
428 } else {
429 egg_iprintf(bot->idx, "%s\n", bot->password);
430 }
431 }
432
433 /*!
434 * \brief Handles a "h" or "handshake" event from a linked bot.
435 *
436 * "handshake" means the linked bot set a new link password. Just save it.
437 *
438 * \format \b handshake new_password
439 *
440 * \param bot The bot the text came from.
441 * \param cmd The first word it sent, the command. Always "h" or "handshake".
442 * \param text Just one word: the new password in plain text.
443 */
444
445 static int got_handshake(botnet_bot_t *bot, const char *cmd, const char *text)
446 {
447 if (!text || !*text) return BIND_RET_BREAK;
448 putlog(LOG_MISC, "*", "Saving password '%s'", text);
449 user_set_setting(bot->user, NULL, "botnet.password", text);
450 return BIND_RET_BREAK;
451 }
452
453 /*!
454 * \brief Handle the version command.
455 *
456 * This function handles the version command. Once the other bot has sent it
457 * the linking process is completed. We will send our version command after
458 * we've seen the other bot's version so we'll know what handle length to send.
459 * After that send our botnet and endlink.
460 *
461 * \format version numeric_version hand_len some version string \<network\>
462 *
463 * \param bot The bot it came from.
464 * \param next The version text.
465 *
466 * \todo Send the actual version and network out here.
467 */
468
469 static void got_version(oldbotnet_t *bot, const char *next)
470 {
471 char buf[32];
472 xml_node_t *info;
473 /* Get their version and handlen. */
474 sscanf(next, "%d %d", &bot->version, &bot->handlen);
475
476 /* Send back our version reply with their handlen. */
477 egg_iprintf(bot->idx, "version 1090000 %d eggdrop v1.9 <alrighty.then>\n", bot->handlen);
478 egg_iprintf(bot->idx, "tb %s\n", bot->name);
479
480 if (bot->version % 100) sprintf(buf, "eggdrop%d.%d.%d.%d", bot->version / 1000000, bot->version / 10000 % 100, bot->version / 100 % 100, bot->version % 100);
481 else sprintf(buf, "eggdrop%d.%d.%d", bot->version / 1000000, bot->version / 10000 % 100, bot->version / 100 % 100);
482
483 info = xml_node_new();
484 xml_node_set_str("eggdrop", info, "type", 0, (void *) 0);
485 xml_node_set_int(bot->version, info, "numversion", 0, (void *) 0);
486 xml_node_set_str(buf, info, "version", 0, (void *) 0);
487
488 /* And now we're connected. */
489 bot->linking = 1;
490 bot->bot = botnet_new(bot->user->handle, bot->user, NULL, NULL, info, &bothandler, bot, &bot_owner, 0);
491 if (!bot->bot) {
492 botnet_link_failed(bot->user, "Could not create bot.");
493 bot->user = NULL;
494 sockbuf_delete(bot->idx);
495 xml_node_delete(info);
496 return;
497 }
498 socktimer_on(bot->idx, 90, TIMER_REPEAT, do_ping, bot, &generic_owner);
499 botnet_replay_net(bot->bot);
500 egg_iprintf(bot->idx, "el\n");
501 }
502
503 static int got_actchan(botnet_bot_t *bot, const char *cmd, const char *next)
504 {
505 char *word[2], buf[1024], *action;
506 partymember_t *p;
507 int n, len;
508
509 n = egg_get_word_array(next, &next, word, 2);
510 if (n != 2 || !next) {
511 egg_free_word_array(word, 2);
512 return BIND_RET_BREAK;
513 }
514
515 p = partymember_lookup(word[0], NULL, -1);
516 if (!p || botnet_check_direction(bot, p->bot)) {
517 egg_free_word_array(word, 2);
518 return BIND_RET_BREAK;
519 }
520 botnet_entity_t src = user_entity(p);
521
522 while (isspace(*next)) next++;
523 action = egg_msprintf(buf, sizeof(buf), &len, "\1ACTION %s\1", next);
524 partychan_msg_name(assoc_get_name(b64dec_int(word[1])), &src, action, len);
525 if (action != buf) free(action);
526
527 egg_free_word_array(word, 2);
528 return BIND_RET_BREAK;
529 }
530
531 static int got_bcast(botnet_bot_t *bot, const char *cmd, const char *text)
532 {
533 char *srcname;
534 botnet_bot_t *srcbot;
535
536 if (egg_get_word(text, &text, &srcname)) return BIND_RET_BREAK;
537 while (isspace(*text)) text++;
538
539 srcbot = botnet_lookup(srcname);
540 free(srcname);
541 if (!botnet_check_direction(bot, srcbot)) return BIND_RET_BREAK;
542
543 botnet_entity_t src = bot_entity(srcbot);
544 botnet_broadcast(&src, text, -1);
545
546 return BIND_RET_BREAK;
547 }
548
549 /*!
550 * \brief Handle a ping.
551 *
552 * It's a ping. Send a pong.
553 *
554 * \param bot The bot the ping came from.
555 * \param cmd "ping" or "pi".
556 * \param next Nothing.
557 */
558
559 static int got_ping(botnet_bot_t *bot, const char *cmd, const char *next)
560 {
561 oldbotnet_t *obot = bot->client_data;
562
563 egg_iprintf(obot->idx, "po\n");
564 return BIND_RET_BREAK;
565 }
566
567 static int got_endlink(botnet_bot_t *bot, const char *cmd, const char *next)
568 {
569 oldbotnet_t *obot = bot->client_data;
570
571 obot->linking = 0;
572 botnet_link_success(obot->bot);
573 return BIND_RET_BREAK;
574 }
575
576 static int got_thisbot(botnet_bot_t *bot, const char *cmd, const char *next)
577 {
578 if (strcmp(bot->name, next)) {
579 putlog(LOG_MISC, "*", "Wrong bot--wanted %s, got %s", bot->name, next);
580 botnet_delete(bot, "imposer");
581 }
582 return BIND_RET_BREAK;
583 }
584
585 static int got_motd(botnet_bot_t *bot, const char *cmd, const char *next)
586 {
587 char *word[2];
588 int n;
589 botnet_bot_t *dst;
590 botnet_entity_t src;
591
592 n = egg_get_word_array(next, NULL, word, 2);
593 if (n != 2) {
594 egg_free_word_array(word, 2);
595 return BIND_RET_BREAK;
596 }
597
598 dst = botnet_lookup(word[1]);
599 if (!dst && strcmp(word[1], botnet_get_name())) {
600 egg_free_word_array(word, 2);
601 return BIND_RET_BREAK;
602 }
603
604 n = get_entity(bot, &src, word[0]);
605 if (n < 0 || src.what != ENTITY_PARTYMEMBER || botnet_check_direction(bot, src.user->bot)) {
606 egg_free_word_array(word, 2);
607 return BIND_RET_BREAK;
608 }
609
610 botnet_extension(EXTENSION_ONE, &src, dst, NULL, "motd", "", 0);
611 return BIND_RET_BREAK;
612 }
613
614 static int got_versions(botnet_bot_t *bot, const char *cmd, const char *next)
615 {
616 char *word[3];
617 int n;
618 botnet_bot_t *dst, *srcbot;
619 partymember_t *src;
620
621 n = egg_get_word_array(next, NULL, word, 3);
622 if (n != 3) {
623 egg_free_word_array(word, 3);
624 return BIND_RET_BREAK;
625 }
626
627 srcbot = botnet_lookup(word[0]);
628 dst = botnet_lookup(word[1]);
629 if (!srcbot || botnet_check_direction(bot, srcbot) || (!dst && strcmp(word[1], botnet_get_name()))) {
630 egg_free_word_array(word, 3);
631 return BIND_RET_BREAK;
632 }
633
634 src = partymember_lookup(word[2], srcbot, -1);
635 if (!src) {
636 int id = -1;
637 char *ptr = strchr(word[2], ':');
638 oldbotnet_t *obot = bot->client_data;
639
640 if (ptr) {
641 *ptr = 0;
642 id = atoi(word[2]);
643 ++ptr;
644 } else {
645 ptr = word[2];
646 }
647 if (obot->anonymous) partymember_delete(obot->anonymous, NULL, "Temp user expired");
648 obot->anonymous = src = partymember_new(id, NULL, srcbot, ptr, "temp", "user.on.an.old.bot", NULL, obot, &anonymous_owner);
649 }
650 botnet_entity_t e = user_entity(src);
651
652 botnet_extension(EXTENSION_ONE, &e, dst, NULL, "versions", "", 0);
653 return BIND_RET_BREAK;
654 }
655
656 static int got_nickchange(botnet_bot_t *bot, const char *cmd, const char *next)
657 {
658 char *word[3];
659 int n, id;
660 botnet_bot_t *srcbot;
661 partymember_t *src;
662
663 n = egg_get_word_array(next, NULL, word, 3);
664 if (n != 3) {
665 egg_free_word_array(word, 3);
666 return BIND_RET_BREAK;
667 }
668
669 srcbot = botnet_lookup(word[0]);
670 if (botnet_check_direction(bot, srcbot)) {
671 egg_free_word_array(word, 3);
672 return BIND_RET_BREAK;
673 }
674
675 id = b64dec_int(word[1]);
676 src = partymember_lookup(NULL, srcbot, id);
677 if (!src) {
678 egg_free_word_array(word, 3);
679 return BIND_RET_BREAK;
680 }
681
682 partymember_set_nick(src, word[2]);
683
684 return BIND_RET_BREAK;
685 }
686
687 /*!
688 * \brief A new bot has linked to the botnet somewhere else.
689 *
690 * Triggered every time a new bot joins the net to introduce that bot and all
691 * the bots behind it. There might be an '!' as the first char of the version
692 * string. If that isn't there, don't announce the new bot on the partyline,
693 * it's probably from a net join. Might get spammy otherwise.
694 *
695 * \param bot The bot the msg came from.
696 * \param cmd "nlinked" or "n".
697 * \param next The parameters.
698 *
699 * \format \b nlinked newbot uplink [!]version
700 */
701
702 static int got_nlinked(botnet_bot_t *bot, const char *cmd, const char *next)
703 {
704 char *word[3], buf[32];
705 int n, linking = 1, version;
706 botnet_bot_t *src, *new;
707 xml_node_t *info;
708 oldbotnet_t *obot = bot->client_data;
709
710 n = egg_get_word_array(next, NULL, word, 3);
711 if (n != 3) {
712 egg_free_word_array(word, 3);
713 return BIND_RET_BREAK;
714 }
715
716 src = botnet_lookup(word[1]);
717 if (botnet_check_direction(bot, src)) {
718 egg_free_word_array(word, 3);
719 return BIND_RET_BREAK;
720 }
721
722 new = botnet_lookup(word[0]);
723 if (new) {
724 putlog(LOG_MISC, "*", "Botnet loop detected! %s introduced %s from %s but it exists from %s\n", bot->name, new->name, src->name, new->direction->name);
725 egg_iprintf(obot->idx, "error Loop! (%s exists from %s)\nbye Loop (%s)\n", new->name, new->direction->name, new->name);
726 botnet_delete(bot, "Loop detected!");
727 return BIND_RET_BREAK;
728 }
729
730 if (word[2][0] == '!') {
731 linking = 0;
732 version = b64dec_int(word[2] + 1);
733 } else {
734 version = b64dec_int(word[2]);
735 }
736
737 if (version % 100) sprintf(buf, "eggdrop%d.%d.%d.%d", version / 1000000, version / 10000 % 100, version / 100 % 100, version % 100);
738 else sprintf(buf, "eggdrop%d.%d.%d", version / 1000000, version / 10000 % 100, version / 100 % 100);
739 info = xml_node_new();
740 xml_node_set_str("eggdrop", info, "type", 0, (void *) 0);
741 xml_node_set_int(version, info, "numversion", 0, (void *) 0);
742 xml_node_set_str(buf, info, "version", 0, (void *) 0);
743
744 new = botnet_new(word[0], NULL, src, bot, info, NULL, NULL, &generic_owner, linking);
745 if (!new) {
746 /* Invalid botname ... should probably do some really clever name mangleing here ... */
747 char obuf[512];
748 snprintf(obuf, sizeof(obuf), "Botname incompatiblity: %s linked from %s", word[0], src->name);
749 botnet_delete(bot, obuf);
750 /* or just be lazy and kill the bot -_- */
751 xml_node_delete(info);
752 }
753 return BIND_RET_BREAK;
754 }
755
756 static int got_bye(botnet_bot_t *bot, const char *cmd, const char *text)
757 {
758 botnet_delete(bot, text);
759 return BIND_RET_BREAK;
760 }
761
762 /*!
763 * \brief Handle pong event.
764 *
765 * Actually, don't handle pong event. The fact that a line was received is
766 * enough to reset the bots idle counter and that already happened. So there's
767 * nothing left to do.
768 *
769 * \param bot The bot the msg came from.
770 * \param cmd "pong" or "po".
771 * \param next Nothing.
772 *
773 * \format \b pong
774 */
775
776 static int got_pong(botnet_bot_t *bot, const char *cmd, const char *next)
777 {
778 return BIND_RET_BREAK;
779 }
780
781 /*!
782 * \brief Remote request to unlink a bot
783 *
784 * Someone on another bot wants us or a bot further downstream to unlink from
785 * a bot. In any case, the details are handled by botnet_unlink(), we just
786 * pass it on.
787 *
788 * \param bot The bot the msg came from.
789 * \param cmd "unlink" or "ul".
790 * \param text The parameters.
791 *
792 * \format \b unlink from@@bot dst bot-to-kill [reason]
793 */
794
795 static int got_unlink(botnet_bot_t *bot, const char *cmd, const char *text)
796 {
797 int n;
798 char *word[3];
799 const char *reason;
800 botnet_bot_t *target;
801 botnet_entity_t src;
802
803 n = egg_get_word_array(text, &text, word, 3);
804 if (n != 3) {
805 egg_free_word_array(word, 3);
806 return BIND_RET_BREAK;
807 }
808 while (isspace(*text)) text++;
809 if (text && *text) reason = text;
810 else reason = "No reason.";
811
812 target = botnet_lookup(word[2]);
813
814 if (!target) {
815 egg_free_word_array(word, 3);
816 return BIND_RET_BREAK;
817 }
818
819 n = get_entity(bot, &src, word[0]);
820 if (n < 0) {
821 egg_free_word_array(word, 3);
822 return BIND_RET_BREAK;
823 }
824
825 botnet_unlink(&src, target, reason);
826 return BIND_RET_BREAK;
827 }
828
829 static int got_away(botnet_bot_t *bot, const char *cmd, const char *next)
830 {
831 char *word[2];
832 int n, linking = 0;
833 botnet_bot_t *src;
834 partymember_t *p;
835
836 n = egg_get_word_array(next, &next, word, 2);
837 if (n != 2) {
838 egg_free_word_array(word, 2);
839 return BIND_RET_BREAK;
840 }
841
842 if (word[0][0] == '!') {
843 linking = 1;
844 src = botnet_lookup(word[0] + 1);
845 } else {
846 src = botnet_lookup(word[0]);
847 }
848 if (botnet_check_direction(bot, src)) {
849 egg_free_word_array(word, 2);
850 return BIND_RET_BREAK;
851 }
852
853 p = partymember_lookup(NULL, src, b64dec_int(word[1]));
854 if (!p) {
855 egg_free_word_array(word, 2);
856 return BIND_RET_BREAK;
857 }
858
859 while (isspace(*next)) ++next;
860
861 botnet_entity_t s = user_entity(p);
862 botnet_extension(EXTENSION_ALL, &s, NULL, NULL, "away", next, -1);
863
864 return BIND_RET_BREAK;
865 }
866
867 static int got_unlinked(botnet_bot_t *bot, const char *cmd, const char *text)
868 {
869 char *lostname;
870 botnet_bot_t *lost;
871
872 if (egg_get_word(text, &text, &lostname)) return BIND_RET_BREAK;
873
874 lost = botnet_lookup(lostname);
875 free(lostname);
876 if (botnet_check_direction(bot, lost)) return BIND_RET_BREAK;
877
878 while (isspace(*text)) ++text;
879 botnet_delete(lost, text);
880 return BIND_RET_BREAK;
881 }
882
883 static int got_idle(botnet_bot_t *bot, const char *cmd, const char *next)
884 {
885 /*! We don't care.
886 * \todo Care! */
887 return BIND_RET_BREAK;
888 }
889
890 static int got_join(botnet_bot_t *bot, const char *cmd, const char *next)
891 {
892 char *word[5];
893 partymember_t *p;
894 char *ident, *sep, *host, *from;
895 botnet_bot_t *frombot;
896 oldbotnet_t *obot = bot->client_data;
897 int n, id, linking = obot->linking;
898
899 n = egg_get_word_array(next, NULL, word, 5);
900 if (n != 5) {
901 egg_free_word_array(word, 5);
902 return BIND_RET_BREAK;
903 }
904
905 from = word[0];
906 if (*from == '!') {
907 from++;
908 linking = 1;
909 }
910 frombot = botnet_lookup(from);
911
912 if (botnet_check_direction(bot, frombot)) {
913 egg_free_word_array(word, 5);
914 return BIND_RET_BREAK;
915 }
916
917 id = b64dec_int(word[3] + 1);
918
919 p = partymember_lookup(NULL, frombot, id);
920 if (p) {
921 if (p == obot->anonymous) {
922 partymember_delete(p, NULL, "Temp user expired");
923 p = NULL;
924 } else if (strcmp(p->nick, word[1])) {
925 partymember_delete(p, NULL, "Botnet desync");
926 p = NULL;
927 }
928 }
929
930 if (p) {
931 /* We already know about him. */
932 partychan_t *chan;
933 chan = partychan_get_default(p);
934 partychan_part(chan, p, "joining another channel");
935 }
936 else {
937 /* Nope, he's new. */
938 ident = word[4];
939 sep = strchr(ident,'@');
940 if (sep) {
941 *sep = 0;
942 host = sep+1;
943 }
944 else host = word[0];
945
946 p = partymember_new(id, NULL, frombot, word[1], ident, host, NULL, NULL, &generic_owner);
947 }
948 partychan_join_name(assoc_get_name(b64dec_int(word[2])), p, linking);
949 egg_free_word_array(word, 5);
950 return BIND_RET_BREAK;
951 }
952
953 static int got_part(botnet_bot_t *bot, const char *cmd, const char *next)
954 {
955 int id, n;
956 char *word[3];
957 const char *reason;
958 botnet_bot_t *src;
959 partymember_t *p;
960
961 n = egg_get_word_array(next, &next, word, 3);
962 if (n != 3) {
963 egg_free_word_array(word, 3);
964 return BIND_RET_BREAK;
965 }
966 while (isspace(*next)) next++;
967 if (next && *next) reason = next;
968 else reason = "No reason.";
969
970 src = botnet_lookup(word[0]);
971 id = b64dec_int(word[2]);
972 if (botnet_check_direction(bot, src)) {
973 egg_free_word_array(word, 3);
974 return BIND_RET_BREAK;
975 }
976
977 p = partymember_lookup(word[1], src, id);
978 if (p) partymember_delete(p, NULL, reason);
979 egg_free_word_array(word, 3);
980 return BIND_RET_BREAK;
981 }
982
983 /*!
984 * \brief Private message for someone.
985 *
986 * A partymember or a bot have a private message for someone, local or remote.
987 * In any case, the details are handled by insert_here(), we just pass it on.
988 *
989 * \param bot The bot the msg came from.
990 * \param cmd "priv" or "p".
991 * \param next The parameters.
992 *
993 * \format \b priv from@@bot dst message
994 */
995
996 static int got_privmsg(botnet_bot_t *bot, const char *cmd, const char *next)
997 {
998 int n;
999 char *word[2];
1000 const char *original = next;
1001 botnet_entity_t src;
1002 partymember_t *dst;
1003
1004 n = egg_get_word_array(next, &next, word, 2);
1005 if (n != 2) {
1006 egg_free_word_array(word, 2);
1007 return BIND_RET_BREAK;
1008 }
1009 while (isspace(*next)) next++;
1010 if (!next || !*next) {
1011 egg_free_word_array(word, 2);
1012 return BIND_RET_BREAK;
1013 }
1014
1015 n = get_entity(bot, &src, word[0]);
1016 if (n < 0) {
1017 egg_free_word_array(word, 2);
1018 return BIND_RET_BREAK;
1019 }
1020
1021 dst = partymember_lookup(word[1], NULL, -1);
1022
1023 if (!dst) {
1024 char *p = strchr(word[1], '@');
1025 if (p) {
1026 botnet_bot_t *dstbot = botnet_lookup(p + 1);
1027 if (dstbot || !strcmp(p + 1, botnet_get_name())) {
1028 botnet_extension(EXTENSION_ONE, &src, dstbot, NULL, "note", strchr(original, ' ') + 1, -1);
1029 }
1030 }
1031 egg_free_word_array(word, 2);
1032 return BIND_RET_BREAK;
1033 }
1034
1035 partymember_msg(dst, &src, next, -1);
1036 return BIND_RET_BREAK;
1037 }
1038
1039 static int got_chat(botnet_bot_t *bot, const char *cmd, const char *next)
1040 {
1041 char *word[2];
1042 int n;
1043 botnet_entity_t src;
1044
1045 n = egg_get_word_array(next, &next, word, 2);
1046 if (n != 2 || !next) {
1047 egg_free_word_array(word, 2);
1048 return BIND_RET_BREAK;
1049 }
1050
1051 if (strchr(word[0], '@')) {
1052 partymember_t *p = partymember_lookup(word[0], NULL, -1);
1053 if (!p || botnet_check_direction(bot, p->bot)) {
1054 egg_free_word_array(word, 2);
1055 return BIND_RET_BREAK;
1056 }
1057 set_user_entity(&src, p);
1058 } else {
1059 botnet_bot_t *b = botnet_lookup(word[0]);
1060 if (!b || !botnet_check_direction(bot, b)) {
1061 egg_free_word_array(word, 2);
1062 return BIND_RET_BREAK;
1063 }
1064 set_bot_entity(&src, b);
1065 }
1066
1067 while (isspace(*next)) next++;
1068 partychan_msg_name(assoc_get_name(b64dec_int(word[1])), &src, next, strlen(next));
1069
1070 egg_free_word_array(word, 2);
1071 return BIND_RET_BREAK;
1072 }
1073
1074 static void got_assoc(botnet_bot_t *src, const char *text)
1075 {
1076
1077 }
1078
1079 /*!
1080 * \brief Handle a message from a bot for a bot.
1081 *
1082 * This is the old "zapf" message, whatever that may mean. It's called botmsg
1083 * in this version. It's some text from a script on a bot for another script
1084 * on another bot. If there's no script listening for the message on the
1085 * destination bot it'll be ignored.
1086 *
1087 * \param bot The bot the msg came from.
1088 * \param cmd "zapf" or "z".
1089 * \param next The parameters.
1090 *
1091 * \format \b zapf from_bot to_bot command [parameters]
1092 */
1093
1094 static int got_botmsg(botnet_bot_t *bot, const char *cmd, const char *next)
1095 {
1096 int n;
1097 char *word[3];
1098 botnet_bot_t *src, *dst;
1099
1100 n = egg_get_word_array(next, &next, word, 3);
1101 if (n != 3) {
1102 egg_free_word_array(word, 3);
1103 return BIND_RET_BREAK;
1104 }
1105
1106 src = botnet_lookup(word[0]);
1107 if (!src || botnet_check_direction(bot, src)) {
1108 egg_free_word_array(word, 3);
1109 return BIND_RET_BREAK;
1110 }
1111
1112 dst = botnet_lookup(word[1]);
1113 if (!dst && strcmp(word[1], botnet_get_name())) {
1114 egg_free_word_array(word, 3);
1115 return BIND_RET_BREAK;
1116 }
1117
1118 while (isspace(*next)) next++;
1119 if (!dst && !strcmp(word[2], "assoc") && next && *next) got_assoc(src, next);
1120 botnet_botmsg(src, dst, word[2], next, -1);
1121 egg_free_word_array(word, 3);
1122 return BIND_RET_BREAK;
1123 }
1124
1125 static int got_link(botnet_bot_t *bot, const char *cmd, const char *next)
1126 {
1127 int n;
1128 char *word[3];
1129 botnet_bot_t *dst;
1130 botnet_entity_t src;
1131
1132 n = egg_get_word_array(next, &next, word, 3);
1133 if (n != 3) {
1134 egg_free_word_array(word, 3);
1135 return BIND_RET_BREAK;
1136 }
1137
1138 n = get_entity(bot, &src, word[0]);
1139 dst = botnet_lookup(word[1]);
1140 if (n < 0 || botnet_check_direction(bot, src.what == ENTITY_BOT ? src.bot : src.user->bot) || (!dst && strcmp(word[1], botnet_get_name()))) {
1141 egg_free_word_array(word, 3);
1142 return BIND_RET_BREAK;
1143 }
1144
1145 botnet_link(&src, dst, word[2]);
1146
1147 return BIND_RET_BREAK;
1148 }
1149
1150 /*!
1151 * \brief Handle a message from a bot to the entire net.
1152 *
1153 * This is the old "zapf-broad" message, whatever that may mean. It's called
1154 * botbroadcast in this version. It's some text from a script on a bot for
1155 * another script all other bots. If there's no script listening for the
1156 * message on any given bot it'll be ignored (but still passed on).
1157 *
1158 * \param bot The bot the msg came from.
1159 * \param cmd "zapf" or "z".
1160 * \param next The parameters.
1161 *
1162 * \format \b zapf from_bot command [parameters]
1163 */
1164
1165 static int got_botbroadcast(botnet_bot_t *bot, const char *cmd, const char *next)
1166 {
1167 int n;
1168 char *word[2];
1169 botnet_bot_t *src;
1170
1171 n = egg_get_word_array(next, &next, word, 2);
1172 if (n != 2) {
1173 egg_free_word_array(word, 2);
1174 return BIND_RET_BREAK;
1175 }
1176
1177 src = botnet_lookup(word[0]);
1178 if (botnet_check_direction(bot, src)) {
1179 egg_free_word_array(word, 2);
1180 return BIND_RET_BREAK;
1181 }
1182
1183 while (isspace(*next)) next++;
1184 botnet_botbroadcast(src, word[1], next, -1);
1185 egg_free_word_array(word, 2);
1186 return BIND_RET_BREAK;
1187 }
1188
1189 static int got_who(botnet_bot_t *bot, const char *cmd, const char *next)
1190 {
1191 int n;
1192 char *word[2];
1193 botnet_entity_t src;
1194 botnet_bot_t *dst;
1195
1196 n = egg_get_word_array(next, &next, word, 2);
1197 if (n != 2) {
1198 egg_free_word_array(word, 2);
1199 return BIND_RET_BREAK;
1200 }
1201
1202 dst = botnet_lookup(word[1]);
1203 if (!dst && strcmp(word[1], botnet_get_name())) {
1204 egg_free_word_array(word, 2);
1205 return BIND_RET_BREAK;
1206 }
1207
1208 n = get_entity(bot, &src, word[0]);
1209 if (n < 0 || src.what == ENTITY_BOT || botnet_check_direction(bot, src.user->bot)) {
1210 egg_free_word_array(word, 2);
1211 return BIND_RET_BREAK;
1212 }
1213
1214 while (isspace(*next)) next++;
1215 botnet_extension(EXTENSION_ONE, &src, dst, NULL, "who", next, -1);
1216 egg_free_word_array(word, 2);
1217 return BIND_RET_BREAK;
1218 }
1219
1220 static int oldbotnet_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
1221 {
1222 oldbotnet_t *data = client_data;
1223
1224 egg_iprintf(idx, "%s\n", data->name);
1225
1226 return 0;
1227 }
1228
1229 static int oldbotnet_on_read(void *client_data, int idx, char *data, int len)
1230 {
1231 char *cmd;
1232 const char *next;
1233 oldbotnet_t *bot = client_data;
1234
1235 bot->idle = 0;
1236 egg_get_word(data, &next, &cmd);
1237 if (!cmd) return(0);
1238
1239 if (next) while (isspace(*next)) next++;
1240
1241 if (!strcasecmp(cmd, "e") || !strcasecmp(cmd, "error") || (!bot->bot && !strcasecmp(cmd, "bye"))) {
1242 char buf[512];
1243 snprintf(buf, sizeof(buf), _("Botnet error from %s: %s"), bot->user->handle, next);
1244 if (bot->bot) {
1245 botnet_delete(bot->bot, buf);
1246 } else {
1247 botnet_link_failed(bot->user, buf);
1248 bot->user = NULL;
1249 sockbuf_delete(bot->idx);
1250 }
1251 free(cmd);
1252 return 0;
1253 }
1254
1255 if (!bot->bot) {
1256 if (!strcasecmp(cmd, "passreq")) {
1257 got_passreq(bot, next);
1258 } else if (!strcasecmp(cmd, "badpass")) {
1259 botnet_link_failed(bot->user, _("Botnet error: Password was rejected."));
1260 bot->user = NULL;
1261 sockbuf_delete(bot->idx);
1262 } else if (!strcasecmp(cmd, "version") || !strcasecmp(cmd, "v")) {
1263 got_version(bot, next);
1264 }
1265 free(cmd);
1266 return 0;
1267 }
1268
1269 if (!bind_check(BT_obot, NULL, cmd, bot->bot, cmd, next)) {
1270 putlog(LOG_MISC, "*", "%s said \"%s\" but noone cared :( (parameters: %s)", bot->bot->name, cmd, next);
1271 }
1272
1273 free(cmd);
1274 return(0);
1275 }
1276
1277 static int oldbotnet_on_eof(void *client_data, int idx, int err, const char *errmsg)
1278 {
1279 oldbotnet_t *bot = client_data;
1280
1281 if (!bot->bot) {
1282 if (bot->user->flags & USER_LINKING_BOT) botnet_link_failed(bot->user, errmsg ? errmsg : "no error");
1283 bot->user = NULL; /* Might already be in the process of being reconnected, forget about it. */
1284 sockbuf_delete(idx);
1285 } else {
1286 putlog(LOG_MISC, "*", _("eof from %s (%s)."), bot->bot->name, errmsg ? errmsg : "no error");
1287 botnet_delete(bot->bot, errmsg ? errmsg : "eof");
1288 }
1289 return 0;
1290 }
1291
1292 static int bot_on_delete(event_owner_t *owner, void *client_data)
1293 {
1294 oldbotnet_t *bot = client_data;
1295
1296 bot->bot = NULL;
1297 if (bot->idx >= 0) sockbuf_delete(bot->idx);
1298
1299 return 0;
1300 }
1301
1302 static int anonymous_on_delete(event_owner_t *owner, void *client_data)
1303 {
1304 oldbotnet_t *bot = client_data;
1305
1306 bot->anonymous = NULL;
1307
1308 return 0;
1309 }
1310
1311 static int oldbotnet_on_delete(event_owner_t *owner, void *client_data)
1312 {
1313 oldbotnet_t *bot = client_data;
1314
1315 bot->idx = -1;
1316 if (bot->bot) botnet_delete(bot->bot, _("Socket deleted."));
1317 else if (bot->user && bot->user->flags & USER_LINKING_BOT) botnet_link_failed(bot->user, _("Socket deleted."));
1318
1319 if (bot->name) free(bot->name);
1320 if (bot->password) free(bot->password);
1321 free(bot);
1322
1323 return 0;
1324 }
1325
1326 static int oldbotnet_init()
1327 {
1328 BT_obot = bind_table_add("obot", 3, "Bss", MATCH_MASK, BIND_STACKABLE);
1329 bind_add_list("obot", obot_binds);
1330 bind_add_list("party", party_binds);
1331 bind_add_simple(BTN_BOTNET_REQUEST_LINK, NULL, "old-eggdrop", do_link);
1332 return 0;
1333 }
1334
1335 static int oldbotnet_close(int why)
1336 {
1337 assoc_t *a, *next;
1338
1339 for (a = assocs.next; a; a = next) {
1340 next = a->next;
1341 free(a->name);
1342 free(a);
1343 }
1344 assocs.next = NULL;
1345
1346 bind_table_del(BT_obot);
1347 bind_rem_list("obot", obot_binds);
1348 bind_rem_list("party", party_binds);
1349 bind_rem_simple(BTN_BOTNET_REQUEST_LINK, NULL, "old-eggdrop", do_link);
1350
1351 return 0;
1352 }
1353
1354 int oldbotnet_LTX_start(egg_module_t *modinfo)
1355 {
1356 sock_owner.module = bot_owner.module = anonymous_owner.module = generic_owner.module = modinfo;
1357 modinfo->name = "oldbotnet";
1358 modinfo->author = "eggdev";
1359 modinfo->version = "1.0.0";
1360 modinfo->description = "oldbotnet support for most things excluding shares";
1361 modinfo->close_func = oldbotnet_close;
1362
1363 oldbotnet_init();
1364
1365 return(0);
1366 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23