ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_server.c
Revision: 6898
Committed: Wed Dec 2 20:19:47 2015 UTC (10 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 28693 byte(s)
Error occurred while calculating annotation data.
Log Message:
- m_server.c: rename set_server_gecos() to server_set_gecos()

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

Properties

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