ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/nickserv/access.C
Revision: 1.6
Committed: Thu Aug 30 19:56:23 2007 UTC (19 years, 2 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.5: +30 -30 lines
Log Message:
- put faultcodes into their own namespace
- removed old files
- limited header garbage in atheme.h
- macros to inline bools for connection_t::is_*
- put some connection_t functions into the connection_t class

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.6 * $Id: access.C,v 1.5 2007-08-28 22:18:30 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.6 static char const rcsid[] = "$Id: access.C,v 1.5 2007-08-28 22:18:30 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 pippijn 1.5 if (u != NULL && u->myuser != mu && mu->access_verify (u))
180 pippijn 1.1 node_add (u, node_create (), &l);
181     }
182     /* remove mask */
183 pippijn 1.5 mu->access_delete (mask);
184 pippijn 1.1 /* 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 pippijn 1.5 if (!mu->access_verify (u))
191 pippijn 1.1 {
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 pippijn 1.6 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS");
212     command_fail (si, fault::needmoreparams, _("Syntax: ACCESS ADD|DEL|LIST [mask]"));
213 pippijn 1.1 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 pippijn 1.6 command_fail (si, fault::noprivs, _("You are not logged in."));
224 pippijn 1.1 return;
225     }
226     }
227     else
228     {
229     if (!has_priv (si, PRIV_USER_AUSPEX))
230     {
231 pippijn 1.6 command_fail (si, fault::noprivs, _("You are not authorized to use the target argument."));
232 pippijn 1.1 return;
233     }
234    
235 pippijn 1.5 if (!(mu = myuser_t::find_ext (parv[1])))
236 pippijn 1.1 {
237 pippijn 1.6 command_fail (si, fault::badparams, _("\2%s\2 is not registered."), parv[1]);
238 pippijn 1.1 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 pippijn 1.6 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS ADD");
265     command_fail (si, fault::needmoreparams, _("Syntax: ACCESS ADD <mask>"));
266 pippijn 1.1 return;
267     }
268     else
269     mask = construct_mask (si->su);
270     }
271     else
272     mask = parv[1];
273     if (mu == NULL)
274     {
275 pippijn 1.6 command_fail (si, fault::noprivs, _("You are not logged in."));
276 pippijn 1.1 return;
277     }
278     if (mask[0] == '*' && mask[1] == '!')
279     mask += 2;
280     if (strlen (mask) >= USERLEN + HOSTLEN)
281     {
282 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
283 pippijn 1.1 return;
284     }
285     p = mask;
286     while (*p != '\0')
287     {
288     if (!isprint (*p) || *p == ' ' || *p == '!')
289     {
290 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
291 pippijn 1.1 return;
292     }
293     p++;
294     }
295     host = strchr (mask, '@');
296     if (host == NULL) /* account name access masks? */
297     {
298 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
299 pippijn 1.1 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 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
312 pippijn 1.1 return;
313     }
314     else if ((strchr (host, '*') || strchr (host, '?')) && (mask[0] == '*' && mask[1] == '@'))
315     {
316     /* can't use * username and wildcarded host */
317 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
318 pippijn 1.1 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 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
325 pippijn 1.1 return;
326     }
327     if (host[0] == '*')
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     }
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 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
342 pippijn 1.1 return;
343     }
344     /* Require non-wildcard top and second level
345     * domain */
346     if (strchr (p, '?') || strchr (p, '*'))
347     {
348 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
349 pippijn 1.1 return;
350     }
351     p--;
352     while (p >= host && *p != '.')
353     {
354     if (*p == '?' || *p == '*')
355     {
356 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
357 pippijn 1.1 return;
358     }
359     p--;
360     }
361     }
362     else if (strchr (host, ':'))
363     {
364     /* No wildcarded IPs */
365     if (strchr (host, '?') || strchr (host, '*'))
366     {
367 pippijn 1.6 command_fail (si, fault::badparams, _("Too wide mask \2%s\2."), parv[1]);
368 pippijn 1.1 return;
369     }
370     }
371     else /* no '.' or ':' */
372     {
373 pippijn 1.6 command_fail (si, fault::badparams, _("Invalid mask \2%s\2."), parv[1]);
374 pippijn 1.1 return;
375     }
376     }
377 pippijn 1.5 if (mu->access_find (mask))
378 pippijn 1.1 {
379 pippijn 1.6 command_fail (si, fault::nochange, _("Mask \2%s\2 is already on your access list."), mask);
380 pippijn 1.1 return;
381     }
382 pippijn 1.5 if (mu->access_add (mask))
383 pippijn 1.1 {
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 pippijn 1.6 command_fail (si, fault::toomany, _("Your access list is full."));
389 pippijn 1.1 }
390     else if (!strcasecmp (parv[0], "DEL"))
391     {
392     if (parc < 2)
393     {
394 pippijn 1.6 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS DEL");
395     command_fail (si, fault::needmoreparams, _("Syntax: ACCESS DEL <mask>"));
396 pippijn 1.1 return;
397     }
398     mu = si->smu;
399     if (mu == NULL)
400     {
401 pippijn 1.6 command_fail (si, fault::noprivs, _("You are not logged in."));
402 pippijn 1.1 return;
403     }
404 pippijn 1.5 if ((mask = mu->access_find (parv[1])) == NULL)
405 pippijn 1.1 {
406 pippijn 1.6 command_fail (si, fault::nochange, _("Mask \2%s\2 is not on your access list."), parv[1]);
407 pippijn 1.1 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 pippijn 1.6 command_fail (si, fault::needmoreparams, STR_INVALID_PARAMS, "ACCESS");
416     command_fail (si, fault::needmoreparams, _("Syntax: ACCESS ADD|DEL|LIST [mask]"));
417 pippijn 1.1 return;
418     }
419     }