ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/modules/m_cryptlink.c
Revision: 1243
Committed: Fri Sep 30 10:47:53 2011 UTC (14 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 13737 byte(s)
Log Message:
- move content of msg.h, ircd_handler.h and handlers.h into parse.h and
  remove headers accordingly
- killed common.h
- remove m_killhost.c and m_flags.c from contrib/
- sort out unused header includes here and there

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

Properties

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