/* * modules.c - support for code modules in eggdrop * by Darrin Smith (beldin@light.iinet.net.au) */ /* This file is part of the eggdrop source code copyright (c) 1997 Robey Pointer and is distributed according to the GNU general public license. For full details, read the top of 'main.c' or the file called COPYING that was distributed with this code. */ #include "main.h" #include "modules.h" #include "tandem.h" #ifndef STATIC #ifdef HPUX_HACKS #include #else #ifdef OSF1_HACKS #include #else #if DLOPEN_1 char *dlerror(); void *dlopen (const char *, int); int dlclose (void *); void * dlsym (void *,char *); #define DLFLAGS 1 #else #include #ifndef RTLD_GLOBAL #define RTLD_GLOBAL 0 #endif #ifndef RTLD_NOW #define RTLD_NOW 1 #endif #ifdef RTLD_LAZY #define DLFLAGS RTLD_LAZY|RTLD_GLOBAL #else #define DLFLAGS RTLD_NOW|RTLD_GLOBAL #endif #endif /* DLOPEN_1 */ #endif /* OSF1_HACKS */ #endif /* HPUX_HACKS */ #endif /* STATIC */ extern struct dcc_t * dcc; #include "users.h" int cmd_note(); /* from other areas */ extern Tcl_Interp *interp; extern struct userrec *userlist, *lastuser; extern char tempdir[], botnetnick[], botname[], natip[], hostname[]; extern char origbotname[], botuser[], admin[], userfile[], ver[], notify_new[]; extern char helpdir[], version[]; extern int reserved_port, noshare, dcc_total, egg_numver, use_silence; extern int use_console_r, ignore_time, debug_output, gban_total, make_userfile; extern int default_flags, require_p, max_dcc, share_greet, password_timeout; extern int min_dcc_port, max_dcc_port; /* dw */ extern int global_flood_ctcp_thr, global_flood_ctcp_time; /* arthur2 */ extern int do_restart; extern time_t now, online_since; extern struct chanset_t * chanset; int cmd_die(), xtra_kill(), xtra_unpack(); static int module_rename (char * name, char * newname); #ifndef STATIC /* directory to look for modules */ char moddir[121] = "modules/"; #else struct static_list { struct static_list * next; char * name; char *(*func)(); } * static_modules = NULL; void check_static(char * name, char *(*func)()) { struct static_list * p = nmalloc(sizeof(struct static_list)); p->name = nmalloc(strlen(name) + 1); strcpy(p->name,name); p->func = func; p->next = static_modules; static_modules = p; } #endif /* the null functions */ void null_func() { } char *charp_func() { return NULL; } int minus_func() { return -1; } /* various hooks & things */ /* the REAL hooks, when these are called, a return of 0 indicates unhandled * 1 is handled */ struct hook_entry *hook_list[REAL_HOOKS]; static void null_share (int idx, char * x) { if ((x[0] == 'u') && (x[1] == 'n')) { putlog(LOG_BOTS, "*", "User file rejected by %s: %s", dcc[idx].nick, x+3); dcc[idx].status &= ~STAT_OFFERED; if (!(dcc[idx].status & STAT_GETTING)) { dcc[idx].status &= ~STAT_SHARE; } } else if ((x[0] != 'v') && (x[0] != 'e')) dprintf(idx, "s un Not sharing userfile.\n"); } /* these are obscure ones that I hope to neaten eventually :/ */ void (*encrypt_pass) (char *, char *) = 0; void (*shareout)() = null_func; void (*sharein)(int,char *) = null_share; void (*qserver)(int,char *,int) = null_func; void (*add_mode)() = null_func; module_entry *module_list; dependancy * dependancy_list = NULL; void mod_context (char * module, char * file, int line) { char x[100]; sprintf(x, "%s:%s", module, file); x[30] = 0; cx_ptr = ((cx_ptr + 1) & 15); strcpy(cx_file[cx_ptr], x); cx_line[cx_ptr] = line; } /* the horrible global lookup table for functions */ /* BUT it makes the whole thing *much* more portable than letting each * OS screw up the symbols their own special way :/ */ Function global_table [] = { /* 0 - 3 */ (Function) mod_malloc, (Function) mod_free, (Function) mod_context, (Function) module_rename, /* 4 - 7 */ (Function) module_register, (Function) module_find, (Function) module_depend, (Function) module_undepend, /* 8 - 11 */ (Function) add_bind_table, (Function) del_bind_table, (Function) find_bind_table, (Function) check_tcl_bind, /* 12 - 15 */ (Function) add_builtins, (Function) rem_builtins, (Function) add_tcl_commands, (Function) rem_tcl_commands, /* 16 - 19 */ (Function) add_tcl_ints, (Function) rem_tcl_ints, (Function) add_tcl_strings, (Function) rem_tcl_strings, /* 20 - 23 */ (Function) base64_to_int, (Function) int_to_base64, (Function) int_to_base10, (Function) simple_sprintf, /* 24 - 27 */ (Function) botnet_send_zapf, (Function) botnet_send_zapf_broad, (Function) botnet_send_unlinked, (Function) botnet_send_bye, /* 28 - 31 */ (Function) botnet_send_chat, (Function) botnet_send_filereject, (Function) botnet_send_filesend, (Function) botnet_send_filereq, /* 32 - 35 */ (Function) botnet_send_join_idx, (Function) botnet_send_part_idx, (Function) updatebot, (Function) nextbot, /* 36 - 39 */ (Function) zapfbot, (Function) n_free, (Function) u_pass_match, (Function) _user_malloc, /* 40 - 43 */ (Function) get_user, (Function) set_user, (Function) add_entry_type, (Function) del_entry_type, /* 44 - 47 */ (Function) get_user_flagrec, (Function) set_user_flagrec, (Function) get_user_by_host, (Function) get_user_by_handle, /* 48 - 51 */ (Function) find_entry_type, (Function) find_user_entry, (Function) adduser, (Function) deluser, /* 52 - 55 */ (Function) addhost_by_handle, (Function) delhost_by_handle, (Function) readuserfile, (Function) write_userfile, /* 56 - 59 */ (Function) geticon, (Function) clear_chanlist, (Function) reaffirm_owners, (Function) change_handle, /* 60 - 63 */ (Function) write_user, (Function) clear_userlist, (Function) count_users, (Function) sanity_check, /* 64 - 67 */ (Function) break_down_flags, (Function) build_flags, (Function) flagrec_eq, (Function) flagrec_ok, /* 68 - 71 */ (Function) &shareout, (Function) dprintf, (Function) chatout, (Function) chanout_but, /* 72 - 75 */ (Function) check_validity, (Function) list_delete, (Function) list_append, (Function) list_contains, /* 76 - 79 */ (Function) answer, (Function) getmyip, (Function) neterror, (Function) tputs, /* 80 - 83 */ (Function) new_dcc, (Function) lostdcc, (Function) getsock, (Function) killsock, /* 84 - 87 */ (Function) open_listen, (Function) open_telnet_dcc, (Function) _get_data_ptr, (Function) open_telnet, /* 88 - 91 */ #ifdef HAVE_BZERO (Function) null_func, #else (Function) bzero, #endif (Function) my_memcpy, (Function) my_atoul, (Function) my_strcpy, /* 92 - 95 */ (Function) &dcc, /* struct dcc_t * */ (Function) &chanset, /* struct chanset_t * */ (Function) &userlist, /* struct userrec * */ (Function) &lastuser, /* struct userrec * */ /* 96 - 99 */ (Function) &global_bans, /* struct banrec * */ (Function) &global_ign, /* struct igrec * */ (Function) &password_timeout,/* int */ (Function) &share_greet, /* int */ /* 100 - 103 */ (Function) &max_dcc, /* int */ (Function) &require_p, /* int */ (Function) &use_silence, /* int */ (Function) &use_console_r, /* int */ /* 104 - 107 */ (Function) &ignore_time, /* int */ (Function) &reserved_port, /* int */ (Function) &debug_output, /* int */ (Function) &noshare, /* int */ /* 108 - 111 */ (Function) &gban_total, /* int */ (Function) &make_userfile, /* int */ (Function) &default_flags, /* int */ (Function) &dcc_total, /* int */ /* 112 - 115 */ (Function) tempdir, /* char * */ (Function) natip, /* char * */ (Function) hostname, /* char * */ (Function) origbotname, /* char * */ /* 116 - 119 */ (Function) botuser, /* char * */ (Function) admin, /* char * */ (Function) userfile, /* char * */ (Function) ver, /* char * */ /* 120 - 123 */ (Function) notify_new, /* char * */ (Function) helpdir, /* char * */ (Function) version, /* char * */ (Function) botnetnick, /* char * */ /* 124 - 127 */ (Function) &DCC_CHAT_PASS, /* struct dcc_table * */ (Function) &DCC_BOT, /* struct dcc_table * */ (Function) &DCC_LOST, /* struct dcc_table * */ (Function) &DCC_CHAT, /* struct dcc_table * */ /* 128 - 131 */ (Function) &interp, /* Tcl_Interp * */ (Function) &now, /* time_t */ (Function) findanyidx, (Function) findchan, /* 132 - 135 */ (Function) cmd_die, (Function) days, (Function) daysago, (Function) daysdur, /* 136 - 139 */ (Function) ismember, (Function) newsplit, (Function) splitnick, (Function) splitc, /* 140 - 143 */ (Function) addignore, (Function) match_ignore, (Function) delignore, (Function) fatal, /* 144 - 147 */ (Function) xtra_kill, (Function) xtra_unpack, (Function) movefile, (Function) copyfile, /* 148 - 151 */ (Function) do_tcl, (Function) readtclprog, (Function) get_language, (Function) def_get, /* 152 - 155 */ (Function) makepass, (Function) _wild_match, (Function) maskhost, (Function) show_motd, /* 156 - 159 */ (Function) tellhelp, (Function) showhelp, (Function) add_help_reference, (Function) rem_help_reference, /* 160 - 163 */ (Function) touch_laston, (Function) &add_mode, (Function) rmspace, (Function) in_chain, /* 164 - 167 */ (Function) add_note, (Function) cmd_note, (Function) detect_dcc_flood, (Function) flush_lines, /* 168 - 171 */ (Function) expected_memory, (Function) tell_mem_status, (Function) &do_restart, (Function) check_tcl_filt, /* 172 - 175 */ (Function) add_hook, (Function) del_hook, (Function) &H_dcc, (Function) &H_filt, /* 176 - 179 */ (Function) &H_chon, (Function) &H_chof, (Function) &H_load, (Function) &H_unld, /* 180 - 183 */ (Function) &H_chat, (Function) &H_act, (Function) &H_bcst, (Function) &H_bot, /* 184 - 187 */ (Function) &H_link, (Function) &H_disc, (Function) &H_away, (Function) &H_nkch, /* 188 - 191 */ (Function) &USERENTRY_BOTADDR, (Function) &USERENTRY_BOTFL, (Function) &USERENTRY_HOSTS, (Function) &USERENTRY_PASS, /* 192 - 195 */ (Function) &USERENTRY_XTRA, (Function) 0, (Function) &USERENTRY_INFO, (Function) &USERENTRY_COMMENT, /* 196 - 199 */ (Function) &USERENTRY_LASTON, (Function) putlog, (Function) botnet_send_chan, (Function) list_type_kill, /* 200 - 203 */ (Function) logmodes, (Function) masktype, (Function) stripmodes, (Function) stripmasktype, /* 204 - 207 */ (Function) sub_lang, (Function) &online_since, (Function) cmd_loadlanguage, (Function) check_dcc_attrs, /* 208 - 211 */ (Function) check_dcc_chanattrs, (Function) add_tcl_coups, (Function) rem_tcl_coups, (Function) botname, /* 212 - 215 */ (Function) remove_gunk, (Function) check_tcl_chjn, (Function) sanitycheck_dcc, (Function) isowner, /* Daemus */ /* 216 - 219 */ (Function) &min_dcc_port, /* dw */ (Function) &max_dcc_port, (Function) &global_flood_ctcp_thr, /* arthur2 */ (Function) &global_flood_ctcp_time, /* arthur2 */ }; void init_modules(void) { int i; context; module_list = nmalloc(sizeof(module_entry)); module_list->name = nmalloc(8); strcpy(module_list->name, "eggdrop"); module_list->major = (egg_numver) / 10000; module_list->minor = ((egg_numver) / 100) % 100; #ifndef STATIC module_list->hand = NULL; #endif module_list->next = NULL; module_list->funcs = NULL; for (i = 0; i < REAL_HOOKS; i++) hook_list[i] = NULL; } int expmem_modules(int y) { int c = 0; int i; module_entry *p = module_list; dependancy *d = dependancy_list; #ifdef STATIC struct static_list * s; #endif Function *f; context; #ifdef STATIC for (s = static_modules;s;s=s->next) c += sizeof(struct static_list) + strlen(s->name) + 1; #endif for (i = 0; i < REAL_HOOKS; i++) { struct hook_entry *q = hook_list[i]; while (q) { c += sizeof(struct hook_entry); q = q->next; } } while (d) { c += sizeof(dependancy); d = d->next; } while (p) { c += sizeof(module_entry); c += strlen(p->name) + 1; f = p->funcs; if (f && f[MODCALL_EXPMEM] && !y) c += (int) (f[MODCALL_EXPMEM] ()); p = p->next; } return c; } int module_register (char * name, Function * funcs, int major, int minor) { module_entry *p = module_list; context; while (p) { if (p->name && !strcasecmp(name, p->name)) { p->major = major; p->minor = minor; p->funcs = funcs; return 1; } p = p->next; } return 0; } const char *module_load (char * name) { module_entry *p; char *e; Function f; #ifndef STATIC char workbuf[1024]; #ifdef HPUX_HACKS shl_t hand; #else #ifdef OSF1_HACKS ldr_module_t hand; #else void *hand; #endif #endif #else struct static_list * sl; #endif context; if (module_find(name, 0, 0) != NULL) return MOD_ALREADYLOAD; #ifndef STATIC if (moddir[0] != '/') { if (getcwd(workbuf, 1024) == NULL) return MOD_BADCWD; sprintf(&(workbuf[strlen(workbuf)]), "/%s%s.so", moddir, name); } else sprintf(workbuf,"%s%s.so",moddir,name); #ifdef HPUX_HACKS hand = shl_load(workbuf, BIND_IMMEDIATE, 0L); if (!hand) return "Can't load module."; #else #ifdef OSF1_HACKS hand = (Tcl_PackageInitProc *) load (workbuf, LDR_NOFLAGS); if (hand == LDR_NULL_MODULE) return "Can't load module."; #else hand = dlopen(workbuf, DLFLAGS); if (!hand) return dlerror(); #endif #endif sprintf(workbuf, "%s_start", name); #ifdef HPUX_HACKS if (shl_findsym(&hand, workbuf, (short) TYPE_PROCEDURE, (void *)&f)) f = NULL; #else #ifdef OSF1_HACKS f = ldr_lookup_package(hand, workbuf); #else f = dlsym(hand, workbuf); #endif #endif if (f == NULL) { /* some OS's need the _ */ sprintf(workbuf, "_%s_start", name); #ifdef HPUX_HACKS if (shl_findsym(&hand, workbuf, (short) TYPE_PROCEDURE, (void *)&f)) f = NULL; #else #ifdef OSF1_HACKS f = ldr_lookup_package(hand, workbuf); #else f = dlsym(hand, workbuf); #endif #endif if (f == NULL) { #ifdef HPUX_HACKS shl_unload(hand); #else #ifdef OSF1_HACKS #else dlclose(hand); #endif #endif return MOD_NOSTARTDEF; } } #else for (sl = static_modules;sl && strcasecmp(sl->name,name);sl = sl->next); if (!sl) return "Unkown module."; f =(Function) sl->func; #endif p = nmalloc(sizeof(module_entry)); if (p == NULL) return "Malloc error"; p->name = nmalloc(strlen(name) + 1); strcpy(p->name, name); p->major = 0; p->minor = 0; #ifndef STATIC p->hand = hand; #endif p->funcs = 0; p->next = module_list; module_list = p; e = (((char *(*)())f)(global_table)); if (e) { module_list = module_list->next; nfree(p->name); nfree(p); return e; } check_tcl_load(name); putlog(LOG_MISC, "*", "%s %s", MOD_LOADED, name); context; return NULL; } char *module_unload (char * name,char * user) { module_entry *p = module_list, *o = NULL; char *e; Function *f; context; while (p) { if ((p->name != NULL) && (strcmp(name, p->name) == 0)) { dependancy *d = dependancy_list; while (d!=NULL) { if (d->needed == p) { return MOD_NEEDED; } d=d->next; } f = p->funcs; if (f && !f[MODCALL_CLOSE]) return MOD_NOCLOSEDEF; if (f) { check_tcl_unld(name); e = (((char *(*)())f[MODCALL_CLOSE]) (user)); if (e != NULL) return e; #ifndef STATIC #ifdef HPUX_HACKS shl_unload(p->hand); #else #ifdef OSF1_HACKS #else dlclose(p->hand); #endif #endif #endif /* STATIC */ } nfree(p->name); if (o == NULL) { module_list = p->next; } else { o->next = p->next; } nfree(p); putlog(LOG_MISC, "*", "%s %s", MOD_UNLOADED, name); return NULL; } o = p; p = p->next; } return MOD_NOSUCH; } module_entry *module_find (char * name, int major, int minor) { module_entry *p = module_list; while (p) { if (p->name && !strcasecmp(name, p->name) && ((major == p->major) || (major == 0)) && (minor <= p->minor)) return p; p = p->next; } return NULL; } static int module_rename (char * name, char * newname) { module_entry *p = module_list; while (p) { if (!strcasecmp(newname,p->name)) return 0; p = p->next; } p = module_list; while (p) { if (p->name && !strcasecmp(name, p->name)) { nfree(p->name); p->name = nmalloc(strlen(newname) +1); strcpy(p->name,newname); return 1; } p = p->next; } return 0; } Function * module_depend (char * name1, char * name2, int major, int minor) { module_entry *p = module_find(name2, major, minor); module_entry *o = module_find(name1, 0, 0); dependancy *d; context; if (!p) { if (module_load(name2)) return 0; p = module_find(name2, major, minor); } if (!p || !o) return 0; d = nmalloc(sizeof(dependancy)); d->needed = p; d->needing = o; d->next = dependancy_list; d->major = major; d->minor = minor; dependancy_list = d; context; return p->funcs ? p->funcs : (Function *)1; } int module_undepend (char * name1) { int ok = 0; module_entry *p = module_find(name1, 0, 0); dependancy *d = dependancy_list, *o = NULL; context; if (p == NULL) return 0; while (d!=NULL) { if (d->needing == p) { if (o == NULL) { dependancy_list = d->next; } else { o->next = d->next; } nfree(d); if (o == NULL) d = dependancy_list; else d = o->next; ok++; } else { o = d; d = d->next; } } context; return ok; } void *mod_malloc (int size, char * modname, char * filename, int line) { char x[100]; sprintf(x, "%s:%s", modname, filename); x[19] = 0; return n_malloc(size, x, line); } void mod_free (void * ptr, char * modname, char * filename, int line) { char x[100]; sprintf(x, "%s:%s", modname, filename); x[19] = 0; n_free(ptr, x, line); } /* hooks, various tables of functions to call on ceratin events */ void add_hook (int hook_num, void * func) { context; if (hook_num < REAL_HOOKS) { struct hook_entry *p; for (p = hook_list[hook_num];p;p=p->next) if (p->func == func) return; /* dont add it if it's already there */ p = nmalloc(sizeof(struct hook_entry)); p->next = hook_list[hook_num]; hook_list[hook_num] = p; p->func = func; } else switch (hook_num) { case HOOK_ENCRYPT_PASS: encrypt_pass = func; break; case HOOK_SHAREOUT: shareout = func; break; case HOOK_SHAREIN: sharein = func; break; case HOOK_QSERV: if (qserver == null_func) qserver = func; break; case HOOK_ADD_MODE: if (add_mode == null_func) add_mode = func; break; } } void del_hook (int hook_num, void * func) { context; if (hook_num < REAL_HOOKS) { struct hook_entry *p = hook_list[hook_num], *o = NULL; while (p) { if (p->func == func) { if (o == NULL) hook_list[hook_num] = p->next; else o->next = p->next; nfree(p); break; } o = p; p = p->next; } } else switch (hook_num) { case HOOK_ENCRYPT_PASS: if (encrypt_pass == func) encrypt_pass = null_func; break; case HOOK_SHAREOUT: if (shareout == func) shareout = null_func; break; case HOOK_SHAREIN: if (sharein == func) sharein = null_share; break; case HOOK_QSERV: if (qserver == func) qserver = null_func; break; case HOOK_ADD_MODE: if (add_mode == func) add_mode = null_func; break; } } int call_hook_cccc (int hooknum, char * a, char * b, char * c, char * d) { struct hook_entry *p; int f = 0; if (hooknum >= REAL_HOOKS) return 0; p = hook_list[hooknum]; context; while ((p != NULL) && !f) { f = p->func(a, b, c, d); p = p->next; } return f; } void do_module_report (int idx,int details,char * which) { module_entry *p = module_list; if (p && !which && details) dprintf(idx, "MODULES LOADED:\n"); while (p) { if (!which || !strcasecmp(which,p->name)) { dependancy *d = dependancy_list; if (details) dprintf(idx, "Module: %s, v %d.%d\n", p->name ? p->name : "CORE", p->major, p->minor); if (details > 1) { while (d != NULL) { if (d->needing == p) dprintf(idx, " requires: %s, v %d.%d\n", d->needed->name, d->major, d->minor); d = d->next; } } if (p->funcs) { Function f = p->funcs[MODCALL_REPORT]; if (f != NULL) f(idx,details); } if (which) return; } p = p->next; } if (which) dprintf(idx, "No such module.\n"); }