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

Properties

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