ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/nickserv/access.C
Revision: 1.4
Committed: Tue Aug 28 17:08:09 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.3: +23 -37 lines
Log Message:
- changed name
- updated the example config to the new system
- added more documentation
- enhanced documentation generators
- added a link to the pdf to the website
- added an RSS feed generator
- transitioned hooks to c++ callbacks
- did various merges with upstream along the way
- added const where appropriate
- removed the old block allocator
- fixed most memory leaks
- transitioned some dictionaries to std::map
- transitioned some lists to std::vector
- made some free functions members where appropriate
- renamed string to dynstr and added a static string ststr
- use NOW instead of time (NULL) if possible
- completely reworked database backends, crypto handlers and protocol handlers
  to use an object factory
- removed the old module system. ermyth does not do any dynamic loading anymore
- fixed most of the build system
- reworked how protocol commands work

File Contents

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