ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_server.c
Revision: 6782
Committed: Sun Nov 15 18:49:32 2015 UTC (9 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 27746 byte(s)
Log Message:
- Use the %ju conversion specifier for time_t and get rid of these non-portable (unsigned long) casts; replace some uint64_t with uintmax_t

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

Properties

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