/* * m_quit * parv[0] = sender prefix * parv[1] = comment */ int m_quit(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) #ifdef TIDY_QUIT { buf[0] = '\0'; if ((parc > 1) && parv[1]) { if (strlen(parv[1]) > (MAX_QUIT_LENGTH - 2)) parv[1][MAX_QUIT_LENGTH - 2] = '\0'; /* Don't add quotes to a null message */ if (MyConnect(sptr) && *parv[1]) { strncpy_irc(buf, "\"", 2); strncat(buf, strip_colour(parv[1]), MAX_QUIT_LENGTH - 2); strncat(buf, "\"", 1); } else strncpy_irc(buf, parv[1], BUFSIZE); } sptr->flags |= FLAGS_NORMALEX; #ifdef ANTI_SPAM_EXIT_MESSAGE /* Your quit message is suppressed if: * * You haven't been connected to the server for long enough */ if( !IsServer(sptr) && MyConnect(sptr) && (sptr->firsttime + ANTI_SPAM_EXIT_MESSAGE_TIME) > CurrentTime) strcpy(buf, "Client Quit"); else if (MyConnect(sptr) && IsPerson(sptr)) { /* Or you are in a channel to which you cannot send */ struct SLink *chptr; for (chptr = sptr->user->channel; chptr; chptr = chptr->next) { if (can_send(sptr, chptr->value.chptr) != 0) { strcpy(buf, "Client Quit"); break; } } } #endif if (IsPerson(sptr)) { sendto_local_ops_flag(UMODE_CCONN, "Client exiting: %s (%s@%s) [%s] [%s] [%s]", sptr->name, sptr->username, sptr->host, #ifdef WINTRHAWK buf, #else (sptr->flags & FLAGS_NORMALEX) ? "Client Quit" : comment, #endif /* WINTRHAWK */ sptr->sockhost, sptr->servptr ? sptr->servptr->name : "<null>"); } return IsServer(sptr) ? 0 : exit_client(cptr, sptr, sptr, buf); }
void TreeAddKline(struct ServerBan *kptr) { char **hostv; char hostname[HOSTLEN + 1]; int hostpieces; assert(kptr != NULL); /* * So we don't destroy kptr->hostname, use another buffer */ memset(hostname, 0, sizeof(hostname)); strncpy_irc(hostname, kptr->hostname, HOSTLEN); hostpieces = BreakupHost(hostname, &hostv); if (IsSortable(hostpieces, hostv)) CreateSubTree(&KlineTree, NULL, kptr, hostpieces, hostv); else { fprintf(stderr, "HOSTNAME [%s] IS NOT SORTABLE\n", kptr->hostname); AddUnsortableKline(kptr); } MyFree(hostv); } /* TreeAddKline() */
/* * m_pass() - Added Sat, 4 March 1989 * * * m_pass - PASS message handler * parv[0] = sender prefix * parv[1] = password * parv[2] = optional extra version information */ int m_pass(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { char* password = parc > 1 ? parv[1] : NULL; if (EmptyString(password)) { sendto_one(cptr, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "PASS"); return 0; } if (!MyConnect(sptr) || (!IsUnknown(cptr) && !IsHandshake(cptr))) { sendto_one(cptr, form_str(ERR_ALREADYREGISTRED), me.name, parv[0]); return 0; } strncpy_irc(cptr->passwd, password, PASSWDLEN); if (parc > 2) { /* * It looks to me as if orabidoo wanted to have more * than one set of option strings possible here... * i.e. ":AABBTS" as long as TS was the last two chars * however, as we are now using CAPAB, I think we can * safely assume if there is a ":TS" then its a TS server * -Dianora */ if ((0 == irccmp(parv[2], "TS")) && (cptr->tsinfo == 0)) cptr->tsinfo = TS_DOESTS; } return 0; }
/* * Whats happening in this next loop ? Well, it takes a name like * foo.bar.edu and proceeds to earch for *.edu and then *.bar.edu. * This is for checking full server names against masks although * it isnt often done this way in lieu of using matches(). * * Rewrote to do *.bar.edu first, which is the most likely case, * also made const correct * --Bleep */ static struct Client* hash_find_masked_server(const char* name) { char buf[HOSTLEN + 1]; char* p = buf; char* s; struct Client* server; if ('*' == *name || '.' == *name) return 0; /* * copy the damn thing and be done with it */ strncpy_irc(buf, name, HOSTLEN + 1); buf[HOSTLEN] = '\0'; while ((s = strchr(p, '.')) != 0) { *--s = '*'; /* * Dont need to check IsServer() here since nicknames cant * have *'s in them anyway. */ if ((server = hash_find_client(s, NULL))) return server; p = s + 2; } return 0; }
struct ServerBan * SearchKlineTree(char *username, char *hostname) { char host[HOSTLEN + 1]; char **hostv; int hostc, ii; struct Level *ret; struct ServerBan *tmp; memset(host, 0, sizeof(host)); strncpy_irc(host, hostname, HOSTLEN); hostc = BreakupHost(host, &hostv); if (!(++SerialNumber)) { ++SerialNumber; ResetTree(&IlineTree); ResetTree(&KlineTree); } while ((ret = SearchSubTree(&KlineTree, hostc, hostv))) { if (!ret->numptrs) { log(L_ERROR, "SearchKlineTree(): search result has 0 Kline pointers"); MyFree(hostv); /*ResetTree(&KlineTree);*/ return (NULL); } /* * Check the username */ for (ii = 0; ii < ret->numptrs; ++ii) { tmp = (struct ServerBan *) ret->typeptrs[ii]; if (match(tmp->username, username)) { MyFree(hostv); /*ResetTree(&KlineTree);*/ return (tmp); } } } /*ResetTree(&KlineTree);*/ /* * We failed to locate the Kline in our tree - search * the unsortable list */ tmp = FindUnsortableKline(username, hostname); MyFree(hostv); return (tmp); } /* SearchKlineTree() */
void cr_sendresponse(struct Client * cptr, struct ConfItem * c_conf, char * chall, char* salt) { struct ConfItem* n_conf = find_conf_by_name(cptr->name, CONF_NOCONNECT_SERVER); char work[PASSWDLEN*2], hash[40]; strncpy_irc(work, chall, PASSWDLEN + 1); strncpy_irc(work + strlen(work), c_conf->passwd ? libshadow_md5_crypt(c_conf->passwd, salt) : "", PASSWDLEN + 1); cr_hashstring(work, hash); if (!IsUnknown(cptr) || (strcmp(cptr->passwd, n_conf->passwd) == 0)) { sendto_one(cptr, "RESP %s", hash); SetResponded(cptr); sendto_ops_flag(UMODE_EXTERNAL, "Sent password response to %s", cptr->name); } else { strncpy_irc(cptr->response, hash, 40); } }
/* * All command line parameters have the syntax "-f string" or "-fstring" * OPTIONS: * -d filename - specify d:line file * -f filename - specify config file * -h hostname - specify server name * -k filename - specify k:line file * -l filename - specify log file * -n - do not fork, run in foreground * -v - print daemon version and exit * -x - set debug level, if compiled for debug logging */ static void parse_command_line(int argc, char* argv[]) { const char* options = "d:f:h:k:l:nvx:"; int opt; while ((opt = getopt(argc, argv, options)) != EOF) { switch (opt) { case 'd': if (optarg) ConfigFileEntry.dpath = optarg; break; case 'f': #ifdef CMDLINE_CONFIG if (optarg) ConfigFileEntry.configfile = optarg; #endif break; case 'k': #ifdef KPATH if (optarg) ConfigFileEntry.klinefile = optarg; #endif break; case 'h': if (optarg) strncpy_irc(me.name, optarg, HOSTLEN); break; case 'l': if (optarg) logFileName = optarg; break; case 'n': bootDaemon = 0; break; case 'v': printf("ircd %s\n\tzlib %s\n\tircd_dir: %s\n", ircd_version, #ifndef ZIP_LINKS "not used", #else zlibVersion(), #endif ConfigFileEntry.dpath); exit(0); break; /* NOT REACHED */ case 'x': #ifdef DEBUGMODE if (optarg) { debuglevel = atoi(optarg); debugmode = optarg; } #endif break; default: bad_command(); break; } } }
void cr_sendchallenge(struct Client * cptr, struct ConfItem * n_conf) { /* Create a challenge using random data and sending it as a hex value. * Store this hex value in cptr->passwd, don't want more fields in cptr. * As this is sent before anything else, we pass the server name too so * the receiving end can look up our C/N lines. */ char chall[17]=""; unsigned int c; int i; for (i=0; i<16; i++) { c = (unsigned int) (16.0 * (random() / (RAND_MAX + 1.0))); chall[i] = (c>=10) ? (c - 10 + 'A' ) : (c + '0'); } chall[16]=0; strncpy_irc(cptr->name, n_conf->name, HOSTLEN + 1); strncpy_irc(cptr->passwd, chall, PASSWDLEN + 1); sendto_one(cptr, "CHALL %s %s %s %s :TS", me.name, cptr->name, chall, get_salt(n_conf->passwd)); SetChallenged(cptr); sendto_ops_flag(UMODE_EXTERNAL, "Sent password challenge to %s", cptr->name); }
void cr_gotresponse(struct Client * cptr, char * resp) { struct ConfItem * n_conf; char work[PASSWDLEN*2], hash[36]; n_conf = find_conf_by_name(cptr->name, CONF_NOCONNECT_SERVER); if (n_conf && cptr->passwd[0]) { strncpy_irc(work, cptr->passwd, PASSWDLEN + 1); strncpy_irc(work + strlen(work), n_conf->passwd ? n_conf->passwd : "", PASSWDLEN + 1); cr_hashstring(work, hash); if (!strcmp(resp, hash)) { strncpy_irc(cptr->passwd, n_conf->passwd, PASSWDLEN + 1); sendto_ops_flag(UMODE_SEEROUTING, "Got a good password response from %s", cptr->name); /* OK, do we have a response pending ourself? */ if (cptr->response[0] && !Responded(cptr)) { sendto_one(cptr, "RESP %s", cptr->response); cptr->response[0] = '\0'; SetResponded(cptr); sendto_ops_flag(UMODE_EXTERNAL, "Sent password response to %s", cptr->name); } } else { sendto_ops_flag(UMODE_SEEROUTING, "Failed password response from %s", cptr->name); } } }
void add_history(aClient* cptr, int online) { aWhowas* who = &WHOWAS[whowas_next]; assert(0 != cptr); if (who->hashv != -1) { if (who->online) del_whowas_from_clist(&(who->online->whowas),who); del_whowas_from_list(&WHOWASHASH[who->hashv], who); } who->hashv = hash_whowas_name(cptr->name); who->logoff = CurrentTime; /* * NOTE: strcpy ok here, the sizes in the client struct MUST * match the sizes in the whowas struct */ strncpy_irc(who->name, cptr->name, NICKLEN); who->name[NICKLEN] = '\0'; strcpy(who->username, cptr->username); strcpy(who->hostname, cptr->host); strcpy(who->realname, cptr->info); /* Its not string copied, a pointer to the scache hash is copied -Dianora */ /* strncpy_irc(who->servername, cptr->user->server, HOSTLEN); */ who->servername = cptr->user->server; if (online) { who->online = cptr; add_whowas_to_clist(&(cptr->whowas), who); } else who->online = NULL; add_whowas_to_list(&WHOWASHASH[who->hashv], who); whowas_next++; if (whowas_next == NICKNAMEHISTORYLENGTH) whowas_next = 0; }
void change_nick(aClient *acptr, char *newnick) { char nick[NICKLEN + 2]; strncpy_irc(nick, newnick, NICKLEN); nick[NICKLEN] = '\0'; ClearIdentified(acptr); /* maybe not needed, but safe -Lamego */ /* send change to common channels */ sendto_common_channels(acptr, ":%s NICK :%s", acptr->name, nick); if (acptr->user) { acptr->tsinfo = CurrentTime; add_history(acptr,1); /* propagate to all servers */ sendto_serv_butone(NULL, ":%s NICK %s :%lu", acptr->name, nick, acptr->tsinfo); } /* ** Finally set new nick name. */ if (acptr->name[0]) { del_from_client_hash_table(acptr->name, acptr); hash_check_watch(acptr, RPL_LOGOFF); } strcpy(acptr->name, nick); add_to_client_hash_table(nick, acptr); hash_check_watch(acptr, RPL_LOGON); /* Lets apply nick change delay (if needed) */ acptr->services_nick_change++; if(acptr->services_nick_change>1) { acptr->number_of_nick_changes = MAX_NICK_CHANGES+1; acptr->last_nick_change = CurrentTime; acptr->services_nick_change = 0; } }
/* * m_server - SERVER message handler * parv[0] = sender prefix * parv[1] = servername * parv[2] = hopcount * parv[3] = version * parv[4] = serverinfo */ int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { int i; char info[REALLEN + 1]; char* host; struct Client* acptr; struct Client* bcptr; struct ConfItem* aconf; int hop; char *remversion = NULL; info[0] = '\0'; /* inpath = get_client_name(cptr,FALSE); */ if (parc < 2 || *parv[1] == '\0') { sendto_one(cptr,"ERROR :No servername"); return 0; } hop = 0; host = parv[1]; if (parc > 4 && atoi(parv[2])) { hop = atoi(parv[2]); strncpy_irc(info, parv[4], REALLEN); info[REALLEN] = '\0'; remversion = parv[3]; } else if (parc > 3 && atoi(parv[2])) { hop = atoi(parv[2]); strncpy_irc(info, parv[3], REALLEN); info[REALLEN] = '\0'; } else if (parc > 2) { /* * XXX - hmmmm */ strncpy_irc(info, parv[2], REALLEN); info[REALLEN] = '\0'; if ((parc > 3) && ((i = strlen(info)) < (REALLEN - 2))) { strcat(info, " "); strncat(info, parv[3], REALLEN - i - 2); info[REALLEN] = '\0'; } } /* * July 5, 1997 * Rewritten to throw away server cruft from users, * combined the hostname validity test with * cleanup of host name, so a cleaned up hostname * can be returned as an error if necessary. - Dianora * * yes, the if(strlen) below is really needed!! */ if (strlen(host) > HOSTLEN) host[HOSTLEN] = '\0'; if (IsPerson(sptr)) { /* * a USER tries something fishy... ;-) */ if (IsServer(cptr)) { /* heh, obviously we've never encountered this condition .. * get_client_name returns a little sumpin-sumpin static, we * can't use it twice here. -gnp */ char nbuf[HOSTLEN * 2 + USERLEN + 5]; /* same size as in s_misc.c */ #ifdef HIDE_SERVERS_IPS strcpy(nbuf, get_client_name(sptr,MASK_IP)); #else strcpy(nbuf, get_client_name(sptr,SHOW_IP)); #endif sendto_realops("SERVER command from remote user %s -- %s is a hacked server", nbuf, #ifdef HIDE_SERVERS_IPS get_client_name(cptr,MASK_IP)); #else get_client_name(cptr,SHOW_IP)); #endif } else { sendto_one(sptr, form_str(ERR_UNKNOWNCOMMAND), me.name, parv[0], "SERVER"); } return 0; }
struct Iline * SearchIlineTree(char *username, char *hostname) { char host[HOSTLEN + 1]; char **hostv; int hostc, ii; struct Level *ret; struct Iline *tmp; memset(host, 0, sizeof(host)); strncpy_irc(host, hostname, HOSTLEN); hostc = BreakupHost(host, &hostv); /* * A loop is needed to continually search the IlineTree * because of the username problem. Suppose we have 2 * Ilines: * (a) foo@*.net * (b) *@*.underworld.net * and suppose the client comes from [email protected]. * SearchSubTree() may return (a) since the hostname part * actually does match, but this routine will return NULL * because it cannot find a username match, even though * there is another I: line that matches. Therefore, this * loop will continue searching the tree until absolutely * no more hostname matches are found. * * We can be sure it will not return the same I: line twice * because the variable SerialNumber gets continually * incremented. When a node has been searched, it's * serial is set to the current SerialNumber variable, so * we know it has been searched if it's serial matches * SerialNumber. */ if (!(++SerialNumber)) { /* * SerialNumber will eventually roll over to 0 when it * reaches it's 32 bit limit - reset both trees and * increment SerialNumber to 1. */ ++SerialNumber; ResetTree(&IlineTree); ResetTree(&KlineTree); } while ((ret = SearchSubTree(&IlineTree, hostc, hostv))) { if (!ret->numptrs) { log(L_ERROR, "SearchIlineTree(): search result has 0 Iline pointers"); MyFree(hostv); /*ResetTree(&IlineTree);*/ return (NULL); } /* * Now for the username check */ for (ii = 0; ii < ret->numptrs; ++ii) { tmp = (struct Iline *) ret->typeptrs[ii]; if (match(tmp->username, username)) { MyFree(hostv); /*ResetTree(&IlineTree);*/ return (tmp); } } } /*ResetTree(&IlineTree);*/ /* * We failed to locate the Iline in our tree - search * the unsortable list */ tmp = FindUnsortableIline(username, hostname); MyFree(hostv); return (tmp); } /* SearchIlineTree() */
static int inetport(struct Listener* listener) { struct SOCKADDR_IN port_sin; int fd; int opt = 1; /* * At first, open a new socket */ fd = socket(AFINET, SOCK_STREAM, 0); if (-1 == fd) { report_error("opening listener socket %s:%s", get_listener_name(listener), errno); return 0; } else if ((HARD_FDLIMIT - 10) < fd) { report_error("no more connections left for listener %s:%s", get_listener_name(listener), errno); CLOSE(fd); return 0; } /* * XXX - we don't want to do all this crap for a listener * set_sock_opts(listener); */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(opt))) { report_error("setting SO_REUSEADDR for listener %s:%s", get_listener_name(listener), errno); CLOSE(fd); return 0; } /* * Bind a port to listen for new connections if port is non-null, * else assume it is already open and try get something from it. */ memset(&port_sin, 0, sizeof(port_sin)); port_sin.SIN_FAMILY = AFINET; port_sin.SIN_PORT = htons(listener->port); #ifdef __CYGWIN__ port_sin.sin_addr = listener->addr; if (INADDR_ANY != listener->addr.S_ADDR) { strncpy_irc(listener->vhost, inetntoa((char *)&listener->addr), HOSTLEN); listener->name = listener->vhost; } #else #ifdef IPV6 bcopy((const char*)listener->addr.S_ADDR, (char*)port_sin.SIN_ADDR.S_ADDR, sizeof(struct IN_ADDR)); if ( bcmp((char*)listener->addr.S_ADDR, &INADDRANY, sizeof(struct IN_ADDR)) == 0 ) #else port_sin.sin_addr = listener->addr; if (INADDRANY != listener->addr.s_addr) #endif { struct addrinfo *ans; int ret; char port[5]; char tmp[HOSTLEN]; /* * XXX - blocking call to getaddrinfo */ sprintf( port, "%d", listener->port); #ifdef IPV6 inetntop(AFINET, &listener->addr, tmp, HOSTLEN); #else inet_ntop(AF_INET, &listener->addr, tmp, HOSTLEN); #endif ret = getaddrinfo(tmp, port, NULL, &ans ); if( ret == 0 && ans->ai_canonname) strncpy_irc(listener->vhost, ans->ai_canonname, HOSTLEN); } #endif if (bind(fd, (struct sockaddr*) &port_sin, sizeof(port_sin))) { report_error("binding listener socket %s:%s", get_listener_name(listener), errno); CLOSE(fd); return 0; } if (listen(fd, HYBRID_SOMAXCONN)) { report_error("listen failed for %s:%s", get_listener_name(listener), errno); CLOSE(fd); return 0; } /* * XXX - this should always work, performance will suck if it doesn't */ if (!set_non_blocking(fd)) report_error(NONB_ERROR_MSG, get_listener_name(listener), errno); listener->fd = fd; return 1; }
int m_snick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *acptr; if (IsPerson(sptr)) { if (IsServer(cptr)) { sendto_ops_flag(UMODE_SERVNOTICE, "SNICK command from remote user %s -- %s is a hacked server", sptr->name, cptr->name); } else { sendto_one(sptr, form_str(ERR_UNKNOWNCOMMAND), me.name, parv[0], "SNICK"); } return 0; } if (!IsServer(sptr)) return 0; if (parc < 3) { sendto_ops_flag(UMODE_DEBUG, "%s sent SNICK with no parameters", sptr->name); return 0; } if (!(acptr = find_client(parv[1], NULL))) { #if 0 /* we don't need this, SNICK is only sent after NICK -- jilles */ /* Ghost. Kill it. */ sendto_ops_flag(UMODE_SERVNOTICE, "Ghosted: %s from %s", parv[1], cptr->name); sendto_one(cptr, ":%s KILL %s :%s (%s ghosted %s)", me.name, parv[1], me.name, me.name, parv[1]); #endif return 0; } if (cptr != acptr->from) { /* Wrong direction. Ignore it to prevent it from being applied * to the wrong user. This code would never have been necessary * if the command had been :<user> SNICK in the first place. * -- jilles */ ServerStats->is_wrdi++; sendto_ops_flag(UMODE_DEBUG, "%s sent SNICK for %s, but %s is at %s", cptr->name, acptr->name, acptr->name, acptr->from->name); return 0; } if (!IsPerson(acptr)) { sendto_ops_flag(UMODE_DEBUG, "%s sent SNICK for non-person %s", sptr->name, acptr->name); return 0; } if (parc > 2) strncpy_irc(acptr->origname, parv[2], HOSTLEN + 1); if (parc > 3) strncpy_irc(acptr->spoofhost, parv[3], HOSTLEN + 1); if (parc > 4) acptr->firsttime = atol(parv[4]); if (parc > 5) strncpy_irc(acptr->dnshost, parv[5], HOSTLEN + 1); if (parc > 6) { strncpy_irc(acptr->user->servlogin, irccmp(parv[6], SERVLOGIN_NONE) ? parv[6] : "", SERVLOGINLEN + 1); } sendto_serv_butone(cptr, "SNICK %s %s %s %.1ld %s %s", acptr->name, acptr->origname, acptr->spoofhost, acptr->firsttime, acptr->dnshost, acptr->user->servlogin[0] ? acptr->user->servlogin : SERVLOGIN_NONE); return 0; }
int main(int argc, char *argv[]) { time_t delay = 0; aConfItem* aconf; if(geteuid() == 0) { fprintf(stderr, "ERROR: Don't run ircd as root!\n"); return -1; } /* * save server boot time right away, so getrusage works correctly */ if ((CurrentTime = time(0)) == -1) { fprintf(stderr, "ERROR: Clock Failure: %s\n", strerror(errno)); exit(errno); } /* * Setup corefile size immediately after boot */ setup_corefile(); /* * set initialVMTop before we allocate any memory */ initialVMTop = get_vm_top(); /* * Initialize the Blockheap allocator */ initBlockHeap(); ServerRunning = 0; memset(&me, 0, sizeof(me)); GlobalClientList = &me; /* Pointer to beginning of Client list */ cold_start = YES; /* set when server first starts up */ memset(&Count, 0, sizeof(Count)); Count.server = 1; /* us */ initialize_global_set_options(); #ifdef REJECT_HOLD reject_held_fds = 0; #endif ConfigFileEntry.dpath = DPATH; ConfigFileEntry.configfile = CPATH; /* Server configuration file */ #ifdef KPATH ConfigFileEntry.klinefile = KPATH; /* Server kline file */ #else ConfigFileEntry.klinefile = CPATH; #endif /* KPATH */ #ifdef DLPATH ConfigFileEntry.dlinefile = DLPATH; #else ConfigFileEntry.dlinefile = CPATH; #endif /* DLPATH */ #ifdef GLINES ConfigFileEntry.glinefile = GLINEFILE; #endif #ifdef ZIP_LINKS /* Make sure the include files match the library version number. */ /* configure takes care of looking for zlib and zlibVersion(). */ if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { fprintf(stderr, "WARNING: zlib include files differ from library.\n"); fprintf(stderr, "WARNING: ZIPLINKS may fail!\n"); fprintf(stderr, "WARNING: library %s, include files %s\n", zlibVersion(), ZLIB_VERSION); } #endif myargv = argv; umask(077); /* better safe than sorry --SRB */ parse_command_line(argc, argv); if (chdir(ConfigFileEntry.dpath)) { perror("chdir"); exit(-1); } /* * Check if daemon is already running */ check_pidfile(); init_sys(bootDaemon); init_log(logFileName); setup_signals(); initialize_message_files(); isupport = make_isupport(); dbuf_init(); /* set up some dbuf stuff to control paging */ init_hash(); clear_scache_hash_table(); /* server cache name table */ clear_ip_hash_table(); /* client host ip hash table */ clear_Dline_table(); /* d line tree */ initlists(); initclass(); initwhowas(); init_stats(); init_tree_parse(msgtab); /* tree parse code (orabidoo) */ fdlist_init(); init_netio(); read_conf_files(YES); /* cold start init conf files */ aconf = find_me(); if (EmptyString(me.name)) strncpy_irc(me.name, aconf->host, HOSTLEN); strncpy_irc(me.host, aconf->host, HOSTLEN); me.fd = -1; me.from = &me; me.servptr = &me; SetMe(&me); make_server(&me); me.serv->up = me.name; me.lasttime = me.since = me.firsttime = CurrentTime; add_to_client_hash_table(me.name, &me); check_class(); write_pidfile(); log(L_NOTICE, "Server Ready"); ServerRunning = 1; while (ServerRunning) { usleep(100000); do_adns_io(); delay = io_loop(delay); do_adns_io(); } return 0; }
static int m_message(struct Client *cptr, struct Client *sptr, int parc, char *parv[], int notice) { struct Client *acptr; #ifdef NEED_TLD_FOR_MASS_NOTICE char *s; #endif struct Channel *chptr; char *nick, *server, *host; char errbuf[BUFSIZE]; const char *cmd; int type=0, msgs=0; #ifdef FLUD int flud; #endif cmd = notice ? MSG_NOTICE : MSG_PRIVATE; if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, form_str(ERR_NORECIPIENT), me.name, parv[0], cmd); return -1; } if (parc < 3 || *parv[2] == '\0') { sendto_one(sptr, form_str(ERR_NOTEXTTOSEND), me.name, parv[0]); return -1; } if (MyConnect(sptr)) { #ifdef ANTI_SPAMBOT #ifndef ANTI_SPAMBOT_WARN_ONLY /* if its a spambot, just ignore it */ if(sptr->join_leave_count >= MAX_JOIN_LEAVE_COUNT) return 0; #endif #endif #ifdef NO_DUPE_MULTI_MESSAGES if (strchr(parv[1],',')) parv[1] = canonize(parv[1]); #endif } /* ** channels are privmsg'd a lot more than other clients, moved up here ** plain old channel msg ? */ while(msgs < MAX_MULTI_MESSAGES) { if(!msgs) nick = strtok(parv[1], ","); else nick = strtok(NULL, ","); if(!nick && msgs == 0) nick = parv[1]; else if(!nick) break; if( IsChanPrefix(*nick) && (IsPerson(sptr) && (chptr = hash_find_channel(nick, NullChn)))) { #ifdef FLUD #ifdef DEATHFLUD if(!notice && check_for_ctcp(parv[2]) && check_for_flud(sptr, NULL, chptr, 1)) return 0; if((flud = check_for_spam(sptr, NULL, chptr, parv[2]))) { if (check_for_flud(sptr, NULL, chptr, flud)) return 0; } #else /* DEATHFLUD */ if(!notice) if(check_for_ctcp(parv[2])) check_for_flud(sptr, NULL, chptr, 1); #endif /* DEATHFLUD */ #endif /* FLUD */ /* * Channel color blocking. Usually set with the +c chanmode. * - Andre Guibert de Bruet <*****@*****.**> */ if(chptr->mode.mode & MODE_NOCOLOR) strip_colour(parv[2]); switch (can_send(sptr, chptr)) { case 0: sendto_channel_message_butone(cptr, sptr, chptr, cmd, parv[2]); break; case MODE_QUIETUNIDENT: if (!notice) sendto_one(sptr, form_str(ERR_QUIETUNIDENT), me.name, parv[0], nick); break; case MODE_MODERATED: if (chptr->mode.mode & MODE_OPMODERATE) { /* The flag MODE_OPMODERATE will instruct sendto_channel_type() * to put bare #channel in the message (instead of @#channel); * it will still be sent to ops and servers with ops only. * Strange things will happen if the user is not banned * remotely. * -- jilles */ sendto_channel_type(cptr, sptr, chptr, MODE_CHANOP | MODE_OPMODERATE, nick, cmd, parv[2]); } else { if (!notice) sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN), me.name, parv[0], nick); } break; default: break; } msgs++; continue; } /* ** @# type of channel msg? */ if(*nick == '@') type = MODE_CHANOP; else if(*nick == '+') type = MODE_CHANOP|MODE_VOICE; if(type) { /* Strip if using DALnet chanop/voice prefix. */ if (*(nick+1) == '@' || *(nick+1) == '+') { nick++; *nick = '@'; type = MODE_CHANOP|MODE_VOICE; } /* suggested by Mortiis */ if(!*nick) /* if its a '\0' dump it, there is no recipient */ { sendto_one(sptr, form_str(ERR_NORECIPIENT), me.name, parv[0], cmd); return -1; } if (!IsPerson(sptr)) /* This means, servers can't send messages */ return -1; /* At this point, nick+1 should be a channel name i.e. #foo or &foo * if the channel is found, fine, if not report an error */ if ( (chptr = hash_find_channel(nick+1, NullChn)) ) { #ifdef FLUD #ifdef DEATHFLUD if(!notice && check_for_ctcp(parv[2]) && check_for_flud(sptr, NULL, chptr, 1)) return 0; if((flud = check_for_spam(sptr, NULL, chptr, parv[2]))) { if (check_for_flud(sptr, NULL, chptr, flud)) return 0; } #else /* DEATHFLUD */ if(!notice) if(check_for_ctcp(parv[2])) check_for_flud(sptr, NULL, chptr, 1); #endif /* DEATHFLUD */ #endif /* FLUD */ if (!is_chan_op(sptr,chptr)) { if (!notice) { sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN), me.name, parv[0], nick); } msgs++; continue; } else { sendto_channel_type(cptr, sptr, chptr, type, nick+1, cmd, parv[2]); } } else { if (!IsServer(sptr)) sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; continue; } return 0; } /* ** nickname addressed? */ if ((acptr = find_person(nick, NULL))) { #ifdef FLUD #ifdef DEATHFLUD if(!notice && MyConnect(sptr) && check_for_ctcp(parv[2]) && check_for_flud(sptr, acptr, NULL, 1)) return 0; if(MyConnect(sptr) && (flud = check_for_spam(sptr, acptr, NULL, parv[2]))) { if (check_for_flud(sptr, acptr, NULL, flud)) return 0; } #else /* DEATHFLUD */ if(!notice && MyConnect(sptr)) if(check_for_ctcp(parv[2])) if(check_for_flud(sptr, acptr, NULL, 1)) return 0; #endif /* DEATHFLUD */ #endif /* FLUD */ #ifdef ANTI_DRONE_FLOOD if(MyConnect(acptr) && IsClient(sptr) && !NoFloodProtection(sptr) && DRONETIME) { if((acptr->first_received_message_time+DRONETIME) < CurrentTime) { acptr->received_number_of_privmsgs=1; acptr->first_received_message_time = CurrentTime; acptr->drone_noticed = 0; } else { if(acptr->received_number_of_privmsgs > DRONECOUNT) { if(acptr->drone_noticed == 0) /* tiny FSM */ { sendto_ops_flag(UMODE_BOTS, "Possible Drone Flooder %s [%s@%s] on %s target: %s", sptr->name, sptr->username, sptr->host, sptr->user->server, acptr->name); acptr->drone_noticed = 1; } /* heuristic here, if target has been getting a lot * of privmsgs from clients, and sendq is above halfway up * its allowed sendq, then throw away the privmsg, otherwise * let it through. This adds some protection, yet doesn't * DOS the client. * -Dianora */ if(DBufLength(&acptr->sendQ) > (get_sendq(acptr)/2UL)) { if(acptr->drone_noticed == 1) /* tiny FSM */ { sendto_ops_flag(UMODE_BOTS, "ANTI_DRONE_FLOOD SendQ protection activated for %s", acptr->name); sendto_one(acptr, ":%s NOTICE %s :*** Notice -- Server drone flood protection activated for %s", me.name, acptr->name, acptr->name); acptr->drone_noticed = 2; } } if(DBufLength(&acptr->sendQ) <= (get_sendq(acptr)/4UL)) { if(acptr->drone_noticed == 2) { sendto_one(acptr, ":%s NOTICE %s :*** Notice -- Server drone flood protection de-activated for %s", me.name, acptr->name, acptr->name); acptr->drone_noticed = 1; } } if(acptr->drone_noticed > 1) return 0; } else acptr->received_number_of_privmsgs++; } } #endif /* * Simple herustic here... If PRIVMSG is locked down via * F:noidprivmsg:1, then act like every client is +E. * Otherwise, assume the normal behaviour. All in a nice * single if statement. --nenolod */ if (MyClient(sptr) && sptr != acptr && (GlobalSetOptions.noidprivmsg != 0 || HasUmode(acptr,UMODE_BLOCK_NOTID)) && !HasUmode(sptr,UMODE_IDENTIFIED) && !sptr->user->servlogin[0] && !HasUmode(acptr,UMODE_DONTBLOCK) && !HasUmode(sptr,UMODE_DONTBLOCK)) { /* Replace errbuf with either the default or custom message, * then send the numeric on... * --nenolod */ if (GlobalSetOptions.noidprivmsg != 0 && GlobalSetOptions.noidprivmsg_notice[0]) { strncpy_irc(errbuf, GlobalSetOptions.noidprivmsg_notice, BUFSIZE); } else { ircsnprintf(errbuf, BUFSIZE, get_str(STR_NOTID_DEFAULT), nick); } sendto_one(sptr, form_str(ERR_BLOCKING_NOTID), me.name, parv[0], errbuf); return 0; } #ifdef SILENCE /* only check silence masks at the recipient's server -- jilles */ if (!MyConnect(acptr) || !is_silenced(sptr, acptr)) { #endif if (MyConnect(sptr) && acptr->user && (sptr != acptr)) { #ifdef NCTCP /* NCTCP (umode +C) checks -- PMA */ if (parv[2][0] == 1) /* is CTCP */ /* Huh? No way, NOCTCP means NOCTCP. */ /* if (!HasUmode(sptr,UMODE_IMMUNE) && */ /* !HasUmode(acptr,UMODE_IMMUNE)) */ if (HasUmode(acptr,UMODE_NOCTCP) || /* block to +C */ (notice && HasUmode(sptr,UMODE_NOCTCP))) /* block replies from +C */ return 0; /* kill it! */ #endif /* NCTCP */ if (!notice && acptr->user->away) sendto_one(sptr, form_str(RPL_AWAY), me.name, parv[0], acptr->name, acptr->user->away); } { /* here's where we actually send the message */ int is_ctcp = check_for_ctcp(parv[2]); int cap = is_ctcp ? CAP_IDENTIFY_CTCP : CAP_IDENTIFY_MSG; sendto_prefix_one(acptr, sptr, ":%s %s %s :%s%s", parv[0], cmd, nick, !(acptr->caps & cap) ? "" : (HasUmode(sptr, UMODE_IDENTIFIED) ? "+" : "-"), parv[2]); } #ifdef SILENCE } #endif msgs++; continue; } /* Everything below here should be reserved for opers * as pointed out by Mortiis, user%[email protected] * syntax could be used to flood without FLUD protection * its also a delightful way for non-opers to find users who * have changed nicks -Dianora * * Grrr it was pointed out to me that x@service is valid * for non-opers too, and wouldn't allow for flooding/stalking * -Dianora * * Valid or not, @servername is unacceptable, it reveals what server * a person is on. Auspexen only. * -- asuffield */ /* ** the following two cases allow masks in NOTICEs ** (for OPERs only) (with +M -- asuffield) ** ** Armin, 8Jun90 ([email protected]) */ if ((*nick == '$' || *nick == '>')) { if(!HasUmode(sptr,UMODE_MASSNOTICE)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); return -1; } #ifdef NEED_TLD_FOR_MASS_NOTICE if (!(s = (char *)strrchr(nick, '.'))) { sendto_one(sptr, form_str(ERR_NOTOPLEVEL), me.name, parv[0], nick); msgs++; continue; } while (*++s) if (*s == '.' || *s == '*' || *s == '?') break; if (*s == '*' || *s == '?') { sendto_one(sptr, form_str(ERR_WILDTOPLEVEL), me.name, parv[0], nick); msgs++; continue; } #endif /* NEED_TLD_FOR_MASS_NOTICE */ sendto_match_butone(IsServer(cptr) ? cptr : NULL, sptr, nick + 1, (*nick == '>') ? MATCH_HOST : MATCH_SERVER, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]); msgs++; continue; } /* ** user[%host]@server addressed? */ if ((server = (char *)strchr(nick, '@')) && (acptr = find_server(server + 1))) { int count = 0; /* Disable the whole farping mess for non-auspexen * -- asuffield */ if (!HasUmode(sptr,UMODE_AUSPEX)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; continue; } /* Disable the user%host@server form for non-opers * -Dianora */ /* Disabled. This isn't very useful and I don't feel like mucking around with privs for it * -- asuffield */ if((char *)strchr(nick,'%')) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; continue; } /* ** Not destined for a user on me :-( */ if (!IsMe(acptr)) { sendto_one(acptr,":%s %s %s :%s", parv[0], cmd, nick, parv[2]); msgs++; continue; } *server = '\0'; /* special case opers@server */ /* We don't want this on OPN -- asuffield */ #if 0 if(!irccmp(nick,"opers") && SendWallops(sptr)) { sendto_realops("To opers: From %s: %s",sptr->name,parv[2]); msgs++; continue; } #endif if ((host = (char *)strchr(nick, '%'))) *host++ = '\0'; /* ** Look for users which match the destination host ** (no host == wildcard) and if one and one only is ** found connected to me, deliver message! */ acptr = find_userhost(nick, host, NULL, &count); if (server) *server = '@'; if (host) *--host = '%'; if (acptr) { if (count == 1) sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]); else if (!notice) sendto_one(sptr, form_str(ERR_TOOMANYTARGETS), me.name, parv[0], nick, MAX_MULTI_MESSAGES); } if (acptr) { msgs++; continue; } } /* Let's not send these remotely for channels */ if (MyConnect(sptr) || (nick[0] != '#')) sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; } if (strtok(NULL, ",")) sendto_one(sptr, form_str(ERR_TOOMANYTARGETS), me.name, parv[0], cmd, MAX_MULTI_MESSAGES); return 0; }