ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/nickserv/access.C
Revision: 1.9
Committed: Sat Sep 22 14:27:27 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +3 -3 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

# User Rev Content
1 pippijn 1.8 /**
2     * access.C: Changes and shows nickname access lists.
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 pippijn 1.4 * Copyright © 2006-2007 Atheme Development Group
10 pippijn 1.2 * Rights to this code are as documented in doc/pod/license.pod.
11 pippijn 1.1 *
12 pippijn 1.9 * $Id: access.C,v 1.8 2007-09-16 18:54:43 pippijn Exp $
13 pippijn 1.1 */
14    
15     #include "atheme.h"
16 pippijn 1.4 #include <ermyth/module.h>
17 pippijn 1.1 #include <account/myuser.h>
18     #include <account/mynick.h>
19    
20 pippijn 1.9 static char const rcsid[] = "$Id: access.C,v 1.8 2007-09-16 18:54:43 pippijn Exp $";
21 pippijn 1.1
22 pippijn 1.9 REGISTER_MODULE ("nickserv/access", false, "The Ermyth Team <http://ermyth.xinutec.org>");
23 pippijn 1.1
24     static void ns_cmd_access (sourceinfo_t *si, int parc, char *parv[]);
25    
26 pippijn 1.4 command_t const ns_access = { "ACCESS", N_("Changes and shows your nickname access list."), AC_NONE, 2, ns_cmd_access };
27 pippijn 1.1
28 pippijn 1.4 E cmdvec ns_cmdtree;
29     E helpvec ns_helptree;
30 pippijn 1.1
31 pippijn 1.4 bool
32     _modinit (module *m)
33 pippijn 1.1 {
34     ns_cmdtree << ns_access;
35     help_addentry (ns_helptree, "ACCESS", "help/nickserv/access", NULL);
36    
37     use_myuser_access++;
38 pippijn 1.4
39     return true;
40 pippijn 1.1 }
41    
42     void
43     _moddeinit ()
44     {
45     ns_cmdtree >> ns_access;
46     help_delentry (ns_helptree, "ACCESS");
47    
48     use_myuser_access--;
49     }
50    
51     static bool
52 pippijn 1.4 username_is_random (char const * const name)
53 pippijn 1.1 {
54 pippijn 1.4 char const *p = name;
55 pippijn 1.1 int lower = 0, upper = 0, digit = 0;
56    
57 pippijn 1.4 if (*p == '~')
58     p++;
59     if (strlen (p) < 9)
60 pippijn 1.1 return false;
61     while (*p != '\0')
62     {
63     if (isdigit (*p))
64     digit++;
65     else if (isupper (*p))
66     upper++;
67     else if (islower (*p))
68     lower++;
69     p++;
70     }
71     if (digit >= 4 && lower + upper > 1)
72     return true;
73     if (lower == 0 || upper == 0 || (upper <= 2 && isupper (*name)))
74     return false;
75     return true;
76     }
77    
78     static char *
79     construct_mask (user_t *u)
80     {
81     static char mask[USERLEN + HOSTLEN];
82 pippijn 1.4 char const * const dynhosts[] = { "*dyn*.*", "*dial*.*.*", "*dhcp*.*.*",
83 pippijn 1.1 "*.t-online.??", "*.t-online.???",
84     "*.t-dialin.??", "*.t-dialin.???",
85     "*.t-ipconnect.??", "*.t-ipconnect.???",
86     "*.ipt.aol.com", NULL
87     };
88     int i;
89     bool hostisdyn = false, havedigits;
90 pippijn 1.4 char const *p, *prevdot, *lastdot;
91 pippijn 1.1
92     for (i = 0; dynhosts[i] != NULL; i++)
93     if (!match (dynhosts[i], u->host))
94     hostisdyn = true;
95     if (hostisdyn)
96     {
97     /* note that all dyn patterns contain a dot */
98     p = u->host;
99     prevdot = u->host;
100     lastdot = strrchr (u->host, '.');
101     havedigits = true;
102     while (*p)
103     {
104     if (*p == '.')
105     {
106     if (!havedigits || p == lastdot || !strcasecmp (p, ".Level3.net"))
107     break;
108     prevdot = p;
109     havedigits = false;
110     }
111     else if (isdigit (*p))
112     havedigits = true;
113     p++;
114     }
115     snprintf (mask, sizeof mask, "%s@*%s", u->user, prevdot);
116     }
117     else if (username_is_random (u->user))
118     snprintf (mask, sizeof mask, "*@%s", u->host);
119     else if (!strcmp (u->host, u->ip) && (p = strrchr (u->ip, '.')) != NULL)
120     snprintf (mask, sizeof mask, "%s@%.*s.0/24", u->user, (int) (p - u->ip), u->ip);
121     else
122     snprintf (mask, sizeof mask, "%s@%s", u->user, u->host);
123     return mask;
124     }
125    
126     static bool
127 pippijn 1.4 mangle_wildcard_to_cidr (char const * const host, char *dest, int destlen)
128 pippijn 1.1 {
129     int i;
130 pippijn 1.4 char const *p = host;
131 pippijn 1.1
132     if ((p[0] != '0' || p[1] != '.') && ((i = atoi (p)) < 1 || i > 255))
133     return false;
134     while (isdigit (*p))
135     p++;
136     if (*p++ != '.')
137     return false;
138     if (p[0] == '*' && p[1] == '\0')
139     {
140     snprintf (dest, destlen, "%.*s0.0.0/8", (int) (p - host), host);
141     return true;
142     }
143    
144     if ((p[0] != '0' || p[1] != '.') && ((i = atoi (p)) < 1 || i > 255))
145     return false;
146     while (isdigit (*p))
147     p++;
148     if (*p++ != '.')
149     return false;
150     if (p[0] == '*' && (p[1] == '\0' || (p[1] == '.' && p[2] == '*' && p[3] == '\0')))
151     {
152     snprintf (dest, destlen, "%.*s0.0/16", (int) (p - host), host);
153     return true;
154     }
155    
156     if ((p[0] != '0' || p[1] != '.') && ((i = atoi (p)) < 1 || i > 255))
157     return false;
158     while (isdigit (*p))
159     p++;
160     if (*p++ != '.')
161     return false;
162     if (p[0] == '*' && p[1] == '\0')
163     {
164     snprintf (dest, destlen, "%.*s0/24", (int) (p - host), host);
165     return true;
166     }
167    
168     return false;
169     }
170    
171     void
172     myuser_access_delete_enforce (myuser_t *mu, char *mask)
173     {
174 pippijn 1.4 list_t l;
175 pippijn 1.1 node_t *n, *tn;
176     mynick_t *mn;
177     user_t *u;
178    
179     /* find users who get access via the access list */
180     LIST_FOREACH (n, mu->nicks.head)
181     {
182     mn = static_cast<mynick_t *> (n->data);
183     u = user_find_named (mn->nick);
184 pippijn 1.5 if (u != NULL && u->myuser != mu && mu->access_verify (u))
185 pippijn 1.1 node_add (u, node_create (), &l);
186     }
187     /* remove mask */
188 pippijn 1.5 mu->access_delete (mask);
189 pippijn 1.1 /* check if those users still have access */
190     LIST_FOREACH_SAFE (n, tn, l.head)
191     {
192     u = static_cast<user_t *> (n->data);
193     node_del (n, &l);
194     node_free (n);
195 pippijn 1.5 if (!mu->access_verify (u))
196 pippijn 1.1 {
197 pippijn 1.7 mn = mynick_t::find (u->nick);
198 pippijn 1.1 if (mn != NULL)
199 pippijn 1.4 mn->callback.enforce (mn, u);
200 pippijn 1.1 }
201     }
202     }
203    
204     static void
205     ns_cmd_access (sourceinfo_t *si, int parc, char *parv[])
206     {
207     myuser_t *mu;
208     node_t *n;
209     char *mask;
210     char *host;
211     char *p;
212     char mangledmask[NICKLEN + HOSTLEN + 10];
213    
214     if (parc < 1)
215     {
216 pippijn 1.6 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS");
217     command_fail (si, fault::needmoreparams, _("Syntax: ACCESS ADD|DEL|LIST [mask]"));
218 pippijn 1.1 return;
219     }
220    
221     if (!strcasecmp (parv[0], "LIST"))
222     {
223     if (parc < 2)
224     {
225     mu = si->smu;
226     if (mu == NULL)
227     {
228 pippijn 1.6 command_fail (si, fault::noprivs, _("You are not logged in."));
229 pippijn 1.1 return;
230     }
231     }
232     else
233     {
234     if (!has_priv (si, PRIV_USER_AUSPEX))
235     {
236 pippijn 1.6 command_fail (si, fault::noprivs, _("You are not authorized to use the target argument."));
237 pippijn 1.1 return;
238     }
239    
240 pippijn 1.5 if (!(mu = myuser_t::find_ext (parv[1])))
241 pippijn 1.1 {
242 pippijn 1.6 command_fail (si, fault::badparams, _("\2%s\2 is not registered."), parv[1]);
243 pippijn 1.1 return;
244     }
245     }
246    
247     if (mu != si->smu)
248     logcommand (si, CMDLOG_ADMIN, "ACCESS LIST %s", mu->name);
249     else
250     logcommand (si, CMDLOG_GET, "ACCESS LIST");
251    
252     command_success_nodata (si, _("Access list for \2%s\2:"), mu->name);
253    
254     LIST_FOREACH (n, mu->access_list.head)
255     {
256     mask = static_cast<char *> (n->data);
257     command_success_nodata (si, "- %s", mask);
258     }
259    
260     command_success_nodata (si, _("End of \2%s\2 access list."), mu->name);
261     }
262     else if (!strcasecmp (parv[0], "ADD"))
263     {
264     mu = si->smu;
265     if (parc < 2)
266     {
267     if (si->su == NULL)
268     {
269 pippijn 1.6 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS ADD");
270     command_fail (si, fault::needmoreparams, _("Syntax: ACCESS ADD <mask>"));
271 pippijn 1.1 return;
272     }
273     else
274     mask = construct_mask (si->su);
275     }
276     else
277     mask = parv[1];
278     if (mu == NULL)
279     {
280 pippijn 1.6 command_fail (si, fault::noprivs, _("You are not logged in."));
281 pippijn 1.1 return;
282     }
283     if (mask[0] == '*' && mask[1] == '!')
284     mask += 2;
285     if (strlen (mask) >= USERLEN + HOSTLEN)
286     {
287 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
288 pippijn 1.1 return;
289     }
290     p = mask;
291     while (*p != '\0')
292     {
293     if (!isprint (*p) || *p == ' ' || *p == '!')
294     {
295 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
296 pippijn 1.1 return;
297     }
298     p++;
299     }
300     host = strchr (mask, '@');
301     if (host == NULL) /* account name access masks? */
302     {
303 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
304 pippijn 1.1 return;
305     }
306     host++;
307     /* try mangling to cidr */
308     strlcpy (mangledmask, mask, sizeof mangledmask);
309     if (mangle_wildcard_to_cidr (host, mangledmask + (host - mask), sizeof mangledmask - (host - mask)))
310     host = mangledmask + (host - mask), mask = mangledmask;
311     /* more checks */
312     if (si->su != NULL && (!strcasecmp (host, si->su->host) || !strcasecmp (host, si->su->vhost)))
313     ; /* it's their host, allow it */
314     else if (host[0] == '.' || host[0] == ':' || host[0] == '\0' || host[1] == '\0' || host == mask + 1 || strchr (host, '@') || strstr (host, ".."))
315     {
316 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
317 pippijn 1.1 return;
318     }
319     else if ((strchr (host, '*') || strchr (host, '?')) && (mask[0] == '*' && mask[1] == '@'))
320     {
321     /* can't use * username and wildcarded host */
322 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
323 pippijn 1.1 return;
324     }
325     else if ((p = strrchr (host, '/')) != NULL)
326     {
327     if (isdigit (p[1]) && (atoi (p + 1) < 16 || (mask[0] == '*' && mask[1] == '@')))
328     {
329 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
330 pippijn 1.1 return;
331     }
332     if (host[0] == '*')
333     {
334 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
335 pippijn 1.1 return;
336     }
337     }
338     else
339     {
340     p = strrchr (host, '.');
341     if (p != NULL)
342     {
343     /* No wildcarded IPs */
344     if (isdigit (p[1]) && (strchr (host, '*') || strchr (host, '?')))
345     {
346 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
347 pippijn 1.1 return;
348     }
349     /* Require non-wildcard top and second level
350     * domain */
351     if (strchr (p, '?') || strchr (p, '*'))
352     {
353 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
354 pippijn 1.1 return;
355     }
356     p--;
357     while (p >= host && *p != '.')
358     {
359     if (*p == '?' || *p == '*')
360     {
361 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
362 pippijn 1.1 return;
363     }
364     p--;
365     }
366     }
367     else if (strchr (host, ':'))
368     {
369     /* No wildcarded IPs */
370     if (strchr (host, '?') || strchr (host, '*'))
371     {
372 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
373 pippijn 1.1 return;
374     }
375     }
376     else /* no '.' or ':' */
377     {
378 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
379 pippijn 1.1 return;
380     }
381     }
382 pippijn 1.5 if (mu->access_find (mask))
383 pippijn 1.1 {
384 pippijn 1.6 command_fail (si, fault::nochange, _("Mask \2%s\2 is already on your access list."), mask);
385 pippijn 1.1 return;
386     }
387 pippijn 1.5 if (mu->access_add (mask))
388 pippijn 1.1 {
389     command_success_nodata (si, _("Added mask \2%s\2 to your access list."), mask);
390     logcommand (si, CMDLOG_SET, "ACCESS ADD %s", mask);
391     }
392     else
393 pippijn 1.6 command_fail (si, fault::toomany, _("Your access list is full."));
394 pippijn 1.1 }
395     else if (!strcasecmp (parv[0], "DEL"))
396     {
397     if (parc < 2)
398     {
399 pippijn 1.6 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS DEL");
400     command_fail (si, fault::needmoreparams, _("Syntax: ACCESS DEL <mask>"));
401 pippijn 1.1 return;
402     }
403     mu = si->smu;
404     if (mu == NULL)
405     {
406 pippijn 1.6 command_fail (si, fault::noprivs, _("You are not logged in."));
407 pippijn 1.1 return;
408     }
409 pippijn 1.5 if ((mask = mu->access_find (parv[1])) == NULL)
410 pippijn 1.1 {
411 pippijn 1.6 command_fail (si, fault::nochange, _("Mask \2%s\2 is not on your access list."), parv[1]);
412 pippijn 1.1 return;
413     }
414     command_success_nodata (si, _("Deleted mask \2%s\2 from your access list."), mask);
415     logcommand (si, CMDLOG_SET, "ACCESS DEL %s", mask);
416     myuser_access_delete_enforce (mu, mask);
417     }
418     else
419     {
420 pippijn 1.6 command_fail (si, fault::needmoreparams, STR_INVALID_PARAMS, "ACCESS");
421     command_fail (si, fault::needmoreparams, _("Syntax: ACCESS ADD|DEL|LIST [mask]"));
422 pippijn 1.1 return;
423     }
424     }