operserv.c

Go to the documentation of this file.
00001 /* OperServ functions.
00002  *
00003  * (C) 2003-2008 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  * $Id: operserv.c 1385 2008-02-12 14:56:33Z drstein $
00012  *
00013  */
00014 
00015 #include "services.h"
00016 #include "pseudo.h"
00017 
00018 /*************************************************************************/
00019 
00020 /* List of Services administrators */
00021 SList servadmins;
00022 /* List of Services operators */
00023 SList servopers;
00024 /* AKILL, SGLINE, SQLINE and SZLINE lists */
00025 SList akills, sglines, sqlines, szlines;
00026 
00027 /*************************************************************************/
00028 
00029 static int compare_adminlist_entries(SList * slist, void *item1,
00030                                      void *item2);
00031 static int compare_operlist_entries(SList * slist, void *item1,
00032                                     void *item2);
00033 static void free_adminlist_entry(SList * slist, void *item);
00034 static void free_operlist_entry(SList * slist, void *item);
00035 
00036 static int is_akill_entry_equal(SList * slist, void *item1, void *item2);
00037 static void free_akill_entry(SList * slist, void *item);
00038 static int is_sgline_entry_equal(SList * slist, void *item1, void *item2);
00039 static void free_sgline_entry(SList * slist, void *item);
00040 static int is_sqline_entry_equal(SList * slist, void *item1, void *item2);
00041 static void free_sqline_entry(SList * slist, void *item);
00042 static int is_szline_entry_equal(SList * slist, void *item1, void *item2);
00043 static void free_szline_entry(SList * slist, void *item);
00044 
00045 time_t DefContimer;
00046 int DefConModesSet = 0;
00047 char *defconReverseModes(const char *modes);
00048 
00049 uint32 DefConModesOn;           /* Modes to be enabled during DefCon */
00050 uint32 DefConModesOff;          /* Modes to be disabled during DefCon */
00051 ChannelInfo DefConModesCI;      /* ChannelInfo containg params for locked modes
00052                                  * during DefCon; I would've done this nicer if i
00053                                  * could, but all damn mode functions require a
00054                                  * ChannelInfo struct! --gdex
00055                                  */
00056 
00057 
00058 #ifdef DEBUG_COMMANDS
00059 static int do_matchwild(User * u);
00060 #endif
00061 
00062 void moduleAddOperServCmds(void);
00063 /*************************************************************************/
00064 
00065 /* Options for the lists */
00066 SListOpts akopts = { 0, NULL, &is_akill_entry_equal, &free_akill_entry };
00067 SListOpts saopts = { SLISTF_SORT, &compare_adminlist_entries, NULL,
00068     &free_adminlist_entry
00069 };
00070 
00071 SListOpts sgopts = { 0, NULL, &is_sgline_entry_equal, &free_sgline_entry };
00072 SListOpts soopts =
00073     { SLISTF_SORT, &compare_operlist_entries, NULL, &free_operlist_entry };
00074 SListOpts sqopts =
00075     { SLISTF_SORT, NULL, &is_sqline_entry_equal, &free_sqline_entry };
00076 SListOpts szopts = { 0, NULL, &is_szline_entry_equal, &free_szline_entry };
00077 
00078 /*************************************************************************/
00079 /* *INDENT-OFF* */
00080 void moduleAddOperServCmds(void) {
00081 #ifdef DEBUG_COMMANDS
00082     Command *c;
00083 #endif
00084     
00085     modules_core_init(OperServCoreNumber, OperServCoreModules); 
00086 
00087 #ifdef DEBUG_COMMANDS
00088     c = createCommand("LISTTIMERS", send_timeout_list,  is_services_root, -1,-1,-1,-1,-1); addCoreCommand(OPERSERV,c);
00089     c = createCommand("MATCHWILD",  do_matchwild,       is_services_root, -1,-1,-1,-1,-1); addCoreCommand(OPERSERV,c);
00090 #endif
00091 }
00092 
00093 /* *INDENT-ON* */
00094 /*************************************************************************/
00095 /*************************************************************************/
00096 
00097 /* OperServ initialization. */
00098 
00099 void os_init(void)
00100 {
00101     moduleAddOperServCmds();
00102 
00103     /* Initialization of the lists */
00104     slist_init(&servadmins);
00105     servadmins.opts = &saopts;
00106     slist_init(&servopers);
00107     servopers.opts = &soopts;
00108 
00109     slist_init(&akills);
00110     akills.opts = &akopts;
00111 
00112     if (ircd->sgline) {
00113         slist_init(&sglines);
00114         sglines.opts = &sgopts;
00115     }
00116     if (ircd->sqline) {
00117         slist_init(&sqlines);
00118         sqlines.opts = &sqopts;
00119     }
00120     if (ircd->szline) {
00121         slist_init(&szlines);
00122         szlines.opts = &szopts;
00123     }
00124 }
00125 
00126 /*************************************************************************/
00127 
00128 /* Main OperServ routine. */
00129 
00130 void operserv(User * u, char *buf)
00131 {
00132     char *cmd;
00133     char *s;
00134 
00135     alog("%s: %s: %s", s_OperServ, u->nick, buf);
00136 
00137     cmd = strtok(buf, " ");
00138     if (!cmd) {
00139         return;
00140     } else if (stricmp(cmd, "\1PING") == 0) {
00141         if (!(s = strtok(NULL, ""))) {
00142             s = "";
00143         }
00144         anope_cmd_ctcp(s_OperServ, u->nick, "PING %s", s);
00145     } else {
00146         mod_run_cmd(s_OperServ, u, OPERSERV, cmd);
00147     }
00148 }
00149 
00150 /*************************************************************************/
00151 /**************************** Privilege checks ***************************/
00152 /*************************************************************************/
00153 
00154 /* Load old AKILL data. */
00155 
00156 #define SAFE(x) do {                                    \
00157     if ((x) < 0) {                                      \
00158         if (!forceload)                                 \
00159             fatal("Read error on %s", AutokillDBName);  \
00160         break;                                          \
00161     }                                                   \
00162 } while (0)
00163 
00164 static void load_old_akill(void)
00165 {
00166     dbFILE *f;
00167     int i, j;
00168     uint16 tmp16;
00169     uint32 tmp32;
00170     char buf[NICKMAX], mask2[BUFSIZE], *mask, *s;
00171     Akill *ak, *entry;
00172 
00173     if (!
00174         (f =
00175          open_db("AKILL", AutokillDBName ? AutokillDBName : "akill.db",
00176                  "r", 9)))
00177         return;
00178 
00179     get_file_version(f);
00180 
00181     read_int16(&tmp16, f);
00182     slist_setcapacity(&akills, tmp16);
00183 
00184     for (j = 0; j < akills.capacity; j++) {
00185         ak = scalloc(sizeof(Akill), 1);
00186 
00187         SAFE(read_string(&mask, f));
00188         s = strchr(mask, '@');
00189         *s = 0;
00190         s++;
00191         ak->user = sstrdup(mask);
00192         ak->host = sstrdup(s);
00193         SAFE(read_string(&ak->reason, f));
00194         SAFE(read_buffer(buf, f));
00195         if (!*buf)
00196             ak->by = sstrdup("<unknown>");
00197         else
00198             ak->by = sstrdup(buf);
00199         SAFE(read_int32(&tmp32, f));
00200         ak->seton = tmp32 ? tmp32 : time(NULL);
00201         SAFE(read_int32(&tmp32, f));
00202         ak->expires = tmp32;
00203 
00204         /* Sanity checks *sigh* */
00205 
00206         /* No nicknames allowed! */
00207         if (strchr(ak->user, '!')) {
00208             anope_cmd_remove_akill(ak->user, ak->host);
00209             free(ak);
00210             continue;
00211         }
00212 
00213         snprintf(mask2, sizeof(mask2), "%s@%s", ak->user, ak->host);
00214 
00215         /* Is the mask already in the AKILL list? */
00216         if (slist_indexof(&akills, mask2) != -1) {
00217             free(ak);
00218             continue;
00219         }
00220 
00221         /* Checks whether there is an AKILL that already covers
00222          * the one we want to add, and whether there are AKILLs
00223          * that would be covered by this one. Expiry time
00224          * does *also* matter.
00225          */
00226 
00227         if (akills.count > 0) {
00228 
00229             for (i = akills.count - 1; i >= 0; i--) {
00230 
00231                 char amask[BUFSIZE];
00232 
00233                 entry = akills.list[i];
00234 
00235                 if (!entry)
00236                     continue;
00237 
00238                 snprintf(amask, sizeof(amask), "%s@%s", entry->user,
00239                          entry->host);
00240 
00241                 if (match_wild_nocase(amask, mask2)
00242                     && (entry->expires >= ak->expires
00243                         || entry->expires == 0)) {
00244                     anope_cmd_remove_akill(ak->user, ak->host);
00245                     free(ak);
00246                     ak = NULL;
00247                     break;
00248                 }
00249 
00250                 if (match_wild_nocase(mask2, amask)
00251                     && (entry->expires <= ak->expires || ak->expires == 0))
00252                     slist_delete(&akills, i);
00253             }
00254 
00255         }
00256 
00257         if (ak)
00258             slist_add(&akills, ak);
00259     }
00260 
00261     close_db(f);
00262 }
00263 
00264 #undef SAFE
00265 
00266 /* Load OperServ data. */
00267 
00268 #define SAFE(x) do {                                    \
00269     if ((x) < 0) {                                      \
00270         if (!forceload)                                 \
00271             fatal("Read error on %s", OperDBName);      \
00272         failed = 1;                                     \
00273         break;                                          \
00274     }                                                   \
00275 } while (0)
00276 
00277 void load_os_dbase(void)
00278 {
00279     dbFILE *f;
00280     int16 i, ver;
00281     uint16 tmp16, n;
00282     uint32 tmp32;
00283     char *s;
00284     int failed = 0;
00285 
00286     if (!(f = open_db(s_OperServ, OperDBName, "r", OPER_VERSION)))
00287         return;
00288 
00289     ver = get_file_version(f);
00290 
00291     if (ver <= 9) {
00292         NickAlias *na;
00293 
00294         SAFE(read_int16(&n, f));
00295         for (i = 0; i < n && !failed; i++) {
00296             SAFE(read_string(&s, f));
00297             if (s) {
00298                 na = findnick(s);
00299                 if (na) {
00300                     na->nc->flags |= NI_SERVICES_ADMIN;
00301                     if (slist_indexof(&servadmins, na) == -1)
00302                         slist_add(&servadmins, na);
00303                 }
00304                 free(s);
00305             }
00306         }
00307         if (!failed)
00308             SAFE(read_int16(&n, f));
00309         for (i = 0; i < n && !failed; i++) {
00310             SAFE(read_string(&s, f));
00311             if (s) {
00312                 na = findnick(s);
00313                 if (na) {
00314                     na->nc->flags |= NI_SERVICES_OPER;
00315                     if (slist_indexof(&servopers, na) == -1)
00316                         slist_add(&servopers, na);
00317                 }
00318                 free(s);
00319             }
00320         }
00321     }
00322 
00323     if (ver >= 7) {
00324         uint32 tmp32;
00325         SAFE(read_int32(&maxusercnt, f));
00326         SAFE(read_int32(&tmp32, f));
00327         maxusertime = tmp32;
00328     }
00329 
00330     if (ver <= 10)
00331         load_old_akill();
00332     else {
00333         Akill *ak;
00334 
00335         read_int16(&tmp16, f);
00336         slist_setcapacity(&akills, tmp16);
00337 
00338         for (i = 0; i < akills.capacity; i++) {
00339             ak = scalloc(sizeof(Akill), 1);
00340 
00341             SAFE(read_string(&ak->user, f));
00342             SAFE(read_string(&ak->host, f));
00343             SAFE(read_string(&ak->by, f));
00344             SAFE(read_string(&ak->reason, f));
00345             SAFE(read_int32(&tmp32, f));
00346             ak->seton = tmp32;
00347             SAFE(read_int32(&tmp32, f));
00348             ak->expires = tmp32;
00349 
00350             slist_add(&akills, ak);
00351         }
00352     }
00353 
00354     if (ver >= 11) {
00355         SXLine *sx;
00356 
00357         read_int16(&tmp16, f);
00358         slist_setcapacity(&sglines, tmp16);
00359 
00360         for (i = 0; i < sglines.capacity; i++) {
00361             sx = scalloc(sizeof(SXLine), 1);
00362 
00363             SAFE(read_string(&sx->mask, f));
00364             SAFE(read_string(&sx->by, f));
00365             SAFE(read_string(&sx->reason, f));
00366             SAFE(read_int32(&tmp32, f));
00367             sx->seton = tmp32;
00368             SAFE(read_int32(&tmp32, f));
00369             sx->expires = tmp32;
00370 
00371             slist_add(&sglines, sx);
00372         }
00373 
00374         if (ver >= 13) {
00375             read_int16(&tmp16, f);
00376             slist_setcapacity(&sqlines, tmp16);
00377 
00378             for (i = 0; i < sqlines.capacity; i++) {
00379                 sx = scalloc(sizeof(SXLine), 1);
00380 
00381                 SAFE(read_string(&sx->mask, f));
00382                 SAFE(read_string(&sx->by, f));
00383                 SAFE(read_string(&sx->reason, f));
00384                 SAFE(read_int32(&tmp32, f));
00385                 sx->seton = tmp32;
00386                 SAFE(read_int32(&tmp32, f));
00387                 sx->expires = tmp32;
00388 
00389                 slist_add(&sqlines, sx);
00390             }
00391         }
00392 
00393         read_int16(&tmp16, f);
00394         slist_setcapacity(&szlines, tmp16);
00395 
00396         for (i = 0; i < szlines.capacity; i++) {
00397             sx = scalloc(sizeof(SXLine), 1);
00398 
00399             SAFE(read_string(&sx->mask, f));
00400             SAFE(read_string(&sx->by, f));
00401             SAFE(read_string(&sx->reason, f));
00402             SAFE(read_int32(&tmp32, f));
00403             sx->seton = tmp32;
00404             SAFE(read_int32(&tmp32, f));
00405             sx->expires = tmp32;
00406 
00407             slist_add(&szlines, sx);
00408         }
00409     }
00410 
00411     close_db(f);
00412 
00413 }
00414 
00415 #undef SAFE
00416 
00417 /*************************************************************************/
00418 
00419 /* Save OperServ data. */
00420 
00421 #define SAFE(x) do {                                            \
00422     if ((x) < 0) {                                              \
00423         restore_db(f);                                          \
00424         log_perror("Write error on %s", OperDBName);            \
00425         if (time(NULL) - lastwarn > WarningTimeout) {           \
00426             anope_cmd_global(NULL, "Write error on %s: %s", OperDBName, \
00427                         strerror(errno));                       \
00428             lastwarn = time(NULL);                              \
00429         }                                                       \
00430         return;                                                 \
00431     }                                                           \
00432 } while (0)
00433 
00434 void save_os_dbase(void)
00435 {
00436     int i;
00437     dbFILE *f;
00438     static time_t lastwarn = 0;
00439     Akill *ak;
00440     SXLine *sx;
00441 
00442     if (!(f = open_db(s_OperServ, OperDBName, "w", OPER_VERSION)))
00443         return;
00444     SAFE(write_int32(maxusercnt, f));
00445     SAFE(write_int32(maxusertime, f));
00446 
00447     SAFE(write_int16(akills.count, f));
00448     for (i = 0; i < akills.count; i++) {
00449         ak = akills.list[i];
00450 
00451         SAFE(write_string(ak->user, f));
00452         SAFE(write_string(ak->host, f));
00453         SAFE(write_string(ak->by, f));
00454         SAFE(write_string(ak->reason, f));
00455         SAFE(write_int32(ak->seton, f));
00456         SAFE(write_int32(ak->expires, f));
00457     }
00458 
00459     SAFE(write_int16(sglines.count, f));
00460     for (i = 0; i < sglines.count; i++) {
00461         sx = sglines.list[i];
00462 
00463         SAFE(write_string(sx->mask, f));
00464         SAFE(write_string(sx->by, f));
00465         SAFE(write_string(sx->reason, f));
00466         SAFE(write_int32(sx->seton, f));
00467         SAFE(write_int32(sx->expires, f));
00468     }
00469 
00470     SAFE(write_int16(sqlines.count, f));
00471     for (i = 0; i < sqlines.count; i++) {
00472         sx = sqlines.list[i];
00473 
00474         SAFE(write_string(sx->mask, f));
00475         SAFE(write_string(sx->by, f));
00476         SAFE(write_string(sx->reason, f));
00477         SAFE(write_int32(sx->seton, f));
00478         SAFE(write_int32(sx->expires, f));
00479     }
00480 
00481     SAFE(write_int16(szlines.count, f));
00482     for (i = 0; i < szlines.count; i++) {
00483         sx = szlines.list[i];
00484 
00485         SAFE(write_string(sx->mask, f));
00486         SAFE(write_string(sx->by, f));
00487         SAFE(write_string(sx->reason, f));
00488         SAFE(write_int32(sx->seton, f));
00489         SAFE(write_int32(sx->expires, f));
00490     }
00491 
00492     close_db(f);
00493 
00494 }
00495 
00496 #undef SAFE
00497 
00498 /*************************************************************************/
00499 
00500 void save_os_rdb_dbase(void)
00501 {
00502 #ifdef USE_RDB
00503     if (!rdb_open())
00504         return;
00505 
00506     if (rdb_tag_table("anope_os_akills") == 0) {
00507         alog("Unable to tag table 'anope_os_akills' - OperServ RDB save failed.");
00508         rdb_close();
00509         return;
00510     }
00511     if (rdb_tag_table("anope_os_sglines") == 0) {
00512         alog("Unable to tag table 'anope_os_sglines' - OperServ RDB save failed.");
00513         rdb_close();
00514         return;
00515     }
00516     if (rdb_tag_table("anope_os_sqlines") == 0) {
00517         alog("Unable to tag table 'anope_os_sqlines' - OperServ RDB save failed.");
00518         rdb_close();
00519         return;
00520     }
00521     if (rdb_tag_table("anope_os_szlines") == 0) {
00522         alog("Unable to tag table 'anope_os_szlines' - OperServ RDB save failed.");
00523         rdb_close();
00524         return;
00525     }
00526     /* We empty anope_os_core as required */
00527     if (rdb_empty_table("anope_os_core") == 0) {
00528         alog("Unable to empty table 'anope_os_core' - OperServ RDB save failed");
00529         rdb_close();
00530         return;
00531     }
00532 
00533     if (rdb_save_os_db
00534         (maxusercnt, maxusertime, &akills, &sglines, &sqlines,
00535          &szlines) == 0) {
00536         alog("Unable to save OperServ data - OperServ RDB save failed");
00537         rdb_close();
00538         return;
00539     }
00540 
00541     if (rdb_clean_table("anope_os_akills") == 0) {
00542         alog("Unable to clean table 'anope_os_akills' - OperServ RDB save failed.");
00543         rdb_close();
00544         return;
00545     }
00546     if (rdb_clean_table("anope_os_sglines") == 0) {
00547         alog("Unable to clean table 'anope_os_sglines' - OperServ RDB save failed.");
00548         rdb_close();
00549         return;
00550     }
00551     if (rdb_clean_table("anope_os_sqlines") == 0) {
00552         alog("Unable to clean table 'anope_os_sqlines' - OperServ RDB save failed.");
00553         rdb_close();
00554         return;
00555     }
00556     if (rdb_clean_table("anope_os_szlines") == 0)
00557         alog("Unable to clean table 'anope_os_szlines' - OperServ RDB save failed.");
00558 
00559     rdb_close();
00560 #endif
00561 }
00562 
00563 /*************************************************************************/
00564 
00565 /* Removes the nick structure from OperServ lists. */
00566 
00567 void os_remove_nick(NickCore * nc)
00568 {
00569     slist_remove(&servadmins, nc);
00570     slist_remove(&servopers, nc);
00571 }
00572 
00573 /*************************************************************************/
00574 
00575 /* Does the given user have Services root privileges?
00576    Now enhanced. */
00577 
00578 int is_services_root(User * u)
00579 {
00580     if ((NSStrictPrivileges && !is_oper(u))
00581         || (!skeleton && !nick_identified(u)))
00582         return 0;
00583     if (skeleton || (u->na->nc->flags & NI_SERVICES_ROOT))
00584         return 1;
00585     return 0;
00586 }
00587 
00588 /*************************************************************************/
00589 
00590 /* Does the given user have Services admin privileges? */
00591 
00592 int is_services_admin(User * u)
00593 {
00594     if ((NSStrictPrivileges && !is_oper(u))
00595         || (!skeleton && !nick_identified(u)))
00596         return 0;
00597     if (skeleton
00598         || (u->na->nc->flags & (NI_SERVICES_ADMIN | NI_SERVICES_ROOT)))
00599         return 1;
00600     return 0;
00601 }
00602 
00603 /*************************************************************************/
00604 
00605 /* Does the given user have Services oper privileges? */
00606 
00607 int is_services_oper(User * u)
00608 {
00609     if ((NSStrictPrivileges && !is_oper(u))
00610         || (!skeleton && !nick_identified(u)))
00611         return 0;
00612     if (skeleton
00613         || (u->na->nc->
00614             flags & (NI_SERVICES_OPER | NI_SERVICES_ADMIN |
00615                      NI_SERVICES_ROOT)))
00616         return 1;
00617     return 0;
00618 }
00619 
00620 /*************************************************************************/
00621 
00622 /* Is the given nick a Services root nick? */
00623 
00624 int nick_is_services_root(NickCore * nc)
00625 {
00626     if (nc) {
00627         if (nc->flags & (NI_SERVICES_ROOT))
00628             return 1;
00629     }
00630     return 0;
00631 }
00632 
00633 /*************************************************************************/
00634 
00635 /* Is the given nick a Services admin/root nick? */
00636 
00637 int nick_is_services_admin(NickCore * nc)
00638 {
00639     if (nc) {
00640         if (nc->flags & (NI_SERVICES_ADMIN | NI_SERVICES_ROOT))
00641             return 1;
00642     }
00643     return 0;
00644 }
00645 
00646 /*************************************************************************/
00647 
00648 /* Is the given nick a Services oper/admin/root nick? */
00649 
00650 int nick_is_services_oper(NickCore * nc)
00651 {
00652     if (nc) {
00653         if (nc->
00654             flags & (NI_SERVICES_OPER | NI_SERVICES_ADMIN |
00655                      NI_SERVICES_ROOT))
00656             return 1;
00657     }
00658     return 0;
00659 }
00660 
00661 
00662 /*************************************************************************/
00663 /*********************** OperServ command functions **********************/
00664 /*************************************************************************/
00665 
00666 /*************************************************************************/
00667 
00668 
00669 Server *server_global(Server * s, char *msg)
00670 {
00671     Server *sl;
00672 
00673     while (s) {
00674         /* Do not send the notice to ourselves our juped servers */
00675         if (!(s->flags & (SERVER_ISME | SERVER_JUPED)))
00676             notice_server(s_GlobalNoticer, s, "%s", msg);
00677 
00678         if (s->links) {
00679             sl = server_global(s->links, msg);
00680             if (sl)
00681                 s = sl;
00682             else
00683                 s = s->next;
00684         } else {
00685             s = s->next;
00686         }
00687     }
00688     return s;
00689 
00690 }
00691 
00692 void oper_global(char *nick, char *fmt, ...)
00693 {
00694     va_list args;
00695     char msg[2048];             /* largest valid message is 512, this should cover any global */
00696     char dmsg[2048];            /* largest valid message is 512, this should cover any global */
00697 
00698     va_start(args, fmt);
00699     vsnprintf(msg, sizeof(msg), fmt, args);
00700     va_end(args);
00701 
00702     /* I don't like the way this is coded... */
00703     if ((nick) && (!AnonymousGlobal)) {
00704         snprintf(dmsg, sizeof(dmsg), "[%s] %s", nick, msg);
00705         server_global(servlist, dmsg);
00706     } else {
00707         server_global(servlist, msg);
00708     }
00709 
00710 }
00711 
00712 /**************************************************************************/
00713 
00714 
00715 /************************************************************************/
00716 /*************************************************************************/
00717 
00718 /* Adds an AKILL to the list. Returns >= 0 on success, -1 if it fails, -2
00719  * if only the expiry time was changed.
00720  * The success result is the number of AKILLs that were deleted to successfully add one.
00721  */
00722 
00723 int add_akill(User * u, char *mask, const char *by, const time_t expires,
00724               const char *reason)
00725 {
00726     int deleted = 0, i;
00727     char *user, *mask2, *host;
00728     Akill *entry;
00729 
00730     if (!mask) {
00731         return -1;
00732     }
00733 
00734     /* Checks whether there is an AKILL that already covers
00735      * the one we want to add, and whether there are AKILLs
00736      * that would be covered by this one. The masks AND the
00737      * expiry times are used to determine this, because some
00738      * AKILLs may become useful when another one expires.
00739      * If so, warn the user in the first case and cleanup
00740      * the useless AKILLs in the second.
00741      */
00742 
00743     if (akills.count > 0) {
00744 
00745         for (i = akills.count - 1; i >= 0; i--) {
00746             char amask[BUFSIZE];
00747 
00748             entry = akills.list[i];
00749 
00750             if (!entry)
00751                 continue;
00752 
00753             snprintf(amask, sizeof(amask), "%s@%s", entry->user,
00754                      entry->host);
00755 
00756             if (!stricmp(amask, mask)) {
00757                 /* We change the AKILL expiry time if its current one is less than the new.
00758                  * This is preferable to be sure we don't change an important AKILL
00759                  * accidentely.
00760                  */
00761                 if (entry->expires >= expires || entry->expires == 0) {
00762                     if (u)
00763                         notice_lang(s_OperServ, u, OPER_AKILL_EXISTS,
00764                                     mask);
00765                     return -1;
00766                 } else {
00767                     entry->expires = expires;
00768                     if (u)
00769                         notice_lang(s_OperServ, u, OPER_AKILL_CHANGED,
00770                                     amask);
00771                     return -2;
00772                 }
00773             }
00774 
00775             if (match_wild_nocase(amask, mask)
00776                 && (entry->expires >= expires || entry->expires == 0)) {
00777                 if (u)
00778                     notice_lang(s_OperServ, u, OPER_AKILL_ALREADY_COVERED,
00779                                 mask, amask);
00780                 return -1;
00781             }
00782 
00783             if (match_wild_nocase(mask, amask)
00784                 && (entry->expires <= expires || expires == 0)) {
00785                 slist_delete(&akills, i);
00786                 deleted++;
00787             }
00788         }
00789 
00790     }
00791 
00792     /* We can now check whether the list is full or not. */
00793     if (slist_full(&akills)) {
00794         if (u)
00795             notice_lang(s_OperServ, u, OPER_AKILL_REACHED_LIMIT,
00796                         akills.limit);
00797         return -1;
00798     }
00799 
00800     /* We can now (really) add the AKILL. */
00801     mask2 = sstrdup(mask);
00802     host = strchr(mask2, '@');
00803 
00804     if (!host) {
00805         free(mask2);
00806         return -1;
00807     }
00808 
00809     user = mask2;
00810     *host = 0;
00811     host++;
00812 
00813     entry = scalloc(sizeof(Akill), 1);
00814 
00815     if (!entry) {
00816         free(mask2);
00817         return -1;
00818     }
00819 
00820     entry->user = sstrdup(user);
00821     entry->host = sstrdup(host);
00822     entry->by = sstrdup(by);
00823     entry->reason = sstrdup(reason);
00824     entry->seton = time(NULL);
00825     entry->expires = expires;
00826 
00827     slist_add(&akills, entry);
00828 
00829     if (AkillOnAdd)
00830         anope_cmd_akill(entry->user, entry->host, entry->by, entry->seton,
00831                         entry->expires, entry->reason);
00832 
00833     free(mask2);
00834 
00835     return deleted;
00836 }
00837 
00838 /* Does the user match any AKILLs? */
00839 
00840 int check_akill(char *nick, const char *username, const char *host,
00841                 const char *vhost, const char *ip)
00842 {
00843     int i;
00844     Akill *ak;
00845 
00849     if (checkDefCon(DEFCON_NO_NEW_CLIENTS)) {
00850         kill_user(s_OperServ, nick, DefConAkillReason);
00851         return 1;
00852     }
00853 
00854     if (akills.count == 0)
00855         return 0;
00856 
00857     for (i = 0; i < akills.count; i++) {
00858         ak = akills.list[i];
00859         if (!ak)
00860             continue;
00861         if (match_wild_nocase(ak->user, username)
00862             && match_wild_nocase(ak->host, host)) {
00863             anope_cmd_akill(ak->user, ak->host, ak->by, ak->seton,
00864                             ak->expires, ak->reason);
00865             return 1;
00866         }
00867         if (ircd->vhost) {
00868             if (vhost) {
00869                 if (match_wild_nocase(ak->user, username)
00870                     && match_wild_nocase(ak->host, vhost)) {
00871                     anope_cmd_akill(ak->user, ak->host, ak->by, ak->seton,
00872                                     ak->expires, ak->reason);
00873                     return 1;
00874                 }
00875             }
00876         }
00877         if (ircd->nickip) {
00878             if (ip) {
00879                 if (match_wild_nocase(ak->user, username)
00880                     && match_wild_nocase(ak->host, ip)) {
00881                     anope_cmd_akill(ak->user, ak->host, ak->by, ak->seton,
00882                                     ak->expires, ak->reason);
00883                     return 1;
00884                 }
00885             }
00886         }
00887 
00888     }
00889 
00890     return 0;
00891 }
00892 
00893 /* Delete any expired autokills. */
00894 
00895 void expire_akills(void)
00896 {
00897     int i;
00898     time_t now = time(NULL);
00899     Akill *ak;
00900 
00901     for (i = akills.count - 1; i >= 0; i--) {
00902         ak = akills.list[i];
00903 
00904         if (!ak->expires || ak->expires > now)
00905             continue;
00906 
00907         if (WallAkillExpire)
00908             anope_cmd_global(s_OperServ, "AKILL on %s@%s has expired",
00909                              ak->user, ak->host);
00910         slist_delete(&akills, i);
00911     }
00912 }
00913 
00914 static void free_akill_entry(SList * slist, void *item)
00915 {
00916     Akill *ak = item;
00917 
00918     /* Remove the AKILLs from all the servers */
00919     anope_cmd_remove_akill(ak->user, ak->host);
00920 
00921     /* Free the structure */
00922     free(ak->user);
00923     free(ak->host);
00924     free(ak->by);
00925     free(ak->reason);
00926     free(ak);
00927 }
00928 
00929 /* item1 is not an Akill pointer, but a char
00930  */
00931 
00932 static int is_akill_entry_equal(SList * slist, void *item1, void *item2)
00933 {
00934     char *ak1 = item1, buf[BUFSIZE];
00935     Akill *ak2 = item2;
00936 
00937     if (!ak1 || !ak2)
00938         return 0;
00939 
00940     snprintf(buf, sizeof(buf), "%s@%s", ak2->user, ak2->host);
00941 
00942     if (!stricmp(ak1, buf))
00943         return 1;
00944     else
00945         return 0;
00946 }
00947 
00948 
00949 /*************************************************************************/
00950 
00951 /* Adds an SGLINE to the list. Returns >= 0 on success, -1 if it failed, -2 if
00952  * only the expiry time changed.
00953  * The success result is the number of SGLINEs that were deleted to successfully add one.
00954  */
00955 
00956 int add_sgline(User * u, char *mask, const char *by, const time_t expires,
00957                const char *reason)
00958 {
00959     int deleted = 0, i;
00960     SXLine *entry;
00961     User *u2, *next;
00962     char buf[BUFSIZE];
00963     *buf = '\0';
00964 
00965     /* Checks whether there is an SGLINE that already covers
00966      * the one we want to add, and whether there are SGLINEs
00967      * that would be covered by this one.
00968      * If so, warn the user in the first case and cleanup
00969      * the useless SGLINEs in the second.
00970      */
00971 
00972     if (!mask) {
00973         return -1;
00974     }
00975 
00976     if (sglines.count > 0) {
00977 
00978         for (i = sglines.count - 1; i >= 0; i--) {
00979             entry = sglines.list[i];
00980 
00981             if (!entry)
00982                 continue;
00983 
00984             if (!stricmp(entry->mask, mask)) {
00985                 if (entry->expires >= expires || entry->expires == 0) {
00986                     if (u)
00987                         notice_lang(s_OperServ, u, OPER_SGLINE_EXISTS,
00988                                     mask);
00989                     return -1;
00990                 } else {
00991                     entry->expires = expires;
00992                     if (u)
00993                         notice_lang(s_OperServ, u, OPER_SGLINE_CHANGED,
00994                                     entry->mask);
00995                     return -2;
00996                 }
00997             }
00998 
00999             if (match_wild_nocase(entry->mask, mask)
01000                 && (entry->expires >= expires || entry->expires == 0)) {
01001                 if (u)
01002                     notice_lang(s_OperServ, u, OPER_SGLINE_ALREADY_COVERED,
01003                                 mask, entry->mask);
01004                 return -1;
01005             }
01006 
01007             if (match_wild_nocase(mask, entry->mask)
01008                 && (entry->expires <= expires || expires == 0)) {
01009                 slist_delete(&sglines, i);
01010                 deleted++;
01011             }
01012         }
01013 
01014     }
01015 
01016     /* We can now check whether the list is full or not. */
01017     if (slist_full(&sglines)) {
01018         if (u)
01019             notice_lang(s_OperServ, u, OPER_SGLINE_REACHED_LIMIT,
01020                         sglines.limit);
01021         return -1;
01022     }
01023 
01024     /* We can now (really) add the SGLINE. */
01025     entry = scalloc(sizeof(SXLine), 1);
01026     if (!entry)
01027         return -1;
01028 
01029     entry->mask = sstrdup(mask);
01030     entry->by = sstrdup(by);
01031     entry->reason = sstrdup(r