2 * Copyright (C) 2006 Michael Tharp <gxti@partiallystapled.com>
3 * Copyright (C) 2006 charybdis 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.
29 * $Id: m_signon.c 1192 2006-04-21 16:21:02Z jilles $
54 static int me_svslogin(struct Client
*, struct Client
*, int, const char **);
55 static int ms_signon(struct Client
*, struct Client
*, int, const char **);
57 static void send_signon(struct Client
*, struct Client
*, const char *, const char *, const char *, unsigned int, const char *);
59 struct Message svslogin_msgtab
= {
60 "SVSLOGIN", 0, 0, 0, MFLG_SLOW
,
61 {mg_ignore
, mg_ignore
, mg_ignore
, mg_ignore
, {me_svslogin
, 6}, mg_ignore
}
63 struct Message signon_msgtab
= {
64 "SIGNON", 0, 0, 0, MFLG_SLOW
,
65 {mg_ignore
, mg_ignore
, {ms_signon
, 6}, mg_ignore
, mg_ignore
, mg_ignore
}
68 mapi_clist_av1 signon_clist
[] = {
69 &svslogin_msgtab
, &signon_msgtab
, NULL
72 DECLARE_MODULE_AV1(signon
, NULL
, NULL
, signon_clist
, NULL
, NULL
, "$Revision: 1192 $");
79 clean_nick(const char *nick
)
86 /* This is used to check logins, which are often
87 * numeric. Don't check for leading digits, if
88 * services wants to set someone's nick to something
89 * starting with a number, let it try.
96 if(!IsNickChar(*nick
))
108 clean_username(const char *username
)
112 for (; *username
; username
++)
116 if(!IsUserChar(*username
))
127 clean_host(const char *host
)
131 for (; *host
; host
++)
135 if(!IsHostChar(*host
))
146 me_svslogin(struct Client
*client_p
, struct Client
*source_p
,
147 int parc
, const char *parv
[])
149 struct Client
*target_p
, *exist_p
;
150 char nick
[NICKLEN
+1], login
[NICKLEN
+1];
151 char user
[USERLEN
+1], host
[HOSTLEN
+1];
154 if(!(source_p
->flags
& FLAGS_SERVICE
))
156 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
157 "Non-service server %s attempting to execute services-only command SVSLOGIN", source_p
->name
);
161 if((target_p
= find_client(parv
[1])) == NULL
)
164 if(!MyClient(target_p
) && !IsUnknown(target_p
))
167 if(clean_nick(parv
[2]))
169 rb_strlcpy(nick
, parv
[2], NICKLEN
+ 1);
172 else if(*target_p
->name
)
173 rb_strlcpy(nick
, target_p
->name
, NICKLEN
+ 1);
177 if(clean_username(parv
[3]))
179 rb_strlcpy(user
, parv
[3], USERLEN
+ 1);
183 rb_strlcpy(user
, target_p
->username
, USERLEN
+ 1);
185 if(clean_host(parv
[4]))
187 rb_strlcpy(host
, parv
[4], HOSTLEN
+ 1);
191 rb_strlcpy(host
, target_p
->host
, HOSTLEN
+ 1);
196 rb_strlcpy(login
, target_p
->user
->suser
, NICKLEN
+ 1);
200 else if(!strcmp(parv
[5], "0"))
203 rb_strlcpy(login
, parv
[5], NICKLEN
+ 1);
205 /* Login (mostly) follows nick rules. */
206 if(*login
&& !clean_nick(login
))
209 if((exist_p
= find_person(nick
)) && target_p
!= exist_p
)
213 if(MyClient(exist_p
))
214 sendto_one(exist_p
, ":%s KILL %s :(Nickname regained by services)",
215 me
.name
, exist_p
->name
);
217 exist_p
->flags
|= FLAGS_KILLED
;
218 kill_client_serv_butone(NULL
, exist_p
, "%s (Nickname regained by services)",
220 sendto_realops_snomask(SNO_SKILL
, L_ALL
,
221 "Nick collision due to SVSLOGIN on %s",
224 rb_snprintf(buf
, sizeof(buf
), "Killed (%s (Nickname regained by services))",
226 exit_client(NULL
, exist_p
, &me
, buf
);
227 }else if((exist_p
= find_client(nick
)) && IsUnknown(exist_p
) && exist_p
!= target_p
) {
228 exit_client(NULL
, exist_p
, &me
, "Overridden");
233 /* Strip leading digits, unless it's purely numeric. */
234 const char *p
= login
;
240 sendto_one(target_p
, form_str(RPL_LOGGEDIN
), me
.name
, EmptyString(target_p
->name
) ? "*" : target_p
->name
,
241 nick
, user
, host
, p
, p
);
244 sendto_one(target_p
, form_str(RPL_LOGGEDOUT
), me
.name
, EmptyString(target_p
->name
) ? "*" : target_p
->name
,
247 if(IsUnknown(target_p
))
249 struct User
*user_p
= make_user(target_p
);
251 if(valid
& NICK_VALID
)
252 strcpy(target_p
->preClient
->spoofnick
, nick
);
254 if(valid
& USER_VALID
)
255 strcpy(target_p
->preClient
->spoofuser
, user
);
257 if(valid
& HOST_VALID
)
258 strcpy(target_p
->preClient
->spoofhost
, host
);
260 rb_strlcpy(user_p
->suser
, login
, NICKLEN
+ 1);
264 char note
[NICKLEN
+ 10];
266 send_signon(NULL
, target_p
, nick
, user
, host
, rb_current_time(), login
);
268 rb_snprintf(note
, NICKLEN
+ 10, "Nick: %s", target_p
->name
);
269 rb_note(target_p
->localClient
->F
, note
);
276 ms_signon(struct Client
*client_p
, struct Client
*source_p
,
277 int parc
, const char *parv
[])
279 struct Client
*target_p
;
281 char login
[NICKLEN
+1];
283 if(!clean_nick(parv
[1]))
285 ServerStats
.is_kill
++;
286 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
287 "Bad Nick from SIGNON: %s From: %s(via %s)",
288 parv
[1], source_p
->servptr
->name
, client_p
->name
);
289 /* if source_p has an id, kill_client_serv_butone() will
290 * send a kill to client_p, otherwise do it here */
291 if (!has_id(source_p
))
292 sendto_one(client_p
, ":%s KILL %s :%s (Bad nickname from SIGNON)",
293 get_id(&me
, client_p
), parv
[1], me
.name
);
294 kill_client_serv_butone(client_p
, source_p
, "%s (Bad nickname from SIGNON)",
296 source_p
->flags
|= FLAGS_KILLED
;
297 exit_client(NULL
, source_p
, &me
, "Bad nickname from SIGNON");
301 if(!clean_username(parv
[2]) || !clean_host(parv
[3]))
303 ServerStats
.is_kill
++;
304 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
305 "Bad user@host from SIGNON: %s@%s From: %s(via %s)",
306 parv
[2], parv
[3], source_p
->servptr
->name
, client_p
->name
);
307 /* if source_p has an id, kill_client_serv_butone() will
308 * send a kill to client_p, otherwise do it here */
309 if (!has_id(source_p
))
310 sendto_one(client_p
, ":%s KILL %s :%s (Bad user@host from SIGNON)",
311 get_id(&me
, client_p
), parv
[1], me
.name
);
312 kill_client_serv_butone(client_p
, source_p
, "%s (Bad user@host from SIGNON)",
314 source_p
->flags
|= FLAGS_KILLED
;
315 exit_client(NULL
, source_p
, &me
, "Bad user@host from SIGNON");
319 newts
= atol(parv
[4]);
321 if(!strcmp(parv
[5], "0"))
323 else if(*parv
[5] != '*')
325 if (clean_nick(parv
[5]))
326 rb_strlcpy(login
, parv
[5], NICKLEN
+ 1);
331 target_p
= find_named_client(parv
[1]);
332 if(target_p
!= NULL
&& target_p
!= source_p
)
334 /* In case of collision, follow NICK rules. */
335 /* XXX this is duplicated code and does not do SAVE */
336 if(IsUnknown(target_p
))
337 exit_client(NULL
, target_p
, &me
, "Overridden");
340 if(!newts
|| !target_p
->tsinfo
|| (newts
== target_p
->tsinfo
) || !source_p
->user
)
342 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
343 "Nick change collision from SIGNON from %s to %s(%s <- %s)(both killed)",
344 source_p
->name
, target_p
->name
, target_p
->from
->name
,
347 ServerStats
.is_kill
++;
348 sendto_one_numeric(target_p
, ERR_NICKCOLLISION
,
349 form_str(ERR_NICKCOLLISION
), target_p
->name
);
351 kill_client_serv_butone(NULL
, source_p
, "%s (Nick change collision)", me
.name
);
353 ServerStats
.is_kill
++;
355 kill_client_serv_butone(NULL
, target_p
, "%s (Nick change collision)", me
.name
);
357 target_p
->flags
|= FLAGS_KILLED
;
358 exit_client(NULL
, target_p
, &me
, "Nick collision(new)");
359 source_p
->flags
|= FLAGS_KILLED
;
360 exit_client(client_p
, source_p
, &me
, "Nick collision(old)");
365 sameuser
= !irccmp(target_p
->username
, source_p
->username
) &&
366 !irccmp(target_p
->host
, source_p
->host
);
368 if((sameuser
&& newts
< target_p
->tsinfo
) ||
369 (!sameuser
&& newts
> target_p
->tsinfo
))
372 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
373 "Nick change collision from SIGNON from %s to %s(%s <- %s)(older killed)",
374 source_p
->name
, target_p
->name
,
375 target_p
->from
->name
, client_p
->name
);
377 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
378 "Nick change collision from SIGNON from %s to %s(%s <- %s)(newer killed)",
379 source_p
->name
, target_p
->name
,
380 target_p
->from
->name
, client_p
->name
);
382 ServerStats
.is_kill
++;
384 sendto_one_numeric(target_p
, ERR_NICKCOLLISION
,
385 form_str(ERR_NICKCOLLISION
), target_p
->name
);
387 /* kill the client issuing the nickchange */
388 kill_client_serv_butone(client_p
, source_p
,
389 "%s (Nick change collision)", me
.name
);
391 source_p
->flags
|= FLAGS_KILLED
;
394 exit_client(client_p
, source_p
, &me
, "Nick collision(old)");
396 exit_client(client_p
, source_p
, &me
, "Nick collision(new)");
402 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
403 "Nick collision from SIGNON on %s(%s <- %s)(older killed)",
404 target_p
->name
, target_p
->from
->name
,
407 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
408 "Nick collision from SIGNON on %s(%s <- %s)(newer killed)",
409 target_p
->name
, target_p
->from
->name
,
412 sendto_one_numeric(target_p
, ERR_NICKCOLLISION
,
413 form_str(ERR_NICKCOLLISION
), target_p
->name
);
415 /* kill the client who existed before hand */
416 kill_client_serv_butone(client_p
, target_p
,
417 "%s (Nick collision)", me
.name
);
419 ServerStats
.is_kill
++;
421 target_p
->flags
|= FLAGS_KILLED
;
422 (void) exit_client(client_p
, target_p
, &me
, "Nick collision");
429 send_signon(client_p
, source_p
, parv
[1], parv
[2], parv
[3], newts
, login
);
434 send_signon(struct Client
*client_p
, struct Client
*target_p
,
435 const char *nick
, const char *user
, const char *host
,
436 unsigned int newts
, const char *login
)
438 sendto_server(client_p
, NULL
, CAP_TS6
, NOCAPS
, ":%s SIGNON %s %s %s %ld %s",
439 use_id(target_p
), nick
, user
, host
,
440 (long) target_p
->tsinfo
, *login
? login
: "0");
442 strcpy(target_p
->user
->suser
, login
);
444 change_nick_user_host(target_p
, nick
, user
, host
, newts
, "Signing %s (%s)", *login
? "in" : "out", nick
);