/[svn]/ircd-hybrid-7.2/modules/m_cryptlink.c
ViewVC logotype

Contents of /ircd-hybrid-7.2/modules/m_cryptlink.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 946 - (show annotations)
Mon Jul 20 23:18:04 2009 UTC (12 years, 2 months ago) by michael
File MIME type: text/x-chdr
File size: 14202 byte(s)
- move m_error.c to modules/


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

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28