/* * ---------------------------------------------------------------- * Night Light IRC Proxy - Channel User * ---------------------------------------------------------------- * Copyright (C) 1997-2007 Jonas Kvinge * All rights reserved. * * 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 2 of the License, 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Last modified by: * Jonas Kvinge (03.12.2007) * */ #define CHAN_USER_C #define NEED_SYS_TYPES_H 1 /* Extra types */ #define NEED_SYS_PARAM_H 1 /* Some systems need this */ #define NEED_LIMITS_H 1 /* Kernel limits */ #define NEED_STDARG_H 1 /* va_list, etc */ #define NEED_ERRNO_H 1 /* errno */ #define NEED_CTYPE_H 1 /* isdigit(), etc */ #define NEED_NETINET_IN_H 1 /* in_addr, sockaddr_in, etc */ #define NEED_ARPA_INET_H 0 /* inet_ntoa(), inet_aton(), etc */ #define NEED_STDIO_H 1 /* Standard C UNIX functions */ #define NEED_STDLIB_H 1 /* malloc(), exit(), atoi(), etc */ #define NEED_TIME_H 1 /* time(), etc */ #define NEED_SYSCTL_H 0 /* sysctl(), etc */ #define NEED_SYS_STAT_H 0 /* chmod(), mkdir(), etc */ #define NEED_SYS_UIO_H 0 /* iovec, etc */ #define NEED_FCNTL_H 1 /* open(), creat(), fcntl(), etc */ #define NEED_SYS_IOCTL_H 0 /* ioctl(), etc */ #define NEED_SYS_FILIO_H 0 /* Solaris need this for ioctl(), etc */ #define NEED_UNISTD_H 1 /* Unix standard functions */ #define NEED_STRING_H 1 /* C string functions */ #define NEED_SIGNAL_H 0 /* Signal functions */ #define NEED_SYS_SOCKET_H 0 /* Socket functions */ #define NEED_NETDB_H 0 /* Network database functions */ #define NEED_ARPA_NAMESER_H 0 /* Nameserver definitions */ #define NEED_GETUSERPW_HEADERS 0 /* Functions to retrive system passwords */ #define NEED_ARES 0 /* Functions needed for ares */ #define NEED_SSL 1 /* Needed for SSL support */ #include "includes.h" #include "irc.h" #include "conn.h" #include "chan.h" #include "chan_user.h" #include "chan_mode.h" #include "autoop_conf.h" /* VARIABLES - JONAS (30.07.2000) */ static CHANUSER_HASHMEMS ChanUser_Hash_Map[CHANUSER_HASHMAPSIZE]; static CHANUSER_HASHMEMS ChanUser_Hash_Weight_Table[CHAR_MAX - CHAR_MIN + 1]; extern struct AutoOPConf_Struct *AutoOPConf_Head; extern struct Conn_Struct *Conn_Head; /* CHAN_ADDUSER FUNCTION - JONAS (26.07.2001) */ struct ChanUser_Struct *chan_adduser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, const char *const NickPT, const char *const UserPT, const char *const HostPT, const char *const NUHPT) { struct ChanUser_Struct *ChanUser = NULL; struct ChanUser_Struct *ChanUser_NEW = NULL; CHANUSER_HASHREGS Hash = 0; assert(ConnS != NULL); assert(ChanS != NULL); assert(NickPT != NULL); assert(UserPT != NULL); assert(HostPT != NULL); assert(NUHPT != NULL); ChanUser = chan_getuser(ConnS, ChanS, NickPT); if (ChanUser != NULL) { aerrno = AEEXISTS; return(ChanUser); } ChanUser_NEW = malloc(sizeof(struct ChanUser_Struct)); if (ChanUser_NEW == NULL) { aerrno = AEMALLOC; return(NULL); } memset(ChanUser_NEW, 0, sizeof(struct ChanUser_Struct)); chan_inituser(ConnS, ChanS, ChanUser_NEW); ChanUser_NEW->Nick = strdup(NickPT); ChanUser_NEW->User = strdup(UserPT); ChanUser_NEW->Host = strdup(HostPT); ChanUser_NEW->NUH = strdup(NUHPT); ChanUser_NEW->Time = NOW; if ((ChanUser_NEW->Nick == NULL) || (ChanUser_NEW->User == NULL) || (ChanUser_NEW->Host == NULL) || (ChanUser_NEW->NUH == NULL)) { free(ChanUser_NEW->Nick); free(ChanUser_NEW->User); free(ChanUser_NEW->Host); free(ChanUser_NEW); aerrno = AEMALLOC; return(NULL); } if (ChanS->User_Head == NULL) { ChanS->User_Head = ChanUser_NEW; ChanS->User_Tail = ChanUser_NEW; } else { ChanUser = ChanS->User_Tail; ChanUser->Next = ChanUser_NEW; ChanUser_NEW->Prev = ChanUser; ChanS->User_Tail = ChanUser_NEW; } Hash = chanuser_strhash(ChanUser_NEW->Nick); ChanUser = ChanS->User_Table[Hash]; if (ChanUser != NULL) { ChanUser->PrevH = ChanUser_NEW; } ChanUser_NEW->NextH = ChanUser; ChanS->User_Table[Hash] = ChanUser_NEW; ChanS->Users++; aerrno = AESUCCESS; return(ChanUser_NEW); } /* CHAN_CHANGEUSER FUNCTION - JONAS (26.07.2001) */ signed short int chan_changeuser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser, const char *const NickPT) { struct ChanUser_Struct *ChanUserH = NULL; CHANUSER_HASHREGS Hash = 0; CHANUSER_HASHREGS NewHash = 0; assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanUser != NULL); assert(NickPT != NULL); Hash = chanuser_strhash(ChanUser->Nick); NewHash = chanuser_strhash(NickPT); for (ChanUserH = ChanS->User_Table[Hash] ; ((ChanUserH != NULL) && (ChanUserH != ChanUser)) ; ChanUserH = ChanUserH->NextH); assert(ChanUserH == ChanUser); if (ChanUserH->PrevH != NULL) { ChanUserH->PrevH->NextH = ChanUserH->NextH; } if (ChanUserH->NextH != NULL) { ChanUserH->NextH->PrevH = ChanUserH->PrevH; } if (ChanS->User_Table[Hash] == ChanUserH) { ChanS->User_Table[Hash] = ChanUserH->NextH; } ChanUserH = ChanS->User_Table[NewHash]; if (ChanUserH != NULL) { ChanUserH->PrevH = ChanUser; } ChanUser->NextH = ChanUserH; ChanS->User_Table[NewHash] = ChanUser; ChanUser->Nick = strrealloc(ChanUser->Nick, NickPT); if (aerrno != AESUCCESS) { return(ERROR); } FAKELOOP { unsigned long int NUHLen = strlen(NickPT) + strlen(ChanUser->User) + strlen(ChanUser->Host) + 2; char NUH[NUHLen+1]; snprintf(NUH, NUHLen+1, "%s!%s@%s", NickPT, ChanUser->User, ChanUser->Host); ChanUser->NUH = strrealloc(ChanUser->NUH, NUH); if (aerrno != AESUCCESS) { return(ERROR); } } aerrno = AESUCCESS; return(SUCCESS); } /* CHAN_REMUSER FUNCTION - JONAS (26.07.2001) */ void chan_remuser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser) { CHANUSER_HASHREGS Hash = 0; struct ChanUser_Struct *ChanUserH = NULL; assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanUser != NULL); if (ChanUser == ChanS->Me) ChanS->Me = NULL; if (ChanUser->Prev == NULL) { ChanS->User_Head = ChanUser->Next; } else { ChanUser->Prev->Next = ChanUser->Next; } if (ChanUser->Next == NULL) { ChanS->User_Tail = ChanUser->Prev; } else { ChanUser->Next->Prev = ChanUser->Prev; } Hash = chanuser_strhash(ChanUser->Nick); for (ChanUserH = ChanS->User_Table[Hash] ; ((ChanUserH != NULL) && (ChanUserH != ChanUser)) ; ChanUserH = ChanUserH->NextH); assert(ChanUserH == ChanUser); if (ChanUserH->PrevH != NULL) { ChanUserH->PrevH->NextH = ChanUserH->NextH; } if (ChanUserH->NextH != NULL) { ChanUserH->NextH->PrevH = ChanUserH->PrevH; } if (ChanS->User_Table[Hash] == ChanUserH) { ChanS->User_Table[Hash] = ChanUserH->NextH; } chan_inituser(ConnS, ChanS, ChanUser); free(ChanUser); ChanS->Users--; } /* CHAN_GETUSER FUNCTION - JONAS (26.07.2001) */ struct ChanUser_Struct *chan_getuser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, const char *const NickPT) { CHANUSER_HASHREGS Hash = 0; struct ChanUser_Struct *ChanUser = NULL; struct ChanUser_Struct *ChanUserH = NULL; assert(ConnS != NULL); assert(ChanS != NULL); assert(NickPT != NULL); Hash = chanuser_strhash(NickPT); for (ChanUser = ChanS->User_Table[Hash] ; ((ChanUser != NULL) && (strcasecmp(NickPT, ChanUser->Nick) != FALSE)) ; ChanUser = ChanUser->NextH); if (ChanUser == NULL) { aerrno = AENOMATCH; return(NULL); } if (ChanUser != ChanS->User_Table[Hash]) { if (ChanUser->PrevH != NULL) { ChanUser->PrevH->NextH = ChanUser->NextH; } if (ChanUser->NextH != NULL) { ChanUser->NextH->PrevH = ChanUser->PrevH; } ChanUserH = ChanS->User_Table[Hash]; ChanUserH->PrevH = ChanUser; ChanUser->PrevH = NULL; ChanUser->NextH = ChanUserH; ChanS->User_Table[Hash] = ChanUser; } aerrno = AESUCCESS; return(ChanUser); } /* CHANUSER_HASH_INIT FUNCTION - JONAS (26.07.2001) */ void chanuser_hash_init(void) { signed short int Index1 = 0; signed short int Index2 = 0; unsigned long Count1 = 0; unsigned long Count2 = 0; for (Index1 = CHAR_MIN ; Index1 <= CHAR_MAX ; Index1++) { ChanUser_Hash_Weight(Index1) = (CHANUSER_HASHMEMS) (CHANUSER_HASHSTEP * ((char) Index1)); } for (Index1 = CHAR_MIN ; Index1 <= CHAR_MAX ; Index1++) { for (Index2 = CHAR_MIN ; Index2 < Index1 ; Index2++) { if (HASHEQ(Index1, Index2)) { ChanUser_Hash_Weight(Index1) = ChanUser_Hash_Weight(Index2); } } } for (Count1 = 0 ; Count1 < (unsigned long) CHANUSER_HASHMAPSIZE ; Count1++) { Count2 = Count1; Count2 *= (unsigned long) CHANUSER_HASHSHIFT; Count2 %= (unsigned long) CHANUSER_HASHSIZE; ChanUser_Hash_Map[Count1] = (CHANUSER_HASHMEMS) Count2; } } /* CHANUSER_STRHASH FUNCTION - JONAS (26.07.2001) */ static CHANUSER_HASHREGS chanuser_strhash(const char *NickPT) { CHANUSER_HASHREGS Hash = ChanUser_Hash_Weight(*NickPT); NickPT++; while (*NickPT != '\0') { Hash = ChanUser_Hash_Map[Hash] + ChanUser_Hash_Weight(*NickPT); NickPT++; } return(ChanUser_Hash_Map[Hash]); } /* CHAN_INITUSER FUNCTION - JONAS (05.07.2000) */ void chan_inituser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser) { assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanUser != NULL); FREE(ChanUser->Nick); FREE(ChanUser->User); FREE(ChanUser->Host); FREE(ChanUser->NUH); } /* CHAN_DESTROYUSERS FUNCTION - JONAS (30.07.2001) */ void chan_destroyusers(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS) { assert(ConnS != NULL); assert(ChanS != NULL); while (ChanS->User_Head != NULL) { chan_remuser(ConnS, ChanS, ChanS->User_Head); } assert(ChanS->Users == 0); } /* CHANUSER_AUTOOPCHECK FUNCTION - JONAS (27.12.2007) */ void chanuser_autoopcheck(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser) { struct AutoOPConf_Struct *AutoOPConf = NULL; struct AutoOPConfChan_Struct *AutoOPConfChan = NULL; for (AutoOPConf = AutoOPConf_Head ; AutoOPConf != NULL ; AutoOPConf = AutoOPConf->Next) { if (strwm(AutoOPConf->NUH, ChanUser->NUH) != TRUE) { continue; } if (strwm(AutoOPConf->Connection, ConnS->Name) != TRUE) { continue; } for (AutoOPConfChan = AutoOPConf->Chan_Head ; AutoOPConfChan != NULL ; AutoOPConfChan = AutoOPConfChan->Next) { if (strwm(AutoOPConfChan->Chan, ChanS->Chan) != TRUE) { continue; } chan_op(ConnS, ChanS, ChanUser); ChanUser_SetAutoOPCheck(ChanUser); return; } } ChanUser_SetAutoOPCheck(ChanUser); } /* CHAN_OP FUNCTION - JONAS (05.07.2000) */ void chan_op(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser) { struct Conn_Struct *P_ConnS = NULL; struct Chan_Struct *P_ChanS = NULL; struct ChanUser_Struct *P_ChanUser = NULL; char Mode[IRCMODELINELEN+1] = ""; assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanUser != NULL); assert(ChanUser_IsOP(ChanS->Me)); assert(!ChanUser_IsOP(ChanUser)); assert(!ChanUser_IsSentOP(ChanUser)); for (P_ConnS = Conn_Head ; P_ConnS != NULL ; P_ConnS = P_ConnS->Next) { if (!Conn_IsWelcome(P_ConnS)) { continue; } P_ChanS = chan_get(P_ConnS, ChanS->Chan); if (P_ChanS == NULL) { continue; } if (!ChanUser_IsOP(P_ChanS->Me)) { continue; } P_ChanUser = chan_getuser(P_ConnS, P_ChanS, ChanUser->Nick); if (P_ChanUser == NULL) { continue; } if ((strcasecmp(ChanUser->User, P_ChanUser->User) != FALSE) || (strcasecmp(ChanUser->Host, P_ChanUser->Host) != FALSE)) { continue; } if (ChanUser_IsSentOP(P_ChanUser)) { return; } } DEBUGPRINT(BITMASK_DEBUG_CONN, "Connection %s is requesting OP for %s on %s.", ConnS->Name, ChanUser->Nick, ChanS->Chan); ChanUser_SetSentOP(ChanUser); ChanUser->SentOPTime = NOW; snprintf(Mode, IRCMODELINELEN+1, "+o %s", ChanUser->Nick); chan_addmode(ConnS, ChanS, Mode, CHANMODEPRIOOP, 0); }