/** * vhost.C: Allows setting a vhost on an account * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Copyright © 2005 William Pitcock * Rights to this code are as documented in doc/pod/license.pod. * * $Id: vhost.C,v 1.9 2007/09/22 14:27:28 pippijn Exp $ */ #include "atheme.h" #include #include #include static char const rcsid[] = "$Id: vhost.C,v 1.9 2007/09/22 14:27:28 pippijn Exp $"; REGISTER_MODULE ("nickserv/vhost", false, "The Ermyth Team "); E cmdvec ns_cmdtree; E helpvec ns_helptree; static void ns_cmd_vhost (sourceinfo_t *si, int parc, char *parv[]); static void ns_cmd_listvhost (sourceinfo_t *si, int parc, char *parv[]); command_t const ns_vhost = { "VHOST", N_("Manages user virtualhosts."), PRIV_USER_VHOST, 2, ns_cmd_vhost }; command_t const ns_listvhost = { "LISTVHOST", N_("Lists user virtualhosts."), PRIV_USER_AUSPEX, 1, ns_cmd_listvhost }; static void do_sethost_all (myuser_t *mu, char *host) { user_t *u; myuser_t::login_vector::iterator it, it_end; for (it = mu->logins.begin (), it_end = mu->logins.end (); it != it_end; ++it) { u = *it; if (!strcmp (u->vhost, host)) continue; strlcpy (u->vhost, host, HOSTLEN); phandler->sethost_sts (nicksvs.nick, u->nick, u->vhost); } } static void do_sethost (user_t *u, char *host) { if (!strcmp (u->vhost, host)) return; strlcpy (u->vhost, host, HOSTLEN); phandler->sethost_sts (nicksvs.nick, u->nick, u->vhost); } static void do_restorehost_all (myuser_t *mu) { user_t *u; myuser_t::login_vector::iterator it, it_end; for (it = mu->logins.begin (), it_end = mu->logins.end (); it != it_end; ++it) { u = *it; if (!strcmp (u->vhost, u->host)) continue; strlcpy (u->vhost, u->host, HOSTLEN); phandler->sethost_sts (nicksvs.nick, u->nick, u->host); } } /* VHOST [host] */ static void ns_cmd_vhost (sourceinfo_t *si, int parc, char *parv[]) { char *target = parv[0]; char *host = parv[1]; myuser_t *mu; char *p; if (!target) { command_fail (si, fault::needmoreparams, STR_INVALID_PARAMS, "VHOST"); command_fail (si, fault::needmoreparams, _("Syntax: VHOST [vhost]")); return; } /* find the user... */ if (!(mu = myuser_t::find_ext (target))) { command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), target); return; } /* deletion action */ if (!host) { mu->del_metadata ("private:usercloak"); command_success_nodata (si, _("Deleted vhost for \2%s\2."), mu->name); snoop ("VHOST:REMOVE: \2%s\2 by \2%s\2", mu->name, get_oper_name (si)); logcommand (si, CMDLOG_ADMIN, "VHOST REMOVE %s", mu->name); do_restorehost_all (mu); return; } /* Never ever allow @!?* as they have special meaning in all ircds */ /* Empty, space anywhere and colon at the start break the protocol */ if (strchr (host, '@') || strchr (host, '!') || strchr (host, '?') || strchr (host, '*') || strchr (host, ' ') || *host == ':' || *host == '\0') { command_fail (si, fault::badparams, _("The vhost provided contains invalid characters.")); return; } if (strlen (host) >= HOSTLEN) { command_fail (si, fault::badparams, _("The vhost provided is too long.")); return; } p = strrchr (host, '/'); if (p != NULL && isdigit (p[1])) { command_fail (si, fault::badparams, _("The vhost provided looks like a CIDR mask.")); return; } /* XXX more checks here, perhaps as a configurable regexp? */ mu->add_metadata ("private:usercloak", host); command_success_nodata (si, _("Assigned vhost \2%s\2 to \2%s\2."), host, mu->name); snoop ("VHOST:ASSIGN: \2%s\2 to \2%s\2 by \2%s\2", host, mu->name, get_oper_name (si)); logcommand (si, CMDLOG_ADMIN, "VHOST ASSIGN %s %s", mu->name, host); do_sethost_all (mu, host); return; } static void ns_cmd_listvhost (sourceinfo_t *si, int parc, char *parv[]) { char const * const pattern = parc >= 1 ? parv[0] : "*"; myuser_t *mu; metadata *md; int matches = 0; snoop ("LISTVHOST: \2%s\2 by \2%s\2", pattern, get_oper_name (si)); foreach (myuser_t::pair_type &mup, myuser_t::map) { mu = mup.second; md = mu->find_metadata ("private:usercloak"); if (md == NULL) continue; if (!match (pattern, md->value)) { command_success_nodata (si, "- %-30s %s", mu->name, md->value); matches++; } } logcommand (si, CMDLOG_ADMIN, "LISTVHOST %s (%d matches)", pattern, matches); if (matches == 0) command_success_nodata (si, _("No vhosts matched pattern \2%s\2"), pattern); else command_success_nodata (si, ngettext (N_("\2%d\2 match for pattern \2%s\2"), N_("\2%d\2 matches for pattern \2%s\2"), matches), matches, pattern); } static void vhost_on_identify (user_t *u) { myuser_t *mu = u->myuser; metadata *md; /* NO CLOAK?!*$*%*&&$(!& */ if (!(md = mu->find_metadata ("private:usercloak"))) return; do_sethost (u, md->value); } bool _modinit (module *m) { user_t::callback.identify.attach (vhost_on_identify); ns_cmdtree << ns_vhost; ns_cmdtree << ns_listvhost; help_addentry (ns_helptree, "VHOST", "help/nickserv/vhost", NULL); help_addentry (ns_helptree, "LISTVHOST", "help/nickserv/listvhost", NULL); return true; } void _moddeinit (void) { user_t::callback.identify.detach (vhost_on_identify); ns_cmdtree >> ns_vhost; ns_cmdtree >> ns_listvhost; help_delentry (ns_helptree, "VHOST"); help_delentry (ns_helptree, "LISTVHOST"); }