ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_server.c
Revision: 7007
Committed: Fri Jan 1 00:09:08 2016 UTC (8 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 27373 byte(s)
Log Message:
- Update copyright years

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2016 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file m_server.c
23 * \brief Includes required functions for processing the SERVER/SID command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "client.h"
30 #include "event.h"
31 #include "hash.h"
32 #include "id.h"
33 #include "irc_string.h"
34 #include "ircd.h"
35 #include "numeric.h"
36 #include "conf.h"
37 #include "log.h"
38 #include "misc.h"
39 #include "server.h"
40 #include "user.h"
41 #include "send.h"
42 #include "parse.h"
43 #include "memory.h"
44 #include "modules.h"
45
46
47 /*
48 * send_tb
49 *
50 * inputs - pointer to Client
51 * - pointer to channel
52 * output - NONE
53 * side effects - Called on a server burst when
54 * server is CAPAB_TBURST capable
55 */
56 static void
57 send_tb(struct Client *client_p, const struct Channel *chptr)
58 {
59 /*
60 * We may also send an empty topic here, but only if topic_time isn't 0,
61 * i.e. if we had a topic that got unset. This is required for syncing
62 * topics properly.
63 *
64 * Imagine the following scenario: Our downlink introduces a channel
65 * to us with a TS that is equal to ours, but the channel topic on
66 * their side got unset while the servers were in splitmode, which means
67 * their 'topic' is newer. They simply wanted to unset it, so we have to
68 * deal with it in a more sophisticated fashion instead of just resetting
69 * it to their old topic they had before. Read m_tburst.c:ms_tburst
70 * for further information -Michael
71 */
72 if (chptr->topic_time)
73 sendto_one(client_p, ":%s TBURST %ju %s %ju %s :%s", me.id,
74 chptr->creationtime, chptr->name,
75 chptr->topic_time,
76 chptr->topic_info,
77 chptr->topic);
78 }
79
80 /* sendnick_TS()
81 *
82 * inputs - client (server) to send nick towards
83 * - client to send nick for
84 * output - NONE
85 * side effects - NICK message is sent towards given client_p
86 */
87 static void
88 sendnick_TS(struct Client *client_p, struct Client *target_p)
89 {
90 dlink_node *node = NULL;
91 char ubuf[IRCD_BUFSIZE] = "";
92
93 if (!IsClient(target_p))
94 return;
95
96 send_umode(NULL, target_p, 0, ubuf);
97
98 if (ubuf[0] == '\0')
99 {
100 ubuf[0] = '+';
101 ubuf[1] = '\0';
102 }
103
104 sendto_one(client_p, ":%s UID %s %u %ju %s %s %s %s %s %s :%s",
105 target_p->servptr->id,
106 target_p->name, target_p->hopcount + 1,
107 target_p->tsinfo,
108 ubuf, target_p->username, target_p->host,
109 target_p->sockhost, target_p->id,
110 target_p->account, target_p->info);
111
112 if (!EmptyString(target_p->certfp))
113 sendto_one(client_p, ":%s CERTFP %s", target_p->id, target_p->certfp);
114
115 if (target_p->away[0])
116 sendto_one(client_p, ":%s AWAY :%s", target_p->id, target_p->away);
117
118
119 DLINK_FOREACH(node, target_p->svstags.head)
120 {
121 const struct ServicesTag *svstag = node->data;
122 char *m = ubuf;
123
124 for (const struct user_modes *tab = umode_tab; tab->c; ++tab)
125 if (svstag->umodes & tab->flag)
126 *m++ = tab->c;
127 *m = '\0';
128
129 sendto_one(client_p, ":%s SVSTAG %s %ju %u +%s :%s", me.id, target_p->id,
130 target_p->tsinfo, svstag->numeric, ubuf, svstag->tag);
131 }
132 }
133
134 /* burst_members()
135 *
136 * inputs - pointer to server to send members to
137 * - dlink_list pointer to membership list to send
138 * output - NONE
139 * side effects -
140 */
141 static void
142 burst_members(struct Client *client_p, struct Channel *chptr)
143 {
144 struct Client *target_p;
145 struct Membership *member;
146 dlink_node *node = NULL;
147
148 DLINK_FOREACH(node, chptr->members.head)
149 {
150 member = node->data;
151 target_p = member->client_p;
152
153 if (!HasFlag(target_p, FLAGS_BURSTED))
154 {
155 AddFlag(target_p, FLAGS_BURSTED);
156
157 if (target_p->from != client_p)
158 sendnick_TS(client_p, target_p);
159 }
160 }
161 }
162
163 /* burst_all()
164 *
165 * inputs - pointer to server to send burst to
166 * output - NONE
167 * side effects - complete burst of channels/nicks is sent to client_p
168 */
169 static void
170 burst_all(struct Client *client_p)
171 {
172 dlink_node *node = NULL;
173
174 DLINK_FOREACH(node, channel_list.head)
175 {
176 struct Channel *chptr = node->data;
177
178 if (dlink_list_length(&chptr->members))
179 {
180 burst_members(client_p, chptr);
181 channel_send_modes(client_p, chptr);
182
183 if (IsCapable(client_p, CAPAB_TBURST))
184 send_tb(client_p, chptr);
185 }
186 }
187
188 /* also send out those that are not on any channel
189 */
190 DLINK_FOREACH(node, global_client_list.head)
191 {
192 struct Client *target_p = node->data;
193
194 if (!HasFlag(target_p, FLAGS_BURSTED) && target_p->from != client_p)
195 sendnick_TS(client_p, target_p);
196
197 DelFlag(target_p, FLAGS_BURSTED);
198 }
199 }
200
201 /* server_burst()
202 *
203 * inputs - struct Client pointer server
204 * -
205 * output - none
206 * side effects - send a server burst
207 * bugs - still too long
208 */
209 static void
210 server_burst(struct Client *client_p)
211 {
212 /* Send it in the shortened format with the TS, if
213 ** it's a TS server; walk the list of channels, sending
214 ** all the nicks that haven't been sent yet for each
215 ** channel, then send the channel itself -- it's less
216 ** obvious than sending all nicks first, but on the
217 ** receiving side memory will be allocated more nicely
218 ** saving a few seconds in the handling of a split
219 ** -orabidoo
220 */
221
222 burst_all(client_p);
223
224 /* EOB stuff is now in burst_all */
225 /* Always send a PING after connect burst is done */
226 sendto_one(client_p, "PING :%s", me.id);
227 }
228
229 /* server_estab()
230 *
231 * inputs - pointer to a struct Client
232 * output -
233 * side effects -
234 */
235 static void
236 server_estab(struct Client *client_p)
237 {
238 struct MaskItem *conf = NULL;
239 dlink_node *node = NULL;
240 #if defined(HAVE_LIBCRYPTO) && !defined(OPENSSL_NO_COMP)
241 const COMP_METHOD *compression = NULL, *expansion = NULL;
242 #endif
243
244 if ((conf = find_conf_name(&client_p->connection->confs, client_p->name, CONF_SERVER)) == NULL)
245 {
246 /* This shouldn't happen, better tell the ops... -A1kmm */
247 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
248 "Warning: lost connect{} block for %s",
249 get_client_name(client_p, SHOW_IP));
250 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
251 "Warning: lost connect{} block for %s",
252 get_client_name(client_p, MASK_IP));
253 exit_client(client_p, "Lost connect{} block!");
254 return;
255 }
256
257 MyFree(client_p->connection->password);
258 client_p->connection->password = NULL;
259
260 if (!ConfigServerInfo.hub && dlink_list_length(&local_server_list))
261 {
262 ++ServerStats.is_ref;
263 exit_client(client_p, "I'm a leaf not a hub");
264 return;
265 }
266
267 if (IsUnknown(client_p))
268 {
269 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
270
271 send_capabilities(client_p);
272
273 sendto_one(client_p, "SERVER %s 1 :%s%s",
274 me.name, ConfigServerHide.hidden ? "(H) " : "", me.info);
275 }
276
277 sendto_one(client_p, ":%s SVINFO %d %d 0 :%ju", me.id, TS_CURRENT, TS_MIN,
278 CurrentTime);
279
280 /* *WARNING*
281 ** In the following code in place of plain server's
282 ** name we send what is returned by get_client_name
283 ** which may add the "sockhost" after the name. It's
284 ** *very* *important* that there is a SPACE between
285 ** the name and sockhost (if present). The receiving
286 ** server will start the information field from this
287 ** first blank and thus puts the sockhost into info.
288 ** ...a bit tricky, but you have been warned, besides
289 ** code is more neat this way... --msa
290 */
291 client_p->servptr = &me;
292
293 if (HasFlag(client_p, FLAGS_CLOSING))
294 return;
295
296 SetServer(client_p);
297
298 /* Some day, all these lists will be consolidated *sigh* */
299 dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list);
300
301 assert(dlinkFind(&unknown_list, client_p));
302
303 dlink_move_node(&client_p->connection->lclient_node,
304 &unknown_list, &local_server_list);
305
306 Count.myserver++;
307
308 dlinkAdd(client_p, &client_p->node, &global_client_list);
309 dlinkAdd(client_p, make_dlink_node(), &global_server_list);
310 hash_add_client(client_p);
311 hash_add_id(client_p);
312
313 /* Doesn't duplicate client_p->serv if allocated this struct already */
314 make_server(client_p);
315
316 /* Fixing eob timings.. -gnp */
317 client_p->connection->firsttime = CurrentTime;
318
319 if (find_matching_name_conf(CONF_SERVICE, client_p->name, NULL, NULL, 0))
320 AddFlag(client_p, FLAGS_SERVICE);
321
322 /* Show the real host/IP to admins */
323 #ifdef HAVE_LIBCRYPTO
324 if (client_p->connection->fd.ssl)
325 {
326 #ifndef OPENSSL_NO_COMP
327 compression = SSL_get_current_compression(client_p->connection->fd.ssl);
328 expansion = SSL_get_current_expansion(client_p->connection->fd.ssl);
329 #endif
330 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
331 "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
332 get_client_name(client_p, SHOW_IP), ssl_get_cipher(client_p->connection->fd.ssl),
333 #ifndef OPENSSL_NO_COMP
334 compression ? SSL_COMP_get_name(compression) : "NONE",
335 expansion ? SSL_COMP_get_name(expansion) : "NONE",
336 #else
337 "NONE", "NONE",
338 #endif
339 show_capabilities(client_p));
340 /* Now show the masked hostname/IP to opers */
341 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
342 "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
343 get_client_name(client_p, MASK_IP), ssl_get_cipher(client_p->connection->fd.ssl),
344 #ifndef OPENSSL_NO_COMP
345 compression ? SSL_COMP_get_name(compression) : "NONE",
346 expansion ? SSL_COMP_get_name(expansion) : "NONE",
347 #else
348 "NONE", "NONE",
349 #endif
350 show_capabilities(client_p));
351 ilog(LOG_TYPE_IRCD, "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
352 get_client_name(client_p, SHOW_IP), ssl_get_cipher(client_p->connection->fd.ssl),
353 #ifndef OPENSSL_NO_COMP
354 compression ? SSL_COMP_get_name(compression) : "NONE",
355 expansion ? SSL_COMP_get_name(expansion) : "NONE",
356 #else
357 "NONE", "NONE",
358 #endif
359 show_capabilities(client_p));
360 }
361 else
362 #endif
363 {
364 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
365 "Link with %s established: (Capabilities: %s)",
366 get_client_name(client_p, SHOW_IP), show_capabilities(client_p));
367 /* Now show the masked hostname/IP to opers */
368 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
369 "Link with %s established: (Capabilities: %s)",
370 get_client_name(client_p, MASK_IP), show_capabilities(client_p));
371 ilog(LOG_TYPE_IRCD, "Link with %s established: (Capabilities: %s)",
372 get_client_name(client_p, SHOW_IP), show_capabilities(client_p));
373 }
374
375 fd_note(&client_p->connection->fd, "Server: %s", client_p->name);
376
377 sendto_server(client_p, 0, 0, ":%s SID %s 2 %s :%s%s",
378 me.id, client_p->name, client_p->id,
379 IsHidden(client_p) ? "(H) " : "", client_p->info);
380
381 /*
382 * Pass on my client information to the new server
383 *
384 * First, pass only servers (idea is that if the link gets
385 * cancelled beacause the server was already there,
386 * there are no NICK's to be cancelled...). Of course,
387 * if cancellation occurs, all this info is sent anyway,
388 * and I guess the link dies when a read is attempted...? --msa
389 *
390 * Note: Link cancellation to occur at this point means
391 * that at least two servers from my fragment are building
392 * up connection this other fragment at the same time, it's
393 * a race condition, not the normal way of operation...
394 */
395 DLINK_FOREACH_PREV(node, global_server_list.tail)
396 {
397 struct Client *target_p = node->data;
398
399 /* target_p->from == target_p for target_p == client_p */
400 if (IsMe(target_p) || target_p->from == client_p)
401 continue;
402
403 sendto_one(client_p, ":%s SID %s %u %s :%s%s",
404 target_p->servptr->id, target_p->name, target_p->hopcount+1,
405 target_p->id, IsHidden(target_p) ? "(H) " : "",
406 target_p->info);
407 }
408
409 server_burst(client_p);
410
411 if (IsCapable(client_p, CAPAB_EOB))
412 {
413 DLINK_FOREACH_PREV(node, global_server_list.tail)
414 {
415 struct Client *target_p = node->data;
416
417 if (target_p->from == client_p)
418 continue;
419
420 if (IsMe(target_p) || HasFlag(target_p, FLAGS_EOB))
421 sendto_one(client_p, ":%s EOB", target_p->id);
422 }
423 }
424 }
425
426 /* set_server_gecos()
427 *
428 * input - pointer to client
429 * output - NONE
430 * side effects - servers gecos field is set
431 */
432 static void
433 set_server_gecos(struct Client *client_p, const char *info)
434 {
435 const char *s = info;
436
437 /* check for (H) which is a hidden server */
438 if (!strncmp(s, "(H) ", 4))
439 {
440 AddFlag(client_p, FLAGS_HIDDEN);
441 s = s + 4;
442 }
443
444 if (!EmptyString(s))
445 strlcpy(client_p->info, s, sizeof(client_p->info));
446 else
447 strlcpy(client_p->info, "(Unknown Location)", sizeof(client_p->info));
448 }
449
450 /* mr_server()
451 * parv[0] = command
452 * parv[1] = servername
453 * parv[2] = hopcount
454 * parv[3] = serverinfo
455 */
456 static int
457 mr_server(struct Client *source_p, int parc, char *parv[])
458 {
459 const char *name = parv[1];
460 struct Client *target_p = NULL;
461
462 if (EmptyString(parv[parc - 1]))
463 {
464 exit_client(source_p, "No server description supplied");
465 return 0;
466 }
467
468 if (!valid_servname(name))
469 {
470 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
471 "Unauthorized server connection attempt from %s: Bogus server name "
472 "for server %s", get_client_name(source_p, SHOW_IP), name);
473 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
474 "Unauthorized server connection attempt from %s: Bogus server name "
475 "for server %s", get_client_name(source_p, MASK_IP), name);
476 exit_client(source_p, "Bogus server name");
477 return 0;
478 }
479
480 if (!valid_sid(source_p->id))
481 {
482 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
483 "Link %s introduced server with bogus server ID %s",
484 get_client_name(source_p, SHOW_IP), source_p->id);
485 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
486 "Link %s introduced server with bogus server ID %s",
487 get_client_name(source_p, MASK_IP), source_p->id);
488 exit_client(source_p, "Bogus server ID introduced");
489 return 0;
490 }
491
492 /* Now we just have to call check_server and everything should
493 * be check for us... -A1kmm.
494 */
495 switch (check_server(name, source_p))
496 {
497 case -1:
498 if (ConfigGeneral.warn_no_connect_block)
499 {
500 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
501 "Unauthorized server connection attempt from %s: No entry for "
502 "servername %s", get_client_name(source_p, SHOW_IP), name);
503
504 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
505 "Unauthorized server connection attempt from %s: No entry for "
506 "servername %s", get_client_name(source_p, MASK_IP), name);
507 }
508
509 exit_client(source_p, "No connect {} block.");
510 return 0;
511 /* NOT REACHED */
512 break;
513
514 case -2:
515 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
516 "Unauthorized server connection attempt from %s: Bad password "
517 "for server %s", get_client_name(source_p, SHOW_IP), name);
518
519 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
520 "Unauthorized server connection attempt from %s: Bad password "
521 "for server %s", get_client_name(source_p, MASK_IP), name);
522
523 exit_client(source_p, "Invalid password.");
524 return 0;
525 /* NOT REACHED */
526 break;
527
528 case -3:
529 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
530 "Unauthorized server connection attempt from %s: Invalid host "
531 "for server %s", get_client_name(source_p, SHOW_IP), name);
532
533 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
534 "Unauthorized server connection attempt from %s: Invalid host "
535 "for server %s", get_client_name(source_p, MASK_IP), name);
536
537 exit_client(source_p, "Invalid host.");
538 return 0;
539 case -4:
540 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
541 "Unauthorized server connection attempt from %s: Invalid certificate fingerprint "
542 "for server %s", get_client_name(source_p, SHOW_IP), name);
543
544 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
545 "Unauthorized server connection attempt from %s: Invalid certificate fingerprint "
546 "for server %s", get_client_name(source_p, MASK_IP), name);
547
548 exit_client(source_p, "Invalid certificate fingerprint.");
549 return 0;
550 /* NOT REACHED */
551 break;
552 }
553
554 if ((target_p = hash_find_server(name)))
555 {
556 /* This link is trying feed me a server that I already have
557 * access through another path -- multiple paths not accepted
558 * currently, kill this link immediately!!
559 *
560 * Rather than KILL the link which introduced it, KILL the
561 * youngest of the two links. -avalon
562 *
563 * Definitely don't do that here. This is from an unregistered
564 * connect - A1kmm.
565 */
566 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
567 "Attempt to re-introduce server %s from %s",
568 name, get_client_name(source_p, SHOW_IP));
569 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
570 "Attempt to re-introduce server %s from %s",
571 name, get_client_name(source_p, MASK_IP));
572 exit_client(source_p, "Server already exists");
573 return 0;
574 }
575
576 if ((target_p = hash_find_id(source_p->id)))
577 {
578 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
579 "Attempt to re-introduce server %s SID %s from %s",
580 name, source_p->id,
581 get_client_name(source_p, SHOW_IP));
582 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
583 "Attempt to re-introduce server %s SID %s from %s",
584 name, source_p->id,
585 get_client_name(source_p, MASK_IP));
586 exit_client(source_p, "Server ID already exists");
587 return 0;
588 }
589
590 /* XXX If somehow there is a connect in progress and
591 * a connect comes in with same name toss the pending one,
592 * but only if it's not the same client! - Dianora
593 */
594 if ((target_p = find_servconn_in_progress(name)))
595 if (target_p != source_p)
596 exit_client(target_p, "Overridden");
597
598 /* if we are connecting (Handshake), we already have the name from the
599 * connect{} block in source_p->name
600 */
601 strlcpy(source_p->name, name, sizeof(source_p->name));
602 set_server_gecos(source_p, parv[parc - 1]);
603 source_p->hopcount = atoi(parv[2]);
604 server_estab(source_p);
605 return 0;
606 }
607
608 /* ms_sid()
609 * parv[0] = command
610 * parv[1] = servername
611 * parv[2] = hopcount
612 * parv[3] = sid of new server
613 * parv[4] = serverinfo
614 */
615 static int
616 ms_sid(struct Client *source_p, int parc, char *parv[])
617 {
618 dlink_node *node = NULL;
619 struct Client *target_p = NULL;
620 struct Client *client_p = source_p->from; /* XXX */
621 const struct MaskItem *conf = NULL;
622 int hlined = 0;
623 int llined = 0;
624
625 /* Just to be sure -A1kmm. */
626 if (!IsServer(source_p))
627 return 0;
628
629 if (EmptyString(parv[parc - 1]))
630 {
631 exit_client(client_p, "No server description supplied");
632 return 0;
633 }
634
635 if (!valid_servname(parv[1]))
636 {
637 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
638 "Link %s introduced server with bogus server name %s",
639 get_client_name(client_p, SHOW_IP), parv[1]);
640 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
641 "Link %s introduced server with bogus server name %s",
642 get_client_name(client_p, MASK_IP), parv[1]);
643 exit_client(client_p, "Bogus server name introduced");
644 return 0;
645 }
646
647 if (!valid_sid(parv[3]))
648 {
649 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
650 "Link %s introduced server with bogus server ID %s",
651 get_client_name(client_p, SHOW_IP), parv[3]);
652 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
653 "Link %s introduced server with bogus server ID %s",
654 get_client_name(client_p, MASK_IP), parv[3]);
655 exit_client(client_p, "Bogus server ID introduced");
656 return 0;
657 }
658
659 /* collision on SID? */
660 if ((target_p = hash_find_id(parv[3])))
661 {
662 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
663 "Link %s cancelled, server ID %s already exists",
664 get_client_name(client_p, SHOW_IP), parv[3]);
665 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
666 "Link %s cancelled, server ID %s already exists",
667 get_client_name(client_p, MASK_IP), parv[3]);
668 exit_client(client_p, "Link cancelled, server ID already exists");
669 return 0;
670 }
671
672 /* collision on name? */
673 if ((target_p = hash_find_server(parv[1])))
674 {
675 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
676 "Link %s cancelled, server %s already exists",
677 get_client_name(client_p, SHOW_IP), parv[1]);
678 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
679 "Link %s cancelled, server %s already exists",
680 get_client_name(client_p, MASK_IP), parv[1]);
681 exit_client(client_p, "Server exists");
682 return 0;
683 }
684
685 /* XXX If somehow there is a connect in progress and
686 * a connect comes in with same name toss the pending one,
687 * but only if it's not the same client! - Dianora
688 */
689 if ((target_p = find_servconn_in_progress(parv[1])))
690 if (target_p != client_p)
691 exit_client(target_p, "Overridden");
692
693 conf = client_p->connection->confs.head->data;
694
695 /* See if the newly found server is behind a guaranteed
696 * leaf. If so, close the link.
697 */
698 DLINK_FOREACH(node, conf->leaf_list.head)
699 {
700 if (!match(node->data, parv[1]))
701 {
702 llined = 1;
703 break;
704 }
705 }
706
707 DLINK_FOREACH(node, conf->hub_list.head)
708 {
709 if (!match(node->data, parv[1]))
710 {
711 hlined = 1;
712 break;
713 }
714 }
715
716 /* Ok, this way this works is
717 *
718 * A server can have a CONF_HUB allowing it to introduce servers
719 * behind it.
720 *
721 * connect {
722 * name = "irc.bighub.net";
723 * hub_mask="*";
724 * ...
725 *
726 * That would allow "irc.bighub.net" to introduce anything it wanted..
727 *
728 * However
729 *
730 * connect {
731 * name = "irc.somehub.fi";
732 * hub_mask="*";
733 * leaf_mask="*.edu";
734 *...
735 * Would allow this server in finland to hub anything but
736 * .edu's
737 */
738
739 /* Ok, check client_p can hub the new server, and make sure it's not a LL */
740 if (!hlined)
741 {
742 /* OOOPs nope can't HUB */
743 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
744 "Non-Hub link %s introduced %s.",
745 get_client_name(client_p, SHOW_IP), parv[1]);
746 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
747 "Non-Hub link %s introduced %s.",
748 get_client_name(client_p, MASK_IP), parv[1]);
749 exit_client(source_p, "No matching hub_mask.");
750 return 0;
751 }
752
753 /* Check for the new server being leafed behind this HUB */
754 if (llined)
755 {
756 /* OOOPs nope can't HUB this leaf */
757 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
758 "Link %s introduced leafed server %s.",
759 get_client_name(client_p, SHOW_IP), parv[1]);
760 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
761 "Link %s introduced leafed server %s.",
762 get_client_name(client_p, MASK_IP), parv[1]);
763 exit_client(client_p, "Leafed server.");
764 return 0;
765 }
766
767 target_p = make_client(client_p);
768 make_server(target_p);
769 target_p->hopcount = atoi(parv[2]);
770 target_p->servptr = source_p;
771
772 strlcpy(target_p->name, parv[1], sizeof(target_p->name));
773 strlcpy(target_p->id, parv[3], sizeof(target_p->id));
774
775 set_server_gecos(target_p, parv[parc - 1]);
776 SetServer(target_p);
777
778 if (find_matching_name_conf(CONF_SERVICE, target_p->name, NULL, NULL, 0))
779 AddFlag(target_p, FLAGS_SERVICE);
780
781 dlinkAdd(target_p, &target_p->node, &global_client_list);
782 dlinkAdd(target_p, make_dlink_node(), &global_server_list);
783 dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->server_list);
784
785 hash_add_client(target_p);
786 hash_add_id(target_p);
787
788 sendto_server(client_p, 0, 0, ":%s SID %s %u %s :%s%s",
789 source_p->id, target_p->name, target_p->hopcount + 1,
790 target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info);
791 sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
792 "Server %s being introduced by %s",
793 target_p->name, source_p->name);
794 return 0;
795 }
796
797 static struct Message server_msgtab =
798 {
799 .cmd = "SERVER",
800 .args_min = 4,
801 .args_max = MAXPARA,
802 .handlers[UNREGISTERED_HANDLER] = mr_server,
803 .handlers[CLIENT_HANDLER] = m_registered,
804 .handlers[SERVER_HANDLER] = m_ignore,
805 .handlers[ENCAP_HANDLER] = m_ignore,
806 .handlers[OPER_HANDLER] = m_registered
807 };
808
809 static struct Message sid_msgtab =
810 {
811 .cmd = "SID",
812 .args_min = 5,
813 .args_max = MAXPARA,
814 .handlers[UNREGISTERED_HANDLER] = m_ignore,
815 .handlers[CLIENT_HANDLER] = m_ignore,
816 .handlers[SERVER_HANDLER] = ms_sid,
817 .handlers[ENCAP_HANDLER] = m_ignore,
818 .handlers[OPER_HANDLER] = m_ignore
819 };
820
821 static void
822 module_init(void)
823 {
824 mod_add_cmd(&sid_msgtab);
825 mod_add_cmd(&server_msgtab);
826 }
827
828 static void
829 module_exit(void)
830 {
831 mod_del_cmd(&sid_msgtab);
832 mod_del_cmd(&server_msgtab);
833 }
834
835 struct module module_entry =
836 {
837 .version = "$Revision$",
838 .modinit = module_init,
839 .modexit = module_exit,
840 .flags = MODULE_FLAG_CORE
841 };

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision