ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.3/modules/m_cryptlink.c
Revision: 1121
Committed: Sun Jan 9 11:03:03 2011 UTC (15 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 13692 byte(s)
Log Message:
- removed all instances of STATIC_MODULES since we don't have
  static modules anymore
- removed m_mkpasswd module from contrib

File Contents

# Content
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 "list.h"
36 #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 {mr_cryptlink, m_ignore, rfc1459_command_send_error, m_ignore, m_ignore, m_ignore}
67 };
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 { NULL, NULL, }
82 };
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 const char *_version = "$Revision$";
97
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 if (!valid_servname(name))
299 {
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 #endif

Properties

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