ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/server.c
Revision: 777
Committed: Wed Aug 23 14:55:16 2006 UTC (19 years, 11 months ago) by adx
Content type: text/x-csrc
File size: 56269 byte(s)
Log Message:
+ misc corrections

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * server.c: Server related functions.
4 *
5 * Copyright (C) 2005 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "conf/conf.h"
27 #ifdef HAVE_LIBCRYPTO
28 #include <openssl/rsa.h>
29 #include "rsa.h"
30 #endif
31 #include "channel.h"
32 #include "channel_mode.h"
33 #include "client.h"
34 #include "common.h"
35 #include "hash.h"
36 #include "ircd.h"
37 #include "ircd_defs.h"
38 #include "motd.h"
39 #include "numeric.h"
40 #include "packet.h"
41 #include "s_serv.h"
42 #include "s_user.h"
43 #include "send.h"
44 #include "channel.h" /* chcap_usage_counts stuff...*/
45
46 #define MIN_CONN_FREQ 300
47
48 static dlink_list cap_list = { NULL, NULL, 0 };
49 static void server_burst(struct Client *);
50 static int fork_server(struct Client *);
51 static void send_tb(struct Client *, const struct Channel *);
52
53 static CNCB serv_connect_callback;
54
55 static void start_io(struct Client *);
56 static void burst_members(struct Client *, struct Channel *);
57
58 static SlinkRplHnd slink_error;
59 static SlinkRplHnd slink_zipstats;
60
61
62 #ifdef HAVE_LIBCRYPTO
63 struct EncCapability CipherTable[] = {
64 #ifdef HAVE_EVP_BF_CFB
65 { "BF/168", CAP_ENC_BF_168, 24, CIPHER_BF },
66 { "BF/128", CAP_ENC_BF_128, 16, CIPHER_BF },
67 #endif
68 #ifdef HAVE_EVP_CAST5_CFB
69 { "CAST/128", CAP_ENC_CAST_128, 16, CIPHER_CAST },
70 #endif
71 #ifdef HAVE_EVP_IDEA_CFB
72 { "IDEA/128", CAP_ENC_IDEA_128, 16, CIPHER_IDEA },
73 #endif
74 #ifdef HAVE_EVP_RC5_32_12_16_CFB
75 { "RC5.16/128", CAP_ENC_RC5_16_128, 16, CIPHER_RC5_16 },
76 { "RC5.12/128", CAP_ENC_RC5_12_128, 16, CIPHER_RC5_12 },
77 { "RC5.8/128", CAP_ENC_RC5_8_128, 16, CIPHER_RC5_8 },
78 #endif
79 #ifdef HAVE_EVP_DES_EDE3_CFB
80 { "3DES/168", CAP_ENC_3DES_168, 24, CIPHER_3DES },
81 #endif
82 #ifdef HAVE_EVP_DES_CFB
83 { "DES/56", CAP_ENC_DES_56, 8, CIPHER_DES },
84 #endif
85 { 0, 0, 0, 0 }
86 };
87 #endif
88
89 struct SlinkRplDef slinkrpltab[] = {
90 { SLINKRPL_ERROR, slink_error, SLINKRPL_FLAG_DATA },
91 { SLINKRPL_ZIPSTATS, slink_zipstats, SLINKRPL_FLAG_DATA },
92 { 0, 0, 0 },
93 };
94
95
96 void
97 server_init(void)
98 {
99 add_capability("QS", CAP_QS, 1);
100 add_capability("EOB", CAP_EOB, 1);
101 add_capability("HUB", CAP_HUB, 0);
102 add_capability("TS6", CAP_TS6, 0);
103 add_capability("ZIP", CAP_ZIP, 0);
104 add_capability("CLUSTER", CAP_CLUSTER, 1);
105 #ifdef HALFOPS
106 add_capability("HOPS", CAP_HOPS, 1);
107 #endif
108 }
109
110 void
111 slink_error(unsigned int rpl, unsigned int len, unsigned char *data,
112 struct Client *server_p)
113 {
114 assert(rpl == SLINKRPL_ERROR);
115 assert(len < 256);
116
117 data[len-1] = '\0';
118
119 sendto_realops_flags(UMODE_ALL, L_ALL, "SlinkError for %s: %s",
120 server_p->name, data);
121 /* XXX should this be exit_client? */
122 exit_client(server_p, &me, "servlink error -- terminating link");
123 }
124
125 /*
126 * slink_zipstats
127 *
128 * inputs - rpl reply
129 * len length of reply
130 * data pointer to data
131 * pointer to server
132 * output - none
133 * side effects - ziplink stats are calculated
134 */
135 void
136 slink_zipstats(unsigned int rpl, unsigned int len, unsigned char *data,
137 struct Client *server_p)
138 {
139 struct ZipStats zipstats;
140 unsigned long in = 0, in_wire = 0, out = 0, out_wire = 0;
141 int i = 0;
142
143 assert(rpl == SLINKRPL_ZIPSTATS);
144 assert(len == 16);
145 assert(IsCapable(server_p, CAP_ZIP));
146
147 /* Yes, it needs to be done this way, no we cannot let the compiler
148 * work with the pointer to the structure. This works around a GCC
149 * bug on SPARC that affects all versions at the time of this writing.
150 * I will feed you to the creatures living in RMS's beard if you do
151 * not leave this as is, without being sure that you are not causing
152 * regression for most of our installed SPARC base.
153 * -jmallett, 04/27/2002
154 */
155 memcpy(&zipstats, &server_p->localClient->zipstats, sizeof(struct ZipStats));
156
157 in |= (data[i++] << 24);
158 in |= (data[i++] << 16);
159 in |= (data[i++] << 8);
160 in |= (data[i++] );
161
162 in_wire |= (data[i++] << 24);
163 in_wire |= (data[i++] << 16);
164 in_wire |= (data[i++] << 8);
165 in_wire |= (data[i++] );
166
167 out |= (data[i++] << 24);
168 out |= (data[i++] << 16);
169 out |= (data[i++] << 8);
170 out |= (data[i++] );
171
172 out_wire |= (data[i++] << 24);
173 out_wire |= (data[i++] << 16);
174 out_wire |= (data[i++] << 8);
175 out_wire |= (data[i++] );
176
177 /* This macro adds b to a if a plus b is not an overflow, and sets the
178 * value of a to b if it is.
179 * Add and Set if No Overflow.
180 */
181 #define ASNO(a, b) a = (a + b >= a ? a + b : b)
182
183 ASNO(zipstats.in, in);
184 ASNO(zipstats.out, out);
185 ASNO(zipstats.in_wire, in_wire);
186 ASNO(zipstats.out_wire, out_wire);
187
188 if (zipstats.in > 0)
189 zipstats.in_ratio = (((double)(zipstats.in - zipstats.in_wire) /
190 (double)zipstats.in) * 100.00);
191 else
192 zipstats.in_ratio = 0;
193
194 if (zipstats.out > 0)
195 zipstats.out_ratio = (((double)(zipstats.out - zipstats.out_wire) /
196 (double)zipstats.out) * 100.00);
197 else
198 zipstats.out_ratio = 0;
199
200 memcpy(&server_p->localClient->zipstats, &zipstats, sizeof (struct ZipStats));
201 }
202
203 void
204 collect_zipstats(void *unused)
205 {
206 dlink_node *ptr;
207 struct Client *target_p;
208
209 DLINK_FOREACH(ptr, serv_list.head)
210 {
211 target_p = ptr->data;
212
213 if (IsCapable(target_p, CAP_ZIP))
214 {
215 /* only bother if we haven't already got something queued... */
216 if (target_p->localClient->slinkq == NULL)
217 {
218 target_p->localClient->slinkq = MyMalloc(1); /* sigh.. */
219 target_p->localClient->slinkq[0] = SLINKCMD_ZIPSTATS;
220 target_p->localClient->slinkq_ofs = 0;
221 target_p->localClient->slinkq_len = 1;
222 send_queued_slink_write(target_p);
223 }
224 }
225 }
226 }
227
228 #ifdef HAVE_LIBCRYPTO
229 struct EncCapability *
230 check_cipher(struct Client *client_p, struct ConnectConf *conf)
231 {
232 struct EncCapability *epref = NULL;
233
234 /* Use connect{} specific info if available */
235 if (conf->cipher_preference)
236 epref = conf->cipher_preference;
237 else if (General.default_cipher_preference)
238 epref = General.default_cipher_preference;
239
240 /* If the server supports the capability in hand, return the matching
241 * conf struct. Otherwise, return NULL (an error).
242 */
243 if (epref && IsCapableEnc(client_p, epref->cap))
244 return epref;
245
246 return NULL;
247 }
248 #endif /* HAVE_LIBCRYPTO */
249
250 /* my_name_for_link()
251 * return wildcard name of my server name
252 * according to given config entry --Jto
253 */
254 const char *
255 my_name_for_link(struct ConnectConf *conf)
256 {
257 return conf->fakename ? conf->fakename : me.name;
258 }
259
260 /*
261 * write_links_file
262 *
263 * inputs - void pointer which is not used
264 * output - NONE
265 * side effects - called from an event, write out list of linked servers
266 * but in no particular order.
267 */
268 void
269 write_links_file(void* notused)
270 {
271 MessageFileLine *next_mptr = 0;
272 MessageFileLine *mptr = 0;
273 MessageFileLine *currentMessageLine = 0;
274 MessageFileLine *newMessageLine = 0;
275 const char *p;
276 FBFILE *file;
277 char buff[512];
278 dlink_node *ptr;
279
280 if ((file = fbopen(linksfile.fileName, "w")) == NULL)
281 return;
282
283 for (mptr = linksfile.contentsOfFile; mptr; mptr = next_mptr)
284 {
285 next_mptr = mptr->next;
286 MyFree(mptr);
287 }
288
289 linksfile.contentsOfFile = NULL;
290 currentMessageLine = NULL;
291
292 DLINK_FOREACH(ptr, global_serv_list.head)
293 {
294 size_t nbytes = 0;
295 struct Client *target_p = ptr->data;
296
297 /* skip ourselves, we send ourselves in /links */
298 if (IsMe(target_p))
299 continue;
300
301 /* skip hidden servers */
302 if (IsHidden(target_p) && !ServerHide.disable_hidden)
303 continue;
304
305 if (target_p->info[0])
306 p = target_p->info;
307 else
308 p = "(Unknown Location)";
309
310 newMessageLine = MyMalloc(sizeof(MessageFileLine));
311
312 /* Attempt to format the file in such a way it follows the usual links output
313 * ie "servername uplink :hops info"
314 * Mostly for aesthetic reasons - makes it look pretty in mIRC ;)
315 * - madmax
316 */
317 /*
318 * For now, check this ircsprintf wont overflow - it shouldnt on a
319 * default config but it is configurable..
320 * This should be changed to an snprintf at some point, but I'm wanting to
321 * know if this is a cause of a bug - cryogen
322 */
323 assert(strlen(target_p->name) + strlen(me.name) + 6 + strlen(p) <=
324 MESSAGELINELEN);
325 ircsprintf(newMessageLine->line, "%s %s :1 %s",
326 target_p->name, me.name, p);
327 newMessageLine->next = NULL;
328
329 if (linksfile.contentsOfFile)
330 {
331 if (currentMessageLine)
332 currentMessageLine->next = newMessageLine;
333 currentMessageLine = newMessageLine;
334 }
335 else
336 {
337 linksfile.contentsOfFile = newMessageLine;
338 currentMessageLine = newMessageLine;
339 }
340
341 nbytes = ircsprintf(buff, "%s %s :1 %s\n", target_p->name, me.name, p);
342 fbputs(buff, file, nbytes);
343 }
344
345 fbclose(file);
346 }
347
348 /* hunt_server()
349 * Do the basic thing in delivering the message (command)
350 * across the relays to the specific server (server) for
351 * actions.
352 *
353 * Note: The command is a format string and *MUST* be
354 * of prefixed style (e.g. ":%s COMMAND %s ...").
355 * Command can have only max 8 parameters.
356 *
357 * server parv[server] is the parameter identifying the
358 * target server.
359 *
360 * *WARNING*
361 * parv[server] is replaced with the pointer to the
362 * real servername from the matched client (I'm lazy
363 * now --msa).
364 *
365 * returns: (see #defines)
366 */
367 int
368 hunt_server(struct Client *source_p, const char *command,
369 int server, int parc, char *parv[])
370 {
371 struct Client *target_p = NULL;
372 struct Client *target_tmp = NULL;
373 dlink_node *ptr = NULL;
374
375 /*
376 * Assume it's me, if no server
377 */
378 if (parc <= server || EmptyString(parv[server]) ||
379 match(me.name, parv[server]) ||
380 match(parv[server], me.name) ||
381 !strcmp(parv[server], me.id))
382 return HUNTED_ISME;
383
384 /*
385 * These are to pickup matches that would cause the following
386 * message to go in the wrong direction while doing quick fast
387 * non-matching lookups.
388 */
389 if (MyClient(source_p))
390 target_p = find_client(parv[server]);
391 else
392 target_p = find_person(source_p->from, parv[server]);
393
394 if (target_p)
395 if (target_p->from == source_p->from && !MyConnect(target_p))
396 target_p = NULL;
397
398 if (target_p == NULL && (target_p = find_server(parv[server])))
399 if (target_p->from == source_p->from && !MyConnect(target_p))
400 target_p = NULL;
401
402 /* Again, if there are no wild cards involved in the server
403 * name, use the hash lookup
404 */
405 if (target_p == NULL)
406 {
407 if (!has_wildcards(parv[server], NO))
408 {
409 if (!(target_p = find_server(parv[server])))
410 {
411 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
412 me.name, parv[0], parv[server]);
413 return HUNTED_NOSUCH;
414 }
415 }
416 else
417 {
418 DLINK_FOREACH(ptr, global_client_list.head)
419 {
420 target_tmp = ptr->data;
421
422 if (match(parv[server], target_tmp->name))
423 {
424 if (target_tmp->from == source_p->from && !MyConnect(target_tmp))
425 continue;
426 target_p = ptr->data;
427
428 if (IsRegistered(target_p) && (target_p != source_p->from))
429 break;
430 }
431 }
432 }
433 }
434
435 if (target_p != NULL)
436 {
437 if (!IsRegistered(target_p))
438 {
439 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
440 me.name, parv[0], parv[server]);
441 return HUNTED_NOSUCH;
442 }
443
444 if (IsMe(target_p) || MyClient(target_p))
445 return HUNTED_ISME;
446
447 if (!match(target_p->name, parv[server]))
448 parv[server] = target_p->name;
449
450 /* This is a little kludgy but should work... */
451 if (IsClient(source_p) &&
452 ((MyConnect(target_p) && IsCapable(target_p, CAP_TS6)) ||
453 (!MyConnect(target_p) && IsCapable(target_p->from, CAP_TS6))))
454 parv[0] = ID(source_p);
455
456 sendto_one(target_p, command, parv[0],
457 parv[1], parv[2], parv[3], parv[4],
458 parv[5], parv[6], parv[7], parv[8]);
459 return HUNTED_PASS;
460 }
461
462 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
463 me.name, parv[0], parv[server]);
464 return HUNTED_NOSUCH;
465 }
466
467 /* try_connections()
468 *
469 * inputs - void pointer which is not used
470 * output - NONE
471 * side effects -
472 * scan through configuration and try new connections.
473 * Returns the calendar time when the next call to this
474 * function should be made latest. (No harm done if this
475 * is called earlier or later...)
476 */
477 void
478 try_connections(void *unused)
479 {
480 dlink_node *ptr;
481 struct ConnectConf *conf;
482
483 if (!GlobalSetOptions.autoconn)
484 return;
485
486 DLINK_FOREACH(ptr, connect_confs.head)
487 {
488 conf = ptr->data;
489
490 /* Also when already connecting! (update holdtimes) --SRB
491 */
492 if (conf->port <= 0 || !(conf->flags & LINK_AUTOCONN))
493 continue;
494
495 /* Skip this entry if the use of it is still on hold until
496 * future. Otherwise handle this entry (and set it on hold
497 * until next time). Will reset only hold times, if already
498 * made one successfull connection... [this algorithm is
499 * a bit fuzzy... -- msa >;) ]
500 */
501 if (conf->hold > CurrentTime)
502 continue;
503
504 /* Found a CONNECT config with port specified, scan clients
505 * and see if this server is already connected?
506 */
507 if (find_server(conf->name) || find_servconn_in_progress(conf->name))
508 continue;
509
510 conf->hold = CurrentTime +
511 LIBIO_MAX(conf->class_ptr->connectfreq, MIN_CONN_FREQ);
512
513 if (conf->class_ptr->cur_clients < conf->class_ptr->max_number)
514 {
515 // Go to the end of the list, if not already last
516 if (ptr->next != NULL)
517 {
518 dlinkDelete(ptr, &connect_confs);
519 dlinkAddTail(conf, &conf->node, &connect_confs);
520 }
521
522 /* We used to only print this if serv_connect() actually
523 * succeeded, but since comm_tcp_connect() can call the callback
524 * immediately if there is an error, we were getting error messages
525 * in the wrong order. SO, we just print out the activated line,
526 * and let serv_connect() / serv_connect_callback() print an
527 * error afterwards if it fails.
528 * -- adrian
529 */
530 if (ServerHide.hide_server_ips)
531 sendto_realops_flags(UMODE_ALL, L_ALL, "Connection to %s activated.",
532 conf->name);
533 else
534 sendto_realops_flags(UMODE_ALL, L_ALL, "Connection to %s[%s] activated.",
535 conf->name, conf->host);
536
537 serv_connect(conf, NULL, conf->port);
538 // We connect only one at time...
539 return;
540 }
541 }
542 }
543
544 /* bogus_host()
545 *
546 * inputs - hostname
547 * output - 1 if a bogus hostname input,
548 * - 0 if its valid
549 * side effects - none
550 */
551 int
552 bogus_host(const char *host)
553 {
554 unsigned int length = 0;
555 unsigned int dots = 0;
556 const unsigned char *s = (const unsigned char *)host;
557
558 for (; *s; ++s)
559 {
560 if (!IsServChar(*s))
561 return 1;
562
563 ++length;
564
565 if ('.' == *s)
566 ++dots;
567 }
568
569 return !dots || length > HOSTLEN;
570 }
571
572 /*
573 * check_server
574 *
575 * inputs - name
576 * - pointer to client struct
577 * - int flag for cryptlink
578 * output - return -'ve value for error
579 * side effects -
580 *
581 * Called from mr_server when a client claiming to be a server
582 * connects. check_server() verifies this client is or isn't a server and
583 * returns an error if it isn't a server, it otherwise attaches the appropriate
584 * server connect block to this client.
585 */
586 int
587 check_server(const char *name, struct Client *client_p, int cryptlink)
588 {
589 struct ConnectConf *server_conf = NULL;
590 dlink_node *ptr;
591 int error = -1;
592
593 assert(client_p != NULL);
594
595 if (strlen(name) > HOSTLEN)
596 return -4;
597
598 // loop through looking for all possible connect items that might work
599 DLINK_FOREACH(ptr, connect_confs.head)
600 {
601 struct ConnectConf *conf = ptr->data;
602 const char *addr = conf->allow_host ? conf->allow_host : conf->host;
603 struct irc_ssaddr ipmask;
604 int bits;
605
606 if (!match(name, conf->name))
607 continue;
608
609 error = -3;
610 if ((parse_netmask(addr, &ipmask, &bits) == HM_HOST) ?
611 irccmp(client_p->host, addr) : !(
612 #ifdef IPV6
613 ipmask.ss.sin_family == AF_INET6 ? match_ipv6 :
614 #endif
615 match_ipv4)(&client_p->localClient->ip, &ipmask, bits))
616 continue;
617
618 error = -2;
619 #ifdef HAVE_LIBCRYPTO
620 if (cryptlink && (conf->flags & LINK_CRYPTLINK))
621 {
622 if (conf->rsa_public_key)
623 server_conf = conf;
624 }
625 else if (!cryptlink && !(conf->flags & LINK_CRYPTLINK))
626 #endif /* HAVE_LIBCRYPTO */
627 {
628 // A NULL password is as good as a bad one
629 if (EmptyString(client_p->localClient->passwd))
630 return -2;
631
632 // code in conf/connect.c should not have allowed this to be NULL
633 if (EmptyString(conf->accept_password))
634 return -2;
635
636 if (match_password(conf->accept_password, client_p->localClient->passwd,
637 (conf->flags & LINK_CRYPTPWD)) || IsServer(client_p))
638 server_conf = conf;
639 }
640 }
641
642 if (server_conf == NULL)
643 return error;
644
645 make_server(client_p);
646 client_p->serv->sconf = ref_link_by_ptr(server_conf);
647
648 #ifdef HAVE_LIBZ /* otherwise, clear it unconditionally */
649 if (!(server_conf->flags & LINK_COMPRESSED))
650 #endif
651 ClearCap(client_p, CAP_ZIP);
652 if (!(server_conf->flags & LINK_CRYPTLINK))
653 ClearCap(client_p, CAP_ENC);
654 if (!(server_conf->flags & LINK_TOPICBURST))
655 {
656 ClearCap(client_p, CAP_TB);
657 ClearCap(client_p, CAP_TBURST);
658 }
659
660 return 0;
661 }
662
663 /* add_capability()
664 *
665 * inputs - string name of CAPAB
666 * - int flag of capability
667 * output - NONE
668 * side effects - Adds given capability name and bit mask to
669 * current supported capabilities. This allows
670 * modules to dynamically add or subtract their capability.
671 */
672 void
673 add_capability(const char *capab_name, int cap_flag, int add_to_default)
674 {
675 struct Capability *cap;
676
677 cap = (struct Capability *)MyMalloc(sizeof(*cap));
678 DupString(cap->name, capab_name);
679 cap->cap = cap_flag;
680 dlinkAdd(cap, &cap->node, &cap_list);
681 if (add_to_default)
682 default_server_capabs |= cap_flag;
683 }
684
685 /* delete_capability()
686 *
687 * inputs - string name of CAPAB
688 * output - NONE
689 * side effects - delete given capability from ones known.
690 */
691 int
692 delete_capability(const char *capab_name)
693 {
694 dlink_node *ptr;
695 dlink_node *next_ptr;
696 struct Capability *cap;
697
698 DLINK_FOREACH_SAFE(ptr, next_ptr, cap_list.head)
699 {
700 cap = ptr->data;
701
702 if (cap->cap != 0)
703 if (!irccmp(cap->name, capab_name))
704 {
705 default_server_capabs &= ~(cap->cap);
706 dlinkDelete(ptr, &cap_list);
707 MyFree(cap->name);
708 MyFree(cap);
709 }
710 }
711
712 return 0;
713 }
714
715 /*
716 * find_capability()
717 *
718 * inputs - string name of capab to find
719 * output - 0 if not found CAPAB otherwise
720 * side effects - none
721 */
722 int
723 find_capability(const char *capab)
724 {
725 dlink_node *ptr;
726 struct Capability *cap;
727
728 DLINK_FOREACH(ptr, cap_list.head)
729 {
730 cap = ptr->data;
731
732 if (cap->cap != 0)
733 {
734 if (!irccmp(cap->name, capab))
735 return cap->cap;
736 }
737 }
738
739 return 0;
740 }
741
742 /* send_capabilities()
743 *
744 * inputs - Client pointer to send to
745 * - Pointer to ConnectConf (for crypt)
746 * - int flag of capabilities that this server can send
747 * - int flag of encryption capabilities
748 * output - NONE
749 * side effects - send the CAPAB line to a server -orabidoo
750 *
751 */
752 void
753 send_capabilities(struct Client *client_p, struct ConnectConf *conf,
754 int cap_can_send, int enc_can_send)
755 {
756 struct Capability *cap = NULL;
757 char msgbuf[IRCD_BUFSIZE];
758 char *t;
759 int tl;
760 dlink_node *ptr;
761 #ifdef HAVE_LIBCRYPTO
762 const struct EncCapability *epref = NULL;
763 char *capend;
764 int sent_cipher = 0;
765 #endif
766
767 t = msgbuf;
768
769 DLINK_FOREACH(ptr, cap_list.head)
770 {
771 cap = ptr->data;
772
773 if (cap->cap & (cap_can_send|default_server_capabs))
774 {
775 tl = ircsprintf(t, "%s ", cap->name);
776 t += tl;
777 }
778 }
779 #ifdef HAVE_LIBCRYPTO
780 if (enc_can_send)
781 {
782 capend = t;
783 strcpy(t, "ENC:");
784 t += 4;
785
786 // use connect{} specific info if available
787 if (conf->cipher_preference)
788 epref = conf->cipher_preference;
789 else if (General.default_cipher_preference)
790 epref = General.default_cipher_preference;
791
792 if (epref && (epref->cap & enc_can_send))
793 {
794 // Leave the space -- it is removed later.
795 tl = ircsprintf(t, "%s ", epref->name);
796 t += tl;
797 sent_cipher = 1;
798 }
799
800 if (!sent_cipher)
801 t = capend; // truncate string before ENC:, below
802 }
803 #endif
804 *(t - 1) = '\0';
805 sendto_one(client_p, "CAPAB :%s", msgbuf);
806 }
807
808 /* sendnick_TS()
809 *
810 * inputs - client (server) to send nick towards
811 * - client to send nick for
812 * output - NONE
813 * side effects - NICK message is sent towards given client_p
814 */
815 void
816 sendnick_TS(struct Client *client_p, struct Client *target_p)
817 {
818 static char ubuf[12];
819
820 if (!IsClient(target_p))
821 return;
822
823 send_umode(NULL, target_p, 0, IsOperHiddenAdmin(target_p) ?
824 SEND_UMODES & ~UMODE_ADMIN : SEND_UMODES, ubuf);
825
826 if (ubuf[0] == '\0')
827 {
828 ubuf[0] = '+';
829 ubuf[1] = '\0';
830 }
831
832 // XXX Both of these need to have a :me.name or :mySID!?!?!
833 if (HasID(target_p) && IsCapable(client_p, CAP_TS6))
834 sendto_one(client_p, ":%s UID %s %d %lu %s %s %s %s %s :%s",
835 target_p->servptr->id,
836 target_p->name, target_p->hopcount + 1,
837 (unsigned long) target_p->tsinfo,
838 ubuf, target_p->username, target_p->host,
839 ((MyClient(target_p)&&!IsIPSpoof(target_p))?target_p->sockhost:"0"),
840 target_p->id, target_p->info);
841 else
842 sendto_one(client_p, "NICK %s %d %lu %s %s %s %s :%s",
843 target_p->name, target_p->hopcount + 1,
844 (unsigned long) target_p->tsinfo,
845 ubuf, target_p->username, target_p->host,
846 target_p->servptr->name, target_p->info);
847
848 if ((client_p->serv->sconf->flags & LINK_BURSTAWAY))
849 if (!EmptyString(target_p->away))
850 sendto_one(client_p, ":%s AWAY :%s", target_p->name, target_p->away);
851 }
852
853 /*
854 * show_capabilities - show current server capabilities
855 *
856 * inputs - pointer to a struct Client
857 * output - pointer to static string
858 * side effects - build up string representing capabilities of server listed
859 */
860 const char *
861 show_capabilities(const struct Client *target_p)
862 {
863 static char msgbuf[IRCD_BUFSIZE];
864 char *t = msgbuf;
865 dlink_node *ptr;
866
867 t += ircsprintf(msgbuf, "TS ");
868
869 DLINK_FOREACH(ptr, cap_list.head)
870 {
871 const struct Capability *cap = ptr->data;
872
873 if (IsCapable(target_p, cap->cap))
874 t += ircsprintf(t, "%s ", cap->name);
875 }
876 #ifdef HAVE_LIBCRYPTO
877 if (IsCapable(target_p, CAP_ENC) &&
878 target_p->localClient->in_cipher &&
879 target_p->localClient->out_cipher)
880 t += ircsprintf(t, "ENC:%s ",
881 target_p->localClient->in_cipher->name);
882 #endif
883 *(t - 1) = '\0';
884
885 return msgbuf;
886 }
887
888 /* make_server()
889 *
890 * inputs - pointer to client struct
891 * output - pointer to struct Server
892 * side effects - add's an Server information block to a client
893 * if it was not previously allocated.
894 */
895 struct Server *
896 make_server(struct Client *client_p)
897 {
898 if (client_p->serv == NULL)
899 client_p->serv = MyMalloc(sizeof(*client_p->serv));
900
901 return client_p->serv;
902 }
903
904 /* server_estab()
905 *
906 * inputs - pointer to a struct Client
907 * output -
908 * side effects -
909 */
910 void
911 server_estab(struct Client *client_p)
912 {
913 struct Client *target_p;
914 struct ConnectConf *conf;
915 char *host;
916 const char *inpath;
917 static char inpath_ip[HOSTLEN * 2 + USERLEN + 6];
918 dlink_node *m;
919 dlink_node *ptr;
920
921 assert(client_p != NULL);
922
923 strlcpy(inpath_ip, get_client_name(client_p, SHOW_IP), sizeof(inpath_ip));
924
925 inpath = get_client_name(client_p, MASK_IP); // "refresh" inpath with host
926 host = client_p->name;
927
928 if ((conf = client_p->serv->sconf) == NULL)
929 {
930 // This shouldn't happen, better tell the ops... -A1kmm
931 sendto_realops_flags(UMODE_ALL, L_ALL, "Warning: Lost connect{} block "
932 "for server %s(this shouldn't happen)!", host);
933 exit_client(client_p, &me, "Lost connect{} block!");
934 return;
935 }
936
937 attach_class(client_p, conf->class_ptr);
938 MyFree(client_p->localClient->passwd);
939 client_p->localClient->passwd = NULL;
940
941 // Its got identd, since its a server
942 SetGotId(client_p);
943
944 /* If there is something in the serv_list, it might be this
945 * connecting server..
946 */
947 if (!ServerInfo.hub && serv_list.head)
948 if (client_p != serv_list.head->data || serv_list.head->next)
949 {
950 ++ServerStats.is_ref;
951 sendto_one(client_p, "ERROR :I'm a leaf not a hub");
952 exit_client(client_p, &me, "I'm a leaf");
953 return;
954 }
955
956 if (IsUnknown(client_p) && !(conf->flags & LINK_CRYPTLINK))
957 {
958 if (!EmptyString(conf->send_password))
959 {
960 // only send ts6 format PASS if we have ts6 enabled
961 if (me.id[0] != '\0') // Send TS 6 form only if id
962 sendto_one(client_p, "PASS %s TS %d %s",
963 conf->send_password, TS_CURRENT, me.id);
964 else
965 sendto_one(client_p, "PASS %s TS 5",
966 conf->send_password);
967 }
968
969 /* Pass my info to the new server
970 *
971 * If this is a HUB, pass on CAP_HUB
972 * Pass on ZIP if supported
973 * Pass on TB if supported.
974 * - Dianora
975 *
976 * TODO: Use a callback instead of hardcoding flag<->cap relations.
977 */
978
979 send_capabilities(client_p, conf, (ServerInfo.hub ? CAP_HUB : 0)
980 | ((conf->flags & LINK_COMPRESSED) ? CAP_ZIP : 0)
981 | ((conf->flags & LINK_TOPICBURST) ? CAP_TBURST|CAP_TB : 0), 0);
982
983 /* SERVER is the last command sent before switching to ziplinks.
984 * We set TCPNODELAY on the socket to make sure it gets sent out
985 * on the wire immediately. Otherwise, it could be sitting in
986 * a kernel buffer when we start sending zipped data, and the
987 * parser on the receiving side can't hand both unzipped and zipped
988 * data in one packet. --Rodder
989 *
990 * currently we only need to call send_queued_write,
991 * Nagle is already disabled at this point --adx
992 */
993 sendto_one(client_p, "SERVER %s 1 :%s%s",
994 my_name_for_link(conf), // XXX
995 ServerHide.hidden ? "(H) " : "", me.info);
996 send_queued_write(client_p);
997 }
998
999 // Hand the server off to servlink now
1000 if (IsCapable(client_p, CAP_ENC) || IsCapable(client_p, CAP_ZIP))
1001 {
1002 if (fork_server(client_p) < 0)
1003 {
1004 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1005 "Warning: fork failed for server %s -- check servlink_path (%s)",
1006 get_client_name(client_p, HIDE_IP), General.servlink_path);
1007 sendto_realops_flags(UMODE_ALL, L_OPER, "Warning: fork failed for server "
1008 "%s -- check servlink_path (%s)",
1009 get_client_name(client_p, MASK_IP),
1010 General.servlink_path);
1011 exit_client(client_p, &me, "fork failed");
1012 return;
1013 }
1014
1015 start_io(client_p);
1016 SetServlink(client_p);
1017 }
1018
1019 // only send ts6 format SVINFO if we have ts6 enabled
1020 sendto_one(client_p, "SVINFO %d %d 0 :%lu",
1021 (me.id[0] ? TS_CURRENT : 5), TS_MIN,
1022 (unsigned long)CurrentTime);
1023
1024 if (IsCapable(client_p, CAP_TS6))
1025 hash_add_id(client_p);
1026
1027 /* *WARNING*
1028 ** In the following code in place of plain server's
1029 ** name we send what is returned by get_client_name
1030 ** which may add the "sockhost" after the name. It's
1031 ** *very* *important* that there is a SPACE between
1032 ** the name and sockhost (if present). The receiving
1033 ** server will start the information field from this
1034 ** first blank and thus puts the sockhost into info.
1035 ** ...a bit tricky, but you have been warned, besides
1036 ** code is more neat this way... --msa
1037 */
1038 client_p->servptr = &me;
1039
1040 if (IsClosing(client_p))
1041 return;
1042
1043 SetServer(client_p);
1044
1045 // Update the capability combination usage counts. -A1kmm
1046 set_chcap_usage_counts(client_p);
1047
1048 dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list);
1049
1050 m = dlinkFind(&unknown_list, client_p);
1051 assert(NULL != m);
1052
1053 dlinkDelete(m, &unknown_list);
1054 dlinkAdd(client_p, m, &serv_list);
1055
1056 Count.myserver++;
1057
1058 dlinkAdd(client_p, make_dlink_node(), &global_serv_list);
1059 hash_add_client(client_p);
1060
1061 // doesnt duplicate client_p->serv if this struct is allocated already
1062 make_server(client_p);
1063
1064 // fixing eob timings.. -gnp
1065 client_p->firsttime = CurrentTime;
1066
1067 // Show the real host/IP to admins
1068 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1069 "Link with %s established: (%s) link",
1070 inpath_ip,show_capabilities(client_p));
1071 // Now show the masked hostname/IP to opers
1072 sendto_realops_flags(UMODE_ALL, L_OPER,
1073 "Link with %s established: (%s) link",
1074 inpath,show_capabilities(client_p));
1075 ilog(L_NOTICE, "Link with %s established: (%s) link",
1076 inpath_ip, show_capabilities(client_p));
1077
1078 if (HasServlink(client_p))
1079 {
1080 /* we won't overflow FD_DESC_SZ here, as it can hold
1081 * client_p->name + 64
1082 */
1083 fd_note(&client_p->localClient->fd, "slink data: %s", client_p->name);
1084 fd_note(&client_p->localClient->ctrlfd, "slink ctrl: %s", client_p->name);
1085 }
1086 else
1087 fd_note(&client_p->localClient->fd, "Server: %s", client_p->name);
1088
1089 /* Old sendto_serv_but_one() call removed because we now
1090 ** need to send different names to different servers
1091 ** (domain name matching) Send new server to other servers.
1092 */
1093 DLINK_FOREACH(ptr, serv_list.head)
1094 {
1095 target_p = ptr->data;
1096
1097 if (target_p == client_p)
1098 continue;
1099
1100 if ((conf = target_p->serv->sconf) &&
1101 match(my_name_for_link(conf), client_p->name))
1102 continue;
1103
1104 if (IsCapable(target_p, CAP_TS6) && HasID(client_p))
1105 sendto_one(target_p, ":%s SID %s 2 %s :%s%s",
1106 me.id, client_p->name, client_p->id,
1107 IsHidden(client_p) ? "(H) " : "",
1108 client_p->info);
1109 else
1110 sendto_one(target_p,":%s SERVER %s 2 :%s%s",
1111 me.name, client_p->name,
1112 IsHidden(client_p) ? "(H) " : "",
1113 client_p->info);
1114 }
1115
1116 server_burst(client_p);
1117 }
1118
1119 static void
1120 start_io(struct Client *server)
1121 {
1122 struct LocalUser *lserver = server->localClient;
1123 int alloclen = 1;
1124 char *buf;
1125 dlink_node *ptr;
1126 struct dbuf_block *block;
1127
1128 /* calculate how many bytes to allocate */
1129 if (IsCapable(server, CAP_ZIP))
1130 alloclen += 6;
1131 #ifdef HAVE_LIBCRYPTO
1132 if (IsCapable(server, CAP_ENC))
1133 alloclen += 16 + lserver->in_cipher->keylen + lserver->out_cipher->keylen;
1134 #endif
1135 alloclen += dbuf_length(&lserver->buf_recvq);
1136 alloclen += dlink_list_length(&lserver->buf_recvq.blocks) * 3;
1137 alloclen += dbuf_length(&lserver->buf_sendq);
1138 alloclen += dlink_list_length(&lserver->buf_sendq.blocks) * 3;
1139
1140 /* initialize servlink control sendq */
1141 lserver->slinkq = buf = MyMalloc(alloclen);
1142 lserver->slinkq_ofs = 0;
1143 lserver->slinkq_len = alloclen;
1144
1145 if (IsCapable(server, CAP_ZIP))
1146 {
1147 /* ziplink */
1148 *buf++ = SLINKCMD_SET_ZIP_OUT_LEVEL;
1149 *buf++ = 0; /* | */
1150 *buf++ = 1; /* \ len is 1 */
1151 *buf++ = General.compression_level;
1152 *buf++ = SLINKCMD_START_ZIP_IN;
1153 *buf++ = SLINKCMD_START_ZIP_OUT;
1154 }
1155 #ifdef HAVE_LIBCRYPTO
1156 if (IsCapable(server, CAP_ENC))
1157 {
1158 /* Decryption settings */
1159 *buf++ = SLINKCMD_SET_CRYPT_IN_CIPHER;
1160 *buf++ = 0; /* / (upper 8-bits of len) */
1161 *buf++ = 1; /* \ cipher id is 1 byte (lower 8-bits of len) */
1162 *buf++ = lserver->in_cipher->cipherid;
1163 *buf++ = SLINKCMD_SET_CRYPT_IN_KEY;
1164 *buf++ = 0; /* keylen < 256 */
1165 *buf++ = lserver->in_cipher->keylen;
1166 memcpy(buf, lserver->in_key, lserver->in_cipher->keylen);
1167 buf += lserver->in_cipher->keylen;
1168 /* Encryption settings */
1169 *buf++ = SLINKCMD_SET_CRYPT_OUT_CIPHER;
1170 *buf++ = 0; /* / (upper 8-bits of len) */
1171 *buf++ = 1; /* \ cipher id is 1 byte (lower 8-bits of len) */
1172 *buf++ = lserver->out_cipher->cipherid;
1173 *buf++ = SLINKCMD_SET_CRYPT_OUT_KEY;
1174 *buf++ = 0; /* keylen < 256 */
1175 *buf++ = lserver->out_cipher->keylen;
1176 memcpy(buf, lserver->out_key, lserver->out_cipher->keylen);
1177 buf += lserver->out_cipher->keylen;
1178 *buf++ = SLINKCMD_START_CRYPT_IN;
1179 *buf++ = SLINKCMD_START_CRYPT_OUT;
1180 }
1181 #endif
1182
1183 /* pass the whole recvq to servlink */
1184 DLINK_FOREACH (ptr, lserver->buf_recvq.blocks.head)
1185 {
1186 block = ptr->data;
1187 *buf++ = SLINKCMD_INJECT_RECVQ;
1188 *buf++ = (block->size >> 8);
1189 *buf++ = (block->size & 0xff);
1190 memcpy(buf, &block->data[0], block->size);
1191 buf += block->size;
1192 }
1193 dbuf_clear(&lserver->buf_recvq);
1194
1195 /* pass the whole sendq to servlink */
1196 DLINK_FOREACH (ptr, lserver->buf_sendq.blocks.head)
1197 {
1198 block = ptr->data;
1199 *buf++ = SLINKCMD_INJECT_SENDQ;
1200 *buf++ = (block->size >> 8);
1201 *buf++ = (block->size & 0xff);
1202 memcpy(buf, &block->data[0], block->size);
1203 buf += block->size;
1204 }
1205 dbuf_clear(&lserver->buf_sendq);
1206
1207 /* start io */
1208 *buf++ = SLINKCMD_INIT;
1209
1210 /* schedule a write */
1211 send_queued_slink_write(server);
1212 }
1213
1214 /* fork_server()
1215 *
1216 * inputs - struct Client *server
1217 * output - success: 0 / failure: -1
1218 * side effect - fork, and exec SERVLINK to handle this connection
1219 */
1220 static int
1221 fork_server(struct Client *server)
1222 {
1223 #ifndef HAVE_SOCKETPAIR
1224 return -1;
1225 #else
1226 int i;
1227 int slink_fds[2][2];
1228 /* 0? - ctrl | 1? - data
1229 * ?0 - child | ?1 - parent */
1230
1231 if (socketpair(AF_UNIX, SOCK_STREAM, 0, slink_fds[0]) < 0)
1232 return -1;
1233 if (socketpair(AF_UNIX, SOCK_STREAM, 0, slink_fds[1]) < 0)
1234 goto free_ctrl_fds;
1235
1236 if ((i = fork()) < 0)
1237 {
1238 close(slink_fds[1][0]); close(slink_fds[1][1]);
1239 free_ctrl_fds:
1240 close(slink_fds[0][0]); close(slink_fds[0][1]);
1241 return -1;
1242 }
1243
1244 if (i == 0)
1245 {
1246 char fd_str[3][6]; /* store 3x sizeof("65535") */
1247 char *kid_argv[7];
1248
1249 #ifdef O_ASYNC
1250 fcntl(server->localClient->fd.fd, F_SETFL,
1251 fcntl(server->localClient->fd.fd, F_GETFL, 0) & ~O_ASYNC);
1252 #endif
1253 close_fds(&server->localClient->fd);
1254 close(slink_fds[0][1]);
1255 close(slink_fds[1][1]);
1256
1257 sprintf(fd_str[0], "%d", slink_fds[0][0]);
1258 sprintf(fd_str[1], "%d", slink_fds[1][0]);
1259 sprintf(fd_str[2], "%d", server->localClient->fd.fd);
1260
1261 kid_argv[0] = "-slink";
1262 kid_argv[1] = kid_argv[2] = fd_str[0]; /* ctrl */
1263 kid_argv[3] = kid_argv[4] = fd_str[1]; /* data */
1264 kid_argv[5] = fd_str[2]; /* network */
1265 kid_argv[6] = NULL;
1266
1267 execv(General.servlink_path, kid_argv);
1268
1269 _exit(1);
1270 }
1271
1272 /* close the network fd and the child ends of the pipes */
1273 fd_close(&server->localClient->fd);
1274 close(slink_fds[0][0]);
1275 close(slink_fds[1][0]);
1276
1277 execute_callback(setup_socket_cb, slink_fds[0][1]);
1278 execute_callback(setup_socket_cb, slink_fds[1][1]);
1279
1280 fd_open(&server->localClient->ctrlfd, slink_fds[0][1], 1, "slink ctrl");
1281 fd_open(&server->localClient->fd, slink_fds[1][1], 1, "slink data");
1282
1283 read_ctrl_packet(&server->localClient->ctrlfd, server);
1284 read_packet(&server->localClient->fd, server);
1285
1286 return 0;
1287 #endif
1288 }
1289
1290 /* server_burst()
1291 *
1292 * inputs - struct Client pointer server
1293 * -
1294 * output - none
1295 * side effects - send a server burst
1296 * bugs - still too long
1297 */
1298 static void
1299 server_burst(struct Client *client_p)
1300 {
1301 /* Send it in the shortened format with the TS, if
1302 ** it's a TS server; walk the list of channels, sending
1303 ** all the nicks that haven't been sent yet for each
1304 ** channel, then send the channel itself -- it's less
1305 ** obvious than sending all nicks first, but on the
1306 ** receiving side memory will be allocated more nicely
1307 ** saving a few seconds in the handling of a split
1308 ** -orabidoo
1309 */
1310 burst_all(client_p);
1311
1312 /* We send the time we started the burst, and let the remote host determine an EOB time,
1313 ** as otherwise we end up sending a EOB of 0 Sending here means it gets sent last -- fl
1314 */
1315 /* Its simpler to just send EOB and use the time its been connected.. --fl_ */
1316 if (IsCapable(client_p, CAP_EOB))
1317 sendto_one(client_p, ":%s EOB", ID_or_name(&me, client_p));
1318
1319 /* Always send a PING after connect burst is done */
1320 sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
1321 }
1322
1323 /* burst_all()
1324 *
1325 * inputs - pointer to server to send burst to
1326 * output - NONE
1327 * side effects - complete burst of channels/nicks is sent to client_p
1328 */
1329 void
1330 burst_all(struct Client *client_p)
1331 {
1332 dlink_node *ptr;
1333 struct ConnectConf *conf = client_p->serv->sconf;
1334 struct Client *target_p;
1335
1336 /* Pass on my client information to the new server
1337 **
1338 ** First, pass only servers (idea is that if the link gets
1339 ** cancelled beacause the server was already there,
1340 ** there are no NICK's to be cancelled...). Of course,
1341 ** if cancellation occurs, all this info is sent anyway,
1342 ** and I guess the link dies when a read is attempted...? --msa
1343 **
1344 ** Note: Link cancellation to occur at this point means
1345 ** that at least two servers from my fragment are building
1346 ** up connection this other fragment at the same time, it's
1347 ** a race condition, not the normal way of operation...
1348 **
1349 ** ALSO NOTE: using the get_client_name for server names--
1350 ** see previous *WARNING*!!! (Also, original inpath
1351 ** is destroyed...)
1352 */
1353 DLINK_FOREACH_PREV(ptr, global_serv_list.tail)
1354 {
1355 target_p = ptr->data;
1356
1357 // target_p->from == target_p for target_p == client_p
1358 if (target_p->from == client_p)
1359 continue;
1360
1361 if (match(my_name_for_link(conf), target_p->name))
1362 continue;
1363
1364 if (IsCapable(client_p, CAP_TS6))
1365 {
1366 if (HasID(target_p))
1367 sendto_one(client_p, ":%s SID %s %d %s :%s%s",
1368 ID(target_p->servptr), target_p->name, target_p->hopcount+1,
1369 target_p->id, IsHidden(target_p) ? "(H) " : "",
1370 target_p->info);
1371 else // introducing non-ts6 server
1372 sendto_one(client_p, ":%s SERVER %s %d :%s%s",
1373 ID(target_p->servptr), target_p->name, target_p->hopcount+1,
1374 IsHidden(target_p) ? "(H) " : "", target_p->info);
1375 }
1376 else
1377 sendto_one(client_p, ":%s SERVER %s %d :%s%s",
1378 target_p->servptr->name, target_p->name, target_p->hopcount+1,
1379 IsHidden(target_p) ? "(H) " : "", target_p->info);
1380 }
1381
1382 DLINK_FOREACH(ptr, global_channel_list.head)
1383 {
1384 struct Channel *chptr = ptr->data;
1385
1386 if (dlink_list_length(&chptr->members) != 0)
1387 {
1388 burst_members(client_p, chptr);
1389 send_channel_modes(client_p, chptr);
1390
1391 if (IsCapable(client_p, CAP_TBURST) ||
1392 IsCapable(client_p, CAP_TB))
1393 send_tb(client_p, chptr);
1394 }
1395 }
1396
1397 /* also send out those that are not on any channel
1398 */
1399 DLINK_FOREACH(ptr, global_client_list.head)
1400 {
1401 target_p = ptr->data;
1402
1403 if (!IsBursted(target_p) && target_p->from != client_p)
1404 sendnick_TS(client_p, target_p);
1405
1406 ClearBursted(target_p);
1407 }
1408 }
1409
1410 /*
1411 * send_tb
1412 *
1413 * inputs - pointer to Client
1414 * - pointer to channel
1415 * output - NONE
1416 * side effects - Called on a server burst when
1417 * server is CAP_TB|CAP_TBURST capable
1418 */
1419 static void
1420 send_tb(struct Client *client_p, const struct Channel *chptr)
1421 {
1422 /*
1423 * XXX - Logic here isn't right either. What if the topic got unset?
1424 * We would need to send an empty TOPIC to reset the topic from the
1425 * other side
1426 */
1427 if (chptr->topic != NULL)
1428 {
1429 if (IsCapable(client_p, CAP_TBURST))
1430 sendto_one(client_p, ":%s TBURST %lu %s %lu %s :%s",
1431 me.name, (unsigned long)chptr->channelts, chptr->chname,
1432 (unsigned long)chptr->topic_time, chptr->topic_info,
1433 chptr->topic);
1434 else if (IsCapable(client_p, CAP_TB))
1435 {
1436 if (Channel.burst_topicwho)
1437 sendto_one(client_p, ":%s TB %s %lu %s :%s",
1438 me.name, chptr->chname,
1439 (unsigned long)chptr->topic_time,
1440 chptr->topic_info, chptr->topic);
1441 else
1442 sendto_one(client_p, ":%s TB %s %lu :%s",
1443 me.name, chptr->chname,
1444 (unsigned long)chptr->topic_time, chptr->topic);
1445 }
1446 }
1447 }
1448
1449 /* burst_members()
1450 *
1451 * inputs - pointer to server to send members to
1452 * - dlink_list pointer to membership list to send
1453 * output - NONE
1454 * side effects -
1455 */
1456 static void
1457 burst_members(struct Client *client_p, struct Channel *chptr)
1458 {
1459 struct Client *target_p;
1460 struct Membership *ms;
1461 dlink_node *ptr;
1462
1463 DLINK_FOREACH(ptr, chptr->members.head)
1464 {
1465 ms = ptr->data;
1466 target_p = ms->client_p;
1467
1468 if (!IsBursted(target_p))
1469 {
1470 SetBursted(target_p);
1471
1472 if (target_p->from != client_p)
1473 sendnick_TS(client_p, target_p);
1474 }
1475 }
1476 }
1477
1478 /*
1479 * serv_connect()
1480 *
1481 * Initializes a server connection.
1482 *
1483 * inputs:
1484 * conf - pointer to conf
1485 * by - pointer to client doing the connect
1486 * connect_port - which port to open connection to
1487 * output: 1 if the connection is attempted, 0 if it fails somewhere.
1488 */
1489 int
1490 serv_connect(struct ConnectConf *conf, struct Client *by, int connect_port)
1491 {
1492 struct Client *client_p;
1493 struct irc_ssaddr *vhost = NULL;
1494
1495 /*
1496 * Make sure this server isn't already connected
1497 * Note: aconf should ALWAYS be a valid C: line
1498 */
1499 if ((client_p = find_server(conf->name)) != NULL)
1500 {
1501 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1502 "Server %s already present from %s",
1503 conf->name, get_client_name(client_p, SHOW_IP));
1504 sendto_realops_flags(UMODE_ALL, L_OPER,
1505 "Server %s already present from %s",
1506 conf->name, get_client_name(client_p, MASK_IP));
1507 /*
1508 * 'by' can be a NULL pointer if called by try_connections()
1509 */
1510 if (by && IsClient(by) && !MyClient(by))
1511 sendto_one(by, ":%s NOTICE %s :Server %s already present from %s",
1512 me.name, by->name, conf->name,
1513 get_client_name(client_p, MASK_IP));
1514 return 0;
1515 }
1516
1517 if (find_servconn_in_progress(conf->name))
1518 return 0;
1519
1520 ilog(L_NOTICE, "Connect to %s[%s] by %s", conf->name, conf->host,
1521 !by ? "AutoConn." : ((by->localClient && by->localClient->auth_oper) ?
1522 by->localClient->auth_oper : by->name));
1523
1524 // Create a local client
1525 client_p = make_client(NULL);
1526
1527 // Copy in the server, hostname, fd
1528 strlcpy(client_p->name, conf->name, sizeof(client_p->name));
1529 strlcpy(client_p->host, conf->host, sizeof(client_p->host));
1530 client_p->localClient->aftype = conf->aftype;
1531
1532 // servernames are always guaranteed under HOSTLEN chars
1533 fd_note(&client_p->localClient->fd, "Server: %s", conf->name);
1534
1535 /* Attach config entries to client here rather than in
1536 * serv_connect_callback(). This to avoid null pointer references.
1537 */
1538 make_server(client_p);
1539 client_p->serv->sconf = ref_link_by_ptr(conf);
1540
1541 if (by && IsClient(by))
1542 strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
1543 else
1544 strlcpy(client_p->serv->by, "AutoConn.", sizeof(client_p->serv->by));
1545
1546 SetConnecting(client_p);
1547 dlinkAdd(client_p, &client_p->node, &global_client_list);
1548
1549 // create a socket for the server connection
1550 if (comm_open(&client_p->localClient->fd, client_p->localClient->aftype,
1551 SOCK_STREAM, 0, NULL) < 0)
1552 {
1553 // Eek, failure to create the socket
1554 report_error(L_ALL,
1555 "opening stream socket to %s: %s", client_p->name, errno);
1556 exit_client(client_p, &me, "Connection failed");
1557 return 0;
1558 }
1559
1560 if (conf->aftype == conf->vhost.ss.sin_family)
1561 vhost = &conf->vhost;
1562 else if (ServerInfo.vhost.ss.sin_family == conf->aftype)
1563 vhost = &ServerInfo.vhost;
1564 #ifdef IPV6
1565 else if (ServerInfo.vhost6.ss.sin_family == conf->aftype)
1566 vhost = &ServerInfo.vhost6;
1567 #endif
1568
1569 comm_connect_tcp(&client_p->localClient->fd, conf->host, connect_port,
1570 (struct sockaddr *) vhost, vhost ? vhost->ss_len : 0,
1571 serv_connect_callback, client_p, conf->aftype,
1572 CONNECTTIMEOUT);
1573
1574 return 1;
1575 }
1576
1577 /* serv_connect_callback() - complete a server connection.
1578 *
1579 * This routine is called after the server connection attempt has
1580 * completed. If unsucessful, an error is sent to ops and the client
1581 * is closed. If sucessful, it goes through the initialisation/check
1582 * procedures, the capabilities are sent, and the socket is then
1583 * marked for reading.
1584 */
1585 static void
1586 serv_connect_callback(fde_t *fd, int status, void *data)
1587 {
1588 struct Client *client_p = data;
1589 struct ConnectConf *conf;
1590
1591 // First, make sure its a real client! */
1592 assert(client_p != NULL);
1593 assert(&client_p->localClient->fd == fd);
1594
1595 // Next, for backward purposes, record the ip of the server */
1596 memcpy(&client_p->localClient->ip, &fd->connect.hostaddr,
1597 sizeof(struct irc_ssaddr));
1598 irc_getnameinfo((struct sockaddr *) &client_p->localClient->ip,
1599 client_p->localClient->ip.ss_len, client_p->sockhost,
1600 sizeof(client_p->sockhost), NULL, 0, NI_NUMERICHOST);
1601
1602 // Check the status
1603 if (status != COMM_OK || IsDead(client_p))
1604 {
1605 /* We have an error, so report it and quit
1606 * Admins get to see any IP, mere opers don't *sigh*
1607 */
1608 if (ServerHide.hide_server_ips)
1609 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1610 "Error connecting to %s: %s",
1611 client_p->name, comm_errstr(status));
1612 else
1613 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1614 "Error connecting to %s[%s]: %s", client_p->name,
1615 client_p->host, comm_errstr(status));
1616
1617 sendto_realops_flags(UMODE_ALL, L_OPER,
1618 "Error connecting to %s: %s",
1619 client_p->name, comm_errstr(status));
1620
1621 /* If a fd goes bad, call dead_link() the socket is no
1622 * longer valid for reading or writing.
1623 */
1624 dead_link_on_write(client_p, 0);
1625 return;
1626 }
1627
1628 // COMM_OK, so continue the connection procedure
1629 // Get the connect block
1630 conf = client_p->serv->sconf;
1631 assert(conf != NULL);
1632
1633 // Next, send the initial handshake
1634 SetHandshake(client_p);
1635
1636 #ifdef HAVE_LIBCRYPTO
1637 // Handle all CRYPTLINK links in cryptlink_init
1638 if ((conf->flags & LINK_CRYPTLINK))
1639 {
1640 cryptlink_init(client_p, conf, fd);
1641 return;
1642 }
1643 #endif
1644
1645 if (!EmptyString(conf->send_password) && me.id[0])
1646 // Send TS 6 form only if id
1647 sendto_one(client_p, "PASS %s TS %d %s",
1648 conf->send_password, TS_CURRENT, me.id);
1649 else
1650 sendto_one(client_p, "PASS %s TS 5",
1651 conf->send_password);
1652
1653 /* Pass my info to the new server
1654 *
1655 * If this is a HUB, pass on CAP_HUB
1656 * Pass on ZIP if supported
1657 * Pass on TB if supported.
1658 * - Dianora
1659 *
1660 * TODO: Use a callback instead of hardcoding flag<->cap relations.
1661 */
1662 send_capabilities(client_p, conf, (ServerInfo.hub ? CAP_HUB : 0)
1663 | ((conf->flags & LINK_COMPRESSED) ? CAP_ZIP : 0)
1664 | ((conf->flags & LINK_TOPICBURST) ? CAP_TBURST|CAP_TB : 0), 0);
1665
1666 sendto_one(client_p, "SERVER %s 1 :%s%s",
1667 my_name_for_link(conf), // XXX
1668 ServerHide.hidden ? "(H) " : "", me.info);
1669
1670 /* If we've been marked dead because a send failed, just exit
1671 * here now and save everyone the trouble of us ever existing.
1672 */
1673 if (IsDead(client_p))
1674 {
1675 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1676 "%s[%s] went dead during handshake",
1677 client_p->name, client_p->host);
1678 sendto_realops_flags(UMODE_ALL, L_OPER,
1679 "%s went dead during handshake", client_p->name);
1680 return;
1681 }
1682
1683 // don't move to serv_list yet -- we haven't sent a burst!
1684 // If we get here, we're ok, so lets start reading some data
1685 comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
1686 }
1687
1688 struct Client *
1689 find_servconn_in_progress(const char *name)
1690 {
1691 dlink_node *ptr;
1692 struct Client *cptr;
1693
1694 DLINK_FOREACH(ptr, unknown_list.head)
1695 {
1696 cptr = ptr->data;
1697
1698 if (cptr && cptr->name[0])
1699 if (match(cptr->name, name) || match(name, cptr->name))
1700 return cptr;
1701 }
1702
1703 return NULL;
1704 }
1705
1706 #ifdef HAVE_LIBCRYPTO
1707 /*
1708 * sends a CRYPTLINK SERV command.
1709 */
1710 void
1711 cryptlink_init(struct Client *client_p, struct ConnectConf *conf, fde_t *fd)
1712 {
1713 char *encrypted;
1714 unsigned char *key_to_send;
1715 char randkey[CIPHERKEYLEN];
1716 int enc_len;
1717
1718 // get key
1719 if ((!ServerInfo.rsa_private_key) ||
1720 (!RSA_check_key(ServerInfo.rsa_private_key)) )
1721 {
1722 cryptlink_error(client_p, "SERV", "Invalid RSA private key",
1723 "Invalid RSA private key");
1724 return;
1725 }
1726
1727 if (conf->rsa_public_key == NULL)
1728 {
1729 cryptlink_error(client_p, "SERV", "Invalid RSA public key",
1730 "Invalid RSA public key");
1731 return;
1732 }
1733
1734 if (get_randomness((unsigned char *)randkey, CIPHERKEYLEN) != 1)
1735 {
1736 cryptlink_error(client_p, "SERV", "Couldn't generate keyphrase",
1737 "Couldn't generate keyphrase");
1738 return;
1739 }
1740
1741 encrypted = MyMalloc(RSA_size(ServerInfo.rsa_private_key));
1742 enc_len = RSA_public_encrypt(CIPHERKEYLEN,
1743 (unsigned char *)randkey,
1744 (unsigned char *)encrypted,
1745 conf->rsa_public_key,
1746 RSA_PKCS1_PADDING);
1747
1748 memcpy(client_p->localClient->in_key, randkey, CIPHERKEYLEN);
1749
1750 if (enc_len <= 0)
1751 {
1752 report_crypto_errors();
1753 MyFree(encrypted);
1754 cryptlink_error(client_p, "SERV", "Couldn't encrypt data",
1755 "Couldn't encrypt data");
1756 return;
1757 }
1758
1759 if (!(base64_block(&key_to_send, encrypted, enc_len)))
1760 {
1761 MyFree(encrypted);
1762 cryptlink_error(client_p, "SERV", "Couldn't base64 encode key",
1763 "Couldn't base64 encode key");
1764 return;
1765 }
1766
1767 send_capabilities(client_p, conf, (ServerInfo.hub ? CAP_HUB : 0)
1768 | ((conf->flags & LINK_COMPRESSED) ? CAP_ZIP : 0)
1769 | ((conf->flags & LINK_TOPICBURST) ? CAP_TBURST|CAP_TB : 0),
1770 CAP_ENC_MASK);
1771
1772 if (me.id[0] != '\0')
1773 sendto_one(client_p, "PASS . TS %d %s", TS_CURRENT, me.id);
1774
1775 sendto_one(client_p, "CRYPTLINK SERV %s %s :%s%s",
1776 my_name_for_link(conf), key_to_send, // XXX
1777 ServerHide.hidden ? "(H) " : "", me.info);
1778
1779 SetHandshake(client_p);
1780 SetWaitAuth(client_p);
1781
1782 MyFree(encrypted);
1783 MyFree(key_to_send);
1784
1785 if (IsDead(client_p))
1786 cryptlink_error(client_p, "SERV", "Went dead during handshake",
1787 "Went dead during handshake");
1788 else if (fd != NULL)
1789 // If we get here, we're ok, so lets start reading some data
1790 comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
1791 }
1792
1793 void
1794 cryptlink_error(struct Client *client_p, const char *type,
1795 const char *reason, const char *client_reason)
1796 {
1797 sendto_realops_flags(UMODE_ALL, L_ADMIN, "%s: CRYPTLINK %s error - %s",
1798 get_client_name(client_p, SHOW_IP), type, reason);
1799 sendto_realops_flags(UMODE_ALL, L_OPER, "%s: CRYPTLINK %s error - %s",
1800 get_client_name(client_p, MASK_IP), type, reason);
1801 ilog(L_ERROR, "%s: CRYPTLINK %s error - %s",
1802 get_client_name(client_p, SHOW_IP), type, reason);
1803
1804 /* If client_reason isn't NULL, then exit the client with the message
1805 * defined in the call.
1806 */
1807 if ((client_reason != NULL) && (!IsDead(client_p)))
1808 exit_client(client_p, &me, client_reason);
1809 }
1810
1811 static char base64_chars[] =
1812 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
1813
1814 static char base64_values[] =
1815 {
1816 /* 00-15 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1817 /* 16-31 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1818 /* 32-47 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
1819 /* 48-63 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1,
1820 /* 64-79 */ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1821 /* 80-95 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
1822 /* 96-111 */ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1823 /* 112-127 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
1824 /* 128-143 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1825 /* 144-159 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1826 /* 160-175 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1827 /* 186-191 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1828 /* 192-207 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1829 /* 208-223 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1830 /* 224-239 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1831 /* 240-255 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
1832 };
1833
1834 /*
1835 * base64_block will allocate and return a new block of memory
1836 * using MyMalloc(). It should be freed after use.
1837 */
1838 int
1839 base64_block(unsigned char **output, char *data, int len)
1840 {
1841 unsigned char *out;
1842 unsigned char *in = (unsigned char*)data;
1843 unsigned long int q_in;
1844 int i;
1845 int count = 0;
1846
1847 out = MyMalloc(((((len + 2) - ((len + 2) % 3)) / 3) * 4) + 1);
1848
1849 /* process 24 bits at a time */
1850 for( i = 0; i < len; i += 3)
1851 {
1852 q_in = 0;
1853
1854 if ( i + 2 < len )
1855 {
1856 q_in = (in[i+2] & 0xc0) << 2;
1857 q_in |= in[i+2];
1858 }
1859
1860 if ( i + 1 < len )
1861 {
1862 q_in |= (in[i+1] & 0x0f) << 10;
1863 q_in |= (in[i+1] & 0xf0) << 12;
1864 }
1865
1866 q_in |= (in[i] & 0x03) << 20;
1867 q_in |= in[i] << 22;
1868
1869 q_in &= 0x3f3f3f3f;
1870
1871 out[count++] = base64_chars[((q_in >> 24) )];
1872 out[count++] = base64_chars[((q_in >> 16) & 0xff)];
1873 out[count++] = base64_chars[((q_in >> 8) & 0xff)];
1874 out[count++] = base64_chars[((q_in ) & 0xff)];
1875 }
1876 if ( (i - len) > 0 )
1877 {
1878 out[count-1] = '=';
1879 if ( (i - len) > 1 )
1880 out[count-2] = '=';
1881 }
1882
1883 out[count] = '\0';
1884 *output = out;
1885 return (count);
1886 }
1887
1888 /*
1889 * unbase64_block will allocate and return a new block of memory
1890 * using MyMalloc(). It should be freed after use.
1891 */
1892 int
1893 unbase64_block(unsigned char **output, char *data, int len)
1894 {
1895 unsigned char *out;
1896 unsigned char *in = (unsigned char*)data;
1897 unsigned long int q_in;
1898 int i;
1899 int count = 0;
1900
1901 if ((len % 4) != 0)
1902 return (0);
1903
1904 out = MyMalloc(((len / 4) * 3) + 1);
1905
1906 /* process 32 bits at a time */
1907 for( i = 0; (i + 3) < len; i+=4)
1908 {
1909 /* compress input (chars a, b, c and d) as follows:
1910 * (after converting ascii -> base64 value)
1911 *
1912 * |00000000aaaaaabbbbbbccccccdddddd|
1913 * | 765432 107654 321076 543210|
1914 */
1915
1916 q_in = 0;
1917
1918 if (base64_values[in[i+3]] > -1)
1919 q_in |= base64_values[in[i+3]] ;
1920 if (base64_values[in[i+2]] > -1)
1921 q_in |= base64_values[in[i+2]] << 6;
1922 if (base64_values[in[i+1]] > -1)
1923 q_in |= base64_values[in[i+1]] << 12;
1924 if (base64_values[in[i ]] > -1)
1925 q_in |= base64_values[in[i ]] << 18;
1926
1927 out[count++] = (q_in >> 16) & 0xff;
1928 out[count++] = (q_in >> 8) & 0xff;
1929 out[count++] = (q_in ) & 0xff;
1930 }
1931
1932 if (in[i-1] == '=') count--;
1933 if (in[i-2] == '=') count--;
1934
1935 out[count] = '\0';
1936 *output = out;
1937 return (count);
1938 }
1939
1940 #endif /* HAVE_LIBCRYPTO */
1941

Properties

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