static int clicap_sort(struct clicap *one, struct clicap *two) { return irccmp(one->name, two->name); }
static void hs_givehelp(struct Luser *lptr, int ac, char **av) { struct Luser *serviceptr; if (!irccmp(av[0], "HELP")) { if (ac >= 2) GiveHelp(n_HelpServ, lptr->nick, av[1], NODCC); else GiveHelp(n_HelpServ, lptr->nick, NULL, NODCC); } else { char str[MAXLINE + 1]; if (!(serviceptr = GetService(av[0]))) { /* * this shouldn't happen unless they entered a partial * service nick, and the abbreviation code allowed it * to go through */ notice(n_HelpServ, lptr->nick, "[\002%s\002] is an invalid service nickname", av[0]); return; } if (ac < 2) strlcpy(str, "HELP", sizeof(str)); else if (ac >= 3) { ircsprintf(str, "HELP %s %s", av[1], av[2]); } else { ircsprintf(str, "HELP %s", av[1]); } if (serviceptr == Me.osptr) os_process(lptr->nick, str, NODCC); #ifdef NICKSERVICES if (serviceptr == Me.nsptr) ns_process(lptr->nick, str); #ifdef CHANNELSERVICES if (serviceptr == Me.csptr) cs_process(lptr->nick, str); #endif #ifdef MEMOSERVICES if (serviceptr == Me.msptr) ms_process(lptr->nick, str); #endif #endif /* NICKSERVICES */ #ifdef STATSERVICES if (serviceptr == Me.ssptr) ss_process(lptr->nick, str); #endif /* STATSERVICES */ #ifdef SEENSERVICES if (serviceptr == Me.esptr) es_process(lptr->nick, str); #endif /* SEENSERVICES */ #ifdef GLOBALSERVICES if (serviceptr == Me.gsptr) gs_process(lptr->nick, str); #endif /* GLOBALSERVICES */ } /* else */ } /* hs_givehelp() */
void RemoveFromChannel(struct Channel *cptr, struct Luser *lptr) { struct UserChannel *tempchan, *prev = NULL; struct ChannelUser *tempuser, *prev2 = NULL; if (!cptr || !lptr) return; SendUmode(OPERUMODE_P, "*** Channel part: %s (%s)", lptr->nick, cptr->name); /* Is this the contact? */ #ifdef CHANNELSERVICES { struct NickInfo *nptr; struct ChanInfo *ciptr; if ((nptr = FindNick(lptr->nick)) && (ciptr = FindChan(cptr->name))) { if (nptr->flags & NS_IDENTIFIED) { if (ciptr->contact && irccmp(lptr->nick, ciptr->contact) == 0) /* That's the contact joining. Update activity timer */ ciptr->last_contact_active = current_ts; if (ciptr->alternate && irccmp(lptr->nick, ciptr->alternate) == 0) ciptr->last_alternate_active = current_ts; } } } #endif /* remove cptr from lptr's chan list */ for (tempchan = lptr->firstchan; tempchan; tempchan = tempchan->next) { if (cptr == tempchan->chptr) { if (prev) prev->next = tempchan->next; else lptr->firstchan = tempchan->next; MyFree(tempchan); tempchan = NULL; break; } prev = tempchan; } /* remove lptr from cptr's nick list */ for (tempuser = cptr->firstuser; tempuser; tempuser = tempuser->next) { if (lptr == tempuser->lptr) { if (prev2) prev2->next = tempuser->next; else cptr->firstuser = tempuser->next; MyFree(tempuser); tempuser = NULL; --cptr->numusers; break; } prev2 = tempuser; } if (cptr->numusers == 0) DeleteChannel(cptr); /* the last nick left the chan, erase it */ } /* RemoveFromChannel() */
/* parse_resvconf() * * inputs - NONE * output - -1 if failure 0 if success * side effects - fills in irc_nsaddr_list */ static int parse_resvconf(void) { char *p; char *opt; char *arg; char input[MAXLINE]; FBFILE *file; /* XXX "/etc/resolv.conf" should be from a define in setup.h perhaps * for cygwin support etc. this hardcodes it to unix for now -db */ if((file = fbopen("/etc/resolv.conf", "r")) == NULL) return -1; while(fbgets(input, sizeof(input), file) != NULL) { /* blow away any newline */ if((p = strpbrk(input, "\r\n")) != NULL) *p = '\0'; p = input; /* skip until something thats not a space is seen */ while(IsSpace(*p)) ++p; /* if at this point, have a '\0' then continue */ if(*p == '\0') continue; /* Ignore comment lines immediately */ if(*p == ';' || *p == '#') continue; /* skip until a space is found */ opt = p; while(!IsSpace(*p) && *p) ++p; if(*p == '\0') continue; /* no arguments?.. ignore this line */ /* blow away the space character */ *p++ = '\0'; /* skip these spaces that are before the argument */ while(IsSpace(*p)) ++p; /* Now arg should be right where p is pointing */ arg = p; if((p = strpbrk(arg, " \t")) != NULL) *p = '\0'; /* take the first word */ if(irccmp(opt, "domain") == 0) strlcpy(irc_domain, arg, HOSTLEN); else if(irccmp(opt, "nameserver") == 0) add_nameserver(arg); } fbclose(file); return 0; }
/* * mo_set - SET command handler * set options while running */ static int mo_set(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { int newval; int i, n; const char *arg = NULL; const char *intarg = NULL; if(parc > 1) { /* * Go through all the commands in set_cmd_table, until one is * matched. I realize strcmp() is more intensive than a numeric * lookup, but at least it's better than a big-ass switch/case * statement. */ for (i = 0; set_cmd_table[i].handler; i++) { if(!irccmp(set_cmd_table[i].name, parv[1])) { /* * Command found; now execute the code */ n = 2; if(set_cmd_table[i].wants_char) { arg = parv[n++]; } if(set_cmd_table[i].wants_int) { intarg = parv[n++]; } if((n - 1) > parc) { sendto_one(source_p, ":%s NOTICE %s :SET %s expects (\"%s%s\") args", me.name, source_p->name, set_cmd_table[i].name, (set_cmd_table[i]. wants_char ? "string, " : ""), (set_cmd_table[i]. wants_char ? "int" : "")); return 0; } if(parc <= 2) { arg = NULL; intarg = NULL; } if(set_cmd_table[i].wants_int && (parc > 2)) { if(intarg) { if(!irccmp(intarg, "yes") || !irccmp(intarg, "on")) newval = 1; else if(!irccmp(intarg, "no") || !irccmp(intarg, "off")) newval = 0; else newval = atoi(intarg); } else { newval = -1; } if(newval < 0) { sendto_one(source_p, ":%s NOTICE %s :Value less than 0 illegal for %s", me.name, source_p->name, set_cmd_table[i].name); return 0; } } else newval = -1; if(set_cmd_table[i].wants_char) { if(set_cmd_table[i].wants_int) set_cmd_table[i].handler(source_p, arg, newval); else set_cmd_table[i].handler(source_p, arg); return 0; } else { if(set_cmd_table[i].wants_int) set_cmd_table[i].handler(source_p, newval); else /* Just in case someone actually wants a * set function that takes no args.. *shrug* */ set_cmd_table[i].handler(source_p); return 0; } } } /* * Code here will be executed when a /QUOTE SET command is not * found within set_cmd_table. */ sendto_one(source_p, ":%s NOTICE %s :Variable not found.", me.name, parv[0]); return 0; } list_quote_commands(source_p); return 0; }
/* * m_pass() - Added Sat, 4 March 1989 * * * mr_pass - PASS message handler * parv[0] = sender prefix * parv[1] = password * parv[2] = "TS" if this server supports TS. * parv[3] = optional TS version field -- needed for TS6 */ static int mr_pass(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(client_p->localClient->passwd) { memset(client_p->localClient->passwd, 0, strlen(client_p->localClient->passwd)); rb_free(client_p->localClient->passwd); } client_p->localClient->passwd = rb_strndup(parv[1], PASSWDLEN); if(parc > 2) { #ifdef COMPAT_211 /* detected 2.11 protocol? */ if (strlen(parv[2]) == 10 && parc > 4) { if (strchr(parv[4], 'Z')) client_p->localClient->caps |= CAP_ZIP; if (strchr(parv[4], 'T')) client_p->localClient->caps |= CAP_TB; if (strchr(parv[4], 'j')) client_p->localClient->caps |= CAP_JAPANESE; if (!strcmp(parv[2], IRCNET_VERSTRING)) { /* nah, it's just us pretending, we're going to receive CAPAB. Will fill the SID in server stage though. */ client_p->localClient->caps |= CAP_TS6|CAPS_IRCNET; } else { /* True 2.11 */ client_p->localClient->caps |= CAP_211|CAPS_IRCNET; /* As we're never going to receive CAPAB for this one */ client_p->localClient->fullcaps = rb_strdup(send_capabilities(NULL, client_p->localClient->caps)); } return 0; } #endif /* * 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(irccmp(parv[2], "TS") == 0 && client_p->tsinfo == 0) client_p->tsinfo = TS_DOESTS; if(parc == 5 && atoi(parv[3]) >= 6) { /* only mark as TS6 if the SID is valid.. */ if(check_sid(parv[4])) { client_p->localClient->caps |= CAP_TS6; strcpy(client_p->id, parv[4]); } } } return 0; }
/* s = service the command was sent to u = user the command was sent from */ void ns_identify(IRC_User *s, IRC_User *u) { MYSQL_RES *res = NULL; MYSQL_ROW row; char *pass = strtok(NULL, " "); char *extraopt = NULL; if(pass != NULL) extraopt = strtok(NULL, ""); if(IsNull(pass)) send_lang(u, s, IDENTIFY_SYNTAX); else if(u->snid) send_lang(u, s, ALREADY_IDENTIFIED); else if((res = sql_query("SELECT snid, flags, lang, email, vhost" " FROM nickserv WHERE nick=%s", sql_str(irc_lower_nick(u->nick)))) && (row = sql_next_row(res))) { int c = 0; u_int32_t snid = atoi(row[c++]); u_int32_t flags = atoi(row[c++]); int lang = atoi(row[c++]); char *email = row[c++]; char *vhost = row[c++]; if((flags & NFL_SUSPENDED) && sql_singlequery("SELECT reason FROM nickserv_suspensions WHERE snid=%d", snid)) { send_lang(u,s, NICK_X_IS_SUSPENDED_X, u->nick, sql_field(0)); return; } if(check_nick_security(snid, u, pass, email, flags) == -1) { log_log(ns_log, mod_info.name, "Nick %s failed identify by %s", u->nick, irc_UserSMask(u)); if(FailedLoginMax && ++u->fcount>FailedLoginMax) { log_log(ns_log, mod_info.name, "Killing %s on too many failed identify attempts", u->nick); irc_Kill(u, s, "Too many failed identify attempts"); } else send_lang(u, s, INCORRECT_PASSWORD); sql_free(res); return; } else { send_lang(u, s, IDENTIFY_OK); log_log(ns_log, mod_info.name, "Nick %s identified by %s", u->nick, irc_UserSMask(u)); update_nick_online_info(u, snid, lang); if(vhost && irccmp(u->publichost, vhost)) /* we need to set the vhost */ irc_ChgHost(u, vhost); irc_CancelUserTimerEvents(u); /* delete the pending change nick event */ mod_do_event(e_nick_identify, u, &snid); } } else send_lang(u, s, NICK_NOT_REGISTERED); sql_free(res); }
/* * mo_set - SET command handler * set options while running */ static int mo_set(struct Client *source_p, int parc, char *parv[]) { int n; int newval; const char *strarg = NULL; const char *intarg = NULL; if (!HasOFlag(source_p, OPER_FLAG_SET)) { sendto_one_numeric(source_p, &me, ERR_NOPRIVS, "set"); return 0; } if (parc > 1) { /* * Go through all the commands in set_cmd_table, until one is * matched. */ for (const struct SetStruct *tab = set_cmd_table; tab->handler; ++tab) { if (irccmp(tab->name, parv[1])) continue; /* * Command found; now execute the code */ n = 2; if (tab->wants_char) strarg = parv[n++]; if (tab->wants_int) intarg = parv[n++]; if ((n - 1) > parc) sendto_one_notice(source_p, &me, ":SET %s expects (\"%s%s\") args", tab->name, (tab->wants_char ? "string, " : ""), (tab->wants_int ? "int" : "")); if (parc <= 2) { strarg = NULL; intarg = NULL; } if (tab->wants_int && parc > 2) { if (intarg) { if (!irccmp(intarg, "yes") || !irccmp(intarg, "on")) newval = 1; else if (!irccmp(intarg, "no") || !irccmp(intarg, "off")) newval = 0; else newval = atoi(intarg); } else newval = -1; if (newval < 0) { sendto_one_notice(source_p, &me, ":Value less than 0 illegal for %s", tab->name); return 0; } } else newval = -1; tab->handler(source_p, strarg, newval); return 0; } /* * Code here will be executed when a /QUOTE SET command is not * found within set_cmd_table. */ sendto_one_notice(source_p, &me, ":Variable not found."); return 0; } list_quote_commands(source_p); return 0; }
/* ** m_flags ** parv[0] = sender prefix ** parv[1] = parameter */ static int m_flags(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { int i, j; int isadd; int setflags; int isgood; char *p; char *flag; if(parc < 2) { /* Generate a list of what flags you have and what you are missing, ** and send it to the user */ sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", me.name, parv[0], set_flags_to_string(source_p)); sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", me.name, parv[0], unset_flags_to_string(source_p)); return 1; } /* Preserve the current flags */ setflags = source_p->umodes; /* XXX - change this to support a multiple last parameter like ISON */ for(i = 1; i < parc; i++) { char *s = LOCAL_COPY(parv[i]); for(flag = strtok_r(s, " ", &p); flag; flag = strtok_r(NULL, " ", &p)) { /* We default to being in ADD mode */ isadd = 1; /* We default to being in BAD mode */ isgood = 0; if(!isalpha(flag[0])) { if(flag[0] == '-') isadd = 0; else if(flag[0] == '+') isadd = 1; flag++; } /* support ALL here */ if(!irccmp(flag, "ALL")) { if(isadd) source_p->umodes |= FL_ALL_USER_FLAGS; else source_p->umodes &= ~FL_ALL_USER_FLAGS; sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", me.name, parv[0], set_flags_to_string(source_p)); sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", me.name, parv[0], unset_flags_to_string(source_p)); send_umode_out(client_p, source_p, setflags); return 1; } for(j = 0; flag_table[j].name; j++) { if(!flag_table[j].oper && !irccmp(flag, flag_table[j].name)) { if(isadd) source_p->umodes |= flag_table[j].mode; else source_p->umodes &= ~(flag_table[j].mode); isgood = 1; continue; } } /* This for ended without matching a valid FLAG, here is where ** I want to operate differently than ircd-comstud, and just ignore ** the invalid flag, send a warning and go on. */ if(!isgood) sendto_one(source_p, ":%s NOTICE %s :Invalid FLAGS: %s (IGNORING)", me.name, parv[0], flag); } } /* All done setting the flags, print the notices out to the user ** telling what flags they have and what flags they are missing */ sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", me.name, parv[0], set_flags_to_string(source_p)); sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", me.name, parv[0], unset_flags_to_string(source_p)); send_umode_out(client_p, source_p, setflags); return 0; }
static int perform_nick_collides(struct Client *source_p, struct Client *client_p, struct Client *target_p, int parc, char *parv[], time_t newts, char *nick) { int sameuser; /* server introducing new nick */ if(IsServer(source_p)) { /* if we dont have a ts, or their TS's are the same, kill both */ if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo)) { sendto_realops_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(both killed)", target_p->name, target_p->from->name, client_p->name); kill_client_serv_butone(NULL, target_p, "%s (Nick collision (new))", me.name); ServerStats->is_kill++; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); target_p->flags |= FLAGS_KILLED; exit_client(client_p, target_p, &me, "Nick collision (new)"); return 0; } /* the timestamps are different */ else { sameuser = (target_p->user) && !irccmp(target_p->username, parv[5]) && !irccmp(target_p->host, parv[6]); /* if the users are the same (loaded a client on a different server) * and the new users ts is older, or the users are different and the * new users ts is newer, ignore the new client and let it do the kill */ if((sameuser && newts < target_p->tsinfo) || (!sameuser && newts > target_p->tsinfo)) { return 0; } else { if(sameuser) sendto_realops_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(older killed)", target_p->name, target_p->from->name, client_p->name); else sendto_realops_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(newer killed)", target_p->name, target_p->from->name, client_p->name); ServerStats->is_kill++; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); /* if it came from a LL server, itd have been source_p, * so we dont need to mark target_p as known */ kill_client_serv_butone(source_p, target_p, "%s (Nick collision (new))", me.name); target_p->flags |= FLAGS_KILLED; (void) exit_client(client_p, target_p, &me, "Nick collision"); nick_from_server(client_p, source_p, parc, parv, newts, nick); return 0; } } } /* its a client changing nick and causing a collide */ if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) || !source_p->user) { sendto_realops_flags(UMODE_ALL, L_ALL, "Nick change collision from %s to %s(%s <- %s)(both killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); ServerStats->is_kill++; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); /* if we got the message from a LL, it knows about source_p */ kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name); ServerStats->is_kill++; kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name); target_p->flags |= FLAGS_KILLED; exit_client(NULL, target_p, &me, "Nick collision(new)"); source_p->flags |= FLAGS_KILLED; exit_client(client_p, source_p, &me, "Nick collision(old)"); return 0; } else { sameuser = !irccmp(target_p->username, source_p->username) && !irccmp(target_p->host, source_p->host); if((sameuser && newts < target_p->tsinfo) || (!sameuser && newts > target_p->tsinfo)) { if(sameuser) sendto_realops_flags(UMODE_ALL, L_ALL, "Nick change collision from %s to %s(%s <- %s)(older killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); else sendto_realops_flags(UMODE_ALL, L_ALL, "Nick change collision from %s to %s(%s <- %s)(newer killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); ServerStats->is_kill++; /* this won't go back to the incoming link, so LL doesnt matter */ kill_client_serv_butone(client_p, source_p, "%s (Nick change collision)", me.name); source_p->flags |= FLAGS_KILLED; if(sameuser) exit_client(client_p, source_p, &me, "Nick collision(old)"); else exit_client(client_p, source_p, &me, "Nick collision(new)"); return 0; } else { if(sameuser) sendto_realops_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(older killed)", target_p->name, target_p->from->name, client_p->name); else sendto_realops_flags(UMODE_ALL, L_ALL, "Nick collision on %s(%s <- %s)(newer killed)", target_p->name, target_p->from->name, client_p->name); kill_client_serv_butone(source_p, target_p, "%s (Nick collision)", me.name); ServerStats->is_kill++; sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name, target_p->name, target_p->name); target_p->flags |= FLAGS_KILLED; (void) exit_client(client_p, target_p, &me, "Nick collision"); } } /* we should only ever call nick_from_server() here, as * this is a client changing nick, not a new client */ nick_from_server(client_p, source_p, parc, parv, newts, nick); return 0; }
static void check_new_user(void *vdata) { struct Client *source_p = (void *)vdata; if (!IsIPSpoof(source_p)) return; if (EmptyString(source_p->user->suser)) return; char *accountpart = strstr(source_p->orighost, "account"); if (!accountpart) return; char buf[HOSTLEN]; memset(buf, 0, sizeof(buf)); char *dst = buf; strncpy(buf, source_p->orighost, accountpart - source_p->orighost); dst += accountpart - source_p->orighost; int needhash = 0; for (char *src = source_p->user->suser; *src ; src++ ) { if (dst > buf + sizeof(buf)) { /* Doesn't fit. Warn opers and bail. */ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Couldn't fit account name part %s in hostname for %s!%s@%s", source_p->user->suser, source_p->name, source_p->username, source_p->orighost); return; } char c = ToLower(*src); if (IsHostChar(c)) *dst++ = c; else needhash = 1; } if (needhash) { if (dst > buf + sizeof(buf) - 12) /* '/x-' plus eight digit hash plus null terminator */ { /* Doesn't fit. Warn opers and bail. */ sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Couldn't fit account name part %s in hostname for %s!%s@%s", source_p->user->suser, source_p->name, source_p->username, source_p->orighost); return; } *dst++ = '/'; *dst++ = 'x'; *dst++ = '-'; unsigned int hashval = fnv_hash_string(source_p->user->suser); hashval %= 100000000; // eight digits only please. snprintf(dst, 9, "%08ud", hashval); } /* just in case */ buf[HOSTLEN-1] = '\0'; /* If hostname has been changed already (probably by services cloak on SASL login), then * leave it intact. If not, change it. In either case, update the original hostname. */ if (0 == irccmp(source_p->host, source_p->orighost)) change_nick_user_host(source_p, source_p->name, source_p->username, buf, 0, "Changing host"); strncpy(source_p->orighost, buf, HOSTLEN); }
/* * nick_from_server() */ static int nick_from_server(struct Client *client_p, struct Client *source_p, int parc, char *parv[], time_t newts, char *nick) { if(IsServer(source_p)) { /* A server introducing a new client, change source */ source_p = make_client(client_p); add_client_to_list(source_p); if(parc > 2) source_p->hopcount = atoi(parv[2]); if(newts) source_p->tsinfo = newts; else { newts = source_p->tsinfo = CurrentTime; ts_warn("Remote nick %s (%s) introduced without a TS", nick, parv[0]); } /* copy the nick in place */ (void) strcpy(source_p->name, nick); (void) add_to_client_hash_table(nick, source_p); if(parc > 8) { int flag; char *m; /* parse usermodes */ m = &parv[4][1]; while (*m) { flag = user_modes_from_c_to_bitmask[(unsigned char) *m]; if(!(source_p->umodes & UMODE_INVISIBLE) && (flag & UMODE_INVISIBLE)) Count.invisi++; if(!(source_p->umodes & UMODE_OPER) && (flag & UMODE_OPER)) Count.oper++; source_p->umodes |= flag & SEND_UMODES; m++; } return do_remote_user(nick, client_p, source_p, parv[5], parv[6], parv[7], (parc > 9)? parv[8] : NULL, parv[(parc > 9)? 9 : 8]); } } else if(source_p->name[0]) { /* client changing their nick */ if(irccmp(parv[0], nick)) source_p->tsinfo = newts ? newts : CurrentTime; sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); if(source_p->user) { add_history(source_p, 1); sendto_server(client_p, NULL, NOCAPS, NOCAPS, ":%s NICK %s :%lu", parv[0], nick, (unsigned long) source_p->tsinfo); } } /* set the new nick name */ if(source_p->name[0]) del_from_client_hash_table(source_p->name, source_p); strcpy(source_p->name, nick); add_to_client_hash_table(nick, source_p); /* remove all accepts pointing to the client */ del_all_accepts(source_p); return 0; }
/* * mr_capab - CAPAB message handler * parv[0] = sender prefix * parv[1] = space-separated list of capabilities * */ static void mr_capab(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Capability *cap; int i; char *p; char *s; #ifdef HAVE_LIBCRYPTO struct EncCapability *ecap; unsigned int cipher = 0; #endif /* ummm, this shouldn't happen. Could argue this should be logged etc. */ if(client_p->localClient == NULL) return; if(client_p->localClient->caps) { exit_client(client_p, client_p, client_p, "CAPAB received twice"); return; } else client_p->localClient->caps |= CAP_CAP; for (i = 1; i < parc; i++) { for (s = strtoken(&p, parv[i], " "); s; s = strtoken(&p, NULL, " ")) { #ifdef HAVE_LIBCRYPTO if((strncmp(s, "ENC:", 4) == 0)) { /* Skip the "ENC:" portion */ s += 4; /* Check the remaining portion against the list of ciphers we * have available (CipherTable). */ for (ecap = CipherTable; ecap->name; ecap++) { if((!irccmp(ecap->name, s)) && (ecap->cap & CAP_ENC_MASK)) { cipher = ecap->cap; break; } } /* Since the name and capabilities matched, use it. */ if(cipher != 0) { SetCapable(client_p, CAP_ENC); client_p->localClient->enc_caps |= cipher; } else { /* cipher is still zero; we didn't find a matching entry. */ exit_client(client_p, client_p, client_p, "Cipher selected is not available here."); return; } } else /* normal capab */ #endif for (cap = captab; cap->name; cap++) { if(!irccmp(cap->name, s)) { client_p->localClient->caps |= cap->cap; break; } } } /* for */ } /* for */ }
static int clicap_compare(const char *name, struct clicap *cap) { return irccmp(name, cap->name); }
/* * m_challenge - generate RSA challenge for wouldbe oper * parv[0] = sender prefix * parv[1] = operator to challenge for, or +response * */ static void m_challenge(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *challenge = NULL; struct ConfItem *conf = NULL; struct AccessItem *aconf = NULL; /* if theyre an oper, reprint oper motd and ignore */ if (IsOper(source_p)) { sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, parv[0]); send_message_file(source_p, &ConfigFileEntry.opermotd); return; } if (*parv[1] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if (source_p->localClient->response == NULL) return; if (irccmp(source_p->localClient->response, ++parv[1])) { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name); failed_challenge_notice(source_p, source_p->localClient->auth_oper, "challenge failed"); return; } conf = find_exact_name_conf(OPER_TYPE, source_p->localClient->auth_oper, source_p->username, source_p->host); if (conf == NULL) conf = find_exact_name_conf(OPER_TYPE, source_p->localClient->auth_oper, source_p->username, source_p->sockhost); if (conf == NULL) { sendto_one (source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); log_oper_action(LOG_FAILED_OPER_TYPE, source_p, "%s\n", source_p->localClient->auth_oper); return; } if (attach_conf(source_p, conf) != 0) { sendto_one(source_p,":%s NOTICE %s :Can't attach conf!", me.name, source_p->name); failed_challenge_notice(source_p, conf->name, "can't attach conf!"); log_oper_action(LOG_FAILED_OPER_TYPE, source_p, "%s\n", source_p->localClient->auth_oper); return; } oper_up(source_p); ilog(L_TRACE, "OPER %s by %s!%s@%s", source_p->localClient->auth_oper, source_p->name, source_p->username, source_p->host); log_oper_action(LOG_OPER_TYPE, source_p, "%s\n", source_p->localClient->auth_oper); MyFree(source_p->localClient->response); MyFree(source_p->localClient->auth_oper); source_p->localClient->response = NULL; source_p->localClient->auth_oper = NULL; return; } MyFree(source_p->localClient->response); MyFree(source_p->localClient->auth_oper); source_p->localClient->response = NULL; source_p->localClient->auth_oper = NULL; if ((conf = find_conf_exact(OPER_TYPE, parv[1], source_p->username, source_p->host )) != NULL) aconf = map_to_conf(conf); else if ((conf = find_conf_exact(OPER_TYPE, parv[1], source_p->username, source_p->sockhost)) != NULL) aconf = map_to_conf(conf); if (aconf == NULL) { sendto_one (source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); conf = find_exact_name_conf(OPER_TYPE, parv[1], NULL, NULL); failed_challenge_notice(source_p, parv[1], (conf != NULL) ? "host mismatch" : "no oper {} block"); log_oper_action(LOG_FAILED_OPER_TYPE, source_p, "%s\n", parv[1]); return; } if (aconf->rsa_public_key == NULL) { sendto_one (source_p, ":%s NOTICE %s :I'm sorry, PK authentication " "is not enabled for your oper{} block.", me.name, parv[0]); return; } if (!generate_challenge(&challenge, &(source_p->localClient->response), aconf->rsa_public_key)) sendto_one(source_p, form_str(RPL_RSACHALLENGE), me.name, parv[0], challenge); DupString(source_p->localClient->auth_oper, conf->name); MyFree(challenge); }
/* ** mo_forcenick ** parv[1] = forcenick victim ** parv[2] = new nickname */ static int mo_forcenick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p, *exist_p; const char *user; const char *newnick; user = parv[1]; /* You must be this tall to ride the ride */ if(!IsOperLocalForce(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "local_force"); return 0; } /* Truncate it so clean_nick doesn't spaz out */ if(!EmptyString(parv[2])) { char *s; s = LOCAL_COPY(parv[2]); if(strlen(s) > (size_t) NICKLEN) s[NICKLEN] = '\0'; newnick = s; } else { sendto_one_numeric(source_p, ERR_NONICKNAMEGIVEN, form_str(ERR_NONICKNAMEGIVEN), me.name, source_p->name); return 0; } /* Nick has to be clean or we'll have a protocol violation... */ if(!clean_nick(newnick)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, user, newnick); return 0; } /* Find the target... */ if((target_p = find_named_person(user)) == NULL) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "FORCENICK"); return 0; } /* If it's a server, sod it, changing its name is stupid... */ if(IsServer(target_p) || IsMe(target_p)) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), user); return 0; } /* Do we have permission to send it globally? */ if(!MyClient(target_p) && (!IsOperGlobalForce(source_p))) { sendto_one_notice(source_p, ":Nick %s is not on your server and you do not have the global_force flag", target_p->name); return 0; } /* Check to see if the new nick exists */ if((exist_p = find_named_person(newnick)) != NULL) { /* Could just be a case shift */ if(irccmp(target_p->name, newnick)) { sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, user, newnick); return 0; } /* If it's the same nick, f**k it */ else if(!strcmp(target_p->name, newnick)) return 0; } sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Received FORCENICK message for %s!%s@%s. From %s (Newnick: %s)", target_p->name, target_p->username, target_p->orighost, source_p->name, newnick); ilog(L_MAIN, "FORCENICK called for [%s] by %s!%s@%s", target_p->name, source_p->name, source_p->username, source_p->host); sendto_one_notice(target_p, ":You have been forcenicked from %s to %s by %s", target_p->name, newnick, source_p->name); if(!MyClient(target_p)) { struct Client *cptr = target_p->servptr; sendto_one(cptr, ":%s ENCAP %s FORCENICK %s :%s", get_id(source_p, cptr), cptr->name, get_id(target_p, cptr), newnick); return 0; } change_nick(target_p, newnick); return 0; }
/* mo_flags() * * parv[0] = sender prefix * parv[1] = parameter */ static void mo_flags(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { int i,j; int isadd; int isgood; unsigned int setflags; char *p; char *flag; if (parc < 2) { /* Generate a list of what flags you have and what you are missing, ** and send it to the user */ sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", me.name, parv[0], set_flags_to_string(source_p)); sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", me.name, parv[0], unset_flags_to_string(source_p)); return; } /* Preserve the current flags */ setflags = source_p->umodes; /* XXX - change this to support a multiple last parameter like ISON */ for (i = 1; i < parc; i++) { for (flag = strtoken(&p, parv[i], " "); flag; flag = strtoken(&p, NULL, " ")) { /* We default to being in ADD mode */ isadd = 1; /* We default to being in BAD mode */ isgood = 0; if (!isalpha(*flag)) { if (*flag == '-') isadd = 0; else if (*flag == '+') isadd = 1; ++flag; } /* support ALL here */ if (!irccmp(flag, "ALL")) { if (isadd) source_p->umodes |= FL_ALL_OPER_FLAGS; else source_p->umodes &= ~FL_ALL_OPER_FLAGS; sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", me.name, parv[0], set_flags_to_string(source_p)); sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", me.name, parv[0], unset_flags_to_string(source_p)); send_umode_out(client_p, source_p, setflags); return; } if (!irccmp(flag, "NICKCHANGES")) { if (!IsOperN(source_p)) { sendto_one(source_p, ":%s NOTICE %s :*** You have no nick_changes flag;", me.name,parv[0]); continue; } if (isadd) source_p->umodes |= UMODE_NCHANGE; else source_p->umodes &= ~UMODE_NCHANGE; isgood = 1; continue; } for (j = 0; flag_table[j].name; j++) { if (!irccmp(flag, flag_table[j].name)) { if (isadd) source_p->umodes |= flag_table[j].mode; else source_p->umodes &= ~ (flag_table[j].mode); isgood = 1; continue; } } /* This for ended without matching a valid FLAG, here is where * I want to operate differently than ircd-comstud, and just ignore * the invalid flag, send a warning and go on. */ if (!isgood) sendto_one(source_p, ":%s NOTICE %s :Invalid FLAGS: %s (IGNORING)", me.name, parv[0], flag); } } /* All done setting the flags, print the notices out to the user ** telling what flags they have and what flags they are missing */ sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", me.name, parv[0], set_flags_to_string(source_p)); sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", me.name, parv[0], unset_flags_to_string(source_p)); send_umode_out(client_p, source_p, setflags); }
/* * mr_webirc * parv[0] = sender prefix * parv[1] = password * parv[2] = fake username (we ignore this) * parv[3] = fake hostname * parv[4] = fake ip */ static void mr_webirc(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct AccessItem *aconf = NULL; struct ConfItem *conf = NULL; struct addrinfo hints, *res; char original_sockhost[HOSTIPLEN + 1]; assert(source_p == client_p); if (invalid_hostname(parv[4])) return; aconf = find_address_conf(source_p->host, IsGotId(source_p) ? source_p->username : "******", &source_p->ip, source_p->aftype, parv[1], source_p->certfp); if (aconf == NULL || !IsConfClient(aconf)) return; conf = unmap_conf_item(aconf); if (!IsConfDoSpoofIp(aconf) || irccmp(conf->name, "webirc.")) { sendto_gnotice_flags(UMODE_UNAUTH, L_ALL, me.name, &me, NULL, "Not a CGI:IRC auth block: %s", source_p->sockhost); return; } if (EmptyString(aconf->passwd)) { sendto_gnotice_flags(UMODE_UNAUTH, L_ALL, me.name, &me, NULL, "CGI:IRC auth blocks must have a password"); return; } if (!match_conf_password(parv[1], aconf)) { sendto_gnotice_flags(UMODE_UNAUTH, L_ALL, me.name, &me, NULL, "CGI:IRC password incorrect"); return; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(parv[4], NULL, &hints, &res)) { sendto_gnotice_flags(UMODE_UNAUTH, L_ALL, me.name, &me, NULL, "Inavlid CGI:IRC IP %s", parv[4]); return; } assert(res != NULL); memcpy(&source_p->ip, res->ai_addr, res->ai_addrlen); source_p->ip.ss_len = res->ai_addrlen; source_p->ip.ss.ss_family = res->ai_family; source_p->aftype = res->ai_family; freeaddrinfo(res); strlcpy(original_sockhost, source_p->sockhost, sizeof(original_sockhost)); strlcpy(source_p->sockhost, parv[4], sizeof(source_p->sockhost)); if (strlen(parv[3]) <= HOSTLEN) strlcpy(source_p->host, parv[3], sizeof(source_p->host)); else strlcpy(source_p->host, source_p->sockhost, sizeof(source_p->host)); /* Check dlines now, k/glines will be checked on registration */ if ((aconf = find_dline_conf(&client_p->ip, client_p->aftype))) { if (!(aconf->status & CONF_EXEMPTDLINE)) { exit_client(client_p, &me, "D-lined"); return; } } sendto_gnotice_flags(UMODE_CCONN, L_ALL, me.name, &me, NULL, "CGI:IRC host/IP set %s to %s (%s)", original_sockhost, parv[3], parv[4]); }
/* * mo_omode - MODE command handler * parv[1] - channel */ static int mo_omode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; char params[512]; int i; int wasonchannel; /* admins only */ if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin"); return 0; } /* Now, try to find the channel in question */ if(!IsChanPrefix(parv[1][0]) || !check_channel_name(parv[1])) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[1]); return 0; } chptr = find_channel(parv[1]); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } /* Now know the channel exists */ msptr = find_channel_membership(chptr, source_p); wasonchannel = msptr != NULL; params[0] = '\0'; for (i = 2; i < parc; i++) { if (i != 2) rb_strlcat(params, " ", sizeof params); rb_strlcat(params, parv[i], sizeof params); } sendto_wallops_flags(UMODE_WALLOP, &me, "OMODE called for [%s] [%s] by %s!%s@%s", parv[1], params, source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "OMODE called for [%s] [%s] by %s", parv[1], params, get_oper_name(source_p)); if(*chptr->chname != '&') sendto_server(NULL, NULL, NOCAPS, NOCAPS, ":%s WALLOPS :OMODE called for [%s] [%s] by %s!%s@%s", me.name, parv[1], params, source_p->name, source_p->username, source_p->host); #if 0 set_channel_mode(client_p, source_p->servptr, chptr, msptr, parc - 2, parv + 2); #else if (parc == 4 && !strcmp(parv[2], "+y") && !irccmp(parv[3], source_p->name)) { /* Ownering themselves */ if (!wasonchannel) { sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname); return 0; } sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +y %s", me.name, parv[1], source_p->name); sendto_server(NULL, chptr, CAP_TS6, NOCAPS, ":%s TMODE %ld %s +y %s", me.id, (long) chptr->channelts, parv[1], source_p->id); msptr->flags |= CHFL_OWNER; } else if (parc == 4 && !strcmp(parv[2], "+a") && !irccmp(parv[3], source_p->name)) { /* Admining themselves */ if (!wasonchannel) { sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname); return 0; } sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +a %s", me.name, parv[1], source_p->name); sendto_server(NULL, chptr, CAP_TS6, NOCAPS, ":%s TMODE %ld %s +a %s", me.id, (long) chptr->channelts, parv[1], source_p->id); msptr->flags |= CHFL_ADMIN; } else if (parc == 4 && !strcmp(parv[2], "+o") && !irccmp(parv[3], source_p->name)) { /* Opping themselves */ if (!wasonchannel) { sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname); return 0; } sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s", me.name, parv[1], source_p->name); sendto_server(NULL, chptr, CAP_TS6, NOCAPS, ":%s TMODE %ld %s +o %s", me.id, (long) chptr->channelts, parv[1], source_p->id); msptr->flags |= CHFL_CHANOP; } else if (parc == 4 && !strcmp(parv[2], "+h") && !irccmp(parv[3], source_p->name)) { /* Halfopping themselves */ if (!wasonchannel) { sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname); return 0; } sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +h %s", me.name, parv[1], source_p->name); sendto_server(NULL, chptr, CAP_TS6, NOCAPS, ":%s TMODE %ld %s +h %s", me.id, (long) chptr->channelts, parv[1], source_p->id); msptr->flags |= CHFL_HALFOP; } else if (ConfigChannel.use_owner) { /* I hope this is correct. * -- Kabaka */ /* Hack it so set_channel_mode() will accept */ if (wasonchannel) msptr->flags |= CHFL_OWNER; else { add_user_to_channel(chptr, source_p, CHFL_CHANOP); msptr = find_channel_membership(chptr, source_p); } set_channel_mode(client_p, source_p, chptr, msptr, parc - 2, parv + 2); if (wasonchannel) msptr->flags &= ~CHFL_OWNER; else remove_user_from_channel(msptr); } else if (ConfigChannel.use_admin) { /* Hack it so set_channel_mode() will accept */ if (wasonchannel) msptr->flags |= CHFL_ADMIN; else { add_user_to_channel(chptr, source_p, CHFL_CHANOP); msptr = find_channel_membership(chptr, source_p); } set_channel_mode(client_p, source_p, chptr, msptr, parc - 2, parv + 2); /* We know they were not opped before and they can't have opped * themselves as set_channel_mode() does not allow that * -- jilles */ if (wasonchannel) msptr->flags &= ~CHFL_ADMIN; else remove_user_from_channel(msptr); } else { /* CHFL_ADMIN is only useful if admin is enabled * so hack it with op if it is not. */ if (wasonchannel) msptr->flags |= CHFL_CHANOP; else { add_user_to_channel(chptr, source_p, CHFL_CHANOP); msptr = find_channel_membership(chptr, source_p); } set_channel_mode(client_p, source_p, chptr, msptr, parc - 2, parv + 2); /* We know they were not opped before and they can't have opped * themselves as set_channel_mode() does not allow that * -- jilles */ if (wasonchannel) msptr->flags &= ~CHFL_CHANOP; else remove_user_from_channel(msptr); } #endif return 0; }
/* * m_challenge - generate RSA challenge for wouldbe oper * parv[0] = sender prefix * parv[1] = operator to challenge for, or +response * */ static void m_challenge(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *challenge = NULL; struct MaskItem *conf = NULL; if (*parv[1] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if (source_p->localClient->response == NULL) return; if (irccmp(source_p->localClient->response, ++parv[1])) { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name); failed_challenge_notice(source_p, source_p->localClient->auth_oper, "challenge failed"); return; } conf = find_exact_name_conf(CONF_OPER, source_p, source_p->localClient->auth_oper, NULL, NULL); if (conf == NULL) { /* XXX: logging */ sendto_one (source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name); return; } if (attach_conf(source_p, conf) != 0) { sendto_one(source_p,":%s NOTICE %s :Can't attach conf!", me.name, source_p->name); failed_challenge_notice(source_p, conf->name, "can't attach conf!"); return; } ++conf->count; oper_up(source_p); ilog(LOG_TYPE_OPER, "OPER %s by %s!%s@%s", source_p->localClient->auth_oper, source_p->name, source_p->username, source_p->host); MyFree(source_p->localClient->response); MyFree(source_p->localClient->auth_oper); source_p->localClient->response = NULL; source_p->localClient->auth_oper = NULL; return; } MyFree(source_p->localClient->response); MyFree(source_p->localClient->auth_oper); source_p->localClient->response = NULL; source_p->localClient->auth_oper = NULL; conf = find_exact_name_conf(CONF_OPER, source_p, parv[1], NULL, NULL); if (!conf) { sendto_one (source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name); conf = find_exact_name_conf(CONF_OPER, NULL, parv[1], NULL, NULL); failed_challenge_notice(source_p, parv[1], (conf != NULL) ? "host mismatch" : "no oper {} block"); return; } if (conf->rsa_public_key == NULL) { sendto_one (source_p, ":%s NOTICE %s :I'm sorry, PK authentication " "is not enabled for your oper{} block.", me.name, source_p->name); return; } if (!generate_challenge(&challenge, &(source_p->localClient->response), conf->rsa_public_key)) sendto_one(source_p, form_str(RPL_RSACHALLENGE), me.name, source_p->name, challenge); source_p->localClient->auth_oper = xstrdup(conf->name); MyFree(challenge); }
/* * m_htm - HTM command handler * high traffic mode info */ int m_htm(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { char *command; if (!MyClient(sptr) || !IsOper(sptr)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } sendto_one(sptr, ":%s NOTICE %s :HTM is %s(%d), %s. Max rate = %dk/s. Current = %.1fk/s", me.name, parv[0], LIFESUX ? "ON" : "OFF", LIFESUX, NOISYHTM ? "NOISY" : "QUIET", LRV, currlife); if (parc > 1) { command = parv[1]; if (!irccmp(command,"TO")) { if (parc > 2) { int new_value = atoi(parv[2]); if (new_value < 10) { sendto_one(sptr, ":%s NOTICE %s :Cannot set LRV < 10!", me.name, parv[0]); } else LRV = new_value; sendto_one(sptr, ":%s NOTICE %s :NEW Max rate = %dk/s. Current = %.1fk/s", me.name, parv[0], LRV, currlife); sendto_realops("%s!%s@%s set new HTM rate to %dk/s (%.1fk/s current)", parv[0], sptr->username, sptr->host, LRV, currlife); } else sendto_one(sptr, ":%s NOTICE %s :LRV command needs an integer parameter",me.name, parv[0]); } else { if (!irccmp(command,"ON")) { LIFESUX = 1; sendto_one(sptr, ":%s NOTICE %s :HTM is now ON.", me.name, parv[0]); sendto_ops("Entering high-traffic mode: Forced by %s!%s@%s", parv[0], sptr->username, sptr->host); LCF = 30; /* 30s */ } else if (!irccmp(command,"OFF")) { LIFESUX = 0; LCF = LOADCFREQ; sendto_one(sptr, ":%s NOTICE %s :HTM is now OFF.", me.name, parv[0]); sendto_ops("Resuming standard operation: Forced by %s!%s@%s", parv[0], sptr->username, sptr->host); } else if (!irccmp(command,"QUIET")) { sendto_ops("HTM is now QUIET"); NOISYHTM = NO; } else if (!irccmp(command,"NOISY")) { sendto_ops("HTM is now NOISY"); NOISYHTM = YES; } else sendto_one(sptr, ":%s NOTICE %s :Commands are:HTM [ON] [OFF] [TO int] [QUIET] [NOISY]", me.name, parv[0]); } } return 0; }
/* ** m_pong ** parv[0] = sender prefix ** parv[1] = origin ** parv[2] = destination */ int m_pong(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *acptr = NULL; char *origin, *destination; if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, form_str(ERR_NOORIGIN), me.name, parv[0]); return 0; } origin = parv[1]; destination = parv[2]; #ifdef HLC /* for HLC --fabulous */ if ((IsServer(cptr)) && (parv[2]) && (IsDigit(*parv[2]))) { sentping = 0; receivedat = atoi(parv[2]); } #endif /* 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) && irccmp(destination, me.name) != 0 && IsRegistered(sptr)) { if ((acptr = find_client(destination, NULL)) || (acptr = find_server(destination))) sendto_one(acptr,":%s PONG %s %s", parv[0], origin, destination); else { sendto_one(sptr, form_str(ERR_NOSUCHSERVER), me.name, parv[0], destination); return 0; } } else { if (MyConnect(sptr)) { sptr->flags &= ~FLAGS_PINGSENT; #ifdef NEED_SPLITCODE #ifdef SPLIT_PONG if (IsServer(sptr)) got_server_pong = 1; #endif #endif if(MyClient(sptr) && cptr->user) check_idle_actions(cptr); } } return 0; }
/* * cryptlink_auth - CRYPTLINK AUTH message handler * parv[1] = secret key */ static void cryptlink_auth(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct EncCapability *ecap; struct ConfItem *conf; struct AccessItem *aconf; int enc_len; int len; unsigned char *enc; unsigned char *key; if (parc < 4) { cryptlink_error(client_p, "AUTH", "Invalid params", "CRYPTLINK AUTH - Invalid params"); return; } if (!IsWaitAuth(client_p)) return; for (ecap = CipherTable; ecap->name; ecap++) { if ((!irccmp(ecap->name, parv[2])) && (IsCapableEnc(client_p, ecap->cap))) { client_p->localClient->in_cipher = ecap; break; } } if (client_p->localClient->in_cipher == NULL) { cryptlink_error(client_p, "AUTH", "Invalid cipher", "Invalid cipher"); return; } if (!(enc_len = unbase64_block(&enc, parv[3], strlen(parv[3])))) { cryptlink_error(client_p, "AUTH", "Could not base64 decode response", "Malformed CRYPTLINK AUTH reply"); return; } if (verify_private_key() == -1) { sendto_realops_flags(UMODE_ALL, L_ADMIN, "verify_private_key() returned -1. Check log for information."); } key = MyMalloc(RSA_size(ServerInfo.rsa_private_key)); len = RSA_private_decrypt(enc_len, (unsigned char *)enc,(unsigned char *)key, ServerInfo.rsa_private_key, RSA_PKCS1_PADDING); if (len < client_p->localClient->in_cipher->keylen) { report_crypto_errors(); if (len < 0) { cryptlink_error(client_p, "AUTH", "Decryption failed", "Malformed CRYPTLINK AUTH reply"); } else { cryptlink_error(client_p, "AUTH", "Not enough random data sent", "Malformed CRYPTLINK AUTH reply"); } MyFree(enc); MyFree(key); return; } if (memcmp(key, client_p->localClient->in_key, client_p->localClient->in_cipher->keylen) != 0) { cryptlink_error(client_p, "AUTH", "Unauthorized server connection attempt", "Malformed CRYPTLINK AUTH reply"); return; } conf = find_conf_name(&client_p->localClient->confs, client_p->name, SERVER_TYPE); if (conf == NULL) { cryptlink_error(client_p, "AUTH", "Lost C-line for server", "Lost C-line"); return; } aconf = (struct AccessItem *)map_to_conf(conf); if (!(client_p->localClient->out_cipher || (client_p->localClient->out_cipher = check_cipher(client_p, aconf)))) { cryptlink_error(client_p, "AUTH", "Couldn't find compatible cipher", "Couldn't find compatible cipher"); return; } /* set hopcount */ client_p->hopcount = 1; SetCryptIn(client_p); ClearWaitAuth(client_p); server_estab(client_p); }
/* * m_challenge - generate RSA challenge for wouldbe oper * parv[0] = sender prefix * parv[1] = operator to challenge for, or +response * */ static void m_challenge( struct Client *client_p, struct Client *source_p, int parc, char *parv[] ) { char * challenge; dlink_node *ptr; struct ConfItem *aconf, *oconf; if(!(source_p->user) || !source_p->localClient) return; /* if theyre an oper, reprint oper motd and ignore */ if(IsOper(source_p)) { sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, parv[0]); SendMessageFile(source_p, &ConfigFileEntry.opermotd); return; } if (*parv[1] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if (!source_p->user->response) return; if (irccmp(source_p->user->response, ++parv[1])) { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name); log_foper(source_p, source_p->user->auth_oper); if(ConfigFileEntry.failed_oper_notice) sendto_realops_flags(UMODE_ALL, L_ALL, "Failed OPER attempt by %s (%s@%s)", source_p->name, source_p->username, source_p->host); return; } if ((aconf = find_conf_by_name(source_p->user->auth_oper, CONF_OPERATOR)) == NULL) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); log_foper(source_p, source_p->user->auth_oper); if(ConfigFileEntry.failed_oper_notice) sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt - host mismatch by %s (%s@%s)", source_p->name, source_p->username, source_p->host); return; } ptr = source_p->localClient->confs.head; oconf = ptr->data; detach_conf(source_p,oconf); if(attach_conf(source_p, aconf) != 0) { sendto_one(source_p,":%s NOTICE %s :Can't attach conf!", me.name,source_p->name); sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt by %s (%s@%s) can't attach conf!", source_p->name, source_p->username, source_p->host); log_foper(source_p, source_p->user->auth_oper); attach_conf(source_p, oconf); return; } oper_up(source_p, aconf); ilog(L_TRACE, "OPER %s by %s!%s@%s", source_p->user->auth_oper, source_p->name, source_p->username, source_p->host); log_oper(source_p, source_p->user->auth_oper); MyFree(source_p->user->response); MyFree(source_p->user->auth_oper); source_p->user->response = NULL; source_p->user->auth_oper = NULL; return; } MyFree(source_p->user->response); MyFree(source_p->user->auth_oper); source_p->user->response = NULL; source_p->user->auth_oper = NULL; if (!(aconf = find_conf_exact(parv[1], source_p->username, source_p->host, CONF_OPERATOR)) && !(aconf = find_conf_exact(parv[1], source_p->username, source_p->localClient->sockhost, CONF_OPERATOR))) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); log_foper(source_p, source_p->user->auth_oper); if(ConfigFileEntry.failed_oper_notice) sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt - host mismatch by %s (%s@%s)", source_p->name, source_p->username, source_p->host); return; } if(!aconf->rsa_public_key) { sendto_one(source_p, ":%s NOTICE %s :I'm sorry, PK authentication " "is not enabled for your oper{} block.", me.name, parv[0]); return; } if(!generate_challenge(&challenge, &(source_p->user->response), aconf->rsa_public_key)) { sendto_one(source_p, form_str(RPL_RSACHALLENGE), me.name, parv[0], challenge); } DupString(source_p->user->auth_oper, aconf->name); MyFree(challenge); return; }
/* * m_pass() - Added Sat, 4 March 1989 * * * mr_pass - PASS message handler * parv[1] = password * parv[2] = "TS" if this server supports TS. * parv[3] = optional TS version field -- needed for TS6 */ static int mr_pass(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { char *auth_user, *pass, *buf; buf = LOCAL_COPY(parv[1]); if(client_p->localClient->passwd) { memset(client_p->localClient->passwd, 0, strlen(client_p->localClient->passwd)); rb_free(client_p->localClient->passwd); client_p->localClient->passwd = NULL; } if (client_p->localClient->auth_user) { memset(client_p->localClient->auth_user, 0, strlen(client_p->localClient->auth_user)); rb_free(client_p->localClient->auth_user); client_p->localClient->auth_user = NULL; } if ((pass = strchr(buf, ':')) != NULL) { *pass++ = '\0'; auth_user = buf; } else { pass = buf; auth_user = NULL; } client_p->localClient->passwd = *pass ? rb_strndup(pass, PASSWDLEN) : NULL; if(auth_user && *auth_user) client_p->localClient->auth_user = rb_strndup(auth_user, PASSWDLEN); /* These are for servers only */ if(parc > 2 && client_p->user == NULL) { /* * 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(irccmp(parv[2], "TS") == 0 && client_p->tsinfo == 0) client_p->tsinfo = TS_DOESTS; if(parc == 5 && atoi(parv[3]) >= 6) { /* only mark as TS6 if the SID is valid.. */ if(IsDigit(parv[4][0]) && IsIdChar(parv[4][1]) && IsIdChar(parv[4][2]) && parv[4][3] == '\0' && EmptyString(client_p->id)) { client_p->localClient->caps |= CAP_TS6; strcpy(client_p->id, parv[4]); } } } return 0; }
static int on_putlog(int flags, const char *chan, const char *text, int len) { char *ts; int i; ts = timer_get_timestamp(); for (i = nlogfiles - 1; i >= 0; i--) { logfile_t *log = &logfiles[i]; /* If this log is disabled, skip it */ if (log->state != LOG_STATE_ENABLED) continue; /* If this log doesn't match, skip it. */ if (!(log->mask & flags)) { continue; } if (chan[0] != '*' && log->chname[0] != '*' && irccmp(chan, log->chname)) continue; /* If it's a repeat message, don't write it again. */ if (log->last_msg && !strcasecmp(text, log->last_msg)) { log->repeats++; continue; } /* If there was a repeated message, write the count. */ if (log->repeats) { fprintf(log->fp, "%s", ts); fprintf(log->fp, _("Last message repeated %d time(s).\n"), log->repeats); log->repeats = 0; } /* Save this msg to check for repeats next time. */ str_redup(&log->last_msg, text); if (log->fp == NULL) { if (log->fname == NULL) { char buf[1024]; time_t now; now = time(NULL); strftime(buf, sizeof(buf), log->filename, localtime(&now)); log->fname = strdup(buf); } log->fp = fopen(log->fname, "a+"); if (log->fp == NULL) { log->state = LOG_STATE_DISABLED; putlog(LOG_MISC, "*", _("Failed to open log file: %s"), log->fname); putlog(LOG_MISC, "*", _(" Check if directory (if any) exists and is read- and writeable.")); continue; } } /* Now output to the file. */ fprintf(log->fp, "%s%s\n", ts, text); } if (!backgrd || use_stderr) { if (terminal_mode) { /* check if HQ is on console. If yes we disable * output to stdout since otherwise everything would * be printed out twice. */ if (!terminal_enabled) { terminal_enabled = (partymember_lookup(TERMINAL_NICK, NULL, -1) != NULL); } if (terminal_enabled) return 0; } fprintf (stdout, "%s %s%s\n", chan, ts, text); } return(0); }
/* * mr_webirc - webirc message handler * parv[1] = password * parv[2] = fake username (we ignore this) * parv[3] = fake hostname * parv[4] = fake ip */ static int mr_webirc(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct ConfItem *aconf; const char *encr; if (!strchr(parv[4], '.') && !strchr(parv[4], ':')) { sendto_one(source_p, "NOTICE * :Invalid IP"); return 0; } aconf = find_address_conf(client_p->host, client_p->sockhost, IsGotId(client_p) ? client_p->username : "******", IsGotId(client_p) ? client_p->username : "******", (struct sockaddr *) &client_p->localClient->ip, client_p->localClient->ip.ss_family, NULL); if (aconf == NULL || !(aconf->status & CONF_CLIENT)) return 0; if (!IsConfDoSpoofIp(aconf) || irccmp(aconf->info.name, "webirc.")) { /* XXX */ sendto_one(source_p, "NOTICE * :Not a CGI:IRC auth block"); return 0; } if (EmptyString(aconf->passwd)) { sendto_one(source_p, "NOTICE * :CGI:IRC auth blocks must have a password"); return 0; } if (EmptyString(parv[1])) encr = ""; else if (IsConfEncrypted(aconf)) encr = rb_crypt(parv[1], aconf->passwd); else encr = parv[1]; if (strcmp(encr, aconf->passwd)) { sendto_one(source_p, "NOTICE * :CGI:IRC password incorrect"); return 0; } rb_strlcpy(source_p->sockhost, parv[4], sizeof(source_p->sockhost)); if(strlen(parv[3]) <= HOSTLEN) rb_strlcpy(source_p->host, parv[3], sizeof(source_p->host)); else rb_strlcpy(source_p->host, source_p->sockhost, sizeof(source_p->host)); rb_inet_pton_sock(parv[4], (struct sockaddr *)&source_p->localClient->ip); /* Check dlines now, klines will be checked on registration */ if((aconf = find_dline((struct sockaddr *)&source_p->localClient->ip, source_p->localClient->ip.ss_family))) { if(!(aconf->status & CONF_EXEMPTDLINE)) { exit_client(client_p, source_p, &me, "D-lined"); return 0; } } sendto_one(source_p, "NOTICE * :CGI:IRC host/IP set to %s %s", parv[3], parv[4]); return 0; }
/* ** m_ltrace - LimitedTRACE... like m_trace() but doesn't return TRACEUSER, TRACEUNKNOWN, or TRACECLASS ** parv[0] = sender prefix ** parv[1] = servername */ int m_ltrace(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { int i; struct Client *acptr = NULL; char *tname; int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS]; int cnt = 0, wilds, dow; static time_t now; if (check_registered(sptr)) return 0; #ifdef SERVERHIDE if (!IsAnOper(sptr)) return 0; #endif if (parc > 2) if (hunt_server(cptr, sptr, ":%s LTRACE %s :%s", 2, parc, parv)) return 0; if (parc > 1) tname = parv[1]; else tname = me.name; switch (hunt_server(cptr, sptr, ":%s LTRACE :%s", 1, parc, parv)) { case HUNTED_PASS: /* note: gets here only if parv[1] exists */ { struct Client *ac2ptr; ac2ptr = next_client(GlobalClientList, tname); if (ac2ptr) sendto_one(sptr, form_str(RPL_TRACELINK), me.name, parv[0], ircd_version, debugmode, tname, ac2ptr->from->name); else sendto_one(sptr, form_str(RPL_TRACELINK), me.name, parv[0], ircd_version, debugmode, tname, "ac2ptr_is_NULL!!"); return 0; } case HUNTED_ISME: break; default: return 0; } if(MyClient(sptr)) sendto_realops_flags(FLAGS_SPY, "ltrace requested by %s (%s@%s) [%s]", sptr->name, sptr->username, sptr->host, sptr->user->server); doall = (parv[1] && (parc > 1)) ? match(tname, me.name): TRUE; wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?'); dow = wilds || doall; if(!IsAnOper(sptr) || !dow) /* non-oper traces must be full nicks */ /* lets also do this for opers tracing nicks */ { const char* name; const char* ip; int c_class; acptr = hash_find_client(tname,(struct Client *)NULL); if(!acptr || !IsPerson(acptr)) { /* this should only be reached if the matching target is this server */ sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0], tname); return 0; } name = get_client_name(acptr, FALSE); ip = inetntoa((char*) &acptr->ip); c_class = get_client_class(acptr); if (IsAnOper(acptr)) { sendto_one(sptr, form_str(RPL_TRACEOPERATOR), me.name, parv[0], c_class, name, IsAnOper(sptr)?ip:(IsIPHidden(acptr)?"255.255.255.255":ip), now - acptr->lasttime, (acptr->user)?(now - acptr->user->last):0); } sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0], tname); return 0; } for (i = 0; i < MAXCONNECTIONS; i++) link_s[i] = 0, link_u[i] = 0; if (dow && LIFESUX && !IsOper(sptr)) { sendto_one(sptr,form_str(RPL_LOAD2HI),me.name,parv[0]); return 0; } /* * Count up all the servers and clients in a downlink. */ if (doall) { for (acptr = GlobalClientList; acptr; acptr = acptr->next) { if (IsServer(acptr)) ++link_s[acptr->from->fd]; } } /* report all direct connections */ now = time(NULL); for (i = 0; i <= highest_fd; i++) { const char* name; const char* ip; int c_class; if (!(acptr = local[i])) /* Local Connection? */ continue; if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsAnOper(sptr)) && !IsAnOper(acptr) && (acptr != sptr)) continue; if (!doall && wilds && !match(tname, acptr->name)) continue; if (!dow && irccmp(tname, acptr->name)) continue; name = get_client_name(acptr, FALSE); ip = inetntoa((const char*) &acptr->ip); c_class = get_client_class(acptr); switch(acptr->status) { case STAT_HANDSHAKE: #ifdef HIDE_SERVERS_IPS name=get_client_name(acptr, MASK_IP); #endif sendto_one(sptr, form_str(RPL_TRACEHANDSHAKE), me.name, parv[0], c_class, name); cnt++; break; case STAT_CONNECTING: #ifdef HIDE_SERVERS_IPS name=get_client_name(acptr, MASK_IP); #endif sendto_one(sptr, form_str(RPL_TRACECONNECTING), me.name, parv[0], c_class, name); cnt++; break; case STAT_ME: break; case STAT_CLIENT: /* Well, most servers don't have a LOT of OPERs... let's show them too */ if ((IsAnOper(sptr) && (MyClient(sptr) || !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr)) { if (IsAnOper(acptr)) sendto_one(sptr, form_str(RPL_TRACEOPERATOR), me.name, parv[0], c_class, name, IsAnOper(sptr)?ip:(IsIPHidden(acptr)?"255.255.255.255":ip), now - acptr->lasttime, (acptr->user)?(now - acptr->user->last):0); cnt++; } break; case STAT_SERVER: #if 0 if (acptr->serv->user) sendto_one(sptr, form_str(RPL_TRACESERVER), me.name, parv[0], c_class, link_s[i], link_u[i], name, acptr->serv->by, acptr->serv->user->username, acptr->serv->user->host, now - acptr->lasttime); else #endif #ifdef HIDE_SERVERS_IPS name=get_client_name(acptr, MASK_IP); #endif sendto_one(sptr, form_str(RPL_TRACESERVER), me.name, parv[0], c_class, link_s[i], link_u[i], name, *(acptr->serv->by) ? acptr->serv->by : "*", "*", me.name, now - acptr->lasttime); cnt++; break; default: /* ...we actually shouldn't come here... --msa */ sendto_one(sptr, form_str(RPL_TRACENEWTYPE), me.name, parv[0], name); cnt++; break; } } /* * Add these lines to summarize the above which can get rather long * and messy when done remotely - Avalon */ if (!IsAnOper(sptr) || !cnt) { if (cnt) return 0; /* let the user have some idea that its at the end of the * trace */ sendto_one(sptr, form_str(RPL_TRACESERVER), me.name, parv[0], 0, link_s[me.fd], link_u[me.fd], me.name, "*", "*", me.name); sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0],tname); return 0; } sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0],tname); return 0; }
static int clicap_cmd_search(const char *command, struct clicap_cmd *entry) { return irccmp(command, entry->cmd); }
/* * mo_rehash - REHASH message handler * */ static void mo_rehash(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { int found = 0; if (!IsOperRehash(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVILEGES), me.name, source_p->name); return; } if (parc > 1) { if (irccmp(parv[1], "DNS") == 0) { sendto_one(source_p, form_str(RPL_REHASHING), me.name, parv[0], "DNS"); sendto_realops_flags(UMODE_ALL, L_ALL, "%s is rehashing DNS", get_oper_name(source_p)); restart_resolver(); /* re-read /etc/resolv.conf AGAIN? and close/re-open res socket */ found = 1; } else if (irccmp(parv[1], "MOTD") == 0) { sendto_realops_flags(UMODE_ALL, L_ALL, "%s is forcing re-reading of MOTD file", get_oper_name(source_p)); read_message_file(&ConfigFileEntry.motd); found = 1; } else if (irccmp(parv[1], "OMOTD") == 0) { sendto_realops_flags(UMODE_ALL, L_ALL, "%s is forcing re-reading of OPER MOTD file", get_oper_name(source_p)); read_message_file(&ConfigFileEntry.opermotd); found = 1; } if (found) { ilog(L_NOTICE, "REHASH %s From %s", parv[1], get_client_name(source_p, HIDE_IP)); return; } else { sendto_one(source_p, ":%s NOTICE %s :rehash one of :DNS MOTD OMOTD", me.name, source_p->name); return; } } else { sendto_one(source_p, form_str(RPL_REHASHING), me.name, source_p->name, ConfigFileEntry.configfile); sendto_realops_flags(UMODE_ALL, L_ALL, "%s is rehashing server config file", get_oper_name(source_p)); ilog(L_NOTICE, "REHASH From %s[%s]", get_oper_name(source_p), source_p->localClient->sockhost); rehash(0); } }