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