void scache_split(struct scache_entry *ptr) { if (ptr == NULL) return; ptr->flags &= ~SC_ONLINE; ptr->last_split = rb_current_time(); }
static int m_cycle(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { char *p, *name; char *s = LOCAL_COPY(parv[1]); struct Channel *chptr; struct membership *msptr; name = rb_strtok_r(s, ",", &p); /* Finish the flood grace period... */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); while(name) { if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(MyConnect(source_p) && !IsOper(source_p) && !IsExemptSpambot(source_p)) check_spambot_warning(source_p, NULL); if((is_any_op(msptr) || !MyConnect(source_p) || ((can_send(chptr, source_p, msptr) > 0 && (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) < rb_current_time())))) { sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s :Cycling", use_id(source_p), chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :Cycling", source_p->name, source_p->username, source_p->host, chptr->chname); } else { sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s", use_id(source_p), chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s", source_p->name, source_p->username, source_p->host, chptr->chname); } remove_user_from_channel(msptr); chptr = NULL; msptr = NULL; name = rb_strtok_r(NULL, ",", &p); } user_join(client_p, source_p, parv[1], parc > 2 ? parv[2] : NULL); return 0; }
/* * mr_admin - ADMIN command handler * parv[1] = servername */ static int mr_admin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { static time_t last_used = 0L; if((last_used + ConfigFileEntry.pace_wait) > rb_current_time()) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, EmptyString(source_p->name) ? "*" : source_p->name, "ADMIN"); return 0; } else last_used = rb_current_time(); do_admin(source_p); return 0; }
/* m_mkpasswd - mkpasswd message handler * parv[1] = password * parv[2] = type */ static int m_mkpasswd(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { static time_t last_used = 0; char *salt; const char *hashtype; const char hashdefault[] = "SHA512"; if(EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "MKPASSWD"); return 0; } if(parc < 3) hashtype = hashdefault; else hashtype = parv[2]; if((last_used + ConfigFileEntry.pace_wait) > rb_current_time()) { /* safe enough to give this on a local connect only */ sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "MKPASSWD"); return 0; } else last_used = rb_current_time(); if(!irccmp(hashtype, "SHA256")) salt = make_sha256_salt(16); else if(!irccmp(hashtype, "SHA512")) salt = make_sha512_salt(16); else if(!irccmp(hashtype, "MD5")) salt = make_md5_salt(8); else { sendto_one_notice(source_p, ":MKPASSWD syntax error: MKPASSWD pass [SHA256|SHA512|MD5]"); return 0; } sendto_one_notice(source_p, ":Hash [%s] for %s: %s", hashtype, parv[1], rb_crypt(parv[1], salt)); return 0; }
/* ** m_motd ** parv[1] = servername */ static int m_motd(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { static time_t last_used = 0; if ((last_used + ConfigFileEntry.pace_wait) > rb_current_time()) { /* safe enough to give this on a local connect only */ sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "MOTD"); sendto_one(source_p, form_str(RPL_ENDOFMOTD), me.name, source_p->name); return 0; } else last_used = rb_current_time(); if (hunt_server(client_p, source_p, ":%s MOTD :%s", 1, parc, parv) != HUNTED_ISME) return 0; motd_spy(source_p); send_user_motd(source_p); return 0; }
/* * part_one_client * * inputs - pointer to server * - pointer to source client to remove * - char pointer of name of channel to remove from * output - none * side effects - remove ONE client given the channel name */ static void part_one_client(struct Client *client_p, struct Client *source_p, char *name, char *reason) { struct Channel *chptr; struct membership *msptr; char reason2[BUFSIZE]; if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return; } msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return; } if(MyConnect(source_p) && !IsOper(source_p) && !IsExemptSpambot(source_p)) check_spambot_warning(source_p, NULL); /* * Remove user from the old channel (if any) * only allow /part reasons in -m chans */ if(reason[0] && (is_chanop(msptr) || !MyConnect(source_p) || ((can_send(chptr, source_p, msptr) > 0 && (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) < rb_current_time())))) { if(chptr->mode.mode & MODE_NOCOLOR) { rb_strlcpy(reason2, reason, BUFSIZE); strip_colour(reason2); reason = reason2; } sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s :%s", use_id(source_p), chptr->chname, reason); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, reason); } else { sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s", use_id(source_p), chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s", source_p->name, source_p->username, source_p->host, chptr->chname); } remove_user_from_channel(msptr); }
static void rb_ssl_info_callback(SSL * ssl, int where, int ret) { if(where & SSL_CB_HANDSHAKE_START) { rb_fde_t *F = SSL_get_ex_data(ssl, libratbox_index); if(F == NULL) return; F->handshake_count++; F->last_handshake = rb_current_time(); } }
/* * m_admin - ADMIN command handler * parv[1] = servername */ static int m_admin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { static time_t last_used = 0L; if(parc > 1) { if((last_used + ConfigFileEntry.pace_wait) > rb_current_time()) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "ADMIN"); return 0; } else last_used = rb_current_time(); if(hunt_server(client_p, source_p, ":%s ADMIN :%s", 1, parc, parv) != HUNTED_ISME) return 0; } do_admin(source_p); return 0; }
/* * m_version - VERSION command handler * parv[1] = remote server */ static int m_version(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { static time_t last_used = 0L; if (parc > 1) { if ((last_used + ConfigFileEntry.pace_wait) > rb_current_time()) { /* safe enough to give this on a local connect only */ sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "VERSION"); return 0; } else last_used = rb_current_time(); if (hunt_server(client_p, source_p, ":%s VERSION :%s", 1, parc, parv) != HUNTED_ISME) return 0; } sendto_one_numeric(source_p, RPL_VERSION, form_str(RPL_VERSION), ircd_version, serno, me.name, confopts(source_p), TS_CURRENT, ServerInfo.sid); show_isupport(source_p); return 0; }
struct scache_entry * scache_connect(const char *name, const char *info, int hidden) { struct scache_entry *ptr; ptr = find_or_add(name); rb_strlcpy(ptr->info, info, sizeof(ptr->info)); ptr->flags |= SC_ONLINE; if (hidden) ptr->flags |= SC_HIDDEN; else ptr->flags &= ~SC_HIDDEN; ptr->last_connect = rb_current_time(); return ptr; }
/* * m_time * parv[0] = sender prefix * parv[1] = servername */ static int m_time(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { /* this is not rate limited, so end the grace period */ char buf[80]; if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if (hunt_server(client_p, source_p, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME) { sendto_one_numeric(source_p, RPL_TIME, form_str(RPL_TIME), me.name, rb_date(rb_current_time(), buf, sizeof(buf))); } return 0; }
struct Client *get_history(const char *nick, time_t timelimit) { struct Whowas *temp; int blah; timelimit = rb_current_time() - timelimit; blah = hash_whowas_name(nick); temp = WHOWASHASH[blah]; for (; temp; temp = temp->next) { if (irccmp(nick, temp->name)) continue; if (temp->logoff < timelimit) continue; return temp->online; } return NULL; }
/* ** ms_eob ** parv[0] = sender prefix ** parv[1] = opt. comma separated list of SIDs for which this EOB is ** also valid */ static int ms_eob(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { char *copy, *state, *id; struct Client *target_p; int act = 0; if(!HasSentEob(source_p)) { if(MyConnect(source_p)) { sendto_realops_flags(UMODE_ALL, L_ALL, "End of burst from %s (%d seconds)", source_p->name, (signed int)(rb_current_time() - source_p->localClient->firsttime)); sendto_one(source_p, ":%s EOBACK", me.id); } act = 1; SetEob(source_p); eob_count++; } if(parc > 1 && *parv[1] != '\0') { copy = LOCAL_COPY(parv[1]); for(id = rb_strtok_r(copy, ",", &state); id != NULL; id = rb_strtok_r(NULL, ",", &state)) { target_p = find_id(id); if(target_p != NULL && IsServer(target_p) && target_p->from == client_p && !HasSentEob(target_p)) { SetEob(target_p); eob_count++; act = 1; } } } if(!act) return 0; sendto_server(client_p, NULL, CAP_IRCNET, NOCAPS, ":%s EOB%s%s", source_p->id, parc > 1 ? " :" : "", parc > 1 ? parv[1] : ""); return 0; }
void add_history(struct Client *client_p, int online) { struct Whowas *who = &WHOWAS[whowas_next]; s_assert(NULL != client_p); if(client_p == NULL) return; 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(client_p->name); who->logoff = rb_current_time(); /* * NOTE: strcpy ok here, the sizes in the client struct MUST * match the sizes in the whowas struct */ rb_strlcpy(who->name, client_p->name, sizeof(who->name)); strcpy(who->username, client_p->username); strcpy(who->hostname, client_p->host); strcpy(who->realname, client_p->info); strcpy(who->suser, client_p->user->suser); if(!EmptyString(client_p->sockhost) && strcmp(client_p->sockhost, "0") && show_ip(NULL, client_p)) strcpy(who->sockhost, client_p->sockhost); else who->sockhost[0] = '\0'; who->servername = scache_get_name(client_p->servptr->serv->nameinfo); if(online) { who->online = client_p; add_whowas_to_clist(&(client_p->whowas), who); } else who->online = NULL; add_whowas_to_list(&WHOWASHASH[who->hashv], who); whowas_next++; if(whowas_next == NICKNAMEHISTORYLENGTH) whowas_next = 0; }
static int ms_pong(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; const char *destination; destination = parv[2]; source_p->flags &= ~FLAGS_PINGSENT; /* Now attempt to route the PONG, comstud pointed out routable PING * is used for SPING. routable PING should also probably be left in * -Dianora * That being the case, we will route, but only for registered clients (a * case can be made to allow them only from servers). -Shadowfax */ if(!EmptyString(destination) && !match(destination, me.name) && irccmp(destination, me.id)) { if((target_p = find_client(destination))) sendto_one(target_p, ":%s PONG %s %s", get_id(source_p, target_p), parv[1], get_id(target_p, target_p)); else { if(!IsDigit(*destination)) sendto_one_numeric(source_p, ERR_NOSUCHSERVER, form_str(ERR_NOSUCHSERVER), destination); return 0; } } /* destination is us, emulate EOB */ if(IsServer(source_p) && !HasSentEob(source_p)) { if(MyConnect(source_p)) sendto_realops_snomask(SNO_GENERAL, L_ALL, "End of burst (emulated) from %s (%d seconds)", source_p->name, (signed int) (rb_current_time() - source_p->localClient->firsttime)); SetEob(source_p); eob_count++; call_hook(h_server_eob, source_p); } return 0; }
static int mo_testgecos(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct ConfItem *aconf; if(!(aconf = find_xline(parv[1], 0))) { sendto_one(source_p, form_str(RPL_NOTESTLINE), me.name, source_p->name, parv[1]); return 0; } sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, aconf->hold ? 'x' : 'X', aconf->hold ? (long) ((aconf->hold - rb_current_time()) / 60) : 0L, aconf->host, aconf->passwd); return 0; }
static int mo_testgecos(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct ConfItem *aconf; if(!(aconf = find_xline(parv[1], 0))) { sendto_one_numeric(source_p, s_RPL(RPL_NOTESTLINE), parv[1]); return 0; } sendto_one_numeric(source_p, s_RPL(RPL_TESTLINE), (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'x' : 'X', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (time_t)((aconf->hold - rb_current_time()) / 60) : (time_t)0L, aconf->host, aconf->passwd); return 0; }
/* scache_send_missing() * * inputs - client to send to * outputs - recently split servers * side effects - */ void scache_send_missing(struct Client *source_p) { struct scache_entry *scache_ptr; int i; for (i = 0; i < SCACHE_HASH_SIZE; i++) { scache_ptr = scache_hash[i]; while (scache_ptr) { if (!(scache_ptr->flags & SC_ONLINE) && scache_ptr->last_split > rb_current_time() - MISSING_TIMEOUT) sendto_one_numeric(source_p, RPL_MAP, "** %s (recently split)", scache_ptr->name); scache_ptr = scache_ptr->next; } } }
void add_history(struct Client *client_p, int online) { struct Whowas *who = &WHOWAS[whowas_next]; s_assert(NULL != client_p); if (client_p == NULL) return; 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(client_p->name); who->logoff = rb_current_time(); strcpy(who->name, client_p->name); strcpy(who->username, client_p->username); strcpy(who->hostname, client_p->host); strcpy(who->virthost, client_p->virthost); strcpy(who->realname, client_p->info); who->cloak = IsCloaked(client_p); who->servername = client_p->servptr->name; if (online) { who->online = client_p; add_whowas_to_clist(&(client_p->whowas), who); } else who->online = NULL; add_whowas_to_list(&WHOWASHASH[who->hashv], who); whowas_next++; if (whowas_next == NICKNAMEHISTORYLENGTH) whowas_next = 0; }
static void log_va(const ilogfile dest, const unsigned int snomask, const char *const fmt, va_list ap) { FILE *const logfile = *log_table[dest].logfile; if(!logfile && !snomask) return; char buf[BUFSIZE]; vsnprintf(buf, sizeof(buf), fmt, ap); if(snomask) sendto_realops_snomask(snomask, L_ALL, "%s", buf); if(fprintf(logfile, "%s %s\n", smalldate(rb_current_time()), buf) < 0) { fclose(logfile); *log_table[dest].logfile = NULL; } else { fflush(logfile); } }
static int change_nick(struct Client *client_p, const char *newnick) { char note[NICKLEN + 10]; client_p->tsinfo = rb_current_time(); monitor_signoff(client_p); invalidate_bancache_user(client_p); sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Forced nick change: From %s to %s [%s@%s]", client_p->name, newnick, client_p->username, client_p->host); sendto_common_channels_local(client_p, NOCAPS, ":%s!%s@%s NICK :%s", client_p->name, client_p->username, client_p->host, newnick); add_history(client_p, 1); sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld", use_id(client_p), newnick, (long) client_p->tsinfo); del_from_client_hash(client_p->name, client_p); strcpy(client_p->name, newnick); add_to_client_hash(client_p->name, client_p); monitor_signon(client_p); del_all_accepts(client_p); rb_snprintf(note, NICKLEN + 10, "Nick: %s", client_p->name); rb_note(client_p->localClient->F, note); return 0; }
/* date() * * returns date in human readable form */ static char * date(void) { static char buf[80]; char plus; struct tm *lt; struct tm *gm; struct tm gmbuf; time_t lclock; int minswest; lclock = rb_current_time(); gm = gmtime(&lclock); memcpy((void *) &gmbuf, (void *) gm, sizeof(gmbuf)); gm = &gmbuf; lt = localtime(&lclock); if(lt->tm_yday == gm->tm_yday) minswest = (gm->tm_hour - lt->tm_hour) * 60 + (gm->tm_min - lt->tm_min); else if(lt->tm_yday > gm->tm_yday && lt->tm_year == gm->tm_year) minswest = (gm->tm_hour - (lt->tm_hour + 24)) * 60; else minswest = ((gm->tm_hour + 24) - lt->tm_hour) * 60; plus = (minswest > 0) ? '-' : '+'; if(minswest < 0) minswest = -minswest; sprintf(buf, "%s %s %d %d -- %02u:%02u:%02u %c%02u:%02u", weekdays[lt->tm_wday], months[lt->tm_mon], lt->tm_mday, lt->tm_year + 1900, lt->tm_hour, lt->tm_min, lt->tm_sec, plus, minswest / 60, minswest % 60); return buf; }
/* ** m_whowas ** parv[1] = nickname queried */ static int m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Whowas *temp; int cur = 0; int max = -1, found = 0; char *p; const char *nick; char tbuf[26]; static time_t last_used = 0L; if(!IsOper(source_p)) { if((last_used + ConfigFileEntry.pace_wait_simple) > rb_current_time()) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "WHOWAS"); sendto_one(source_p, form_str(RPL_ENDOFWHOWAS), me.name, source_p->name, parv[1]); return 0; } else last_used = rb_current_time(); } if(parc > 2) max = atoi(parv[2]); #if 0 if(parc > 3) if(hunt_server(client_p, source_p, ":%s WHOWAS %s %s :%s", 3, parc, parv)) return 0; #endif if((p = strchr(parv[1], ','))) *p = '\0'; nick = parv[1]; temp = WHOWASHASH[hash_whowas_name(nick)]; found = 0; for (; temp; temp = temp->next) { if(!irccmp(nick, temp->name)) { sendto_one(source_p, form_str(RPL_WHOWASUSER), me.name, source_p->name, temp->name, temp->username, temp->hostname, temp->realname); if (MyOper(source_p) && !EmptyString(temp->sockhost)) #if 0 sendto_one(source_p, form_str(RPL_WHOWASREAL), me.name, source_p->name, temp->name, "<untracked>", temp->sockhost); #else sendto_one_numeric(source_p, RPL_WHOISACTUALLY, form_str(RPL_WHOISACTUALLY), temp->name, temp->sockhost); #endif if (!EmptyString(temp->suser)) sendto_one_numeric(source_p, RPL_WHOISLOGGEDIN, "%s %s :was logged in as", temp->name, temp->suser); if(SeesServers(source_p)) sendto_one_numeric(source_p, RPL_WHOISSERVER, form_str(RPL_WHOISSERVER), temp->name, temp->servername, rb_ctime(temp->logoff, tbuf, sizeof(tbuf))); else sendto_one_numeric(source_p, RPL_WHOISSERVER, form_str(RPL_WHOISSERVER), temp->name, source_p->servptr->mname, rb_ctime(temp->logoff, tbuf, sizeof(tbuf))); cur++; found++; } if(max > 0 && cur >= max) break; } if(!found) sendto_one(source_p, form_str(ERR_WASNOSUCHNICK), me.name, source_p->name, nick); sendto_one(source_p, form_str(RPL_ENDOFWHOWAS), me.name, source_p->name, parv[1]); return 0; }
static int accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, void *data) { struct Listener *listener = (struct Listener *)data; char buf[BUFSIZE]; struct ConfItem *aconf; static time_t last_oper_notice = 0; int len; if(listener->ssl && (!ssl_ok || !get_ssld_count())) { rb_close(F); return 0; } if((maxconnections - 10) < rb_get_fd(F)) /* XXX this is kinda bogus */ { ++ServerStats.is_ref; /* * slow down the whining to opers bit */ if((last_oper_notice + 20) <= rb_current_time()) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "All connections in use. (%s)", get_listener_name(listener)); last_oper_notice = rb_current_time(); } rb_write(F, "ERROR :All connections in use\r\n", 32); rb_close(F); /* Re-register a new IO request for the next accept .. */ return 0; } aconf = find_dline(addr, addr->sa_family); if(aconf != NULL && (aconf->status & CONF_EXEMPTDLINE)) return 1; /* Do an initial check we aren't connecting too fast or with too many * from this IP... */ if(aconf != NULL) { ServerStats.is_ref++; if(ConfigFileEntry.dline_with_reason) { len = rb_snprintf(buf, sizeof(buf), "ERROR :*** Banned: %s\r\n", get_user_ban_reason(aconf)); if (len >= (int)(sizeof(buf)-1)) { buf[sizeof(buf) - 3] = '\r'; buf[sizeof(buf) - 2] = '\n'; buf[sizeof(buf) - 1] = '\0'; } } else strcpy(buf, "ERROR :You have been D-lined.\r\n"); rb_write(F, buf, strlen(buf)); rb_close(F); return 0; } if(check_reject(F, addr)) return 0; if(throttle_add(addr)) { rb_write(F, toofast, strlen(toofast)); rb_close(F); return 0; } return 1; }
/* ms_ban() * * parv[1] - type * parv[2] - username mask or * * parv[3] - hostname mask * parv[4] - creation TS * parv[5] - duration (relative to creation) * parv[6] - lifetime (relative to creation) * parv[7] - oper or * * parv[8] - reason (possibly with |operreason) */ static int ms_ban(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { rb_dlink_node *ptr; struct ConfItem *aconf; unsigned int ntype; const char *oper, *stype; time_t now, created, hold, lifetime; char *p; int act; int valid; now = rb_current_time(); if (strlen(parv[1]) != 1) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Unknown BAN type %s from %s", parv[1], source_p->name); return 0; } switch (parv[1][0]) { case 'K': ntype = CONF_KILL; stype = "K-Line"; break; case 'X': ntype = CONF_XLINE; stype = "X-Line"; break; case 'R': ntype = IsChannelName(parv[3]) ? CONF_RESV_CHANNEL : CONF_RESV_NICK; stype = "RESV"; break; default: sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Unknown BAN type %s from %s", parv[1], source_p->name); return 0; } created = atol(parv[4]); hold = created + atoi(parv[5]); lifetime = created + atoi(parv[6]); if (!strcmp(parv[7], "*")) oper = IsServer(source_p) ? source_p->name : get_oper_name(source_p); else oper = parv[7]; ptr = find_prop_ban(ntype, parv[2], parv[3]); if (ptr != NULL) { /* We already know about this ban mask. */ aconf = ptr->data; if (aconf->created > created || (aconf->created == created && aconf->lifetime >= lifetime)) { if (IsPerson(source_p)) sendto_one_notice(source_p, ":Your %s [%s%s%s] has been superseded", stype, aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host); return 0; } /* act indicates if something happened (from the oper's * point of view). This is the case if the ban was * previously active (not deleted) or if the new ban * is not a removal and not already expired. */ act = !(aconf->status & CONF_ILLEGAL) || (hold != created && hold > now); if (lifetime > aconf->lifetime) aconf->lifetime = lifetime; /* already expired, hmm */ if (aconf->lifetime <= now) return 0; /* Deactivate, it will be reactivated later if appropriate. */ deactivate_conf(aconf, ptr, now); rb_free(aconf->user); aconf->user = NULL; rb_free(aconf->host); aconf->host = NULL; operhash_delete(aconf->info.oper); aconf->info.oper = NULL; rb_free(aconf->passwd); aconf->passwd = NULL; rb_free(aconf->spasswd); aconf->spasswd = NULL; } else { /* New ban mask. */ aconf = make_conf(); aconf->status = CONF_ILLEGAL | ntype; aconf->lifetime = lifetime; rb_dlinkAddAlloc(aconf, &prop_bans); act = hold != created && hold > now; } aconf->flags &= ~CONF_FLAGS_MYOPER; aconf->flags |= CONF_FLAGS_TEMPORARY; aconf->user = ntype == CONF_KILL ? rb_strdup(parv[2]) : NULL; aconf->host = rb_strdup(parv[3]); aconf->info.oper = operhash_add(oper); aconf->created = created; aconf->hold = hold; if (ntype != CONF_KILL || (p = strchr(parv[parc - 1], '|')) == NULL) aconf->passwd = rb_strdup(parv[parc - 1]); else { aconf->passwd = rb_strndup(parv[parc - 1], p - parv[parc - 1] + 1); aconf->spasswd = rb_strdup(p + 1); } /* The ban is fully filled in and in the prop_bans list * but still deactivated. Now determine if it should be activated * and send the server notices. */ /* We only reject *@* and the like here. * Otherwise malformed bans are fairly harmless and can be removed. */ switch (ntype) { case CONF_KILL: valid = valid_wild_card(aconf->user, aconf->host); break; case CONF_RESV_CHANNEL: valid = 1; break; default: valid = valid_wild_card_simple(aconf->host); break; } if (act && hold != created && !valid) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "Ignoring global %d min. %s from %s%s%s for [%s%s%s]: too few non-wildcard characters", (int)((hold - now) / 60), stype, IsServer(source_p) ? source_p->name : get_oper_name(source_p), strcmp(parv[7], "*") ? " on behalf of " : "", strcmp(parv[7], "*") ? parv[7] : "", aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host); if(IsPerson(source_p)) sendto_one_notice(source_p, ":Your %s [%s%s%s] has too few non-wildcard characters", stype, aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host); /* Propagate it, but do not apply it locally. */ } else if (act && hold != created) { /* Keep the notices in sync with modules/m_kline.c etc. */ sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s added global %d min. %s%s%s for [%s%s%s] [%s]", IsServer(source_p) ? source_p->name : get_oper_name(source_p), (int)((hold - now) / 60), stype, strcmp(parv[7], "*") ? " from " : "", strcmp(parv[7], "*") ? parv[7] : "", aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host, parv[parc - 1]); ilog(L_KLINE, "%s %s %d %s%s%s %s", parv[1], IsServer(source_p) ? source_p->name : get_oper_name(source_p), (int)((hold - now) / 60), aconf->user ? aconf->user : "", aconf->user ? " " : "", aconf->host, parv[parc - 1]); aconf->status &= ~CONF_ILLEGAL; } else if (act) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has removed the global %s for: [%s%s%s]%s%s", IsServer(source_p) ? source_p->name : get_oper_name(source_p), stype, aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host, strcmp(parv[7], "*") ? " on behalf of " : "", strcmp(parv[7], "*") ? parv[7] : ""); ilog(L_KLINE, "U%s %s %s%s %s", parv[1], IsServer(source_p) ? source_p->name : get_oper_name(source_p), aconf->user ? aconf->user : "", aconf->user ? " " : "", aconf->host); } /* If CONF_ILLEGAL is still set at this point, remove entries from the * reject cache (for klines and xlines). * If CONF_ILLEGAL is not set, add the ban to the type-specific data * structure and take action on matched clients/channels. */ switch (ntype) { case CONF_KILL: if (aconf->status & CONF_ILLEGAL) remove_reject_mask(aconf->user, aconf->host); else { add_conf_by_address(aconf->host, CONF_KILL, aconf->user, NULL, aconf); if(ConfigFileEntry.kline_delay || (IsServer(source_p) && !HasSentEob(source_p))) { if(kline_queued == 0) { rb_event_addonce("check_klines", check_klines_event, NULL, ConfigFileEntry.kline_delay ? ConfigFileEntry.kline_delay : 1); kline_queued = 1; } } else check_klines(); } break; case CONF_XLINE: if (aconf->status & CONF_ILLEGAL) remove_reject_mask(aconf->host, NULL); else { rb_dlinkAddAlloc(aconf, &xline_conf_list); check_xlines(); } break; case CONF_RESV_CHANNEL: if (!(aconf->status & CONF_ILLEGAL)) { add_to_resv_hash(aconf->host, aconf); resv_chan_forcepart(aconf->host, aconf->passwd, hold - now); } break; case CONF_RESV_NICK: if (!(aconf->status & CONF_ILLEGAL)) rb_dlinkAddAlloc(aconf, &resv_conf_list); break; } sendto_server(client_p, NULL, CAP_BAN|CAP_TS6, NOCAPS, ":%s BAN %s %s %s %s %s %s %s :%s", source_p->id, parv[1], parv[2], parv[3], parv[4], parv[5], parv[6], parv[7], parv[parc - 1]); return 0; }
static int mo_testline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct ConfItem *aconf; struct ConfItem *resv_p; struct rb_sockaddr_storage ip; const char *name = NULL; const char *username = NULL; const char *host = NULL; char *mask; char *p; int host_mask; int type; mask = LOCAL_COPY(parv[1]); if(IsChannelName(mask)) { resv_p = hash_find_resv(mask); if(resv_p != NULL) { sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, (resv_p->flags & CONF_FLAGS_TEMPORARY) ? 'q' : 'Q', (resv_p->flags & CONF_FLAGS_TEMPORARY) ? (long)((resv_p->hold - rb_current_time ()) / 60) : 0L, resv_p->host, resv_p->passwd); /* this is a false positive, so make sure it isn't counted in stats q * --nenolod */ resv_p->port--; } else sendto_one(source_p, form_str(RPL_NOTESTLINE), me.name, source_p->name, parv[1]); return 0; } if((p = strchr(mask, '!'))) { *p++ = '\0'; name = mask; mask = p; if(EmptyString(mask)) return 0; } if((p = strchr(mask, '@'))) { *p++ = '\0'; username = mask; host = p; if(EmptyString(host)) return 0; } else host = mask; /* parses as an IP, check for a dline */ if((type = parse_netmask(host, (struct sockaddr *)&ip, &host_mask)) != HM_HOST) { aconf = find_dline((struct sockaddr *)&ip); if(aconf && aconf->status & CONF_DLINE) { sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'd' : 'D', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (long)((aconf->hold - rb_current_time()) / 60) : 0L, aconf->host, aconf->passwd); return 0; } } /* now look for a matching I/K/G */ if((aconf = find_address_conf(host, NULL, username ? username : "******", (type != HM_HOST) ? (struct sockaddr *)&ip : NULL, (type != HM_HOST) ? ( #ifdef RB_IPV6 (type == HM_IPV6) ? AF_INET6 : #endif AF_INET) : 0))) { static char buf[HOSTLEN + USERLEN + 2]; if(aconf->status & CONF_KILL) { rb_snprintf(buf, sizeof(buf), "%s@%s", aconf->user, aconf->host); sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'k' : 'K', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (long)((aconf->hold - rb_current_time()) / 60) : 0L, buf, aconf->passwd); return 0; } else if(aconf->status & CONF_GLINE) { rb_snprintf(buf, sizeof(buf), "%s@%s", aconf->user, aconf->host); sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, 'G', (long)((aconf->hold - rb_current_time()) / 60), buf, aconf->passwd); return 0; } } /* they asked us to check a nick, so hunt for resvs.. */ if(name && (resv_p = find_nick_resv(name))) { sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, (resv_p->flags & CONF_FLAGS_TEMPORARY) ? 'q' : 'Q', (resv_p->flags & CONF_FLAGS_TEMPORARY) ? (long)((resv_p->hold - rb_current_time()) / 60) : 0L, resv_p->host, resv_p->passwd); /* this is a false positive, so make sure it isn't counted in stats q * --nenolod */ resv_p->port--; return 0; } /* no matching resv, we can print the I: if it exists */ if(aconf && aconf->status & CONF_CLIENT) { sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE), aconf->info.name, show_iline_prefix(source_p, aconf, aconf->user), aconf->host, aconf->port, get_class_name(aconf)); return 0; } /* nothing matches.. */ sendto_one(source_p, form_str(RPL_NOTESTLINE), me.name, source_p->name, parv[1]); return 0; }
/* ** m_away ** parv[1] = away message */ static int m_away(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(MyClient(source_p) && source_p->localClient->next_away && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsClient(source_p)) return 0; if(parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if(source_p->user->away != NULL) { /* we now send this only if they were away before --is */ sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY", use_id(source_p)); free_away(source_p); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, ":%s!%s@%s AWAY", source_p->name, source_p->username, source_p->host); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_UNAWAY, form_str(RPL_UNAWAY)); return 0; } /* Rate limit this because it is sent to common channels. */ if (MyClient(source_p)) { if(!IsOper(source_p) && source_p->localClient->next_away > rb_current_time()) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "AWAY"); return 0; } if(source_p->localClient->next_away < rb_current_time() - ConfigFileEntry.away_interval) source_p->localClient->next_away = rb_current_time(); else source_p->localClient->next_away = rb_current_time() + ConfigFileEntry.away_interval; } if(source_p->user->away == NULL) allocate_away(source_p); if(strncmp(source_p->user->away, parv[1], AWAYLEN - 1)) { rb_strlcpy(source_p->user->away, parv[1], AWAYLEN); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY :%s", use_id(source_p), source_p->user->away); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, ":%s!%s@%s AWAY :%s", source_p->name, source_p->username, source_p->host, source_p->user->away); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_NOWAWAY, form_str(RPL_NOWAWAY)); return 0; }
/* m_knock * parv[1] = channel * * The KNOCK command has the following syntax: * :<sender> KNOCK <channel> * * If a user is not banned from the channel they can use the KNOCK * command to have the server NOTICE the channel operators notifying * they would like to join. Helpful if the channel is invite-only, the * key is forgotten, or the channel is full (INVITE can bypass each one * of these conditions. Concept by Dianora <*****@*****.**> and written by * <anonymous> */ static int m_knock(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; char *p, *name; if(MyClient(source_p) && ConfigChannel.use_knock == 0) { sendto_one(source_p, form_str(ERR_KNOCKDISABLED), me.name, source_p->name); return 0; } name = LOCAL_COPY(parv[1]); /* dont allow one knock to multiple chans */ if((p = strchr(name, ','))) *p = '\0'; if(!IsChannelName(name)) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if(IsMember(source_p, chptr)) { if(MyClient(source_p)) sendto_one(source_p, form_str(ERR_KNOCKONCHAN), me.name, source_p->name, name); return 0; } if(!((chptr->mode.mode & MODE_INVITEONLY) || (*chptr->mode.key) || (chptr->mode.limit && rb_dlink_list_length(&chptr->members) >= (unsigned long)chptr->mode.limit))) { sendto_one_numeric(source_p, ERR_CHANOPEN, form_str(ERR_CHANOPEN), name); return 0; } /* cant knock to a +p channel */ if(HiddenChannel(chptr)) { sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), name, "channel does not accept knocks"); return 0; } if(MyClient(source_p)) { /* don't allow a knock if the user is banned */ if(is_banned(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN || is_quieted(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN) { sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), name, "you are banned from this channel"); return 0; } /* local flood protection: * allow one knock per user per knock_delay * allow one knock per channel per knock_delay_channel */ if(!IsOper(source_p) && (source_p->localClient->last_knock + ConfigChannel.knock_delay) > rb_current_time()) { sendto_one(source_p, form_str(ERR_TOOMANYKNOCK), me.name, source_p->name, name, "user"); return 0; } else if((chptr->last_knock + ConfigChannel.knock_delay_channel) > rb_current_time()) { sendto_one(source_p, form_str(ERR_TOOMANYKNOCK), me.name, source_p->name, name, "channel"); return 0; } /* ok, we actually can send the knock, tell client */ source_p->localClient->last_knock = rb_current_time(); sendto_one(source_p, form_str(RPL_KNOCKDLVR), me.name, source_p->name, name); } chptr->last_knock = rb_current_time(); if(ConfigChannel.use_knock) sendto_channel_local(chptr->mode.mode & MODE_FREEINVITE ? ALL_MEMBERS : ONLY_CHANOPS, chptr, form_str(RPL_KNOCK), me.name, name, name, source_p->name, source_p->username, source_p->host); sendto_server(client_p, chptr, CAP_KNOCK|CAP_TS6, NOCAPS, ":%s KNOCK %s", use_id(source_p), name); sendto_server(client_p, chptr, CAP_KNOCK, CAP_TS6, ":%s KNOCK %s", source_p->name, name); return 0; }
/* ** mo_ojoin ** parv[1] = channel */ static int mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; int move_me = 0; /* admins only */ if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin"); return 0; } if(*parv[1] == '@' || *parv[1] == '%' || *parv[1] == '+' || *parv[1] == '!' || *parv[1] == '~') { parv[1]++; move_me = 1; } else { sendto_one_notice(source_p, ":Unrecognized op prefix '%c'", *parv[1]); return 0; } if((chptr = find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } if(IsMember(source_p, chptr)) { sendto_one_notice(source_p, ":Please part %s before using OJOIN", parv[1]); return 0; } if(move_me == 1) parv[1]--; /* only sends stuff for #channels remotely */ if(*parv[1] == '!') { if(!ConfigChannel.use_admin) { sendto_one_notice(source_p, ":This server's configuration file does not support admin prefix"); return 0; } add_user_to_channel(chptr, source_p, CHFL_ADMIN); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :!%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +a %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '@') { add_user_to_channel(chptr, source_p, CHFL_CHANOP); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :@%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); send_channel_join(chptr, source_p); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '%') { if(!ConfigChannel.use_halfop) { sendto_one_notice(source_p, ":This server's configuration file does not support halfop prefix"); return 0; } add_user_to_channel(chptr, source_p, CHFL_HALFOP); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :%s%s", me.id, (long) chptr->channelts, chptr->chname, "%", source_p->id); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s", source_p->name, source_p->username, source_p->host, chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +h %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '+') { add_user_to_channel(chptr, source_p, CHFL_VOICE); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :+%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); send_channel_join(chptr, source_p); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s", me.name, chptr->chname, source_p->name); } else if(*parv[1] == '~') { if(!ConfigChannel.use_founder) { sendto_one_notice(source_p, ":This server's configuration file does not support founder prefix"); return 0; } add_user_to_channel(chptr, source_p, CHFL_FOUNDER); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s + :~%s", me.id, (long) chptr->channelts, chptr->chname, source_p->id); send_channel_join(chptr, source_p); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +u %s", me.name, chptr->chname, source_p->name); } else { add_user_to_channel(chptr, source_p, CHFL_PEON); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s JOIN %ld %s +", source_p->id, (long) chptr->channelts, chptr->chname); send_channel_join(chptr, source_p); } /* send the topic... */ if(chptr->topic != NULL) { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } source_p->localClient->last_join_time = rb_current_time(); channel_member_names(chptr, source_p, 1); sendto_realops_snomask(SNO_GENERAL, L_ALL, "OJOIN called for %s by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "OJOIN called for %s by %s", parv[1], get_oper_name(source_p)); return 0; }
static int mo_testline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct ConfItem *aconf; struct ConfItem *resv_p; struct rb_sockaddr_storage ip; char user_trunc[USERLEN + 1], notildeuser_trunc[USERLEN + 1]; const char *name = NULL; const char *username = NULL; const char *host = NULL; char *mask; char *p; int host_mask; int type; int duration; char *puser, *phost, *reason, *operreason; char reasonbuf[BUFSIZE]; mask = LOCAL_COPY(parv[1]); if (IsChannelName(mask)) { resv_p = hash_find_resv(mask); if (resv_p != NULL) { sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, resv_p->hold ? 'q' : 'Q', resv_p->hold ? (long) ((resv_p->hold - rb_current_time()) / 60) : 0L, resv_p->host, resv_p->passwd); /* this is a false positive, so make sure it isn't counted in stats q * --nenolod */ resv_p->port--; } else sendto_one(source_p, form_str(RPL_NOTESTLINE), me.name, source_p->name, parv[1]); return 0; } if((p = strchr(mask, '!'))) { *p++ = '\0'; name = mask; mask = p; if(EmptyString(mask)) return 0; } if((p = strchr(mask, '@'))) { *p++ = '\0'; username = mask; host = p; if(EmptyString(host)) return 0; } else host = mask; /* parses as an IP, check for a dline */ if((type = parse_netmask(host, &ip, &host_mask)) != HM_HOST) { #ifdef RB_IPV6 if(type == HM_IPV6) aconf = find_dline((struct sockaddr *)&ip, AF_INET6); else #endif aconf = find_dline((struct sockaddr *)&ip, AF_INET); if(aconf && aconf->status & CONF_DLINE) { get_printable_kline(source_p, aconf, &phost, &reason, &puser, &operreason); snprintf(reasonbuf, sizeof(reasonbuf), "%s%s%s", reason, operreason ? "|" : "", operreason ? operreason : ""); sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'd' : 'D', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (long) ((aconf->hold - rb_current_time()) / 60) : 0L, phost, reasonbuf); return 0; } /* Otherwise, aconf is an exempt{} */ if(aconf == NULL && (duration = is_reject_ip((struct sockaddr *)&ip))) sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, '!', duration / 60L, host, "Reject cache"); if(aconf == NULL && (duration = is_throttle_ip((struct sockaddr *)&ip))) sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, '!', duration / 60L, host, "Throttled"); } if (username != NULL) { rb_strlcpy(user_trunc, username, sizeof user_trunc); rb_strlcpy(notildeuser_trunc, *username == '~' ? username + 1 : username, sizeof notildeuser_trunc); } else { rb_strlcpy(user_trunc, "dummy", sizeof user_trunc); rb_strlcpy(notildeuser_trunc, "dummy", sizeof notildeuser_trunc); } /* now look for a matching I/K/G */ if((aconf = find_address_conf(host, NULL, user_trunc, notildeuser_trunc, (type != HM_HOST) ? (struct sockaddr *)&ip : NULL, (type != HM_HOST) ? ( #ifdef RB_IPV6 (type == HM_IPV6) ? AF_INET6 : #endif AF_INET) : 0, NULL))) { static char buf[HOSTLEN+USERLEN+2]; if(aconf->status & CONF_KILL) { get_printable_kline(source_p, aconf, &phost, &reason, &puser, &operreason); snprintf(buf, sizeof(buf), "%s@%s", puser, phost); snprintf(reasonbuf, sizeof(reasonbuf), "%s%s%s", reason, operreason ? "|" : "", operreason ? operreason : ""); sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, (aconf->flags & CONF_FLAGS_TEMPORARY) ? 'k' : 'K', (aconf->flags & CONF_FLAGS_TEMPORARY) ? (long) ((aconf->hold - rb_current_time()) / 60) : 0L, buf, reasonbuf); return 0; } } /* they asked us to check a nick, so hunt for resvs.. */ if(name && (resv_p = find_nick_resv(name))) { sendto_one(source_p, form_str(RPL_TESTLINE), me.name, source_p->name, resv_p->hold ? 'q' : 'Q', resv_p->hold ? (long) ((resv_p->hold - rb_current_time()) / 60) : 0L, resv_p->host, resv_p->passwd); /* this is a false positive, so make sure it isn't counted in stats q * --nenolod */ resv_p->port--; return 0; } /* no matching resv, we can print the I: if it exists */ if(aconf && aconf->status & CONF_CLIENT) { sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE), aconf->info.name, EmptyString(aconf->spasswd) ? "<NULL>" : aconf->spasswd, show_iline_prefix(source_p, aconf, aconf->user), aconf->host, aconf->port, aconf->className); return 0; } /* nothing matches.. */ sendto_one(source_p, form_str(RPL_NOTESTLINE), me.name, source_p->name, parv[1]); return 0; }