ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/nickserv/access.C
Revision: 1.3
Committed: Sat Jul 21 13:23:20 2007 UTC (19 years, 2 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.2: +2 -2 lines
Log Message:
- added rcsid to some files
- more documentation tweaks
- made most protocol commands local to phandler.C
- added ircd metadata (inspircd only for now)
- added inspircd swhois support

File Contents

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