/************************************************************************ * IRC - Internet Relay Chat, src/m_unkline.c * Copyright (C) 1990 Jarkko Oikarinen and * University of Oulu, Computing Center * * See file AUTHORS in IRC package for additional names of * the programmers. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * $Id: m_unkline.c,v 1.4 2005/08/27 16:23:50 jpinto Exp $ */ #include "m_commands.h" #include "channel.h" #include "client.h" #include "common.h" #include "dline_conf.h" #include "fileio.h" #include "irc_string.h" #include "ircd.h" #include "mtrie_conf.h" #include "numeric.h" #include "s_conf.h" #include "s_log.h" #include "s_misc.h" #include "send.h" #include "struct.h" #include #include #include #include extern ConfigFileEntryType ConfigFileEntry; /* defined in ircd.c */ static int flush_write(aClient *, FBFILE* , char *, char *); static int remove_tkline_match(char *,char *, unsigned long); /* ** m_unkline ** Added Aug 31, 1997 ** common (Keith Fralick) fralick@gate.net ** ** parv[0] = sender ** parv[1] = address to remove * * * re-worked and cleanedup for use in hybrid-5 * -Dianora * */ int m_unkline (aClient *cptr,aClient *sptr,int parc,char *parv[]) { FBFILE* in; FBFILE* out; int pairme = NO; char buf[BUFSIZE]; char buff[BUFSIZE]; /* matches line definition in s_conf.c */ char temppath[BUFSIZE]; const char *filename; /* filename to use for unkline */ char *user,*host; char *p; int error_on_write = NO; mode_t oldumask; unsigned long ip; unsigned long ip_mask; ircsprintf(temppath, "%s/%s.tmp", ConfigFileEntry.varpath, "kline.conf"); if (check_registered(sptr)) { return -1; } if (!IsAnOper(sptr)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (!IsSetOperUnkline(sptr)) { sendto_one(sptr,":%s NOTICE %s :You have no U flag",me.name,parv[0]); return 0; } if ( parc < 2 ) { sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "UNKLINE"); return 0; } if ( (host = strchr(parv[1], '@')) || *parv[1] == '*' ) { /* Explicit user@host mask given */ if(host) /* Found user@host */ { user = parv[1]; /* here is user part */ *(host++) = '\0'; /* and now here is host */ } else { user = "*"; /* no @ found, assume its *@somehost */ host = parv[1]; } } else { sendto_one(sptr, ":%s NOTICE %s :Invalid parameters", me.name, parv[0]); return 0; } if( (user[0] == '*') && (user[1] == '\0') && (host[0] == '*') && (host[1] == '\0') ) { sendto_one(sptr, ":%s NOTICE %s :Cannot UNK-Line everyone", me.name, parv[0]); return 0; } if(!(is_address(host, &ip, &ip_mask))) ip = 0L; if(remove_tkline_match(host,user,(unsigned long)ip)) { sendto_one(sptr, ":%s NOTICE %s :Un-klined [%s@%s] from temporary k-lines", me.name, parv[0],user, host); sendto_ops("%s has removed the temporary K-Line for: [%s@%s]", parv[0], user, host ); irclog(L_NOTICE, "%s removed temporary K-Line for [%s@%s]", parv[0], user, host); return 0; } filename = get_conf_name(KLINE_TYPE); if( (in = fbopen(filename, "r")) == 0) { sendto_one(sptr, ":%s NOTICE %s :Cannot open %s", me.name,parv[0],filename); return 0; } oldumask = umask(0); /* ircd is normally too paranoid */ if( (out = fbopen(temppath, "w")) == 0) { sendto_one(sptr, ":%s NOTICE %s :Cannot open %s", me.name,parv[0],temppath); fbclose(in); umask(oldumask); /* Restore the old umask */ return 0; } umask(oldumask); /* Restore the old umask */ /* #Dianora!db@ts2-11.ottawa.net K'd: foo@bar:No reason K:bar:No reason (1997/08/30 14.56):foo */ while(fbgets(buf, sizeof(buf), in)) { if((buf[1] == ':') && ((buf[0] == 'k') || (buf[0] == 'K'))) { /* its a K: line */ char *found_host; char *found_user; char *found_comment; strncpy_irc(buff, buf, BUFSIZE); /* extra paranoia */ p = strchr(buff,'\n'); if(p) *p = '\0'; found_host = buff + 2; /* point past the K: */ p = strchr(found_host,':'); if(p == (char *)NULL) { sendto_one(sptr, ":%s NOTICE %s :K-Line file corrupted", me.name, parv[0]); sendto_one(sptr, ":%s NOTICE %s :Couldn't find host", me.name, parv[0]); irclog(L_ERROR, "K-Line file corrupted (couldn't find host)"); if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); continue; /* This K line is corrupted ignore */ } *p = '\0'; p++; found_comment = p; p = strchr(found_comment,':'); if(p == (char *)NULL) { sendto_one(sptr, ":%s NOTICE %s :K-Line file corrupted", me.name, parv[0]); sendto_one(sptr, ":%s NOTICE %s :Couldn't find comment", me.name, parv[0]); irclog(L_ERROR, "K-Line file corrupted (couldn't find comment)"); if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); continue; /* This K line is corrupted ignore */ } *p = '\0'; p++; found_user = p; /* * Ok, if its not an exact match on either the user or the host * then, write the K: line out, and I add it back to the K line * tree */ if(irccmp(host,found_host) || irccmp(user,found_user)) { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); } else pairme++; } else if(buf[0] == '#') { char *userathost; char *found_user; char *found_host; strncpy_irc(buff, buf, BUFSIZE); /* #Dianora!db@ts2-11.ottawa.net K'd: foo@bar:No reason K:bar:No reason (1997/08/30 14.56):foo If its a comment coment line, i.e. #ignore this line Then just ignore the line */ p = strchr(buff,':'); if(p == (char *)NULL) { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); continue; } *p = '\0'; p++; userathost = p; p = strchr(userathost,':'); if(p == (char *)NULL) { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); continue; } *p = '\0'; while(*userathost == ' ') userathost++; found_user = userathost; p = strchr(found_user,'@'); if(p == (char *)NULL) { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); continue; } *p = '\0'; found_host = p; found_host++; if( (irccmp(found_host,host)) || (irccmp(found_user,user)) ) { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); } } else /* its the ircd.conf file, and not a K line or comment */ { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); } } fbclose(in); /* The result of the rename should be checked too... oh well */ /* If there was an error on a write above, then its been reported * and I am not going to trash the original kline /conf file * -Dianora */ if(!error_on_write) { fbclose(out); (void)rename(temppath, filename); rehash(cptr,sptr,0); } else { sendto_one(sptr,":%s NOTICE %s :Couldn't write temp kline file, aborted", me.name,parv[0]); return -1; } if(!pairme) { sendto_one(sptr, ":%s NOTICE %s :No K-Line for %s@%s", me.name, parv[0],user,host); return 0; } sendto_one(sptr, ":%s NOTICE %s :K-Line for [%s@%s] is removed", me.name, parv[0], user,host); sendto_realops("%s has removed the K-Line for: [%s@%s]", parv[0], user, host); irclog(L_NOTICE, "%s removed K-Line for [%s@%s]", parv[0], user, host); return 0; } /* * flush_write() * * inputs - pointer to client structure of oper requesting unkline * - out is the file descriptor * - buf is the buffer to write * - ntowrite is the expected number of character to be written * - temppath is the temporary file name to be written * output - YES for error on write * - NO for success * side effects - if successful, the buf is written to output file * if a write failure happesn, and the file pointed to * by temppath, if its non NULL, is removed. * * The idea here is, to be as robust as possible when writing to the * kline file. * * -Dianora */ static int flush_write(aClient *sptr, FBFILE* out, char *buf, char *temppath) { int error_on_write = (fbputs(buf, out) < 0) ? YES : NO; if (error_on_write) { sendto_one(sptr,":%s NOTICE %s :Unable to write to %s", me.name, sptr->name, temppath ); fbclose(out); if(temppath != (char *)NULL) (void)unlink(temppath); } return(error_on_write); } /* ** remove_tkline_match() * * un-kline a temporary k-line. * */ static int remove_tkline_match(char *host,char *user, unsigned long ip) { aConfItem *kill_list_ptr; aConfItem *last_kill_ptr=(aConfItem *)NULL; if(!temporary_klines && !temporary_ip_klines) return NO; if(ip) { kill_list_ptr = temporary_ip_klines; while(kill_list_ptr) { if((ip & kill_list_ptr->ip_mask) == kill_list_ptr->ip) { if(last_kill_ptr) last_kill_ptr->next = kill_list_ptr->next; else temporary_ip_klines = kill_list_ptr->next; free_conf(kill_list_ptr); return YES; } else { last_kill_ptr = kill_list_ptr; kill_list_ptr = kill_list_ptr->next; } } return NO; } else { kill_list_ptr = temporary_klines; while(kill_list_ptr) { if( !irccmp(kill_list_ptr->host,host) && !irccmp(kill_list_ptr->user,user)) /* match */ { if(last_kill_ptr) last_kill_ptr->next = kill_list_ptr->next; else temporary_klines = kill_list_ptr->next; free_conf(kill_list_ptr); return YES; } else { last_kill_ptr = kill_list_ptr; kill_list_ptr = kill_list_ptr->next; } } return NO; } } /* ** m_undline ** added May 28th 2000 by Toby Verrall ** based totally on m_unkline ** ** parv[0] = sender nick ** parv[1] = dline to remove */ int m_undline (aClient *cptr,aClient *sptr,int parc,char *parv[]) { FBFILE* in; FBFILE* out; int pairme = NO; char buf[BUFSIZE]; char buff[BUFSIZE]; /* matches line definition in s_conf.c */ char temppath[256]; const char *filename; /* filename to use for undline */ char *cidr; char *p; unsigned long ip_host; unsigned long ip_mask; int error_on_write = NO; mode_t oldumask; ircsprintf(temppath, "%s/%s.tmp", ConfigFileEntry.etcpath, "kline.conf"); if (check_registered(sptr)) { return -1; } if (!IsAnOper(sptr)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (!IsSetOperUnkline(sptr)) { sendto_one(sptr,":%s NOTICE %s :You have no U flag",me.name, parv[0]); return 0; } if ( parc < 2 ) { sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "UNDLINE"); return 0; } cidr = parv[1]; if (!is_address(cidr,&ip_host,&ip_mask)) { sendto_one(sptr, ":%s NOTICE %s :Invalid parameters", me.name, parv[0]); return 0; } filename = get_conf_name(DLINE_TYPE); if( (in = fbopen(filename, "r")) == 0) { sendto_one(sptr, ":%s NOTICE %s :Cannot open %s", me.name,parv[0],filename); return 0; } oldumask = umask(0); /* ircd is normally too paranoid */ if( (out = fbopen(temppath, "w")) == 0) { sendto_one(sptr, ":%s NOTICE %s :Cannot open %s", me.name,parv[0],temppath); fbclose(in); umask(oldumask); /* Restore the old umask */ return 0; } umask(oldumask); /* Restore the old umask */ /* #toot!~toot@127.0.0.1 D'd: 123.4.5.0/24:test (2000/05/28 12.48) D:123.4.5.0/24:test (2000/05/28 12.48) */ while(fbgets(buf, sizeof(buf), in)) { if((buf[1] == ':') && ((buf[0] == 'd') || (buf[0] == 'D'))) { /* its a D: line */ char *found_cidr; strncpy_irc(buff, buf, BUFSIZE); /* extra paranoia */ p = strchr(buff,'\n'); if(p) *p = '\0'; found_cidr = buff + 2; /* point past the D: */ p = strchr(found_cidr,':'); if(p == (char *)NULL) { sendto_one(sptr, ":%s NOTICE %s :D-Line file corrupted", me.name, parv[0]); sendto_one(sptr, ":%s NOTICE %s :Couldn't find CIDR", me.name, parv[0]); if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); continue; /* This D line is corrupted ignore */ } *p = '\0'; if(irccmp(cidr,found_cidr)) { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); } else pairme++; } else if(buf[0] == '#') { char *found_cidr; strncpy_irc(buff, buf, BUFSIZE); /* #toot!~toot@127.0.0.1 D'd: 123.4.5.0/24:test (2000/05/28 12.48) D:123.4.5.0/24:test (2000/05/28 12.48) If its a comment coment line, i.e. #ignore this line Then just ignore the line */ p = strchr(buff,':'); if(p == (char *)NULL) { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); continue; } *p = '\0'; p++; found_cidr = p; p = strchr(found_cidr,':'); if(p == (char *)NULL) { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); continue; } *p = '\0'; while(*found_cidr == ' ') found_cidr++; if( (irccmp(found_cidr,cidr))) { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); } } else /* its the ircd.conf file, and not a D line or comment */ { if(!error_on_write) error_on_write = flush_write(sptr, out, buf, temppath); } } fbclose(in); if(!error_on_write) { fbclose(out); (void)rename(temppath, filename); rehash(cptr,sptr,0); } else { sendto_one(sptr,":%s NOTICE %s :Couldn't write D-line file, aborted", me.name,parv[0]); return -1; } if(!pairme) { sendto_one(sptr, ":%s NOTICE %s :No D-Line for %s", me.name, parv[0],cidr); return 0; } sendto_one(sptr, ":%s NOTICE %s :D-Line for [%s] is removed", me.name, parv[0], cidr); sendto_ops("%s has removed the D-Line for: [%s]", parv[0], cidr); irclog(L_NOTICE, "%s removed D-Line for [%s]", parv[0], cidr); return 0; }