1 /* modules/m_services.c
2 * Copyright (C) 2005 Lee Hardy <lee -at- leeh.co.uk>
3 * Copyright (C) 2005 ircd-ratbox development team
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * 1.Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2.Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3.The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
39 #include "s_newconf.h"
47 #include "supported.h"
49 static const char services_desc
[] = "Provides support for running a services daemon";
51 static int _modinit(void);
52 static void _moddeinit(void);
54 static void mark_services(void);
55 static void unmark_services(void);
57 static void me_su(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
58 static void me_login(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
59 static void me_rsfnc(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
60 static void me_nickdelay(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
62 static void h_svc_server_introduced(void *);
63 static void h_svc_whois(void *);
64 static void h_svc_stats(void *);
65 static void h_svc_conf_read_start(void *);
66 static void h_svc_conf_read_end(void *);
68 struct Message su_msgtab
= {
70 {mg_ignore
, mg_ignore
, mg_ignore
, mg_ignore
, {me_su
, 2}, mg_ignore
}
72 struct Message login_msgtab
= {
74 {mg_ignore
, mg_ignore
, mg_ignore
, mg_ignore
, {me_login
, 2}, mg_ignore
}
76 struct Message rsfnc_msgtab
= {
78 {mg_ignore
, mg_ignore
, mg_ignore
, mg_ignore
, {me_rsfnc
, 4}, mg_ignore
}
80 struct Message nickdelay_msgtab
= {
81 "NICKDELAY", 0, 0, 0, 0,
82 {mg_unreg
, mg_ignore
, mg_ignore
, mg_ignore
, {me_nickdelay
, 3}, mg_ignore
}
85 mapi_clist_av1 services_clist
[] = {
86 &su_msgtab
, &login_msgtab
, &rsfnc_msgtab
, &nickdelay_msgtab
, NULL
88 mapi_hfn_list_av1 services_hfnlist
[] = {
89 { "doing_stats", h_svc_stats
},
90 { "doing_whois", h_svc_whois
},
91 { "doing_whois_global", h_svc_whois
},
92 { "server_introduced", h_svc_server_introduced
},
93 { "conf_read_start", h_svc_conf_read_start
},
94 { "conf_read_end", h_svc_conf_read_end
},
98 DECLARE_MODULE_AV2(services
, _modinit
, _moddeinit
, services_clist
, NULL
, services_hfnlist
, NULL
, NULL
, services_desc
);
104 add_isupport("FNC", isupport_string
, "");
111 delete_isupport("FNC");
116 me_su(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
,
117 int parc
, const char *parv
[])
119 struct Client
*target_p
;
121 if(!(source_p
->flags
& FLAGS_SERVICE
))
123 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
124 "Non-service server %s attempting to execute services-only command SU", source_p
->name
);
128 if((target_p
= find_client(parv
[1])) == NULL
)
134 if(EmptyString(parv
[2]))
135 target_p
->user
->suser
[0] = '\0';
137 rb_strlcpy(target_p
->user
->suser
, parv
[2], sizeof(target_p
->user
->suser
));
139 sendto_common_channels_local(target_p
, CLICAP_ACCOUNT_NOTIFY
, NOCAPS
, ":%s!%s@%s ACCOUNT %s",
140 target_p
->name
, target_p
->username
, target_p
->host
,
141 EmptyString(target_p
->user
->suser
) ? "*" : target_p
->user
->suser
);
143 if (MyClient(target_p
))
145 if (EmptyString(target_p
->user
->suser
))
146 sendto_one(target_p
, form_str(RPL_LOGGEDOUT
), me
.name
, target_p
->name
,
147 target_p
->name
, target_p
->username
, target_p
->host
);
149 sendto_one(target_p
, form_str(RPL_LOGGEDIN
), me
.name
, target_p
->name
,
150 target_p
->name
, target_p
->username
, target_p
->host
, parv
[2], parv
[2]);
153 invalidate_bancache_user(target_p
);
157 me_login(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
,
158 int parc
, const char *parv
[])
160 if(!IsPerson(source_p
))
163 rb_strlcpy(source_p
->user
->suser
, parv
[1], sizeof(source_p
->user
->suser
));
167 * parv[1] = current user nickname
168 * parv[2] = target nickname
169 * parv[3] = new nickts
170 * parv[4] = current nickts
171 * parv[5] = optional; 0 (don't override RESVs) or 1 (override RESVs)
174 me_rsfnc(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
,
175 int parc
, const char *parv
[])
177 struct Client
*target_p
;
178 struct Client
*exist_p
;
181 char note
[NAMELEN
+ 10];
183 if(!(source_p
->flags
& FLAGS_SERVICE
))
185 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
186 "Non-service server %s attempting to execute services-only command RSFNC", source_p
->name
);
190 if((target_p
= find_person(parv
[1])) == NULL
)
193 if(!MyClient(target_p
))
196 if(!clean_nick(parv
[2], 0) || IsDigit(parv
[2][0]))
199 curts
= atol(parv
[4]);
201 /* if tsinfo is different from what it was when services issued the
202 * RSFNC, then we ignore it. This can happen when a client changes
203 * nicknames before the RSFNC arrives.. --anfl
205 if(target_p
->tsinfo
!= curts
)
208 /* received a non-forced RSFNC for a nickname that is RESV.
209 * silently ignore it. ~jess
211 if(parc
> 5 && atoi(parv
[5]) == 0 && find_nick_resv(parv
[2]))
214 if((exist_p
= find_named_client(parv
[2])))
218 /* this would be one hell of a race condition to trigger
219 * this one given the tsinfo check above, but its here for
222 if(target_p
== exist_p
)
225 if(MyClient(exist_p
))
226 sendto_one(exist_p
, ":%s KILL %s :(Nickname regained by services)",
227 me
.name
, exist_p
->name
);
229 exist_p
->flags
|= FLAGS_KILLED
;
230 /* Do not send kills to servers for unknowns -- jilles */
231 if(IsClient(exist_p
))
233 kill_client_serv_butone(NULL
, exist_p
, "%s (Nickname regained by services)",
235 sendto_realops_snomask(SNO_SKILL
, L_ALL
,
236 "Nick collision due to services forced nick change on %s",
240 snprintf(buf
, sizeof(buf
), "Killed (%s (Nickname regained by services))",
242 exit_client(NULL
, exist_p
, &me
, buf
);
246 newts
= atol(parv
[3]);
248 /* timestamp is older than 15mins, ignore it */
249 if(newts
< (rb_current_time() - 900))
250 newts
= rb_current_time() - 900;
252 target_p
->tsinfo
= newts
;
254 monitor_signoff(target_p
);
256 invalidate_bancache_user(target_p
);
258 sendto_realops_snomask(SNO_NCHANGE
, L_ALL
,
259 "Nick change: From %s to %s [%s@%s]",
260 target_p
->name
, parv
[2], target_p
->username
,
263 sendto_common_channels_local(target_p
, NOCAPS
, NOCAPS
, ":%s!%s@%s NICK :%s",
264 target_p
->name
, target_p
->username
,
265 target_p
->host
, parv
[2]);
267 whowas_add_history(target_p
, 1);
268 sendto_server(NULL
, NULL
, CAP_TS6
, NOCAPS
, ":%s NICK %s :%ld",
269 use_id(target_p
), parv
[2], (long) target_p
->tsinfo
);
271 del_from_client_hash(target_p
->name
, target_p
);
273 /* invalidate nick delay because we're forcing this nick to be used */
274 nd
= rb_dictionary_retrieve(nd_dict
, parv
[2]);
278 rb_strlcpy(target_p
->name
, parv
[2], NICKLEN
);
279 add_to_client_hash(target_p
->name
, target_p
);
281 monitor_signon(target_p
);
283 del_all_accepts(target_p
);
285 snprintf(note
, sizeof(note
), "Nick: %s", target_p
->name
);
286 rb_note(target_p
->localClient
->F
, note
);
291 ** parv[1] = duration in seconds (0 to remove)
295 me_nickdelay(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
300 if(!(source_p
->flags
& FLAGS_SERVICE
))
302 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
303 "Non-service server %s attempting to execute services-only command NICKDELAY", source_p
->name
);
307 duration
= atoi(parv
[1]);
310 nd
= rb_dictionary_retrieve(nd_dict
, parv
[2]);
316 if (duration
> 86400)
318 add_nd_entry(parv
[2]);
319 nd
= rb_dictionary_retrieve(nd_dict
, parv
[2]);
321 nd
->expire
= rb_current_time() + duration
;
326 h_svc_server_introduced(void *data
)
328 hook_data_client
*hdata
= data
;
331 RB_DLINK_FOREACH(ptr
, service_list
.head
)
333 if(!irccmp((const char *) ptr
->data
, hdata
->target
->name
))
335 hdata
->target
->flags
|= FLAGS_SERVICE
;
342 h_svc_whois(void *data_
)
344 hook_data_client
*data
= data_
;
345 char *p
= data
->target
->user
->suser
;
348 /* Try to strip off any leading digits as this may be used to
349 * store both an ID number and an account name in one field.
350 * If only digits are present, leave as is.
355 p
= data
->target
->user
->suser
;
357 sendto_one_numeric(data
->client
, RPL_WHOISLOGGEDIN
,
358 form_str(RPL_WHOISLOGGEDIN
),
359 data
->target
->name
, p
);
364 h_svc_stats(void *data_
)
366 hook_data_int
*data
= data_
;
367 char statchar
= (char) data
->arg2
;
370 if (statchar
== 'U' && IsOperGeneral(data
->client
))
372 RB_DLINK_FOREACH(ptr
, service_list
.head
)
374 sendto_one_numeric(data
->client
, RPL_STATSULINE
,
375 form_str(RPL_STATSULINE
),
376 (const char *)ptr
->data
, "*", "*", "s");
382 h_svc_conf_read_start(void *dummy
)
388 unmark_services(void)
390 struct Client
*target_p
;
393 RB_DLINK_FOREACH(ptr
, global_serv_list
.head
)
395 target_p
= ptr
->data
;
397 target_p
->flags
&= ~FLAGS_SERVICE
;
402 h_svc_conf_read_end(void *dummy
)
410 struct Client
*target_p
;
413 RB_DLINK_FOREACH(ptr
, service_list
.head
)
415 target_p
= find_server(NULL
, (const char *)ptr
->data
);
418 target_p
->flags
|= FLAGS_SERVICE
;