Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

clone.c

Go to the documentation of this file.
00001 
00014 /*
00015  * Copyright (c) 1996-1997 Chip Norkus
00016  * Copyright (c) 1997 Max Byrd
00017  * Copyright (c) 1997 Greg Poma
00018  * Copyright (c) 1999, 2001 James Hess
00019  * All rights reserved.
00020  *
00021  * Redistribution and use in source and binary forms, with or without
00022  * modification, are permitted provided that the following conditions
00023  * are met:
00024  * 1. Redistributions of source code must retain the above copyright
00025  *    notice, this list of conditions and the following disclaimer.
00026  * 2. Redistributions in binary form must reproduce the above copyright
00027  *    notice, this list of conditions and the following disclaimer in the
00028  *    documentation and/or other materials provided with the distribution.
00029  * 3. Neither the name of the authors nor the names of its contributors
00030  *    may be used to endorse or promote products derived from this software
00031  *    without specific prior written permission.
00032  *
00033  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
00034  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00035  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00036  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
00037  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00038  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00039  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00040  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00041  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00042  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00043  * SUCH DAMAGE.
00044  */
00045 
00046 #include "services.h"
00047 #include "nickserv.h"
00048 #include "hash.h"
00049 
00050 HostClone *firstClone = NULL;   
00051 HostClone *lastClone = NULL;    
00052 CloneRule *first_crule = NULL;  
00061 struct pending_alert
00062 {
00063     HostClone       *hc;            
00064     char            ha, ua;         
00065     int             signon_ct,      
00066                     signoff_ct;     
00067 
00068     int         signon_ct_r;
00069     int         signoff_ct_r;
00070 
00071     time_t          firstTime,      
00072                     lastAlert;      
00073 
00074     struct pending_alert *next;     
00075 } *pendingAlerts;       
00076 
00077 
00086 struct pending_alert* find_palert(HostClone *hc)
00087 {
00088     struct pending_alert *pI;
00089 
00090     for(pI = pendingAlerts; pI; pI = pI->next)
00091         if (pI->hc == hc)
00092             break;
00093     return pI;
00094 }
00095 
00100 struct pending_alert* make_palert()
00101 {
00102     struct pending_alert *pa = 
00103         (struct pending_alert *)oalloc(sizeof(pending_alert));
00104 
00105     pa->ua = pa->ha = 0;
00106     pa->hc = NULL;
00107     pa->next = NULL;
00108 
00109     return pa;
00110 }
00111 
00118 void free_palert(struct pending_alert *pArg)
00119 {
00120     FREE(pArg);
00121 }
00122 
00130 void add_palert(struct pending_alert *pArg)
00131 {
00132     struct pending_alert *pTmp;
00133 
00134     pTmp = pendingAlerts;
00135     pendingAlerts = pArg;
00136     pArg->next = pTmp;
00137 }
00138 
00146 void remove_palert(struct pending_alert *pZap)
00147 {
00148     struct pending_alert *pTmp = NULL, *pI;
00149 
00150     for(pI = pendingAlerts; pI; pI = pI->next)
00151     {
00152         if (pI == pZap) {
00153             if (pTmp)
00154                 pTmp->next = pZap->next;
00155             else
00156                 pendingAlerts = pZap->next;
00157             return;
00158         }
00159         else
00160             pTmp = pI;
00161     }
00162 }
00163 
00170 void listCloneAlerts(UserList *nick)
00171 {
00172     char *from = nick->nick;
00173     struct pending_alert *pIterator;
00174     HostClone *hc;
00175     UserClone *uc;
00176     float signonRate;
00177     int found = 0;
00178 
00179     for(pIterator = pendingAlerts; pIterator; pIterator = pIterator->next)
00180     {
00181         if (CTime == pIterator->lastAlert)
00182             continue;
00183 
00184         hc = pIterator->hc;
00185 
00186         if (pIterator->lastAlert)
00187             signonRate = (pIterator->signon_ct_r - pIterator->signoff_ct_r) /
00188                          (float)(CTime - pIterator->lastAlert);
00189         else
00190             signonRate = 1.0;
00191 
00192         if (hc->clones >= hc->trigger) {
00193             sSend(":%s NOTICE %s :CLONES(%i) *@%s   (Signon Rate: %.2f)", OperServ, from,
00194                   hc->clones, hc->host, signonRate);
00195             found = 1;
00196             continue;
00197         }
00198 
00199         for(uc = hc->firstUser; uc; uc = uc->next) {
00200             if (!(uc->uflags & CLONE_ALERT) || (uc->uflags & CLONE_OK)
00201                 || (uc->clones < uc->trigger))
00202                 continue;
00203             sSend(":%s NOTICE %s : -- %i %s@%s     (H: %.2f)", OperServ, from,
00204                   uc->clones, uc->user, hc->host, signonRate);
00205             found = 1;
00206         }
00207     }
00208 
00209     if (found == 0)
00210         sSend(":%s NOTICE %s :No clone alerts at the moment.", OperServ, from);
00211 }
00212 
00219 time_t updateCloneAlerts(time_t aval)
00220 {
00221     struct pending_alert *pIterator;
00222     float signonRate;
00223     HostClone *hc;
00224     UserClone *uc;
00225 
00226     aval += 60;
00227 
00228     for(pIterator = pendingAlerts; pIterator; pIterator = pIterator->next)
00229     {
00230         if (CTime == pIterator->lastAlert || (pIterator->lastAlert + 10) >= CTime)
00231             continue;
00232 
00233         if (pIterator->lastAlert) {
00234             if (CTime - pIterator->lastAlert != 0)
00235                 signonRate = (pIterator->signon_ct_r - pIterator->signoff_ct_r) /
00236                              (float)(CTime - pIterator->lastAlert);
00237             else
00238                 signonRate = (pIterator->signon_ct_r - pIterator->signoff_ct_r) / 1;
00239         }
00240         else
00241             signonRate = 1.0;
00242 
00243 
00244         if (pIterator->signon_ct_r == 0 && (CTime - pIterator->lastAlert) < 1200)
00245             continue;
00246 
00247         //
00248         // Don't warn more than once per 60 seconds unless
00249         // we get a significant increase.
00250         //
00251         if (((CTime - pIterator->lastAlert) < 90) &&
00252             signonRate < .03)
00253             continue;
00254 
00255         if (pIterator->lastAlert && (pIterator->signon_ct - pIterator->signoff_ct) < 0)
00256             continue;
00257 
00258         pIterator->lastAlert = CTime;
00259         pIterator->signon_ct_r = 0;
00260         pIterator->signoff_ct_r = 0;
00261 
00262         hc = pIterator->hc;
00263 
00264         if ((hc->flags & CLONE_ALERT) && !(hc->flags & CLONE_OK)
00265             && (hc->clones >= hc->trigger))
00266             sSend(":%s GLOBOPS :CLONES(%i/%i): *@%s  (%.2f cps)", OperServ, hc->clones, hc->trigger, hc->host, signonRate);
00267 
00268         for(uc = hc->firstUser; uc; uc = uc->next) {
00269             if (!(uc->uflags & CLONE_ALERT) || (uc->uflags & CLONE_OK)
00270                 || (uc->clones < uc->trigger))
00271                 continue;
00272             sSend(":%s GLOBOPS :CLONES(%i/%i): %s@%s", OperServ, uc->clones,
00273                   uc->trigger, uc->user,
00274                   hc->host);
00275         }
00276     }
00277 
00278     return aval;
00279 }
00280 
00281 /************************************************************************/
00282 
00288 CloneRule *
00289 GetCrule(char *mask)
00290 {
00291     int ct = 0, num = 0;
00292     CloneRule *crule;
00293 
00294     if (!mask)
00295         return NULL;
00296 
00297     for (crule = first_crule; crule; crule = crule->next)
00298         if (crule->mask[0] && !strcasecmp(mask, crule->mask))
00299             return crule;
00300     if (isdigit(*mask)) {
00301         num = atoi(mask);
00302         for (ct = 1, crule = first_crule; crule; crule = crule->next, ct++)
00303             if (num == ct)
00304                 return crule;
00305     }
00306     return NULL;
00307 }
00308 
00314 CloneRule *
00315 GetCruleMatch(char *host)
00316 {
00317     CloneRule *crule;
00318 
00319     if (!host)
00320         return NULL;
00321 
00322     for (crule = first_crule; crule; crule = crule->next) {
00323         if (crule->mask && !match(crule->mask, host))
00324             return crule;
00325     }
00326     return NULL;
00327 }
00328 
00333 CloneRule *
00334 NewCrule()
00335 {
00336     return (CloneRule *) oalloc(sizeof(CloneRule));
00337 }
00338 
00343 void
00344 AddCrule(CloneRule * rule, int n)
00345 {
00346     CloneRule *tmp;
00347     int ct = 0;
00348 
00349     if (!rule)
00350         return;
00351 
00352     for (tmp = first_crule; tmp; tmp = tmp->next)
00353         if (rule == tmp)
00354             return;
00355     if ((n != -2 && n < 2) || !first_crule) {
00356         /* insert at the beginning */
00357         rule->next = first_crule;
00358         first_crule = rule;
00359     } else {
00360         /* insert before point n */
00361         for (ct = 1, tmp = first_crule; tmp && tmp->next;
00362              tmp = tmp->next, ct++)
00363             if ((((ct + 1) >= n) && n != -2) || !tmp->next)
00364                 break;
00365         if (tmp) {
00366             rule->next = tmp->next;
00367             tmp->next = rule;
00368         }
00369     }
00370 }
00371 
00372 
00378 static char *
00379 MakeUserHost(char *user, char *host)
00380 {
00381     static char maskbuf[HOSTLEN + USERLEN + 10] = "";
00382     if (snprintf
00383         (maskbuf, sizeof(maskbuf), "%s@%s", user ? user : "*",
00384          host ? host : "*") == 0)
00385         maskbuf[0] = '\0';
00386     return maskbuf;
00387 }
00388 
00398 void
00399 UpdateCrule(CloneRule orig, CloneRule * rule)
00400 {
00401     HostClone *hc;
00402     UserClone *uc;
00403 
00404     if (!rule)
00405         return;
00406 
00407     for (hc = firstClone; hc; hc = hc->next) {
00408         if (
00409             (hc->trigger != orig.trigger
00410              && hc->trigger != DEFHOSTCLONETRIGGER)
00411             || (hc->flags != DEFCLONEFLAGS && hc->flags != orig.flags))
00412             continue;
00413 
00414         if (!match(rule->mask, MakeUserHost("*", hc->host))) {
00415             if (rule->trigger > 1)
00416                 hc->trigger = rule->trigger;
00417             else
00418                 hc->trigger = DEFHOSTCLONETRIGGER;
00419             hc->flags = rule->flags;
00420         }
00421         for (uc = hc->firstUser; uc; uc = uc->next) {
00422             if (uc->trigger != orig.utrigger
00423                 && uc->trigger != DEFUSERCLONETRIGGER) continue;
00424             if (!match(rule->mask, MakeUserHost(uc->user, hc->host))) {
00425                 /* Make a rule value of '0' mean "default" */
00426                 if (rule->trigger > 1)
00427                     hc->trigger = rule->trigger;
00428                 else
00429                     hc->trigger = DEFHOSTCLONETRIGGER;
00430                 if (rule->utrigger > 1)
00431                     uc->trigger = rule->utrigger;
00432                 else
00433                     uc->trigger = DEFUSERCLONETRIGGER;
00434                 hc->flags = rule->flags;
00435             }
00436         }
00437     }
00438 }
00439 
00443 void
00444 RemoveCrule(CloneRule * zap)
00445 {
00446     CloneRule *tmp, *rule;
00447     for (rule = first_crule, tmp = NULL; rule; rule = rule->next) {
00448         if (rule == zap) {
00449             if (tmp)
00450                 tmp->next = rule->next;
00451             else
00452                 first_crule = rule->next;
00453             return;
00454         } else
00455             tmp = rule;
00456     }
00457 }
00458 
00462 void
00463 initCloneData(HostClone * hc)
00464 {
00465     hc->host[0] = 0;
00466     hc->firstUser = hc->lastUser = NULL;
00467     hc->trigger = DEFHOSTCLONETRIGGER;
00468     hc->clones = 0;
00469     hc->flags = DEFCLONEFLAGS;
00470     hc->next = hc->previous = hc->hashnext = hc->hashprev = NULL;
00471 }
00472 
00485 int
00486 addClone(char *nick, char *user, char *host)
00487 {
00488     HostClone *hc;
00489     struct pending_alert *pA;
00490     HashKeyVal hashEnt;
00491     UserClone *uc;
00492     CloneRule *rule;
00493     int user_alert = 0, host_alert = 0;
00494 
00495     hc = getCloneData(host);
00496     if (!hc) {
00497         hc = (HostClone *) oalloc(sizeof(HostClone));
00498         initCloneData(hc);
00499         if ((rule = GetCruleMatch(MakeUserHost(user, host)))) {
00500             if (rule->trigger > 1)
00501                 hc->trigger = rule->trigger;
00502             hc->flags = rule->flags;
00503         }
00504         strcpy(hc->host, host);
00505         hc->clones = 1;
00506         if (!firstClone) {
00507             firstClone = hc;
00508             hc->previous = NULL;
00509         } else {
00510             lastClone->next = hc;
00511             hc->previous = lastClone;
00512         }
00513         lastClone = hc;
00514         hc->next = NULL;
00515 
00516         hashEnt = getHashKey(host) % CLONEHASHSIZE;
00517         if (!CloneHash[hashEnt].clone) {
00518             CloneHash[hashEnt].clone = hc;
00519             hc->hashprev = NULL;
00520         } else {
00521             CloneHash[hashEnt].lastclone->hashnext = hc;
00522             hc->hashprev = CloneHash[hashEnt].lastclone;
00523         }
00524         CloneHash[hashEnt].lastclone = hc;
00525         hc->hashnext = NULL;
00526     } else
00527         hc->clones++;
00528 
00529     uc = addUserClone(hc, user);
00530     if (hc->flags & CLONE_IGNOREFLAG)
00531         return 0;
00532 
00533     if (hc->clones >= hc->trigger || uc->clones >= uc->trigger) {
00534         if (hc->flags & CLONE_KILLFLAG) {
00535             if (!(rule = GetCruleMatch(MakeUserHost(user, host)))
00536                 || !rule->kill_msg)
00537                 sSend(":%s KILL %s :%s!%s (Cloning is not allowed on "
00538                       NETWORK ".)", NickServ, nick, services[1].host,
00539                       NickServ);
00540             else
00541                 sSend(":%s KILL %s :%s!%s (%s)", NickServ, nick,
00542                       services[1].host, NickServ, rule->kill_msg);
00543             delClone(user, host);
00544             return 1;
00545         } else {
00546             if ((rule = GetCruleMatch(MakeUserHost(user, host)))
00547                 && rule->warn_msg)
00548                 if (uc->clones == uc->trigger + 1
00549                     || hc->clones == hc->trigger + 1)
00550                     sSend(":%s NOTICE #%s :%s", OperServ, host,
00551                           rule->warn_msg);
00552         }
00553     }
00554     if (uc->clones >= uc->trigger && !(uc->uflags & CLONE_ALERT)) {
00555         uc->uflags &= ~(CLONE_OK);
00556         uc->uflags |= CLONE_ALERT;
00557         user_alert = 1;
00558     }
00559 
00560     if (hc->clones >= hc->trigger
00561         && !(hc->flags & CLONE_ALERT))
00562     {
00563         hc->flags &= ~(CLONE_OK);
00564         hc->flags |= CLONE_ALERT;
00565         host_alert = 1;
00566     }
00567 
00568     pA = find_palert(hc);
00569 
00570     if (pA) {
00571         pA->signon_ct++;
00572         pA->signon_ct_r++;
00573     }
00574 
00575     if (user_alert || host_alert) {
00576         if (!pA) {
00577             pA = make_palert();
00578             add_palert(pA);
00579             pA->hc = hc;
00580             pA->firstTime = time(NULL);
00581             pA->lastAlert = 0;
00582             pA->signon_ct = pA->signoff_ct = 0;
00583             pA->signon_ct_r = pA->signoff_ct_r = 0;
00584         }
00585 
00586         if (user_alert)
00587             pA->ua = 1;
00588         if (host_alert)
00589             pA->ha = 1;
00590     }
00591 
00592     (void)updateCloneAlerts(0);
00593 /*
00594     if (pA)
00595     {
00596         if (user_alert)
00597             sSend(":%s GLOBOPS :CLONES(%i): %s@%s", OperServ, uc->clones, user,
00598                   host);
00599         else if (host_alert)
00600             sSend(":%s GLOBOPS :CLONES(%i): *@%s", OperServ, hc->clones, host);
00601     }
00602 
00603 */
00604     return 0;
00605 }
00606 
00613 UserClone *
00614 addUserClone(HostClone * hc, char *user)
00615 {
00616     UserClone *uc = getUserCloneData(hc, user);
00617     CloneRule *rule;
00618 
00619     if (!uc) {
00620         uc = (UserClone *) oalloc(sizeof(UserClone));
00621         uc->user[0] = 0;
00622         uc->clones = 1;
00623         uc->trigger = DEFUSERCLONETRIGGER;
00624         if ((rule = GetCruleMatch(MakeUserHost(user, hc->host)))) {
00625             if (rule->utrigger > 0)
00626                 uc->trigger = rule->utrigger;
00632             if (hc->trigger == DEFHOSTCLONETRIGGER
00633                 && hc->flags == DEFCLONEFLAGS) {
00634                 if (rule->trigger > 1)
00635                     hc->trigger = rule->trigger;
00636                 hc->flags = rule->flags;
00637             }
00638         }
00639         strcpy(uc->user, user);
00640 
00641         if (!hc->firstUser) {
00642             hc->firstUser = uc;
00643             uc->previous = NULL;
00644         } else {
00645             hc->lastUser->next = uc;
00646             uc->previous = hc->lastUser;
00647         }
00648         hc->lastUser = uc;
00649         uc->next = NULL;
00650     } else
00651         uc->clones++;
00652 
00653     if (uc->clones >= uc->trigger)
00654         return uc;
00655     return uc;
00656 }
00657 
00662 void
00663 delClone(char *user, char *host)
00664 {
00665     HostClone *hc = getCloneData(host);
00666     if (hc) {
00667         UserClone *uc = getUserCloneData(hc, user);
00668         if (uc) {
00669             hc->clones--;
00670             uc->clones--;
00671 
00672             if (!uc->clones)
00673                 delUserClone(hc, uc);
00674             if (hc->clones) {
00675                 struct pending_alert* pA = find_palert(hc);
00676 
00677                 if (pA) {
00678                     pA->signoff_ct++;
00679                     pA->signoff_ct_r++;
00680                     if ((hc->clones < hc->trigger &&
00681                         uc->clones < uc->trigger) &&
00682                         (CTime - pA->firstTime) > 30)
00683                     {
00684                         remove_palert(pA);
00685                         free_palert(pA);
00686                         uc->uflags &= ~CLONE_ALERT;
00687                     }
00688                 }
00689             }
00690 
00691             if (!hc->clones) {
00692                 HashKeyVal hashEnt;
00693                 HostClone *tmp;
00694                 struct pending_alert* pA = find_palert(hc);
00695 
00696                 if (pA) {
00697                     remove_palert(pA);
00698                     free_palert(pA);
00699                     hc->flags &= ~CLONE_ALERT;
00700                 }
00701 
00702                 if (hc->previous)
00703                     hc->previous->next = hc->next;
00704                 else
00705                     firstClone = hc->next;
00706                 if (hc->next)
00707                     hc->next->previous = hc->previous;
00708                 else
00709                     lastClone = hc->previous;
00710                 hashEnt = getHashKey(hc->host) % CLONEHASHSIZE;
00711                 for (tmp = CloneHash[hashEnt].clone; tmp;
00712                      tmp = tmp->hashnext) {
00713                     if (tmp == hc) {
00714                         if (hc->hashprev)
00715                             hc->hashprev->hashnext = hc->hashnext;
00716                         else
00717                             CloneHash[hashEnt].clone = hc->hashnext;
00718                         if (hc->hashnext)
00719                             hc->hashnext->hashprev = hc->hashprev;
00720                         else
00721                             CloneHash[hashEnt].lastclone = hc->hashprev;
00722                     }
00723                 }
00724                 FREE(hc);
00725             }
00726         }
00727     }
00728 }
00729 
00733 void
00734 delUserClone(HostClone * hc, UserClone * uc)
00735 {
00736     if (uc->previous)
00737         uc->previous->next = uc->next;
00738     else
00739         hc->firstUser = uc->next;
00740     if (uc->next)
00741         uc->next->previous = uc->previous;
00742     else
00743         hc->lastUser = uc->previous;
00744 
00745     FREE(uc);
00746 }
00747 
00751 HostClone *
00752 getCloneData(char *host)
00753 {
00754     HashKeyVal hashEnt;
00755     hashEnt = getHashKey(host) % CLONEHASHSIZE;
00756     if (!CloneHash[hashEnt].clone)
00757         return NULL;
00758     else {
00759         HostClone *tmp;
00760         for (tmp = CloneHash[hashEnt].clone; tmp; tmp = tmp->hashnext) {
00761             if (!strcasecmp(host, tmp->host))
00762                 return tmp;
00763         }
00764         return NULL;
00765     }
00766 }
00767 
00772 UserClone *
00773 getUserCloneData(HostClone * hc, char *user)
00774 {
00775     UserClone *tmp;
00776 
00777     for (tmp = hc->firstUser; tmp; tmp = tmp->next) {
00778         if (!strcasecmp(tmp->user, user))
00779             return tmp;
00780     }
00781     return NULL;
00782 }
00783 
00784 /************************************************************************/

Generated at Sat Oct 25 20:56:07 2003 for Services using Doxygen.
Services Copyr. 1996-2001 Chip Norkus, Max Byrd, Greg Poma, Michael Graff, James Hess, Dafydd James. All rights reserved See LICENSE for licensing information.