ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/server.c
Revision: 7033
Committed: Sun Jan 3 14:37:29 2016 UTC (8 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 29097 byte(s)
Log Message:
- Renamed MyCalloc to xcalloc

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2016 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file s_serv.c
23 * \brief Server related functions.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #ifdef HAVE_LIBCRYPTO
29 #include <openssl/rsa.h>
30 #include "rsa.h"
31 #endif
32 #include "list.h"
33 #include "client.h"
34 #include "event.h"
35 #include "hash.h"
36 #include "irc_string.h"
37 #include "ircd.h"
38 #include "ircd_defs.h"
39 #include "s_bsd.h"
40 #include "numeric.h"
41 #include "packet.h"
42 #include "conf.h"
43 #include "server.h"
44 #include "log.h"
45 #include "user.h"
46 #include "send.h"
47 #include "memory.h"
48 #include "channel.h"
49 #include "parse.h"
50
51
52 dlink_list flatten_links;
53 static dlink_list server_capabilities_list;
54 static void serv_connect_callback(fde_t *, int, void *);
55
56
57 /*
58 * write_links_file
59 *
60 * inputs - void pointer which is not used
61 * output - NONE
62 * side effects - called from an event, write out list of linked servers
63 * but in no particular order.
64 */
65 void
66 write_links_file(void *unused)
67 {
68 FILE *file = NULL;
69 dlink_node *node = NULL, *node_next = NULL;
70 char buff[IRCD_BUFSIZE] = "";
71
72 if (EmptyString(ConfigServerHide.flatten_links_file))
73 return;
74
75 if ((file = fopen(ConfigServerHide.flatten_links_file, "w")) == NULL)
76 {
77 ilog(LOG_TYPE_IRCD, "Couldn't open \"%s\": %s", ConfigServerHide.flatten_links_file,
78 strerror(errno));
79 return;
80 }
81
82 DLINK_FOREACH_SAFE(node, node_next, flatten_links.head)
83 {
84 dlinkDelete(node, &flatten_links);
85 xfree(node->data);
86 free_dlink_node(node);
87 }
88
89 DLINK_FOREACH(node, global_server_list.head)
90 {
91 const struct Client *target_p = node->data;
92
93 /*
94 * Skip hidden servers, aswell as ourselves, since we already send
95 * ourselves in /links
96 */
97 if (IsHidden(target_p) || IsMe(target_p))
98 continue;
99
100 if (HasFlag(target_p, FLAGS_SERVICE) && ConfigServerHide.hide_services)
101 continue;
102
103 /*
104 * Attempt to format the file in such a way it follows the usual links output
105 * ie "servername uplink :hops info"
106 * Mostly for aesthetic reasons - makes it look pretty in mIRC ;)
107 * - madmax
108 */
109 snprintf(buff, sizeof(buff), "%s %s :1 %s", target_p->name,
110 me.name, target_p->info);
111 dlinkAddTail(xstrdup(buff), make_dlink_node(), &flatten_links);
112 snprintf(buff, sizeof(buff), "%s %s :1 %s\n", target_p->name,
113 me.name, target_p->info);
114
115 fputs(buff, file);
116 }
117
118 fclose(file);
119 }
120
121 void
122 read_links_file(void)
123 {
124 FILE *file = NULL;
125 char *p = NULL;
126 char buff[IRCD_BUFSIZE] = "";
127
128 if (EmptyString(ConfigServerHide.flatten_links_file))
129 return;
130
131 if ((file = fopen(ConfigServerHide.flatten_links_file, "r")) == NULL)
132 {
133 ilog(LOG_TYPE_IRCD, "Couldn't open \"%s\": %s", ConfigServerHide.flatten_links_file,
134 strerror(errno));
135 return;
136 }
137
138 while (fgets(buff, sizeof(buff), file))
139 {
140 if ((p = strchr(buff, '\n')))
141 *p = '\0';
142
143 dlinkAddTail(xstrdup(buff), make_dlink_node(), &flatten_links);
144 }
145
146 fclose(file);
147 }
148
149 /* hunt_server()
150 * Do the basic thing in delivering the message (command)
151 * across the relays to the specific server (server) for
152 * actions.
153 *
154 * Note: The command is a format string and *MUST* be
155 * of prefixed style (e.g. ":%s COMMAND %s ...").
156 * Command can have only max 8 parameters.
157 *
158 * server parv[server] is the parameter identifying the
159 * target server.
160 *
161 * *WARNING*
162 * parv[server] is replaced with the pointer to the
163 * real servername from the matched client (I'm lazy
164 * now --msa).
165 *
166 * returns: (see #defines)
167 */
168 int
169 hunt_server(struct Client *source_p, const char *command,
170 const int server, const int parc, char *parv[])
171 {
172 struct Client *target_p = NULL;
173 dlink_node *node = NULL;
174
175 /* Assume it's me, if no server */
176 if (parc <= server || EmptyString(parv[server]))
177 return HUNTED_ISME;
178
179 if ((target_p = find_person(source_p, parv[server])) == NULL)
180 target_p = hash_find_server(parv[server]);
181
182 /*
183 * These are to pickup matches that would cause the following
184 * message to go in the wrong direction while doing quick fast
185 * non-matching lookups.
186 */
187 if (target_p)
188 if (target_p->from == source_p->from && !MyConnect(target_p))
189 target_p = NULL;
190
191 if (!target_p && has_wildcards(parv[server]))
192 {
193 DLINK_FOREACH(node, global_server_list.head)
194 {
195 struct Client *tmp = node->data;
196
197 assert(IsMe(tmp) || IsServer(tmp));
198 if (!match(parv[server], tmp->name))
199 {
200 if (tmp->from == source_p->from && !MyConnect(tmp))
201 continue;
202
203 target_p = node->data;
204 break;
205 }
206 }
207
208 if (!target_p)
209 {
210 DLINK_FOREACH(node, global_client_list.head)
211 {
212 struct Client *tmp = node->data;
213
214 assert(IsMe(tmp) || IsServer(tmp) || IsClient(tmp));
215 if (!match(parv[server], tmp->name))
216 {
217 if (tmp->from == source_p->from && !MyConnect(tmp))
218 continue;
219
220 target_p = node->data;
221 break;
222 }
223 }
224 }
225 }
226
227 if (target_p)
228 {
229 assert(IsMe(target_p) || IsServer(target_p) || IsClient(target_p));
230 if (IsMe(target_p) || MyClient(target_p))
231 return HUNTED_ISME;
232
233 parv[server] = target_p->id;
234 sendto_one(target_p, command, source_p->id,
235 parv[1], parv[2], parv[3], parv[4],
236 parv[5], parv[6], parv[7], parv[8]);
237 return HUNTED_PASS;
238 }
239
240 sendto_one_numeric(source_p, &me, ERR_NOSUCHSERVER, parv[server]);
241 return HUNTED_NOSUCH;
242 }
243
244 /* try_connections()
245 *
246 * inputs - void pointer which is not used
247 * output - NONE
248 * side effects -
249 * scan through configuration and try new connections.
250 * Returns the calendar time when the next call to this
251 * function should be made latest. (No harm done if this
252 * is called earlier or later...)
253 */
254 void
255 try_connections(void *unused)
256 {
257 dlink_node *node = NULL;
258
259 if (GlobalSetOptions.autoconn == 0)
260 return;
261
262 DLINK_FOREACH(node, server_items.head)
263 {
264 struct MaskItem *conf = node->data;
265
266 assert(conf->type == CONF_SERVER);
267
268 /* Also when already connecting! (update holdtimes) --SRB */
269 if (!conf->port || !IsConfAllowAutoConn(conf))
270 continue;
271
272 /*
273 * Skip this entry if the use of it is still on hold until
274 * future. Otherwise handle this entry (and set it on hold
275 * until next time). Will reset only hold times, if already
276 * made one successfull connection... [this algorithm is
277 * a bit fuzzy... -- msa >;) ]
278 */
279 if (conf->until > CurrentTime)
280 continue;
281
282 assert(conf->class);
283
284 conf->until = CurrentTime + conf->class->con_freq;
285
286 /*
287 * Found a CONNECT config with port specified, scan clients
288 * and see if this server is already connected?
289 */
290 if (hash_find_server(conf->name))
291 continue;
292
293 if (conf->class->ref_count < conf->class->max_total)
294 {
295 /* Move this entry to the end of the list, if not already last */
296 if (node->next)
297 {
298 dlinkDelete(node, &server_items);
299 dlinkAddTail(conf, &conf->node, &server_items);
300 }
301
302 if (find_servconn_in_progress(conf->name))
303 return;
304
305 /*
306 * We used to only print this if serv_connect() actually
307 * succeeded, but since comm_tcp_connect() can call the callback
308 * immediately if there is an error, we were getting error messages
309 * in the wrong order. SO, we just print out the activated line,
310 * and let serv_connect() / serv_connect_callback() print an
311 * error afterwards if it fails.
312 * -- adrian
313 */
314 if (ConfigServerHide.hide_server_ips)
315 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
316 "Connection to %s activated.",
317 conf->name);
318 else
319 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
320 "Connection to %s[%s] activated.",
321 conf->name, conf->host);
322
323 serv_connect(conf, NULL);
324 /* We connect only one at time... */
325 return;
326 }
327 }
328 }
329
330 int
331 valid_servname(const char *name)
332 {
333 unsigned int dots = 0;
334 const char *p = name;
335
336 for (; *p; ++p)
337 {
338 if (!IsServChar(*p))
339 return 0;
340
341 if (*p == '.')
342 ++dots;
343 }
344
345 return dots && (p - name) <= HOSTLEN;
346 }
347
348 int
349 check_server(const char *name, struct Client *client_p)
350 {
351 dlink_node *node = NULL;
352 struct MaskItem *conf = NULL;
353 struct MaskItem *server_conf = NULL;
354 int error = -1;
355
356 assert(client_p);
357
358 /* Loop through looking for all possible connect items that might work */
359 DLINK_FOREACH(node, server_items.head)
360 {
361 conf = node->data;
362
363 if (match(name, conf->name))
364 continue;
365
366 error = -3;
367
368 if (!match(conf->host, client_p->host) ||
369 !match(conf->host, client_p->sockhost))
370 {
371 error = -2;
372
373 if (!match_conf_password(client_p->connection->password, conf))
374 return -2;
375
376 if (!EmptyString(conf->certfp))
377 if (EmptyString(client_p->certfp) || strcasecmp(client_p->certfp, conf->certfp))
378 return -4;
379
380 server_conf = conf;
381 }
382 }
383
384 if (server_conf == NULL)
385 return error;
386
387 attach_conf(client_p, server_conf);
388
389 switch (server_conf->aftype)
390 {
391 case AF_INET6:
392 {
393 const struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&server_conf->addr;
394
395 if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr))
396 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
397 break;
398 }
399 case AF_INET:
400 {
401 const struct sockaddr_in *v4 = (struct sockaddr_in *)&server_conf->addr;
402
403 if (v4->sin_addr.s_addr == INADDR_NONE)
404 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
405 break;
406 }
407 }
408
409 return 0;
410 }
411
412 /* add_capability()
413 *
414 * inputs - string name of CAPAB
415 * - int flag of capability
416 * output - NONE
417 * side effects - Adds given capability name and bit mask to
418 * current supported capabilities. This allows
419 * modules to dynamically add or subtract their capability.
420 */
421 void
422 add_capability(const char *name, unsigned int flag)
423 {
424 struct Capability *cap = xcalloc(sizeof(*cap));
425
426 cap->name = xstrdup(name);
427 cap->cap = flag;
428 dlinkAdd(cap, &cap->node, &server_capabilities_list);
429 }
430
431 /* delete_capability()
432 *
433 * inputs - string name of CAPAB
434 * output - NONE
435 * side effects - delete given capability from ones known.
436 */
437 void
438 delete_capability(const char *name)
439 {
440 dlink_node *node = NULL, *node_next = NULL;
441
442 DLINK_FOREACH_SAFE(node, node_next, server_capabilities_list.head)
443 {
444 struct Capability *cap = node->data;
445
446 if (!irccmp(cap->name, name))
447 {
448 dlinkDelete(node, &server_capabilities_list);
449 xfree(cap->name);
450 xfree(cap);
451 }
452 }
453 }
454
455 /*
456 * find_capability()
457 *
458 * inputs - string name of capab to find
459 * output - 0 if not found CAPAB otherwise
460 * side effects - none
461 */
462 unsigned int
463 find_capability(const char *name)
464 {
465 const dlink_node *node = NULL;
466
467 DLINK_FOREACH(node, server_capabilities_list.head)
468 {
469 const struct Capability *cap = node->data;
470
471 if (!irccmp(cap->name, name))
472 return cap->cap;
473 }
474
475 return 0;
476 }
477
478 /* send_capabilities()
479 *
480 * inputs - Client pointer to send to
481 * - int flag of capabilities that this server can send
482 * output - NONE
483 * side effects - send the CAPAB line to a server -orabidoo
484 *
485 */
486 void
487 send_capabilities(struct Client *client_p)
488 {
489 char buf[IRCD_BUFSIZE] = "";
490 const dlink_node *node = NULL;
491
492 DLINK_FOREACH(node, server_capabilities_list.head)
493 {
494 const struct Capability *cap = node->data;
495
496 strlcat(buf, cap->name, sizeof(buf));
497
498 if (node->next)
499 strlcat(buf, " ", sizeof(buf));
500 }
501
502 sendto_one(client_p, "CAPAB :%s", buf);
503 }
504
505 /*
506 * show_capabilities - show current server capabilities
507 *
508 * inputs - pointer to a struct Client
509 * output - pointer to static string
510 * side effects - build up string representing capabilities of server listed
511 */
512 const char *
513 show_capabilities(const struct Client *target_p)
514 {
515 static char msgbuf[IRCD_BUFSIZE] = "";
516 const dlink_node *node = NULL;
517
518 strlcpy(msgbuf, "TS", sizeof(msgbuf));
519
520 DLINK_FOREACH(node, server_capabilities_list.head)
521 {
522 const struct Capability *cap = node->data;
523
524 if (!IsCapable(target_p, cap->cap))
525 continue;
526
527 strlcat(msgbuf, " ", sizeof(msgbuf));
528 strlcat(msgbuf, cap->name, sizeof(msgbuf));
529 }
530
531 return msgbuf;
532 }
533
534 /* make_server()
535 *
536 * inputs - pointer to client struct
537 * output - pointer to struct Server
538 * side effects - add's an Server information block to a client
539 * if it was not previously allocated.
540 */
541 struct Server *
542 make_server(struct Client *client_p)
543 {
544 if (client_p->serv == NULL)
545 client_p->serv = xcalloc(sizeof(struct Server));
546
547 return client_p->serv;
548 }
549
550 /* New server connection code
551 * Based upon the stuff floating about in s_bsd.c
552 * -- adrian
553 */
554
555 /* serv_connect() - initiate a server connection
556 *
557 * inputs - pointer to conf
558 * - pointer to client doing the connect
559 * output -
560 * side effects -
561 *
562 * This code initiates a connection to a server. It first checks to make
563 * sure the given server exists. If this is the case, it creates a socket,
564 * creates a client, saves the socket information in the client, and
565 * initiates a connection to the server through comm_connect_tcp(). The
566 * completion of this goes through serv_completed_connection().
567 *
568 * We return 1 if the connection is attempted, since we don't know whether
569 * it suceeded or not, and 0 if it fails in here somewhere.
570 */
571 int
572 serv_connect(struct MaskItem *conf, struct Client *by)
573 {
574 struct Client *client_p = NULL;
575 char buf[HOSTIPLEN + 1] = "";
576
577 /* conversion structs */
578 struct sockaddr_in *v4;
579
580 /* Make sure conf is useful */
581 assert(conf);
582
583 getnameinfo((const struct sockaddr *)&conf->addr, conf->addr.ss_len,
584 buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
585 ilog(LOG_TYPE_IRCD, "Connect to %s[%s] @%s", conf->name, conf->host,
586 buf);
587
588 /* Still processing a DNS lookup? -> exit */
589 if (conf->dns_pending)
590 {
591 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
592 "Error connecting to %s: DNS lookup for connect{} in progress.",
593 conf->name);
594 return 0;
595 }
596
597 if (conf->dns_failed)
598 {
599 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
600 "Error connecting to %s: DNS lookup for connect{} failed.",
601 conf->name);
602 return 0;
603 }
604
605 /*
606 * Make sure this server isn't already connected.
607 * Note: conf should ALWAYS be a valid connect {} block
608 */
609 if ((client_p = hash_find_server(conf->name)))
610 {
611 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
612 "Server %s already present from %s",
613 conf->name, get_client_name(client_p, SHOW_IP));
614 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
615 "Server %s already present from %s",
616 conf->name, get_client_name(client_p, MASK_IP));
617 if (by && IsClient(by) && !MyClient(by))
618 sendto_one_notice(by, &me, ":Server %s already present from %s",
619 conf->name, get_client_name(client_p, MASK_IP));
620 return 0;
621 }
622
623 /* Create a local client */
624 client_p = make_client(NULL);
625
626 /* Copy in the server, hostname, fd */
627 strlcpy(client_p->name, conf->name, sizeof(client_p->name));
628 strlcpy(client_p->host, conf->host, sizeof(client_p->host));
629
630 /* We already converted the ip once, so lets use it - stu */
631 strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost));
632
633 /* Create a socket for the server connection */
634 if (comm_open(&client_p->connection->fd, conf->addr.ss.ss_family, SOCK_STREAM, 0, NULL) < 0)
635 {
636 /* Eek, failure to create the socket */
637 report_error(L_ALL, "opening stream socket to %s: %s", conf->name, errno);
638
639 SetDead(client_p);
640 exit_client(client_p, "Connection failed");
641 return 0;
642 }
643
644 /* Server names are always guaranteed under HOSTLEN chars */
645 fd_note(&client_p->connection->fd, "Server: %s", client_p->name);
646
647 /*
648 * Attach config entries to client here rather than in serv_connect_callback().
649 * This to avoid null pointer references.
650 */
651 if (!attach_connect_block(client_p, conf->name, conf->host))
652 {
653 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
654 "Host %s is not enabled for connecting: no connect {} block",
655 conf->name);
656 if (by && IsClient(by) && !MyClient(by))
657 sendto_one_notice(by, &me, ":Connect to host %s failed: no connect {} block", client_p->name);
658
659 SetDead(client_p);
660 exit_client(client_p, "Connection failed");
661 return 0;
662 }
663
664 /*
665 * At this point we have a connection in progress and a connect {} block
666 * attached to the client, the socket info should be saved in the client
667 * and it should either be resolved or have a valid address.
668 *
669 * The socket has been connected or connect is in progress.
670 */
671 make_server(client_p);
672
673 if (by && IsClient(by))
674 strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
675 else
676 strlcpy(client_p->serv->by, "AutoConn.", sizeof(client_p->serv->by));
677
678 SetConnecting(client_p);
679 client_p->connection->aftype = conf->aftype;
680
681 /* Now, initiate the connection */
682 /* XXX assume that a non 0 type means a specific bind address
683 * for this connect.
684 */
685 switch (conf->aftype)
686 {
687 case AF_INET:
688 v4 = (struct sockaddr_in*)&conf->bind;
689 if (v4->sin_addr.s_addr)
690 {
691 struct irc_ssaddr ipn;
692 memset(&ipn, 0, sizeof(struct irc_ssaddr));
693 ipn.ss.ss_family = AF_INET;
694 ipn.ss_port = 0;
695 memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
696 comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
697 (struct sockaddr *)&ipn, ipn.ss_len,
698 serv_connect_callback, client_p, conf->aftype,
699 CONNECTTIMEOUT);
700 }
701 else if (ConfigServerInfo.specific_ipv4_vhost)
702 {
703 struct irc_ssaddr ipn;
704 memset(&ipn, 0, sizeof(struct irc_ssaddr));
705 ipn.ss.ss_family = AF_INET;
706 ipn.ss_port = 0;
707 memcpy(&ipn, &ConfigServerInfo.ip, sizeof(struct irc_ssaddr));
708 comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
709 (struct sockaddr *)&ipn, ipn.ss_len,
710 serv_connect_callback, client_p, conf->aftype,
711 CONNECTTIMEOUT);
712 }
713 else
714 comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
715 NULL, 0, serv_connect_callback, client_p, conf->aftype,
716 CONNECTTIMEOUT);
717 break;
718 case AF_INET6:
719 {
720 struct irc_ssaddr ipn;
721 struct sockaddr_in6 *v6;
722 struct sockaddr_in6 *v6conf;
723
724 memset(&ipn, 0, sizeof(struct irc_ssaddr));
725 v6conf = (struct sockaddr_in6 *)&conf->bind;
726 v6 = (struct sockaddr_in6 *)&ipn;
727
728 if (memcmp(&v6conf->sin6_addr, &v6->sin6_addr, sizeof(struct in6_addr)))
729 {
730 memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
731 ipn.ss.ss_family = AF_INET6;
732 ipn.ss_port = 0;
733 comm_connect_tcp(&client_p->connection->fd,
734 conf->host, conf->port,
735 (struct sockaddr *)&ipn, ipn.ss_len,
736 serv_connect_callback, client_p,
737 conf->aftype, CONNECTTIMEOUT);
738 }
739 else if (ConfigServerInfo.specific_ipv6_vhost)
740 {
741 memcpy(&ipn, &ConfigServerInfo.ip6, sizeof(struct irc_ssaddr));
742 ipn.ss.ss_family = AF_INET6;
743 ipn.ss_port = 0;
744 comm_connect_tcp(&client_p->connection->fd,
745 conf->host, conf->port,
746 (struct sockaddr *)&ipn, ipn.ss_len,
747 serv_connect_callback, client_p,
748 conf->aftype, CONNECTTIMEOUT);
749 }
750 else
751 comm_connect_tcp(&client_p->connection->fd,
752 conf->host, conf->port,
753 NULL, 0, serv_connect_callback, client_p,
754 conf->aftype, CONNECTTIMEOUT);
755 }
756 }
757
758 return 1;
759 }
760
761 #ifdef HAVE_LIBCRYPTO
762 static void
763 finish_ssl_server_handshake(struct Client *client_p)
764 {
765 struct MaskItem *conf = NULL;
766
767 conf = find_conf_name(&client_p->connection->confs,
768 client_p->name, CONF_SERVER);
769 if (conf == NULL)
770 {
771 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
772 "Lost connect{} block for %s", get_client_name(client_p, SHOW_IP));
773 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
774 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
775
776 exit_client(client_p, "Lost connect{} block");
777 return;
778 }
779
780 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
781
782 send_capabilities(client_p);
783
784 sendto_one(client_p, "SERVER %s 1 :%s%s",
785 me.name, ConfigServerHide.hidden ? "(H) " : "",
786 me.info);
787
788 /*
789 * If we've been marked dead because a send failed, just exit
790 * here now and save everyone the trouble of us ever existing.
791 */
792 if (IsDead(client_p))
793 {
794 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
795 "%s went dead during handshake", get_client_name(client_p, SHOW_IP));
796 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
797 "%s went dead during handshake", get_client_name(client_p, MASK_IP));
798 return;
799 }
800
801 /* don't move to serv_list yet -- we haven't sent a burst! */
802 /* If we get here, we're ok, so lets start reading some data */
803 comm_setselect(&client_p->connection->fd, COMM_SELECT_READ, read_packet, client_p, 0);
804 }
805
806 static void
807 ssl_server_handshake(fde_t *fd, void *data)
808 {
809 struct Client *client_p = data;
810 X509 *cert = NULL;
811 int ret = 0;
812
813 if ((ret = SSL_connect(client_p->connection->fd.ssl)) <= 0)
814 {
815 if ((CurrentTime - client_p->connection->firsttime) > CONNECTTIMEOUT)
816 {
817 exit_client(client_p, "Timeout during SSL handshake");
818 return;
819 }
820
821 switch (SSL_get_error(client_p->connection->fd.ssl, ret))
822 {
823 case SSL_ERROR_WANT_WRITE:
824 comm_setselect(&client_p->connection->fd, COMM_SELECT_WRITE,
825 ssl_server_handshake, client_p, CONNECTTIMEOUT);
826 return;
827 case SSL_ERROR_WANT_READ:
828 comm_setselect(&client_p->connection->fd, COMM_SELECT_READ,
829 ssl_server_handshake, client_p, CONNECTTIMEOUT);
830 return;
831 default:
832 {
833 const char *sslerr = ERR_error_string(ERR_get_error(), NULL);
834 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
835 "Error connecting to %s: %s", client_p->name,
836 sslerr ? sslerr : "unknown SSL error");
837 exit_client(client_p, "Error during SSL handshake");
838 return;
839 }
840 }
841 }
842
843 comm_settimeout(&client_p->connection->fd, 0, NULL, NULL);
844
845 if ((cert = SSL_get_peer_certificate(client_p->connection->fd.ssl)))
846 {
847 int res = SSL_get_verify_result(client_p->connection->fd.ssl);
848 char buf[EVP_MAX_MD_SIZE * 2 + 1] = "";
849 unsigned char md[EVP_MAX_MD_SIZE] = "";
850
851 if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
852 res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
853 res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
854 {
855 unsigned int n = 0;
856
857 if (X509_digest(cert, ConfigServerInfo.message_digest_algorithm, md, &n))
858 {
859 binary_to_hex(md, buf, n);
860 client_p->certfp = xstrdup(buf);
861 }
862 }
863 else
864 ilog(LOG_TYPE_IRCD, "Server %s!%s@%s gave bad SSL client certificate: %d",
865 client_p->name, client_p->username, client_p->host, res);
866 X509_free(cert);
867 }
868
869 finish_ssl_server_handshake(client_p);
870 }
871
872 static void
873 ssl_connect_init(struct Client *client_p, const struct MaskItem *conf, fde_t *fd)
874 {
875 if ((client_p->connection->fd.ssl = SSL_new(ConfigServerInfo.client_ctx)) == NULL)
876 {
877 ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
878 ERR_error_string(ERR_get_error(), NULL));
879 SetDead(client_p);
880 exit_client(client_p, "SSL_new failed");
881 return;
882 }
883
884 SSL_set_fd(fd->ssl, fd->fd);
885
886 if (!EmptyString(conf->cipher_list))
887 SSL_set_cipher_list(client_p->connection->fd.ssl, conf->cipher_list);
888
889 ssl_server_handshake(NULL, client_p);
890 }
891 #endif
892
893 /* serv_connect_callback() - complete a server connection.
894 *
895 * This routine is called after the server connection attempt has
896 * completed. If unsucessful, an error is sent to ops and the client
897 * is closed. If sucessful, it goes through the initialisation/check
898 * procedures, the capabilities are sent, and the socket is then
899 * marked for reading.
900 */
901 static void
902 serv_connect_callback(fde_t *fd, int status, void *data)
903 {
904 struct Client *const client_p = data;
905 const struct MaskItem *conf = NULL;
906
907 /* First, make sure it's a real client! */
908 assert(client_p);
909 assert(&client_p->connection->fd == fd);
910
911 /* Next, for backward purposes, record the ip of the server */
912 memcpy(&client_p->connection->ip, &fd->connect.hostaddr,
913 sizeof(struct irc_ssaddr));
914
915 /* Check the status */
916 if (status != COMM_OK)
917 {
918 /* We have an error, so report it and quit */
919 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
920 "Error connecting to %s: %s",
921 get_client_name(client_p, SHOW_IP), comm_errstr(status));
922 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
923 "Error connecting to %s: %s",
924 get_client_name(client_p, MASK_IP), comm_errstr(status));
925
926 /*
927 * If a fd goes bad, call dead_link() the socket is no
928 * longer valid for reading or writing.
929 */
930 dead_link_on_write(client_p, 0);
931 return;
932 }
933
934 /* COMM_OK, so continue the connection procedure */
935 /* Get the C/N lines */
936 conf = find_conf_name(&client_p->connection->confs,
937 client_p->name, CONF_SERVER);
938 if (conf == NULL)
939 {
940 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
941 "Lost connect{} block for %s", get_client_name(client_p, SHOW_IP));
942 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
943 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
944
945 exit_client(client_p, "Lost connect{} block");
946 return;
947 }
948
949 /* Next, send the initial handshake */
950 SetHandshake(client_p);
951
952 #ifdef HAVE_LIBCRYPTO
953 if (IsConfSSL(conf))
954 {
955 ssl_connect_init(client_p, conf, fd);
956 return;
957 }
958 #endif
959
960 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
961
962 send_capabilities(client_p);
963
964 sendto_one(client_p, "SERVER %s 1 :%s%s", me.name,
965 ConfigServerHide.hidden ? "(H) " : "", me.info);
966
967 /*
968 * If we've been marked dead because a send failed, just exit
969 * here now and save everyone the trouble of us ever existing.
970 */
971 if (IsDead(client_p))
972 {
973 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
974 "%s went dead during handshake", get_client_name(client_p, SHOW_IP));
975 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
976 "%s went dead during handshake", get_client_name(client_p, MASK_IP));
977 return;
978 }
979
980 /* don't move to serv_list yet -- we haven't sent a burst! */
981 /* If we get here, we're ok, so lets start reading some data */
982 comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
983 }
984
985 struct Client *
986 find_servconn_in_progress(const char *name)
987 {
988 dlink_node *ptr;
989 struct Client *cptr;
990
991 DLINK_FOREACH(ptr, unknown_list.head)
992 {
993 cptr = ptr->data;
994
995 if (cptr && cptr->name[0])
996 if (!match(name, cptr->name))
997 return cptr;
998 }
999
1000 return NULL;
1001 }

Properties

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