ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/src/function.C
Revision: 1.7
Committed: Sun Sep 9 20:05:52 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +3 -10 lines
Log Message:
- changed configurations to the c++ stdlib
- more #defines to enum
- removed getopt.h and link.h from the system as they were unused
- reworked logstreams
- added an itoa with old syntax
- made klines objects
- moved some global variables into appropriate classes
- fixed boost.foreach's compiler workaround #if's
- allow other files to add exceptions with ADD_EXCEPTION
- changed mynick_t to c++ object
- moved servers.h out of atheme.h
- corrected PING from inspircd 1.2

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * function.C: Miscellaneous functions.
3 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
4 pippijn 1.1 *
5 pippijn 1.7 * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team (http://ermyth.schmorp.de)
6 pippijn 1.4 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
7 pippijn 1.1 */
8    
9 pippijn 1.7 static char const rcsid[] = "$Id: function.C,v 1.6 2007-09-05 11:23:15 pippijn Exp $";
10 pippijn 1.1
11     #include "atheme.h"
12 pippijn 1.7 #include <common/util.h>
13 pippijn 1.4 #include <ermyth/crypto.h>
14 pippijn 1.1 #include <account/mychan.h>
15     #include <account/chanacs.h>
16     #include <account/myuser.h>
17 pippijn 1.4 #include <common/random.h>
18 pippijn 1.1
19     char ch[27] = "abcdefghijklmnopqrstuvwxyz";
20    
21 pippijn 1.4 /* This function uses allocates memory.
22 pippijn 1.1 * You MUST free the result when you are done with it!
23     */
24     char *
25     gen_pw (int sz)
26     {
27     int i;
28 pippijn 1.5 char *buf = salloc<char> (sz + 1); /* padding */
29 pippijn 1.1
30     for (i = 0; i < sz; i++)
31     {
32 pippijn 1.4 buf[i] = ch[gen_rand32 () % 26];
33 pippijn 1.1 }
34    
35     buf[sz] = 0;
36    
37     return buf;
38     }
39    
40     #ifdef HAVE_GETTIMEOFDAY
41     /* starts a timer */
42     void
43     s_time (struct timeval *sttime)
44     {
45     gettimeofday (sttime, NULL);
46     }
47     #endif
48    
49     #ifdef HAVE_GETTIMEOFDAY
50     /* ends a timer */
51     void
52     e_time (struct timeval sttime, struct timeval *ttime)
53     {
54     struct timeval now;
55    
56     gettimeofday (&now, NULL);
57     timersub (&now, &sttime, ttime);
58     }
59     #endif
60    
61     #ifdef HAVE_GETTIMEOFDAY
62     /* translates microseconds into miliseconds */
63     int
64     tv2ms (struct timeval *tv)
65     {
66     return (tv->tv_sec * 1000) + (int) (tv->tv_usec / 1000);
67     }
68     #endif
69    
70     /* replaces tabs with a single ASCII 32 */
71     void
72     tb2sp (char *line)
73     {
74     char *c;
75    
76     while ((c = strchr (line, '\t')))
77     *c = ' ';
78     }
79    
80     /* replace all occurances of 'oldstr' with 'newstr' */
81     char *
82 pippijn 1.4 replace (char *s, int size, char const * const oldstr, char const * const newstr)
83 pippijn 1.1 {
84     char *ptr = s;
85     int left = strlen (s);
86     int avail = size - (left + 1);
87     int oldstrlen = strlen (oldstr);
88     int newstrlen = strlen (newstr);
89     int diff = newstrlen - oldstrlen;
90    
91     while (left >= oldstrlen)
92     {
93     if (strncmp (ptr, oldstr, oldstrlen))
94     {
95     left--;
96     ptr++;
97     continue;
98     }
99    
100     if (diff > avail)
101     break;
102    
103     if (diff != 0)
104     memmove (ptr + oldstrlen + diff, ptr + oldstrlen, left + 1);
105    
106     memcpy (ptr, newstr, newstrlen);
107     ptr += newstrlen;
108     left -= oldstrlen;
109     }
110    
111     return s;
112     }
113    
114     /* return the time elapsed since an event */
115     char *
116     time_ago (time_t event)
117     {
118     static char ret[128];
119     int years, weeks, days, hours, minutes, seconds;
120    
121     event = NOW - event;
122     years = weeks = days = hours = minutes = seconds = 0;
123    
124     while (event >= 60 * 60 * 24 * 365)
125     {
126     event -= 60 * 60 * 24 * 365;
127     years++;
128     }
129     while (event >= 60 * 60 * 24 * 7)
130     {
131     event -= 60 * 60 * 24 * 7;
132     weeks++;
133     }
134     while (event >= 60 * 60 * 24)
135     {
136     event -= 60 * 60 * 24;
137     days++;
138     }
139     while (event >= 60 * 60)
140     {
141     event -= 60 * 60;
142     hours++;
143     }
144     while (event >= 60)
145     {
146     event -= 60;
147     minutes++;
148     }
149    
150     seconds = event;
151    
152     if (years)
153     snprintf (ret, sizeof (ret), "%d year%s, %d week%s, %d day%s, %02d:%02d:%02d", years, years == 1 ? "" : "s", weeks, weeks == 1 ? "" : "s", days, days == 1 ? "" : "s", hours, minutes, seconds);
154     else if (weeks)
155     snprintf (ret, sizeof (ret), "%d week%s, %d day%s, %02d:%02d:%02d", weeks, weeks == 1 ? "" : "s", days, days == 1 ? "" : "s", hours, minutes, seconds);
156     else if (days)
157     snprintf (ret, sizeof (ret), "%d day%s, %02d:%02d:%02d", days, days == 1 ? "" : "s", hours, minutes, seconds);
158     else if (hours)
159     snprintf (ret, sizeof (ret), "%d hour%s, %d minute%s, %d second%s", hours, hours == 1 ? "" : "s", minutes, minutes == 1 ? "" : "s", seconds, seconds == 1 ? "" : "s");
160     else if (minutes)
161     snprintf (ret, sizeof (ret), "%d minute%s, %d second%s", minutes, minutes == 1 ? "" : "s", seconds, seconds == 1 ? "" : "s");
162     else
163     snprintf (ret, sizeof (ret), "%d second%s", seconds, seconds == 1 ? "" : "s");
164    
165     return ret;
166     }
167    
168     char *
169     timediff (time_t seconds)
170     {
171     static char buf[BUFSIZE];
172     long unsigned days, hours, minutes;
173    
174     days = seconds / 86400;
175     seconds %= 86400;
176     hours = seconds / 3600;
177     hours %= 3600;
178     minutes = seconds / 60;
179     minutes %= 60;
180     seconds %= 60;
181    
182     snprintf (buf, sizeof (buf), "%lu day%s, %lu:%02lu:%02lu", days, (days == 1) ? "" : "s", hours, minutes, (long unsigned) seconds);
183    
184     return buf;
185     }
186    
187     /* generate a random number, for use as a key */
188     unsigned long
189     makekey (void)
190     {
191     unsigned long k;
192    
193 pippijn 1.4 k = gen_rand32 () & 0x7FFFFFFF;
194 pippijn 1.1
195     /* shorten or pad it to 9 digits */
196     if (k > 1000000000)
197     k = k - 1000000000;
198     if (k < 100000000)
199     k = k + 100000000;
200    
201     return k;
202     }
203    
204     bool
205     is_internal_client (user_t *u)
206     {
207     return (u && (!u->server || u->server == me.me));
208     }
209    
210     int
211     validemail (char *email)
212     {
213     int i, valid = 1, chars = 0;
214    
215     /* sane length */
216     if (strlen (email) >= EMAILLEN)
217     valid = 0;
218    
219     /* make sure it has @ and . */
220     if (!strchr (email, '@') || !strchr (email, '.'))
221     valid = 0;
222    
223     /* check for other bad things */
224     if (strchr (email, '\'') || strchr (email, ' ') || strchr (email, ',') || strchr (email, '$') || strchr (email, '/') || strchr (email, ';') || strchr (email, '<') || strchr (email, '>') || strchr (email, '&') || strchr (email, '"'))
225     valid = 0;
226    
227     /* make sure there are at least 6 characters besides the above
228     * mentioned @ and .
229     */
230     for (i = strlen (email) - 1; i > 0; i--)
231     if (!(email[i] == '@' || email[i] == '.'))
232     chars++;
233    
234     if (chars < 6)
235     valid = 0;
236    
237     return valid;
238     }
239    
240     bool
241     validhostmask (char *host)
242     {
243 pippijn 1.4 char *p, *q;
244    
245 pippijn 1.1 if (strchr (host, ' '))
246     return false;
247    
248 pippijn 1.4 /* make sure it has ! and @ in that order and only once */
249     p = strchr (host, '!');
250     q = strchr (host, '@');
251     if (p == NULL || q == NULL || p > q || strchr (p + 1, '!') || strchr (q + 1, '@'))
252 pippijn 1.1 return false;
253    
254     /* XXX this NICKLEN is too long */
255     if (strlen (host) > NICKLEN + USERLEN + HOSTLEN + 1)
256     return false;
257    
258     if (host[0] == ',' || host[0] == '-' || host[0] == '#' || host[0] == '@' || host[0] == '!')
259     return false;
260    
261     return true;
262     }
263    
264     /* send the specified type of email.
265     *
266     * u is whoever caused this to be called, the corresponding service
267     * in case of xmlrpc
268     * type is EMAIL_*, see include/tools.h
269     * mu is the recipient user
270     * param depends on type, also see include/tools.h
271     */
272     int
273 pippijn 1.4 sendemail (user_t *u, int type, myuser_t *mu, char const * const param)
274 pippijn 1.1 {
275     char *email, *date = NULL;
276     char cmdbuf[512], timebuf[256], to[128], from[128], subject[128];
277     FILE *out;
278     time_t t;
279     struct tm tm;
280     int pipfds[2];
281     pid_t pid;
282     int status;
283     int rc;
284     static time_t period_start = 0, lastwallops = 0;
285     static unsigned emailcount = 0;
286    
287     if (u == NULL || mu == NULL)
288     return 0;
289    
290     if (me.mta == NULL)
291     {
292     if (type != EMAIL_MEMO && !is_internal_client (u))
293     notice (opersvs.me ? opersvs.nick : me.name, u->nick, "Sending email is administratively disabled.");
294     return 0;
295     }
296    
297     if (type == EMAIL_SETEMAIL)
298     {
299     /* special case for e-mail change */
300 pippijn 1.6 metadata *md = mu->find_metadata ("private:verify:emailchg:newemail");
301 pippijn 1.1
302     if (md && md->value)
303     email = md->value;
304     else /* should NEVER happen */
305     {
306     slog (LG_ERROR, "sendemail(): got email change request, but newemail unset!");
307     return 0;
308     }
309     }
310     else
311     email = mu->email;
312    
313     if (NOW - period_start > me.emailtime)
314     {
315     emailcount = 0;
316     period_start = NOW;
317     }
318     emailcount++;
319     if (emailcount > me.emaillimit)
320     {
321     if (NOW - lastwallops > 60)
322     {
323     wallops (_("Rejecting email for %s[%s@%s] due to too high load (type %d to %s <%s>)"), u->nick, u->user, u->vhost, type, mu->name, email);
324     slog (LG_ERROR, "sendemail(): rejecting email for %s[%s@%s] (%s) due to too high load (type %d to %s <%s>)", u->nick, u->user, u->vhost, u->ip[0] ? u->ip : u->host, type, mu->name, email);
325     lastwallops = NOW;
326     }
327     return 0;
328     }
329    
330     slog (LG_INFO, "sendemail(): email for %s[%s@%s] (%s) type %d to %s <%s>", u->nick, u->user, u->vhost, u->ip[0] ? u->ip : u->host, type, mu->name, email);
331    
332     /* set up the email headers */
333     time (&t);
334     tm = *gmtime (&t);
335     strftime (timebuf, sizeof (timebuf) - 1, "%a, %d %b %Y %H:%M:%S +0000", &tm);
336    
337     date = timebuf;
338    
339     snprintf (from, sizeof from, "%s automailer <noreply.%s>", me.netname, me.adminemail);
340     snprintf (to, sizeof to, "%s <%s>", mu->name, email);
341    
342     strlcpy (subject, me.netname, sizeof subject);
343     strlcat (subject, " ", sizeof subject);
344     if (type == EMAIL_REGISTER)
345     if (nicksvs.no_nick_ownership)
346     strlcat (subject, "Account Registration", sizeof subject);
347     else
348     strlcat (subject, "Nickname Registration", sizeof subject);
349     else if (type == EMAIL_SENDPASS || type == EMAIL_SETPASS)
350     strlcat (subject, "Password Retrieval", sizeof subject);
351     else if (type == EMAIL_SETEMAIL)
352     strlcat (subject, "Change Email Confirmation", sizeof subject);
353     else if (type == EMAIL_MEMO)
354     strlcat (subject, "New memo", sizeof subject);
355    
356     /* now set up the email */
357     sprintf (cmdbuf, "%s %s", me.mta, email);
358     if (pipe (pipfds) < 0)
359     return 0;
360     switch (pid = fork ())
361     {
362     case -1:
363     return 0;
364     case 0:
365     close (pipfds[1]);
366     dup2 (pipfds[0], 0);
367     switch (fork ())
368     {
369     /* fork again to avoid zombies -- jilles */
370     case -1:
371     _exit (255);
372     case 0:
373     execl ("/bin/sh", "sh", "-c", cmdbuf, NULL);
374     _exit (255);
375     default:
376     _exit (0);
377     }
378     }
379     close (pipfds[0]);
380     waitpid (pid, &status, 0);
381     out = fdopen (pipfds[1], "w");
382    
383     fprintf (out, "From: %s\n", from);
384     fprintf (out, "To: %s\n", to);
385     fprintf (out, "Subject: %s\n", subject);
386     fprintf (out, "Date: %s\n\n", date);
387    
388     fprintf (out, "%s,\n\n", mu->name);
389    
390     if (type == EMAIL_REGISTER)
391     {
392     fprintf (out, "In order to complete your registration, you must send the following\ncommand on IRC:\n");
393     fprintf (out, "/MSG %s VERIFY REGISTER %s %s\n\n", nicksvs.nick, mu->name, param);
394     fprintf (out, "Thank you for registering your %s on the %s IRC " "network!\n\n", (nicksvs.no_nick_ownership ? "account" : "nickname"), me.netname);
395     }
396     else if (type == EMAIL_SENDPASS)
397     {
398     fprintf (out, "Someone has requested the password for %s be sent to the\n" "corresponding email address. If you did not request this action\n" "please let us know.\n\n", mu->name);
399     fprintf (out, "The password for %s is %s. Please write this down for " "future reference.\n\n", mu->name, param);
400     }
401     else if (type == EMAIL_SETEMAIL)
402     {
403     fprintf (out, "In order to complete your email change, you must send\n" "the following command on IRC:\n");
404     fprintf (out, "/MSG %s VERIFY EMAILCHG %s %s\n\n", nicksvs.nick, mu->name, param);
405     }
406     else if (type == EMAIL_MEMO)
407     {
408     if (u->myuser != NULL)
409     fprintf (out, "You have a new memo from %s.\n\n", u->myuser->name);
410     else
411     /* shouldn't happen */
412     fprintf (out, "You have a new memo from %s (unregistered?).\n\n", u->nick);
413     fprintf (out, "%s\n\n", param);
414     }
415     else if (type == EMAIL_SETPASS)
416     {
417     fprintf (out, "In order to set a new password, you must send\n" "the following command on IRC:\n");
418     fprintf (out, "/MSG %s SETPASS %s %s <password>\nwhere <password> is your desired new password.\n\n", nicksvs.nick, mu->name, param);
419     }
420    
421     fprintf (out, "Thank you for your interest in the %s IRC network.\n", me.netname);
422     if (u->server != me.me)
423     fprintf (out, "\nThis email was sent due to a command from %s[%s@%s]\nat %s.\n", u->nick, u->user, u->vhost, date);
424     fprintf (out, "If this message is spam, please contact %s\nwith a full copy.\n", me.adminemail);
425     fprintf (out, ".\n");
426     rc = 1;
427     if (ferror (out))
428     rc = 0;
429     if (fclose (out) < 0)
430     rc = 0;
431     if (rc == 0)
432     slog (LG_ERROR, "sendemail(): mta failure");
433     return rc;
434     }
435    
436     /* various access level checkers */
437     bool
438 pippijn 1.4 myuser_t::is_founder (mychan_t *mc) const
439 pippijn 1.1 {
440 pippijn 1.4 if (chanacs_find (mc, this, CA_FOUNDER))
441 pippijn 1.1 return true;
442    
443     return false;
444     }
445    
446     bool
447 pippijn 1.4 myuser_t::should_owner (mychan_t *mc) const
448 pippijn 1.1 {
449 pippijn 1.4 if (MC_NOOP & mc->flags)
450 pippijn 1.1 return false;
451    
452 pippijn 1.4 if (MU_NOOP & flags)
453 pippijn 1.1 return false;
454    
455 pippijn 1.4 if (is_founder (mc))
456 pippijn 1.1 return true;
457    
458     return false;
459     }
460    
461     bool
462 pippijn 1.4 myuser_t::should_protect (mychan_t *mc) const
463 pippijn 1.1 {
464 pippijn 1.4 if (MC_NOOP & mc->flags)
465 pippijn 1.1 return false;
466    
467 pippijn 1.4 if (MU_NOOP & flags)
468 pippijn 1.1 return false;
469    
470 pippijn 1.4 if (chanacs_find (mc, this, CA_SET))
471 pippijn 1.1 return true;
472    
473     return false;
474     }
475    
476     bool
477     is_ircop (user_t *user)
478     {
479     if (UF_IRCOP & user->flags)
480     return true;
481    
482     return false;
483     }
484    
485     bool
486     is_admin (user_t *user)
487     {
488     if (UF_ADMIN & user->flags)
489     return true;
490    
491     return false;
492     }
493    
494     void
495 pippijn 1.4 myuser_t::set_password (char const * const newpassword)
496 pippijn 1.1 {
497 pippijn 1.4 if (newpassword == NULL)
498 pippijn 1.1 return;
499    
500     /* if we can, try to crypt it */
501 pippijn 1.4 if (crypto::handler::loaded)
502 pippijn 1.1 {
503 pippijn 1.4 flags |= MU_CRYPTPASS;
504     strlcpy (pass, crypter->crypt (newpassword, crypto::gen_salt ()), NICKLEN);
505 pippijn 1.1 }
506     else
507     {
508 pippijn 1.4 flags &= ~MU_CRYPTPASS; /* just in case */
509     strlcpy (pass, newpassword, NICKLEN);
510 pippijn 1.1 }
511     }
512    
513     bool
514 pippijn 1.4 myuser_t::verify_password (char const * const password) const
515 pippijn 1.1 {
516 pippijn 1.4 if (password == NULL)
517 pippijn 1.1 return false;
518    
519 pippijn 1.4 if (flags & MU_CRYPTPASS)
520     if (crypto::handler::loaded)
521     return crypto::verify_password (password, pass);
522 pippijn 1.1 else
523     { /* not good! */
524     slog (LG_ERROR, "check_password(): can't check crypted password -- no crypto module!");
525     return false;
526     }
527     else
528 pippijn 1.4 return (strcmp (pass, password) == 0);
529 pippijn 1.1 }
530    
531 pippijn 1.4 char const *
532 pippijn 1.1 sbytes (float x)
533     {
534     if (x > 1073741824.0)
535     return "GB";
536    
537     else if (x > 1048576.0)
538     return "MB";
539    
540     else if (x > 1024.0)
541     return "KB";
542    
543     return "B";
544     }
545    
546     float
547     bytes (float x)
548     {
549     if (x > 1073741824.0)
550     return (x / 1073741824.0);
551    
552     if (x > 1048576.0)
553     return (x / 1048576.0);
554    
555     if (x > 1024.0)
556     return (x / 1024.0);
557    
558     return x;
559     }