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