Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / ipkdb / ipkdb_ipkdb.c
blobb26b7654a20968dd55a4f3f07dcca818065d253b
1 /* $NetBSD: ipkdb_ipkdb.c,v 1.26 2009/04/12 22:37:50 elad Exp $ */
3 /*
4 * Copyright (C) 1993-2000 Wolfgang Solfrank.
5 * Copyright (C) 1993-2000 TooLs GmbH.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: ipkdb_ipkdb.c,v 1.26 2009/04/12 22:37:50 elad Exp $");
37 #include "opt_ipkdb.h"
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <sys/mbuf.h>
42 #include <sys/reboot.h>
43 #include <sys/systm.h>
44 #include <sys/kauth.h>
45 #include <sys/cpu.h>
47 #include <net/if.h>
48 #include <net/if_arp.h>
49 #include <net/if_ether.h>
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/if_inarp.h>
54 #include <netinet/ip.h>
55 #include <netinet/ip_var.h>
56 #include <netinet/udp.h>
58 #include <machine/reg.h>
60 #include <ipkdb/ipkdb.h>
61 #include <machine/ipkdb.h>
63 int ipkdbpanic = 0;
65 #ifndef IPKDBKEY
66 #error You must specify the IPKDBKEY option to use IPKDB.
67 #else
68 static char ipkdbkey[] = IPKDBKEY;
69 #endif
71 static struct ipkdb_if ipkdb_if;
73 static kauth_listener_t ipkdb_listener;
75 static u_char *ipkdbaddr(u_char *, int *, void **);
76 static void peekmem(struct ipkdb_if *, u_char *, void *, long);
77 static void pokemem(struct ipkdb_if *, u_char *, void *, long);
78 static u_int32_t getnl(void *);
79 static u_int getns(void *);
80 static void setnl(void *, u_int32_t);
81 static void setns(void *, int);
82 static u_short cksum(u_short, void *, int);
83 static int assemble(struct ipkdb_if *, void *);
84 static char *inpkt(struct ipkdb_if *, char *, int);
85 static void outpkt(struct ipkdb_if *, char *, int, int, int);
86 static void init(struct ipkdb_if *);
87 static void *chksum(void *, int);
88 static void getpkt(struct ipkdb_if *, char *, int *);
89 static void putpkt(struct ipkdb_if *, const char *, int);
90 static int check_ipkdb(struct ipkdb_if *, struct in_addr *, char *, int);
91 static int connectipkdb(struct ipkdb_if *, char *, int);
92 static int hmac_init(void);
94 static int
95 ipkdb_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
96 void *arg0, void *arg1, void *arg2, void *arg3)
98 enum kauth_system_req req;
99 int result;
101 req = (enum kauth_system_req)arg0;
102 result = KAUTH_RESULT_DEFER;
104 if ((action != KAUTH_SYSTEM_DEBUG) ||
105 (req != KAUTH_REQ_SYSTEM_DEBUG_IPKDB))
106 return result;
108 result = KAUTH_RESULT_ALLOW;
110 return result;
113 void
114 ipkdb_init(void)
116 ipkdbinit();
117 if ( ipkdbifinit(&ipkdb_if) < 0
118 || !(ipkdb_if.flags&IPKDB_MYHW)
119 || !hmac_init()) {
120 /* Interface not found, drop IPKDB */
121 printf("IPKDB: No interface found!\n");
122 boothowto &= ~RB_KDB;
125 ipkdb_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
126 ipkdb_listener_cb, NULL);
129 void
130 ipkdb_connect(int when)
132 boothowto |= RB_KDB;
133 if (when == 0)
134 printf("waiting for remote debugger\n");
135 ipkdb_trap();
138 void
139 ipkdb_panic(void)
141 ipkdbpanic = 1;
142 ipkdb_trap();
146 * Doesn't handle overlapping regions!
148 void
149 ipkdbcopy(const void *s, void *d, int n)
151 const char *sp = s;
152 char *dp = d;
154 while (--n >= 0)
155 *dp++ = *sp++;
158 void
159 ipkdbzero(void *d, int n)
161 char *dp = d;
163 while (--n >= 0)
164 *dp++ = 0;
168 ipkdbcmp(void *s, void *d, int n)
170 char *sp = s, *dp = d;
172 while (--n >= 0)
173 if (*sp++ != *dp++)
174 return *--dp - *--sp;
175 return 0;
179 ipkdbcmds(void)
181 static char buf[512];
182 char *cp;
183 int plen;
185 if (!(ipkdb_if.flags&IPKDB_MYHW)) /* no interface */
186 return IPKDB_CMD_EXIT;
187 init(&ipkdb_if);
188 if (ipkdbpanic > 1) {
189 ipkdb_if.leave(&ipkdb_if);
190 return IPKDB_CMD_RUN;
192 putpkt(&ipkdb_if, "s", 1);
193 while (1) {
194 getpkt(&ipkdb_if, buf, &plen);
195 if (!plen) {
196 if (ipkdbpanic && ipkdb_poll()) {
197 ipkdb_if.leave(&ipkdb_if);
198 return IPKDB_CMD_RUN;
199 } else
200 continue;
201 } else
202 ipkdbpanic = 0;
203 switch (*buf) {
204 default:
205 putpkt(&ipkdb_if, "eunknown command", 16);
206 break;
207 case 'O':
208 /* This is an allowed reconnect, ack it */
209 putpkt(&ipkdb_if, "s", 1);
210 break;
211 case 'R':
212 peekmem(&ipkdb_if, buf, ipkdbregs, sizeof ipkdbregs);
213 break;
214 case 'W':
215 if (plen != sizeof ipkdbregs + 1) {
216 putpkt(&ipkdb_if, "einvalid register size", 22);
217 break;
219 pokemem(&ipkdb_if, buf + 1, ipkdbregs, sizeof ipkdbregs);
220 break;
221 case 'M':
223 void *addr, *len;
225 plen--;
226 if ( !(cp = ipkdbaddr(buf + 1, &plen, &addr))
227 || !ipkdbaddr(cp, &plen, &len)) {
228 putpkt(&ipkdb_if, "einvalid peek format", 20);
229 break;
231 peekmem(&ipkdb_if, buf, addr, (long)len);
232 break;
234 case 'N':
236 void *addr, *len;
238 plen--;
239 if ( !(cp = ipkdbaddr(buf + 1, &plen, &addr))
240 || !(cp = ipkdbaddr(cp, &plen, &len))
241 || plen < (long)len) {
242 putpkt(&ipkdb_if, "einvalid poke format", 20);
243 break;
245 pokemem(&ipkdb_if, cp, addr, (long)len);
246 break;
248 case 'S':
249 ipkdb_if.leave(&ipkdb_if);
250 return IPKDB_CMD_STEP;
251 case 'X':
252 putpkt(&ipkdb_if, "ok",2);
253 ipkdb_if.leave(&ipkdb_if);
254 return IPKDB_CMD_EXIT;
255 case 'C':
256 ipkdb_if.leave(&ipkdb_if);
257 return IPKDB_CMD_RUN;
262 static u_char *
263 ipkdbaddr(u_char *cp, int *pl, void **dp)
265 /* Assume that sizeof(void *) <= sizeof(u_long) */
266 u_long l;
267 int i;
269 if ((*pl -= sizeof *dp) < 0)
270 return 0;
271 for (i = sizeof *dp, l = 0; --i >= 0;) {
272 l <<= 8;
273 l |= *cp++;
275 *dp = (void *)l;
276 return cp;
279 static void
280 peekmem(struct ipkdb_if *ifp, u_char *buf, void *addr, long len)
282 u_char *cp, *p = addr;
283 int l;
285 cp = buf;
286 *cp++ = 'p';
287 for (l = len; --l >= 0;)
288 *cp++ = ipkdbfbyte(p++);
289 putpkt(ifp, buf, len + 1);
292 static void
293 pokemem(struct ipkdb_if *ifp, u_char *cp, void *addr, long len)
295 u_char *p = addr;
297 while (--len >= 0)
298 ipkdbsbyte(p++, *cp++);
299 putpkt(ifp, "ok", 2);
302 inline static u_int32_t
303 getnl(void *vs)
305 u_char *s = vs;
307 return (*s << 24)|(s[1] << 16)|(s[2] << 8)|s[3];
310 inline static u_int
311 getns(void *vs)
313 u_char *s = vs;
315 return (*s << 8)|s[1];
318 inline static void
319 setnl(void *vs, u_int32_t l)
321 u_char *s = vs;
323 *s++ = l >> 24;
324 *s++ = l >> 16;
325 *s++ = l >> 8;
326 *s = l;
329 inline static void
330 setns(void *vs, int l)
332 u_char *s = vs;
334 *s++ = l >> 8;
335 *s = l;
338 static u_short
339 cksum(u_short st, void *vcp, int l)
341 u_char *cp = vcp;
342 u_long s;
344 for (s = st; (l -= 2) >= 0; cp += 2)
345 s += (*cp << 8) + cp[1];
346 if (l == -1)
347 s += *cp << 8;
348 while (s&0xffff0000)
349 s = (s&0xffff) + (s >> 16);
350 return s == 0xffff ? 0 : s;
353 static int
354 assemble(struct ipkdb_if *ifp, void *buf)
356 struct ip *ip, iph;
357 int off, len, i;
358 u_char *cp, *ecp;
360 ip = (struct ip *)buf;
361 ipkdbcopy(ip, &iph, sizeof iph);
362 iph.ip_hl = 5;
363 iph.ip_tos = 0;
364 iph.ip_len = 0;
365 iph.ip_off = 0;
366 iph.ip_ttl = 0;
367 iph.ip_sum = 0;
368 if (ifp->asslen) {
369 if (ipkdbcmp(&iph, ifp->ass, sizeof iph)) {
371 * different packet
372 * decide whether to keep the old
373 * or start a new one
375 i = (getns(&ip->ip_id)
376 ^ getns(&((struct ip *)ifp->ass)->ip_id));
377 i ^= ((i >> 2) ^ (i >> 4) ^ (i >> 8) ^ (i >> 12));
378 if (i & 1)
379 /* keep the old */
380 return 0;
381 ifp->asslen = 0;
384 if (!ifp->asslen) {
385 ipkdbzero(ifp->assbit, sizeof ifp->assbit);
386 ipkdbcopy(&iph, ifp->ass, sizeof iph);
388 off = getns(&ip->ip_off);
389 len = ((off & IP_OFFMASK) << 3) + getns(&ip->ip_len) - ip->ip_hl * 4;
390 if (ifp->asslen < len)
391 ifp->asslen = len;
392 if (ifp->asslen + sizeof *ip > sizeof ifp->ass) {
393 /* packet too long */
394 ifp->asslen = 0;
395 return 0;
397 if (!(off & IP_MF)) {
398 off &= IP_OFFMASK;
399 cp = ifp->assbit + (off >> 3);
400 for (i = (off & 7); i < 8; *cp |= 1 << i++);
401 for (; cp < ifp->assbit + sizeof ifp->assbit; *cp++ = -1);
402 } else {
403 off &= IP_OFFMASK;
404 cp = ifp->assbit + (off >> 3);
405 ecp = ifp->assbit + (len >> 6);
406 if (cp == ecp)
407 for (i = (off & 7); i <= ((len >> 3) & 7);
408 *cp |= 1 << i++);
409 else {
410 for (i = (off & 7); i < 8; *cp |= 1 << i++);
411 for (; ++cp < ecp; *cp = -1);
412 for (i = 0; i < ((len >> 3) & 7); *cp |= 1 << i++);
415 ipkdbcopy((char *)buf + ip->ip_hl * 4,
416 ifp->ass + sizeof *ip + (off << 3),
417 len - (off << 3));
418 for (cp = ifp->assbit; cp < ifp->assbit + sizeof ifp->assbit;)
419 if (*cp++ != (u_char)-1)
420 /* not complete */
421 return 0;
422 ip = (struct ip *)ifp->ass;
423 setns(&ip->ip_len, sizeof *ip + ifp->asslen);
424 /* complete */
425 return 1;
428 static char *
429 inpkt(struct ipkdb_if *ifp, char *ibuf, int poll)
431 int cnt = 1000000;
432 int l, ul;
433 struct ether_header *eh;
434 struct arphdr *ah;
435 struct ip *ip;
436 struct udphdr *udp;
437 struct ipovly ipo;
439 while (1) {
440 l = ifp->receive(ifp, ibuf, poll != 0);
441 if (!l) {
442 if (poll == 1 || (poll == 2 && --cnt <= 0))
443 break;
444 else
445 continue;
447 eh = (struct ether_header *)ibuf;
448 switch (getns(&eh->ether_type)) {
449 case ETHERTYPE_ARP:
450 ah = (struct arphdr *)(ibuf + 14);
451 if ( getns(&ah->ar_hrd) != ARPHRD_ETHER
452 || getns(&ah->ar_pro) != ETHERTYPE_IP
453 || ah->ar_hln != 6
454 || ah->ar_pln != 4)
455 /* unsupported arp packet */
456 break;
457 switch (getns(&ah->ar_op)) {
458 case ARPOP_REQUEST:
459 if ( (ifp->flags&IPKDB_MYIP)
460 && !ipkdbcmp(ar_tpa(ah),
461 ifp->myinetaddr,
462 sizeof ifp->myinetaddr)) {
463 /* someone requested my address */
464 ipkdbcopy(eh->ether_shost,
465 eh->ether_dhost,
466 sizeof eh->ether_dhost);
467 ipkdbcopy(ifp->myenetaddr,
468 eh->ether_shost,
469 sizeof eh->ether_shost);
470 setns(&ah->ar_op, ARPOP_REPLY);
471 ipkdbcopy(ar_sha(ah),
472 ar_tha(ah),
473 ah->ar_hln);
474 ipkdbcopy(ar_spa(ah),
475 ar_tpa(ah),
476 ah->ar_pln);
477 ipkdbcopy(ifp->myenetaddr,
478 ar_sha(ah),
479 ah->ar_hln);
480 ipkdbcopy(ifp->myinetaddr,
481 ar_spa(ah),
482 ah->ar_pln);
483 ifp->send(ifp, ibuf, 74);
484 continue;
486 break;
487 default:
488 break;
490 break;
491 case ETHERTYPE_IP:
492 ip = (struct ip *)(ibuf + 14);
493 if ( ip->ip_v != IPVERSION
494 || ip->ip_hl < 5
495 || getns(&ip->ip_len) + 14 > l)
496 /* invalid packet */
497 break;
498 if (cksum(0, ip, ip->ip_hl * 4))
499 /* wrong checksum */
500 break;
501 if (ip->ip_p != IPPROTO_UDP)
502 break;
503 if (getns(&ip->ip_off) & ~IP_DF) {
504 if (!assemble(ifp, ip))
505 break;
506 ip = (struct ip *)ifp->ass;
507 ifp->asslen = 0;
509 udp = (struct udphdr *)((char *)ip + ip->ip_hl * 4);
510 ul = getns(&ip->ip_len) - ip->ip_hl * 4;
511 if (getns(&udp->uh_ulen) != ul)
512 /* invalid UDP packet length */
513 break;
514 ipkdbcopy(ip, &ipo, sizeof ipo);
515 ipkdbzero(ipo.ih_x1, sizeof ipo.ih_x1);
516 ipo.ih_len = udp->uh_ulen;
517 if ( udp->uh_sum
518 && cksum(cksum(0, &ipo, sizeof ipo), udp, ul))
519 /* wrong checksum */
520 break;
521 if (!(ifp->flags & IPKDB_MYIP)) {
522 if ( getns(&udp->uh_sport) == 67
523 && getns(&udp->uh_dport) == 68
524 && *(char *)(udp + 1) == 2) {
525 /* this is a BOOTP reply to our ethernet address */
526 /* should check a bit more? XXX */
527 char *bootp = (char *)(udp + 1);
528 ipkdbcopy(bootp + 16,
529 ifp->myinetaddr,
530 sizeof ifp->myinetaddr);
531 ifp->flags |= IPKDB_MYIP;
533 /* give caller a chance to resend his request */
534 return 0;
536 if ( ipkdbcmp(&ip->ip_dst, ifp->myinetaddr, sizeof ifp->myinetaddr)
537 || getns(&udp->uh_dport) != IPKDBPORT)
538 break;
539 /* so now it's a UDP packet for the debugger */
541 /* Check for reconnect packet */
542 u_char *p;
544 p = (u_char *)(udp + 1);
545 if (!getnl(p) && p[6] == 'O') {
546 l = getns(p + 4);
547 if ( l <= ul - sizeof *udp - 6
548 && check_ipkdb(ifp, &ip->ip_src,
549 p, l + 6)) {
550 ipkdbcopy(&ip->ip_src,
551 ifp->hisinetaddr,
552 sizeof ifp->hisinetaddr);
553 ipkdbcopy(eh->ether_shost,
554 ifp->hisenetaddr,
555 sizeof ifp->hisenetaddr);
556 ifp->hisport = getns(&udp->uh_sport);
557 ifp->flags |= IPKDB_HISHW|IPKDB_HISIP;
558 return p;
562 if ( (ifp->flags&IPKDB_HISIP)
563 && ipkdbcmp(&ip->ip_src,
564 ifp->hisinetaddr, sizeof ifp->hisinetaddr))
565 /* It's a packet from someone else */
566 break;
567 if (!(ifp->flags&IPKDB_HISIP))
568 break;
569 return (char *)(udp + 1);
570 default:
571 /* unknown type */
572 break;
575 return 0;
578 static short ipkdb_ipid = 0;
580 static void
581 outpkt(struct ipkdb_if *ifp, char *in, int l, int srcport, int dstport)
583 struct ether_header *eh;
584 struct ip *ip;
585 struct udphdr *udp;
586 u_char *cp;
587 char _obuf[ETHERMTU + 16];
588 #define obuf (_obuf + 2) /* align ip data in packet */
589 struct ipovly ipo;
590 int i, off;
592 ipkdbzero(_obuf, sizeof _obuf);
593 eh = (struct ether_header *)obuf;
595 * If we don't have his ethernet address, or this is a bootp request,
596 * broadcast the packet.
598 if (!(ifp->flags & IPKDB_HISHW)
599 || dstport == 67)
600 for (cp = eh->ether_dhost;
601 cp < eh->ether_dhost + sizeof eh->ether_dhost;
602 *cp++ = -1);
603 else
604 ipkdbcopy(ifp->hisenetaddr, eh->ether_dhost, sizeof eh->ether_dhost);
605 ipkdbcopy(ifp->myenetaddr, eh->ether_shost, sizeof eh->ether_shost);
606 setns(&eh->ether_type, ETHERTYPE_IP);
607 ip = (struct ip *)(obuf + 14);
608 ip->ip_v = IPVERSION;
609 ip->ip_hl = 5;
610 setns(&ip->ip_id, ipkdb_ipid++);
611 ip->ip_ttl = 255;
612 ip->ip_p = IPPROTO_UDP;
613 ipkdbcopy(ifp->myinetaddr, &ip->ip_src, sizeof ip->ip_src);
615 * If this is a bootp request, broadcast it.
617 if (dstport == 67)
618 for (cp = (u_char *)&ip->ip_dst;
619 cp < (u_char *)&ip->ip_dst + sizeof ip->ip_dst;
620 *cp++ = -1);
621 else
622 ipkdbcopy(ifp->hisinetaddr, &ip->ip_dst, sizeof ip->ip_dst);
623 udp = (struct udphdr *)(ip + 1);
624 setns(&udp->uh_sport, srcport);
625 setns(&udp->uh_dport, dstport);
626 setns(&udp->uh_ulen, l + sizeof *udp);
627 ipkdbcopy(ip, &ipo, sizeof ipo);
628 ipkdbzero(ipo.ih_x1, sizeof ipo.ih_x1);
629 ipo.ih_len = udp->uh_ulen;
630 setns(&udp->uh_sum,
631 ~cksum(cksum(cksum(0, &ipo, sizeof ipo),
632 udp, sizeof *udp),
633 in, l));
634 for (cp = (u_char *)(udp + 1), l += sizeof *udp, off = 0;
635 l > 0;
636 l -= i, in += i, off += i, cp = (u_char *)udp) {
637 i = l > ifp->mtu - sizeof *ip ? ((ifp->mtu - sizeof *ip) & ~7) : l;
638 ipkdbcopy(in, cp, i);
639 setns(&ip->ip_len, i + sizeof *ip);
640 setns(&ip->ip_off, (l > i ? IP_MF : 0) | (off >> 3));
641 ip->ip_sum = 0;
642 setns(&ip->ip_sum, ~cksum(0, ip, sizeof *ip));
643 if (i + sizeof *ip < ETHERMIN)
644 i = ETHERMIN - sizeof *ip;
645 ifp->send(ifp, obuf, i + sizeof *ip + 14);
647 #undef obuf
650 static void
651 init(struct ipkdb_if *ifp)
653 u_char *cp;
654 u_char _ibuf[ETHERMTU + 16];
655 #define ibuf (_ibuf + 2) /* align ip data in packet */
656 int secs = 0;
658 ifp->start(ifp);
659 if (ifp->flags & IPKDB_MYIP)
660 return;
662 while (!(ifp->flags & IPKDB_MYIP)) {
663 ipkdbzero(_ibuf, sizeof _ibuf);
664 cp = _ibuf;
665 *cp++ = 1; /* BOOTP_REQUEST */
666 *cp++ = 1; /* Ethernet hardware */
667 *cp++ = 6; /* length of address */
668 setnl(++cp, 0x12345678); /* some random number? */
669 setns(cp + 4, secs++);
670 ipkdbcopy(ifp->myenetaddr, cp + 24, sizeof ifp->myenetaddr);
671 outpkt(ifp, _ibuf, 300, 68, 67);
672 inpkt(ifp, ibuf, 2);
673 if (ipkdbpanic && ipkdb_poll()) {
674 ipkdbpanic++;
675 return;
678 cp = ifp->myinetaddr;
679 printf("My IP address is %d.%d.%d.%d\n",
680 cp[0], cp[1], cp[2], cp[3]);
681 #undef ibuf
684 /* HMAC Checksumming routines, see draft-ietf-ipsec-hmac-md5-00.txt */
685 #define LENCHK 16 /* Length of checksum in bytes */
688 * This code is based on the MD5 implementation as found in ssh.
689 * It's quite a bit hacked by myself, but the original has
690 * the following non-copyright comments on it:
692 /* This code has been heavily hacked by Tatu Ylonen <ylo@cs.hut.fi> to
693 make it compile on machines like Cray that don't have a 32 bit integer
694 type. */
696 * This code implements the MD5 message-digest algorithm.
697 * The algorithm is due to Ron Rivest. This code was
698 * written by Colin Plumb in 1993, no copyright is claimed.
699 * This code is in the public domain; do with it what you wish.
701 * Equivalent code is available from RSA Data Security, Inc.
702 * This code has been tested against that, and is equivalent,
703 * except that you don't need to include two pages of legalese
704 * with every copy.
706 static struct ipkdb_MD5Context {
707 u_int buf[4];
708 u_int bits[2];
709 u_char in[64];
710 } icontext, ocontext;
712 static u_int32_t getNl(void *);
713 static void setNl(void *, u_int32_t);
714 static void ipkdb_MD5Transform(struct ipkdb_MD5Context *);
715 static void ipkdb_MD5Init(struct ipkdb_MD5Context *);
716 static void ipkdb_MD5Update(struct ipkdb_MD5Context *, u_char *, u_int);
717 static u_char *ipkdb_MD5Final(struct ipkdb_MD5Context *);
719 inline static u_int32_t
720 getNl(void *vs)
722 u_char *s = vs;
724 return *s | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
727 inline static void
728 setNl(void *vs, u_int32_t l)
730 u_char *s = vs;
732 *s++ = l;
733 *s++ = l >> 8;
734 *s++ = l >> 16;
735 *s = l >> 24;
738 /* The four core functions - F1 is optimized somewhat */
739 /* #define F1(x, y, z) (((x) & (y)) | (~(x) & (z))) */
740 #define F1(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
741 #define F2(x, y, z) F1(z, x, y)
742 #define F3(x, y, z) ((x) ^ (y) ^ (z))
743 #define F4(x, y, z) ((y) ^ ((x) | ~(z)))
745 /* This is the central step in the MD5 algorithm. */
746 #define ipkdb_MD5STEP(f, w, x, y, z, data, s) \
747 ((w) += f(x, y, z) + (data), \
748 (w) = ((w) << (s)) | (((w) >> (32 - s)) & 0xffffffff), \
749 (w) += (x))
752 * The core of the MD5 algorithm, this alters an existing MD5 hash to
753 * reflect the addition of 16 longwords of new data. MD5Update blocks
754 * the data for this routine.
756 static void
757 ipkdb_MD5Transform(struct ipkdb_MD5Context *ctx)
759 u_int a, b, c, d, i;
760 u_int in[16];
762 for (i = 0; i < 16; i++)
763 in[i] = getNl(ctx->in + 4 * i);
765 a = ctx->buf[0];
766 b = ctx->buf[1];
767 c = ctx->buf[2];
768 d = ctx->buf[3];
770 ipkdb_MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
771 ipkdb_MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
772 ipkdb_MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
773 ipkdb_MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
774 ipkdb_MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
775 ipkdb_MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
776 ipkdb_MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
777 ipkdb_MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
778 ipkdb_MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
779 ipkdb_MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
780 ipkdb_MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
781 ipkdb_MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
782 ipkdb_MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
783 ipkdb_MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
784 ipkdb_MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
785 ipkdb_MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
787 ipkdb_MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
788 ipkdb_MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
789 ipkdb_MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
790 ipkdb_MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
791 ipkdb_MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
792 ipkdb_MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
793 ipkdb_MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
794 ipkdb_MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
795 ipkdb_MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
796 ipkdb_MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
797 ipkdb_MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
798 ipkdb_MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
799 ipkdb_MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
800 ipkdb_MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
801 ipkdb_MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
802 ipkdb_MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
804 ipkdb_MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
805 ipkdb_MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
806 ipkdb_MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
807 ipkdb_MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
808 ipkdb_MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
809 ipkdb_MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
810 ipkdb_MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
811 ipkdb_MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
812 ipkdb_MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
813 ipkdb_MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
814 ipkdb_MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
815 ipkdb_MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
816 ipkdb_MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
817 ipkdb_MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
818 ipkdb_MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
819 ipkdb_MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
821 ipkdb_MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
822 ipkdb_MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
823 ipkdb_MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
824 ipkdb_MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
825 ipkdb_MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
826 ipkdb_MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
827 ipkdb_MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
828 ipkdb_MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
829 ipkdb_MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
830 ipkdb_MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
831 ipkdb_MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
832 ipkdb_MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
833 ipkdb_MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
834 ipkdb_MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
835 ipkdb_MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
836 ipkdb_MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
838 ctx->buf[0] += a;
839 ctx->buf[1] += b;
840 ctx->buf[2] += c;
841 ctx->buf[3] += d;
845 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
846 * initialization constants.
848 static void
849 ipkdb_MD5Init(struct ipkdb_MD5Context *ctx)
851 ctx->buf[0] = 0x67452301;
852 ctx->buf[1] = 0xefcdab89;
853 ctx->buf[2] = 0x98badcfe;
854 ctx->buf[3] = 0x10325476;
856 ctx->bits[0] = 0;
857 ctx->bits[1] = 0;
861 * Update context to reflect the concatenation of another buffer full
862 * of bytes.
864 static void
865 ipkdb_MD5Update(struct ipkdb_MD5Context *ctx, u_char *buf, unsigned len)
867 u_int t;
869 /* Update bitcount */
870 t = ctx->bits[0];
871 if ((ctx->bits[0] = (t + (len << 3)) & 0xffffffff) < t)
872 ctx->bits[1]++; /* Carry from low to high */
873 ctx->bits[1] += (len >> 29) & 0xffffffff;
875 t = (t >> 3) & 0x3f; /* Bytes already in ctx->in */
877 /* Handle any leading odd-sized chunks */
878 if (t) {
879 u_char *p = ctx->in + t;
881 t = 64 - t;
882 if (len < t) {
883 ipkdbcopy(buf, p, len);
884 return;
886 ipkdbcopy(buf, p, t);
887 ipkdb_MD5Transform(ctx);
888 buf += t;
889 len -= t;
892 /* Process data in 64-byte chunks */
893 while (len >= 64) {
894 ipkdbcopy(buf, ctx->in, 64);
895 ipkdb_MD5Transform(ctx);
896 buf += 64;
897 len -= 64;
900 /* Handle any remaining bytes of data. */
901 ipkdbcopy(buf, ctx->in, len);
905 * Final wrapup - pad to 64-byte boundary with the bit pattern
906 * 1 0* (64-bit count of bits processed, LSB-first)
908 static u_char *
909 ipkdb_MD5Final(struct ipkdb_MD5Context *ctx)
911 static u_char digest[16];
912 unsigned count;
913 u_char *p;
915 /* Compute number of bytes mod 64 */
916 count = (ctx->bits[0] >> 3) & 0x3f;
918 /* Set the first char of padding to 0x80. This is safe since there is
919 always at least one byte free */
920 p = ctx->in + count;
921 *p++ = 0x80;
923 /* Bytes of padding needed to make 64 bytes */
924 count = 64 - 1 - count;
926 /* Pad out to 56 mod 64 */
927 if (count < 8) {
928 /* Two lots of padding: Pad the first block to 64 bytes */
929 ipkdbzero(p, count);
930 ipkdb_MD5Transform(ctx);
932 /* Now fill the next block with 56 bytes */
933 ipkdbzero(ctx->in, 56);
934 } else
935 /* Pad block to 56 bytes */
936 ipkdbzero(p, count - 8);
938 /* Append length in bits and transform */
939 setNl(ctx->in + 56, ctx->bits[0]);
940 setNl(ctx->in + 60, ctx->bits[1]);
942 ipkdb_MD5Transform(ctx);
943 setNl(digest, ctx->buf[0]);
944 setNl(digest + 4, ctx->buf[1]);
945 setNl(digest + 8, ctx->buf[2]);
946 setNl(digest + 12, ctx->buf[3]);
948 return digest;
952 * The following code is more or less stolen from the hmac_md5
953 * function in the Appendix of the HMAC IETF draft, but is
954 * optimized as suggested in this same paper.
956 static int
957 hmac_init(void)
959 char pad[64];
960 char tk[16];
961 u_char *key = ipkdbkey;
962 int key_len = strlen(key);
963 int i;
965 /* Require key to be at least 16 bytes long */
966 if (key_len < 16) {
967 printf("IPKDBKEY must be at least 16 bytes long!\n");
968 ipkdbzero(key, key_len); /* XXX */
969 return 0;
972 /* if key is longer than 64 bytes reset it to key=MD5(key) */
973 if (key_len > 64) {
974 ipkdb_MD5Init(&icontext);
975 ipkdb_MD5Update(&icontext, key, key_len);
976 ipkdbcopy(ipkdb_MD5Final(&icontext), tk, 16);
977 ipkdbzero(key, key_len); /* XXX */
978 key = tk;
979 key_len = 16;
983 * the HMAC_MD5 transform looks like:
985 * MD5(K XOR opad, MD5(K XOR ipad, text))
987 * where K is and n byte key
988 * ipad is the byte 0x36 repeated 64 times
989 * opad is the byte 0x5c repeated 64 times
990 * and text is the data being protected
993 * We do the initial part of MD5(K XOR ipad)
994 * and MD5(K XOR opad) here, in order to
995 * speed up the computation later on.
997 ipkdbzero(pad, sizeof pad);
998 ipkdbcopy(key, pad, key_len);
999 for (i = 0; i < 64; i++)
1000 pad[i] ^= 0x36;
1001 ipkdb_MD5Init(&icontext);
1002 ipkdb_MD5Update(&icontext, pad, 64);
1004 ipkdbzero(pad, sizeof pad);
1005 ipkdbcopy(key, pad, key_len);
1006 for (i = 0; i < 64; i++)
1007 pad[i] ^= 0x5c;
1008 ipkdb_MD5Init(&ocontext);
1009 ipkdb_MD5Update(&ocontext, pad, 64);
1011 /* Zero out the key XXX */
1012 ipkdbzero(key, key_len);
1014 return 1;
1018 * This is more or less hmac_md5 from the HMAC IETF draft, Appendix.
1020 static void *
1021 chksum(void *buf, int len)
1023 u_char *digest;
1024 struct ipkdb_MD5Context context;
1027 * the HMAC_MD5 transform looks like:
1029 * MD5(K XOR opad, MD5(K XOR ipad, text))
1031 * where K is an n byte key
1032 * ipad is the byte 0x36 repeated 64 times
1033 * opad is the byte 0x5c repeated 64 times
1034 * and text is the data being protected
1037 * Since we've already done the precomputation,
1038 * we can now stuff the data into the relevant
1039 * preinitialized contexts to get the result.
1042 * perform inner MD5
1044 ipkdbcopy(&icontext, &context, sizeof context);
1045 ipkdb_MD5Update(&context, buf, len);
1046 digest = ipkdb_MD5Final(&context);
1048 * perform outer MD5
1050 ipkdbcopy(&ocontext, &context, sizeof context);
1051 ipkdb_MD5Update(&context, digest, 16);
1052 return ipkdb_MD5Final(&context);
1055 static void
1056 getpkt(struct ipkdb_if *ifp, char *buf, int *lp)
1058 char *got;
1059 int l;
1060 char _ibuf[ETHERMTU + 16];
1061 #define ibuf (_ibuf + 2) /* align ip data in packet */
1063 *lp = 0;
1064 while (1) {
1065 if (!(got = inpkt(ifp, ibuf, ipkdbpanic != 0))) {
1066 *lp = 0;
1067 return;
1069 if ( ifp->seq == getnl(got)
1070 && got[6] >= 'A'
1071 && got[6] <= 'Z'
1072 && (l = getns(got + 4))
1073 && !ipkdbcmp(chksum(got, l + 6), got + l + 6, LENCHK)) {
1074 ipkdbcopy(got + 6, buf, *lp = l);
1075 return;
1077 if ( ifp->pktlen
1078 && ((ifp->flags & (IPKDB_MYIP | IPKDB_HISIP | IPKDB_CONNECTED))
1079 == (IPKDB_MYIP | IPKDB_HISIP | IPKDB_CONNECTED)))
1080 outpkt(ifp, ifp->pkt, ifp->pktlen, IPKDBPORT, ifp->hisport);
1082 #undef ibuf
1085 static void
1086 putpkt(struct ipkdb_if *ifp, const char *buf, int l)
1088 setnl(ifp->pkt, ifp->seq++);
1089 setns(ifp->pkt + 4, l);
1090 ipkdbcopy(buf, ifp->pkt + 6, l);
1091 ipkdbcopy(chksum(ifp->pkt, l + 6), ifp->pkt + 6 + l, LENCHK);
1092 ifp->pktlen = l + 6 + LENCHK;
1093 if ( (ifp->flags & (IPKDB_MYIP | IPKDB_HISIP | IPKDB_CONNECTED))
1094 != (IPKDB_MYIP | IPKDB_HISIP | IPKDB_CONNECTED))
1095 return;
1096 outpkt(ifp, ifp->pkt, ifp->pktlen, IPKDBPORT, ifp->hisport);
1099 static int
1100 check_ipkdb(struct ipkdb_if *ifp, struct in_addr *shost, char *p, int l)
1102 u_char hisenet[6];
1103 u_char hisinet[4];
1104 u_int16_t hisport;
1105 char save;
1107 #ifndef IPKDBSECURE
1108 if (kauth_authorize_system(curlwp->l_cred, KAUTH_SYSTEM_DEBUG,
1109 KAUTH_REQ_SYSTEM_DEBUG_IPKDB, NULL, NULL, NULL))
1110 return 0;
1111 #endif
1112 if (ipkdbcmp(chksum(p, l), p + l, LENCHK))
1113 return 0;
1114 ipkdbcopy(ifp->hisenetaddr, hisenet, sizeof hisenet);
1115 ipkdbcopy(ifp->hisinetaddr, hisinet, sizeof hisinet);
1116 hisport = ifp->hisport;
1117 save = ifp->flags;
1118 ipkdbcopy(shost, ifp->hisinetaddr, sizeof ifp->hisinetaddr);
1119 ifp->flags &= ~IPKDB_HISHW;
1120 ifp->flags |= IPKDB_HISIP;
1121 if (connectipkdb(ifp, p + 6, l - 6) < 0) {
1122 ipkdbcopy(hisenet, ifp->hisenetaddr, sizeof ifp->hisenetaddr);
1123 ipkdbcopy(hisinet, ifp->hisinetaddr, sizeof ifp->hisinetaddr);
1124 ifp->hisport = hisport;
1125 ifp->flags = save;
1126 return 0;
1128 return 1;
1132 * Should check whether packet came across the correct interface. XXX
1135 checkipkdb(struct in_addr *shost, u_short sport, u_short dport, struct mbuf *m, int off, int len)
1137 char *p;
1138 int l;
1139 char ibuf[ETHERMTU+50];
1141 if (dport != IPKDBPORT)
1142 return 0;
1143 if (len > sizeof ibuf)
1144 return 0;
1145 m_copydata(m, off, len, ibuf);
1146 p = ibuf;
1147 if (getnl(p) || p[6] != 'O')
1148 return 0;
1149 l = getns(p + 4);
1150 if (l > len - 6 || !check_ipkdb(&ipkdb_if, shost, p, l + 6))
1151 return 0;
1152 ipkdb_if.hisport = sport;
1153 ipkdb_connect(1);
1154 return 1;
1157 static int
1158 connectipkdb(struct ipkdb_if *ifp, char *buf, int l)
1160 char *cp;
1161 u_char *ip;
1163 if (*buf != 'O')
1164 return -1;
1165 if (getnl(buf + 1) == ifp->id)
1166 /* It's a retry of a connect packet, ignore it */
1167 return -1;
1168 ip = ifp->hisinetaddr;
1169 printf("debugged by ");
1170 l -= 1 + sizeof(u_int32_t);
1171 for (cp = buf + 1 + sizeof(u_int32_t); --l >= 0; printf("%c", *cp++));
1172 printf(" (%d.%d.%d.%d)\n", ip[0], ip[1], ip[2], ip[3]);
1173 ifp->flags |= IPKDB_CONNECTED;
1174 ifp->seq = 0;
1175 ifp->pktlen = 0;
1176 ifp->id = getnl(buf + 1);
1177 return 0;