ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/modules/m_cryptlink.c
Revision: 1156
Committed: Tue Aug 9 20:29:20 2011 UTC (14 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 13692 byte(s)
Log Message:
- create ircd-hybrid-8 "branch"

File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * m_cryptlink.c: Used to negotiate an encrypted link.
4     *
5     * Copyright (C) 2002 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     /*
26     * CRYPTLINK protocol.
27     *
28     * Please see doc/cryptlink.txt for a description of this protocol.
29     *
30     */
31    
32     #include "stdinc.h"
33 michael 912 #ifdef HAVE_LIBCRYPTO
34    
35 michael 1011 #include "list.h"
36 adx 30 #include "handlers.h"
37     #include "client.h" /* client struct */
38     #include "ircd.h" /* me */
39     #include "modules.h"
40     #include "numeric.h" /* ERR_xxx */
41     #include "send.h" /* sendto_one */
42     #include <openssl/rsa.h> /* rsa.h is implicit when building this */
43     #include "rsa.h"
44     #include "msg.h"
45     #include "parse.h"
46     #include "irc_string.h" /* strncpy_irc */
47     #include "memory.h"
48     #include "common.h" /* TRUE bleah */
49     #include "event.h"
50     #include "hash.h" /* add_to_client_hash_table */
51     #include "s_conf.h" /* struct AccessItem */
52     #include "s_log.h" /* log level defines */
53     #include "s_serv.h" /* server_estab, check_server, my_name_for_link */
54     #include "motd.h"
55    
56     static char *parse_cryptserv_args(struct Client *client_p,
57     char *parv[], int parc, char *info,
58     char *key);
59    
60     static void mr_cryptlink(struct Client *, struct Client *, int, char **);
61     static void cryptlink_serv(struct Client *, struct Client *, int, char **);
62     static void cryptlink_auth(struct Client *, struct Client *, int, char **);
63    
64     struct Message cryptlink_msgtab = {
65     "CRYPTLINK", 0, 0, 4, 0, MFLG_SLOW | MFLG_UNREG, 0,
66 michael 946 {mr_cryptlink, m_ignore, rfc1459_command_send_error, m_ignore, m_ignore, m_ignore}
67 adx 30 };
68    
69     struct CryptLinkStruct
70     {
71     const char *cmd; /* CRYPTLINK <command> to match */
72     void (*handler)(); /* Function to call */
73     };
74    
75     static struct CryptLinkStruct cryptlink_cmd_table[] =
76     {
77     /* command function */
78     { "AUTH", cryptlink_auth, },
79     { "SERV", cryptlink_serv, },
80     /* End of table */
81 michael 948 { NULL, NULL, }
82 adx 30 };
83    
84     void
85     _modinit(void)
86     {
87     mod_add_cmd(&cryptlink_msgtab);
88     }
89    
90     void
91     _moddeinit(void)
92     {
93     mod_del_cmd(&cryptlink_msgtab);
94     }
95    
96 knight 31 const char *_version = "$Revision$";
97 adx 30
98     /* mr_cryptlink - CRYPTLINK message handler
99     * parv[0] == CRYPTLINK
100     * parv[1] = command (SERV, AUTH)
101     * parv[2] = Parameters specific to each command (parv[1]):
102     * SERV - parc must be >= 5
103     * parv[0] == CRYPTLINK
104     * parv[1] == SERV
105     * parv[2] == server name
106     * parv[3] == keyphrase
107     * parv[4] == :server info (M-line)
108     * AUTH - parc must be >= 4
109     * parv[0] == CRYPTLINK
110     * parv[1] == AUTH
111     * parv[2] == cipher (eg. BF/168)
112     * parv[3] == keyphrase
113     */
114     static void
115     mr_cryptlink(struct Client *client_p, struct Client *source_p,
116     int parc, char *parv[])
117     {
118     int i;
119    
120     for (i = 0; cryptlink_cmd_table[i].handler; i++)
121     {
122     /* Traverse through the command table */
123     if (!irccmp(cryptlink_cmd_table[i].cmd, parv[1]))
124     {
125     /*
126     * Match found. Time to execute the function
127     */
128     cryptlink_cmd_table[i].handler(client_p, source_p, parc, parv);
129     }
130     }
131     }
132    
133     /*
134     * cryptlink_auth - CRYPTLINK AUTH message handler
135     * parv[1] = secret key
136     */
137     static void
138     cryptlink_auth(struct Client *client_p, struct Client *source_p,
139     int parc, char *parv[])
140     {
141     struct EncCapability *ecap;
142     struct ConfItem *conf;
143     struct AccessItem *aconf;
144     int enc_len;
145     int len;
146     unsigned char *enc;
147     unsigned char *key;
148    
149     if (parc < 4)
150     {
151     cryptlink_error(client_p, "AUTH", "Invalid params",
152     "CRYPTLINK AUTH - Invalid params");
153     return;
154     }
155    
156     if (!IsWaitAuth(client_p))
157     return;
158    
159     for (ecap = CipherTable; ecap->name; ecap++)
160     {
161     if ((!irccmp(ecap->name, parv[2])) &&
162     (IsCapableEnc(client_p, ecap->cap)))
163     {
164     client_p->localClient->in_cipher = ecap;
165     break;
166     }
167     }
168    
169     if (client_p->localClient->in_cipher == NULL)
170     {
171     cryptlink_error(client_p, "AUTH", "Invalid cipher", "Invalid cipher");
172     return;
173     }
174    
175     if (!(enc_len = unbase64_block(&enc, parv[3], strlen(parv[3]))))
176     {
177     cryptlink_error(client_p, "AUTH",
178     "Could not base64 decode response",
179     "Malformed CRYPTLINK AUTH reply");
180     return;
181     }
182    
183     if (verify_private_key() == -1)
184     {
185     sendto_realops_flags(UMODE_ALL, L_ADMIN,
186     "verify_private_key() returned -1. Check log for information.");
187     }
188    
189     key = MyMalloc(RSA_size(ServerInfo.rsa_private_key));
190     len = RSA_private_decrypt(enc_len, (unsigned char *)enc,(unsigned char *)key,
191     ServerInfo.rsa_private_key,
192     RSA_PKCS1_PADDING);
193    
194     if (len < client_p->localClient->in_cipher->keylen)
195     {
196     report_crypto_errors();
197     if (len < 0)
198     {
199     cryptlink_error(client_p, "AUTH",
200     "Decryption failed",
201     "Malformed CRYPTLINK AUTH reply");
202     }
203     else
204     {
205     cryptlink_error(client_p, "AUTH",
206     "Not enough random data sent",
207     "Malformed CRYPTLINK AUTH reply");
208     }
209     MyFree(enc);
210     MyFree(key);
211     return;
212     }
213    
214     if (memcmp(key, client_p->localClient->in_key,
215     client_p->localClient->in_cipher->keylen) != 0)
216     {
217     cryptlink_error(client_p, "AUTH",
218     "Unauthorized server connection attempt",
219     "Malformed CRYPTLINK AUTH reply");
220     return;
221     }
222    
223     conf = find_conf_name(&client_p->localClient->confs,
224     client_p->name, SERVER_TYPE);
225    
226     if (conf == NULL)
227     {
228     cryptlink_error(client_p, "AUTH",
229     "Lost C-line for server",
230     "Lost C-line");
231     return;
232     }
233    
234     aconf = (struct AccessItem *)map_to_conf(conf);
235    
236     if (!(client_p->localClient->out_cipher ||
237     (client_p->localClient->out_cipher = check_cipher(client_p, aconf))))
238     {
239     cryptlink_error(client_p, "AUTH",
240     "Couldn't find compatible cipher",
241     "Couldn't find compatible cipher");
242     return;
243     }
244    
245     /* set hopcount */
246     client_p->hopcount = 1;
247    
248     SetCryptIn(client_p);
249     ClearWaitAuth(client_p);
250     server_estab(client_p);
251     }
252    
253     /*
254     * cryptlink_serv - CRYPTLINK SERV message handler
255     * parv[0] == CRYPTLINK
256     * parv[1] == SERV
257     * parv[2] == server name
258     * parv[3] == keyphrase
259     * parv[4] == :server info (M-line)
260     */
261     static void
262     cryptlink_serv(struct Client *client_p, struct Client *source_p,
263     int parc, char *parv[])
264     {
265     char info[REALLEN + 1];
266     char *name;
267     struct Client *target_p;
268     char *key = client_p->localClient->out_key;
269     unsigned char *b64_key;
270     struct ConfItem *conf;
271     struct AccessItem *aconf;
272     char *encrypted;
273     const char *p;
274     int enc_len;
275    
276     /*
277     if (client_p->name[0] != 0)
278     return;
279     */
280    
281     if ((parc < 5) || (*parv[4] == '\0'))
282     {
283     cryptlink_error(client_p, "SERV", "Invalid params",
284     "CRYPTLINK SERV - Invalid params");
285     return;
286     }
287    
288     if ((name = parse_cryptserv_args(client_p, parv, parc, info, key)) == NULL)
289     {
290     cryptlink_error(client_p, "SERV", "Invalid params",
291     "CRYPTLINK SERV - Invalid params");
292     return;
293     }
294    
295     /* CRYPTLINK SERV support => TS support */
296     client_p->tsinfo = TS_DOESTS;
297    
298 michael 1118 if (!valid_servname(name))
299 adx 30 {
300     exit_client(client_p, client_p, "Bogus server name");
301     return;
302     }
303    
304     /* Now we just have to call check_server and everything should be
305     * checked for us... -A1kmm. */
306     switch (check_server(name, client_p, CHECK_SERVER_CRYPTLINK))
307     {
308     case -1:
309     if (ConfigFileEntry.warn_no_nline)
310     {
311     cryptlink_error(client_p, "SERV",
312     "Unauthorized server connection attempt: No entry for server",
313     NULL);
314     }
315     exit_client(client_p, client_p, "Invalid server name");
316     return;
317     break;
318     case -2:
319     cryptlink_error(client_p, "SERV",
320     "Unauthorized server connection attempt: CRYPTLINK not "
321     "enabled on remote server",
322     "CRYPTLINK not enabled");
323     return;
324     break;
325     case -3:
326     cryptlink_error(client_p, "SERV",
327     "Unauthorized server connection attempt: Invalid host",
328     "Invalid host");
329     return;
330     break;
331     }
332    
333     if ((target_p = find_server(name)))
334     {
335     /*
336     * This link is trying feed me a server that I already have
337     * access through another path -- multiple paths not accepted
338     * currently, kill this link immediately!!
339     *
340     * Rather than KILL the link which introduced it, KILL the
341     * youngest of the two links. -avalon
342     *
343     * Definitely don't do that here. This is from an unregistered
344     * connect - A1kmm.
345     */
346     cryptlink_error(client_p, "SERV",
347     "Attempt to re-introduce existing server",
348     "Server Exists");
349     return;
350     }
351    
352     conf = find_conf_name(&client_p->localClient->confs,
353     name, SERVER_TYPE);
354     if (conf == NULL)
355     {
356     cryptlink_error(client_p, "AUTH",
357     "Lost C-line for server",
358     "Lost C-line" );
359     return;
360     }
361    
362     /*
363     * if we are connecting (Handshake), we already have the name from the
364     * connect {} block in client_p->name
365     */
366     strlcpy(client_p->name, name, sizeof(client_p->name));
367    
368     p = info;
369    
370     if (!strncmp(info, "(H)", 3))
371     {
372     SetHidden(client_p);
373    
374     if ((p = strchr(info, ' ')) != NULL)
375     {
376     p++;
377     if (*p == '\0')
378     p = "(Unknown Location)";
379     }
380     else
381     p = "(Unknown Location)";
382     }
383    
384     strlcpy(client_p->info, p, sizeof(client_p->info));
385     client_p->hopcount = 0;
386    
387     aconf = (struct AccessItem *)map_to_conf(conf);
388    
389     if (!(client_p->localClient->out_cipher ||
390     (client_p->localClient->out_cipher = check_cipher(client_p, aconf))))
391     {
392     cryptlink_error(client_p, "AUTH",
393     "Couldn't find compatible cipher",
394     "Couldn't find compatible cipher");
395     return;
396     }
397    
398     encrypted = MyMalloc(RSA_size(ServerInfo.rsa_private_key));
399     enc_len = RSA_public_encrypt(client_p->localClient->out_cipher->keylen,
400     (unsigned char *)key,
401     (unsigned char *)encrypted,
402     aconf->rsa_public_key,
403     RSA_PKCS1_PADDING);
404    
405     if (enc_len <= 0)
406     {
407     report_crypto_errors();
408     MyFree(encrypted);
409     cryptlink_error(client_p, "AUTH",
410     "Couldn't encrypt data",
411     "Couldn't encrypt data");
412     return;
413     }
414    
415     base64_block(&b64_key, encrypted, enc_len);
416    
417     MyFree(encrypted);
418    
419     if (!IsWaitAuth(client_p))
420     cryptlink_init(client_p, conf, NULL);
421    
422     sendto_one(client_p, "CRYPTLINK AUTH %s %s",
423     client_p->localClient->out_cipher->name,
424     b64_key);
425    
426     /* needed for old servers that can't shove data back into slink */
427     send_queued_write(client_p);
428    
429     SetCryptOut(client_p);
430     MyFree(b64_key);
431     }
432    
433     /* parse_cryptserv_args()
434     *
435     * inputs - parv parameters
436     * - parc count
437     * - info string (to be filled in by this routine)
438     * - key (to be filled in by this routine)
439     * output - NULL if invalid params, server name otherwise
440     * side effects - parv[2] is trimmed to HOSTLEN size if needed.
441     */
442     static char *
443     parse_cryptserv_args(struct Client *client_p, char *parv[],
444     int parc, char *info, char *key)
445     {
446     char *name;
447     unsigned char *tmp, *out;
448     int len;
449     int decoded_len;
450    
451     info[0] = '\0';
452    
453     name = parv[2];
454    
455     /* parv[2] contains encrypted auth data */
456     if (!(decoded_len = unbase64_block(&tmp, parv[3],
457     strlen(parv[3]))))
458     {
459     cryptlink_error(client_p, "SERV",
460     "Couldn't base64 decode data",
461     NULL);
462     return(NULL);
463     }
464    
465     if (verify_private_key() == -1)
466     {
467     sendto_realops_flags(UMODE_ALL, L_ADMIN,
468     "verify_private_key() returned -1. Check log for information.");
469     }
470    
471     if (ServerInfo.rsa_private_key == NULL)
472     {
473     cryptlink_error(client_p, "SERV", "No local private key found", NULL);
474     return(NULL);
475     }
476    
477     out = MyMalloc(RSA_size(ServerInfo.rsa_private_key));
478     len = RSA_private_decrypt(decoded_len, tmp, out,
479     ServerInfo.rsa_private_key,
480     RSA_PKCS1_PADDING);
481    
482     MyFree(tmp);
483    
484     if (len < CIPHERKEYLEN)
485     {
486     report_crypto_errors();
487     if (len < 0)
488     {
489     cryptlink_error(client_p, "AUTH", "Decryption failed", NULL);
490     }
491     else
492     {
493     cryptlink_error(client_p, "AUTH", "Not enough random data sent", NULL);
494     }
495     MyFree(out);
496     return(NULL);
497     }
498    
499     memcpy(key, out, CIPHERKEYLEN);
500     MyFree(out);
501    
502     strlcpy(info, parv[4], REALLEN + 1);
503    
504     if (strlen(name) > HOSTLEN)
505     name[HOSTLEN] = '\0';
506    
507     return(name);
508     }
509 michael 912 #endif

Properties

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