void relay_private_notice(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; assert(0 != sptr); assert(0 != name); assert(0 != text); if (0 == (acptr = FindUser(name))) return; if (IsOnlyreg(acptr) && !IsRegnick(sptr)) { send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); return; } if (!IsChannelService(acptr)) { if (check_target_limit(sptr, acptr, cli_name(acptr), 0)) { return; } if (is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } } /* * deliver the message */ if (MyUser(acptr)) add_target(acptr, sptr); sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text); }
/** Send a jupe (or a list of jupes) to a server. * @param[in] sptr Client searching for jupes. * @param[in] server Name of jupe to search for (if NULL, list all). * @return Zero. */ int jupe_list(struct Client *sptr, char *server) { struct Jupe *jupe; struct Jupe *sjupe; if (server) { if (!(jupe = jupe_find(server))) /* no such jupe */ return send_reply(sptr, ERR_NOSUCHJUPE, server); /* send jupe information along */ send_reply(sptr, RPL_JUPELIST, jupe->ju_server, jupe->ju_expire + TSoffset, JupeIsLocal(jupe) ? cli_name(&me) : "*", JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason); } else { for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */ sjupe = jupe->ju_next; if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */ jupe_free(jupe); else /* send jupe information along */ send_reply(sptr, RPL_JUPELIST, jupe->ju_server, jupe->ju_expire + TSoffset, JupeIsLocal(jupe) ? cli_name(&me) : "*", JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason); } } /* end of jupe information */ return send_reply(sptr, RPL_ENDOFJUPELIST); }
void server_relay_private_message(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; assert(0 != sptr); assert(0 != name); assert(0 != text); /* * nickname addressed? */ if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) { send_reply(sptr, SND_EXPLICIT | ERR_NOSUCHNICK, "* :Target left %s. " "Failed to deliver: [%.20s]", feature_str(FEAT_NETWORK), text); return; } if (!IsChannelService(sptr) && is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } if (IsOnlyreg(acptr) && !IsRegnick(sptr)) { send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); return; } if (MyUser(acptr)) add_target(acptr, sptr); sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text); }
/* * mr_pong - registration message handler * * parv[0] = sender prefix * parv[1] = pong response echo * NOTE: cptr is always unregistered here */ int mr_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { assert(0 != cptr); assert(cptr == sptr); assert(!IsRegistered(sptr)); ClrFlag(cptr, FLAG_PINGSENT); cli_lasttime(cptr) = CurrentTime; /* * Check to see if this is a PONG :cookie reply from an * unregistered user. If so, process it. -record */ if (0 != cli_cookie(sptr) && COOKIE_VERIFIED != cli_cookie(sptr)) { if (parc > 1 && cli_cookie(sptr) == atol(parv[parc - 1])) { cli_cookie(sptr) = COOKIE_VERIFIED; if (cli_user(sptr) && *(cli_user(sptr))->host && (cli_name(sptr))[0]) /* * NICK and USER OK */ return register_user(cptr, sptr, cli_name(sptr), cli_user(sptr)->username); } else send_reply(sptr, SND_EXPLICIT | ERR_BADPING, ":To connect, type /QUOTE PONG %u", cli_cookie(sptr)); } return 0; }
void server_relay_private_notice(struct Client* sptr, const char* name, const char* text) { struct Client* acptr; assert(0 != sptr); assert(0 != name); assert(0 != text); /* * nickname addressed? */ if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) return; if (!IsChannelService(sptr) && is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } if (IsOnlyreg(acptr) && !IsRegnick(sptr)) { send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); return; } if (MyUser(acptr)) add_target(acptr, sptr); sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text); }
/* * mo_asll - oper message handler */ int mo_asll(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *mask; struct Client *acptr; int hits; int i; if (parc < 2) return need_more_params(sptr, "ASLL"); if (parc == 2 && MyUser(sptr)) parv[parc++] = cli_name(&me); if (hunt_server_prio_cmd(sptr, CMD_ASLL, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME) return 0; mask = parv[1]; for (i = hits = 0; i <= HighestFd; i++) { acptr = LocalClientArray[i]; if (!acptr || !IsServer(acptr) || !MyConnect(acptr) || match(mask, cli_name(acptr))) continue; send_asll_reply(&me, sptr, cli_name(acptr), cli_serv(acptr)->asll_rtt, cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from); hits++; } sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :AsLL for %s: %d local servers matched", sptr, mask, hits); return 0; }
/* * ms_links - server message handler * * parv[0] = sender prefix * parv[1] = servername mask * * or * * parv[0] = sender prefix * parv[1] = server to query * parv[2] = servername mask */ int ms_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *mask; struct Client *acptr; if (parc > 2) { if (hunt_server_cmd(sptr, CMD_LINKS, cptr, 1, "%C :%s", 1, parc, parv) != HUNTED_ISME) return 0; mask = parv[2]; } else mask = parc < 2 ? 0 : parv[1]; for (acptr = GlobalClientList, collapse(mask); acptr; acptr = cli_next(acptr)) { if (!IsServer(acptr) && !IsMe(acptr)) continue; if (!BadPtr(mask) && match(mask, cli_name(acptr))) continue; send_reply(sptr, RPL_LINKS, cli_name(acptr), cli_name(cli_serv(acptr)->up), cli_hopcount(acptr), cli_serv(acptr)->prot, ((cli_info(acptr))[0] ? cli_info(acptr) : "(Unknown Location)")); } send_reply(sptr, RPL_ENDOFLINKS, BadPtr(mask) ? "*" : mask); return 0; }
/** Display one or all Z-lines to a user. * If \a ipmask is not NULL, only send the first matching Z-line. * Otherwise send the whole list. * @param[in] sptr User asking for Z-line list. * @param[in] ipmask Z-line mask to search for (or NULL). * @return Zero. */ int zline_list(struct Client *sptr, char *ipmask) { struct Zline *zline; struct Zline *szline; if (ipmask) { if (!(zline = zline_find(ipmask, ZLINE_ANY))) /* no such zline */ return send_reply(sptr, ERR_NOSUCHZLINE, ipmask); /* send zline information along */ send_reply(sptr, RPL_ZLIST, zline->zl_mask, zline->zl_expire, zline->zl_lastmod, zline->zl_lifetime, ZlineIsLocal(zline) ? cli_name(&me) : "*", zline->zl_state == ZLOCAL_ACTIVATED ? ">" : (zline->zl_state == ZLOCAL_DEACTIVATED ? "<" : ""), ZlineIsRemActive(zline) ? '+' : '-', zline->zl_reason); } else { zliter(GlobalZlineList, zline, szline) { send_reply(sptr, RPL_ZLIST, zline->zl_mask, zline->zl_expire, zline->zl_lastmod, zline->zl_lifetime, ZlineIsLocal(zline) ? cli_name(&me) : "*", zline->zl_state == ZLOCAL_ACTIVATED ? ">" : (zline->zl_state == ZLOCAL_DEACTIVATED ? "<" : ""), ZlineIsRemActive(zline) ? '+' : '-', zline->zl_reason); } }
/** Handle a SILENCE command from a local user. * See @ref m_functions for general discussion of parameters. * * \a parv[1] may be any of the following: * \li Omitted or empty, to view your own silence list. * \li Nickname of a user, to view that user's silence list. * \li A comma-separated list of silence updates * * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int m_silence(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; struct Ban *sile; assert(0 != cptr); assert(cptr == sptr); /* See if the user is requesting a silence list. */ acptr = sptr; if (parc < 2 || EmptyString(parv[1]) || (acptr = FindUser(parv[1]))) { if (cli_user(acptr)) { for (sile = cli_user(acptr)->silence; sile; sile = sile->next) { send_reply(sptr, RPL_SILELIST, cli_name(acptr), (sile->flags & BAN_EXCEPTION ? "~" : ""), sile->banstr); } } send_reply(sptr, RPL_ENDOFSILELIST, cli_name(acptr)); return 0; } /* The user must be attempting to update their list. */ forward_silences(sptr, parv[1], NULL); return 0; }
/* * mo_version - oper message handler * * parv[0] = sender prefix * parv[1] = servername */ int mo_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; if (MyConnect(sptr) && parc > 1) { if (!(acptr = find_match_server(parv[1]))) { send_reply(sptr, ERR_NOSUCHSERVER, parv[1]); return 0; } parv[1] = cli_name(acptr); } if (hunt_server_cmd(sptr, CMD_VERSION, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", 1, parc, parv) == HUNTED_ISME) { send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me), debug_serveropts()); send_supported(sptr); } return 0; }
/** Complete non-blocking connect()-sequence. Check access and * terminate connection, if trouble detected. * @param cptr Client to which we have connected, with all ConfItem structs attached. * @return Zero on failure (caller should exit_client()), non-zero on success. */ static int completed_connection(struct Client* cptr) { struct ConfItem *aconf; time_t newts; struct Client *acptr; int i; assert(0 != cptr); /* * get the socket status from the fd first to check if * connection actually succeeded */ if ((cli_error(cptr) = os_get_sockerr(cli_fd(cptr)))) { const char* msg = strerror(cli_error(cptr)); if (!msg) msg = "Unknown error"; sendto_opmask_butone(0, SNO_OLDSNO, "Connection failed to %s: %s", cli_name(cptr), msg); return 0; } if (!(aconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_SERVER))) { sendto_opmask_butone(0, SNO_OLDSNO, "Lost Server Line for %s", cli_name(cptr)); return 0; } if (s_state(&(cli_socket(cptr))) == SS_CONNECTING) socket_state(&(cli_socket(cptr)), SS_CONNECTED); if (!EmptyString(aconf->passwd)) sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd); /* * Create a unique timestamp */ newts = TStime(); for (i = HighestFd; i > -1; --i) { if ((acptr = LocalClientArray[i]) && (IsServer(acptr) || IsHandshake(acptr))) { if (cli_serv(acptr)->timestamp >= newts) newts = cli_serv(acptr)->timestamp + 1; } } assert(0 != cli_serv(cptr)); cli_serv(cptr)->timestamp = newts; SetHandshake(cptr); /* * Make us timeout after twice the timeout for DNS look ups */ cli_lasttime(cptr) = CurrentTime; ClearPingSent(cptr); sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s6n :%s", cli_name(&me), cli_serv(&me)->timestamp, newts, MAJOR_PROTOCOL, NumServCap(&me), feature_bool(FEAT_HUB) ? "h" : "", cli_info(&me)); return (IsDead(cptr)) ? 0 : 1; }
int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[], u64 valid, u32 flags) { int type; int rc = 0; ENTRY; if ((valid & (OBD_MD_FLALLQUOTA)) == 0) RETURN(0); for (type = 0; type < LL_MAXQUOTAS; type++) { struct osc_quota_info *oqi; if ((valid & md_quota_flag(type)) == 0) continue; /* lookup the ID in the per-type hash table */ oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]); if ((flags & fl_quota_flag(type)) != 0) { /* This ID is getting close to its quota limit, let's * switch to sync I/O */ if (oqi != NULL) continue; oqi = osc_oqi_alloc(qid[type]); if (oqi == NULL) { rc = -ENOMEM; break; } rc = cfs_hash_add_unique(cli->cl_quota_hash[type], &qid[type], &oqi->oqi_hash); /* race with others? */ if (rc == -EALREADY) { rc = 0; OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem); } CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d (%d)\n", cli_name(cli), qtype_name(type), qid[type], rc); } else { /* This ID is now off the hook, let's remove it from * the hash table */ if (oqi == NULL) continue; oqi = cfs_hash_del_key(cli->cl_quota_hash[type], &qid[type]); if (oqi) OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem); CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d (%p)\n", cli_name(cli), qtype_name(type), qid[type], oqi); } } RETURN(rc); }
/** Send a server map to a client. * @param[in] cptr Client to who to send the map. * @param[in] server Top-level server to display. * @param[in] mask Mask to filter which servers are shown. * @param[in] prompt_length Number of characters used in prompt. */ static void dump_map(struct Client *cptr, struct Client *server, char *mask, int prompt_length) { const char *chr; static char prompt[64]; struct DLink *lp; char *p = prompt + prompt_length; int cnt = 0; *p = '\0'; if (prompt_length > 60) send_reply(cptr, RPL_MAPMORE, prompt, cli_name(server)); else { char lag[512]; if (cli_serv(server)->lag>10000) lag[0]=0; else if (cli_serv(server)->lag<0) strcpy(lag,"(0s)"); else sprintf(lag,"(%is)",cli_serv(server)->lag); if (IsBurst(server)) chr = "*"; else if (IsBurstAck(server)) chr = "!"; else chr = ""; send_reply(cptr, RPL_MAP, prompt, chr, cli_name(server), lag, (server == &me) ? UserStats.local_clients : cli_serv(server)->clients); } if (prompt_length > 0) { p[-1] = ' '; if (p[-2] == '`') p[-2] = ' '; } if (prompt_length > 60) return; strcpy(p, "|-"); for (lp = cli_serv(server)->down; lp; lp = lp->next) if (match(mask, cli_name(lp->value.cptr))) ClrFlag(lp->value.cptr, FLAG_MAP); else { SetFlag(lp->value.cptr, FLAG_MAP); cnt++; } for (lp = cli_serv(server)->down; lp; lp = lp->next) { if (!HasFlag(lp->value.cptr, FLAG_MAP)) continue; if (--cnt == 0) *p = '`'; dump_map(cptr, lp->value.cptr, mask, prompt_length + 2); } if (prompt_length > 0) p[-1] = '-'; }
/* * do_kill - Performs the generic work involved in killing a client * */ static int do_kill(struct Client* cptr, struct Client* sptr, struct Client* victim, char* inpath, char* path, char* msg) { assert(0 != cptr); assert(0 != sptr); assert(!IsServer(victim)); /* * Notify all *local* opers about the KILL (this includes the one * originating the kill, if from this server--the special numeric * reply message is not generated anymore). * * Note: "victim->name" is used instead of "user" because we may * have changed the target because of the nickname change. */ sendto_opmask_butone(0, IsServer(sptr) ? SNO_SERVKILL : SNO_OPERKILL, "Received KILL message for %s. From %s Path: %s!%s %s", get_client_name(victim, SHOW_IP), cli_name(sptr), inpath, path, msg); log_write_kill(victim, sptr, inpath, path, msg); /* * And pass on the message to other servers. Note, that if KILL * was changed, the message has to be sent to all links, also * back. * Client suicide kills are NOT passed on --SRB */ if (IsServer(cptr) || !MyConnect(victim)) { sendcmdto_serv_butone(sptr, CMD_KILL, cptr, "%C :%s!%s %s", victim, inpath, path, msg); /* * Set FLAG_KILLED. This prevents exit_one_client from sending * the unnecessary QUIT for this. (This flag should never be * set in any other place) */ SetFlag(victim, FLAG_KILLED); } /* * Tell the victim she/he has been zapped, but *only* if * the victim is on current server--no sense in sending the * notification chasing the above kill, it won't get far * anyway (as this user don't exist there any more either) * In accordance with the new hiding rules, the victim * always sees the kill as coming from me. */ if (MyConnect(victim)) sendcmdto_one(feature_bool(FEAT_HIS_KILLWHO) ? &me : sptr, CMD_KILL, victim, "%C :%s %s", victim, feature_bool(FEAT_HIS_KILLWHO) ? feature_str(FEAT_HIS_SERVERNAME) : cli_name(sptr), msg); return exit_client_msg(cptr, victim, feature_bool(FEAT_HIS_KILLWHO) ? &me : sptr, "Killed (%s %s)", feature_bool(FEAT_HIS_KILLWHO) ? feature_str(FEAT_HIS_SERVERNAME) : cli_name(sptr), msg); }
/** Deactivate a Z-line. * @param[in] cptr Peer that gave us the message. * @param[in] sptr Client that initiated the deactivation. * @param[in] zline Z-line to deactivate. * @param[in] lastmod New value for Z-line last modification timestamp. * @param[in] flags ZLINE_LOCAL to only deactivate locally, 0 to propagate. * @return Zero. */ int zline_deactivate(struct Client *cptr, struct Client *sptr, struct Zline *zline, time_t lastmod, unsigned int flags) { unsigned int saveflags = 0; char *msg; assert(0 != zline); saveflags = zline->zl_flags; if (ZlineIsLocal(zline)) msg = "removing local"; else if (!zline->zl_lastmod && !(flags & ZLINE_LOCAL)) { msg = "removing global"; zline->zl_flags &= ~ZLINE_ACTIVE; /* propagate a -<mask> */ } else { msg = "deactivating global"; if (flags & ZLINE_LOCAL) zline->zl_flags |= ZLINE_LDEACT; else { zline->zl_flags &= ~ZLINE_ACTIVE; if (zline->zl_lastmod) { if (zline->zl_lastmod >= lastmod) zline->zl_lastmod++; else zline->zl_lastmod = lastmod; } } if ((saveflags & ZLINE_ACTMASK) != ZLINE_ACTIVE) return 0; /* was inactive to begin with */ } /* Inform ops and log it */ sendto_opmask_butone(0, SNO_GLINE, "%s %s ZLINE for %s, expiring at %Tu: " "%s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? cli_name(sptr) : cli_name((cli_user(sptr))->server), msg, zline->zl_mask, zline->zl_expire, zline->zl_reason); log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, "%#C %s ZLINE for %s, expiring at %Tu: %s", sptr, msg, zline->zl_mask, zline->zl_expire, zline->zl_reason); if (!(flags & ZLINE_LOCAL)) /* don't propagate local changes */ zline_propagate(cptr, sptr, zline); /* if it's a local zline or a Uworld zline (and not locally deactivated).. */ if (ZlineIsLocal(zline) || (!zline->zl_lastmod && !(flags & ZLINE_LOCAL))) zline_free(zline); /* get rid of it */ return 0; }
/* * m_version - generic message handler * * parv[0] = sender prefix * parv[1] = servername */ int m_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (parc > 1 && match(parv[1], cli_name(&me))) return send_reply(sptr, ERR_NOPRIVILEGES); send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me), debug_serveropts()); send_supported(sptr); return 0; }
/** Return the name of the client for various tracking and admin * purposes. The main purpose of this function is to return the * "socket host" name of the client, if that differs from the * advertised name (other than case). But, this can be used on any * client structure. * @param sptr Client to operate on. * @param showip If non-zero, append [username\@text-ip] to name. * @return Either cli_name(\a sptr) or a static buffer. */ const char* get_client_name(const struct Client* sptr, int showip) { static char nbuf[HOSTLEN * 2 + USERLEN + 5]; if (!MyConnect(sptr) || !showip) return cli_name(sptr); ircd_snprintf(0, nbuf, sizeof(nbuf), "%s[%s@%s]", cli_name(sptr), IsIdented(sptr) ? cli_username(sptr) : "", cli_sock_ip(sptr)); return nbuf; }
/* * mo_kill - oper message handler * * NOTE: IsPrivileged(sptr), IsAnOper(sptr) == true * IsServer(cptr), IsServer(sptr) == false * * parv[0] = sender prefix * parv[1] = kill victim * parv[parc-1] = kill path */ int mo_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* victim; char* user; char msg[TOPICLEN + 3]; /* (, ), and \0 */ assert(0 != cptr); assert(0 != sptr); /* * oper connection to this server, cptr is always sptr */ assert(cptr == sptr); assert(IsAnOper(sptr)); if (parc < 3 || EmptyString(parv[parc - 1])) return need_more_params(sptr, "KILL"); user = parv[1]; ircd_snprintf(0, msg, sizeof(msg), "(%.*s)", TOPICLEN, parv[parc - 1]); if (!(victim = FindClient(user))) { /* * If the user has recently changed nick, we automaticly * rewrite the KILL for this new nickname--this keeps * servers in synch when nick change and kill collide */ if (!(victim = get_history(user, (long)15))) return send_reply(sptr, ERR_NOSUCHNICK, user); sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Changed KILL %s into %s", sptr, user, cli_name(victim)); } if (!HasPriv(sptr, MyConnect(victim) ? PRIV_LOCAL_KILL : PRIV_KILL)) return send_reply(sptr, ERR_NOPRIVILEGES); if (IsServer(victim) || IsMe(victim)) { return send_reply(sptr, ERR_CANTKILLSERVER); } /* * if the user is +k, prevent a kill from local user */ if (IsChannelService(victim)) return send_reply(sptr, ERR_ISCHANSERVICE, "KILL", cli_name(victim)); if (!MyConnect(victim) && !HasPriv(sptr, PRIV_KILL)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Nick %s isnt on your server", sptr, cli_name(victim)); return 0; } return do_kill(cptr, sptr, victim, cli_user(sptr)->host, cli_name(sptr), msg); }
int ms_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { int flag = 0; if ((parc > 2) && (hunt_server_cmd(sptr, CMD_REHASH, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME)) return 0; /* OK, the message has been forwarded, but before we can act... */ if (!feature_bool(FEAT_NETWORK_REHASH)) return 0; if (parc > 1) { /* special processing */ if (parv[1][1] == '\0') { /* one character server name */ if (*parv[1] == 'm') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Flushing MOTD cache"); motd_recache(); /* flush MOTD cache */ return 0; } else if (*parv[1] == 'l') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reopening log files"); log_reopen(); /* reopen log files */ return 0; } else if (*parv[1] == 'a') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Restarting IAuth"); auth_restart(); /* Restart IAuth program */ return 0; #ifdef USE_SSL } else if (*parv[1] == 's') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reloading SSL certificates"); ssl_reinit(); return 0; #endif } else if (*parv[1] == 'q') flag = 2; } /* * Maybe the user wants to rehash another server with no parameters. * NOTE: Here we assume that there are no servers named * 'm', 'l', 's', or 'q'. */ else if ((parc == 2) && (hunt_server_cmd(sptr, CMD_REHASH, cptr, 1, "%C", 1, parc, parv) != HUNTED_ISME)) return 0; } send_reply(sptr, RPL_REHASHING, configfile); sendto_opmask_butone(0, SNO_OLDSNO, "%C [%s] is remotely rehashing Server config file", sptr, cli_name(cli_user(sptr)->server)); log_write(LS_SYSTEM, L_INFO, 0, "Remote REHASH From %#C [%s]", sptr, cli_name(cli_user(sptr)->server)); return rehash(cptr, flag); }
/** Send the content of a MotdCache to a user. * If \a cache is NULL, simply send ERR_NOOMOTD to the client. * @param[in] cptr Client to send MOTD to. * @param[in] cache MOTD body to send to client. */ static int motd_forward_type(struct Client *cptr, int type) { int i; struct MotdCache *cache = NULL; assert(0 != cptr); if (type == MOTD_OPER) cache = motd_cache(MotdList.oper); else if (type == MOTD_RULES) cache = motd_cache(MotdList.rules); if (!cache) {/* no motd to send */ if (type == MOTD_OPER) return send_reply(cptr, ERR_NOOMOTD); else if (type == MOTD_RULES) return send_reply(cptr, ERR_NORULES); else return send_reply(cptr, ERR_NOMOTD); } if (type == MOTD_OPER) { /* send the motd */ send_reply(cptr, RPL_OMOTDSTART, cli_name(&me)); send_reply(cptr, SND_EXPLICIT | RPL_OMOTD, ":- %d-%d-%d %d:%02d", cache->modtime.tm_year + 1900, cache->modtime.tm_mon + 1, cache->modtime.tm_mday, cache->modtime.tm_hour, cache->modtime.tm_min); for (i = 0; i < cache->count; i++) send_reply(cptr, RPL_OMOTD, cache->motd[i]); return send_reply(cptr, RPL_ENDOFOMOTD); /* end */ } else if (type == MOTD_RULES) { /* send the motd */ send_reply(cptr, RPL_RULESSTART, cli_name(&me)); send_reply(cptr, SND_EXPLICIT | RPL_RULES, ":- %d-%d-%d %d:%02d", cache->modtime.tm_year + 1900, cache->modtime.tm_mon + 1, cache->modtime.tm_mday, cache->modtime.tm_hour, cache->modtime.tm_min); for (i = 0; i < cache->count; i++) send_reply(cptr, RPL_RULES, cache->motd[i]); return send_reply(cptr, RPL_ENDOFRULES); /* end */ }else { return send_reply(cptr, ERR_NOMOTD); } }
/** Deactivate a jupe. * @param[in] cptr Local client that sent us the jupe. * @param[in] sptr Originator of the jupe. * @param[in] jupe Jupe to deactivate. * @param[in] lastmod New timestamp for last modification of the jupe. * @param[in] flags Flags to set on the jupe. * @return Zero. */ int jupe_deactivate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe, time_t lastmod, unsigned int flags) { unsigned int saveflags = 0; assert(0 != jupe); saveflags = jupe->ju_flags; if (!JupeIsLocal(jupe)) { if (flags & JUPE_LOCAL) jupe->ju_flags |= JUPE_LDEACT; else { jupe->ju_flags &= ~JUPE_ACTIVE; if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */ jupe->ju_lastmod++; else jupe->ju_lastmod = lastmod; } if ((saveflags & JUPE_ACTMASK) != JUPE_ACTIVE) return 0; /* was inactive to begin with */ } /* Inform ops and log it */ sendto_opmask_butone(0, SNO_NETWORK, "%s %s JUPE for %s, expiring at %Tu: " "%s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? cli_name(sptr) : cli_name((cli_user(sptr))->server), JupeIsLocal(jupe) ? "removing local" : "deactivating", jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason); log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, "%#C %s JUPE for %s, expiring at %Tu: %s", sptr, JupeIsLocal(jupe) ? "removing local" : "deactivating", jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason); if (JupeIsLocal(jupe)) jupe_free(jupe); else if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */ propagate_jupe(cptr, sptr, jupe); return 0; }
void start_auth(struct Client* client) { struct AuthRequest* auth = 0; assert(0 != client); if (conf_check_slines(client)) { sendheader(client, REPORT_USING_SLINE); SetSLined(client); release_auth_client(client); return; } auth = make_auth_request(client); assert(0 != auth); Debug((DEBUG_INFO, "Beginning auth request on client %p", client)); if (!feature_bool(FEAT_NODNS)) { if (LOOPBACK == inet_netof(cli_ip(client))) strcpy(cli_sockhost(client), cli_name(&me)); else { struct DNSQuery query; query.vptr = auth; query.callback = auth_dns_callback; if (IsUserPort(auth->client)) sendheader(client, REPORT_DO_DNS); cli_dns_reply(client) = gethost_byaddr((const char*) &(cli_ip(client)), &query); if (cli_dns_reply(client)) { ++(cli_dns_reply(client))->ref_count; ircd_strncpy(cli_sockhost(client), cli_dns_reply(client)->hp->h_name, HOSTLEN); if (IsUserPort(auth->client)) sendheader(client, REPORT_FIN_DNSC); Debug((DEBUG_LIST, "DNS entry for %p was cached", auth->client)); } else SetDNSPending(auth); } } if (start_auth_query(auth)) { Debug((DEBUG_LIST, "identd query for %p initiated successfully", auth->client)); link_auth_request(auth, &AuthPollList); } else if (IsDNSPending(auth)) { Debug((DEBUG_LIST, "identd query for %p not initiated successfully; " "waiting on DNS", auth->client)); link_auth_request(auth, &AuthIncompleteList); } else { Debug((DEBUG_LIST, "identd query for %p not initiated successfully; " "no DNS pending; releasing immediately", auth->client)); free_auth_request(auth); release_auth_client(client); } }
/* * mr_error - unregistered client message handler * * parv[0] = sender prefix * parv[parc-1] = text */ int mr_error(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const char *para; if (!IsHandshake(cptr) && !IsConnecting(cptr)) return 0; /* ignore ERROR from regular clients */ para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>"; Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", cli_name(sptr), para)); if (cptr == sptr) sendto_opmask_butone(0, SNO_OLDSNO, "ERROR :from %C -- %s", cptr, para); else sendto_opmask_butone(0, SNO_OLDSNO, "ERROR :from %C via %C -- %s", sptr, cptr, para); if (cli_serv(sptr)) { MyFree(cli_serv(sptr)->last_error_msg); DupString(cli_serv(sptr)->last_error_msg, para); } return 0; }
/** Set a channel topic or report an error. * @param[in] sptr Original topic setter. * @param[in] cptr Neighbor that sent the topic message. * @param[in] chptr Channel to set topic on. * @param[in] topic New topic. * @param[in] ts Timestamp that topic was set (0 for current time). */ static void do_settopic(struct Client *sptr, struct Client *cptr, struct Channel *chptr, char *topic, time_t ts) { struct Client *from; int newtopic; if (feature_bool(FEAT_HIS_BANWHO) && IsServer(sptr)) from = &his; else from = sptr; /* Note if this is just a refresh of an old topic, and don't * send it to all the clients to save bandwidth. We still send * it to other servers as they may have split and lost the topic. */ newtopic=ircd_strncmp(chptr->topic,topic,TOPICLEN)!=0; /* setting a topic */ ircd_strncpy(chptr->topic, topic, TOPICLEN); ircd_strncpy(chptr->topic_nick, cli_name(from), NICKLEN); chptr->topic_time = ts ? ts : TStime(); /* Fixed in 2.10.11: Don't propagate local topics */ if (!IsLocalChannel(chptr->chname)) sendcmdto_serv(sptr, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr, chptr->creationtime, chptr->topic_time, chptr->topic); if (newtopic) sendcmdto_channel(from, CMD_TOPIC, chptr, NULL, SKIP_SERVERS, "%H :%s", chptr, chptr->topic); /* if this is the same topic as before we send it to the person that * set it (so they knew it went through ok), but don't bother sending * it to everyone else on the channel to save bandwidth */ else if (MyUser(sptr)) sendcmdto_one(sptr, CMD_TOPIC, sptr, "%H :%s", chptr, chptr->topic); }
/** Send a server notice to all users with the indicated \a mode except * for \a one. * @param[in] one Client direction to skip (or NULL). * @param[in] mode One mode character. * @param[in] pattern Format string for server notice. * @param[in] vl Argument list for format string. */ void vsendto_mode_butone(struct Client *one, struct Client *from, const char *mode, const char *pattern, va_list vl) { struct VarData vd; struct MsgBuf *mb; struct Client* acptr = 0; vd.vd_format = pattern; va_copy(vd.vd_args, vl); /* send to local users */ mb = msgq_make(0, ":%s " MSG_NOTICE " * :*** Notice -- %v", cli_name(from), &vd); for (acptr = &me; acptr; acptr = cli_prev(acptr)) { if (IsUser(acptr)) { switch (*mode) { case 'O': if (IsLocOp(acptr)) send_buffer(acptr, mb, 0); break; case 'o': if (IsOper(acptr)) send_buffer(acptr, mb, 0); break; default: break; /* ignore, should only happen if incorrectly injected via raw */ } } } msgq_clean(mb); }
/** Send a server notice to all users subscribing to the indicated \a * mask except for \a one. * @param[in] one Client direction to skip (or NULL). * @param[in] mask One of the SNO_* constants. * @param[in] pattern Format string for server notice. * @param[in] vl Argument list for format string. */ void vsendto_opmask_butone(struct Client *from, struct Client *one, unsigned int mask, const char *pattern, va_list vl) { struct VarData vd; struct MsgBuf *mb; int i = 0; /* so that 1 points to opsarray[0] */ struct SLink *opslist; while ((mask >>= 1)) i++; if (!(opslist = opsarray[i])) return; /* * build string; I don't want to bother with client nicknames, so I hope * this is ok... */ vd.vd_format = pattern; va_copy(vd.vd_args, vl); mb = msgq_make(0, ":%s " MSG_NOTICE " * :*** Notice -- %v", cli_name(from), &vd); for (; opslist; opslist = opslist->next) if (opslist->value.cptr != one) send_buffer(opslist->value.cptr, mb, 0); msgq_clean(mb); }
void failed_challenge_notice(struct Client *sptr, char *name, char *reason) { sendto_allops(&me, SNO_OLDREALOP, "Failed CHALLENGE attempt as %s " "by %s (%s@%s) - %s", name, cli_name(sptr), cli_user(sptr)->realusername, cli_user(sptr)->host, reason); }
/** * Removes all clients and downlinks (+clients) of any server * QUITs are generated and sent to local users. * @param cptr server that must have all dependents removed * @param sptr source who thought that this was a good idea * @param comment comment sent as sign off message to local clients */ static void exit_downlinks(struct Client *cptr, struct Client *sptr, char *comment) { struct Client *acptr; struct DLink *next; struct DLink *lp; struct Client **acptrp; int i; /* Run over all its downlinks */ for (lp = cli_serv(cptr)->down; lp; lp = next) { next = lp->next; acptr = lp->value.cptr; /* Remove the downlinks and client of the downlink */ exit_downlinks(acptr, sptr, comment); /* Remove the downlink itself */ exit_one_client(acptr, cli_name(&me)); } /* Remove all clients of this server */ acptrp = cli_serv(cptr)->client_list; for (i = 0; i <= cli_serv(cptr)->nn_mask; ++acptrp, ++i) { if (*acptrp) exit_one_client(*acptrp, comment); } }
void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text) { struct Client* acptr; char* host; assert(0 != sptr); assert(0 != name); assert(0 != text); assert(0 != server); if (0 == (acptr = FindServer(server + 1))) return; /* * NICK[%host]@server addressed? See if <server> is me first */ if (!IsMe(acptr)) { sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text); return; } /* * Look for an user whose NICK is equal to <name> and then * check if it's hostname matches <host> and if it's a local * user. */ *server = '\0'; if ((host = strchr(name, '%'))) *host++ = '\0'; if (!(acptr = FindUser(name)) || !MyUser(acptr) || (!EmptyString(host) && 0 != match(host, cli_user(acptr)->realhost))) return; *server = '@'; if (host) *--host = '%'; if (!IsChannelService(sptr) && is_silenced(sptr, acptr)) { send_reply(sptr, ERR_SILENCED, cli_name(acptr)); return; } if (IsOnlyreg(acptr) && !IsRegnick(sptr)) send_reply(sptr, RPL_MSGONLYREG, cli_name(acptr)); else sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text); }
/* * mo_squit (oper) * * parv[0] = sender prefix * parv[1] = server name * parv[2] = comment (optional) * */ int mo_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const char* server; struct Client *acptr; struct Client *acptr2; char *comment; if (parc < 2) return need_more_params(sptr, "SQUIT"); if (parc < 3 || BadPtr(parv[2])) comment = cli_name(sptr); else comment = parv[2]; server = parv[1]; /* * The following allows wild cards in SQUIT. Only useful * when the command is issued by an oper. */ for (acptr = GlobalClientList; (acptr = next_client(acptr, server)); acptr = cli_next(acptr)) { if (IsServer(acptr) || IsMe(acptr)) break; } /* Not found? Bugger. */ if (!acptr || IsMe(acptr)) return send_reply(sptr, ERR_NOSUCHSERVER, server); /* * Look for a matching server that is closer, * that way we won't accidentally squit two close * servers like davis.* and davis-r.* when typing * /SQUIT davis* */ for (acptr2 = cli_serv(acptr)->up; acptr2 != &me; acptr2 = cli_serv(acptr2)->up) if (!match(server, cli_name(acptr2))) acptr = acptr2; /* Disallow local opers to squit remote servers */ if (IsLocOp(sptr) && !MyConnect(acptr)) return send_reply(sptr, ERR_NOPRIVILEGES); return exit_client(cptr, acptr, sptr, comment); }