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