Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/VibeDevelopers/Comet.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439/* modules/m_services.c * Copyright (C) 2005 Lee Hardy <lee -at- leeh.co.uk> * Copyright (C) 2005 ircd-ratbox development team * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1.Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2.Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3.The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */
#include "stdinc.h"
#include "send.h"#include "channel.h"#include "client.h"#include "defaults.h"#include "ircd.h"#include "numeric.h"#include "s_conf.h"#include "s_newconf.h"#include "s_serv.h"#include "hash.h"#include "msg.h"#include "parse.h"#include "modules.h"#include "whowas.h"#include "monitor.h"#include "supported.h"
static int h_account_change;static const char services_desc[] = "Provides support for running a services daemon";
static int _modinit(void);static void _moddeinit(void);
static void mark_services(void);static void unmark_services(void);
static void me_su(struct MsgBuf *, struct Client *, struct Client *, int, const char **);static void me_login(struct MsgBuf *, struct Client *, struct Client *, int, const char **);static void me_rsfnc(struct MsgBuf *, struct Client *, struct Client *, int, const char **);static void me_nickdelay(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
static void h_svc_server_introduced(void *);static void h_svc_whois(void *);static void h_svc_stats(void *);static void h_svc_conf_read_start(void *);static void h_svc_conf_read_end(void *);
struct Message su_msgtab = { "SU", 0, 0, 0, 0, {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_su, 2}, mg_ignore}};struct Message login_msgtab = { "LOGIN", 0, 0, 0, 0, {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_login, 2}, mg_ignore}};struct Message rsfnc_msgtab = { "RSFNC", 0, 0, 0, 0, {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_rsfnc, 4}, mg_ignore}};struct Message nickdelay_msgtab = { "NICKDELAY", 0, 0, 0, 0, {mg_unreg, mg_ignore, mg_ignore, mg_ignore, {me_nickdelay, 3}, mg_ignore}};
mapi_clist_av1 services_clist[] = { &su_msgtab, &login_msgtab, &rsfnc_msgtab, &nickdelay_msgtab, NULL};
mapi_hlist_av1 services_hlist[] = { { "account_change", &h_account_change }, { NULL, NULL }};
mapi_hfn_list_av1 services_hfnlist[] = { { "doing_stats", h_svc_stats }, { "doing_whois", h_svc_whois }, { "doing_whois_global", h_svc_whois }, { "server_introduced", h_svc_server_introduced }, { "conf_read_start", h_svc_conf_read_start }, { "conf_read_end", h_svc_conf_read_end }, { NULL, NULL }};
DECLARE_MODULE_AV2(services, _modinit, _moddeinit, services_clist, services_hlist, services_hfnlist, NULL, NULL, services_desc);
static int_modinit(void){ add_isupport("FNC", isupport_string, ""); return 0;}
static void_moddeinit(void){ delete_isupport("FNC"); unmark_services();}
static voidme_su(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]){ struct Client *target_p; char old_suser[NICKLEN + 1] = { 0 };
if(!(source_p->flags & FLAGS_SERVICE)) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "Non-service server %s attempting to execute services-only command SU", source_p->name); return; }
if((target_p = find_client(parv[1])) == NULL) return;
if(!target_p->user) return;
rb_strlcpy(old_suser, target_p->user->suser, sizeof(old_suser));
if(EmptyString(parv[2])) target_p->user->suser[0] = '\0'; else rb_strlcpy(target_p->user->suser, parv[2], sizeof(target_p->user->suser));
sendto_common_channels_local(target_p, CLICAP_ACCOUNT_NOTIFY, NOCAPS, ":%s!%s@%s ACCOUNT %s", target_p->name, target_p->username, target_p->host, EmptyString(target_p->user->suser) ? "*" : target_p->user->suser);
if (MyClient(target_p)) { if (EmptyString(target_p->user->suser)) sendto_one(target_p, form_str(RPL_LOGGEDOUT), me.name, target_p->name, target_p->name, target_p->username, target_p->host); else sendto_one(target_p, form_str(RPL_LOGGEDIN), me.name, target_p->name, target_p->name, target_p->username, target_p->host, parv[2], parv[2]); }
invalidate_bancache_user(target_p); hook_cdata hdata = { target_p, old_suser, NULL }; call_hook(h_account_change, &hdata);}
static voidme_login(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]){ char old_suser[NICKLEN + 1] = { 0 }; if(!IsPerson(source_p)) return;
rb_strlcpy(old_suser, source_p->user->suser, sizeof(old_suser)); rb_strlcpy(source_p->user->suser, parv[1], sizeof(source_p->user->suser)); hook_cdata hdata = { source_p, old_suser, NULL }; call_hook(h_account_change, &hdata);}
/* me_rsfnc() * parv[1] = current user nickname * parv[2] = target nickname * parv[3] = new nickts * parv[4] = current nickts * parv[5] = optional; 0 (don't override RESVs) or 1 (override RESVs) */static voidme_rsfnc(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]){ struct Client *target_p; struct Client *exist_p; time_t newts, curts; struct nd_entry *nd; char note[NAMELEN + 10];
if(!(source_p->flags & FLAGS_SERVICE)) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "Non-service server %s attempting to execute services-only command RSFNC", source_p->name); return; }
if((target_p = find_person(parv[1])) == NULL) return;
if(!MyClient(target_p)) return;
if(!clean_nick(parv[2], 0) || IsDigit(parv[2][0])) return;
curts = atol(parv[4]);
/* if tsinfo is different from what it was when services issued the * RSFNC, then we ignore it. This can happen when a client changes * nicknames before the RSFNC arrives.. --anfl */ if(target_p->tsinfo != curts) return;
/* received a non-forced RSFNC for a nickname that is RESV. * silently ignore it. ~jess */ if(parc > 5 && atoi(parv[5]) == 0 && find_nick_resv(parv[2])) return;
if((exist_p = find_named_client(parv[2]))) { char buf[BUFSIZE];
/* this would be one hell of a race condition to trigger * this one given the tsinfo check above, but its here for * safety --anfl */ if(target_p == exist_p) goto doit;
if(MyClient(exist_p)) sendto_one(exist_p, ":%s KILL %s :(Nickname regained by services)", me.name, exist_p->name);
exist_p->flags |= FLAGS_KILLED; /* Do not send kills to servers for unknowns -- jilles */ if(IsClient(exist_p)) { kill_client_serv_butone(NULL, exist_p, "%s (Nickname regained by services)", me.name); sendto_realops_snomask(SNO_SKILL, L_ALL, "Nick collision due to services forced nick change on %s", parv[2]); }
snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))", me.name); exit_client(NULL, exist_p, &me, buf); }
doit: newts = atol(parv[3]);
/* timestamp is older than 15mins, ignore it */ if(newts < (rb_current_time() - 900)) newts = rb_current_time() - 900;
target_p->tsinfo = newts;
monitor_signoff(target_p);
invalidate_bancache_user(target_p);
sendto_realops_snomask(SNO_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]", target_p->name, parv[2], target_p->username, target_p->host);
sendto_common_channels_local(target_p, NOCAPS, NOCAPS, ":%s!%s@%s NICK :%s", target_p->name, target_p->username, target_p->host, parv[2]);
whowas_add_history(target_p, 1); sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld", use_id(target_p), parv[2], (long) target_p->tsinfo);
del_from_client_hash(target_p->name, target_p);
/* invalidate nick delay because we're forcing this nick to be used */ nd = rb_dictionary_retrieve(nd_dict, parv[2]); if (nd != NULL) free_nd_entry(nd);
rb_strlcpy(target_p->name, parv[2], NICKLEN); add_to_client_hash(target_p->name, target_p);
monitor_signon(target_p);
/* Make sure everyone that has this client on its accept list * loses that reference. */ del_all_accepts(target_p, false);
snprintf(note, sizeof(note), "Nick: %s", target_p->name); rb_note(target_p->localClient->F, note);}
/*** me_nickdelay** parv[1] = duration in seconds (0 to remove)** parv[2] = nick*/static voidme_nickdelay(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]){ int duration; struct nd_entry *nd;
if(!(source_p->flags & FLAGS_SERVICE)) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "Non-service server %s attempting to execute services-only command NICKDELAY", source_p->name); return; }
duration = atoi(parv[1]); if (duration <= 0) { nd = rb_dictionary_retrieve(nd_dict, parv[2]); if (nd != NULL) free_nd_entry(nd); } else { if (duration > 86400) duration = 86400; add_nd_entry(parv[2]); nd = rb_dictionary_retrieve(nd_dict, parv[2]); if (nd != NULL) nd->expire = rb_current_time() + duration; }}
static voidh_svc_server_introduced(void *data){ hook_data_client *hdata = data; rb_dlink_node *ptr;
RB_DLINK_FOREACH(ptr, service_list.head) { if(!irccmp((const char *) ptr->data, hdata->target->name)) { hdata->target->flags |= FLAGS_SERVICE; return; } }}
static voidh_svc_whois(void *data_){ hook_data_client *data = data_; char *p = data->target->user->suser; if(!EmptyString(p)) { /* Try to strip off any leading digits as this may be used to * store both an ID number and an account name in one field. * If only digits are present, leave as is. */ while(IsDigit(*p)) p++; if(*p == '\0') p = data->target->user->suser;
sendto_one_numeric(data->client, RPL_WHOISLOGGEDIN, form_str(RPL_WHOISLOGGEDIN), data->target->name, p); }}
static voidh_svc_stats(void *data_){ hook_data_int *data = data_; char statchar = (char) data->arg2; rb_dlink_node *ptr;
if (statchar == 'U' && IsOperGeneral(data->client)) { RB_DLINK_FOREACH(ptr, service_list.head) { sendto_one_numeric(data->client, RPL_STATSULINE, form_str(RPL_STATSULINE), (const char *)ptr->data, "*", "*", "s"); } }}
static voidh_svc_conf_read_start(void *dummy){ unmark_services();}
static voidunmark_services(void){ struct Client *target_p; rb_dlink_node *ptr;
RB_DLINK_FOREACH(ptr, global_serv_list.head) { target_p = ptr->data;
target_p->flags &= ~FLAGS_SERVICE; }}
static voidh_svc_conf_read_end(void *dummy){ mark_services();}
static voidmark_services(void){ struct Client *target_p; rb_dlink_node *ptr;
RB_DLINK_FOREACH(ptr, service_list.head) { target_p = find_server(NULL, (const char *)ptr->data);
if (target_p) target_p->flags |= FLAGS_SERVICE; }}