/* * 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 gexempt_total, ginvite_total; extern int default_flags, require_p, max_dcc, share_greet, password_timeout; extern int min_dcc_port, max_dcc_port; /* dw */ extern int use_invites, use_exempts; /* Jason/drummer */ extern int force_expire; /* Rufus */ extern int do_restart; extern time_t now, online_since; extern struct chanset_t *chanset; int cmd_die(), xtra_kill(), xtra_unpack(); /* wtf ??? */ 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) rfc_casecmp, (Function) rfc_ncasecmp, /* 220 - 223 */ (Function) &global_exempts, /* struct exemptrec * */ (Function) &global_invites, /* struct inviterec * */ (Function) &gexempt_total, /* int */ (Function) &ginvite_total, /* int */ /* 224 - 227 */ (Function) & H_event, (Function) & use_exempts, /* int - drummer/Jason */ (Function) & use_invites, /* int - drummer/Jason */ (Function) & force_expire, /* int - Rufus */ }; 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 context; 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); context; 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 context; hand = dlopen(workbuf, DLFLAGS); if (!hand) return dlerror(); #endif #endif sprintf(workbuf, "%s_start", name); #ifdef HPUX_HACKS context; 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); context; 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); context; 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)); context; 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))) { 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"); }