ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/src/function.C
Revision: 1.6
Committed: Wed Sep 5 11:23:15 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.5: +2 -2 lines
Log Message:
removed GPLed code and put license back to BSD

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