ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_server.c
Revision: 7248
Committed: Thu Feb 4 17:21:58 2016 UTC (10 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 27639 byte(s)
Error occurred while calculating annotation data.
Log Message:
- Move service {} block configuration management into its own module

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

Properties

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