#include "atheme-compat.h" #ifndef _WIN32 #include #include #include #include DECLARE_MODULE_V1 ( "contrib/ns_mxcheck_async", false, _modinit, _moddeinit, "1.1", "Jamie L. Penman-Smithson " ); struct procdata { char name[NICKLEN]; char email[EMAILLEN]; }; #define MAX_CHILDPROCS 10 static unsigned int proccount; static struct procdata procdata[MAX_CHILDPROCS]; static void childproc_cb(pid_t pid, int status, void *data); static void check_registration(hook_user_register_check_t *hdata); int count_mx (const char *host); void _modinit(module_t *m) { hook_add_event("user_can_register"); hook_add_user_can_register(check_registration); } void _moddeinit(module_unload_intent_t intent) { hook_del_user_can_register(check_registration); childproc_delete_all(childproc_cb); } static void childproc_cb(pid_t pid, int status, void *data) { struct procdata *pd = data; myuser_t *mu; const char *domain; return_if_fail(proccount > 0); proccount--; if (!WIFEXITED(status)) return; mu = myuser_find(pd->name); if (mu == NULL || strcmp(pd->email, mu->email)) return; domain = strchr(pd->email, '@'); if (domain == NULL) return; domain++; if (WEXITSTATUS(status) == 1) { slog(LG_INFO, "REGISTER: mxcheck: no A/MX records for %s - " "REGISTER failed", domain); myuser_notice(nicksvs.nick, mu, "Sorry, \2%s\2 does not exist, " "I can't send mail there. Please check and try again.", domain); object_unref(mu); } else if (WEXITSTATUS(status) == 0) { slog(LG_INFO, "REGISTER: mxcheck: valid MX records for %s", domain); } } static void check_registration(hook_user_register_check_t *hdata) { char buf[1024]; const char *user; const char *domain; int count; pid_t pid; struct procdata *pd; if (hdata->approved) return; if (proccount >= MAX_CHILDPROCS) { command_fail(hdata->si, fault_toomany, "Sorry, too many registrations in progress. Try again later."); hdata->approved = 1; return; } switch (pid = fork()) { case 0: /* child */ connection_close_all_fds(); mowgli_strlcpy(buf, hdata->email, sizeof buf); user = strtok(buf, "@"); domain = strtok(NULL, "@"); count = count_mx(domain); if (count <= 0) { /* no MX records or error */ struct hostent *host; /* attempt to resolve host (fallback to A) */ if((host = gethostbyname(domain)) == NULL) _exit(1); } _exit(0); break; case -1: /* error */ slog(LG_ERROR, "fork() failed for check_registration(): %s", strerror(errno)); command_fail(hdata->si, fault_toomany, "Sorry, too many registrations in progress. Try again later."); hdata->approved = 1; return; default: /* parent */ pd = &procdata[proccount++]; mowgli_strlcpy(pd->name, hdata->account, sizeof pd->name); mowgli_strlcpy(pd->email, hdata->email, sizeof pd->email); childproc_add(pid, "ns_mxcheck_async", childproc_cb, pd); return; } } int count_mx (const char *host) { u_char nsbuf[4096]; ns_msg amsg; int l; l = res_query (host, ns_c_any, ns_t_mx, nsbuf, sizeof (nsbuf)); if (l < 0) { return 0; } else { ns_initparse (nsbuf, l, &amsg); l = ns_msg_count (amsg, ns_s_an); } return l; } #endif