/[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 912 - (show annotations)
Wed Nov 7 22:47:44 2007 UTC (12 years, 1 month ago) by michael
File MIME type: text/x-chdr
File size: 14183 byte(s)
- Implemented libtool-ltdl. Only shared modules are supported currently
- Several build fixes and cleanups. ircd now builds and runs without any problems
- Added back all files to SVN that are needed to built the daemon
  I really don't want to force other people that want to test the snapshots
  or svn versions to install yyacc, lex, automake, autoconf and libtool...
  No problem having required files in svn
- Removed some automake maintainer stuff which is kinda useless for us

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, m_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.26