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