int match_usermask2(const char *mask, User *u) { char *mask2; char *nick, *username, *host; int result; if (!mask || !*mask || !u) return 0; mask2 = sstrdup(mask); if (strchr(mask2, '!')) { nick = strtok(mask2, "!"); username = strtok(NULL, "@"); } else { nick = NULL; username = strtok(mask2, "@"); } host = strtok(NULL, ""); if (!username || !host) { free(mask2); return 0; } if (nick) result = match_wild_nocase(nick, u->nick) && match_wild_nocase(username, u->username) && match_wild_nocase(host, u->vhost); else result = match_wild_nocase(username, u->username) && match_wild_nocase(host, u->vhost); free(mask2); return result; }
/* Same as find_host_exception() except * this tries to find the exception by IP also. */ Exception *find_hostip_exception(const char *host, const char *hostip) { int i; for (i = 0; i < nexceptions; i++) { if ((match_wild_nocase(exceptions[i].mask, host)) || ((ircd->nickip && hostip) && (match_wild_nocase(exceptions[i].mask, hostip)))) { return &exceptions[i]; } } return NULL; }
int check_sgline(char *nick, const char *realname) { int i; SXLine *sx; time_t now = time(NULL); if (sglines.count == 0) return 0; for (i = 0; i < sglines.count; i++) { sx = sglines.list[i]; if (!sx) continue; if (match_wild_nocase(sx->mask, realname)) { if (!sx->expires || sx->expires > now) { anope_cmd_sgline(sx->mask, sx->reason); /* We kill nick since s_sgline can't */ anope_cmd_svskill(ServerName, nick, "G-Lined: %s", sx->reason); return 1; } } } return 0; }
int check_sqline(char *nick, int nick_change) { int i; SXLine *sx; char reason[300]; if (sqlines.count == 0) return 0; for (i = 0; i < sqlines.count; i++) { sx = sqlines.list[i]; if (!sx) continue; if (ircd->chansqline) { if (*sx->mask == '#') continue; } if (match_wild_nocase(sx->mask, nick)) { sqline(sx->mask, sx->reason); /* We kill nick since s_sqline can't */ snprintf(reason, sizeof(reason), "Q-Lined: %s", sx->reason); kill_user(s_OperServ, nick, reason); return 1; } } return 0; }
/* Check and enforce any Zlines that we have */ int check_szline(char *nick, char *ip) { int i; SXLine *sx; if (szlines.count == 0) { return 0; } if (!ip) { return 0; } for (i = 0; i < szlines.count; i++) { sx = szlines.list[i]; if (!sx) { continue; } if (match_wild_nocase(sx->mask, ip)) { xanadu_cmd_szline(sx->mask, sx->reason, sx->by); return 1; } } return 0; }
/* Check and enforce any Zlines that we have */ int check_szline(char *nick, char *ip) { int i; SXLine *sx; time_t now = time(NULL); if (szlines.count == 0) { return 0; } if (!ip) { return 0; } for (i = 0; i < szlines.count; i++) { sx = szlines.list[i]; if (!sx) { continue; } if (match_wild_nocase(sx->mask, ip)) { if (!sx->expires || sx->expires > now) { anope_cmd_szline(sx->mask, sx->reason, sx->by); return 1; } } } return 0; }
/* Find the first exception this host matches and return it. */ Exception *find_host_exception(const char *host) { int i; for (i = 0; i < nexceptions; i++) { if ((match_wild_nocase(exceptions[i].mask, host))) { return &exceptions[i]; } } return NULL; }
static int do_userlist(User * u) { char *pattern = strtok(NULL, " "); char *opt = strtok(NULL, " "); Channel *c; int modes = 0; if (opt && !stricmp(opt, "INVISIBLE")) modes |= anope_get_invis_mode(); if (pattern && (c = findchan(pattern))) { struct c_userlist *cu; notice_lang(s_OperServ, u, OPER_USERLIST_HEADER_CHAN, pattern); for (cu = c->users; cu; cu = cu->next) { if (modes && !(cu->user->mode & modes)) continue; notice_lang(s_OperServ, u, OPER_USERLIST_RECORD, cu->user->nick, common_get_vident(cu->user), common_get_vhost(cu->user)); } } else { char mask[BUFSIZE]; int i; User *u2; notice_lang(s_OperServ, u, OPER_USERLIST_HEADER); for (i = 0; i < 1024; i++) { for (u2 = userlist[i]; u2; u2 = u2->next) { if (pattern) { snprintf(mask, sizeof(mask), "%s!%s@%s", u2->nick, common_get_vident(u2), common_get_vhost(u2)); if (!match_wild_nocase(pattern, mask)) continue; if (modes && !(u2->mode & modes)) continue; } notice_lang(s_OperServ, u, OPER_USERLIST_RECORD, u2->nick, common_get_vident(u2), common_get_vhost(u2)); } } } notice_lang(s_OperServ, u, OPER_USERLIST_END); return MOD_CONT; }
static int _match_usermask(const char *mask, User * user, boolean full) { char *mask2; char *nick, *username, *host; int result; if (!mask || !*mask) { return 0; } mask2 = sstrdup(mask); if (strchr(mask2, '!')) { nick = strtok(mask2, "!"); username = strtok(NULL, "@"); } else { nick = NULL; username = strtok(mask2, "@"); } host = strtok(NULL, ""); if (!username || !host) { free(mask2); return 0; } if (nick) { result = match_wild_nocase(nick, user->nick) && match_wild_nocase(username, user->username) && ((full && match_wild_nocase(host, user->host)) || match_wild_nocase(host, user->vhost) || match_wild_nocase(host, user->chost)); } else { result = match_wild_nocase(username, user->username) && ((full && match_wild_nocase(host, user->host)) || match_wild_nocase(host, user->vhost) || match_wild_nocase(host, user->chost)); } free(mask2); return result; }
int check_akill(char *nick, const char *username, const char *host, const char *vhost, const char *ip) { int i; Akill *ak; /** * If DefCon is set to NO new users - kill the user ;). **/ if (checkDefCon(DEFCON_NO_NEW_CLIENTS)) { kill_user(s_OperServ, nick, DefConAkillReason); return 1; } if (akills.count == 0) return 0; for (i = 0; i < akills.count; i++) { ak = akills.list[i]; if (!ak) continue; if (match_wild_nocase(ak->user, username) && match_wild_nocase(ak->host, host)) { xanadu_cmd_akill(ak->user, ak->host, ak->by, ak->seton, ak->expires, ak->reason); return 1; } if (ircd->vhost) { if (vhost) { if (match_wild_nocase(ak->user, username) && match_wild_nocase(ak->host, vhost)) { xanadu_cmd_akill(ak->user, ak->host, ak->by, ak->seton, ak->expires, ak->reason); return 1; } } } if (ircd->nickip) { if (ip) { if (match_wild_nocase(ak->user, username) && match_wild_nocase(ak->host, ip)) { xanadu_cmd_akill(ak->user, ak->host, ak->by, ak->seton, ak->expires, ak->reason); return 1; } } } } return 0; }
/** * Check and enforce SQlines * @param mask of the sqline * @param reason for the sqline * @return void */ void sqline(char *mask, char *reason) { int i; Channel *c, *next; char *av[3]; struct c_userlist *cu, *cunext; if (ircd->chansqline) { if (*mask == '#') { xanadu_cmd_sqline(mask, reason); for (i = 0; i < 1024; i++) { for (c = chanlist[i]; c; c = next) { next = c->next; if (!match_wild_nocase(mask, c->name)) { continue; } for (cu = c->users; cu; cu = cunext) { cunext = cu->next; if (is_oper(cu->user)) { continue; } av[0] = c->name; av[1] = cu->user->nick; av[2] = reason; xanadu_cmd_kick(s_OperServ, av[0], av[1], "Q-Lined: %s", av[2]); do_kick(s_ChanServ, 3, av); } } } } else { xanadu_cmd_sqline(mask, reason); } } else { xanadu_cmd_sqline(mask, reason); } }
int check_sgline(char *nick, const char *realname) { int i; SXLine *sx; if (sglines.count == 0) return 0; for (i = 0; i < sglines.count; i++) { sx = sglines.list[i]; if (!sx) continue; if (match_wild_nocase(sx->mask, realname)) { xanadu_cmd_sgline(sx->mask, sx->reason); /* We kill nick since s_sgline can't */ xanadu_cmd_svskill(ServerName, nick, "G-Lined: %s", sx->reason); return 1; } } return 0; }
int check_chan_sqline(const char *chan) { int i; SXLine *sx; if (sqlines.count == 0) return 0; for (i = 0; i < sqlines.count; i++) { sx = sqlines.list[i]; if (!sx) continue; if (*sx->mask != '#') continue; if (match_wild_nocase(sx->mask, chan)) { sqline(sx->mask, sx->reason); return 1; } } return 0; }
/** * The /os sgline command. * @param u The user who issued the command * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing. **/ int do_sgline(User * u) { char *cmd = strtok(NULL, " "); if (!cmd) cmd = ""; if (!stricmp(cmd, "ADD")) { int deleted = 0; char *expiry, *mask, *reason; time_t expires; mask = strtok(NULL, ":"); if (mask && *mask == '+') { expiry = mask; mask = strchr(expiry, ' '); if (mask) { *mask = 0; mask++; } } else { expiry = NULL; } expires = expiry ? dotime(expiry) : SGLineExpiry; /* If the expiry given does not contain a final letter, it's in days, * said the doc. Ah well. */ if (expiry && isdigit(expiry[strlen(expiry) - 1])) expires *= 86400; /* Do not allow less than a minute expiry time */ if (expires != 0 && expires < 60) { notice_lang(s_OperServ, u, BAD_EXPIRY_TIME); return MOD_CONT; } else if (expires > 0) { expires += time(NULL); } if (mask && (reason = strtok(NULL, ""))) { /* Clean up the last character of the mask if it is a space * See bug #761 */ size_t masklen = strlen(mask); if (mask[masklen - 1] == ' ') mask[masklen - 1] = '\0'; /* We first do some sanity check on the proposed mask. */ if (mask && strspn(mask, "*?") == strlen(mask)) { notice_lang(s_OperServ, u, USERHOST_MASK_TOO_WIDE, mask); return MOD_CONT; } deleted = add_sgline(u, mask, u->nick, expires, reason); if (deleted < 0) return MOD_CONT; else if (deleted) notice_lang(s_OperServ, u, OPER_SGLINE_DELETED_SEVERAL, deleted); notice_lang(s_OperServ, u, OPER_SGLINE_ADDED, mask); if (WallOSSGLine) { char buf[128]; if (!expires) { strcpy(buf, "does not expire"); } else { int wall_expiry = expires - time(NULL); char *s = NULL; if (wall_expiry >= 86400) { wall_expiry /= 86400; s = "day"; } else if (wall_expiry >= 3600) { wall_expiry /= 3600; s = "hour"; } else if (wall_expiry >= 60) { wall_expiry /= 60; s = "minute"; } snprintf(buf, sizeof(buf), "expires in %d %s%s", wall_expiry, s, (wall_expiry == 1) ? "" : "s"); } xanadu_cmd_global(s_OperServ, "%s added an SGLINE for %s (%s)", u->nick, mask, buf); } if (readonly) notice_lang(s_OperServ, u, READ_ONLY_MODE); } else { syntax_error(s_OperServ, u, "SGLINE", OPER_SGLINE_SYNTAX); } } else if (!stricmp(cmd, "DEL")) { char *mask; int res = 0; mask = strtok(NULL, ""); if (!mask) { syntax_error(s_OperServ, u, "SGLINE", OPER_SGLINE_SYNTAX); return MOD_CONT; } if (sglines.count == 0) { notice_lang(s_OperServ, u, OPER_SGLINE_LIST_EMPTY); return MOD_CONT; } if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) { /* Deleting a range */ res = slist_delete_range(&sglines, mask, NULL); if (res == 0) { notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH); return MOD_CONT; } else if (res == 1) { notice_lang(s_OperServ, u, OPER_SGLINE_DELETED_ONE); } else { notice_lang(s_OperServ, u, OPER_SGLINE_DELETED_SEVERAL, res); } } else { if ((res = slist_indexof(&sglines, mask)) == -1) { notice_lang(s_OperServ, u, OPER_SGLINE_NOT_FOUND, mask); return MOD_CONT; } slist_delete(&sglines, res); notice_lang(s_OperServ, u, OPER_SGLINE_DELETED, mask); } if (readonly) notice_lang(s_OperServ, u, READ_ONLY_MODE); } else if (!stricmp(cmd, "LIST")) { char *mask; int res, sent_header = 0; if (sglines.count == 0) { notice_lang(s_OperServ, u, OPER_SGLINE_LIST_EMPTY); return MOD_CONT; } mask = strtok(NULL, ""); if (!mask || (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask))) { res = slist_enum(&sglines, mask, &sgline_list_callback, u, &sent_header); if (res == 0) { notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH); return MOD_CONT; } } else { int i; char *amask; for (i = 0; i < sglines.count; i++) { amask = ((SXLine *) sglines.list[i])->mask; if (!stricmp(mask, amask) || match_wild_nocase(mask, amask)) sgline_list(i + 1, sglines.list[i], u, &sent_header); } if (!sent_header) notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH); else { notice_lang(s_OperServ, u, END_OF_ANY_LIST, "SGLine"); } } } else if (!stricmp(cmd, "VIEW")) { char *mask; int res, sent_header = 0; if (sglines.count == 0) { notice_lang(s_OperServ, u, OPER_SGLINE_LIST_EMPTY); return MOD_CONT; } mask = strtok(NULL, ""); if (!mask || (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask))) { res = slist_enum(&sglines, mask, &sgline_view_callback, u, &sent_header); if (res == 0) { notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH); return MOD_CONT; } } else { int i; char *amask; for (i = 0; i < sglines.count; i++) { amask = ((SXLine *) sglines.list[i])->mask; if (!stricmp(mask, amask) || match_wild_nocase(mask, amask)) sgline_view(i + 1, sglines.list[i], u, &sent_header); } if (!sent_header) notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH); } } else if (!stricmp(cmd, "CLEAR")) { slist_clear(&sglines, 1); notice_lang(s_OperServ, u, OPER_SGLINE_CLEAR); } else { syntax_error(s_OperServ, u, "SGLINE", OPER_SGLINE_SYNTAX); } return MOD_CONT; }
int add_sgline(User * u, char *mask, const char *by, const time_t expires, const char *reason) { int deleted = 0, i; SXLine *entry; User *u2, *next; char buf[BUFSIZE]; *buf = '\0'; /* Checks whether there is an SGLINE that already covers * the one we want to add, and whether there are SGLINEs * that would be covered by this one. * If so, warn the user in the first case and cleanup * the useless SGLINEs in the second. */ if (!mask) { return -1; } if (sglines.count > 0) { for (i = sglines.count - 1; i >= 0; i--) { entry = sglines.list[i]; if (!entry) continue; if (!stricmp(entry->mask, mask)) { if (entry->expires >= expires || entry->expires == 0) { if (u) notice_lang(s_OperServ, u, OPER_SGLINE_EXISTS, mask); return -1; } else { entry->expires = expires; if (u) notice_lang(s_OperServ, u, OPER_SGLINE_CHANGED, entry->mask); return -2; } } if (match_wild_nocase(entry->mask, mask) && (entry->expires >= expires || entry->expires == 0)) { if (u) notice_lang(s_OperServ, u, OPER_SGLINE_ALREADY_COVERED, mask, entry->mask); return -1; } if (match_wild_nocase(mask, entry->mask) && (entry->expires <= expires || expires == 0)) { slist_delete(&sglines, i); deleted++; } } } /* We can now check whether the list is full or not. */ if (slist_full(&sglines)) { if (u) notice_lang(s_OperServ, u, OPER_SGLINE_REACHED_LIMIT, sglines.limit); return -1; } /* We can now (really) add the SGLINE. */ entry = scalloc(sizeof(SXLine), 1); if (!entry) return -1; entry->mask = sstrdup(mask); entry->by = sstrdup(by); entry->reason = sstrdup(reason); entry->seton = time(NULL); entry->expires = expires; slist_add(&sglines, entry); xanadu_cmd_sgline(entry->mask, entry->reason); if (KillonSGline && !ircd->sglineenforce) { snprintf(buf, (BUFSIZE - 1), "G-Lined: %s", entry->reason); u2 = firstuser(); while (u2) { next = nextuser(); if (!is_oper(u2)) { if (match_wild_nocase(entry->mask, u2->realname)) { kill_user(ServerName, u2->nick, buf); } } u2 = next; } } return deleted; }
int do_exception(User * u) { char *cmd = strtok(NULL, " "); char *mask, *reason, *expiry, *limitstr; int limit, expires; int i; int x; if (!LimitSessions) { notice_lang(s_OperServ, u, OPER_EXCEPTION_DISABLED); return MOD_CONT; } if (!cmd) cmd = ""; if (stricmp(cmd, "ADD") == 0) { if (nexceptions >= 32767) { notice_lang(s_OperServ, u, OPER_EXCEPTION_TOO_MANY); return MOD_CONT; } mask = strtok(NULL, " "); if (mask && *mask == '+') { expiry = mask; mask = strtok(NULL, " "); } else { expiry = NULL; } limitstr = strtok(NULL, " "); reason = strtok(NULL, ""); if (!reason) { syntax_error(s_OperServ, u, "EXCEPTION", OPER_EXCEPTION_ADD_SYNTAX); return MOD_CONT; } expires = expiry ? dotime(expiry) : ExceptionExpiry; if (expires < 0) { notice_lang(s_OperServ, u, BAD_EXPIRY_TIME); return MOD_CONT; } else if (expires > 0) { expires += time(NULL); } limit = (limitstr && isdigit(*limitstr)) ? atoi(limitstr) : -1; if (limit < 0 || limit > MaxSessionLimit) { notice_lang(s_OperServ, u, OPER_EXCEPTION_INVALID_LIMIT, MaxSessionLimit); return MOD_CONT; } else { if (strchr(mask, '!') || strchr(mask, '@')) { notice_lang(s_OperServ, u, OPER_EXCEPTION_INVALID_HOSTMASK); return MOD_CONT; } x = exception_add(u, mask, limit, reason, u->nick, expires); if (x == 1) { notice_lang(s_OperServ, u, OPER_EXCEPTION_ADDED, mask, limit); } if (readonly) notice_lang(s_OperServ, u, READ_ONLY_MODE); } } else if (stricmp(cmd, "DEL") == 0) { mask = strtok(NULL, " "); if (!mask) { syntax_error(s_OperServ, u, "EXCEPTION", OPER_EXCEPTION_DEL_SYNTAX); return MOD_CONT; } if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) { int count, deleted, last = -1; deleted = process_numlist(mask, &count, exception_del_callback, u, &last); if (!deleted) { if (count == 1) { notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_SUCH_ENTRY, last); } else { notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH); } } else if (deleted == 1) { notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_ONE); } else { notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_SEVERAL, deleted); } } else { int deleted = 0; for (i = 0; i < nexceptions; i++) { if (stricmp(mask, exceptions[i].mask) == 0) { exception_del(i); notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED, mask); deleted = 1; break; } } if (!deleted && i == nexceptions) notice_lang(s_OperServ, u, OPER_EXCEPTION_NOT_FOUND, mask); } /* Renumber the exception list. I don't believe in having holes in * lists - it makes code more complex, harder to debug and we end up * with huge index numbers. Imho, fixed numbering is only beneficial * when one doesn't have range capable manipulation. -TheShadow */ for (i = 0; i < nexceptions; i++) exceptions[i].num = i; if (readonly) notice_lang(s_OperServ, u, READ_ONLY_MODE); } else if (stricmp(cmd, "MOVE") == 0) { Exception *exception; char *n1str = strtok(NULL, " "); /* From position */ char *n2str = strtok(NULL, " "); /* To position */ int n1, n2; if (!n2str) { syntax_error(s_OperServ, u, "EXCEPTION", OPER_EXCEPTION_MOVE_SYNTAX); return MOD_CONT; } n1 = atoi(n1str) - 1; n2 = atoi(n2str) - 1; if ((n1 >= 0 && n1 < nexceptions) && (n2 >= 0 && n2 < nexceptions) && (n1 != n2)) { exception = scalloc(sizeof(Exception), 1); memcpy(exception, &exceptions[n1], sizeof(Exception)); if (n1 < n2) { /* Shift upwards */ memmove(&exceptions[n1], &exceptions[n1 + 1], sizeof(Exception) * (n2 - n1)); memmove(&exceptions[n2], exception, sizeof(Exception)); } else { /* Shift downwards */ memmove(&exceptions[n2 + 1], &exceptions[n2], sizeof(Exception) * (n1 - n2)); memmove(&exceptions[n2], exception, sizeof(Exception)); } free(exception); notice_lang(s_OperServ, u, OPER_EXCEPTION_MOVED, exceptions[n1].mask, n1 + 1, n2 + 1); /* Renumber the exception list. See the DEL block above for why. */ for (i = 0; i < nexceptions; i++) exceptions[i].num = i; if (readonly) notice_lang(s_OperServ, u, READ_ONLY_MODE); } else { syntax_error(s_OperServ, u, "EXCEPTION", OPER_EXCEPTION_MOVE_SYNTAX); } } else if (stricmp(cmd, "LIST") == 0) { int sent_header = 0; expire_exceptions(); mask = strtok(NULL, " "); if (mask && strspn(mask, "1234567890,-") == strlen(mask)) { process_numlist(mask, NULL, exception_list_callback, u, &sent_header); } else { for (i = 0; i < nexceptions; i++) { if (!mask || match_wild_nocase(mask, exceptions[i].mask)) exception_list(u, i, &sent_header); } } if (!sent_header) notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH); } else if (stricmp(cmd, "VIEW") == 0) { int sent_header = 0; expire_exceptions(); mask = strtok(NULL, " "); if (mask && strspn(mask, "1234567890,-") == strlen(mask)) { process_numlist(mask, NULL, exception_view_callback, u, &sent_header); } else { for (i = 0; i < nexceptions; i++) { if (!mask || match_wild_nocase(mask, exceptions[i].mask)) exception_view(u, i, &sent_header); } } if (!sent_header) notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH); } else { syntax_error(s_OperServ, u, "EXCEPTION", OPER_EXCEPTION_SYNTAX); } return MOD_CONT; }
int add_akill(User * u, char *mask, const char *by, const time_t expires, const char *reason) { int deleted = 0, i; char *user, *mask2, *host; Akill *entry; if (!mask) { return -1; } /* Checks whether there is an AKILL that already covers * the one we want to add, and whether there are AKILLs * that would be covered by this one. The masks AND the * expiry times are used to determine this, because some * AKILLs may become useful when another one expires. * If so, warn the user in the first case and cleanup * the useless AKILLs in the second. */ if (akills.count > 0) { for (i = akills.count - 1; i >= 0; i--) { char amask[BUFSIZE]; entry = akills.list[i]; if (!entry) continue; snprintf(amask, sizeof(amask), "%s@%s", entry->user, entry->host); if (!stricmp(amask, mask)) { /* We change the AKILL expiry time if its current one is less than the new. * This is preferable to be sure we don't change an important AKILL * accidentely. */ if (entry->expires >= expires || entry->expires == 0) { if (u) notice_lang(s_OperServ, u, OPER_AKILL_EXISTS, mask); return -1; } else { entry->expires = expires; if (u) notice_lang(s_OperServ, u, OPER_AKILL_CHANGED, amask); return -2; } } if (match_wild_nocase(amask, mask) && (entry->expires >= expires || entry->expires == 0)) { if (u) notice_lang(s_OperServ, u, OPER_AKILL_ALREADY_COVERED, mask, amask); return -1; } if (match_wild_nocase(mask, amask) && (entry->expires <= expires || expires == 0)) { slist_delete(&akills, i); deleted++; } } } /* We can now check whether the list is full or not. */ if (slist_full(&akills)) { if (u) notice_lang(s_OperServ, u, OPER_AKILL_REACHED_LIMIT, akills.limit); return -1; } /* We can now (really) add the AKILL. */ mask2 = sstrdup(mask); host = strchr(mask2, '@'); if (!host) return -1; user = mask2; *host = 0; host++; entry = scalloc(sizeof(Akill), 1); if (!entry) return -1; entry->user = sstrdup(user); entry->host = sstrdup(host); entry->by = sstrdup(by); entry->reason = sstrdup(reason); entry->seton = time(NULL); entry->expires = expires; slist_add(&akills, entry); if (AkillOnAdd) xanadu_cmd_akill(entry->user, entry->host, entry->by, entry->seton, entry->expires, entry->reason); free(mask2); return deleted; }
static void load_old_akill(void) { dbFILE *f; int i, j; uint16 tmp16; uint32 tmp32; char buf[NICKMAX], mask2[BUFSIZE], *mask, *s; Akill *ak, *entry; if (! (f = open_db("AKILL", AutokillDBName ? AutokillDBName : "akill.db", "r", 9))) return; get_file_version(f); read_int16(&tmp16, f); slist_setcapacity(&akills, tmp16); for (j = 0; j < akills.capacity; j++) { ak = scalloc(sizeof(Akill), 1); SAFE(read_string(&mask, f)); s = strchr(mask, '@'); *s = 0; s++; ak->user = sstrdup(mask); ak->host = sstrdup(s); SAFE(read_string(&ak->reason, f)); SAFE(read_buffer(buf, f)); if (!*buf) ak->by = sstrdup("<unknown>"); else ak->by = sstrdup(buf); SAFE(read_int32(&tmp32, f)); ak->seton = tmp32 ? tmp32 : time(NULL); SAFE(read_int32(&tmp32, f)); ak->expires = tmp32; /* Sanity checks *sigh* */ /* No nicknames allowed! */ if (strchr(ak->user, '!')) { xanadu_cmd_remove_akill(ak->user, ak->host); free(ak); continue; } snprintf(mask2, sizeof(mask2), "%s@%s", ak->user, ak->host); /* Is the mask already in the AKILL list? */ if (slist_indexof(&akills, mask2) != -1) { free(ak); continue; } /* Checks whether there is an AKILL that already covers * the one we want to add, and whether there are AKILLs * that would be covered by this one. Expiry time * does *also* matter. */ if (akills.count > 0) { for (i = akills.count - 1; i >= 0; i--) { char amask[BUFSIZE]; entry = akills.list[i]; if (!entry) continue; snprintf(amask, sizeof(amask), "%s@%s", entry->user, entry->host); if (match_wild_nocase(amask, mask2) && (entry->expires >= ak->expires || entry->expires == 0)) { xanadu_cmd_remove_akill(ak->user, ak->host); free(ak); ak = NULL; break; } if (match_wild_nocase(mask2, amask) && (entry->expires <= ak->expires || ak->expires == 0)) slist_delete(&akills, i); } } if (ak) slist_add(&akills, ak); } close_db(f); }
/** * The /os admin command. * @param u The user who issued the command * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing. **/ int do_admin(User * u) { char *cmd = strtok(NULL, " "); char *nick = strtok(NULL, " "); NickAlias *na; int res = 0; if (skeleton) { notice_lang(s_OperServ, u, OPER_ADMIN_SKELETON); return MOD_CONT; } if (!cmd || (!nick && stricmp(cmd, "LIST") && stricmp(cmd, "CLEAR"))) { syntax_error(s_OperServ, u, "ADMIN", OPER_ADMIN_SYNTAX); } else if (!stricmp(cmd, "ADD")) { if (!is_services_root(u)) { notice_lang(s_OperServ, u, PERMISSION_DENIED); return MOD_CONT; } if (!(na = findnick(nick))) { notice_lang(s_OperServ, u, NICK_X_NOT_REGISTERED, nick); return MOD_CONT; } if (na->status & NS_VERBOTEN) { notice_lang(s_OperServ, u, NICK_X_FORBIDDEN, nick); return MOD_CONT; } if (na->nc->flags & NI_SERVICES_ADMIN || slist_indexof(&servadmins, na->nc) != -1) { notice_lang(s_OperServ, u, OPER_ADMIN_EXISTS, nick); return MOD_CONT; } res = slist_add(&servadmins, na->nc); if (res == -2) { notice_lang(s_OperServ, u, OPER_ADMIN_REACHED_LIMIT, nick); return MOD_CONT; } else { if (na->nc->flags & NI_SERVICES_OPER && (res = slist_indexof(&servopers, na->nc)) != -1) { slist_delete(&servopers, res); na->nc->flags |= NI_SERVICES_ADMIN; notice_lang(s_OperServ, u, OPER_ADMIN_MOVED, nick); } else if (na->nc->flags & NI_SERVICES_HELPOP && (res = slist_indexof(&servhelpops, na->nc)) != -1) { slist_delete(&servhelpops, res); na->nc->flags |= NI_SERVICES_ADMIN; notice_lang(s_OperServ, u, OPER_ADMIN_MOVED, nick); } else { na->nc->flags |= NI_SERVICES_ADMIN; notice_lang(s_OperServ, u, OPER_ADMIN_ADDED, nick); } LogStaffAction(STAFFLOG_CHANNEL | STAFFLOG_OPERGLOBAL, "OperServ", "%s!%s@%s added %s to the services admin list", u->nick, u->username, u->host, nick); } if (readonly) notice_lang(s_OperServ, u, READ_ONLY_MODE); } else if (!stricmp(cmd, "DEL")) { if (!is_services_root(u)) { notice_lang(s_OperServ, u, PERMISSION_DENIED); return MOD_CONT; } if (servadmins.count == 0) { notice_lang(s_OperServ, u, OPER_ADMIN_LIST_EMPTY); return MOD_CONT; } if (isdigit(*nick) && strspn(nick, "1234567890,-") == strlen(nick)) { /* Deleting a range */ res = slist_delete_range(&servadmins, nick, NULL); if (res == 0) { notice_lang(s_OperServ, u, OPER_ADMIN_NO_MATCH); return MOD_CONT; } else if (res == 1) { notice_lang(s_OperServ, u, OPER_ADMIN_DELETED_ONE); } else { notice_lang(s_OperServ, u, OPER_ADMIN_DELETED_SEVERAL, res); } } else { if (!(na = findnick(nick))) { notice_lang(s_OperServ, u, NICK_X_NOT_REGISTERED, nick); return MOD_CONT; } if (na->status & NS_VERBOTEN) { notice_lang(s_OperServ, u, NICK_X_FORBIDDEN, nick); return MOD_CONT; } if (!(na->nc->flags & NI_SERVICES_ADMIN) || (res = slist_indexof(&servadmins, na->nc)) == -1) { notice_lang(s_OperServ, u, OPER_ADMIN_NOT_FOUND, nick); return MOD_CONT; } slist_delete(&servadmins, res); notice_lang(s_OperServ, u, OPER_ADMIN_DELETED, nick); } if (readonly) notice_lang(s_OperServ, u, READ_ONLY_MODE); } else if (!stricmp(cmd, "LIST")) { int sent_header = 0; if (servadmins.count == 0) { notice_lang(s_OperServ, u, OPER_ADMIN_LIST_EMPTY); return MOD_CONT; } if (!nick || (isdigit(*nick) && strspn(nick, "1234567890,-") == strlen(nick))) { res = slist_enum(&servadmins, nick, &admin_list_callback, u, &sent_header); if (res == 0) { notice_lang(s_OperServ, u, OPER_ADMIN_NO_MATCH); return MOD_CONT; } else { notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Admin"); } } else { int i; for (i = 0; i < servadmins.count; i++) if (!stricmp (nick, ((NickCore *) servadmins.list[i])->display) || match_wild_nocase(nick, ((NickCore *) servadmins. list[i])->display)) admin_list(i + 1, servadmins.list[i], u, &sent_header); if (!sent_header) notice_lang(s_OperServ, u, OPER_ADMIN_NO_MATCH); else { notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Admin"); } } } else if (!stricmp(cmd, "CLEAR")) { if (!is_services_root(u)) { notice_lang(s_OperServ, u, PERMISSION_DENIED); return MOD_CONT; } if (servadmins.count == 0) { notice_lang(s_OperServ, u, OPER_ADMIN_LIST_EMPTY); return MOD_CONT; } slist_clear(&servadmins, 1); notice_lang(s_OperServ, u, OPER_ADMIN_CLEAR); } else { syntax_error(s_OperServ, u, "ADMIN", OPER_ADMIN_SYNTAX); } return MOD_CONT; }
int add_szline(User * u, char *mask, const char *by, const time_t expires, const char *reason) { int deleted = 0, i; SXLine *entry; if (!mask) { return -1; } /* Checks whether there is an SZLINE that already covers * the one we want to add, and whether there are SZLINEs * that would be covered by this one. * If so, warn the user in the first case and cleanup * the useless SZLINEs in the second. */ if (szlines.count > 0) { for (i = szlines.count - 1; i >= 0; i--) { entry = szlines.list[i]; if (!entry) continue; if (!stricmp(entry->mask, mask)) { if (entry->expires >= expires || entry->expires == 0) { if (u) notice_lang(s_OperServ, u, OPER_SZLINE_EXISTS, mask); return -1; } else { entry->expires = expires; if (u) notice_lang(s_OperServ, u, OPER_SZLINE_EXISTS, mask); return -2; } } if (match_wild_nocase(entry->mask, mask)) { if (u) notice_lang(s_OperServ, u, OPER_SZLINE_ALREADY_COVERED, mask, entry->mask); return -1; } if (match_wild_nocase(mask, entry->mask)) { slist_delete(&szlines, i); deleted++; } } } /* We can now check whether the list is full or not. */ if (slist_full(&szlines)) { if (u) notice_lang(s_OperServ, u, OPER_SZLINE_REACHED_LIMIT, szlines.limit); return -1; } /* We can now (really) add the SZLINE. */ entry = scalloc(sizeof(SXLine), 1); if (!entry) return -1; entry->mask = sstrdup(mask); entry->by = sstrdup(by); entry->reason = sstrdup(reason); entry->seton = time(NULL); entry->expires = expires; slist_add(&szlines, entry); xanadu_cmd_szline(entry->mask, entry->reason, entry->by); return deleted; }
/** * The /hs list command. * @param u The user who issued the command * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing. **/ int listOut(User * u) { char *key = strtok(NULL, ""); struct tm *tm; char buf[BUFSIZE]; int counter = 1; int from = 0, to = 0; char *tmp = NULL; char *s = NULL; int display_counter = 0; HostCore *head = NULL; HostCore *current; head = hostCoreListHead(); current = head; if (current == NULL) notice_lang(s_HostServ, u, HOST_EMPTY); else { /** * Do a check for a range here, then in the next loop * we'll only display what has been requested.. **/ if (key) { if (key[0] == '#') { tmp = myStrGetOnlyToken((key + 1), '-', 0); /* Read FROM out */ if (!tmp) { notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE); return MOD_CONT; } for (s = tmp; *s; s++) { if (!isdigit(*s)) { free(tmp); notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE); return MOD_CONT; } } from = atoi(tmp); free(tmp); tmp = myStrGetTokenRemainder(key, '-', 1); /* Read TO out */ if (!tmp) { notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE); return MOD_CONT; } for (s = tmp; *s; s++) { if (!isdigit(*s)) { free(tmp); notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE); return MOD_CONT; } } to = atoi(tmp); free(tmp); key = NULL; } } while (current != NULL) { if (key) { if (((match_wild_nocase(key, current->nick)) || (match_wild_nocase(key, current->vHost))) && (display_counter < NSListMax)) { display_counter++; tm = localtime(¤t->time); strftime_lang(buf, sizeof(buf), u, STRFTIME_DATE_TIME_FORMAT, tm); if (current->vIdent) { notice_lang(s_HostServ, u, HOST_IDENT_ENTRY, counter, current->nick, current->vIdent, current->vHost, current->creator, buf); } else { notice_lang(s_HostServ, u, HOST_ENTRY, counter, current->nick, current->vHost, current->creator, buf); } } } else { /** * List the host if its in the display range, and not more * than NSListMax records have been displayed... **/ if ((((counter >= from) && (counter <= to)) || ((from == 0) && (to == 0))) && (display_counter < NSListMax)) { display_counter++; tm = localtime(¤t->time); strftime_lang(buf, sizeof(buf), u, STRFTIME_DATE_TIME_FORMAT, tm); if (current->vIdent) { notice_lang(s_HostServ, u, HOST_IDENT_ENTRY, counter, current->nick, current->vIdent, current->vHost, current->creator, buf); } else { notice_lang(s_HostServ, u, HOST_ENTRY, counter, current->nick, current->vHost, current->creator, buf); } } } counter++; current = current->next; } if (key) { notice_lang(s_HostServ, u, HOST_LIST_KEY_FOOTER, key, display_counter); } else { if (from != 0) { notice_lang(s_HostServ, u, HOST_LIST_RANGE_FOOTER, from, to); } else { notice_lang(s_HostServ, u, HOST_LIST_FOOTER, display_counter); } } } return MOD_CONT; }
static int do_akill(User * u) { char *cmd = strtok(NULL, " "); char breason[BUFSIZE]; if (!cmd) cmd = ""; if (!stricmp(cmd, "ADD")) { int deleted = 0; char *expiry, *mask, *reason; time_t expires, now = time(NULL); mask = strtok(NULL, " "); if (mask && *mask == '+') { expiry = mask; mask = strtok(NULL, " "); } else { expiry = NULL; } expires = expiry ? dotime(expiry) : AutokillExpiry; /* If the expiry given does not contain a final letter, it's in days, * said the doc. Ah well. */ if (expiry && isdigit(expiry[strlen(expiry) - 1])) expires *= 86400; /* Do not allow less than a minute expiry time */ if (expires != 0 && expires < 60) { notice_lang(s_OperServ, u, BAD_EXPIRY_TIME); return MOD_CONT; } else if (expires > 0) { expires += time(NULL); } if (mask && (reason = strtok(NULL, ""))) { /* We first do some sanity check on the proposed mask. */ if (strchr(mask, '!')) { notice_lang(s_OperServ, u, OPER_AKILL_NO_NICK); return MOD_CONT; } if (!strchr(mask, '@')) { notice_lang(s_OperServ, u, BAD_USERHOST_MASK); return MOD_CONT; } if (mask && strspn(mask, "~@.*?") == strlen(mask)) { notice_lang(s_OperServ, u, USERHOST_MASK_TOO_WIDE, mask); return MOD_CONT; } /** * Changed sprintf() to snprintf()and increased the size of * breason to match bufsize * -Rob **/ if (AddAkiller) { snprintf(breason, sizeof(breason), "[%s] %s", u->nick, reason); reason = sstrdup(breason); } deleted = add_akill(u, mask, u->nick, expires, reason); if (deleted < 0) { if (AddAkiller) { free(reason); } return MOD_CONT; } else if (deleted) { notice_lang(s_OperServ, u, OPER_AKILL_DELETED_SEVERAL, deleted); } notice_lang(s_OperServ, u, OPER_AKILL_ADDED, mask); if (WallOSAkill) { char buf[128]; if (!expires) { strcpy(buf, "does not expire"); } else { int wall_expiry = expires - now; char *s = NULL; if (wall_expiry >= 86400) { wall_expiry /= 86400; s = "day"; } else if (wall_expiry >= 3600) { wall_expiry /= 3600; s = "hour"; } else if (wall_expiry >= 60) { wall_expiry /= 60; s = "minute"; } snprintf(buf, sizeof(buf), "expires in %d %s%s", wall_expiry, s, (wall_expiry == 1) ? "" : "s"); } anope_cmd_global(s_OperServ, "%s added an AKILL for %s (%s) (%s)", u->nick, mask, reason, buf); } if (readonly) { notice_lang(s_OperServ, u, READ_ONLY_MODE); } if (AddAkiller) { free(reason); } } else { syntax_error(s_OperServ, u, "AKILL", OPER_AKILL_SYNTAX); } } else if (!stricmp(cmd, "DEL")) { char *mask; int res = 0; mask = strtok(NULL, " "); if (!mask) { syntax_error(s_OperServ, u, "AKILL", OPER_AKILL_SYNTAX); return MOD_CONT; } if (akills.count == 0) { notice_lang(s_OperServ, u, OPER_AKILL_LIST_EMPTY); return MOD_CONT; } if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) { /* Deleting a range */ res = slist_delete_range(&akills, mask, NULL); if (res == 0) { notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH); return MOD_CONT; } else if (res == 1) { notice_lang(s_OperServ, u, OPER_AKILL_DELETED_ONE); } else { notice_lang(s_OperServ, u, OPER_AKILL_DELETED_SEVERAL, res); } } else { if ((res = slist_indexof(&akills, mask)) == -1) { notice_lang(s_OperServ, u, OPER_AKILL_NOT_FOUND, mask); return MOD_CONT; } slist_delete(&akills, res); notice_lang(s_OperServ, u, OPER_AKILL_DELETED, mask); } if (readonly) notice_lang(s_OperServ, u, READ_ONLY_MODE); } else if (!stricmp(cmd, "LIST")) { char *mask; int res, sent_header = 0; if (akills.count == 0) { notice_lang(s_OperServ, u, OPER_AKILL_LIST_EMPTY); return MOD_CONT; } mask = strtok(NULL, " "); if (!mask || (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask))) { res = slist_enum(&akills, mask, &akill_list_callback, u, &sent_header); if (res == 0) { notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH); return MOD_CONT; } else { notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Akill"); } } else { int i; char amask[BUFSIZE]; for (i = 0; i < akills.count; i++) { snprintf(amask, sizeof(amask), "%s@%s", ((Akill *) akills.list[i])->user, ((Akill *) akills.list[i])->host); if (!stricmp(mask, amask) || match_wild_nocase(mask, amask)) akill_list(i + 1, akills.list[i], u, &sent_header); } if (!sent_header) notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH); else { notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Akill"); } } } else if (!stricmp(cmd, "VIEW")) { char *mask; int res, sent_header = 0; if (akills.count == 0) { notice_lang(s_OperServ, u, OPER_AKILL_LIST_EMPTY); return MOD_CONT; } mask = strtok(NULL, " "); if (!mask || (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask))) { res = slist_enum(&akills, mask, &akill_view_callback, u, &sent_header); if (res == 0) { notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH); return MOD_CONT; } } else { int i; char amask[BUFSIZE]; for (i = 0; i < akills.count; i++) { snprintf(amask, sizeof(amask), "%s@%s", ((Akill *) akills.list[i])->user, ((Akill *) akills.list[i])->host); if (!stricmp(mask, amask) || match_wild_nocase(mask, amask)) akill_view(i + 1, akills.list[i], u, &sent_header); } if (!sent_header) notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH); } } else if (!stricmp(cmd, "CLEAR")) { slist_clear(&akills, 1); notice_lang(s_OperServ, u, OPER_AKILL_CLEAR); } else { syntax_error(s_OperServ, u, "AKILL", OPER_AKILL_SYNTAX); } return MOD_CONT; }
/** * The /ns list command. * @param u The user who issued the command * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing. **/ static int do_list(User * u) { /* SADMINS can search for nicks based on their NS_VERBOTEN and NS_NO_EXPIRE * status. The keywords FORBIDDEN and NOEXPIRE represent these two states * respectively. These keywords should be included after the search pattern. * Multiple keywords are accepted and should be separated by spaces. Only one * of the keywords needs to match a nick's state for the nick to be displayed. * Forbidden nicks can be identified by "[Forbidden]" appearing in the last * seen address field. Nicks with NOEXPIRE set are preceeded by a "!". Only * SADMINS will be shown forbidden nicks and the "!" indicator. * Syntax for sadmins: LIST pattern [FORBIDDEN] [NOEXPIRE] * -TheShadow * * UPDATE: SUSPENDED keyword is now accepted as well. */ char *pattern = strtok(NULL, " "); char *keyword; NickAlias *na; NickCore *mync; int nnicks, i; char buf[BUFSIZE]; int is_servadmin = is_services_admin(u); int16 matchflags = 0; NickRequest *nr = NULL; int nronly = 0; int susp_keyword = 0; char noexpire_char = ' '; int count = 0, from = 0, to = 0, tofree = 0; char *tmp = NULL; char *s = NULL; if (!(!NSListOpersOnly || (is_oper(u)))) { /* reverse the help logic */ notice_lang(s_NickServ, u, ACCESS_DENIED); return MOD_STOP; } if (!pattern) { syntax_error(s_NickServ, u, "LIST", is_servadmin ? NICK_LIST_SERVADMIN_SYNTAX : NICK_LIST_SYNTAX); } else { if (pattern) { if (pattern[0] == '#') { tmp = myStrGetOnlyToken((pattern + 1), '-', 0); /* Read FROM out */ if (!tmp) { notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE); return MOD_CONT; } for (s = tmp; *s; s++) { if (!isdigit(*s)) { free(tmp); notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE); return MOD_CONT; } } from = atoi(tmp); free(tmp); tmp = myStrGetTokenRemainder(pattern, '-', 1); /* Read TO out */ if (!tmp) { notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE); return MOD_CONT; } for (s = tmp; *s; s++) { if (!isdigit(*s)) { free(tmp); notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE); return MOD_CONT; } } to = atoi(tmp); free(tmp); pattern = sstrdup("*"); tofree = 1; } } nnicks = 0; while (is_servadmin && (keyword = strtok(NULL, " "))) { if (stricmp(keyword, "FORBIDDEN") == 0) matchflags |= NS_VERBOTEN; if (stricmp(keyword, "NOEXPIRE") == 0) matchflags |= NS_NO_EXPIRE; if (stricmp(keyword, "SUSPENDED") == 0) susp_keyword = 1; if (stricmp(keyword, "UNCONFIRMED") == 0) nronly = 1; } mync = (nick_identified(u) ? u->na->nc : NULL); notice_lang(s_NickServ, u, NICK_LIST_HEADER, pattern); if (nronly != 1) { for (i = 0; i < 1024; i++) { for (na = nalists[i]; na; na = na->next) { /* Don't show private and forbidden nicks to non-services admins. */ if ((na->status & NS_VERBOTEN) && !is_servadmin) continue; if ((na->nc->flags & NI_PRIVATE) && !is_servadmin && na->nc != mync) continue; if ((matchflags != 0) && !(na->status & matchflags) && (susp_keyword == 0)) continue; else if ((susp_keyword == 1) && !(na->nc->flags & NI_SUSPENDED)) continue; /* We no longer compare the pattern against the output buffer. * Instead we build a nice nick!user@host buffer to compare. * The output is then generated separately. -TheShadow */ snprintf(buf, sizeof(buf), "%s!%s", na->nick, (na->last_usermask && !(na->status & NS_VERBOTEN)) ? na-> last_usermask : "*@*"); if (stricmp(pattern, na->nick) == 0 || match_wild_nocase(pattern, buf)) { if ((((count + 1 >= from) && (count + 1 <= to)) || ((from == 0) && (to == 0))) && (++nnicks <= NSListMax)) { if (is_servadmin && (na->status & NS_NO_EXPIRE)) noexpire_char = '!'; else { noexpire_char = ' '; } if ((na->nc->flags & NI_HIDE_MASK) && !is_servadmin && na->nc != mync) { snprintf(buf, sizeof(buf), "%-20s [Hostname Hidden]", na->nick); } else if (na->status & NS_VERBOTEN) { snprintf(buf, sizeof(buf), "%-20s [Forbidden]", na->nick); } else if (na->nc->flags & NI_SUSPENDED) { snprintf(buf, sizeof(buf), "%-20s [Suspended]", na->nick); } else { snprintf(buf, sizeof(buf), "%-20s %s", na->nick, na->last_usermask); } notice_user(s_NickServ, u, " %c%s", noexpire_char, buf); } count++; } } } } if (nronly == 1 || (is_servadmin && matchflags == 0 && susp_keyword == 0)) { noexpire_char = ' '; for (i = 0; i < 1024; i++) { for (nr = nrlists[i]; nr; nr = nr->next) { snprintf(buf, sizeof(buf), "%s!*@*", nr->nick); if (stricmp(pattern, nr->nick) == 0 || match_wild_nocase(pattern, buf)) { if (++nnicks <= NSListMax) { snprintf(buf, sizeof(buf), "%-20s [UNCONFIRMED]", nr->nick); notice_user(s_NickServ, u, " %c%s", noexpire_char, buf); } } } } } notice_lang(s_NickServ, u, NICK_LIST_RESULTS, nnicks > NSListMax ? NSListMax : nnicks, nnicks); } if (tofree) free(pattern); return MOD_CONT; }
int do_akick(User * u, Channel *c, char *cmd, char *mask, char *reason) { ChannelInfo *ci = c->ci; AutoKick *akick; int i; struct c_userlist *cu = NULL, *next = NULL; User *u2; char *argv[3]; int count = 0; if (!cmd || (!mask && (!stricmp(cmd, "ADD") || !stricmp(cmd, "STICK") || !stricmp(cmd, "UNSTICK") || !stricmp(cmd, "DEL")))) { noticeLang(ci->bi->nick, u, LANG_AKICK_SYNTAX); } else if (!check_access(u, ci, CA_AKICK) && !is_services_admin(u)) { notice_lang(ci->bi->nick, u, ACCESS_DENIED); } else if (stricmp(cmd, "ADD") == 0) { NickAlias *na = findnick(mask), *na2; User *target = finduser(mask); NickCore *nc = NULL; char *nick, *user, *host; int freemask = 0; if (readonly) { notice_lang(ci->bi->nick, u, CHAN_AKICK_DISABLED); return MOD_CONT; } if (!na) { if (target) { char tmp[BUFSIZE]; mask = NULL; freemask = 1; get_idealban(ci, target, tmp, BUFSIZE); mask = sstrdup(tmp); } else { split_usermask(mask, &nick, &user, &host); mask = scalloc(strlen(nick) + strlen(user) + strlen(host) + 3, 1); freemask = 1; sprintf(mask, "%s!%s@%s", nick, user, host); free(nick); free(user); free(host); } } else { if (na->status & NS_VERBOTEN) { notice_lang(ci->bi->nick, u, NICK_X_FORBIDDEN, mask); return MOD_CONT; } nc = na->nc; } /* Check excepts BEFORE we get this far */ if (ircd->except) { if (is_excepted_mask(ci, mask) == 1) { notice_lang(ci->bi->nick, u, CHAN_EXCEPTED, mask, c->name); if (freemask) free(mask); return MOD_CONT; } } /* Check whether target nick has equal/higher access * or whether the mask matches a user with higher/equal access ~ Viper */ if ((ci->flags & CI_PEACE) && nc) { if ((nc == ci->founder) || (get_access_nc(nc, ci) >= get_access(u, ci))) { notice_lang(s_ChanServ, u, PERMISSION_DENIED); if (freemask) free(mask); return MOD_CONT; } } else if ((ci->flags & CI_PEACE)) { char buf[BUFSIZE]; /* Match against all currently online users with equal or * higher access. - Viper */ for (i = 0; i < 1024; i++) { for (u2 = userlist[i]; u2; u2 = u2->next) { if (is_founder(u2, ci) || (get_access(u2, ci) >= get_access(u, ci))) { if (match_usermask(mask, u2)) { notice_lang(s_ChanServ, u, PERMISSION_DENIED); free(mask); return MOD_CONT; } } } } /* Match against the lastusermask of all nickalias's with equal * or higher access. ~ Viper */ for (i = 0; i < 1024; i++) { for (na2 = nalists[i]; na2; na2 = na2->next) { if (na2->status & NS_VERBOTEN) continue; if (na2->nc && ((na2->nc == ci->founder) || (get_access_nc(na2->nc, ci) >= get_access(u, ci)))) { snprintf(buf, BUFSIZE, "%s!%s", na2->nick, na2->last_usermask); if (match_wild_nocase(mask, buf)) { notice_lang(s_ChanServ, u, PERMISSION_DENIED); free(mask); return MOD_CONT; } } } } } for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) { if (!(akick->flags & AK_USED)) continue; if ((akick->flags & AK_ISNICK) ? akick->u.nc == nc : stricmp(akick->u.mask, mask) == 0) { notice_lang(ci->bi->nick, u, CHAN_AKICK_ALREADY_EXISTS, (akick->flags & AK_ISNICK) ? akick->u.nc-> display : akick->u.mask, c->name); if (freemask) free(mask); return MOD_CONT; } } /* All entries should be in use so we don't have to go over * the entire list. We simply add new entries at the end. */ if (ci->akickcount >= CSAutokickMax) { notice_lang(s_ChanServ, u, CHAN_AKICK_REACHED_LIMIT, CSAutokickMax); if (freemask) free(mask); return MOD_CONT; } ci->akickcount++; ci->akick = srealloc(ci->akick, sizeof(AutoKick) * ci->akickcount); akick = &ci->akick[i]; akick->flags = AK_USED; if (nc) { akick->flags |= AK_ISNICK; akick->u.nc = nc; } else { akick->u.mask = sstrdup(mask); } akick->creator = sstrdup(u->nick); akick->addtime = time(NULL); if (reason) { if (strlen(reason) > 200) reason[200] = '\0'; akick->reason = sstrdup(reason); } else { akick->reason = NULL; } /* Auto ENFORCE #63 */ cu = c->users; while (cu) { next = cu->next; if (check_kick(cu->user, c->name, c->creation_time)) { argv[0] = sstrdup(c->name); argv[1] = sstrdup(cu->user->nick); if (akick->reason) argv[2] = sstrdup(akick->reason); else argv[2] = sstrdup("none"); do_kick(ci->bi->nick, 3, argv); free(argv[2]); free(argv[1]); free(argv[0]); count++; } cu = next; } alog("%s: %s!%s@%s added akick for %s to %s", ci->bi->nick, u->nick, u->username, u->host, mask, c->name); notice_lang(ci->bi->nick, u, CHAN_AKICK_ADDED, mask, c->name); if (count) notice_lang(ci->bi->nick, u, CHAN_AKICK_ENFORCE_DONE, c->name, count); if (freemask) free(mask); } else if (stricmp(cmd, "STICK") == 0) { NickAlias *na; NickCore *nc; if (readonly) { notice_lang(ci->bi->nick, u, CHAN_AKICK_DISABLED); return MOD_CONT; } if (ci->akickcount == 0) { notice_lang(ci->bi->nick, u, CHAN_AKICK_LIST_EMPTY, ci->name); return MOD_CONT; } na = findnick(mask); nc = (na ? na->nc : NULL); for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) { if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK)) continue; if (!stricmp(akick->u.mask, mask)) break; } if (i == ci->akickcount) { notice_lang(ci->bi->nick, u, CHAN_AKICK_NOT_FOUND, mask, ci->name); return MOD_CONT; } akick->flags |= AK_STUCK; alog("%s: %s!%s@%s set STICK on akick %s on %s", ci->bi->nick, u->nick, u->username, u->host, akick->u.mask, ci->name); notice_lang(ci->bi->nick, u, CHAN_AKICK_STUCK, akick->u.mask, ci->name); if (ci->c) stick_mask(ci, akick); } else if (stricmp(cmd, "UNSTICK") == 0) { NickAlias *na; NickCore *nc; if (readonly) { notice_lang(ci->bi->nick, u, CHAN_AKICK_DISABLED); return MOD_CONT; } if (ci->akickcount == 0) { notice_lang(ci->bi->nick, u, CHAN_AKICK_LIST_EMPTY, ci->name); return MOD_CONT; } na = findnick(mask); nc = (na ? na->nc : NULL); for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) { if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK)) continue; if (!stricmp(akick->u.mask, mask)) break; } if (i == ci->akickcount) { notice_lang(ci->bi->nick, u, CHAN_AKICK_NOT_FOUND, mask, ci->name); return MOD_CONT; } akick->flags &= ~AK_STUCK; alog("%s: %s!%s@%s unset STICK on akick %s on %s", ci->bi->nick, u->nick, u->username, u->host, akick->u.mask, ci->name); notice_lang(ci->bi->nick, u, CHAN_AKICK_UNSTUCK, akick->u.mask, ci->name); } else if (stricmp(cmd, "DEL") == 0) { int deleted, a, b; if (readonly) { notice_lang(ci->bi->nick, u, CHAN_AKICK_DISABLED); return MOD_CONT; } if (ci->akickcount == 0) { notice_lang(ci->bi->nick, u, CHAN_AKICK_LIST_EMPTY, c->name); return MOD_CONT; } /* Special case: is it a number/list? Only do search if it isn't. */ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) { int count, last = -1; deleted = process_numlist(mask, &count, akick_del_callback, u, ci, &last); if (!deleted) { if (count == 1) { notice_lang(ci->bi->nick, u, CHAN_AKICK_NO_SUCH_ENTRY, last, ci->name); } else { notice_lang(ci->bi->nick, u, CHAN_AKICK_NO_MATCH, ci->name); } } else if (deleted == 1) { alog("%s: %s!%s@%s deleted 1 akick on %s", ci->bi->nick, u->nick, u->username, u->host, ci->name); notice_lang(ci->bi->nick, u, CHAN_AKICK_DELETED_ONE, ci->name); } else { alog("%s: %s!%s@%s deleted %d akicks on %s", ci->bi->nick, u->nick, u->username, u->host, deleted, ci->name); notice_lang(ci->bi->nick, u, CHAN_AKICK_DELETED_SEVERAL, deleted, ci->name); } } else { NickAlias *na = findnick(mask); NickCore *nc = (na ? na->nc : NULL); for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) { if (!(akick->flags & AK_USED)) continue; if (((akick->flags & AK_ISNICK) && akick->u.nc == nc) || (!(akick->flags & AK_ISNICK) && stricmp(akick->u.mask, mask) == 0)) break; } if (i == ci->akickcount) { notice_lang(ci->bi->nick, u, CHAN_AKICK_NOT_FOUND, mask, c->name); return MOD_CONT; } alog("%s: %s!%s@%s deleted akick %s on %s", ci->bi->nick, u->nick, u->username, u->host, mask, c->name); notice_lang(ci->bi->nick, u, CHAN_AKICK_DELETED, mask, c->name); akick_del(u, akick); deleted = 1; } if (deleted) { /* Reordering - DrStein */ for (b = 0; b < ci->akickcount; b++) { if (ci->akick[b].flags & AK_USED) { for (a = 0; a < ci->akickcount; a++) { if (a > b) break; if (!(ci->akick[a].flags & AK_USED)) { ci->akick[a].flags = ci->akick[b].flags; if (ci->akick[b].flags & AK_ISNICK) { ci->akick[a].u.nc = ci->akick[b].u.nc; } else { ci->akick[a].u.mask = sstrdup(ci->akick[b].u.mask); } /* maybe we should first check whether there is a reason before we sstdrup it -Certus */ if (ci->akick[b].reason) ci->akick[a].reason = sstrdup(ci->akick[b].reason); else ci->akick[a].reason = NULL; ci->akick[a].creator = sstrdup(ci->akick[b].creator); ci->akick[a].addtime = ci->akick[b].addtime; akick_del(u, &ci->akick[b]); break; } } } } /* After reordering only the entries at the end could still be empty. * We ll free the places no longer in use... - Viper */ for (i = ci->akickcount - 1; i >= 0; i--) { if (ci->akick[i].flags & AK_USED) break; ci->akickcount--; } ci->akick = srealloc(ci->akick,sizeof(AutoKick) * ci->akickcount); } } else if (stricmp(cmd, "LIST") == 0) { int sent_header = 0; if (ci->akickcount == 0) { notice_lang(ci->bi->nick, u, CHAN_AKICK_LIST_EMPTY, c->name); return MOD_CONT; } if (mask && isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) { process_numlist(mask, NULL, akick_list_callback, u, ci, &sent_header); } else { for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) { if (!(akick->flags & AK_USED)) continue; if (mask) { if (!(akick->flags & AK_ISNICK) && !my_match_wild_nocase(mask, akick->u.mask)) continue; if ((akick->flags & AK_ISNICK) && !my_match_wild_nocase(mask, akick->u.nc->display)) continue; } akick_list(u, i, ci, &sent_header); } } if (!sent_header) notice_lang(ci->bi->nick, u, CHAN_AKICK_NO_MATCH, c->name); } else if (stricmp(cmd, "VIEW") == 0) { int sent_header = 0; if (ci->akickcount == 0) { notice_lang(ci->bi->nick, u, CHAN_AKICK_LIST_EMPTY, c->name); return MOD_CONT; } if (mask && isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) { process_numlist(mask, NULL, akick_view_callback, u, ci, &sent_header); } else { for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) { if (!(akick->flags & AK_USED)) continue; if (mask) { if (!(akick->flags & AK_ISNICK) && !my_match_wild_nocase(mask, akick->u.mask)) continue; if ((akick->flags & AK_ISNICK) && !my_match_wild_nocase(mask, akick->u.nc->display)) continue; } akick_view(u, i, ci, &sent_header); } } if (!sent_header) notice_lang(ci->bi->nick, u, CHAN_AKICK_NO_MATCH, c->name); } else if (stricmp(cmd, "ENFORCE") == 0) { struct c_userlist *cu = NULL, *next = NULL; char *argv[3]; int count = 0; if (!c) { notice_lang(ci->bi->nick, u, CHAN_X_NOT_IN_USE, ci->name); return MOD_CONT; } cu = c->users; while (cu) { next = cu->next; if (check_kick(cu->user, c->name, c->creation_time)) { argv[0] = sstrdup(c->name); argv[1] = sstrdup(cu->user->nick); argv[2] = sstrdup(CSAutokickReason); do_kick(ci->bi->nick, 3, argv); free(argv[2]); free(argv[1]); free(argv[0]); count++; } cu = next; } notice_lang(ci->bi->nick, u, CHAN_AKICK_ENFORCE_DONE, ci->name, count); } else if (stricmp(cmd, "CLEAR") == 0) { if (readonly) { notice_lang(ci->bi->nick, u, CHAN_AKICK_DISABLED); return MOD_CONT; } for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) { if (!(akick->flags & AK_USED)) continue; akick_del(u, akick); } free(ci->akick); ci->akick = NULL; ci->akickcount = 0; alog("%s: %s!%s@%s cleared akicks on %s", ci->bi->nick, u->nick, u->username, u->host, ci->name); notice_lang(ci->bi->nick, u, CHAN_AKICK_CLEAR, ci->name); } else { noticeLang(ci->bi->nick, u, LANG_AKICK_SYNTAX); } return MOD_CONT; }