153 lines
3.3 KiB
C
153 lines
3.3 KiB
C
#include "atheme.h"
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <netinet/in.h>
|
|
#include <arpa/nameser.h>
|
|
#include <resolv.h>
|
|
#include <netdb.h>
|
|
|
|
DECLARE_MODULE_V1
|
|
(
|
|
"contrib/ns_mxcheck_async", false, _modinit, _moddeinit,
|
|
"1.1",
|
|
"Jamie L. Penman-Smithson <jamie@slacked.org>"
|
|
);
|
|
|
|
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
|