1 |
/** |
2 |
* vhost.C: Allows setting a vhost on an account |
3 |
* |
4 |
* Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team |
5 |
* Rights to this code are as documented in COPYING. |
6 |
* |
7 |
* |
8 |
* Portions of this file were derived from sources bearing the following license: |
9 |
* Copyright © 2005 William Pitcock <nenolod -at- nenolod.net> |
10 |
* Rights to this code are as documented in doc/pod/license.pod. |
11 |
* |
12 |
* $Id: vhost.C,v 1.8 2007-09-16 18:54:43 pippijn Exp $ |
13 |
*/ |
14 |
|
15 |
#include "atheme.h" |
16 |
#include <ermyth/module.h> |
17 |
#include <account/myuser.h> |
18 |
#include <boost/foreach.hpp> |
19 |
|
20 |
static char const rcsid[] = "$Id: vhost.C,v 1.8 2007-09-16 18:54:43 pippijn Exp $"; |
21 |
|
22 |
REGISTER_MODULE ("nickserv/vhost", false, "The Ermyth Team <http://ermyth.xinutec.org>"); |
23 |
|
24 |
E cmdvec ns_cmdtree; |
25 |
E helpvec ns_helptree; |
26 |
|
27 |
static void ns_cmd_vhost (sourceinfo_t *si, int parc, char *parv[]); |
28 |
static void ns_cmd_listvhost (sourceinfo_t *si, int parc, char *parv[]); |
29 |
|
30 |
command_t const ns_vhost = { "VHOST", N_("Manages user virtualhosts."), PRIV_USER_VHOST, 2, ns_cmd_vhost }; |
31 |
command_t const ns_listvhost = { "LISTVHOST", N_("Lists user virtualhosts."), PRIV_USER_AUSPEX, 1, ns_cmd_listvhost }; |
32 |
|
33 |
static void |
34 |
do_sethost_all (myuser_t *mu, char *host) |
35 |
{ |
36 |
user_t *u; |
37 |
myuser_t::login_vector::iterator it, it_end; |
38 |
|
39 |
for (it = mu->logins.begin (), it_end = mu->logins.end (); it != it_end; ++it) |
40 |
{ |
41 |
u = *it; |
42 |
|
43 |
if (!strcmp (u->vhost, host)) |
44 |
continue; |
45 |
strlcpy (u->vhost, host, HOSTLEN); |
46 |
phandler->sethost_sts (nicksvs.nick, u->nick, u->vhost); |
47 |
} |
48 |
} |
49 |
|
50 |
static void |
51 |
do_sethost (user_t *u, char *host) |
52 |
{ |
53 |
if (!strcmp (u->vhost, host)) |
54 |
return; |
55 |
strlcpy (u->vhost, host, HOSTLEN); |
56 |
phandler->sethost_sts (nicksvs.nick, u->nick, u->vhost); |
57 |
} |
58 |
|
59 |
static void |
60 |
do_restorehost_all (myuser_t *mu) |
61 |
{ |
62 |
user_t *u; |
63 |
myuser_t::login_vector::iterator it, it_end; |
64 |
|
65 |
for (it = mu->logins.begin (), it_end = mu->logins.end (); it != it_end; ++it) |
66 |
{ |
67 |
u = *it; |
68 |
|
69 |
if (!strcmp (u->vhost, u->host)) |
70 |
continue; |
71 |
strlcpy (u->vhost, u->host, HOSTLEN); |
72 |
phandler->sethost_sts (nicksvs.nick, u->nick, u->host); |
73 |
} |
74 |
} |
75 |
|
76 |
/* VHOST <nick> [host] */ |
77 |
static void |
78 |
ns_cmd_vhost (sourceinfo_t *si, int parc, char *parv[]) |
79 |
{ |
80 |
char *target = parv[0]; |
81 |
char *host = parv[1]; |
82 |
myuser_t *mu; |
83 |
char *p; |
84 |
|
85 |
if (!target) |
86 |
{ |
87 |
command_fail (si, fault::needmoreparams, STR_INVALID_PARAMS, "VHOST"); |
88 |
command_fail (si, fault::needmoreparams, _("Syntax: VHOST <nick> [vhost]")); |
89 |
return; |
90 |
} |
91 |
|
92 |
/* find the user... */ |
93 |
if (!(mu = myuser_t::find_ext (target))) |
94 |
{ |
95 |
command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), target); |
96 |
return; |
97 |
} |
98 |
|
99 |
/* deletion action */ |
100 |
if (!host) |
101 |
{ |
102 |
mu->del_metadata ("private:usercloak"); |
103 |
command_success_nodata (si, _("Deleted vhost for \2%s\2."), mu->name); |
104 |
snoop ("VHOST:REMOVE: \2%s\2 by \2%s\2", mu->name, get_oper_name (si)); |
105 |
logcommand (si, CMDLOG_ADMIN, "VHOST REMOVE %s", mu->name); |
106 |
do_restorehost_all (mu); |
107 |
return; |
108 |
} |
109 |
|
110 |
/* Never ever allow @!?* as they have special meaning in all ircds */ |
111 |
/* Empty, space anywhere and colon at the start break the protocol */ |
112 |
if (strchr (host, '@') || strchr (host, '!') || strchr (host, '?') || strchr (host, '*') || strchr (host, ' ') || *host == ':' || *host == '\0') |
113 |
{ |
114 |
command_fail (si, fault::badparams, _("The vhost provided contains invalid characters.")); |
115 |
return; |
116 |
} |
117 |
if (strlen (host) >= HOSTLEN) |
118 |
{ |
119 |
command_fail (si, fault::badparams, _("The vhost provided is too long.")); |
120 |
return; |
121 |
} |
122 |
p = strrchr (host, '/'); |
123 |
if (p != NULL && isdigit (p[1])) |
124 |
{ |
125 |
command_fail (si, fault::badparams, _("The vhost provided looks like a CIDR mask.")); |
126 |
return; |
127 |
} |
128 |
/* XXX more checks here, perhaps as a configurable regexp? */ |
129 |
|
130 |
mu->add_metadata ("private:usercloak", host); |
131 |
command_success_nodata (si, _("Assigned vhost \2%s\2 to \2%s\2."), host, mu->name); |
132 |
snoop ("VHOST:ASSIGN: \2%s\2 to \2%s\2 by \2%s\2", host, mu->name, get_oper_name (si)); |
133 |
logcommand (si, CMDLOG_ADMIN, "VHOST ASSIGN %s %s", mu->name, host); |
134 |
do_sethost_all (mu, host); |
135 |
return; |
136 |
} |
137 |
|
138 |
static void |
139 |
ns_cmd_listvhost (sourceinfo_t *si, int parc, char *parv[]) |
140 |
{ |
141 |
char const * const pattern = parc >= 1 ? parv[0] : "*"; |
142 |
myuser_t *mu; |
143 |
metadata *md; |
144 |
int matches = 0; |
145 |
|
146 |
snoop ("LISTVHOST: \2%s\2 by \2%s\2", pattern, get_oper_name (si)); |
147 |
foreach (myuser_t::pair_type &mup, myuser_t::map) |
148 |
{ |
149 |
mu = mup.second; |
150 |
md = mu->find_metadata ("private:usercloak"); |
151 |
if (md == NULL) |
152 |
continue; |
153 |
if (!match (pattern, md->value)) |
154 |
{ |
155 |
command_success_nodata (si, "- %-30s %s", mu->name, md->value); |
156 |
matches++; |
157 |
} |
158 |
} |
159 |
|
160 |
logcommand (si, CMDLOG_ADMIN, "LISTVHOST %s (%d matches)", pattern, matches); |
161 |
if (matches == 0) |
162 |
command_success_nodata (si, _("No vhosts matched pattern \2%s\2"), pattern); |
163 |
else |
164 |
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); |
165 |
} |
166 |
|
167 |
static void |
168 |
vhost_on_identify (user_t *u) |
169 |
{ |
170 |
myuser_t *mu = u->myuser; |
171 |
metadata *md; |
172 |
|
173 |
/* NO CLOAK?!*$*%*&&$(!& */ |
174 |
if (!(md = mu->find_metadata ("private:usercloak"))) |
175 |
return; |
176 |
|
177 |
do_sethost (u, md->value); |
178 |
} |
179 |
|
180 |
bool |
181 |
_modinit (module *m) |
182 |
{ |
183 |
user_t::callback.identify.attach (vhost_on_identify); |
184 |
|
185 |
ns_cmdtree << ns_vhost; |
186 |
ns_cmdtree << ns_listvhost; |
187 |
|
188 |
help_addentry (ns_helptree, "VHOST", "help/nickserv/vhost", NULL); |
189 |
help_addentry (ns_helptree, "LISTVHOST", "help/nickserv/listvhost", NULL); |
190 |
|
191 |
return true; |
192 |
} |
193 |
|
194 |
void |
195 |
_moddeinit (void) |
196 |
{ |
197 |
user_t::callback.identify.detach (vhost_on_identify); |
198 |
|
199 |
ns_cmdtree >> ns_vhost; |
200 |
ns_cmdtree >> ns_listvhost; |
201 |
|
202 |
help_delentry (ns_helptree, "VHOST"); |
203 |
help_delentry (ns_helptree, "LISTVHOST"); |
204 |
} |