/*! \brief Blindly opers up given source_p, using conf info. * All checks on passwords have already been done. * \param source_p Pointer to given client to oper * \param conf operator {} configuration record */ static void oper_up(struct Client *source_p, const struct MaskItem *conf) { const unsigned int old = source_p->umodes; ++Count.oper; SetOper(source_p); if (conf->modes) AddUMode(source_p, conf->modes); else if (ConfigGeneral.oper_umodes) AddUMode(source_p, ConfigGeneral.oper_umodes); if (!(old & UMODE_INVISIBLE) && HasUMode(source_p, UMODE_INVISIBLE)) ++Count.invisi; else if ((old & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE)) --Count.invisi; assert(dlinkFind(&oper_list, source_p) == NULL); dlinkAdd(source_p, make_dlink_node(), &oper_list); AddOFlag(source_p, conf->port); if (HasOFlag(source_p, OPER_FLAG_ADMIN)) AddUMode(source_p, UMODE_ADMIN); if (!EmptyString(conf->whois)) { svstag_attach(&source_p->svstags, RPL_WHOISOPERATOR, "+", conf->whois); sendto_server(NULL, 0, 0, ":%s SVSTAG %s %ju %u + :%s", me.id, source_p->id, source_p->tsinfo, RPL_WHOISOPERATOR, conf->whois); } ilog(LOG_TYPE_OPER, "OPER %s by %s!%s@%s", conf->name, source_p->name, source_p->username, source_p->host); sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "%s is now an operator", get_oper_name(source_p)); sendto_server(NULL, 0, 0, ":%s GLOBOPS :%s is now an operator", me.id, get_oper_name(source_p)); send_umode_out(source_p, old); sendto_one_numeric(source_p, &me, RPL_YOUREOPER); }
/*! * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * * server introducing new nick/UID (without services support) * - parv[0] = command * - parv[1] = nickname * - parv[2] = hop count * - parv[3] = TS * - parv[4] = umode * - parv[5] = username * - parv[6] = hostname * - parv[7] = ip * - parv[8] = uid * - parv[9] = ircname (gecos) * * server introducing new nick/UID (with services support) * - parv[ 0] = command * - parv[ 1] = nickname * - parv[ 2] = hop count * - parv[ 3] = TS * - parv[ 4] = umode * - parv[ 5] = username * - parv[ 6] = hostname * - parv[ 7] = ip * - parv[ 8] = uid * - parv[ 9] = services account * - parv[10] = ircname (gecos) */ static void uid_from_server(struct Client *source_p, int parc, char *parv[]) { struct Client *client_p = NULL; client_p = make_client(source_p->from); client_p->servptr = source_p; client_p->hopcount = atoi(parv[2]); client_p->tsinfo = atol(parv[3]); strlcpy(client_p->account, (parc == 11 ? parv[9] : "*"), sizeof(client_p->account)); strlcpy(client_p->name, parv[1], sizeof(client_p->name)); strlcpy(client_p->id, parv[8], sizeof(client_p->id)); strlcpy(client_p->sockhost, parv[7], sizeof(client_p->sockhost)); strlcpy(client_p->info, parv[parc - 1], sizeof(client_p->info)); strlcpy(client_p->host, parv[6], sizeof(client_p->host)); strlcpy(client_p->username, parv[5], sizeof(client_p->username)); hash_add_client(client_p); hash_add_id(client_p); /* Parse user modes */ for (const char *m = &parv[4][1]; *m; ++m) { const struct user_modes *tab = umode_map[(unsigned char)*m]; if (!tab) continue; if ((tab->flag & UMODE_INVISIBLE) && !HasUMode(client_p, UMODE_INVISIBLE)) ++Count.invisi; if ((tab->flag & UMODE_OPER) && !HasUMode(client_p, UMODE_OPER)) ++Count.oper; AddUMode(client_p, tab->flag); } register_remote_user(client_p); }
/*! \brief WEBIRC command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = password * - parv[2] = fake username (we ignore this) * - parv[3] = fake hostname * - parv[4] = fake ip */ static int mr_webirc(struct Client *source_p, int parc, char *parv[]) { struct MaskItem *conf = NULL; struct addrinfo hints, *res; assert(MyConnect(source_p)); if (!valid_hostname(parv[3])) { sendto_one_notice(source_p, &me, ":WEBIRC: Invalid hostname"); return 0; } conf = find_address_conf(source_p->host, IsGotId(source_p) ? source_p->username : "******", &source_p->connection->ip, source_p->connection->aftype, parv[1]); if (conf == NULL || !IsConfClient(conf)) return 0; if (!IsConfWebIRC(conf)) { sendto_one_notice(source_p, &me, ":Not a WEBIRC auth {} block"); return 0; } if (EmptyString(conf->passwd)) { sendto_one_notice(source_p, &me, ":WEBIRC auth {} blocks must have a password"); return 0; } if (!match_conf_password(parv[1], conf)) { sendto_one_notice(source_p, &me, ":WEBIRC password incorrect"); return 0; } 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_one_notice(source_p, &me, ":Invalid WEBIRC IP %s", parv[4]); return 0; } assert(res); memcpy(&source_p->connection->ip, res->ai_addr, res->ai_addrlen); source_p->connection->ip.ss_len = res->ai_addrlen; source_p->connection->ip.ss.ss_family = res->ai_family; source_p->connection->aftype = res->ai_family; freeaddrinfo(res); strlcpy(source_p->sockhost, parv[4], sizeof(source_p->sockhost)); strlcpy(source_p->host, parv[3], sizeof(source_p->host)); /* Check dlines now, k-lines will be checked on registration */ if ((conf = find_dline_conf(&source_p->connection->ip, source_p->connection->aftype))) { if (!(conf->type == CONF_EXEMPT)) { exit_client(source_p, "D-lined"); return 0; } } AddUMode(source_p, UMODE_WEBIRC); sendto_one_notice(source_p, &me, ":WEBIRC host/IP set to %s %s", parv[3], parv[4]); return 0; }
/*! \brief SVSMODE command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = nickname * - parv[2] = TS * - parv[3] = mode * - parv[4] = optional argument (services account, vhost) */ static int ms_svsmode(struct Client *source_p, int parc, char *parv[]) { const struct user_modes *tab = NULL; struct Client *target_p = NULL; int what = MODE_ADD; unsigned int setmodes = 0; const char *modes = NULL, *extarg = NULL; time_t ts = 0; if (!HasFlag(source_p, FLAGS_SERVICE)) return 0; ts = atol(parv[2]); modes = parv[3]; extarg = (parc > 4) ? parv[4] : NULL; if ((target_p = find_person(source_p, parv[1])) == NULL) return 0; if (ts && (ts != target_p->tsinfo)) return 0; setmodes = target_p->umodes; for (const char *m = modes; *m; ++m) { switch (*m) { case '+': what = MODE_ADD; break; case '-': what = MODE_DEL; break; case 'd': if (!EmptyString(extarg)) strlcpy(target_p->account, extarg, sizeof(target_p->account)); break; case 'x': if (!EmptyString(extarg) && valid_hostname(extarg)) user_set_hostmask(target_p, extarg, what); break; case 'o': if (what == MODE_DEL && HasUMode(target_p, UMODE_OPER)) { ClearOper(target_p); --Count.oper; if (MyConnect(target_p)) { dlink_node *node = NULL; detach_conf(target_p, CONF_OPER); ClrOFlag(target_p); DelUMode(target_p, ConfigGeneral.oper_only_umodes); if ((node = dlinkFindDelete(&oper_list, target_p))) free_dlink_node(node); } } break; case 'i': if (what == MODE_ADD && !HasUMode(target_p, UMODE_INVISIBLE)) { AddUMode(target_p, UMODE_INVISIBLE); ++Count.invisi; } if (what == MODE_DEL && HasUMode(target_p, UMODE_INVISIBLE)) { DelUMode(target_p, UMODE_INVISIBLE); --Count.invisi; } break; case 'S': /* Only servers may set +S in a burst */ case 'W': /* Only servers may set +W in a burst */ break; default: if ((tab = umode_map[(unsigned char)*m])) { if (what == MODE_ADD) AddUMode(target_p, tab->flag); else DelUMode(target_p, tab->flag); } break; } } if (extarg) sendto_server(source_p, 0, 0, ":%s SVSMODE %s %lu %s %s", source_p->id, target_p->id, (unsigned long)target_p->tsinfo, modes, extarg); else sendto_server(source_p, 0, 0, ":%s SVSMODE %s %lu %s", source_p->id, target_p->id, (unsigned long)target_p->tsinfo, modes); if (MyConnect(target_p) && (setmodes != target_p->umodes)) { char modebuf[IRCD_BUFSIZE] = ""; send_umode(target_p, target_p, setmodes, modebuf); } return 0; }
/*! \brief SVSMODE command handler (called by services) * * \param client_p Pointer to allocated Client struct with physical connection * to this server, i.e. with an open socket connected. * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = sender prefix * - parv[1] = nickname * - parv[2] = TS (or mode, depending on svs version) * - parv[3] = mode (or services id if old svs version) * - parv[4] = optional argument (services id) */ static void ms_svsmode(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; int what = MODE_ADD; unsigned int flag = 0, setflags = 0; char *m = NULL, *modes = NULL, *extarg = NULL; time_t ts = 0; if (!HasFlag(source_p, FLAGS_SERVICE)) return; if ((parc >= 4) && ((*parv[3] == '+') || (*parv[3] == '-'))) { ts = atol(parv[2]); modes = parv[3]; extarg = (parc > 4) ? parv[4] : NULL; } else { modes = parv[2]; extarg = (parc > 3) ? parv[3] : NULL; } if ((target_p = find_person(client_p, parv[1])) == NULL) return; if (ts && (ts != target_p->tsinfo)) return; setflags = target_p->umodes; for (m = modes; *m; ++m) { switch (*m) { case '+': what = MODE_ADD; break; case '-': what = MODE_DEL; break; case 'x': if (what == MODE_ADD && extarg) user_set_hostmask(target_p, extarg); break; case 'd': if (!EmptyString(extarg)) strlcpy(target_p->svid, extarg, sizeof(target_p->svid)); break; case 'o': if (what == MODE_DEL && HasUMode(target_p, UMODE_OPER)) { ClearOper(target_p); Count.oper--; if (MyConnect(target_p)) { dlink_node *dm = NULL; detach_conf(target_p, OPER_TYPE); ClrOFlag(target_p); DelUMode(target_p, ConfigFileEntry.oper_only_umodes); if ((dm = dlinkFindDelete(&oper_list, target_p)) != NULL) free_dlink_node(dm); } } break; case 'i': if (what == MODE_ADD && !HasUMode(target_p, UMODE_INVISIBLE)) { AddUMode(target_p, UMODE_INVISIBLE); ++Count.invisi; } if (what == MODE_DEL && HasUMode(target_p, UMODE_INVISIBLE)) { DelUMode(target_p, UMODE_INVISIBLE); --Count.invisi; } break; case ' ': case '\n': case '\r': case '\t': break; default: if ((flag = user_modes[(unsigned char) * m])) execute_callback(umode_cb, client_p, target_p, what, flag); break; } } if (extarg) { sendto_server(client_p, CAP_TS6, NOCAPS, ":%s SVSMODE %s %lu %s %s", ID(source_p), ID(target_p), (unsigned long)target_p->tsinfo, modes, extarg); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s SVSMODE %s %lu %s %s", source_p->name, target_p->name, (unsigned long)target_p->tsinfo, modes, extarg); } else { sendto_server(client_p, CAP_TS6, NOCAPS, ":%s SVSMODE %s %lu %s", ID(source_p), ID(target_p), (unsigned long)target_p->tsinfo, modes); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s SVSMODE %s %lu %s", source_p->name, target_p->name, (unsigned long)target_p->tsinfo, modes); } if (MyConnect(target_p) && (setflags != target_p->umodes)) { char modebuf[IRCD_BUFSIZE]; send_umode(target_p, target_p, setflags, 0xffffffff, modebuf); } }
/* set_user_mode() * * added 15/10/91 By Darren Reed. * parv[0] - command * parv[1] - username to change mode for * parv[2] - modes to change */ static void set_user_mode(struct Client *source_p, const int parc, char *parv[]) { const struct user_modes *tab = NULL; const unsigned int setmodes = source_p->umodes; const struct Client *target_p = NULL; int what = MODE_ADD, badmode = 0; if ((target_p = find_person(source_p, parv[1])) == NULL) { if (MyConnect(source_p)) sendto_one_numeric(source_p, &me, ERR_NOSUCHCHANNEL, parv[1]); return; } if (source_p != target_p) { sendto_one_numeric(source_p, &me, ERR_USERSDONTMATCH); return; } if (parc < 3) { char buf[IRCD_BUFSIZE] = ""; char *m = buf; *m++ = '+'; for (tab = umode_tab; tab->c; ++tab) if (HasUMode(source_p, tab->flag)) *m++ = tab->c; *m = '\0'; sendto_one_numeric(source_p, &me, RPL_UMODEIS, buf); return; } /* Parse user mode change string */ for (const char *m = parv[2]; *m; ++m) { switch (*m) { case '+': what = MODE_ADD; break; case '-': what = MODE_DEL; break; case 'o': if (what == MODE_ADD) { if (!MyConnect(source_p) && !HasUMode(source_p, UMODE_OPER)) { ++Count.oper; SetOper(source_p); } } else { if (!HasUMode(source_p, UMODE_OPER)) break; ClearOper(source_p); --Count.oper; if (MyConnect(source_p)) { dlink_node *node = NULL; detach_conf(source_p, CONF_OPER); ClrOFlag(source_p); DelUMode(source_p, ConfigGeneral.oper_only_umodes); if ((node = dlinkFindDelete(&oper_list, source_p))) free_dlink_node(node); } } break; case 'S': /* Only servers may set +S in a burst */ case 'W': /* Only servers may set +W in a burst */ case 'r': /* Only services may set +r */ case 'x': /* Only services may set +x */ break; default: if ((tab = umode_map[(unsigned char)*m])) { if (MyConnect(source_p) && !HasUMode(source_p, UMODE_OPER) && (ConfigGeneral.oper_only_umodes & tab->flag)) badmode = 1; else { if (what == MODE_ADD) AddUMode(source_p, tab->flag); else DelUMode(source_p, tab->flag); } } else if (MyConnect(source_p)) badmode = 1; break; } } if (badmode) sendto_one_numeric(source_p, &me, ERR_UMODEUNKNOWNFLAG); if (MyConnect(source_p) && HasUMode(source_p, UMODE_ADMIN) && !HasOFlag(source_p, OPER_FLAG_ADMIN)) { sendto_one_notice(source_p, &me, ":*** You have no admin flag;"); DelUMode(source_p, UMODE_ADMIN); } if (!(setmodes & UMODE_INVISIBLE) && HasUMode(source_p, UMODE_INVISIBLE)) ++Count.invisi; if ((setmodes & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE)) --Count.invisi; /* * Compare new modes with old modes and send string which will cause * servers to update correctly. */ send_umode_out(source_p, setmodes); }