]> jfr.im git - solanum.git/blame - modules/m_signon.c
Can IGNORE_BOGUS_TS at the behest of @kaniini and @jilest
[solanum.git] / modules / m_signon.c
CommitLineData
212380e3
AC
1/* modules/m_signon.c
2 * Copyright (C) 2006 Michael Tharp <gxti@partiallystapled.com>
3 * Copyright (C) 2006 charybdis development team
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
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.
16 *
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.
212380e3
AC
28 */
29
30#include "stdinc.h"
31
212380e3
AC
32#include "send.h"
33#include "channel.h"
34#include "client.h"
35#include "common.h"
36#include "config.h"
37#include "ircd.h"
38#include "numeric.h"
212380e3
AC
39#include "s_conf.h"
40#include "s_serv.h"
41#include "hash.h"
42#include "msg.h"
43#include "parse.h"
44#include "modules.h"
212380e3
AC
45#include "whowas.h"
46#include "monitor.h"
47#include "s_stats.h"
48#include "snomask.h"
4562c604 49#include "match.h"
212380e3
AC
50#include "s_user.h"
51
eeabf33a
EM
52static const char signon_desc[] = "Provides account login/logout support for services";
53
3c7d6fcc
EM
54static void me_svslogin(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
55static void ms_signon(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
212380e3
AC
56
57static void send_signon(struct Client *, struct Client *, const char *, const char *, const char *, unsigned int, const char *);
58
59struct Message svslogin_msgtab = {
7baa37a9 60 "SVSLOGIN", 0, 0, 0, 0,
212380e3
AC
61 {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_svslogin, 6}, mg_ignore}
62};
63struct Message signon_msgtab = {
7baa37a9 64 "SIGNON", 0, 0, 0, 0,
212380e3
AC
65 {mg_ignore, mg_ignore, {ms_signon, 6}, mg_ignore, mg_ignore, mg_ignore}
66};
67
55abcbb2 68mapi_clist_av1 signon_clist[] = {
212380e3
AC
69 &svslogin_msgtab, &signon_msgtab, NULL
70};
71
3abc337f 72DECLARE_MODULE_AV2(signon, NULL, NULL, signon_clist, NULL, NULL, NULL, NULL, signon_desc);
212380e3
AC
73
74#define NICK_VALID 1
75#define USER_VALID 2
76#define HOST_VALID 4
77
3c7d6fcc 78static bool
212380e3
AC
79clean_username(const char *username)
80{
81 int len = 0;
82
83 for (; *username; username++)
84 {
85 len++;
86
87 if(!IsUserChar(*username))
3c7d6fcc 88 return false;
212380e3
AC
89 }
90
91 if(len > USERLEN)
3c7d6fcc 92 return false;
212380e3 93
3c7d6fcc 94 return true;
212380e3
AC
95}
96
3c7d6fcc 97static bool
212380e3
AC
98clean_host(const char *host)
99{
100 int len = 0;
101
102 for (; *host; host++)
103 {
104 len++;
105
106 if(!IsHostChar(*host))
3c7d6fcc 107 return false;
212380e3
AC
108 }
109
110 if(len > HOSTLEN)
3c7d6fcc 111 return false;
212380e3 112
3c7d6fcc 113 return true;
212380e3
AC
114}
115
3c7d6fcc 116static void
428ca87b 117me_svslogin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
212380e3
AC
118 int parc, const char *parv[])
119{
120 struct Client *target_p, *exist_p;
121 char nick[NICKLEN+1], login[NICKLEN+1];
122 char user[USERLEN+1], host[HOSTLEN+1];
123 int valid = 0;
124
125 if(!(source_p->flags & FLAGS_SERVICE))
ec57fe67
KB
126 {
127 sendto_realops_snomask(SNO_GENERAL, L_ALL,
128 "Non-service server %s attempting to execute services-only command SVSLOGIN", source_p->name);
3c7d6fcc 129 return;
ec57fe67 130 }
212380e3
AC
131
132 if((target_p = find_client(parv[1])) == NULL)
3c7d6fcc 133 return;
212380e3
AC
134
135 if(!MyClient(target_p) && !IsUnknown(target_p))
3c7d6fcc 136 return;
212380e3 137
2d28539c 138 if(clean_nick(parv[2], 0))
212380e3 139 {
f427c8b0 140 rb_strlcpy(nick, parv[2], NICKLEN + 1);
212380e3
AC
141 valid |= NICK_VALID;
142 }
143 else if(*target_p->name)
f427c8b0 144 rb_strlcpy(nick, target_p->name, NICKLEN + 1);
212380e3
AC
145 else
146 strcpy(nick, "*");
147
148 if(clean_username(parv[3]))
149 {
f427c8b0 150 rb_strlcpy(user, parv[3], USERLEN + 1);
212380e3
AC
151 valid |= USER_VALID;
152 }
153 else
f427c8b0 154 rb_strlcpy(user, target_p->username, USERLEN + 1);
212380e3
AC
155
156 if(clean_host(parv[4]))
157 {
f427c8b0 158 rb_strlcpy(host, parv[4], HOSTLEN + 1);
212380e3
AC
159 valid |= HOST_VALID;
160 }
161 else
f427c8b0 162 rb_strlcpy(host, target_p->host, HOSTLEN + 1);
212380e3
AC
163
164 if(*parv[5] == '*')
165 {
166 if(target_p->user)
f427c8b0 167 rb_strlcpy(login, target_p->user->suser, NICKLEN + 1);
212380e3
AC
168 else
169 login[0] = '\0';
170 }
171 else if(!strcmp(parv[5], "0"))
172 login[0] = '\0';
173 else
f427c8b0 174 rb_strlcpy(login, parv[5], NICKLEN + 1);
212380e3
AC
175
176 /* Login (mostly) follows nick rules. */
2d28539c 177 if(*login && !clean_nick(login, 0))
3c7d6fcc 178 return;
212380e3
AC
179
180 if((exist_p = find_person(nick)) && target_p != exist_p)
181 {
182 char buf[BUFSIZE];
183
184 if(MyClient(exist_p))
185 sendto_one(exist_p, ":%s KILL %s :(Nickname regained by services)",
186 me.name, exist_p->name);
187
188 exist_p->flags |= FLAGS_KILLED;
189 kill_client_serv_butone(NULL, exist_p, "%s (Nickname regained by services)",
190 me.name);
45ed8835
JT
191 sendto_realops_snomask(SNO_SKILL, L_ALL,
192 "Nick collision due to SVSLOGIN on %s",
193 nick);
212380e3 194
5203cba5 195 snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))",
212380e3
AC
196 me.name);
197 exit_client(NULL, exist_p, &me, buf);
3c7d6fcc
EM
198 }
199 else if((exist_p = find_client(nick)) && IsUnknown(exist_p) && exist_p != target_p)
200 {
212380e3
AC
201 exit_client(NULL, exist_p, &me, "Overridden");
202 }
203
204 if(*login)
205 {
206 /* Strip leading digits, unless it's purely numeric. */
207 const char *p = login;
208 while(IsDigit(*p))
209 p++;
210 if(!*p)
211 p = login;
212
213 sendto_one(target_p, form_str(RPL_LOGGEDIN), me.name, EmptyString(target_p->name) ? "*" : target_p->name,
214 nick, user, host, p, p);
215 }
216 else
217 sendto_one(target_p, form_str(RPL_LOGGEDOUT), me.name, EmptyString(target_p->name) ? "*" : target_p->name,
218 nick, user, host);
219
220 if(IsUnknown(target_p))
221 {
222 struct User *user_p = make_user(target_p);
223
224 if(valid & NICK_VALID)
225 strcpy(target_p->preClient->spoofnick, nick);
226
227 if(valid & USER_VALID)
228 strcpy(target_p->preClient->spoofuser, user);
229
230 if(valid & HOST_VALID)
231 strcpy(target_p->preClient->spoofhost, host);
232
f427c8b0 233 rb_strlcpy(user_p->suser, login, NICKLEN + 1);
212380e3
AC
234 }
235 else
236 {
cf9a6b75
AC
237 char note[NICKLEN + 10];
238
e3354945 239 send_signon(NULL, target_p, nick, user, host, rb_current_time(), login);
cf9a6b75 240
5203cba5 241 snprintf(note, NICKLEN + 10, "Nick: %s", target_p->name);
cf9a6b75 242 rb_note(target_p->localClient->F, note);
212380e3 243 }
212380e3
AC
244}
245
3c7d6fcc 246static void
428ca87b 247ms_signon(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
212380e3
AC
248 int parc, const char *parv[])
249{
250 struct Client *target_p;
251 int newts, sameuser;
252 char login[NICKLEN+1];
253
2d28539c 254 if(!clean_nick(parv[1], 0))
212380e3 255 {
47adde3d 256 ServerStats.is_kill++;
212380e3
AC
257 sendto_realops_snomask(SNO_DEBUG, L_ALL,
258 "Bad Nick from SIGNON: %s From: %s(via %s)",
259 parv[1], source_p->servptr->name, client_p->name);
260 /* if source_p has an id, kill_client_serv_butone() will
261 * send a kill to client_p, otherwise do it here */
262 if (!has_id(source_p))
263 sendto_one(client_p, ":%s KILL %s :%s (Bad nickname from SIGNON)",
264 get_id(&me, client_p), parv[1], me.name);
265 kill_client_serv_butone(client_p, source_p, "%s (Bad nickname from SIGNON)",
266 me.name);
267 source_p->flags |= FLAGS_KILLED;
268 exit_client(NULL, source_p, &me, "Bad nickname from SIGNON");
3c7d6fcc 269 return;
212380e3
AC
270 }
271
272 if(!clean_username(parv[2]) || !clean_host(parv[3]))
273 {
47adde3d 274 ServerStats.is_kill++;
212380e3
AC
275 sendto_realops_snomask(SNO_DEBUG, L_ALL,
276 "Bad user@host from SIGNON: %s@%s From: %s(via %s)",
277 parv[2], parv[3], source_p->servptr->name, client_p->name);
278 /* if source_p has an id, kill_client_serv_butone() will
279 * send a kill to client_p, otherwise do it here */
280 if (!has_id(source_p))
281 sendto_one(client_p, ":%s KILL %s :%s (Bad user@host from SIGNON)",
282 get_id(&me, client_p), parv[1], me.name);
283 kill_client_serv_butone(client_p, source_p, "%s (Bad user@host from SIGNON)",
284 me.name);
285 source_p->flags |= FLAGS_KILLED;
286 exit_client(NULL, source_p, &me, "Bad user@host from SIGNON");
3c7d6fcc 287 return;
212380e3
AC
288 }
289
290 newts = atol(parv[4]);
291
292 if(!strcmp(parv[5], "0"))
293 login[0] = '\0';
294 else if(*parv[5] != '*')
295 {
2d28539c 296 if (clean_nick(parv[5], 0))
f427c8b0 297 rb_strlcpy(login, parv[5], NICKLEN + 1);
212380e3 298 else
3c7d6fcc 299 return;
212380e3 300 }
299e25a6
JT
301 else
302 login[0] = '\0';
212380e3
AC
303
304 target_p = find_named_client(parv[1]);
305 if(target_p != NULL && target_p != source_p)
306 {
307 /* In case of collision, follow NICK rules. */
308 /* XXX this is duplicated code and does not do SAVE */
309 if(IsUnknown(target_p))
310 exit_client(NULL, target_p, &me, "Overridden");
311 else
312 {
313 if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) || !source_p->user)
314 {
315 sendto_realops_snomask(SNO_GENERAL, L_ALL,
316 "Nick change collision from SIGNON from %s to %s(%s <- %s)(both killed)",
317 source_p->name, target_p->name, target_p->from->name,
318 client_p->name);
55abcbb2 319
47adde3d 320 ServerStats.is_kill++;
212380e3
AC
321 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
322 form_str(ERR_NICKCOLLISION), target_p->name);
55abcbb2 323
212380e3 324 kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name);
55abcbb2 325
47adde3d 326 ServerStats.is_kill++;
55abcbb2 327
212380e3 328 kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name);
55abcbb2 329
212380e3
AC
330 target_p->flags |= FLAGS_KILLED;
331 exit_client(NULL, target_p, &me, "Nick collision(new)");
332 source_p->flags |= FLAGS_KILLED;
333 exit_client(client_p, source_p, &me, "Nick collision(old)");
3c7d6fcc 334 return;
212380e3
AC
335 }
336 else
337 {
338 sameuser = !irccmp(target_p->username, source_p->username) &&
339 !irccmp(target_p->host, source_p->host);
55abcbb2 340
212380e3
AC
341 if((sameuser && newts < target_p->tsinfo) ||
342 (!sameuser && newts > target_p->tsinfo))
343 {
344 if(sameuser)
345 sendto_realops_snomask(SNO_GENERAL, L_ALL,
346 "Nick change collision from SIGNON from %s to %s(%s <- %s)(older killed)",
347 source_p->name, target_p->name,
348 target_p->from->name, client_p->name);
349 else
350 sendto_realops_snomask(SNO_GENERAL, L_ALL,
351 "Nick change collision from SIGNON from %s to %s(%s <- %s)(newer killed)",
352 source_p->name, target_p->name,
353 target_p->from->name, client_p->name);
55abcbb2 354
47adde3d 355 ServerStats.is_kill++;
55abcbb2 356
212380e3
AC
357 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
358 form_str(ERR_NICKCOLLISION), target_p->name);
55abcbb2 359
212380e3
AC
360 /* kill the client issuing the nickchange */
361 kill_client_serv_butone(client_p, source_p,
362 "%s (Nick change collision)", me.name);
55abcbb2 363
212380e3 364 source_p->flags |= FLAGS_KILLED;
55abcbb2 365
212380e3
AC
366 if(sameuser)
367 exit_client(client_p, source_p, &me, "Nick collision(old)");
368 else
369 exit_client(client_p, source_p, &me, "Nick collision(new)");
3c7d6fcc 370 return;
212380e3
AC
371 }
372 else
373 {
374 if(sameuser)
375 sendto_realops_snomask(SNO_GENERAL, L_ALL,
376 "Nick collision from SIGNON on %s(%s <- %s)(older killed)",
377 target_p->name, target_p->from->name,
378 client_p->name);
379 else
380 sendto_realops_snomask(SNO_GENERAL, L_ALL,
381 "Nick collision from SIGNON on %s(%s <- %s)(newer killed)",
382 target_p->name, target_p->from->name,
383 client_p->name);
55abcbb2 384
212380e3
AC
385 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
386 form_str(ERR_NICKCOLLISION), target_p->name);
55abcbb2 387
212380e3 388 /* kill the client who existed before hand */
55abcbb2 389 kill_client_serv_butone(client_p, target_p,
212380e3 390 "%s (Nick collision)", me.name);
55abcbb2 391
47adde3d 392 ServerStats.is_kill++;
55abcbb2 393
212380e3
AC
394 target_p->flags |= FLAGS_KILLED;
395 (void) exit_client(client_p, target_p, &me, "Nick collision");
396 }
397 }
55abcbb2 398
212380e3
AC
399 }
400 }
401
402 send_signon(client_p, source_p, parv[1], parv[2], parv[3], newts, login);
212380e3
AC
403}
404
405static void
406send_signon(struct Client *client_p, struct Client *target_p,
407 const char *nick, const char *user, const char *host,
408 unsigned int newts, const char *login)
409{
410 sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s SIGNON %s %s %s %ld %s",
411 use_id(target_p), nick, user, host,
412 (long) target_p->tsinfo, *login ? login : "0");
212380e3
AC
413
414 strcpy(target_p->user->suser, login);
415
416 change_nick_user_host(target_p, nick, user, host, newts, "Signing %s (%s)", *login ? "in" : "out", nick);
417}