ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/s_serv.c
Revision: 1028
Committed: Sun Nov 8 13:03:38 2009 UTC (14 years, 5 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/src/s_serv.c
File size: 62742 byte(s)
Log Message:
- move ircd-hybrid-7.2 to trunk

File Contents

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

Properties

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