ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/s_serv.c
Revision: 896
Committed: Sat Nov 3 08:54:09 2007 UTC (18 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 62590 byte(s)
Log Message:
- Killed s_stats.c

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

Properties

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