ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/s_serv.c
Revision: 126
Committed: Fri Oct 14 02:41:46 2005 UTC (20 years, 10 months ago) by db
Content type: text/x-csrc
File size: 69944 byte(s)
Log Message:
- attach/conf cleanup take 2
- Each client has now one AccessItem for its connect
  stored in localClient->iline
- The corresponding class is now stored in localClient->class

The ramifications of this move are, there is no conf list to traverse
to find the AccessItem, the class is instantly available from the localClient
struct without having to traverse the confs list and indirectly through the
aconf. This speeds up get_sendq etc. functions. As a bonus, at least
4 fewer bytes are used in the Client struct, since a dlink list is 4 words.
It does mean there is no longer a separate conf oper, which leads to the
kludge of patching the clients iline into an oper conf when
a client opers up. I don't think the oper flags are used after the client
is opered, so the patching operation may not be necessary.

- Server confs are stored in ->serv->sconf as before but attaching
  happens much earlier.
- server hub/leaf masks continues to be a dlink list but linked from
  the ->serv which is only allocated for servers.

- cleaned up some comments, added a comment, notably to check_server()
  which badly needed it.
- Pass ClassItem or AccessItem etc. in when it makes more sense than passing
  in struct ConfItem. This simplified and clarified rebuild_cidr_class()

And lo, there was a great rejoicing.


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

Properties

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