]> jfr.im git - irc/quakenet/newserv.git/commitdiff
merge
authorPaul <redacted>
Sat, 26 Jan 2008 18:27:14 +0000 (18:27 +0000)
committerPaul <redacted>
Sat, 26 Jan 2008 18:27:14 +0000 (18:27 +0000)
83 files changed:
.hgignore
channel/channelhandlers.c
chanprofile/Makefile [new file with mode: 0644]
chanprofile/chanprofile.c [new file with mode: 0644]
chanprofile/chanprofile.h [new file with mode: 0644]
chanserv/Makefile
chanserv/newsearch/Makefile [new file with mode: 0644]
chanserv/newsearch/cs-newsearch.c [new file with mode: 0644]
chanserv/newsearch/formats.c [new file with mode: 0644]
control/control.c
core/events-epoll.c
core/events-poll.c
core/modules.c
core/modules.h
core/nsmalloc.h
depmod.pl [changed mode: 0755->0644]
geoip/geoip.c
geoip/geoip.h
helpmod2/hcommands.c
lib/Makefile
lib/helix.c [deleted file]
lib/helix.h [deleted file]
lib/irc_ipv6.c
lib/irc_ipv6.h
lib/patricia.c
lib/rijndael.c [new file with mode: 0644]
lib/rijndael.h [new file with mode: 0644]
lib/sha2.c [new file with mode: 0644]
lib/sha2.h [new file with mode: 0644]
lib/sstring [changed mode: 0755->0644]
lua/Makefile
lua/lua.c
lua/lua.h
lua/luabot.c
lua/luacommands.c
lua/luadb.c [new file with mode: 0644]
lua/luasocket.c [new file with mode: 0644]
lua/luasocket.h [new file with mode: 0644]
mkflat.pl [changed mode: 0755->0644]
newsearch/Makefile
newsearch/formats.c [new file with mode: 0644]
newsearch/newsearch.c
newsearch/newsearch.h
newsearch/ns-authts.c [new file with mode: 0644]
newsearch/ns-channels.c [new file with mode: 0644]
newsearch/ns-country.c
newsearch/ns-gline.c
newsearch/ns-kick.c [new file with mode: 0644]
newsearch/ns-kill.c
newsearch/ns-not.c
newsearch/ns-server.c [new file with mode: 0644]
nick/nick.c
nick/nick.h
noperserv/noperserv_commands.c
noperserv/noperserv_fakeuser.c
nterface/esockets.c
nterface/esockets.h
nterface/library.c
nterface/library.h
nterface/nterfacer.c
nterface/nterfacer.h
nterface/nterfacer_chanstats.c
nterface/nterfacer_control.c
nterface/nterfacer_control.h
nterface/nterfacer_country.c
pqsql/pqsql.c
pqsql/pqsql.h
proxyscan/Makefile
proxyscan/proxyscan.c
proxyscan/proxyscanalloc.c
proxyscan/proxyscandb.c
proxyscan/proxyscanhandlers.c
proxyscan/proxyscanqueue.c
regexgline/regexgline.c
regexgline/regexgline.h
request/request.c
request/request_block.c
request/request_block.h
request/sqrequest.c
request/sqrequest.h
testmod/testmod.c
trojanscan/trojanscan.c
trojanscan/trojanscan.h

index 12c4dc024bb5fd954548fac96de18b4995b37ab2..9c1912caa035f4fe20189fdb40916463fdaebc7f 100644 (file)
--- a/.hgignore
+++ b/.hgignore
@@ -6,4 +6,7 @@ syntax: glob
 local.in
 newserv
 modules/
-newserv.local.conf
+newserv.conf
+chanservlog.*
+logs/*
+core/events.c
index fe45face3b60192b3cbea5c3a3bb1ae517342303..49d6c154e3c4fc09040db26126c937cc2b5611d8 100644 (file)
@@ -257,6 +257,7 @@ int handlejoinmsg(void *source, int cargc, char **cargv) {
         /* Send hook */
         harg[0]=ch[i];
         harg[1]=np;
+        harg[2]=NULL;
         triggerhook(HOOK_CHANNEL_PART,harg);
         delnickfromchannel(ch[i],np->numeric,0);
       }
@@ -283,16 +284,23 @@ int handlejoinmsg(void *source, int cargc, char **cargv) {
         if (newchan) {
           delchannel(cp);
         } 
-      } else { 
+      } else {
+        chanindex *cip=cp->index;
+         
         /* If we just created a channel, flag it */
         if (newchan) {
           triggerhook(HOOK_CHANNEL_NEWCHANNEL,cp);
         }
-
-        /* send hook */
-        harg[0]=cp;
-        harg[1]=np;
-        triggerhook(HOOK_CHANNEL_JOIN,harg);
+        
+        /* Don't send HOOK_CHANNEL_JOIN if the channel doesn't exist any
+         * more (can happen if something destroys it in response to
+         * HOOK_CHANNEL_NEWCHANNEL) */
+        if (cp == cip->channel) {
+          /* send hook */
+          harg[0]=cp;
+          harg[1]=np;
+          triggerhook(HOOK_CHANNEL_JOIN,harg);
+        }
       }
     }
     nextchan=pos;
@@ -354,16 +362,22 @@ int handlecreatemsg(void *source, int cargc, char **cargv) {
       if (newchan) {
         delchannel(cp);
       }
-    } else {  
+    } else {
+      chanindex *cip = cp->index;
+        
       /* Flag the channel as new if necessary */
       if (newchan) {
         triggerhook(HOOK_CHANNEL_NEWCHANNEL,cp);
       }
     
-      /* Trigger hook */
-      harg[0]=cp;
-      harg[1]=np;
-      triggerhook(HOOK_CHANNEL_CREATE,harg);
+      /* If HOOK_CHANNEL_NEWCHANNEL has caused the channel to be deleted,
+       * don't trigger the CREATE hook. */
+      if (cip->channel == cp) {
+        /* Trigger hook */
+        harg[0]=cp;
+        harg[1]=np;
+        triggerhook(HOOK_CHANNEL_CREATE,harg);
+      }
     }
     nextchan=pos;
   }
diff --git a/chanprofile/Makefile b/chanprofile/Makefile
new file mode 100644 (file)
index 0000000..af4364c
--- /dev/null
@@ -0,0 +1,6 @@
+
+.PHONY: all
+all: chanprofile.so
+
+chanprofile.so: chanprofile.o
+       ld -shared -Bdynamic -o $@ $^
diff --git a/chanprofile/chanprofile.c b/chanprofile/chanprofile.c
new file mode 100644 (file)
index 0000000..0907f74
--- /dev/null
@@ -0,0 +1,187 @@
+
+#include "chanprofile.h"
+#include "../channel/channel.h"
+#include "../control/control.h"
+#include "../newsearch/newsearch.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+unsigned int activeprofiles;
+struct chanprofile *cptable[CPHASHSIZE];
+
+struct chanprofile *getcprec(nick *np) {
+  unsigned int hash=0,mhash;
+  unsigned int ccount=0;
+  unsigned int clen=0;
+  unsigned int i;
+  struct chanprofile *cpp;
+  
+  struct channel **cs=(np->channels->content);
+  
+  ccount=np->channels->cursi;
+  
+  for (i=0;i<np->channels->cursi;i++) {
+    clen+=cs[i]->index->name->length;
+    hash ^= (unsigned int )cs[i];
+  }
+  
+  mhash=hash%CPHASHSIZE;
+  
+  for (cpp=cptable[mhash];cpp;cpp=cpp->next) {
+    if ((cpp->hashval==hash) && (cpp->ccount==ccount) && 
+          (cpp->clen==clen)) 
+      return cpp;
+  }
+  
+  cpp=malloc(sizeof(struct chanprofile));
+  
+  cpp->clones=0;
+  cpp->hashval=hash;
+  cpp->ccount=ccount;
+  cpp->clen=clen;
+  cpp->nicks=NULL;
+  cpp->next=cptable[mhash];
+  cptable[mhash]=cpp;
+  
+  activeprofiles++;
+  
+  return cpp;
+}
+
+void popprofiles() {
+  unsigned int i;
+  struct chanprofile *cpp;
+  nick *np;
+  
+  /* Create the chanprofile records and count clones for each profile */
+  for (i=0;i<NICKHASHSIZE;i++) {
+    for (np=nicktable[i];np;np=np->next) {
+      cpp=getcprec(np);
+      cpp->clones++;
+    }
+  }
+  
+  /* Allocate space for nick array in each profile */
+  for (i=0;i<CPHASHSIZE;i++) {
+    for (cpp=cptable[i];cpp;cpp=cpp->next) {
+      cpp->nicks=(nick **)malloc(cpp->clones * sizeof(nick *));
+      cpp->clones=0;
+    }
+  }
+  
+  /* Populate the nick arrays */
+  for (i=0;i<NICKHASHSIZE;i++) {
+    for (np=nicktable[i];np;np=np->next) {
+      cpp=getcprec(np);
+      cpp->nicks[cpp->clones++]=np;
+    }
+  }
+}
+
+void clearprofiles() {
+  unsigned int i;
+  struct chanprofile *cpp, *ncpp;
+  
+  for (i=0;i<CPHASHSIZE;i++) {
+    for (cpp=cptable[i];cpp;cpp=ncpp) {
+      ncpp=cpp->next;
+      free(cpp->nicks);
+      free(cpp);
+    }
+    cptable[i]=NULL;
+  }
+  
+  activeprofiles=0;
+}
+
+int cpcompare(const void *a, const void *b) {
+  const struct chanprofile **cpa=a, **cpb=b;
+  
+  return (*cpb)->clones - (*cpa)->clones;
+}
+
+void reportprofile(nick *sender, struct chanprofile *cpp) {
+  channel **cps, *cp;
+  unsigned int i;
+  nick *np;
+  char buf[1024];
+  unsigned int repwidth=80;
+  unsigned int bufpos;
+  
+  controlreply(sender,"============================================================");
+
+  if (cpp->ccount==0) {
+    controlreply(sender,"(no channels): %u users",cpp->clones);
+    return;
+  }
+  
+  controlreply(sender,"Channels (%u):",cpp->ccount);
+  
+  np=cpp->nicks[0];
+  cps=np->channels->content;
+  bufpos=0;
+  for (i=0;i<np->channels->cursi;i++) {
+    cp=cps[i];
+    if (bufpos && ((bufpos + cp->index->name->length) > repwidth)) {
+      controlreply(sender," %s",buf);
+      bufpos=0;
+    }
+    
+    bufpos += sprintf(buf+bufpos,"%s ",cp->index->name->content);
+  }
+  
+  if (bufpos)
+    controlreply(sender," %s",buf);
+    
+  controlreply(sender,"Users (%u):",cpp->clones);
+  
+  for (i=0;i<cpp->clones;i++) {
+    printnick(sender,cpp->nicks[i]);
+  }
+}
+
+int reportprofiles(void *source, int cargc, char **cargv) {
+  unsigned int i,j;
+  struct chanprofile **cpary, *cpp;
+  unsigned int repnum=20;
+  nick *sender=source;
+  
+  if (cargc>0) 
+    repnum=strtoul(cargv[0],NULL,10);
+  
+  popprofiles();
+  
+  /* Make a big fat array */
+  cpary=malloc(activeprofiles*sizeof(struct chanprofile *));
+  for (i=0,j=0;i<CPHASHSIZE;i++)
+    for (cpp=cptable[i];cpp;cpp=cpp->next)
+      cpary[j++]=cpp;
+
+  controlreply(sender,"Populated array, lest number=%u (should be %u)",j,activeprofiles);
+      
+  qsort(cpary, activeprofiles, sizeof(struct chanprofile *), cpcompare); 
+  
+  controlreply(sender,"Top %u channel profiles (%u total):",repnum,activeprofiles);
+  
+  for (i=0;i<repnum;i++) {
+    reportprofile(sender,cpary[i]);
+  }
+   
+  controlreply(sender,"--- End of list."); 
+
+  clearprofiles();  
+  
+  return CMD_OK;
+}
+
+void _init() {
+  memset(cptable,0,sizeof(cptable));
+  registercontrolhelpcmd("chanprofiles",NO_DEVELOPER,1,reportprofiles,"Usage: chanprofiles [count]\nDisplays the most common channel profiles.  count defaults to 20.");
+}
+
+void _fini() {
+  deregistercontrolcmd("chanprofiles",reportprofiles);
+}
+
diff --git a/chanprofile/chanprofile.h b/chanprofile/chanprofile.h
new file mode 100644 (file)
index 0000000..5e49c31
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef CHANPROFILE_H
+#define CHANPROFILE_H
+
+#include "../nick/nick.h"
+
+#define CPHASHSIZE     50000
+
+struct chanprofile {
+  unsigned int clones;
+  unsigned int hashval;
+  unsigned int ccount;
+  unsigned int clen;
+  nick **nicks;
+  struct chanprofile *next;
+};
+
+struct chanprofile *cptable[CPHASHSIZE];
+
+#endif
index 7cbd818be07d122f67d4bf5b34d69962ffd0f0ba..981191e83a791125206b486c48048cac666f5b8c 100644 (file)
@@ -1,5 +1,5 @@
 
-CSDIRS=database chancmds usercmds authcmds authtracker
+CSDIRS=database chancmds usercmds authcmds authtracker newsearch
 
 .PHONY: all dirs clean
 all: chanserv.so chanserv_protect.so chanserv_grep.so chanserv_chansearch.so chanserv_authlib.so dirs
diff --git a/chanserv/newsearch/Makefile b/chanserv/newsearch/Makefile
new file mode 100644 (file)
index 0000000..5eec26e
--- /dev/null
@@ -0,0 +1,7 @@
+
+.PHONY: all
+all: chanserv_newsearch.so
+
+chanserv_newsearch.so: cs-newsearch.o formats.o 
+       ld -shared -Bdynamic -o $@ $^
+        
diff --git a/chanserv/newsearch/cs-newsearch.c b/chanserv/newsearch/cs-newsearch.c
new file mode 100644 (file)
index 0000000..0a01d25
--- /dev/null
@@ -0,0 +1,16 @@
+#include "../../newsearch/newsearch.h"
+#include "../chanserv.h"
+
+/* formats.c */
+void printnick_auth(nick *, nick *);
+void printnick_authchans(nick *, nick *);
+
+void _init() {
+  regnickdisp("auth", printnick_auth);
+  regnickdisp("authchans", printnick_authchans);
+}
+
+void _fini() {
+  unregnickdisp("auth", printnick_auth);
+  unregnickdisp("authchans", printnick_authchans);
+}
diff --git a/chanserv/newsearch/formats.c b/chanserv/newsearch/formats.c
new file mode 100644 (file)
index 0000000..d4bb638
--- /dev/null
@@ -0,0 +1,58 @@
+#include "../chanserv.h"
+#include "../../newsearch/newsearch.h"
+#include "../../control/control.h"
+
+void printnick_auth(nick *sender, nick *np) {
+  struct reguser *rup;
+  
+  if (!(rup=getreguserfromnick(np))) {
+    controlreply(sender,"%s (not authed)",np->nick);
+  } else {
+    controlreply(sender,"%s (%s/%u) (%s) (%s)",np->nick,rup->username,rup->ID,
+        rup->email ? rup->email->content : "no email",
+        rup->comment ? rup->comment->content : "no comment" );
+  }
+}
+
+void printnick_authchans(nick *sender, nick *np) {
+  struct reguser *rup;
+  struct regchanuser *rcup;
+  char thebuf[1024];
+  char buf2[512];
+  unsigned int bufpos=0, buf2len;
+  unsigned char ch;
+  
+  printnick_auth(sender,np);
+  
+  if (!(rup=getreguserfromnick(np)))
+    return;
+  
+  if (!rup->knownon) {
+    controlreply(sender, " (no channels)");
+  } else {
+    for (rcup=rup->knownon;rcup;rcup=rcup->nextbyuser) {
+      if (CUIsOwner(rcup))
+        ch='*';
+      else if (CUHasMasterPriv(rcup))
+        ch='&';
+      else if (CUHasOpPriv(rcup))
+        ch='@';
+      else if (CUHasVoicePriv(rcup))
+        ch='+';
+      else if (CUKnown(rcup))
+        ch=' ';
+      else 
+        ch='!';
+      
+      buf2len=sprintf(buf2,"%c%s",ch,rcup->chan->index->name->content);
+
+      if (buf2len+bufpos > 400) {
+        controlreply(sender," %s", thebuf);
+        bufpos=0;
+      } 
+      bufpos+=sprintf(thebuf+bufpos,"%s ",buf2);
+    }
+    if (bufpos)
+      controlreply(sender," %s", thebuf);
+  }
+}
index a632418068ea740fafdeda21b42523946a3268a5..741fa079b1ed4e2474da3ceed675cc67d23b62ff 100644 (file)
@@ -111,7 +111,7 @@ void controlconnect(void *arg) {
   myrealname=getcopyconfigitem("control","realname","NewServ Control Service",REALLEN);
   myauthname=getcopyconfigitem("control","authname","C",ACCOUNTLEN);
 
-  mynick=registerlocaluser(cnick->content,myident->content,myhost->content,myrealname->content,myauthname->content,UMODE_SERVICE|UMODE_DEAF|UMODE_OPER|UMODE_ACCOUNT,&handlemessages);
+  mynick=registerlocaluser(cnick->content,myident->content,myhost->content,myrealname->content,myauthname->content,UMODE_SERVICE|UMODE_DEAF|UMODE_OPER|UMODE_ACCOUNT|UMODE_INV,&handlemessages);
   triggerhook(HOOK_CONTROL_REGISTERED, mynick);
   cp=findchannel("#twilightzone");
   if (!cp) {
@@ -388,7 +388,6 @@ int controlchannel(void *sender, int cargc, char **cargv) {
         buf[i*18]=' ';
     }
   }
-  
 
   for (cbp=cp->bans;cbp;cbp=cbp->next) {
     controlreply((nick *)sender,"Ban     : %s",bantostringdebug(cbp));
index 4db945d260d9844dc191776b1aa51990c55eecde..3cb3a7a19ae4f908a6bbbac2af79d4ca7f1e788d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * events.c: the event handling core, poll() version
+ * events.c: the event handling core, epoll() version
  */
 
 #include <stdio.h>
index 6f2812a064a652b638126ecd4d69fe7c75c6a1a5..51ca8478de1d2f969cec44e42a72373fabc04832 100644 (file)
@@ -69,9 +69,9 @@ void checkindex(unsigned index) {
   }
 
   eventfds=(struct pollfd *)realloc((void *)eventfds,maxfds*sizeof(struct pollfd));
-  memset(&eventfds[oldmax],0,maxfds-oldmax);
+  memset(&eventfds[oldmax],0,(maxfds-oldmax)*sizeof(struct pollfd));
   eventhandlers=(reghandler *)realloc((void *)eventhandlers,maxfds*sizeof(reghandler));
-  memset(&eventhandlers[oldmax],0,maxfds-oldmax);
+  memset(&eventhandlers[oldmax],0,(maxfds-oldmax)*sizeof(reghandler));
 }
 
 /* 
index 92857f085e336b72d00700eb6b637228dbb349c0..688285a480a594fd8c8d060bace4b0476ffe99e3 100644 (file)
@@ -455,3 +455,14 @@ void newserv_shutdown() {
   
   Error("core",ERR_INFO,"All modules removed.  Exiting.");
 }
+
+/* very slow, make sure you cache the pointer! */
+void *ndlsym(char *modulename, char *fn) {
+  module *mods=(module *)(modules.content);
+  int i=getindex(modulename);
+
+  if (i<0)
+    return NULL;
+
+  return dlsym(mods[i].handle, fn);
+}
index 227fd6722012c60bff1b94edded3f1e508b5bc78..24b352e0a2b5021f726d8a521a921f406c07776d 100644 (file)
@@ -25,6 +25,7 @@ void preparereload(char *modulename);
 void reloadmarked(void);
 void safereload(char *themodule);
 void newserv_shutdown();
+void *ndlsym(char *module, char *fn);
 
 extern int newserv_shutdown_pending;
 
index f6e8e906cd857c92d0b16b4f897d9d594250ee24..bd113abe3f8b6a44ee1e04425be7f198861b8df3 100644 (file)
@@ -18,3 +18,4 @@ void nsexit(void);
 #define POOL_CHANSERVDB                5
 #define POOL_SSTRING           6
 #define POOL_AUTHTRACKER       7
+#define POOL_PROXYSCAN         8
old mode 100755 (executable)
new mode 100644 (file)
index 1a3cae61ba4ca6aa9d553f5d569c32ce16cad2ae..6c1db14d3c321ff70592439c5d63a50c8032b7ba 100644 (file)
 #include "../control/control.h"
 #include "../lib/version.h"
 
+#include <strings.h>
+
 #include "libGeoIP/GeoIP.h"
 #include "geoip.h"
 
-#warning This module is GPL'ed. Load/link at your peril.
+#warning This module is GPLed. Load/link at your peril.
 
 MODULE_VERSION("");
 
@@ -115,3 +117,11 @@ void geoip_whois_handler(int hooknum, void *arg) {
   }
 }
 
+int geoip_lookupcode(char *code) {
+  int i;
+  for(i=COUNTRY_MIN;i<COUNTRY_MAX;i++)
+    if(!strcasecmp(code, GeoIP_country_code[i]))
+      return i;
+
+  return -1;
+}
index 600f4d8c4c93b3a003d072b1ac3d751b5f070702..cabb92338bb8db873867406fd6513383e93239db 100644 (file)
@@ -3,3 +3,6 @@
 
 extern int geoip_totals[COUNTRY_MAX + 1];
 
+int geoip_lookupcode(char *code);
+typedef int (*GeoIP_LookupCode)(char *);
+
index 672c041c257b988c4e51c510b36361cd08f6284b..38e0fdc9dd1adf152052a251857c5d88b242e1ff 100644 (file)
@@ -2657,9 +2657,9 @@ static void helpmod_cmd_checkchannel(huser *sender, channel* returntype, char* o
            if (IsAccount(nck))
                 authed_count++;
 
-            if (IsOper(nck) && strlen(nck->nick) > 1)
+            if (IsOper(nck) && strlen(nck->nick) > 1 && (IsSecret(chan) || IsPrivate(chan) || IsKey(chan) || IsInviteOnly(chan)))
             {
-                helpmod_reply(sender, returntype, "Cannot check channel: Permission denied. Channel %s has an oper on it", argv[0]);
+                helpmod_reply(sender, returntype, "Cannot check channel: Permission denied. Channel %s has an oper on it and one or more of +i/+k/+p/+s", argv[0]);
                 return;
             }
        }
index d5c9359b02047f45fce8254702b5a2e2b9ef0275..ff14691b2490f7df192e9e6de569c32aa560b068 100644 (file)
@@ -1,3 +1,3 @@
 
 .PHONY: all
-all: sstring.o array.o splitline.o base64.o flags.o irc_string.o malloc.o strlfunc.o sha1.o helix.o irc_ipv6.o patricia.o
+all: sstring.o array.o splitline.o base64.o flags.o irc_string.o malloc.o strlfunc.o sha1.o irc_ipv6.o patricia.o rijndael.o sha2.o
diff --git a/lib/helix.c b/lib/helix.c
deleted file mode 100644 (file)
index 7330d16..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-/* Cleanroom reference implementation of Helix */
-
-/* HEAVILY modified by Chris Porter to support contexts. */
-
-/* See Ferguson et. al, Fast Software Encryption 2003, or
- * http://www.macfergus.com/helix/helixPreproc.pdf
- */
-
-#include <string.h>
-#include "helix.h"
-
-/* some useful macros -- little-endian */
-#define B(x,i) ((UCHAR)(((x) >> (8*i)) & 0xFF))
-#define BYTE2WORD(b) ( \
-       (((WORD)(b)[3] & 0xFF)<<24) | \
-       (((WORD)(b)[2] & 0xFF)<<16) | \
-       (((WORD)(b)[1] & 0xFF)<<8) | \
-       (((WORD)(b)[0] & 0xFF)) \
-)
-#define WORD2BYTE(w, b) { \
-       (b)[3] = B(w,3); \
-       (b)[2] = B(w,2); \
-       (b)[1] = B(w,1); \
-       (b)[0] = B(w,0); \
-}
-#define XORWORD(w, b) { \
-       (b)[3] ^= B(w,3); \
-       (b)[2] ^= B(w,2); \
-       (b)[1] ^= B(w,1); \
-       (b)[0] ^= B(w,0); \
-}
-#define ROTL(w,x) (((w) << (x))|((w) >> (32 - (x))))
-
-/* 3.2, figure 2, block function */
-WORD
-h_block(struct helix_ctx *ctx, WORD X_i0, WORD P_i, WORD X_i1)
-{
-    WORD    r;
-
-    r = ctx->A; /* for returning later */
-    ctx->A += ctx->D;      ctx->D = ROTL(ctx->D, 15);
-    ctx->B += ctx->E;      ctx->E = ROTL(ctx->E, 25);
-    ctx->C ^= ctx->A;      ctx->A = ROTL(ctx->A, 9);
-    ctx->D ^= ctx->B;      ctx->B = ROTL(ctx->B, 10);
-    ctx->E += ctx->C;      ctx->C = ROTL(ctx->C, 17);
-    ctx->A ^= ctx->D + X_i0;  ctx->D = ROTL(ctx->D, 30);
-    ctx->B ^= ctx->E;      ctx->E = ROTL(ctx->E, 13);
-    ctx->C += ctx->A;      ctx->A = ROTL(ctx->A, 20);
-    ctx->D += ctx->B;      ctx->B = ROTL(ctx->B, 11);
-    ctx->E ^= ctx->C;      ctx->C = ROTL(ctx->C, 5);
-    ctx->A += ctx->D ^ P_i;   ctx->D = ROTL(ctx->D, 15);
-    ctx->B += ctx->E;      ctx->E = ROTL(ctx->E, 25);
-    ctx->C ^= ctx->A;      ctx->A = ROTL(ctx->A, 9);
-    ctx->D ^= ctx->B;      ctx->B = ROTL(ctx->B, 10);
-    ctx->E += ctx->C;      ctx->C = ROTL(ctx->C, 17);
-    ctx->A ^= ctx->D + X_i1;  ctx->D = ROTL(ctx->D, 30);
-    ctx->B ^= ctx->E;      ctx->E = ROTL(ctx->E, 13);
-    ctx->C += ctx->A;      ctx->A = ROTL(ctx->A, 20);
-    ctx->D += ctx->B;      ctx->B = ROTL(ctx->B, 11);
-    ctx->E ^= ctx->C;      ctx->C = ROTL(ctx->C, 5);
-    /* increment i in funny way */
-    if (++ctx->h_iplus8[0] == 0x80000000lu) {
-       ++ctx->h_iplus8[1];
-       ctx->h_iplus8[0] = 0;
-    }
-    return r;
-}
-
-/* 3.7 Key schedule.
- * Could do feistel in place, but this follows description in paper.
- */
-void
-h_key(struct helix_ctx *ctx, unsigned char *U, int U_len)
-{
-    WORD    k[40]; /* room for key schedule */
-    int            i;
-
-    if (U_len > 32)
-       U_len = 32; /* limit size of key */
-    memset((void *)k, 0, sizeof k);
-    memcpy((void *)&k[32], U, U_len);
-    ctx->h_iplus8[0] = ctx->h_iplus8[1] = 0;
-
-    for (i = 32; i < 40; ++i)
-       k[i] = BYTE2WORD(((unsigned char *)&k[i])); /* convert to words */
-    for (i = 7; i >= 0; --i) {
-       ctx->A = k[4*i+4];
-       ctx->B = k[4*i+5];
-       ctx->C = k[4*i+6];
-       ctx->D = k[4*i+7];
-       ctx->E = U_len + 64;
-       (void)h_block(ctx, 0, 0, 0);
-       k[4*i+0] = ctx->A ^ k[4*i+8];
-       k[4*i+1] = ctx->B ^ k[4*i+9];
-       k[4*i+2] = ctx->C ^ k[4*i+10];
-       k[4*i+3] = ctx->D ^ k[4*i+11];
-    }
-    /* copy into K */
-    for (i = 0; i < 8; ++i)
-       ctx->K[i] = k[i];
-    /* remember length of key */
-    ctx->l_u = U_len;
-}
-
-/* 3.3, nonce setup */
-void
-h_nonce(struct helix_ctx *ctx, UCHAR nonce[16])
-{
-    ctx->N[0] = BYTE2WORD(&nonce[0]);
-    ctx->N[1] = BYTE2WORD(&nonce[4]);
-    ctx->N[2] = BYTE2WORD(&nonce[8]);
-    ctx->N[3] = BYTE2WORD(&nonce[12]);
-    ctx->N[4] = 0 - ctx->N[0];
-    ctx->N[5] = 1 - ctx->N[1];
-    ctx->N[6] = 2 - ctx->N[2];
-    ctx->N[7] = 3 - ctx->N[3];
-}
-
-/* 3.3, X_i functions */
-WORD
-X(struct helix_ctx *ctx, int one)
-{
-    WORD    x = 0;
-
-    if (one) {
-       x = ctx->K[(ctx->h_iplus8[0] + 4) & 0x07] + ctx->N[ctx->h_iplus8[0] & 0x07] + ctx->h_iplus8[0];
-       if ((ctx->h_iplus8[0] & 0x03) == 3)
-           x += ctx->h_iplus8[1];
-       else if ((ctx->h_iplus8[0] & 0x03) == 1)
-           x += ctx->l_u << 2;
-    }
-    else
-       x = ctx->K[ctx->h_iplus8[0] & 0x07];
-    return x;
-}
-
-/* 3.4 initialisation */
-void
-h_init(struct helix_ctx *ctx)
-{
-    int            i;
-
-    ctx->h_iplus8[0] = ctx->h_iplus8[1] = 0;
-    ctx->A = ctx->K[3] ^ ctx->N[0];
-    ctx->B = ctx->K[4] ^ ctx->N[1];
-    ctx->C = ctx->K[5] ^ ctx->N[2];
-    ctx->D = ctx->K[6] ^ ctx->N[3];
-    ctx->E = ctx->K[7];
-    for (i = 0; i < 8; ++i)
-       (void) h_block(ctx, X(ctx, 0), 0, X(ctx, 1));
-}
-
-/* 3.5 encryption, and 3.6 compute MAC */
-void
-h_encrypt(struct helix_ctx *ctx, UCHAR *buf, int n, UCHAR macbuf[16])
-{
-    UCHAR   b[4];
-    WORD    w;
-    int            i;
-
-    h_init(ctx);
-    while (n >= 4) {
-       w = h_block(ctx, X(ctx, 0), BYTE2WORD(buf), X(ctx, 1));
-       XORWORD(w, buf);
-       buf += 4;
-       n -= 4;
-    }
-    if (n != 0) {
-       /* handle an odd bit at the end */
-       for (i = 0; i < n; ++i)
-           b[i] = buf[i];
-       for (/*...*/; i < 4; ++i)
-           b[i] = 0;
-       w = BYTE2WORD(b);
-       w = h_block(ctx, X(ctx,0), w, X(ctx,1));
-       XORWORD(w, b);
-       for (i = 0; i < n; ++i)
-           buf[i] = b[i];
-    }
-    /* now compute MAC. Note that "n" is currently l(P) mod 4. */
-    ctx->A ^= 0x912d94f1;
-    for (i = 0; i < 8; ++i)
-       (void) h_block(ctx, X(ctx,0), n, X(ctx,1));
-    for (i = 0; i < 4; ++i) {
-       w = h_block(ctx, X(ctx,0), n, X(ctx,1));
-       WORD2BYTE(w, &macbuf[i*4]);
-    }
-}
-
-/* 3.8 decryption, and 3.6 compute MAC */
-void
-h_decrypt(struct helix_ctx *ctx, UCHAR *buf, int n, UCHAR macbuf[16])
-{
-    UCHAR   b[4];
-    WORD    w;
-    int            i;
-
-    h_init(ctx);
-    while (n >= 4) {
-       /* rather than muck with h_block, we use knowledge of A */
-       w = BYTE2WORD(buf) ^ ctx->A; /* plaintext */
-       w = h_block(ctx, X(ctx,0), w, X(ctx,1));
-       XORWORD(w, buf);
-       buf += 4;
-       n -= 4;
-    }
-    if (n != 0) {
-       /* handle an odd bit at the end */
-       for (i = 0; i < n; ++i)
-           b[i] = buf[i];
-       XORWORD(ctx->A, b);
-       for (/*...*/; i < 4; ++i)
-           b[i] = 0;
-       w = BYTE2WORD(b);
-       (void) h_block(ctx, X(ctx,0), w, X(ctx,1)); /* note decryption already done */
-       for (i = 0; i < n; ++i)
-           buf[i] = b[i];
-    }
-    /* now compute MAC. Note that "n" is currently l(P) mod 4. */
-    ctx->A ^= 0x912d94f1;
-    for (i = 0; i < 8; ++i)
-       (void) h_block(ctx, X(ctx,0), n, X(ctx,1));
-    for (i = 0; i < 4; ++i) {
-       w = h_block(ctx, X(ctx,0), n, X(ctx,1));
-       WORD2BYTE(w, &macbuf[i*4]);
-    }
-}
-
-#ifdef TEST
-/*--------------------------------------------------------------------------*/
-/* test harness                                                             */
-/*--------------------------------------------------------------------------*/
-
-#include "hexlib.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-
-/* self test */
-void
-test_helix(int quick)
-{
-    extern int keylen;
-    UCHAR      key[32], nonce[16], buf[32], mac[16];
-    struct helix_ctx ctx;
-
-    /* basic test */
-    printf("Test Vector set 1:\n");
-    hexprint("Initial Key", key, 0);
-    memset((void *)nonce, 0, 16);
-    hexprint("Nonce", nonce, 16);
-    h_key(&ctx, key, 0);
-    h_nonce(&ctx, nonce);
-    hexwprint("Working Key", ctx.K, 32);
-    hexwcheck(ctx.K, "a9 3b 6e 32 bc 23 4f 6c 32 6c 0f 82 74 ff a2 41"
-                "e3 da 57 7d ef 7c 1b 64 af 78 7c 38 dc ef e3 de", 32);
-    hexwprint("Working N", ctx.N, 32);
-    memset(buf, 0, 10);
-    hexprint("Plaintext", buf, 10);
-    h_encrypt(&ctx, buf, 10, mac);
-    hexprint("Ciphertext", buf, 10);
-    hexcheck(buf, "70 44 c9 be 48 ae 89 22 66 e4", 10);
-    hexprint("MAC", mac, 16);
-    hexcheck(mac, "65 be 7a 60 fd 3b 8a 5e 31 61 80 80 56 32 d8 10", 16);
-    h_decrypt(&ctx, buf, 10, mac);
-    hexprint("decrypted", buf, 10);
-    hexprint("MAC", mac, 16);
-    hexcheck(mac, "65 be 7a 60 fd 3b 8a 5e 31 61 80 80 56 32 d8 10", 16);
-
-    /* second vector */
-    printf("\nTest Vector set 2:\n");
-    hexread(key, "00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00"
-                 "04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00", 32);
-    hexprint("Initial Key", key, 32);
-    hexread(nonce, "00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00", 16);
-    hexprint("Nonce", nonce, 16);
-    h_key(&ctx, key, 32);
-    h_nonce(&ctx, nonce);
-    hexwprint("Working Key", ctx.K, 32);
-    hexwcheck(ctx.K, "6e e9 a7 6c bd 0b f6 20 a6 d9 b7 59 49 d3 39 95"
-                "04 f8 4a d6 83 12 f9 06 ed d1 a6 98 9e c8 9d 45", 32);
-    hexread(buf, "00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00"
-                 "04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00", 32);
-    hexprint("Plaintext", buf, 32);
-    h_encrypt(&ctx, buf, 32, mac);
-    hexprint("Ciphertext", buf, 32);
-    hexcheck(buf, "7a 72 a7 5b 62 50 38 0b 69 75 1c d1 28 30 8d 9a"
-                 "0c 74 46 a3 bf 3f 99 e6 65 56 b9 c1 18 ca 7d 87", 32);
-    hexprint("MAC", mac, 16);
-    hexcheck(mac, "e4 e5 49 01 c5 0b 34 e7 80 c0 9c 39 b1 09 a1 17", 16);
-    h_decrypt(&ctx, buf, 32, mac);
-    hexprint("decrypted", buf, 32);
-    hexprint("MAC", mac, 16);
-    hexcheck(mac, "e4 e5 49 01 c5 0b 34 e7 80 c0 9c 39 b1 09 a1 17", 16);
-
-    /* third vector */
-    printf("\nTest Vector set 3:\n");
-    hexread(key, "48 65 6c 69 78", 5);
-    hexprint("Initial Key", key, 5);
-    hexread(nonce, "30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66", 16);
-    hexprint("Nonce", nonce, 16);
-    h_key(&ctx, key, 5);
-    h_nonce(&ctx, nonce);
-    hexwprint("Working Key", ctx.K, 32);
-    hexwcheck(ctx.K, "6c 1e d7 7a cb a3 a1 d2 8f 1c d6 20 6d f1 15 da"
-                "f4 03 28 4a 73 9b b6 9f 35 7a 85 f5 51 32 11 39", 32);
-    hexread(buf, "48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21", 13);
-    hexprint("Plaintext", buf, 13);
-    h_encrypt(&ctx, buf, 13, mac);
-    hexprint("Ciphertext", buf, 13);
-    hexcheck(buf, "6c 4c 27 b9 7a 82 a0 c5 80 2c 23 f2 0d", 13);
-    hexprint("MAC", mac, 16);
-    hexcheck(mac, "6c 82 d1 aa 3b 90 5f 12 f1 44 3f a7 f6 a1 01 d2", 16);
-    h_decrypt(&ctx, buf, 13, mac);
-    hexprint("decrypted", buf, 13);
-    hexprint("MAC", mac, 16);
-    hexcheck(mac, "6c 82 d1 aa 3b 90 5f 12 f1 44 3f a7 f6 a1 01 d2", 16);
-}
-
-#define BLOCKSIZE      1600    /* for MAC-style tests */
-#define MACSIZE                16
-char   *testkey = "test key 128bits";
-UCHAR  testIV[16];
-UCHAR  testframe[BLOCKSIZE];
-UCHAR  testmac[16];
-
-/* Perform various timing tests
- */
-UCHAR  bigbuf[1024*1024];
-UCHAR  macbuf[16];
-int
-main(int ac, char **av)
-{
-    int         n, i;
-    int                vflag = 0;
-    UCHAR      key[32], IV[32];
-    int         keysz, IVsz;
-    extern int keylen;
-    extern WORD        K[];
-
-    if (ac == 2 && strcmp(av[1], "-test") == 0) {
-        test_helix(0);
-        return nerrors;
-    }
-    if (ac >= 2 && strcmp(av[1], "-verbose") == 0) {
-       vflag = 1;
-       ++av, --ac;
-    }
-    return 0;
-}
-#endif /* TEST */
diff --git a/lib/helix.h b/lib/helix.h
deleted file mode 100644 (file)
index 82a17cf..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __helix_H
-#define __helix_H
-
-typedef unsigned long WORD;
-typedef unsigned char UCHAR;
-
-#define NONCE_LEN 16
-#define MAC_LEN   16
-
-/* HELIX variables */
-typedef struct helix_ctx {
-WORD   h_iplus8[2];            /* block number maintained in two parts */
-WORD   K[8];                   /* expanded key */
-WORD   N[8];                   /* expanded nonce */
-int    l_u;                    /* length of user key */
-WORD   A, B, C, D, E;          /* Z_0..Z_4 in the paper */
-} helix_ctx;
-
-#undef TEST
-
-void
-h_key(struct helix_ctx *ctx, unsigned char *U, int U_len);
-void
-h_nonce(struct helix_ctx *ctx, UCHAR nonce[16]);
-void
-h_encrypt(struct helix_ctx *ctx, UCHAR *buf, int n, UCHAR macbuf[16]);
-void
-h_decrypt(struct helix_ctx *ctx, UCHAR *buf, int n, UCHAR macbuf[16]);
-
-#endif
index 8b318e2c9f3adad925c47c8211bdcd84caac67b2..122c420eee39bbb236b2f1c38040fc9c9cf0d910 100644 (file)
@@ -6,7 +6,7 @@
 #include <netdb.h>
 #include "irc_ipv6.h"
 
-#warning This source file is probably GPL'ed, it needs relicensing.
+#warning This source file is probably GPLed, it needs relicensing.
 
 /*
  * this new faster inet_ntoa was ripped from:
index d78efc8d529b7bb85a944dbcb447cd0ed4483643..52ff90a208e10b64cde478deed85154c100388f7 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef __irc_ipv6_H
 #define __irc_ipv6_H
 
+#include <limits.h>
+
 /* from res.h */
 
 /** Structure to store an IP address. */
index d3dfb223860e31e1ff49ace83286d0fab91becb5..441b09e6803b2af4097865bce530430cd6e7196f 100644 (file)
@@ -16,7 +16,6 @@ static char copyright[] =
 "This product includes software developed by the University of Michigan, Merit"
 "Network, Inc., and their contributors.";
 
-#include <malloc.h>
 #include <assert.h> /* assert */
 #include <ctype.h> /* isdigit */
 #include <errno.h> /* errno */
@@ -322,6 +321,7 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
        node->prefix = patricia_ref_prefix (prefix);
        node->parent = NULL;
        node->l = node->r = NULL;
+       node->usercount = 0;
        patricia->head = node;
        patricia->num_active_node++;
        return (node);
@@ -393,6 +393,7 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
     new_node->prefix = patricia_ref_prefix (prefix);
     new_node->parent = NULL;
     new_node->l = new_node->r = NULL;
+    new_node->usercount = 0;
     patricia->num_active_node++;
 
     if (node->bit == differ_bit) {
@@ -435,6 +436,7 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
         glue->bit = differ_bit;
         glue->prefix = NULL;
         glue->parent = node->parent;
+        glue->usercount = 0;
         patricia->num_active_node++;
        if (differ_bit < patricia->maxbits &&
            (addr[differ_bit >> 3]) & (0x80 >> (differ_bit & 0x07))) {
diff --git a/lib/rijndael.c b/lib/rijndael.c
new file mode 100644 (file)
index 0000000..2d51535
--- /dev/null
@@ -0,0 +1,1206 @@
+#define FULL_UNROLL
+
+#include "rijndael.h"
+
+typedef unsigned long u32;
+typedef unsigned char u8;
+
+static const u32 Te0[256] =
+{
+  0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+  0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+  0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+  0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+  0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+  0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+  0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+  0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+  0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+  0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+  0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+  0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+  0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+  0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+  0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+  0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+  0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+  0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+  0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+  0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+  0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+  0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+  0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+  0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+  0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+  0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+  0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+  0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+  0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+  0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+  0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+  0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+  0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+  0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+  0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+  0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+  0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+  0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+  0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+  0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+  0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+  0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+  0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+  0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+  0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+  0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+  0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+  0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+  0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+  0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+  0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+  0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+  0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+  0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+  0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+  0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+  0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+  0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+  0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+  0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+  0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+  0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+  0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+  0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+
+static const u32 Te1[256] =
+{
+  0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+  0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+  0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+  0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+  0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+  0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+  0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+  0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+  0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+  0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+  0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+  0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+  0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+  0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+  0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+  0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+  0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+  0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+  0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+  0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+  0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+  0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+  0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+  0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+  0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+  0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+  0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+  0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+  0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+  0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+  0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+  0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+  0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+  0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+  0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+  0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+  0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+  0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+  0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+  0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+  0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+  0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+  0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+  0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+  0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+  0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+  0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+  0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+  0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+  0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+  0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+  0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+  0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+  0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+  0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+  0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+  0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+  0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+  0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+  0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+  0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+  0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+  0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+  0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+
+static const u32 Te2[256] =
+{
+  0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+  0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+  0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+  0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+  0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+  0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+  0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+  0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+  0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+  0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+  0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+  0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+  0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+  0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+  0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+  0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+  0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+  0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+  0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+  0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+  0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+  0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+  0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+  0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+  0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+  0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+  0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+  0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+  0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+  0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+  0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+  0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+  0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+  0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+  0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+  0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+  0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+  0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+  0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+  0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+  0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+  0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+  0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+  0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+  0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+  0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+  0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+  0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+  0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+  0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+  0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+  0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+  0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+  0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+  0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+  0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+  0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+  0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+  0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+  0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+  0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+  0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+  0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+  0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+
+static const u32 Te3[256] =
+{
+  0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+  0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+  0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+  0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+  0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+  0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+  0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+  0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+  0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+  0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+  0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+  0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+  0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+  0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+  0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+  0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+  0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+  0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+  0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+  0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+  0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+  0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+  0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+  0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+  0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+  0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+  0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+  0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+  0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+  0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+  0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+  0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+  0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+  0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+  0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+  0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+  0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+  0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+  0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+  0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+  0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+  0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+  0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+  0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+  0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+  0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+  0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+  0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+  0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+  0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+  0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+  0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+  0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+  0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+  0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+  0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+  0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+  0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+  0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+  0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+  0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+  0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+  0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+  0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+
+static const u32 Te4[256] =
+{
+  0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+  0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+  0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+  0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+  0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+  0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+  0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+  0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+  0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+  0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+  0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+  0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+  0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+  0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+  0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+  0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+  0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+  0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+  0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+  0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+  0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+  0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+  0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+  0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+  0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+  0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+  0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+  0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+  0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+  0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+  0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+  0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+  0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+  0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+  0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+  0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+  0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+  0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+  0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+  0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+  0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+  0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+  0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+  0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+  0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+  0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+  0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+  0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+  0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+  0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+  0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+  0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+  0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+  0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+  0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+  0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+  0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+  0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+  0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+  0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+  0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+  0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+  0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+  0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+
+static const u32 Td0[256] =
+{
+  0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+  0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+  0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+  0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+  0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+  0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+  0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+  0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+  0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+  0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+  0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+  0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+  0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+  0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+  0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+  0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+  0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+  0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+  0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+  0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+  0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+  0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+  0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+  0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+  0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+  0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+  0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+  0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+  0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+  0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+  0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+  0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+  0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+  0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+  0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+  0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+  0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+  0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+  0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+  0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+  0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+  0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+  0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+  0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+  0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+  0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+  0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+  0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+  0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+  0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+  0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+  0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+  0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+  0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+  0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+  0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+  0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+  0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+  0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+  0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+  0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+  0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+  0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+  0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+
+static const u32 Td1[256] =
+{
+  0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+  0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+  0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+  0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+  0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+  0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+  0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+  0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+  0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+  0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+  0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+  0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+  0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+  0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+  0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+  0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+  0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+  0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+  0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+  0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+  0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+  0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+  0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+  0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+  0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+  0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+  0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+  0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+  0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+  0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+  0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+  0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+  0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+  0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+  0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+  0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+  0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+  0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+  0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+  0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+  0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+  0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+  0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+  0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+  0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+  0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+  0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+  0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+  0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+  0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+  0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+  0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+  0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+  0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+  0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+  0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+  0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+  0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+  0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+  0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+  0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+  0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+  0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+  0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+
+static const u32 Td2[256] =
+{
+  0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+  0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+  0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+  0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+  0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+  0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+  0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+  0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+  0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+  0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+  0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+  0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+  0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+  0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+  0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+  0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+  0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+  0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+  0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+  0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+  0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+  0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+  0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+  0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+  0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+  0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+  0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+  0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+  0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+  0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+  0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+  0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+  0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+  0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+  0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+  0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+  0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+  0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+  0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+  0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+  0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+  0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+  0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+  0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+  0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+  0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+  0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+  0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+  0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+  0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+  0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+  0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+  0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+  0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+  0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+  0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+  0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+  0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+  0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+  0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+  0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+  0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+  0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+  0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+
+static const u32 Td3[256] =
+{
+  0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+  0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+  0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+  0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+  0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+  0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+  0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+  0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+  0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+  0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+  0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+  0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+  0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+  0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+  0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+  0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+  0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+  0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+  0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+  0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+  0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+  0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+  0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+  0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+  0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+  0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+  0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+  0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+  0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+  0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+  0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+  0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+  0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+  0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+  0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+  0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+  0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+  0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+  0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+  0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+  0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+  0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+  0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+  0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+  0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+  0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+  0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+  0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+  0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+  0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+  0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+  0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+  0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+  0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+  0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+  0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+  0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+  0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+  0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+  0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+  0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+  0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+  0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+  0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+
+static const u32 Td4[256] =
+{
+  0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+  0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+  0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+  0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+  0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+  0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+  0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+  0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+  0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+  0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+  0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+  0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+  0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+  0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+  0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+  0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+  0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+  0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+  0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+  0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+  0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+  0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+  0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+  0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+  0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+  0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+  0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+  0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+  0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+  0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+  0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+  0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+  0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+  0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+  0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+  0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+  0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+  0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+  0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+  0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+  0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+  0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+  0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+  0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+  0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+  0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+  0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+  0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+  0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+  0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+  0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+  0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+  0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+  0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+  0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+  0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+  0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+  0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+  0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+  0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+  0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+  0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+  0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+  0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+
+static const u32 rcon[] =
+{
+  0x01000000, 0x02000000, 0x04000000, 0x08000000,
+  0x10000000, 0x20000000, 0x40000000, 0x80000000,
+  0x1B000000, 0x36000000,
+  /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+#define GETU32(plaintext) (((u32)(plaintext)[0] << 24) ^ \
+                    ((u32)(plaintext)[1] << 16) ^ \
+                    ((u32)(plaintext)[2] <<  8) ^ \
+                    ((u32)(plaintext)[3]))
+
+#define PUTU32(ciphertext, st) { (ciphertext)[0] = (u8)((st) >> 24); \
+                         (ciphertext)[1] = (u8)((st) >> 16); \
+                         (ciphertext)[2] = (u8)((st) >>  8); \
+                         (ciphertext)[3] = (u8)(st); }
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+int rijndaelSetupEncrypt(u32 *rk, const u8 *key, int keybits)
+{
+  int i = 0;
+  u32 temp;
+
+  rk[0] = GETU32(key     );
+  rk[1] = GETU32(key +  4);
+  rk[2] = GETU32(key +  8);
+  rk[3] = GETU32(key + 12);
+  if (keybits == 128)
+  {
+    for (;;)
+    {
+      temp  = rk[3];
+      rk[4] = rk[0] ^
+        (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+        (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+        (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+        (Te4[(temp >> 24)       ] & 0x000000ff) ^
+        rcon[i];
+      rk[5] = rk[1] ^ rk[4];
+      rk[6] = rk[2] ^ rk[5];
+      rk[7] = rk[3] ^ rk[6];
+      if (++i == 10)
+        return 10;
+      rk += 4;
+    }
+  }
+  rk[4] = GETU32(key + 16);
+  rk[5] = GETU32(key + 20);
+  if (keybits == 192)
+  {
+    for (;;)
+    {
+      temp = rk[ 5];
+      rk[ 6] = rk[ 0] ^
+        (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+        (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+        (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+        (Te4[(temp >> 24)       ] & 0x000000ff) ^
+        rcon[i];
+      rk[ 7] = rk[ 1] ^ rk[ 6];
+      rk[ 8] = rk[ 2] ^ rk[ 7];
+      rk[ 9] = rk[ 3] ^ rk[ 8];
+      if (++i == 8)
+        return 12;
+      rk[10] = rk[ 4] ^ rk[ 9];
+      rk[11] = rk[ 5] ^ rk[10];
+      rk += 6;
+    }
+  }
+  rk[6] = GETU32(key + 24);
+  rk[7] = GETU32(key + 28);
+  if (keybits == 256)
+  {
+    for (;;)
+    {
+      temp = rk[ 7];
+      rk[ 8] = rk[ 0] ^
+        (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+        (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+        (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+        (Te4[(temp >> 24)       ] & 0x000000ff) ^
+        rcon[i];
+      rk[ 9] = rk[ 1] ^ rk[ 8];
+      rk[10] = rk[ 2] ^ rk[ 9];
+      rk[11] = rk[ 3] ^ rk[10];
+      if (++i == 7)
+        return 14;
+      temp = rk[11];
+      rk[12] = rk[ 4] ^
+        (Te4[(temp >> 24)       ] & 0xff000000) ^
+        (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+        (Te4[(temp >>  8) & 0xff] & 0x0000ff00) ^
+        (Te4[(temp      ) & 0xff] & 0x000000ff);
+      rk[13] = rk[ 5] ^ rk[12];
+      rk[14] = rk[ 6] ^ rk[13];
+      rk[15] = rk[ 7] ^ rk[14];
+      rk += 8;
+    }
+  }
+  return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+int rijndaelSetupDecrypt(u32 *rk, const u8 *key, int keybits)
+{
+  int nrounds, i, j;
+  u32 temp;
+
+  /* expand the cipher key: */
+  nrounds = rijndaelSetupEncrypt(rk, key, keybits);
+  /* invert the order of the round keys: */
+  for (i = 0, j = 4*nrounds; i < j; i += 4, j -= 4)
+  {
+    temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+    temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+    temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+    temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+  }
+  /* apply the inverse MixColumn transform to all round keys but the first and the last: */
+  for (i = 1; i < nrounds; i++)
+  {
+    rk += 4;
+    rk[0] =
+      Td0[Te4[(rk[0] >> 24)       ] & 0xff] ^
+      Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+      Td2[Te4[(rk[0] >>  8) & 0xff] & 0xff] ^
+      Td3[Te4[(rk[0]      ) & 0xff] & 0xff];
+    rk[1] =
+      Td0[Te4[(rk[1] >> 24)       ] & 0xff] ^
+      Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+      Td2[Te4[(rk[1] >>  8) & 0xff] & 0xff] ^
+      Td3[Te4[(rk[1]      ) & 0xff] & 0xff];
+    rk[2] =
+      Td0[Te4[(rk[2] >> 24)       ] & 0xff] ^
+      Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+      Td2[Te4[(rk[2] >>  8) & 0xff] & 0xff] ^
+      Td3[Te4[(rk[2]      ) & 0xff] & 0xff];
+    rk[3] =
+      Td0[Te4[(rk[3] >> 24)       ] & 0xff] ^
+      Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+      Td2[Te4[(rk[3] >>  8) & 0xff] & 0xff] ^
+      Td3[Te4[(rk[3]      ) & 0xff] & 0xff];
+  }
+  return nrounds;
+}
+
+void rijndaelEncrypt(const u32 *rk, int nrounds, const u8 plaintext[16],
+  u8 ciphertext[16])
+{
+  u32 s0, s1, s2, s3, t0, t1, t2, t3;
+  #ifndef FULL_UNROLL
+    int r;
+  #endif /* ?FULL_UNROLL */
+  /*
+   * map byte array block to cipher state
+   * and add initial round key:
+  */
+  s0 = GETU32(plaintext     ) ^ rk[0];
+  s1 = GETU32(plaintext +  4) ^ rk[1];
+  s2 = GETU32(plaintext +  8) ^ rk[2];
+  s3 = GETU32(plaintext + 12) ^ rk[3];
+  #ifdef FULL_UNROLL
+    /* round 1: */
+    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+    /* round 2: */
+    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+    /* round 3: */
+    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+    /* round 4: */
+    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+    /* round 5: */
+    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+    /* round 6: */
+    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+    /* round 7: */
+    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+    /* round 8: */
+    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+    /* round 9: */
+    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+    if (nrounds > 10)
+    {
+      /* round 10: */
+      s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+      s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+      s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+      s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+      /* round 11: */
+      t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+      t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+      t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+      t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+      if (nrounds > 12)
+      {
+        /* round 12: */
+        s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+        s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+        s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+        s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+        /* round 13: */
+        t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+        t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+        t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+        t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+      }
+    }
+    rk += nrounds << 2;
+  #else  /* !FULL_UNROLL */
+    /*
+    * nrounds - 1 full rounds:
+    */
+    r = nrounds >> 1;
+    for (;;)
+    {
+      t0 =
+        Te0[(s0 >> 24)       ] ^
+        Te1[(s1 >> 16) & 0xff] ^
+        Te2[(s2 >>  8) & 0xff] ^
+        Te3[(s3      ) & 0xff] ^
+        rk[4];
+      t1 =
+        Te0[(s1 >> 24)       ] ^
+        Te1[(s2 >> 16) & 0xff] ^
+        Te2[(s3 >>  8) & 0xff] ^
+        Te3[(s0      ) & 0xff] ^
+        rk[5];
+      t2 =
+        Te0[(s2 >> 24)       ] ^
+        Te1[(s3 >> 16) & 0xff] ^
+        Te2[(s0 >>  8) & 0xff] ^
+        Te3[(s1      ) & 0xff] ^
+        rk[6];
+      t3 =
+        Te0[(s3 >> 24)       ] ^
+        Te1[(s0 >> 16) & 0xff] ^
+        Te2[(s1 >>  8) & 0xff] ^
+        Te3[(s2      ) & 0xff] ^
+        rk[7];
+        rk += 8;
+        if (--r == 0)
+            break;
+      s0 =
+        Te0[(t0 >> 24)       ] ^
+        Te1[(t1 >> 16) & 0xff] ^
+        Te2[(t2 >>  8) & 0xff] ^
+        Te3[(t3      ) & 0xff] ^
+        rk[0];
+      s1 =
+        Te0[(t1 >> 24)       ] ^
+        Te1[(t2 >> 16) & 0xff] ^
+        Te2[(t3 >>  8) & 0xff] ^
+        Te3[(t0      ) & 0xff] ^
+        rk[1];
+      s2 =
+        Te0[(t2 >> 24)       ] ^
+        Te1[(t3 >> 16) & 0xff] ^
+        Te2[(t0 >>  8) & 0xff] ^
+        Te3[(t1      ) & 0xff] ^
+        rk[2];
+      s3 =
+        Te0[(t3 >> 24)       ] ^
+        Te1[(t0 >> 16) & 0xff] ^
+        Te2[(t1 >>  8) & 0xff] ^
+        Te3[(t2      ) & 0xff] ^
+        rk[3];
+     }
+ #endif /* ?FULL_UNROLL */
+  /*
+  * apply last round and
+  * map cipher state to byte array block:
+  */
+  s0 =
+    (Te4[(t0 >> 24)       ] & 0xff000000) ^
+    (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+    (Te4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+    (Te4[(t3      ) & 0xff] & 0x000000ff) ^
+    rk[0];
+  PUTU32(ciphertext     , s0);
+  s1 =
+    (Te4[(t1 >> 24)       ] & 0xff000000) ^
+    (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+    (Te4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+    (Te4[(t0      ) & 0xff] & 0x000000ff) ^
+    rk[1];
+  PUTU32(ciphertext +  4, s1);
+  s2 =
+    (Te4[(t2 >> 24)       ] & 0xff000000) ^
+    (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+    (Te4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+    (Te4[(t1      ) & 0xff] & 0x000000ff) ^
+    rk[2];
+  PUTU32(ciphertext +  8, s2);
+  s3 =
+    (Te4[(t3 >> 24)       ] & 0xff000000) ^
+    (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+    (Te4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+    (Te4[(t2      ) & 0xff] & 0x000000ff) ^
+    rk[3];
+  PUTU32(ciphertext + 12, s3);
+}
+
+void rijndaelDecrypt(const u32 *rk, int nrounds, const u8 ciphertext[16],
+  u8 plaintext[16])
+{
+  u32 s0, s1, s2, s3, t0, t1, t2, t3;
+  #ifndef FULL_UNROLL
+    int r;
+  #endif /* ?FULL_UNROLL */
+
+  /*
+  * map byte array block to cipher state
+  * and add initial round key:
+  */
+    s0 = GETU32(ciphertext     ) ^ rk[0];
+    s1 = GETU32(ciphertext +  4) ^ rk[1];
+    s2 = GETU32(ciphertext +  8) ^ rk[2];
+    s3 = GETU32(ciphertext + 12) ^ rk[3];
+  #ifdef FULL_UNROLL
+    /* round 1: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+    /* round 2: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+    /* round 3: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+    /* round 4: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+    /* round 5: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+    /* round 6: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+    /* round 7: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+    /* round 8: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+    /* round 9: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+    if (nrounds > 10)
+    {
+      /* round 10: */
+      s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+      s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+      s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+      s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+      /* round 11: */
+      t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+      t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+      t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+      t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+      if (nrounds > 12)
+      {
+        /* round 12: */
+        s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+        s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+        s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+        s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+        /* round 13: */
+        t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+        t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+        t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+        t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+      }
+    }
+    rk += nrounds << 2;
+  #else  /* !FULL_UNROLL */
+    /*
+    * nrounds - 1 full rounds:
+    */
+    r = nrounds >> 1;
+    for (;;)
+    {
+      t0 =
+        Td0[(s0 >> 24)       ] ^
+        Td1[(s3 >> 16) & 0xff] ^
+        Td2[(s2 >>  8) & 0xff] ^
+        Td3[(s1      ) & 0xff] ^
+        rk[4];
+      t1 =
+        Td0[(s1 >> 24)       ] ^
+        Td1[(s0 >> 16) & 0xff] ^
+        Td2[(s3 >>  8) & 0xff] ^
+        Td3[(s2      ) & 0xff] ^
+        rk[5];
+      t2 =
+        Td0[(s2 >> 24)       ] ^
+        Td1[(s1 >> 16) & 0xff] ^
+        Td2[(s0 >>  8) & 0xff] ^
+        Td3[(s3      ) & 0xff] ^
+        rk[6];
+      t3 =
+        Td0[(s3 >> 24)       ] ^
+        Td1[(s2 >> 16) & 0xff] ^
+        Td2[(s1 >>  8) & 0xff] ^
+        Td3[(s0      ) & 0xff] ^
+        rk[7];
+      rk += 8;
+      if (--r == 0)
+          break;
+      s0 =
+        Td0[(t0 >> 24)       ] ^
+        Td1[(t3 >> 16) & 0xff] ^
+        Td2[(t2 >>  8) & 0xff] ^
+        Td3[(t1      ) & 0xff] ^
+        rk[0];
+      s1 =
+        Td0[(t1 >> 24)       ] ^
+        Td1[(t0 >> 16) & 0xff] ^
+        Td2[(t3 >>  8) & 0xff] ^
+        Td3[(t2      ) & 0xff] ^
+        rk[1];
+      s2 =
+        Td0[(t2 >> 24)       ] ^
+        Td1[(t1 >> 16) & 0xff] ^
+        Td2[(t0 >>  8) & 0xff] ^
+        Td3[(t3      ) & 0xff] ^
+        rk[2];
+      s3 =
+        Td0[(t3 >> 24)       ] ^
+        Td1[(t2 >> 16) & 0xff] ^
+        Td2[(t1 >>  8) & 0xff] ^
+        Td3[(t0      ) & 0xff] ^
+        rk[3];
+    }
+  #endif /* ?FULL_UNROLL */
+  /*
+  * apply last round and
+  * map cipher state to byte array block:
+  */
+  s0 =
+    (Td4[(t0 >> 24)       ] & 0xff000000) ^
+    (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+    (Td4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+    (Td4[(t1      ) & 0xff] & 0x000000ff) ^
+    rk[0];
+  PUTU32(plaintext     , s0);
+  s1 =
+    (Td4[(t1 >> 24)       ] & 0xff000000) ^
+    (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+    (Td4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+    (Td4[(t2      ) & 0xff] & 0x000000ff) ^
+    rk[1];
+  PUTU32(plaintext +  4, s1);
+  s2 =
+    (Td4[(t2 >> 24)       ] & 0xff000000) ^
+    (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+    (Td4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+    (Td4[(t3      ) & 0xff] & 0x000000ff) ^
+    rk[2];
+  PUTU32(plaintext +  8, s2);
+  s3 =
+    (Td4[(t3 >> 24)       ] & 0xff000000) ^
+    (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+    (Td4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+    (Td4[(t0      ) & 0xff] & 0x000000ff) ^
+    rk[3];
+  PUTU32(plaintext + 12, s3);
+}
diff --git a/lib/rijndael.h b/lib/rijndael.h
new file mode 100644 (file)
index 0000000..9394a5b
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef H__RIJNDAEL
+#define H__RIJNDAEL
+
+int rijndaelSetupEncrypt(unsigned long *rk, const unsigned char *key,
+  int keybits);
+int rijndaelSetupDecrypt(unsigned long *rk, const unsigned char *key,
+  int keybits);
+void rijndaelEncrypt(const unsigned long *rk, int nrounds,
+  const unsigned char plaintext[16], unsigned char ciphertext[16]);
+void rijndaelDecrypt(const unsigned long *rk, int nrounds,
+  const unsigned char ciphertext[16], unsigned char plaintext[16]);
+
+#define KEYLENGTH(keybits) ((keybits)/8)
+#define RKLENGTH(keybits)  ((keybits)/8+28)
+#define NROUNDS(keybits)   ((keybits)/32+6)
+
+#endif
diff --git a/lib/sha2.c b/lib/sha2.c
new file mode 100644 (file)
index 0000000..1bc2690
--- /dev/null
@@ -0,0 +1,1069 @@
+/*
+ * FILE:       sha2.c
+ * AUTHOR:     Aaron D. Gifford <me@aarongifford.com>
+ * 
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
+ */
+
+#include <string.h>    /* memcpy()/memset() or bcopy()/bzero() */
+#include <assert.h>    /* assert() */
+#include "sha2.h"
+
+/*
+ * ASSERT NOTE:
+ * Some sanity checking code is included using assert().  On my FreeBSD
+ * system, this additional code can be removed by compiling with NDEBUG
+ * defined.  Check your own systems manpage on assert() to see how to
+ * compile WITHOUT the sanity checking code on your system.
+ *
+ * UNROLLED TRANSFORM LOOP NOTE:
+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
+ * loop version for the hash transform rounds (defined using macros
+ * later in this file).  Either define on the command line, for example:
+ *
+ *   cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
+ *
+ * or define below:
+ *
+ *   #define SHA2_UNROLL_TRANSFORM
+ *
+ */
+
+
+/*** SHA-256/384/512 Machine Architecture Definitions *****************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * Please make sure that your system defines BYTE_ORDER.  If your
+ * architecture is little-endian, make sure it also defines
+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
+ * equivilent.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ *   #define LITTLE_ENDIAN 1234
+ *   #define BIG_ENDIAN    4321
+ *
+ * And for little-endian machines, add:
+ *
+ *   #define BYTE_ORDER LITTLE_ENDIAN 
+ *
+ * Or for big-endian machines:
+ *
+ *   #define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+#if !defined(BYTE_ORDER)
+#define BYTE_ORDER __BYTE_ORDER
+#endif
+
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
+#endif
+
+/*
+ * Define the followingsha2_* types to types of the correct length on
+ * the native archtecture.   Most BSD systems and Linux define u_intXX_t
+ * types.  Machines with very recent ANSI C headers, can use the
+ * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H
+ * during compile or in the sha.h header file.
+ *
+ * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t
+ * will need to define these three typedefs below (and the appropriate
+ * ones in sha.h too) by hand according to their system architecture.
+ *
+ * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t
+ * types and pointing out recent ANSI C support for uintXX_t in inttypes.h.
+ */
+#ifdef SHA2_USE_INTTYPES_H
+
+typedef uint8_t  sha2_byte;    /* Exactly 1 byte */
+typedef uint32_t sha2_word32;  /* Exactly 4 bytes */
+typedef uint64_t sha2_word64;  /* Exactly 8 bytes */
+
+#else /* SHA2_USE_INTTYPES_H */
+
+typedef u_int8_t  sha2_byte;   /* Exactly 1 byte */
+typedef u_int32_t sha2_word32; /* Exactly 4 bytes */
+typedef u_int64_t sha2_word64; /* Exactly 8 bytes */
+
+#endif /* SHA2_USE_INTTYPES_H */
+
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+/* NOTE: Most of these are in sha2.h */
+#define SHA256_SHORT_BLOCK_LENGTH      (SHA256_BLOCK_LENGTH - 8)
+#define SHA384_SHORT_BLOCK_LENGTH      (SHA384_BLOCK_LENGTH - 16)
+#define SHA512_SHORT_BLOCK_LENGTH      (SHA512_BLOCK_LENGTH - 16)
+
+
+/*** ENDIAN REVERSAL MACROS *******************************************/
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define REVERSE32(w,x) { \
+       sha2_word32 tmp = (w); \
+       tmp = (tmp >> 16) | (tmp << 16); \
+       (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
+}
+#define REVERSE64(w,x) { \
+       sha2_word64 tmp = (w); \
+       tmp = (tmp >> 32) | (tmp << 32); \
+       tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
+             ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
+       (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
+             ((tmp & 0x0000ffff0000ffffULL) << 16); \
+}
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+       (w)[0] += (sha2_word64)(n); \
+       if ((w)[0] < (n)) { \
+               (w)[1]++; \
+       } \
+}
+
+/*
+ * Macros for copying blocks of memory and for zeroing out ranges
+ * of memory.  Using these macros makes it easy to switch from
+ * using memset()/memcpy() and using bzero()/bcopy().
+ *
+ * Please define either SHA2_USE_MEMSET_MEMCPY or define
+ * SHA2_USE_BZERO_BCOPY depending on which function set you
+ * choose to use:
+ */
+#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)
+/* Default to memset()/memcpy() if no option is specified */
+#define        SHA2_USE_MEMSET_MEMCPY  1
+#endif
+#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)
+/* Abort with an error if BOTH options are defined */
+#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!
+#endif
+
+#ifdef SHA2_USE_MEMSET_MEMCPY
+#define MEMSET_BZERO(p,l)      memset((p), 0, (l))
+#define MEMCPY_BCOPY(d,s,l)    memcpy((d), (s), (l))
+#endif
+#ifdef SHA2_USE_BZERO_BCOPY
+#define MEMSET_BZERO(p,l)      bzero((p), (l))
+#define MEMCPY_BCOPY(d,s,l)    bcopy((s), (d), (l))
+#endif
+
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ *   NOTE:  The naming of R and S appears backwards here (R is a SHIFT and
+ *   S is a ROTATION) because the SHA-256/384/512 description document
+ *   (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ *   same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x)                 ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define S32(b,x)       (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x)       (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z)      (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z)     (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-256: */
+#define Sigma0_256(x)  (S32(2,  (x)) ^ S32(13, (x)) ^ S32(22, (x)))
+#define Sigma1_256(x)  (S32(6,  (x)) ^ S32(11, (x)) ^ S32(25, (x)))
+#define sigma0_256(x)  (S32(7,  (x)) ^ S32(18, (x)) ^ R(3 ,   (x)))
+#define sigma1_256(x)  (S32(17, (x)) ^ S32(19, (x)) ^ R(10,   (x)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x)  (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x)  (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x)  (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7,   (x)))
+#define sigma1_512(x)  (S64(19, (x)) ^ S64(61, (x)) ^ R( 6,   (x)))
+
+/*** INTERNAL FUNCTION PROTOTYPES *************************************/
+/* NOTE: These should not be accessed directly from outside this
+ * library -- they are intended for private internal visibility/use
+ * only.
+ */
+void SHA512_Last(SHA512_CTX*);
+void SHA256_Transform(SHA256_CTX*, const sha2_word32*);
+void SHA512_Transform(SHA512_CTX*, const sha2_word64*);
+
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-256: */
+const static sha2_word32 K256[64] = {
+       0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+       0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+       0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+       0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+       0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+       0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+       0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+       0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+       0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+       0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+       0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+       0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+       0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+       0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+       0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+       0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Initial hash value H for SHA-256: */
+const static sha2_word32 sha256_initial_hash_value[8] = {
+       0x6a09e667UL,
+       0xbb67ae85UL,
+       0x3c6ef372UL,
+       0xa54ff53aUL,
+       0x510e527fUL,
+       0x9b05688cUL,
+       0x1f83d9abUL,
+       0x5be0cd19UL
+};
+
+/* Hash constant words K for SHA-384 and SHA-512: */
+const static sha2_word64 K512[80] = {
+       0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+       0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+       0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+       0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+       0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+       0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+       0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+       0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+       0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+       0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+       0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+       0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+       0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+       0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+       0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+       0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+       0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+       0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+       0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+       0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+       0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+       0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+       0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+       0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+       0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+       0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+       0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+       0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+       0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+       0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+       0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+       0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+       0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+       0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+       0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+       0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+       0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+       0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+       0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+       0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* Initial hash value H for SHA-384 */
+const static sha2_word64 sha384_initial_hash_value[8] = {
+       0xcbbb9d5dc1059ed8ULL,
+       0x629a292a367cd507ULL,
+       0x9159015a3070dd17ULL,
+       0x152fecd8f70e5939ULL,
+       0x67332667ffc00b31ULL,
+       0x8eb44a8768581511ULL,
+       0xdb0c2e0d64f98fa7ULL,
+       0x47b5481dbefa4fa4ULL
+};
+
+/* Initial hash value H for SHA-512 */
+const static sha2_word64 sha512_initial_hash_value[8] = {
+       0x6a09e667f3bcc908ULL,
+       0xbb67ae8584caa73bULL,
+       0x3c6ef372fe94f82bULL,
+       0xa54ff53a5f1d36f1ULL,
+       0x510e527fade682d1ULL,
+       0x9b05688c2b3e6c1fULL,
+       0x1f83d9abfb41bd6bULL,
+       0x5be0cd19137e2179ULL
+};
+
+/*
+ * Constant used by SHA256/384/512_End() functions for converting the
+ * digest to a readable hexadecimal character string:
+ */
+static const char *sha2_hex_digits = "0123456789abcdef";
+
+
+/*** SHA-256: *********************************************************/
+void SHA256_Init(SHA256_CTX* context) {
+       if (context == (SHA256_CTX*)0) {
+               return;
+       }
+       MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH);
+       MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH);
+       context->bitcount = 0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)      \
+       REVERSE32(*data++, W256[j]); \
+       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+             K256[j] + W256[j]; \
+       (d) += T1; \
+       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+       j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)      \
+       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+            K256[j] + (W256[j] = *data++); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+       j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256(a,b,c,d,e,f,g,h)      \
+       s0 = W256[(j+1)&0x0f]; \
+       s0 = sigma0_256(s0); \
+       s1 = W256[(j+14)&0x0f]; \
+       s1 = sigma1_256(s1); \
+       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
+            (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+       j++
+
+void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
+       sha2_word32     a, b, c, d, e, f, g, h, s0, s1;
+       sha2_word32     T1, *W256;
+       int             j;
+
+       W256 = (sha2_word32*)context->buffer;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+               /* Rounds 0 to 15 (unrolled): */
+               ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+               ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+               ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+               ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+               ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+               ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+               ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+               ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+       } while (j < 16);
+
+       /* Now for the remaining rounds to 64: */
+       do {
+               ROUND256(a,b,c,d,e,f,g,h);
+               ROUND256(h,a,b,c,d,e,f,g);
+               ROUND256(g,h,a,b,c,d,e,f);
+               ROUND256(f,g,h,a,b,c,d,e);
+               ROUND256(e,f,g,h,a,b,c,d);
+               ROUND256(d,e,f,g,h,a,b,c);
+               ROUND256(c,d,e,f,g,h,a,b);
+               ROUND256(b,c,d,e,f,g,h,a);
+       } while (j < 64);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
+       sha2_word32     a, b, c, d, e, f, g, h, s0, s1;
+       sha2_word32     T1, T2, *W256;
+       int             j;
+
+       W256 = (sha2_word32*)context->buffer;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+               /* Copy data while converting to host byte order */
+               REVERSE32(*data++,W256[j]);
+               /* Apply the SHA-256 compression function to update a..h */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+               /* Apply the SHA-256 compression function to update a..h with copy */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+               T2 = Sigma0_256(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 16);
+
+       do {
+               /* Part of the message block expansion: */
+               s0 = W256[(j+1)&0x0f];
+               s0 = sigma0_256(s0);
+               s1 = W256[(j+14)&0x0f]; 
+               s1 = sigma1_256(s1);
+
+               /* Apply the SHA-256 compression function to update a..h */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + 
+                    (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+               T2 = Sigma0_256(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 64);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {
+       unsigned int    freespace, usedspace;
+
+       if (len == 0) {
+               /* Calling with no data is valid - we do nothing */
+               return;
+       }
+
+       /* Sanity check: */
+       assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0);
+
+       usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+       if (usedspace > 0) {
+               /* Calculate how much free space is available in the buffer */
+               freespace = SHA256_BLOCK_LENGTH - usedspace;
+
+               if (len >= freespace) {
+                       /* Fill the buffer completely and process it */
+                       MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
+                       context->bitcount += freespace << 3;
+                       len -= freespace;
+                       data += freespace;
+                       SHA256_Transform(context, (sha2_word32*)context->buffer);
+               } else {
+                       /* The buffer is not yet full */
+                       MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
+                       context->bitcount += len << 3;
+                       /* Clean up: */
+                       usedspace = freespace = 0;
+                       return;
+               }
+       }
+       while (len >= SHA256_BLOCK_LENGTH) {
+               /* Process as many complete blocks as we can */
+               SHA256_Transform(context, (sha2_word32*)data);
+               context->bitcount += SHA256_BLOCK_LENGTH << 3;
+               len -= SHA256_BLOCK_LENGTH;
+               data += SHA256_BLOCK_LENGTH;
+       }
+       if (len > 0) {
+               /* There's left-overs, so save 'em */
+               MEMCPY_BCOPY(context->buffer, data, len);
+               context->bitcount += len << 3;
+       }
+       /* Clean up: */
+       usedspace = freespace = 0;
+}
+
+void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
+       sha2_word32     *d = (sha2_word32*)digest;
+       unsigned int    usedspace;
+
+       /* Sanity check: */
+       assert(context != (SHA256_CTX*)0);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (sha2_byte*)0) {
+               usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+#if BYTE_ORDER == LITTLE_ENDIAN
+               /* Convert FROM host byte order */
+               REVERSE64(context->bitcount,context->bitcount);
+#endif
+               if (usedspace > 0) {
+                       /* Begin padding with a 1 bit: */
+                       context->buffer[usedspace++] = 0x80;
+
+                       if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
+                               /* Set-up for the last transform: */
+                               MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace);
+                       } else {
+                               if (usedspace < SHA256_BLOCK_LENGTH) {
+                                       MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace);
+                               }
+                               /* Do second-to-last transform: */
+                               SHA256_Transform(context, (sha2_word32*)context->buffer);
+
+                               /* And set-up for the last transform: */
+                               MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
+                       }
+               } else {
+                       /* Set-up for the last transform: */
+                       MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
+
+                       /* Begin padding with a 1 bit: */
+                       *context->buffer = 0x80;
+               }
+               /* Set the bit count: */
+               *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
+
+               /* Final transform: */
+               SHA256_Transform(context, (sha2_word32*)context->buffer);
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 8; j++) {
+                               REVERSE32(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH);
+#endif
+       }
+
+       /* Clean up state data: */
+       MEMSET_BZERO(context, sizeof(context));
+       usedspace = 0;
+}
+
+char *SHA256_End(SHA256_CTX* context, char buffer[]) {
+       sha2_byte       digest[SHA256_DIGEST_LENGTH], *d = digest;
+       int             i;
+
+       /* Sanity check: */
+       assert(context != (SHA256_CTX*)0);
+
+       if (buffer != (char*)0) {
+               SHA256_Final(digest, context);
+
+               for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+                       *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+                       *buffer++ = sha2_hex_digits[*d & 0x0f];
+                       d++;
+               }
+               *buffer = (char)0;
+       } else {
+               MEMSET_BZERO(context, sizeof(context));
+       }
+       MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH);
+       return buffer;
+}
+
+char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) {
+       SHA256_CTX      context;
+
+       SHA256_Init(&context);
+       SHA256_Update(&context, data, len);
+       return SHA256_End(&context, digest);
+}
+
+
+/*** SHA-512: *********************************************************/
+void SHA512_Init(SHA512_CTX* context) {
+       if (context == (SHA512_CTX*)0) {
+               return;
+       }
+       MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);
+       MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH);
+       context->bitcount[0] = context->bitcount[1] =  0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-512 round macros: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)      \
+       REVERSE64(*data++, W512[j]); \
+       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+             K512[j] + W512[j]; \
+       (d) += T1, \
+       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
+       j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)      \
+       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+             K512[j] + (W512[j] = *data++); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+       j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512(a,b,c,d,e,f,g,h)      \
+       s0 = W512[(j+1)&0x0f]; \
+       s0 = sigma0_512(s0); \
+       s1 = W512[(j+14)&0x0f]; \
+       s1 = sigma1_512(s1); \
+       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
+             (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+       j++
+
+void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
+       sha2_word64     a, b, c, d, e, f, g, h, s0, s1;
+       sha2_word64     T1, *W512 = (sha2_word64*)context->buffer;
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+               ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
+               ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
+               ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
+               ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
+               ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
+               ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
+               ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
+               ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
+       } while (j < 16);
+
+       /* Now for the remaining rounds up to 79: */
+       do {
+               ROUND512(a,b,c,d,e,f,g,h);
+               ROUND512(h,a,b,c,d,e,f,g);
+               ROUND512(g,h,a,b,c,d,e,f);
+               ROUND512(f,g,h,a,b,c,d,e);
+               ROUND512(e,f,g,h,a,b,c,d);
+               ROUND512(d,e,f,g,h,a,b,c);
+               ROUND512(c,d,e,f,g,h,a,b);
+               ROUND512(b,c,d,e,f,g,h,a);
+       } while (j < 80);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
+       sha2_word64     a, b, c, d, e, f, g, h, s0, s1;
+       sha2_word64     T1, T2, *W512 = (sha2_word64*)context->buffer;
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+               /* Convert TO host byte order */
+               REVERSE64(*data++, W512[j]);
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+               /* Apply the SHA-512 compression function to update a..h with copy */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 16);
+
+       do {
+               /* Part of the message block expansion: */
+               s0 = W512[(j+1)&0x0f];
+               s0 = sigma0_512(s0);
+               s1 = W512[(j+14)&0x0f];
+               s1 =  sigma1_512(s1);
+
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+                    (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 80);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) {
+       unsigned int    freespace, usedspace;
+
+       if (len == 0) {
+               /* Calling with no data is valid - we do nothing */
+               return;
+       }
+
+       /* Sanity check: */
+       assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0);
+
+       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+       if (usedspace > 0) {
+               /* Calculate how much free space is available in the buffer */
+               freespace = SHA512_BLOCK_LENGTH - usedspace;
+
+               if (len >= freespace) {
+                       /* Fill the buffer completely and process it */
+                       MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
+                       ADDINC128(context->bitcount, freespace << 3);
+                       len -= freespace;
+                       data += freespace;
+                       SHA512_Transform(context, (sha2_word64*)context->buffer);
+               } else {
+                       /* The buffer is not yet full */
+                       MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
+                       ADDINC128(context->bitcount, len << 3);
+                       /* Clean up: */
+                       usedspace = freespace = 0;
+                       return;
+               }
+       }
+       while (len >= SHA512_BLOCK_LENGTH) {
+               /* Process as many complete blocks as we can */
+               SHA512_Transform(context, (sha2_word64*)data);
+               ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
+               len -= SHA512_BLOCK_LENGTH;
+               data += SHA512_BLOCK_LENGTH;
+       }
+       if (len > 0) {
+               /* There's left-overs, so save 'em */
+               MEMCPY_BCOPY(context->buffer, data, len);
+               ADDINC128(context->bitcount, len << 3);
+       }
+       /* Clean up: */
+       usedspace = freespace = 0;
+}
+
+void SHA512_Last(SHA512_CTX* context) {
+       unsigned int    usedspace;
+
+       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+#if BYTE_ORDER == LITTLE_ENDIAN
+       /* Convert FROM host byte order */
+       REVERSE64(context->bitcount[0],context->bitcount[0]);
+       REVERSE64(context->bitcount[1],context->bitcount[1]);
+#endif
+       if (usedspace > 0) {
+               /* Begin padding with a 1 bit: */
+               context->buffer[usedspace++] = 0x80;
+
+               if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
+                       /* Set-up for the last transform: */
+                       MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
+               } else {
+                       if (usedspace < SHA512_BLOCK_LENGTH) {
+                               MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace);
+                       }
+                       /* Do second-to-last transform: */
+                       SHA512_Transform(context, (sha2_word64*)context->buffer);
+
+                       /* And set-up for the last transform: */
+                       MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2);
+               }
+       } else {
+               /* Prepare for final transform: */
+               MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH);
+
+               /* Begin padding with a 1 bit: */
+               *context->buffer = 0x80;
+       }
+       /* Store the length of input data (in bits): */
+       *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
+       *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
+
+       /* Final transform: */
+       SHA512_Transform(context, (sha2_word64*)context->buffer);
+}
+
+void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
+       sha2_word64     *d = (sha2_word64*)digest;
+
+       /* Sanity check: */
+       assert(context != (SHA512_CTX*)0);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (sha2_byte*)0) {
+               SHA512_Last(context);
+
+               /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 8; j++) {
+                               REVERSE64(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH);
+#endif
+       }
+
+       /* Zero out state data */
+       MEMSET_BZERO(context, sizeof(context));
+}
+
+char *SHA512_End(SHA512_CTX* context, char buffer[]) {
+       sha2_byte       digest[SHA512_DIGEST_LENGTH], *d = digest;
+       int             i;
+
+       /* Sanity check: */
+       assert(context != (SHA512_CTX*)0);
+
+       if (buffer != (char*)0) {
+               SHA512_Final(digest, context);
+
+               for (i = 0; i < SHA512_DIGEST_LENGTH; i++) {
+                       *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+                       *buffer++ = sha2_hex_digits[*d & 0x0f];
+                       d++;
+               }
+               *buffer = (char)0;
+       } else {
+               MEMSET_BZERO(context, sizeof(context));
+       }
+       MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH);
+       return buffer;
+}
+
+char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) {
+       SHA512_CTX      context;
+
+       SHA512_Init(&context);
+       SHA512_Update(&context, data, len);
+       return SHA512_End(&context, digest);
+}
+
+
+/*** SHA-384: *********************************************************/
+void SHA384_Init(SHA384_CTX* context) {
+       if (context == (SHA384_CTX*)0) {
+               return;
+       }
+       MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH);
+       MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH);
+       context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) {
+       SHA512_Update((SHA512_CTX*)context, data, len);
+}
+
+void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
+       sha2_word64     *d = (sha2_word64*)digest;
+
+       /* Sanity check: */
+       assert(context != (SHA384_CTX*)0);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (sha2_byte*)0) {
+               SHA512_Last((SHA512_CTX*)context);
+
+               /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 6; j++) {
+                               REVERSE64(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH);
+#endif
+       }
+
+       /* Zero out state data */
+       MEMSET_BZERO(context, sizeof(context));
+}
+
+char *SHA384_End(SHA384_CTX* context, char buffer[]) {
+       sha2_byte       digest[SHA384_DIGEST_LENGTH], *d = digest;
+       int             i;
+
+       /* Sanity check: */
+       assert(context != (SHA384_CTX*)0);
+
+       if (buffer != (char*)0) {
+               SHA384_Final(digest, context);
+
+               for (i = 0; i < SHA384_DIGEST_LENGTH; i++) {
+                       *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+                       *buffer++ = sha2_hex_digits[*d & 0x0f];
+                       d++;
+               }
+               *buffer = (char)0;
+       } else {
+               MEMSET_BZERO(context, sizeof(context));
+       }
+       MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH);
+       return buffer;
+}
+
+char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) {
+       SHA384_CTX      context;
+
+       SHA384_Init(&context);
+       SHA384_Update(&context, data, len);
+       return SHA384_End(&context, digest);
+}
+
diff --git a/lib/sha2.h b/lib/sha2.h
new file mode 100644 (file)
index 0000000..3a4d5b2
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * FILE:       sha2.h
+ * AUTHOR:     Aaron D. Gifford <me@aarongifford.com>
+ * 
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
+ */
+
+#ifndef __SHA2_H__
+#define __SHA2_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Import u_intXX_t size_t type definitions from system headers.  You
+ * may need to change this, or define these things yourself in this
+ * file.
+ */
+#include <sys/types.h>
+
+#ifdef SHA2_USE_INTTYPES_H
+
+#include <inttypes.h>
+
+#endif /* SHA2_USE_INTTYPES_H */
+
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+#define SHA256_BLOCK_LENGTH            64
+#define SHA256_DIGEST_LENGTH           32
+#define SHA256_DIGEST_STRING_LENGTH    (SHA256_DIGEST_LENGTH * 2 + 1)
+#define SHA384_BLOCK_LENGTH            128
+#define SHA384_DIGEST_LENGTH           48
+#define SHA384_DIGEST_STRING_LENGTH    (SHA384_DIGEST_LENGTH * 2 + 1)
+#define SHA512_BLOCK_LENGTH            128
+#define SHA512_DIGEST_LENGTH           64
+#define SHA512_DIGEST_STRING_LENGTH    (SHA512_DIGEST_LENGTH * 2 + 1)
+
+
+/*** SHA-256/384/512 Context Structures *******************************/
+/* NOTE: If your architecture does not define either u_intXX_t types or
+ * uintXX_t (from inttypes.h), you may need to define things by hand
+ * for your system:
+ */
+#if 0
+typedef unsigned char u_int8_t;                /* 1-byte  (8-bits)  */
+typedef unsigned int u_int32_t;                /* 4-bytes (32-bits) */
+typedef unsigned long long u_int64_t;  /* 8-bytes (64-bits) */
+#endif
+/*
+ * Most BSD systems already define u_intXX_t types, as does Linux.
+ * Some systems, however, like Compaq's Tru64 Unix instead can use
+ * uintXX_t types defined by very recent ANSI C standards and included
+ * in the file:
+ *
+ *   #include <inttypes.h>
+ *
+ * If you choose to use <inttypes.h> then please define: 
+ *
+ *   #define SHA2_USE_INTTYPES_H
+ *
+ * Or on the command line during compile:
+ *
+ *   cc -DSHA2_USE_INTTYPES_H ...
+ */
+#ifdef SHA2_USE_INTTYPES_H
+
+typedef struct _SHA256_CTX {
+       uint32_t        state[8];
+       uint64_t        bitcount;
+       uint8_t buffer[SHA256_BLOCK_LENGTH];
+} SHA256_CTX;
+typedef struct _SHA512_CTX {
+       uint64_t        state[8];
+       uint64_t        bitcount[2];
+       uint8_t buffer[SHA512_BLOCK_LENGTH];
+} SHA512_CTX;
+
+#else /* SHA2_USE_INTTYPES_H */
+
+typedef struct _SHA256_CTX {
+       u_int32_t       state[8];
+       u_int64_t       bitcount;
+       u_int8_t        buffer[SHA256_BLOCK_LENGTH];
+} SHA256_CTX;
+typedef struct _SHA512_CTX {
+       u_int64_t       state[8];
+       u_int64_t       bitcount[2];
+       u_int8_t        buffer[SHA512_BLOCK_LENGTH];
+} SHA512_CTX;
+
+#endif /* SHA2_USE_INTTYPES_H */
+
+typedef SHA512_CTX SHA384_CTX;
+
+
+/*** SHA-256/384/512 Function Prototypes ******************************/
+#ifndef NOPROTO
+#ifdef SHA2_USE_INTTYPES_H
+
+void SHA256_Init(SHA256_CTX *);
+void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t);
+void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);
+char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]);
+char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]);
+
+void SHA384_Init(SHA384_CTX*);
+void SHA384_Update(SHA384_CTX*, const uint8_t*, size_t);
+void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*);
+char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]);
+char* SHA384_Data(const uint8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]);
+
+void SHA512_Init(SHA512_CTX*);
+void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t);
+void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);
+char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]);
+char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]);
+
+#else /* SHA2_USE_INTTYPES_H */
+
+void SHA256_Init(SHA256_CTX *);
+void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t);
+void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);
+char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]);
+char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]);
+
+void SHA384_Init(SHA384_CTX*);
+void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t);
+void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*);
+char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]);
+char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]);
+
+void SHA512_Init(SHA512_CTX*);
+void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t);
+void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);
+char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]);
+char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]);
+
+#endif /* SHA2_USE_INTTYPES_H */
+
+#else /* NOPROTO */
+
+void SHA256_Init();
+void SHA256_Update();
+void SHA256_Final();
+char* SHA256_End();
+char* SHA256_Data();
+
+void SHA384_Init();
+void SHA384_Update();
+void SHA384_Final();
+char* SHA384_End();
+char* SHA384_Data();
+
+void SHA512_Init();
+void SHA512_Update();
+void SHA512_Final();
+char* SHA512_End();
+char* SHA512_Data();
+
+#endif /* NOPROTO */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __SHA2_H__ */
+
old mode 100755 (executable)
new mode 100644 (file)
index c0398a59f6637c1c7075470834a492077e828a63..445487a365612e02b4ba3f765da3a69b127a7ca9 100644 (file)
@@ -2,7 +2,7 @@
 .PHONY: all
 all: lua.so nterfacer_lua.so
 
-lua.so: lua.o luacommands.o luacontrol.o luabot.o lualocal.o luadebug.o
+lua.so: lua.o luacommands.o luacontrol.o luabot.o lualocal.o luadebug.o luadb.o luasocket.o
        ld -shared -Bdynamic -o $@ $^ ${LIBLUA} ${ADDLIB}
 
 nterfacer_lua.so: nterfacer_lua.o
index c2c3e14d966fe81dd56ddfefe4d10fd883afdb24..060a19ffdef031e7ca1ef4b04721f19e27c84e6b 100644 (file)
--- a/lua/lua.c
+++ b/lua/lua.c
@@ -31,6 +31,7 @@ MODULE_VERSION(LUA_FULLVERSION);
 void lua_startup(void *arg);
 void lua_loadscripts(void);
 void lua_registercommands(lua_State *l);
+void lua_registerdbcommands(lua_State *l);
 void lua_initnickpusher(void);
 void lua_initchanpusher(void);
 void lua_loadlibs(lua_State *l);
@@ -52,6 +53,8 @@ void lua_freedebugsocket(void);
 void lua_deregisternicks(lua_list *l);
 void lua_registerlocalcommands(lua_State *ps);
 void lua_registerdebug(lua_State *ps);
+void lua_socket_closeall(lua_list *l);
+void lua_registersocketcommands(lua_State *ps);
 
 #ifdef LUA_DEBUGSOCKET
 
@@ -202,6 +205,8 @@ lua_State *lua_loadscript(char *file) {
   lua_registerdebug(l);
   lua_registercommands(l);
   lua_registerlocalcommands(l);
+  lua_registerdbcommands(l);
+  lua_registersocketcommands(l);
 
   lua_setpath(l);
 
@@ -220,24 +225,12 @@ lua_State *lua_loadscript(char *file) {
     return NULL;
   }
 
-  top = lua_gettop(l);
-
-  if(lua_pcall(l, 0, 0, 0)) {
-    Error("lua", ERR_ERROR, "Error pcalling: %s.", file);
-    lua_close(l);
-    freesstring(n->name);
-    free(n);
-    return NULL;
-  }
-
-  lua_settop(l, top);
-
-  Error("lua", ERR_INFO, "Loaded %s.", file);
   n->l = l;
 
   n->next = NULL;
   n->prev = lua_tail;
   n->nicks = NULL;
+  n->sockets = NULL;
 
   if(!lua_head) { 
     lua_head = n;
@@ -247,6 +240,19 @@ lua_State *lua_loadscript(char *file) {
 
   lua_tail = n;
 
+  top = lua_gettop(l);
+
+  if(lua_pcall(l, 0, 0, 0)) {
+    Error("lua", ERR_ERROR, "Error pcalling: %s.", file);
+    lua_close(l);
+    freesstring(n->name);
+    free(n);
+    return NULL;
+  }
+
+  lua_settop(l, top);
+
+  Error("lua", ERR_INFO, "Loaded %s.", file);
   lua_onload(l);
 
   return l;
@@ -255,6 +261,7 @@ lua_State *lua_loadscript(char *file) {
 void lua_unloadscript(lua_list *l) {
   lua_onunload(l->l);
   lua_deregisternicks(l);
+  lua_socket_closeall(l);
   lua_close(l->l);
   freesstring(l->name);
 
@@ -419,6 +426,16 @@ lua_list *lua_listfromstate(lua_State *l) {
   return &dummy;
 }
 
+int lua_listexists(lua_list *l) {
+  lua_list *i;
+
+  for(i=lua_head;i;i=i->next)
+    if(i == l)
+      return 1;
+
+  return 0;
+}
+
 int lua_lineok(const char *data) {
   if(strchr(data, '\r') || strchr(data, '\n'))
     return 0;
index 05f92740cbf8c0c359985c32612c1a6aa9f10dc1..c4c0e97ff96425a9bedc3a8c0cc0639de7f84874 100644 (file)
--- a/lua/lua.h
+++ b/lua/lua.h
 #include "../lib/sstring.h"
 
 #include "lualocal.h"
+#include "luasocket.h"
 
 /*** defines ************************************/
 
-#define LUA_BOTVERSION "1.75"
+#define LUA_BOTVERSION "1.83"
 #define LUA_CHANFIXBOT "Z"
 #define LUA_OPERCHAN "#twilightzone"
 
@@ -54,6 +55,7 @@ typedef struct lua_list {
   struct lua_list *next;
   struct lua_list *prev;
   lua_localnick *nicks;
+  lua_socket *sockets;
 } lua_list;
 
 #define LUA_STARTLOOP(l) { lua_list *ll; for(ll=lua_head;ll;ll=ll->next) {  l = ll->l
@@ -69,6 +71,7 @@ lua_State *lua_loadscript(char *file);
 void lua_unloadscript(lua_list *l);
 lua_list *lua_scriptloaded(char *name);
 lua_list *lua_listfromstate(lua_State *l);
+int lua_listexists(lua_list *l);
 int lua_lineok(const char *data);
 
 #define lua_toint(l, n) (int)lua_tonumber(l, n)
index 50d1c9c7a099a33bcbfaa7bc15af9b672916557a..97b2413ed3c4ef9f6dd77389969e1a9a95c2acde 100644 (file)
@@ -6,6 +6,7 @@
 #include "../localuser/localuserchannel.h"
 #include "../core/schedule.h"
 #include "../lib/irc_string.h"
+#include "../core/config.h"
 
 #include "lua.h"
 #include "luabot.h"
@@ -72,10 +73,12 @@ void lua_deregisterevents(void) {
 
 void lua_startbot(void *arg) {
   channel *cp;
+  sstring *n;
 
   myureconnect = NULL;
 
-  lua_nick = registerlocaluser("U", "lua", "quakenet.department.of.corrections", LUA_FULLVERSION, "U", UMODE_ACCOUNT | UMODE_DEAF | UMODE_OPER | UMODE_SERVICE, &lua_bothandler);
+  n = getcopyconfigitem("lua", "botnick", "U", NICKLEN);
+  lua_nick = registerlocaluser(n->content, "lua", "quakenet.department.of.corrections", LUA_FULLVERSION, "U", UMODE_ACCOUNT | UMODE_DEAF | UMODE_OPER | UMODE_SERVICE, &lua_bothandler);
   if(!lua_nick) {
     myureconnect = scheduleoneshot(time(NULL) + 1, &lua_startbot, NULL);
     return;
@@ -149,6 +152,13 @@ int _lua_vpcall(lua_State *l, void *function, int mode, const char *sig, ...) {
       case 'S':
         lua_pushstring(l, ((sstring *)(va_arg(va, sstring *)))->content);
         break;
+      case 'L':
+        {
+          char *p = va_arg(va, char *);
+          long len = va_arg(va, long);
+          lua_pushlstring(l, p, len);
+        }
+        break;
       case 'N':
         {
           nick *np = va_arg(va, nick *);
@@ -164,6 +174,12 @@ int _lua_vpcall(lua_State *l, void *function, int mode, const char *sig, ...) {
       case '0':
         lua_pushnil(l);
         break;
+      case 'R':
+        lua_rawgeti(l, LUA_REGISTRYINDEX, va_arg(va, long));
+        break;
+      case 'b':
+        lua_pushboolean(l, va_arg(va, int));
+        break;
       case '>':
         goto endwhile;
 
@@ -270,14 +286,17 @@ void lua_onkick(int hooknum, void *arg) {
   nick *kicked = arglist[1];
   nick *kicker = arglist[2];
   char *message = (char *)arglist[3];
+  int mode = 1;
 
   if(!kicker || IsOper(kicker) || IsService(kicker) || IsXOper(kicker)) /* bloody Cruicky */
-    return;
+    mode = 0;
 
-  if(kicker) {
+  if(mode) {
     lua_avpcall("irc_onkick", "Slls", ci->name, kicked->numeric, kicker->numeric, message);
+  } else if(kicker) {
+    lua_avpcall("irc_onkickall", "Slls", ci->name, kicked->numeric, kicker->numeric, message);
   } else {
-    lua_avpcall("irc_onkick", "Sl0s", ci->name, kicked->numeric, message);
+    lua_avpcall("irc_onkickall", "Sl0s", ci->name, kicked->numeric, message);
   }
 }
 
index 341913a1c23eef84a22ea3a9284d8b7c0a471c40..d86b47add64b1b6f02a9044bddbc6ef69ae79f58 100644 (file)
@@ -432,6 +432,7 @@ static int lua_getnickchanindex(lua_State *l) {
 
 int hashindex;
 nick *lasthashnick;
+static int geoipext;
 
 struct lua_pusher *nickhashpusher[MAX_PUSHER];
 
@@ -458,6 +459,7 @@ static int lua_getfirstnick(lua_State *l) {
   lasthashnick = NULL;
 
   lua_setupnickpusher(l, 1, nickhashpusher, MAX_PUSHER);
+  geoipext = findnickext("geoip");
 
   return lua_getnextnick(l);
 }
@@ -908,11 +910,14 @@ static int lua_skill(lua_State *ps) {
 #define PUSHER_SSTRING 6
 #define PUSHER_TOTALUSERS 7
 #define PUSHER_TOPIC 8
+#define PUSHER_UMODES 9
+#define PUSHER_COUNTRY 10
 
 void lua_initnickpusher(void) {
   int i = 0;
 
 #define PUSH_NICKPUSHER(F2, O2) nickpusher[i].argtype = F2; nickpusher[i].structname = #O2; nickpusher[i].offset = offsetof(nick, O2); i++;
+#define PUSH_NICKPUSHER_CUSTOM(F2, custom) nickpusher[i].argtype = F2; nickpusher[i].structname = custom; nickpusher[i].offset = 0; i++;
 
   PUSH_NICKPUSHER(PUSHER_STRING, nick);
   PUSH_NICKPUSHER(PUSHER_STRING, ident);
@@ -921,6 +926,10 @@ void lua_initnickpusher(void) {
   PUSH_NICKPUSHER(PUSHER_STRING, authname);
   PUSH_NICKPUSHER(PUSHER_IP, ipnode);
   PUSH_NICKPUSHER(PUSHER_LONG, numeric);
+  PUSH_NICKPUSHER(PUSHER_LONG, timestamp);
+  PUSH_NICKPUSHER(PUSHER_LONG, accountts);
+  PUSH_NICKPUSHER(PUSHER_UMODES, umodes);
+  PUSH_NICKPUSHER_CUSTOM(PUSHER_COUNTRY, "country");
 
   nickpushercount = i;
   nickpusher[i].argtype = 0;
@@ -978,11 +987,14 @@ INLINE int lua_usepusher(lua_State *l, struct lua_pusher **lp, void *np) {
         lua_pushlong(l, *((long *)offset));
         break;
       case PUSHER_IP:
-        lua_pushstring(l, IPtostr((((patricia_node_t *)offset)->prefix->sin)));
+        lua_pushstring(l, IPtostr((*((patricia_node_t **)offset))->prefix->sin));
         break;
       case PUSHER_TOTALUSERS:
         lua_pushint(l, (*((channel **)offset))->users->totalusers);
         break;
+      case PUSHER_UMODES:
+        lua_pushstring(l, printflags(*((flag_t *)offset), umodeflags));
+        break;
       case PUSHER_TOPIC:
         if((*((channel **)offset))->topic) {
           lua_pushstring(l, (*((channel **)offset))->topic->content);
@@ -990,6 +1002,13 @@ INLINE int lua_usepusher(lua_State *l, struct lua_pusher **lp, void *np) {
           lua_pushnil(l);
         }
         break;
+      case PUSHER_COUNTRY:
+        if(geoipext < 0) {
+          lua_pushint(l, -1);
+        } else {
+          lua_pushint(l, (long)((nick *)offset)->exts[geoipext]);
+        }
+        break;
     }
 
     i++;
diff --git a/lua/luadb.c b/lua/luadb.c
new file mode 100644 (file)
index 0000000..e47ca2d
--- /dev/null
@@ -0,0 +1,146 @@
+#include "../pqsql/pqsql.h"
+#include "lua.h"
+#include "luabot.h"
+
+static int lua_dbcreatequery(lua_State *ps) {
+  char *s = (char *)lua_tostring(ps, 1);
+
+  if(!s)
+    LUA_RETURN(ps, LUA_FAIL);
+
+  pqcreatequery(s);
+  LUA_RETURN(ps, LUA_OK);
+}
+
+/* TODO */
+/*
+static int lua_dbloadtable(lua_State *ps) {
+  lua_list *l = lua_listfromstate(ps);
+  if(!l)
+    LUA_RETURN(ps, LUA_FAIL);
+
+}
+*/
+
+typedef struct lua_callback {
+  lua_list *l;
+  long handler, args;
+} lua_callback;
+
+/* hack */
+PGresult *pgres;
+
+static int lua_dbnumfields(lua_State *ps) {
+  lua_pushint(ps, PQnfields(pgres));
+
+  return 1;
+}
+
+static int lua_dbnumrows(lua_State *ps) {
+  lua_pushint(ps, PQntuples(pgres));
+
+  return 1;
+}
+
+static int lua_dbgetvalue(lua_State *ps) {
+  char *r;
+  int tuple, field, len;
+
+  if(!lua_isint(ps, 1) || !lua_isint(ps, 2))
+    return 0;
+
+  tuple = lua_toint(ps, 1);
+  field = lua_toint(ps, 2);
+
+  r = PQgetvalue(pgres, lua_toint(ps, 1), lua_toint(ps, 2));
+  len = PQgetlength(pgres, tuple, field);
+
+  lua_pushlstring(ps, r, len); /* safe?! */
+
+  return 1;
+}
+
+void lua_dbcallback(PGconn *dbconn, void *arg) {
+  pgres = PQgetResult(dbconn);
+  lua_callback *c = (lua_callback *)arg;
+
+  if(!lua_listexists(c->l)) {
+    free(c);
+    return;
+  }
+
+  if(PQresultStatus(pgres) != PGRES_TUPLES_OK) {
+    _lua_vpcall(c->l->l, (void *)c->handler, LUA_POINTERMODE, "bR", 0, c->args);
+
+    luaL_unref(c->l->l, LUA_REGISTRYINDEX, c->handler);
+    luaL_unref(c->l->l, LUA_REGISTRYINDEX, c->args);
+    free(c);
+    return;
+  }
+
+  _lua_vpcall(c->l->l, (void *)c->handler, LUA_POINTERMODE, "bR", 1, c->args);
+
+  luaL_unref(c->l->l, LUA_REGISTRYINDEX, c->handler);
+  luaL_unref(c->l->l, LUA_REGISTRYINDEX, c->args);
+  free(c);
+  PQclear(pgres);
+  pgres = NULL;
+}
+
+static int lua_dbquery(lua_State *ps) {
+  lua_list *l = lua_listfromstate(ps);
+  char *q = (char *)lua_tostring(ps, 1);
+  lua_callback *cb;
+
+  /* what happens if 3 isn't there? */
+  if(!l || !q)
+    LUA_RETURN(ps, LUA_FAIL);
+
+  if(!lua_isfunction(ps, 2)) {
+    pqquery(q);
+    LUA_RETURN(ps, LUA_OK);
+  }
+
+  cb = (lua_callback *)malloc(sizeof(lua_callback));
+  if(!cb)
+    LUA_RETURN(ps, LUA_FAIL);
+
+  cb->l = l;
+  cb->args = luaL_ref(ps, LUA_REGISTRYINDEX);
+  cb->handler = luaL_ref(ps, LUA_REGISTRYINDEX);
+
+  pqasyncquery(lua_dbcallback, cb, q);
+
+  LUA_RETURN(ps, LUA_OK);
+}
+
+static int lua_dbescape(lua_State *ps) {
+  char ebuf[8192 * 2];
+  char *s = (char *)lua_tostring(ps, 1);
+  int len;
+  size_t elen;
+
+  if(!s)
+    return 0;
+
+  len = lua_strlen(ps, 1);
+  if(len > sizeof(ebuf) / 2 - 5)
+    return 0;
+
+  elen = PQescapeString(ebuf, s, len);
+  lua_pushlstring(ps, ebuf, elen);
+
+  return 1;
+}
+
+void lua_registerdbcommands(lua_State *l) {
+  lua_register(l, "db_createquery", lua_dbcreatequery);
+
+/*   lua_register(l, "db_loadtable", lua_dbloadtable); */
+
+  lua_register(l, "db_query", lua_dbquery);
+  lua_register(l, "db_escape", lua_dbescape);
+  lua_register(l, "db_numfields", lua_dbnumfields);
+  lua_register(l, "db_numrows", lua_dbnumrows);
+  lua_register(l, "db_getvalue", lua_dbgetvalue);
+}
diff --git a/lua/luasocket.c b/lua/luasocket.c
new file mode 100644 (file)
index 0000000..a6d6b07
--- /dev/null
@@ -0,0 +1,268 @@
+/* Copyright (C) Chris Porter 2007 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "../lib/strlfunc.h"
+#include "../core/events.h"
+
+#include "lua.h"
+#include "luabot.h"
+
+#define lua_vnpcall(F2, N2, S2, ...) _lua_vpcall(F2->l->l, (void *)F2->handler, LUA_POINTERMODE, "lsR" S2 , F2->identifier, N2, F2->tag , ##__VA_ARGS__)
+
+/*
+ * instead of these identifiers I could just use the file descriptor...
+ * BUT I can't remember the exact semantics of the fd table WRT reuse...
+ */
+static long nextidentifier = 0;
+static void lua_socket_poll_event(int fd, short events);
+
+static int lua_socket_unix_connect(lua_State *l) {
+  int len, ret;
+  struct sockaddr_un r;
+  char *path;
+  lua_socket *ls;
+  lua_list *ll;
+
+  ll = lua_listfromstate(l);
+  if(!ll)
+    return 0;
+
+  if(!lua_isfunction(l, 2))
+    return 0;
+
+  path = (char *)lua_tostring(l, 1);
+  if(!path)
+    return 0;
+
+  ls = (lua_socket *)malloc(sizeof(lua_socket));
+  if(!ls)
+    return 0;
+
+  ls->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if(ls->fd <= -1) {
+    free(ls);
+    return 0;
+  }
+
+  memset(&r, 0, sizeof(r));
+  r.sun_family = AF_UNIX;
+  strlcpy(r.sun_path, path, sizeof(r.sun_path));
+
+  /* don't really like this, there's a macro in sys/un.h but it's not there under FreeBSD */
+  len = sizeof(r.sun_family) + strlen(r.sun_path) + 1;
+
+  /* WTB exceptions */
+  ret = fcntl(ls->fd, F_GETFL, 0);
+  if(ret < 0) {
+    free(ls);
+    close(ls->fd);
+    return 0;
+  }
+
+  ret = fcntl(ls->fd, F_SETFL, ret | O_NONBLOCK);
+  if(ret < 0) {
+    free(ls);
+    close(ls->fd);
+    return 0;
+  }
+
+  ret = connect(ls->fd, (struct sockaddr *)&r, len);
+  if(ret == 0) {
+    ls->state = SOCKET_CONNECTED;
+  } else if(ret == -1 && (errno == EINPROGRESS)) {
+    ls->state = SOCKET_CONNECTING;
+  } else {
+    free(ls);
+    close(ls->fd);
+    return 0;
+  }
+
+  /* this whole identifier thing should probably use userdata stuff */
+  ls->identifier = nextidentifier++;
+  ls->tag = luaL_ref(l, LUA_REGISTRYINDEX);
+  ls->handler = luaL_ref(l, LUA_REGISTRYINDEX);
+
+  ls->l = ll;
+
+  ls->next = ll->sockets;
+  ll->sockets = ls;
+
+  registerhandler(ls->fd, (ls->state==SOCKET_CONNECTED?POLLIN:POLLOUT) | POLLERR | POLLHUP, lua_socket_poll_event);
+
+  lua_pushboolean(l, ls->state==SOCKET_CONNECTED?1:0);
+  lua_pushlong(l, ls->identifier);
+  return 2;
+}
+
+static lua_socket *socketbyfd(int fd) {
+  lua_list *l;
+  lua_socket *ls;
+
+  for(l=lua_head;l;l=l->next)
+    for(ls=l->sockets;ls;ls=ls->next)
+      if(ls->fd == fd)
+        return ls;
+
+  return NULL;
+}
+
+static lua_socket *socketbyidentifier(long identifier) {
+  lua_list *l;
+  lua_socket *ls;
+
+  for(l=lua_head;l;l=l->next)
+    for(ls=l->sockets;ls;ls=ls->next)
+      if(ls->identifier == identifier)
+        return ls;
+
+  return NULL;
+}
+
+static void lua_socket_call_close(lua_socket *ls) {
+  lua_socket *p, *c;
+
+  for(c=ls->l->sockets,p=NULL;c;p=c,c=c->next) {
+    if(c == ls) {
+      if(ls->state == SOCKET_CLOSED)
+        return;
+
+      ls->state = SOCKET_CLOSED;
+      deregisterhandler(ls->fd, 1);
+
+      lua_vnpcall(ls, "close", "");
+
+      if(!p) {
+        ls->l->sockets = ls->next;
+      } else {
+        p->next = ls->next;
+      }
+
+      luaL_unref(ls->l->l, LUA_REGISTRYINDEX, ls->tag);
+      luaL_unref(ls->l->l, LUA_REGISTRYINDEX, ls->handler);
+
+      free(ls);
+      return;
+    }
+  }
+
+}
+
+static int lua_socket_write(lua_State *l) {
+  char *buf;
+  long len;
+  lua_socket *ls;
+  int ret;
+
+  buf = (char *)lua_tostring(l, 2);
+
+  if(!lua_islong(l, 1) || !buf) {
+    lua_pushint(l, -1);
+    return 1;
+  }
+  len = lua_strlen(l, 2);
+
+  ls = socketbyidentifier(lua_tolong(l, 1));
+  if(!ls || (ls->state != SOCKET_CONNECTED)) {
+    lua_pushint(l, -1);
+    return 1;
+  }
+
+  ret = write(ls->fd, buf, len);
+  if(ret == -1 && (errno == EAGAIN)) {
+    deregisterhandler(ls->fd, 0);
+    registerhandler(ls->fd, POLLIN | POLLOUT | POLLERR | POLLHUP, lua_socket_poll_event);
+
+    lua_pushint(l, 0);
+    return 1;
+  }
+
+  if(ret == -1)
+    lua_socket_call_close(ls);
+
+  if(ret < len) {
+    deregisterhandler(ls->fd, 0);
+    registerhandler(ls->fd, POLLIN | POLLOUT | POLLERR | POLLHUP, lua_socket_poll_event);
+  }
+
+  lua_pushint(l, ret);
+  return 1;
+}
+
+static int lua_socket_close(lua_State *l) {
+  lua_socket *ls;
+
+  if(!lua_islong(l, 1))
+    LUA_RETURN(l, LUA_FAIL);
+
+  ls = socketbyidentifier(lua_tolong(l, 1));
+  if(!ls || (ls->state == SOCKET_CLOSED))
+    LUA_RETURN(l, LUA_FAIL);
+
+  lua_socket_call_close(ls);
+
+  LUA_RETURN(l, LUA_OK);
+}
+
+static void lua_socket_poll_event(int fd, short events) {
+  lua_socket *ls = socketbyfd(fd);
+  if(!ls || (ls->state == SOCKET_CLOSED))
+    return;
+
+  if(events & (POLLERR | POLLHUP)) {
+    lua_socket_call_close(ls);
+    return;
+  }
+
+  switch(ls->state) {
+    case SOCKET_CONNECTING:
+      if(events & POLLOUT) {
+        deregisterhandler(fd, 0);
+        registerhandler(fd, POLLIN | POLLERR | POLLHUP, lua_socket_poll_event);
+        ls->state = SOCKET_CONNECTED;
+
+        lua_vnpcall(ls, "connect", "");
+      }
+      break;
+    case SOCKET_CONNECTED:
+      if(events & POLLOUT) {
+        deregisterhandler(fd, 0);
+        registerhandler(fd, POLLIN | POLLERR | POLLHUP, lua_socket_poll_event);
+
+        lua_vnpcall(ls, "flush", "");
+      }
+      if(events & POLLIN) {
+        char buf[8192 * 2];
+        int bytesread;
+
+        bytesread = read(fd, buf, sizeof(buf));
+        if((bytesread == -1) && (errno == EAGAIN))
+          return;
+
+        if(bytesread <= 0) {
+          lua_socket_call_close(ls);
+         return;
+        }
+
+        lua_vnpcall(ls, "read", "L", buf, bytesread);
+      }
+      break;
+  }
+}
+
+void lua_socket_closeall(lua_list *l) {
+  while(l->sockets)
+    lua_socket_call_close(l->sockets);
+}
+
+void lua_registersocketcommands(lua_State *l) {
+  lua_register(l, "socket_unix_connect", lua_socket_unix_connect);
+  lua_register(l, "socket_close", lua_socket_close);
+  lua_register(l, "socket_write", lua_socket_write);
+}
diff --git a/lua/luasocket.h b/lua/luasocket.h
new file mode 100644 (file)
index 0000000..bd17417
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (C) Chris Porter 2007 */
+
+#ifndef _LUA_SOCKET_H
+#define _LUA_SOCKET_H
+
+#include "lua.h"
+
+typedef struct lua_socket {
+  int fd;
+  int state;
+  long handler;
+  long tag;
+  unsigned long identifier;
+  struct lua_list *l;
+  struct lua_socket *next;
+} lua_socket;
+
+#define SOCKET_CONNECTING 0x00
+#define SOCKET_CONNECTED  0x01
+#define SOCKET_CLOSED     0x02
+
+#endif
+
old mode 100755 (executable)
new mode 100644 (file)
index 2d69f98a6b83262a5e093bc68763e6c72dbf9fd6..d67348c4dc76083dd81ffd111f40d02299d17977 100644 (file)
@@ -2,5 +2,5 @@
 .PHONY: all
 all: newsearch.so
 
-newsearch.so: newsearch.o ns-not.o ns-and.o ns-or.o ns-eq.o ns-match.o ns-hostmask.o ns-realname.o ns-modes.o ns-nick.o ns-ident.o ns-regex.o ns-host.o ns-channel.o ns-lt.o ns-gt.o ns-timestamp.o ns-country.o ns-authname.o ns-ip.o ns-kill.o ns-gline.o ns-exists.o ns-services.o ns-size.o ns-name.o ns-topic.o ns-oppct.o ns-hostpct.o ns-authedpct.o ns-length.o
+newsearch.so: newsearch.o formats.o ns-not.o ns-and.o ns-or.o ns-eq.o ns-match.o ns-hostmask.o ns-realname.o ns-modes.o ns-nick.o ns-ident.o ns-regex.o ns-host.o ns-channel.o ns-lt.o ns-gt.o ns-timestamp.o ns-country.o ns-authname.o ns-ip.o ns-kill.o ns-gline.o ns-exists.o ns-services.o ns-size.o ns-name.o ns-topic.o ns-oppct.o ns-hostpct.o ns-authedpct.o ns-length.o ns-kick.o ns-authts.o ns-channels.o ns-server.o
        ld -shared -Bdynamic $(LIBPCRE) -o $@ $^
diff --git a/newsearch/formats.c b/newsearch/formats.c
new file mode 100644 (file)
index 0000000..c00ac8a
--- /dev/null
@@ -0,0 +1,149 @@
+
+#include <stdio.h>
+#include "newsearch.h"
+
+#include "../irc/irc_config.h"
+#include "../lib/irc_string.h"
+#include "../parser/parser.h"
+#include "../control/control.h"
+#include "../lib/splitline.h"
+#include "../lib/version.h"
+
+void printnick(nick *sender, nick *np) {
+  char hostbuf[HOSTLEN+NICKLEN+USERLEN+4];
+
+  controlreply(sender,"%s [%s] (%s) (%s)",visiblehostmask(np,hostbuf),
+              IPtostr(np->p_ipaddr), printflags(np->umodes, umodeflags), np->realname->name->content);
+}
+
+void printnick_channels(nick *sender, nick *np) {
+  char hostbuf[HOSTLEN+NICKLEN+USERLEN+4];
+  char chanlistbuf[512];
+  unsigned int bufpos=0, overflow=0;
+  channel **cs, *cp;
+  unsigned int i;
+  unsigned long *lp;
+  
+  /* Include the default format too */
+  printnick(sender,np);
+  
+  /* Now add the channels.. */
+  cs=(channel **)(np->channels->content);
+  for (i=0;i<np->channels->cursi;i++) {
+    cp=cs[i];
+    
+    if (!(lp=getnumerichandlefromchanhash(cp->users,np->numeric)))
+      /* "Impossible" error case - nick not on this channel */
+      continue;
+    
+    if (bufpos + cp->index->name->length > 400) {
+      overflow=1;
+      break;
+    }
+    
+    if (*lp & CUMODE_OP) {
+      chanlistbuf[bufpos++]='@';
+    } else if (*lp & CUMODE_VOICE) {
+      chanlistbuf[bufpos++]='+';
+    }
+    
+    bufpos+=sprintf(chanlistbuf+bufpos,"%s ",cp->index->name->content);
+  }
+  
+  if (!bufpos) {
+    controlreply(sender,"  Not an any channels.");
+  } else {
+    controlreply(sender,"  On channel%s: %s%s",np->channels->cursi>1?"s":"", chanlistbuf, overflow?"[...]":"");
+  }
+}
+
+void printchannel(nick *sender, chanindex *cip) {
+  /* shamelessly stolen from (now defunct) chansearch.c */
+  int i;
+  int op,voice,peon;
+  int oper,service,hosts;
+  nick *np;
+  chanuserhash *cuhp;
+  unsigned int marker;
+  
+  op=voice=peon=oper=service=hosts=0;
+  marker=nexthostmarker();
+  
+  if (cip->channel==NULL) {
+    controlreply(sender,"[         Channel currently empty          ] %s",cip->name->content);
+  } else {
+    cuhp=cip->channel->users;
+    for (i=0;i<cuhp->hashsize;i++) {
+      if (cuhp->content[i]!=nouser) {
+        if (cuhp->content[i]&CUMODE_OP) {
+          op++;
+        } else if (cuhp->content[i]&CUMODE_VOICE) {
+          voice++;
+        } else {
+          peon++;
+        }
+        if ((np=getnickbynumeric(cuhp->content[i]&CU_NUMERICMASK))!=NULL) {
+          if (IsOper(np)) {
+            oper++;
+          }
+          if (IsService(np)) {
+            service++;
+          }
+          if (np->host->marker!=marker) {
+            np->host->marker=marker;
+            hosts++;
+          }            
+        }
+      }
+    }
+    controlreply(sender,"[ %4dU %4d@ %4d+ %4d %4d* %4dk %4dH ] %s (%s)",cuhp->totalusers,op,voice,peon,oper,
+      service,hosts,cip->name->content, printflags(cip->channel->flags, cmodeflags));
+  }
+}
+
+
+void printchannel_topic(nick *sender, chanindex *cip) {
+  if (cip->channel==NULL) {
+    controlreply(sender,"[   empty  ] %-30s",cip->name->content);
+  } else {
+    controlreply(sender,"[%4u users] %s (%s)",cip->channel->users->totalusers,cip->name->content,cip->channel->topic?cip->channel->topic->content:"no topic");
+  }
+}
+
+void printchannel_services(nick *sender, chanindex *cip) {
+  int i;
+  chanuserhash *cuhp;
+  char servlist[300];
+  int slpos=0,slfull=0;
+  nick *np;
+  int servs=0;
+  
+  if (cip->channel==NULL) {
+    controlreply(sender,"%-30s empty",cip->name->content);
+  } else {
+    cuhp=cip->channel->users;
+    for (i=0;i<cuhp->hashsize;i++) {
+      if (cuhp->content[i]!=nouser) {
+        if ((np=getnickbynumeric(cuhp->content[i]&CU_NUMERICMASK))) {
+          if (IsService(np)) {
+            servs++;
+            if (!slfull) {
+              if (slpos) {
+                slpos+=sprintf(&servlist[slpos],", ");
+              }
+              slpos+=sprintf(&servlist[slpos],"%s",np->nick);
+              if (slpos>280) {
+                sprintf(&servlist[slpos],", ...");
+                slfull=1;
+              }
+            }
+          }
+        }
+      }
+    }  
+     
+    controlreply(sender,"%-30s %5d user%c %2d service%c %s%s%s",cip->name->content,cuhp->totalusers,
+                         cuhp->totalusers>1?'s':' ',servs,(servs==1)?' ':'s',servs?"(":"",slpos?servlist:"",servs?")":"");
+  }
+}
+
index 4967cde6be8844e908ce55b87ef47b2e8b3efa59..226379ef17c1dd7ec82f67aa75e51d5095ce9ee4 100644 (file)
 MODULE_VERSION("");
 
 CommandTree *searchTree;
+CommandTree *chanOutputTree;
+CommandTree *nickOutputTree;
 
 int do_nicksearch(void *source, int cargc, char **cargv);
 int do_chansearch(void *source, int cargc, char **cargv);
 struct searchNode *search_parse(int type, char *input);
 
+void printnick(nick *, nick *);
+void printnick_channels(nick *, nick *);
+void printchannel(nick *, chanindex *);
+void printchannel_topic(nick *, chanindex *);
+void printchannel_services(nick *, chanindex *);
+
 void registersearchterm(char *term, parseFunc parsefunc);
 void deregistersearchterm(char *term, parseFunc parsefunc);
 
-void *trueval(int type);
-void *falseval(int type);
+void regchandisp(const char *name, ChanDisplayFunc handler) {
+  addcommandtotree(chanOutputTree, name, 0, 0, (CommandHandler)handler);
+}
+
+void unregchandisp(const char *name, ChanDisplayFunc handler) {
+  deletecommandfromtree(chanOutputTree, name, (CommandHandler)handler);
+}
+
+void regnickdisp(const char *name, NickDisplayFunc handler) {
+  addcommandtotree(nickOutputTree, name, 0, 0, (CommandHandler)handler);
+}
+
+void unregnickdisp(const char *name, NickDisplayFunc handler) {
+  deletecommandfromtree(nickOutputTree, name, (CommandHandler)handler);
+}
 
 const char *parseError;
 /* used for *_free functions that need to warn users of certain things
@@ -30,6 +51,8 @@ nick *senderNSExtern;
 
 void _init() {
   searchTree=newcommandtree();
+  chanOutputTree=newcommandtree();
+  nickOutputTree=newcommandtree();
 
   /* Boolean operations */
   registersearchterm("and",and_parse);
@@ -50,12 +73,15 @@ void _init() {
   registersearchterm("hostmask",hostmask_parse);
   registersearchterm("realname",realname_parse);
   registersearchterm("authname",authname_parse);
+  registersearchterm("authts",authts_parse);
   registersearchterm("ident",ident_parse);
   registersearchterm("host",host_parse);
   registersearchterm("channel",channel_parse);
   registersearchterm("timestamp",timestamp_parse);
   registersearchterm("country",country_parse);
   registersearchterm("ip",ip_parse);
+  registersearchterm("channels",channels_parse);
+  registersearchterm("server",server_parse);
 
   /* Channel operations */
   registersearchterm("exists",exists_parse);
@@ -66,6 +92,7 @@ void _init() {
   registersearchterm("oppct",oppct_parse);
   registersearchterm("uniquehostpct",hostpct_parse);
   registersearchterm("authedpct",authedpct_parse);
+  registersearchterm("kick",kick_parse);
 
   /* Nickname / channel operations */
   registersearchterm("modes",modes_parse);
@@ -74,6 +101,15 @@ void _init() {
   /* Kill / gline parameters */
   registersearchterm("kill",kill_parse);
   registersearchterm("gline",gline_parse);
+  
+  /* Nick output filters */
+  regnickdisp("default",printnick);
+  regnickdisp("channels",printnick_channels);
+    
+  /* Channel output filters */
+  regchandisp("default",printchannel);
+  regchandisp("topic",printchannel_topic);
+  regchandisp("services",printchannel_services);
 
   registercontrolhelpcmd("nicksearch",NO_OPER,4,do_nicksearch, "Usage: nicksearch <criteria>\nSearches for nicknames with the given criteria.");
   registercontrolhelpcmd("chansearch",NO_OPER,4,do_chansearch, "Usage: chansearch <criteria>\nSearches for channels with the given criteria.");
@@ -81,6 +117,8 @@ void _init() {
 
 void _fini() {
   destroycommandtree(searchTree);
+  destroycommandtree(chanOutputTree);
+  destroycommandtree(nickOutputTree);
   deregistercontrolcmd("nicksearch", do_nicksearch);
   deregistercontrolcmd("chansearch", do_chansearch);
 }
@@ -93,65 +131,19 @@ void deregistersearchterm(char *term, parseFunc parsefunc) {
   deletecommandfromtree(searchTree, term, (CommandHandler) parsefunc);
 }
 
-void printnick(nick *sender, nick *np) {
-  char hostbuf[HOSTLEN+NICKLEN+USERLEN+4];
-
-  controlreply(sender,"%s [%s] (%s) (%s)",visiblehostmask(np,hostbuf),
-              IPtostr(np->p_ipaddr), printflags(np->umodes, umodeflags), np->realname->name->content);
-}
-
-void printchannel(nick *sender, chanindex *cip) {
-  /* shamelessly stolen from (now defunct) chansearch.c */
-  int i;
-  int op,voice,peon;
-  int oper,service,hosts;
-  nick *np;
-  chanuserhash *cuhp;
-  unsigned int marker;
-  
-  op=voice=peon=oper=service=hosts=0;
-  marker=nexthostmarker();
-  
-  if (cip->channel==NULL) {
-    controlreply(sender,"[         Channel currently empty          ] %s",cip->name->content);
-  } else {
-    cuhp=cip->channel->users;
-    for (i=0;i<cuhp->hashsize;i++) {
-      if (cuhp->content[i]!=nouser) {
-        if (cuhp->content[i]&CUMODE_OP) {
-          op++;
-        } else if (cuhp->content[i]&CUMODE_VOICE) {
-          voice++;
-        } else {
-          peon++;
-        }
-        if ((np=getnickbynumeric(cuhp->content[i]&CU_NUMERICMASK))!=NULL) {
-          if (IsOper(np)) {
-            oper++;
-          }
-          if (IsService(np)) {
-            service++;
-          }
-          if (np->host->marker!=marker) {
-            np->host->marker=marker;
-            hosts++;
-          }            
-        }
-      }
-    }
-    controlreply(sender,"[ %4dU %4d@ %4d+ %4d %4d* %4dk %4dH ] %s (%s)",cuhp->totalusers,op,voice,peon,oper,
-      service,hosts,cip->name->content, printflags(cip->channel->flags, cmodeflags));
-  }
-}
-
 int do_nicksearch(void *source, int cargc, char **cargv) {
   nick *sender = senderNSExtern = source, *np;
-  int i;
+  int i,j;
   struct searchNode *search;
   int limit=500,matches=0;
   char *ch;
   int arg=0;
-
+  struct Command *cmd;
+  NickDisplayFunc display=printnick;
+  unsigned int cmarker;
+  unsigned int tchans=0,uchans=0;
+  struct channel **cs;
+  
   if (cargc<1)
     return CMD_USAGE;
   
@@ -169,6 +161,20 @@ int do_nicksearch(void *source, int cargc, char **cargv) {
        limit=strtoul(cargv[arg++],NULL,10);
        break;
        
+      case 'd':
+        if (cargc<arg) {
+          controlreply(sender,"Error: -d switch requires an argument");
+          return CMD_USAGE;
+        }
+        cmd=findcommandintree(nickOutputTree, cargv[arg], 1);
+        if (!cmd) {
+          controlreply(sender,"Error: unknown output format %s",cargv[arg]);
+          return CMD_USAGE;
+        }
+        display=(NickDisplayFunc)cmd->handler;
+        arg++;
+        break;
+        
       default:
        controlreply(sender,"Unrecognised flag -%c.",*ch);
       }
@@ -189,14 +195,30 @@ int do_nicksearch(void *source, int cargc, char **cargv) {
     return CMD_ERROR;
   }
   
+  /* Get a marker value to mark "seen" channels for unique count */
+  cmarker=nextchanmarker();
+  
   /* The top-level node needs to return a BOOL */
   search=coerceNode(search, RETURNTYPE_BOOL);
   
   for (i=0;i<NICKHASHSIZE;i++) {
     for (np=nicktable[i];np;np=np->next) {
       if ((search->exe)(search, np)) {
+        /* Add total channels */
+        tchans += np->channels->cursi;
+        
+        /* Check channels for uniqueness */
+        cs=(channel **)np->channels->content;
+        for (j=0;j<np->channels->cursi;j++) {
+          if (cs[j]->index->marker != cmarker) {
+            cs[j]->index->marker=cmarker;
+            uchans++;
+          }
+        }
+          
        if (matches<limit)
-         printnick(sender, np);
+         display(sender, np);
+         
        if (matches==limit)
          controlreply(sender, "--- More than %d matches, skipping the rest",limit);
        matches++;
@@ -206,8 +228,9 @@ int do_nicksearch(void *source, int cargc, char **cargv) {
 
   (search->free)(search);
 
-  controlreply(sender,"--- End of list: %d matches", matches);
-  
+  controlreply(sender,"--- End of list: %d matches; users were on %u channels (%u unique, %.1f average clones)", 
+                matches, tchans, uchans, (float)tchans/uchans);
+
   return CMD_OK;
 }  
 
@@ -219,6 +242,8 @@ int do_chansearch(void *source, int cargc, char **cargv) {
   int limit=500,matches=0;
   char *ch;
   int arg=0;
+  struct Command *cmd;
+  ChanDisplayFunc display=printchannel;
 
   if (cargc<1)
     return CMD_USAGE;
@@ -236,6 +261,20 @@ int do_chansearch(void *source, int cargc, char **cargv) {
        }
        limit=strtoul(cargv[arg++],NULL,10);
        break;
+
+      case 'd':
+        if (cargc<arg) {
+          controlreply(sender,"Error: -d switch requires an argument");
+          return CMD_USAGE;
+        }
+        cmd=findcommandintree(chanOutputTree, cargv[arg], 1);
+        if (!cmd) {
+          controlreply(sender,"Error: unknown output format %s",cargv[arg]);
+          return CMD_USAGE;
+        }
+        display=(ChanDisplayFunc)cmd->handler;
+        arg++;
+        break;
        
       default:
        controlreply(sender,"Unrecognised flag -%c.",*ch);
@@ -263,7 +302,7 @@ int do_chansearch(void *source, int cargc, char **cargv) {
     for (cip=chantable[i];cip;cip=cip->next) {
       if ((search->exe)(search, cip)) {
        if (matches<limit)
-         printchannel(sender, cip);
+         display(sender, cip);
        if (matches==limit)
          controlreply(sender, "--- More than %d matches, skipping the rest",limit);
        matches++;
@@ -278,30 +317,6 @@ int do_chansearch(void *source, int cargc, char **cargv) {
   return CMD_OK;
 }
 
-void *trueval(int type) {
-  switch(type) {
-  default:
-  case RETURNTYPE_INT:
-  case RETURNTYPE_BOOL:
-    return (void *)1;
-    
-  case RETURNTYPE_STRING:
-    return "1";
-  }
-}
-
-void *falseval(int type) {
-  switch (type) {
-  default:
-  case RETURNTYPE_INT:
-  case RETURNTYPE_BOOL:
-    return NULL;
-    
-  case RETURNTYPE_STRING:
-    return "";
-  }
-}
-
 struct coercedata {
   struct searchNode *child;
   union {
@@ -661,3 +676,93 @@ struct searchNode *search_parse(int type, char *input) {
     return thenode;
   }    
 }
+
+struct bufs {
+  char *buf;
+  int capacity;
+  int len;
+};
+
+static int addchar(struct bufs *buf, char c) {
+  if(buf->len >= buf->capacity - 1)
+    return 0;
+
+  buf->buf[buf->len++] = c;
+
+  return 1;
+}
+
+static int addstr(struct bufs *buf, char *c) {
+  int remaining = buf->capacity - buf->len - 1;
+  char *p;
+
+  for(p=c;*p;p++) {
+    if(remaining-- <= 0)
+      return 0;
+
+    buf->buf[buf->len++] = *p;
+  }
+
+  return 1;
+}
+
+void nssnprintf(char *buf, size_t size, const char *format, nick *np) {
+  struct bufs b;
+  const char *p;
+  char *c;
+  char hostbuf[512];
+
+  if(size == 0)
+    return;
+
+  b.buf = buf;
+  b.capacity = size;
+  b.len = 0;
+
+  for(p=format;*p;p++) {
+    if(*p != '%') {
+      if(!addchar(&b, *p))
+        break;
+      continue;
+    }
+    p++;
+    if(*p == '\0')
+      break;
+    if(*p == '%') {
+      if(!addchar(&b, *p))
+        break;
+      continue;
+    }
+
+    c = NULL;
+    switch(*p) {
+      case 'n':
+        c = np->nick; break;
+      case 'i':
+        c = np->ident; break;
+      case 'h':
+        c = np->host->name->content; break;
+      case 'I':
+        snprintf(hostbuf, sizeof(hostbuf), "%s", IPtostr(np->p_ipaddr));
+        c = hostbuf;
+        break;
+      case 'u':
+        snprintf(hostbuf, sizeof(hostbuf), "%s!%s@%s", np->nick, np->ident, IPtostr(np->p_ipaddr));
+        c = hostbuf;
+        break;
+      default:
+        c = "(bad format specifier)";
+    }
+    if(c)
+      if(!addstr(&b, c))
+        break;
+  }
+
+  buf[b.len] = '\0';
+
+  /* not required */
+  /*
+  buf[size-1] = '\0';
+  */
+}
+
index bd94144dc28017825b2c6e0339d2a044fa71f72e..5d001249d5926fe4ea3d5d72295c1e6c1ab4160f 100644 (file)
@@ -31,6 +31,8 @@ struct searchNode;
 typedef struct searchNode *(*parseFunc)(int, int, char **);
 typedef void (*freeFunc)(struct searchNode *);
 typedef void *(*exeFunc)(struct searchNode *, void *);
+typedef void (*ChanDisplayFunc)(nick *, chanindex *);
+typedef void (*NickDisplayFunc)(nick *, nick *);
 
 /* Core functions */
 /* Logical  (BOOL -> BOOL)*/
@@ -62,12 +64,15 @@ struct searchNode *modes_parse(int type, int argc, char **argv);
 struct searchNode *hostmask_parse(int type, int argc, char **argv);
 struct searchNode *realname_parse(int type, int argc, char **argv);
 struct searchNode *authname_parse(int type, int argc, char **argv);
+struct searchNode *authts_parse(int type, int argc, char **argv);
 struct searchNode *ident_parse(int type, int argc, char **argv);
 struct searchNode *host_parse(int type, int argc, char **argv);
 struct searchNode *channel_parse(int type, int argc, char **argv);
 struct searchNode *timestamp_parse(int type, int argc, char **argv);
 struct searchNode *country_parse(int type, int argc, char **argv);
 struct searchNode *ip_parse(int type, int argc, char **argv);
+struct searchNode *channels_parse(int type, int argc, char **argv);
+struct searchNode *server_parse(int type, int argc, char **argv);
 
 /* Channel functions (various types) */
 struct searchNode *exists_parse(int type, int argc, char **argv);
@@ -78,6 +83,7 @@ struct searchNode *topic_parse(int type, int argc, char **argv);
 struct searchNode *oppct_parse(int type, int argc, char **argv);
 struct searchNode *hostpct_parse(int type, int argc, char **argv);
 struct searchNode *authedpct_parse(int type, int argc, char **argv);
+struct searchNode *kick_parse(int type, int argc, char **argv);
 
 /* Interpret a string to give a node */
 struct searchNode *search_parse(int type, char *input);
@@ -88,9 +94,13 @@ struct searchNode *coerceNode(struct searchNode *thenode, int type);
 /* Registration functions */
 void registersearchterm(char *term, parseFunc parsefunc);
 void deregistersearchterm(char *term, parseFunc parsefunc);
+void regchandisp(const char *name, ChanDisplayFunc handler);
+void unregchandisp(const char *name, ChanDisplayFunc handler);
+void regnickdisp(const char *name, NickDisplayFunc handler);
+void unregnickdisp(const char *name, NickDisplayFunc handler);
 
-void *trueval(int type);
-void *falseval(int type);
+/* Special nick* printf */
+void nssnprintf(char *, size_t, const char *, nick *);
 
 typedef struct searchNode {
   int returntype;
diff --git a/newsearch/ns-authts.c b/newsearch/ns-authts.c
new file mode 100644 (file)
index 0000000..46b02bf
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * AUTHTS functionality 
+ */
+
+#include "newsearch.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void *authts_exe(struct searchNode *thenode, void *theinput);
+void authts_free(struct searchNode *thenode);
+
+struct searchNode *authts_parse(int type, int argc, char **argv) {
+  struct searchNode *thenode;
+
+  if (type != SEARCHTYPE_NICK) {
+    parseError = "authts: this function is only valid for nick searches.";
+    return NULL;
+  }
+
+  if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) {
+    parseError = "malloc: could not allocate memory for this search.";
+    return NULL;
+  }
+
+  thenode->returntype = RETURNTYPE_INT;
+  thenode->localdata = NULL;
+  thenode->exe = authts_exe;
+  thenode->free = authts_free;
+
+  return thenode;
+}
+
+void *authts_exe(struct searchNode *thenode, void *theinput) {
+  nick *np = (nick *)theinput;
+
+  if (IsAccount(np))
+    return (void *)(np->accountts);
+  else
+    return (void *)0; /* will cast to a FALSE */
+
+}
+
+void authts_free(struct searchNode *thenode) {
+  free(thenode);
+}
diff --git a/newsearch/ns-channels.c b/newsearch/ns-channels.c
new file mode 100644 (file)
index 0000000..5f05598
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * CHANNELS functionality
+ */
+
+#include "newsearch.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../irc/irc_config.h"
+#include "../lib/irc_string.h"
+
+void *channels_exe(struct searchNode *thenode, void *theinput);
+void channels_free(struct searchNode *thenode);
+
+struct searchNode *channels_parse(int type, int argc, char **argv) {
+  struct searchNode *thenode;
+
+  if (type != SEARCHTYPE_NICK) {
+    parseError = "channels: this function is only valid for nick searches.";
+    return NULL;
+  }
+
+  if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) {
+    parseError = "malloc: could not allocate memory for this search.";
+    return NULL;
+  }
+
+  thenode->returntype = RETURNTYPE_INT;
+  thenode->localdata = NULL;
+  thenode->exe = channels_exe;
+  thenode->free = channels_free;
+
+  return thenode;
+}
+
+void *channels_exe(struct searchNode *thenode, void *theinput) {
+  nick *np = (nick *)theinput;
+
+  return (void *)np->channels->cursi;
+}
+
+void channels_free(struct searchNode *thenode) {
+  free(thenode);
+}
index d5a1a29a57c8130d97abe5c1f07c58369d12236b..ffd87813b5e0f1468cb83dc64da0d0ff3c6c8e58 100644 (file)
@@ -9,6 +9,8 @@
 
 #include "../irc/irc_config.h"
 #include "../lib/irc_string.h"
+#include "../geoip/geoip.h"
+#include "../core/modules.h"
 
 void *country_exe(struct searchNode *thenode, void *theinput);
 void country_free(struct searchNode *thenode);
@@ -17,26 +19,39 @@ int ext;
 
 struct searchNode *country_parse(int type, int argc, char **argv) {
   struct searchNode *thenode;
+  GeoIP_LookupCode l;
+  int target;
 
   if (type != SEARCHTYPE_NICK) {
     parseError = "country: this function is only valid for nick searches.";
     return NULL;
   }
 
+  if (argc<1) {
+    parseError = "country: usage: country <country 2 character ISO code>";
+    return NULL;
+  }
+
   ext = findnickext("geoip");
   if(ext == -1) {
     parseError = "country: Geoip module not loaded.";
     return NULL;
   }
   
+  l = ndlsym("geoip", "geoip_lookupcode");
+  target = l(argv[0]);
+  if(target == -1) {
+    parseError = "country: invalid country.";
+    return NULL;
+  }
 
   if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) {
     parseError = "malloc: could not allocate memory for this search.";
     return NULL;
   }
 
-  thenode->returntype = RETURNTYPE_INT;
-  thenode->localdata = NULL;
+  thenode->returntype = RETURNTYPE_BOOL;
+  thenode->localdata = (void *)target;
   thenode->exe = country_exe;
   thenode->free = country_free;
 
@@ -45,8 +60,12 @@ struct searchNode *country_parse(int type, int argc, char **argv) {
 
 void *country_exe(struct searchNode *thenode, void *theinput) {
   nick *np = (nick *)theinput;
+  int country = (int)thenode->localdata, rc = (int)np->exts[ext];
+
+  if(country == rc)
+    return (void *)1;
 
-  return (void *)np->exts[ext];
+  return (void *)0;
 }
 
 void country_free(struct searchNode *thenode) {
index 270f64c2bda34a0b2bb573283a39b83a8a227ad5..7803cdb428f1f1e91349a613a6122ab6e9042ee6 100644 (file)
 #include "../control/control.h" /* controlreply() */
 #include "../irc/irc.h" /* irc_send() */
 #include "../lib/irc_string.h" /* IPtostr(), longtoduration(), durationtolong() */
+#include "../lib/strlfunc.h"
 
 /* used for *_free functions that need to warn users of certain things
    i.e. hitting too many users in a (kill) or (gline) - declared in newsearch.c */
 extern nick *senderNSExtern;
+static const char *defaultreason = "You (%u) have been g-lined for violating our terms of service";
 
 void *gline_exe(struct searchNode *thenode, void *theinput);
 void gline_free(struct searchNode *thenode);
@@ -31,6 +33,7 @@ struct searchNode *gline_parse(int type, int argc, char **argv) {
   struct gline_localdata *localdata;
   struct searchNode *thenode;
   int len;
+  char *p;
 
   if (!(localdata = (struct gline_localdata *) malloc(sizeof(struct gline_localdata)))) {
     parseError = "malloc: could not allocate memory for this search.";
@@ -46,7 +49,7 @@ struct searchNode *gline_parse(int type, int argc, char **argv) {
   switch (argc) {
   case 0:
     localdata->duration = NSGLINE_DURATION;
-    snprintf(localdata->reason, NSMAX_REASON_LEN, ".");
+    strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
     break;
 
   case 1:
@@ -55,14 +58,20 @@ struct searchNode *gline_parse(int type, int argc, char **argv) {
       /* error checking on gline duration */
       if (localdata->duration == 0)
         localdata->duration = NSGLINE_DURATION;
-      snprintf(localdata->reason, NSMAX_REASON_LEN, ".");
+      strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
     }
     else { /* reason specified */
       localdata->duration = NSGLINE_DURATION;
-      len = snprintf(localdata->reason, NSMAX_REASON_LEN, ":%s", argv[0]);
-      /* strip leading and trailing '"'s */
-      localdata->reason[1] = ' ';
-      localdata->reason[len-1] = '\0';
+
+      p = argv[0];
+      if(*p == '\"')
+        *p++;
+      len = strlcpy(localdata->reason, p, sizeof(localdata->reason));
+      if(len >= sizeof(localdata->reason)) {
+        localdata->reason[sizeof(localdata->reason)-1] = '\0';
+      } else {
+        localdata->reason[len-1] = '\0';
+      }
     }
     break;
 
@@ -71,12 +80,18 @@ struct searchNode *gline_parse(int type, int argc, char **argv) {
     /* error checking on gline duration */
     if (localdata->duration == 0)
       localdata->duration = NSGLINE_DURATION;
-    len = snprintf(localdata->reason, NSMAX_REASON_LEN, ":%s", argv[1]);
-    /* strip leading and trailing '"'s */
-    localdata->reason[1] = ' ';
-    localdata->reason[len-1] = '\0';
-    break;
 
+    p = argv[1];
+    if(*p == '\"')
+      *p++;
+    len = strlcpy(localdata->reason, p, sizeof(localdata->reason));
+    if(len >= sizeof(localdata->reason)) {
+      localdata->reason[sizeof(localdata->reason)-1] = '\0';
+    } else {
+      localdata->reason[len-1] = '\0';
+    }
+
+    break;
   default:
     free(localdata);
     parseError = "gline: invalid number of arguments";
@@ -124,6 +139,7 @@ void gline_free(struct searchNode *thenode) {
   nick *np, *nnp;
   chanindex *cip, *ncip;
   int i, j, safe=0;
+  char msgbuf[512];
 
   localdata = thenode->localdata;
 
@@ -146,15 +162,14 @@ void gline_free(struct searchNode *thenode) {
     
             if ((np=getnickbynumeric(cip->channel->users->content[j]))) {
               if (!IsOper(np) && !IsService(np) && !IsXOper(np)) {
+                nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
                 if (np->host->clonecount <= NSMAX_GLINE_CLONES)
-                  irc_send("%s GL * +*@%s %u :You (%s!%s@%s) have been glined for violating our terms of service%s", 
-                    mynumeric->content, IPtostr(np->p_ipaddr), localdata->duration, np->nick, np->ident, IPtostr(np->p_ipaddr), localdata->reason);
-                else
-                  irc_send("%s GL * +%s@%s %u :You (%s!%s@%s) have been glined for violating our terms of service%s", 
-                    mynumeric->content, np->ident, IPtostr(np->p_ipaddr), localdata->duration, np->nick, np->ident, IPtostr(np->p_ipaddr), localdata->reason);
-                }
+                  irc_send("%s GL * +*@%s %u :%s", mynumeric->content, IPtostr(np->p_ipaddr), localdata->duration, msgbuf);
                 else
-                  safe++;
+                  irc_send("%s GL * +%s@%s %u :%s", mynumeric->content, np->ident, IPtostr(np->p_ipaddr), localdata->duration, msgbuf);
+              }
+              else
+                safe++;
             }
           }
         }
@@ -167,12 +182,11 @@ void gline_free(struct searchNode *thenode) {
         nnp = np->next;
         if (np->marker == localdata->marker) {
           if (!IsOper(np) && !IsService(np) && !IsXOper(np)) {
+            nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
             if (np->host->clonecount <= NSMAX_GLINE_CLONES)
-              irc_send("%s GL * +*@%s %u :You (%s!%s@%s) have been glined for violating our terms of service%s", 
-                mynumeric->content, IPtostr(np->p_ipaddr), localdata->duration, np->nick, np->ident, IPtostr(np->p_ipaddr), localdata->reason);
+              irc_send("%s GL * +*@%s %u :%s", mynumeric->content, IPtostr(np->p_ipaddr), localdata->duration, msgbuf);
             else
-              irc_send("%s GL * +%s@%s %u :You (%s!%s@%s) have been glined for violating our terms of service%s", 
-                mynumeric->content, np->ident, IPtostr(np->p_ipaddr), localdata->duration, np->nick, np->ident, IPtostr(np->p_ipaddr), localdata->reason);
+              irc_send("%s GL * +%s@%s %u :%s", mynumeric->content, np->ident, IPtostr(np->p_ipaddr), localdata->duration, msgbuf);
           }
           else
               safe++;
diff --git a/newsearch/ns-kick.c b/newsearch/ns-kick.c
new file mode 100644 (file)
index 0000000..9f4f935
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * KICK functionality 
+ */
+
+#include "newsearch.h"
+#include "../localuser/localuserchannel.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void *kick_exe(struct searchNode *thenode, void *theinput);
+void kick_free(struct searchNode *thenode);
+
+struct searchNode *kick_parse(int type, int argc, char **argv) {
+  struct searchNode *thenode;
+  nick *np;
+  
+  if (type!=SEARCHTYPE_CHANNEL) {
+    parseError="kick: only channel searches are supported";
+    return NULL;
+  }
+
+  if (argc!=1) {
+    parseError="kick: usage: (kick target)";
+    return NULL;
+  }
+
+  if ((np=getnickbynick(argv[0]))==NULL) {
+    parseError="kick: unknown nickname";
+    return NULL;
+  }
+  
+  if (IsOper(np) || IsService(np)) {
+    parseError="kick: can't kick opers or services";
+    return NULL;
+  }
+
+  if (!(thenode=(struct searchNode *)malloc(sizeof(struct searchNode)))) {
+    parseError = "malloc: could not allocate memory for this search.";
+    return NULL;
+  }
+
+  thenode->returntype = RETURNTYPE_BOOL;
+  thenode->localdata = np;
+  thenode->exe = kick_exe;
+  thenode->free = kick_free;
+
+  return thenode;
+}
+
+void *kick_exe(struct searchNode *thenode, void *theinput) {
+  nick *np;
+  chanindex *cip;
+
+  np=thenode->localdata;
+  cip=(chanindex *)theinput;
+
+  if (cip->channel==NULL || getnumerichandlefromchanhash(cip->channel->users, np->numeric)==NULL)
+    return (void *)0;
+  
+  localkickuser(NULL, cip->channel, np, "");
+  return (void *)1;
+}
+
+void kick_free(struct searchNode *thenode) {
+  free(thenode);
+}
index 258a3b07fbc39f0c294eaabac08cde7433790fbb..a8166787d63336797a9d460c5d80fd3ebc5e32c4 100644 (file)
@@ -10,6 +10,7 @@
 #include "../control/control.h" /* controlreply() */
 #include "../localuser/localuser.h" /* killuser() */
 #include "../lib/irc_string.h" /* IPtostr() */
+#include "../lib/strlfunc.h"
 
 /* used for *_free functions that need to warn users of certain things
    i.e. hitting too many users in a (kill) or (gline) - declared in newsearch.c */
@@ -17,6 +18,7 @@ extern nick *senderNSExtern;
 
 void *kill_exe(struct searchNode *thenode, void *theinput);
 void kill_free(struct searchNode *thenode);
+static const char *defaultreason = "You (%u) have been disconnected for violating our terms of service";
 
 struct kill_localdata {
   unsigned int marker;
@@ -42,13 +44,18 @@ struct searchNode *kill_parse(int type, int argc, char **argv) {
     localdata->marker = nextnickmarker();
 
   if (argc==1) {
-    len = snprintf(localdata->reason, NSMAX_REASON_LEN, ":%s", argv[0]);
-    /* strip leading and trailing '"'s */
-    localdata->reason[1] = ' ';
-    localdata->reason[len-1] = '\0';
+    char *p = argv[0];
+    if(*p == '\"')
+      *p++;
+    len = strlcpy(localdata->reason, p, sizeof(localdata->reason));
+    if(len >= sizeof(localdata->reason)) {
+      localdata->reason[sizeof(localdata->reason)-1] = '\0';
+    } else {
+      localdata->reason[len-1] = '\0';
+    }
   }
   else
-    snprintf(localdata->reason, NSMAX_REASON_LEN, ".");
+    strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
 
   if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) {
     /* couldn't malloc() memory for thenode, so free localdata to avoid leakage */
@@ -92,6 +99,7 @@ void kill_free(struct searchNode *thenode) {
   chanindex *cip, *ncip;
   int i, j, safe=0;
   unsigned int nickmarker;
+  char msgbuf[512];
 
   localdata = thenode->localdata;
 
@@ -127,9 +135,10 @@ void kill_free(struct searchNode *thenode) {
     for (i=0;i<NICKHASHSIZE;i++) {
       for(np=nicktable[i];np;np=nnp) {
         nnp = np->next;
-        if (np->marker == nickmarker) 
-          killuser(NULL, np, "You (%s!%s@%s) have been disconnected for violating our terms of service%s", 
-                         np->nick,np->ident, IPtostr(np->p_ipaddr), localdata->reason);
+        if (np->marker == nickmarker) {
+          nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
+          killuser(NULL, np, "%s", msgbuf);
+        }
       }
     }
   }
@@ -139,8 +148,8 @@ void kill_free(struct searchNode *thenode) {
         nnp = np->next;
         if (np->marker == localdata->marker) {
           if (!IsOper(np) && !IsService(np) && !IsXOper(np)) {
-            killuser(NULL, np, "You (%s!%s@%s) have been disconnected for violating our terms of service%s", np->nick,
-              np->ident, IPtostr(np->p_ipaddr), localdata->reason);
+            nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
+            killuser(NULL, np, "%s", msgbuf);
           }
           else
               safe++;
index c1f28a78dcd46e20df3b8ab3275ce3e51277c599..f61ae15a259fa1af80f2a2233c9257b98627d2d0 100644 (file)
@@ -36,7 +36,7 @@ struct searchNode *not_parse(int type, int argc, char **argv) {
   }
 
   /* Our subnode needs to return a BOOL */  
-  subnode=coerceNode(thenode, RETURNTYPE_BOOL);
+  subnode=coerceNode(subnode, RETURNTYPE_BOOL);
 
   thenode->localdata=(void *)subnode;
       
diff --git a/newsearch/ns-server.c b/newsearch/ns-server.c
new file mode 100644 (file)
index 0000000..769e663
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * SERVER functionality
+ */
+
+#include "newsearch.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../irc/irc_config.h"
+#include "../lib/irc_string.h"
+#include "../core/modules.h"
+#include "../server/server.h"
+
+void *server_exe_bool(struct searchNode *thenode, void *theinput);
+void *server_exe_str(struct searchNode *thenode, void *theinput);
+void server_free(struct searchNode *thenode);
+
+int ext;
+
+struct searchNode *server_parse(int type, int argc, char **argv) {
+  struct searchNode *thenode;
+  int i;
+  long numeric;
+
+  if (type != SEARCHTYPE_NICK) {
+    parseError = "server: this function is only valid for nick searches.";
+    return NULL;
+  }
+
+  if (argc>0) {
+    numeric = -1;
+    for(i=0;i<MAXSERVERS;i++) {
+      sstring *n = serverlist[i].name;
+      if(n && !strcmp(n->content, argv[0])) {
+        numeric = i;
+        break;
+      }
+    }
+
+    if(numeric == -1) {
+      parseError = "server: server not found.";
+      return NULL;
+    }
+
+    thenode->returntype = RETURNTYPE_BOOL;
+    thenode->localdata = (void *)numeric;
+
+    thenode->exe = server_exe_bool;
+  } else {
+    thenode->returntype = RETURNTYPE_STRING;
+    thenode->localdata = NULL;
+
+    thenode->exe = server_exe_str;
+  }
+
+  thenode->free = server_free;
+
+  return thenode;
+}
+
+void *server_exe_bool(struct searchNode *thenode, void *theinput) {
+  nick *np = (nick *)theinput;
+  long server = (long)thenode->localdata;
+
+  if(homeserver(np->numeric) == server)
+    return (void *)1;
+
+  return (void *)0;
+}
+
+void *server_exe_str(struct searchNode *thenode, void *theinput) {
+  nick *np = (nick *)theinput;
+  sstring *n = serverlist[homeserver(np->numeric)].name;
+
+  if(!n)
+    return NULL;
+
+  return n->content;
+}
+
+void server_free(struct searchNode *thenode) {
+  free(thenode);
+}
index 3106527af75cf3f2495f804d697483976166899f..f739384706b90ca1b128abda72735955c0b3635e 100644 (file)
@@ -34,6 +34,7 @@ const flag umodeflags[] = {
    { 'h', UMODE_SETHOST },
    { 'R', UMODE_REGPRIV },
    { 'I', UMODE_HIDEIDLE },
+   { 'P', UMODE_PARANOID },
    { '\0', 0 } };
 
 #define nickhash(x)       ((crc32i(x))%NICKHASHSIZE)
index 4cba97bdcf480c8b2f98bc53174b2326db6de015..1e9731888260fbfe7b29f0710ce048d10612c157 100644 (file)
@@ -16,7 +16,9 @@
 
 #include <time.h>
 
+#ifndef MAXNICKEXTS
 #define MAXNICKEXTS       6
+#endif
 
 #define UMODE_INV       0x0001
 #define UMODE_WALLOPS   0x0002
index 9f2987f378dc6fe8295421ffcbb227958228586d..023457417395927da212c57800dffe931c0705a5 100644 (file)
@@ -12,6 +12,7 @@
 #include "../localuser/localuserchannel.h"
 #include "../geoip/geoip.h"
 #include "../lib/version.h"
+#include "../core/modules.h"
 
 MODULE_VERSION("");
 
@@ -291,11 +292,10 @@ int controlobroadcast(void *sender, int cargc, char **cargv) {
   return CMD_OK;
 }
 
-const char GeoIP_country_code[247][3] = { "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN","AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF","CG","CH","CI","CK","CL","CM","CN","CO","CR","CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO","DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR","FX","GA","GB","GD","GE","GF","GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA","MC","MD","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY","QA","RE","RO","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO","SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH","TJ","TK","TM","TN","TO","TP","TR","TT","TV","TW","TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","YE","YT","YU","ZA","ZM","ZR","ZW","A1","A2","O1"};
-
 int controlcbroadcast(void *sender, int cargc, char **cargv) {
   nick *np = (nick *)sender, *nip;
   int i, ext, target;
+  GeoIP_LookupCode l;
 
   if(cargc < 2)
     return CMD_USAGE;
@@ -306,13 +306,8 @@ int controlcbroadcast(void *sender, int cargc, char **cargv) {
     return CMD_ERROR;
   }
 
-  target = COUNTRY_MIN - 1;
-  for(i=COUNTRY_MIN;i<COUNTRY_MAX;i++) {
-    if(!strcasecmp(cargv[0], GeoIP_country_code[i])) {
-      target = i;
-      break;
-    }
-  }
+  l = ndlsym("geoip", "geoip_lookupcode");
+  target = l(cargv[0]);
 
   if(target == -1) {
     controlreply(np, "Invalid country.");
index f6a7850f88601ad8de9ac03de59f04405971bcc3..95fca8602674cd20adc423c3a32b5635b68306f6 100644 (file)
@@ -59,7 +59,7 @@ void reconnectfake(void *details);
 void _init() {
   if (!fakeuser_loaddb())
   {
-    Error("noperserv_fakeuser", ERR_ERROR, "Cannot load database");
+    Error("noperserv_fakeuser", ERR_FATAL, "Cannot load database");
     return;
   }
   registercontrolhelpcmd("fakeuser", NO_OPER, 4, &fakeadd, "Usage: FAKEUSER nick <ident> <host> <realname>\nCreates a fake user.");
@@ -92,11 +92,13 @@ void fakeuser_cleanup()
     free(killed);
   }
   fakeusercount = 0;
+  killedusercount = 0;
   fakeuserlist = NULL;
   killeduserlist = NULL;
 }
 
 int fakeuser_loaddb()
+// Called from _init
 {
   if (!pqconnected())
     return 0;
@@ -112,21 +114,21 @@ int fakeuser_loaddb()
 }
 
 void fakeusers_load(PGconn *dbconn, void *tag)
+// Called automatically when the async database query finishes
 {
   PGresult *pgres = PQgetResult(dbconn);
   user_details details;
   int i, rowcount;
 
   if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
-    Error("noperserv_fakeuser", ERR_ERROR, "Error loading fakeuser list (%d)", PQresultStatus(pgres));
+    Error("noperserv_fakeuser", ERR_FATAL, "Error loading fakeuser list (%d)", PQresultStatus(pgres));
     return;
   }
-  details.schedule = NULL;
   rowcount = PQntuples(pgres);
   Error("noperserv_fakeuser", ERR_INFO, "Loading %d users", rowcount);
 
   details.lastkill = 0;
-
+  details.schedule = NULL;
   for (i = 0; i < rowcount; i++)
   {
     strlcpy(details.nick, PQgetvalue(pgres, i, 0), NICKLEN + 1);
@@ -143,11 +145,11 @@ user_details *getdetails(nick *user)
   details = malloc(sizeof(user_details));
   if (!details)
     return NULL;
-  details->schedule = NULL;
   strlcpy(details->nick, user->nick, NICKLEN + 1);
   strlcpy(details->ident, user->ident, USERLEN + 1);
   strlcpy(details->host, user->host->name->content, HOSTLEN + 1);
   strlcpy(details->realname, user->realname->name->content, REALLEN + 1);
+  details->schedule = NULL;
   details->lastkill = 0;
   return details;
 }
@@ -160,7 +162,7 @@ int err_code;
 nick *register_fakeuser(user_details *details)
 {
   nick *user;
-  if((user = getnickbynick(details->nick)) && (IsOper(user) || IsService(user) || IsXOper(user))) {
+  if ((user = getnickbynick(details->nick)) && (IsOper(user) || IsService(user) || IsXOper(user))) {
     err_code = ERR_WONTKILL;
     return NULL;
   }
@@ -170,7 +172,8 @@ nick *register_fakeuser(user_details *details)
     NULL, UMODE_INV | UMODE_DEAF, &fakeuser_handler);
 }
 
-fakeuser *ll_add(user_details *details) //Adds to the (sorted) linked list
+fakeuser *ll_add(user_details *details) 
+// Adds to the (sorted) linked list
 {
   fakeuser *fake, *newfake;
   int cmp;
@@ -194,13 +197,11 @@ fakeuser *ll_add(user_details *details) //Adds to the (sorted) linked list
       err_code = ERR_MEM;
       return NULL;
     }
-
     newfake->user = register_fakeuser(details);
     if (!newfake->user)
     {
       free(newfake);
-      /* errcode already set by register_fakeuser */
-      return NULL;
+      return NULL;   //errcode already set by register_fakeuser
     }
     newfake->lastkill = details->lastkill;
     newfake->next = fakeuserlist;
@@ -228,8 +229,7 @@ fakeuser *ll_add(user_details *details) //Adds to the (sorted) linked list
       if (!newfake->user)
       {
         free(newfake);
-        /* errcode already set by register_fakeuser */
-        return NULL;
+        return NULL;   //errcode already set by register_fakeuser
       }
       newfake->lastkill = details->lastkill;
       newfake->next = fake->next;
@@ -248,8 +248,7 @@ fakeuser *ll_add(user_details *details) //Adds to the (sorted) linked list
   if (!newfake->user)
   {
     free(newfake);
-    /* errcode already set by register_fakeuser */
-    return NULL;
+    return NULL;   //errcode already set by register_fakeuser
   }
   newfake->lastkill = details->lastkill;
   newfake->next = NULL;
@@ -258,7 +257,8 @@ fakeuser *ll_add(user_details *details) //Adds to the (sorted) linked list
   return newfake;
 }
 
-void kll_add(user_details *details) //Adds to the (sorted) linked list of killed users
+void kll_add(user_details *details)
+//Adds to the (sorted) linked list of killed users
 {
   int cmp;
   user_details *killed;
@@ -291,7 +291,8 @@ void kll_add(user_details *details) //Adds to the (sorted) linked list of killed
   return;
 }
 
-fakeuser *ll_remove(char *nickname) //Removes from the linked list
+fakeuser *ll_remove(char *nickname)
+//Removes from the linked list
 {
   fakeuser *fake, *rmfake;
   int cmp;
@@ -371,18 +372,19 @@ void fakeuser_handler(nick *user, int command, void **params)
 
     details = getdetails(user);
     item = ll_remove(details->nick);
-    if(!item)
+    if (!item)
+    {
+      controlwall(NO_OPER, NL_FAKEUSERS, "Error: A fakeuser was killed, but wasn't found in the list");
+      Error("noperserv_fakeuser", ERR_ERROR, "A fakeuser was killed, but wasn't found in the list");
       return;
+    }
 
     details->lastkill = item->lastkill;
     free(item);
 
-    if(timenow - item->lastkill < KILL_TIME) {
+    if (timenow - details->lastkill < KILL_TIME) {
       char escnick[NICKLEN * 2 + 1];
       controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) KILL'ed twice under in %d seconds. Removing.", details->nick, details->ident, details->host, details->realname, KILL_TIME);
-      item = ll_remove(details->nick);
-      free(item);
-
       PQescapeString(escnick, details->nick, strlen(details->nick));
       pqquery("DELETE FROM noperserv.fakeusers WHERE nick = '%s'", escnick);
       return;
@@ -439,11 +441,17 @@ int fakeadd(void *sender, int cargc, char **cargv)
     if (err_code == ERR_EXISTS)
       controlreply(sender, "Error: fakeuser already exists");
     else if (err_code == ERR_MEM)
+    {
       controlreply(sender, "Error: memory error!!");
+      Error("noperserv_fakeuser", ERR_STOP, "malloc error");
+    }
     else if (err_code == ERR_WONTKILL)
       controlreply(sender, "Nick already exists and I won't kill it");
     else
+    {
       controlreply(sender, "Unknown error when adding fakeuser");
+      Error("noperserv_fakeuser", ERR_ERROR, "Unknown error when adding fakeuser");
+    }
     return CMD_ERROR;
   }
   newnick = newfake->user;
@@ -536,6 +544,7 @@ int fakekill(void *sender, int cargc, char **cargv)
 }
 
 void reconnectfake(void *details)
+//Called after the timeout period has expired since a fakeuser was killed, or on load
 {
   fakeuser *fake;
   user_details *u_details = details;
index 2be2f44c84ec5f821800e9441fc4a1aa3fd89752..6b5465b2095dac6b3f3247649ec7671db7c8563f 100644 (file)
@@ -1,15 +1,6 @@
 /*
-  Easy async socket library with HELIX encryption and authentication
-  Copyright (C) 2004-2005 Chris Porter.
-
-  v1.03
-    - changed nonce logic
-  v1.02
-    - added some \n stripping in crypto code
-  v1.01
-    - noticed small problem in _read, if ret == -1 && errno != EAGAIN then it would mess up
-    - now disconnects on write buffer filling up
-    - increased buffer size and maximum queue size
+  Easy async socket library
+  Copyright (C) 2004-2007 Chris Porter.
 */
 
 #include "esockets.h"
@@ -24,7 +15,6 @@
 #include <stdarg.h>
 #include <netinet/in.h>
 
-#include "../lib/sha1.h"
 #include "../core/events.h"
 
 struct esocket *socklist = NULL;
@@ -76,10 +66,13 @@ struct esocket *esocket_add(int fd, char socket_type, struct esocket_events *eve
   newsock->fd = fd;
   newsock->next = socklist;
 
-  newsock->in.on_parse = buffer_parse_ascii;
-  newsock->in.startpos = newsock->in.curpos = newsock->in.writepos = newsock->in.data;
-  newsock->in.buffer_size = MAX_ASCII_LINE_SIZE;
-  newsock->in.packet_length = 0;
+  newsock->in.mode = PARSE_ASCII;
+  newsock->in.data = NULL;
+  newsock->in.size = 0;
+  newsock->in.cryptobuf = NULL;
+  newsock->in.cryptobufsize = 0;
+  newsock->in.mac = 0;
+
   newsock->out.head = NULL;
   newsock->out.end = NULL;
   newsock->out.count = 0;
@@ -194,6 +187,11 @@ void esocket_disconnect(struct esocket *active) {
         pkt = npkt;
       }
 
+      if(p->in.data)
+        free(p->in.data);
+      if(p->in.cryptobuf)
+        free(p->in.cryptobuf);
+
       free(p);
       break;
     }  
@@ -207,37 +205,139 @@ void esocket_disconnect_when_complete(struct esocket *active) {
   }
 }
 
+int parse_ascii(struct esocket *sock, int *bytes_to_strip) {
+  struct esocket_in_buffer *buf = &sock->in;
+  char *p;
+  int i, ret;
+
+  for(p=buf->data,i=0;i<buf->size;i++,p++) {
+    if(*p == '\0' || *p == '\n') {
+      *p = '\0';
+
+      *bytes_to_strip = i + 1;
+      ret = sock->events.on_line(sock, buf->data);
+      if(ret)
+        return ret;
+
+      return 0;
+    }
+  }
+
+  *bytes_to_strip = 0;
+  return 0;
+}
+
+void seqno_update(hmacsha256 *h, u_int64_t value) {
+  u_int64_t v2 = htonq(value);
+  hmacsha256_update(h, (unsigned char *)&v2, 8);
+}
+
+int crypto_newblock(struct esocket *sock, unsigned char *block) {
+  unsigned char *p, *p2;
+  int i;
+  struct esocket_in_buffer *buf = &sock->in;
+
+  if(buf->mac) {
+    unsigned char digest[32];
+    int ret;
+    hmacsha256_final(&sock->clienthmac, digest);
+
+    if(memcmp(block, digest, 16)) /* mac error */
+      return 1;
+
+    hmacsha256_init(&sock->clienthmac, sock->clientkey, 32);
+    seqno_update(&sock->clienthmac, sock->clientseqno);
+    sock->clientseqno++;
+
+    ret = sock->events.on_line(sock, (char *)buf->cryptobuf);
+    free(buf->cryptobuf);
+    buf->cryptobuf = NULL;
+    buf->cryptobufsize = 0;
+    buf->mac = 0;
+
+    return ret;
+  }
+
+  hmacsha256_update(&sock->clienthmac, block, 16);
+  p = rijndaelcbc_decrypt(sock->clientcrypto, block);
+  for(p2=p,i=0;i<16;i++,p2++) { /* locate terminator */
+    if(*p2 == '\n' || *p2 == '\0') {
+      *p2 = '\0';
+      buf->mac = 1;
+    }
+  }
+
+  p2 = realloc(buf->cryptobuf, buf->cryptobufsize + 16);
+  if(!p2)
+    Error("nterface", ERR_STOP, "realloc() failed in crypto_newblock (esockets.c)");
+  buf->cryptobuf = p2;
+
+  memcpy(p2 + buf->cryptobufsize, p, 16);
+  buf->cryptobufsize+=16;
+
+  return 0;
+}
+
+int parse_crypt(struct esocket *sock, int *bytes_to_strip) {
+  struct esocket_in_buffer *buf = &sock->in;
+  int remaining = buf->size, ret;
+
+  *bytes_to_strip = 0;
+  if(remaining < 16)
+    return 0;
+
+  ret = crypto_newblock(sock, (unsigned char *)buf->data);
+  *bytes_to_strip = 16;
+
+  return ret;
+}
+
 int esocket_read(struct esocket *sock) {
   struct esocket_in_buffer *buf = &sock->in;
-  int ret, bytesread = read(sock->fd, buf->writepos, buf->buffer_size - (buf->writepos - buf->data));
+  char bufd[16384], *p;
+  int bytesread, ret, strip;
 
+  bytesread = read(sock->fd, bufd, sizeof(bufd));
   if(!bytesread || ((bytesread == -1) && (errno != EAGAIN)))
     return 1;
 
   if((bytesread == -1) && (errno == EAGAIN))
     return 0;
 
-  buf->writepos+=bytesread;
+  p = realloc(buf->data, buf->size + bytesread);
+  if(!p)
+    Error("nterface", ERR_STOP, "realloc() failed in esocket_read (esockets.c)");
+
+  buf->data = p;
+  memcpy(buf->data + buf->size, bufd, bytesread);
+  buf->size+=bytesread;
 
   do {
-    ret = buf->on_parse(sock);
-    if((ret != BUF_CONT) && ret)
-      return ret;
-  } while(ret);
+    if(buf->mode == PARSE_ASCII) {
+      ret = parse_ascii(sock, &strip);
+    } else {
+      ret = parse_crypt(sock, &strip);
+    }
 
-  if((buf->curpos == (buf->data + buf->buffer_size)) && (buf->startpos == buf->data))
-    return 1;
+    if(strip > 0) {
+      if(buf->size - strip == 0) {
+        free(buf->data);
+        buf->data = NULL;
+      } else {
+        memmove(buf->data, buf->data + strip, buf->size - strip);
+        p = realloc(buf->data, buf->size - strip);
+        if(!p)
+          Error("nterface", ERR_STOP, "realloc() failed in esocket_read (esockets.c)");
 
-  if(buf->startpos != buf->curpos) {
-    int moveback = buf->writepos - buf->startpos;
-    memmove(buf->data, buf->startpos, moveback);
-    buf->writepos = buf->data + moveback;
-  } else {
-    buf->writepos = buf->data;
-  }
+        buf->data = p;
+      }
 
-  buf->curpos = buf->writepos;
-  buf->startpos = buf->data;
+      buf->size-=strip;
+    }
+
+    if(ret)
+      return ret;
+  } while(strip && buf->data);
 
   return 0;
 }
@@ -365,32 +465,42 @@ int esocket_raw_write(struct esocket *sock, char *buffer, int bytes) {
   return 1;
 }
 
-unsigned char *increase_nonce(unsigned char *nonce) {
-  u_int64_t *inonce = (u_int64_t *)(nonce + 8);
-  *inonce = htonq(ntohq(*inonce) + 1);
-  return nonce;
-}
-
 int esocket_write(struct esocket *sock, char *buffer, int bytes) {
   int ret;
-  if(sock->in.on_parse == buffer_parse_ascii) {
+  if(sock->in.mode == PARSE_ASCII) {
     ret = esocket_raw_write(sock, buffer, bytes);
   } else {
-    unsigned char mac[MAC_LEN];
-    char newbuf[MAX_BUFSIZE + USED_MAC_LEN + sizeof(packet_t)];
-    packet_t packetlength;
-    if(bytes > MAX_BUFSIZE)
-      return 1;
-    packetlength = htons(bytes + USED_MAC_LEN);
-
-    memcpy(newbuf, &packetlength, sizeof(packet_t));
-    h_nonce(&sock->keysend, increase_nonce(sock->sendnonce));
-    h_encrypt(&sock->keysend, (unsigned char *)buffer, bytes, mac);
+    unsigned char newbuf[MAX_BUFSIZE + USED_MAC_LEN], *p = newbuf, hmacdigest[32];
+    hmacsha256 hmac;
+    int padding = 16 - bytes % 16, i;
+
+    if(padding == 16)
+      padding = 0;
+
+    memcpy(newbuf, buffer, bytes);
+    for(i=0;i<padding;i++)
+      newbuf[bytes + i] = i;
+    bytes+=padding;
+
+    hmacsha256_init(&hmac, sock->serverkey, 32);
+    seqno_update(&hmac, sock->serverseqno);
+    sock->serverseqno++;
+
+    i = bytes;
+    while(i) {
+      unsigned char *ct = rijndaelcbc_encrypt(sock->servercrypto, p);
+      hmacsha256_update(&hmac, ct, 16);
+      memcpy(p, ct, 16);
+
+      buffer+=16;
+      p+=16;
+      i-=16;
+    }
 
-    memcpy(newbuf + sizeof(packet_t), buffer, bytes);
-    memcpy(newbuf + sizeof(packet_t) + bytes, mac, USED_MAC_LEN);
+    hmacsha256_final(&hmac, hmacdigest);
+    memcpy(p, hmacdigest, USED_MAC_LEN);
 
-    ret = esocket_raw_write(sock, newbuf, bytes + sizeof(packet_t) + USED_MAC_LEN);
+    ret = esocket_raw_write(sock, (char *)newbuf, bytes + USED_MAC_LEN);
   }
 
   /* AWOOGA!! */
@@ -407,124 +517,32 @@ int esocket_write_line(struct esocket *sock, char *format, ...) {
 
   va_start(va, format);
   
-  if(sock->in.on_parse == buffer_parse_ascii) {
-    vsnprintf(nbuf, sizeof(nbuf) - 1, format, va); /* snprintf() and vsnprintf() will write at most size-1 of the characters, one for \n */
-  } else {
-    vsnprintf(nbuf, sizeof(nbuf), format, va);
-  }
+  vsnprintf(nbuf, sizeof(nbuf) - 1, format, va); /* snprintf() and vsnprintf() will write at most size-1 of the characters, one for \n */
   va_end(va);
 
   len = strlen(nbuf);
 
-  if(sock->in.on_parse == buffer_parse_ascii)
-    nbuf[len++] = '\n';
-
+  nbuf[len++] = '\n';
   nbuf[len] = '\0';
 
   return esocket_write(sock, nbuf, len);
 }
 
-int buffer_parse_ascii(struct esocket *sock) {
-  struct esocket_in_buffer *buf = &sock->in;
-
-  for(;buf->curpos<buf->writepos;buf->curpos++) {
-    if((*buf->curpos == '\n') || !*buf->curpos) {
-      int ret;
-      char *newline = buf->startpos;
-
-      *buf->curpos = '\0';
-
-      buf->startpos = buf->curpos + 1;
-
-      ret = sock->events.on_line(sock, newline);
-      if(ret)
-        return ret;
-
-      if(buf->curpos + 1 < buf->writepos) {
-        buf->curpos++;
-        return BUF_CONT;
-      }
-    }
-  }
-
-  return 0;
-}
-
-int buffer_parse_crypt(struct esocket *sock) {
-  struct esocket_in_buffer *buf = &sock->in;
-  unsigned char mac[MAC_LEN];
+void switch_buffer_mode(struct esocket *sock, unsigned char *serverkey, unsigned char *serveriv, unsigned char *clientkey, unsigned char *clientiv) {
+  memcpy(sock->serverkey, serverkey, 32);
+  memcpy(sock->clientkey, clientkey, 32);
 
-  if(!buf->packet_length) {
-    if(buf->writepos - buf->startpos > sizeof(packet_t)) {
-      memcpy(&buf->packet_length, buf->startpos, sizeof(packet_t));
-      buf->startpos = buf->startpos + sizeof(packet_t);
-      buf->curpos = buf->startpos;
+  sock->in.mode = PARSE_CRYPTO;
 
-      buf->packet_length = ntohs(buf->packet_length);
-      if((buf->packet_length > buf->buffer_size - sizeof(packet_t)) || (buf->packet_length <= 0))
-        return 1;
+  sock->clientseqno = 0;
+  sock->serverseqno = 0;
 
-    } else {
-      buf->curpos = buf->writepos;
-      return 0;
-    }
-  }
-  if(buf->packet_length <= buf->writepos - buf->startpos) {
-    int ret;
-    char *newline, *p;
-    h_nonce(&sock->keyreceive, increase_nonce(sock->recvnonce));
-    h_decrypt(&sock->keyreceive, (unsigned char *)buf->startpos, buf->packet_length - USED_MAC_LEN, mac);
-    
-    if(memcmp(mac, buf->startpos + buf->packet_length - USED_MAC_LEN, USED_MAC_LEN))
-      return 1;
-    
-    p = newline = buf->startpos;
-    newline[buf->packet_length - USED_MAC_LEN] = '\0';
-    
-    for(;*p;p++) /* shouldn't happen */
-      if(*p == '\n')
-        *p = '\0';
-
-    buf->startpos = buf->startpos + buf->packet_length;
-    buf->packet_length = 0;
-
-    ret = sock->events.on_line(sock, newline);
-    if(ret)
-      return ret;
-
-    return BUF_CONT;
-  }
-  
-  buf->curpos = buf->writepos;
-  return 0;
-}
-
-void switch_buffer_mode(struct esocket *sock, char *key, unsigned char *ournonce, unsigned char *theirnonce) {
-  unsigned char ukey[20];
-  SHA1_CTX context;
-
-  memcpy(sock->sendnonce, ournonce, sizeof(sock->sendnonce));
-  memcpy(sock->recvnonce, theirnonce, sizeof(sock->recvnonce));
-
-  SHA1Init(&context);
-  SHA1Update(&context, (unsigned char *)key, strlen(key));
-  SHA1Update(&context, (unsigned char *)" ", 1);
-  /* not sure if this is cryptographically secure! */
-  SHA1Update(&context, (unsigned char *)ournonce, NONCE_LEN);
-  SHA1Final(ukey, &context);
-
-  sock->in.on_parse = buffer_parse_crypt;
-  sock->in.buffer_size = MAX_BINARY_LINE_SIZE;
-  
-  h_key(&sock->keysend, ukey, sizeof(ukey));
+  sock->servercrypto = rijndaelcbc_init(serverkey, 256, serveriv, 0);
+  sock->clientcrypto = rijndaelcbc_init(clientkey, 256, clientiv, 1);
 
-  SHA1Init(&context);
-  SHA1Update(&context, (unsigned char *)key, strlen(key));
-  SHA1Update(&context, (unsigned char *)" ", 1);
-  SHA1Update(&context, (unsigned char *)theirnonce, NONCE_LEN);
-  SHA1Final(ukey, &context);
+  hmacsha256_init(&sock->clienthmac, sock->clientkey, 32);
+  seqno_update(&sock->clienthmac, sock->clientseqno);
 
-  h_key(&sock->keyreceive, ukey, sizeof(ukey));
+  sock->clientseqno++;
 }
 
index 071cf7a4b1239e09d7ace607fd0bc3718d0c9818..4be28148da0467caa2e15546b9682a23be74cbbf 100644 (file)
@@ -1,12 +1,14 @@
 /*
-  Easy async socket library with HELIX encryption and authentication
-  Copyright (C) 2004 Chris Porter.
+  Easy async socket library
+  Copyright (C) 2004-2007 Chris Porter.
 */
 
 #ifndef __esockets_H
 #define __esockets_H
 
-#include "../lib/helix.h"
+#include "../lib/rijndael.h"
+#include "../lib/sha2.h"
+#include "library.h"
 #include <sys/types.h>
 #include <ctype.h>
 
 #define BUF_CONT -1
 #define BUF_OVERFLOW -2
 #define BUF_ERROR -3
+#define BUF_RESET -4
+
+#define PARSE_ASCII 0
+#define PARSE_CRYPTO 1
 
 #define MAX_BUFSIZE 50000
 
-#define USED_MAC_LEN 3
+#define USED_MAC_LEN 16
 
 typedef unsigned short packet_t;
 
 #define MAX_BINARY_LINE_SIZE MAX_BUFSIZE
-#define MAX_ASCII_LINE_SIZE  MAX_BINARY_LINE_SIZE - sizeof(packet_t) - USED_MAC_LEN
+#define MAX_ASCII_LINE_SIZE  MAX_BINARY_LINE_SIZE - 10 - USED_MAC_LEN
 
 #define MAX_OUT_QUEUE_SIZE   5000
 
@@ -53,13 +59,12 @@ typedef int (*parse_event)(struct esocket *sock);
 typedef int (*line_event)(struct esocket *sock, char *newline);
 
 typedef struct esocket_in_buffer {
-  char data[MAX_BUFSIZE];
-  char *writepos;
-  char *curpos;
-  char *startpos;
-  unsigned short buffer_size;
-  parse_event on_parse;
-  packet_t packet_length;
+  char *data;
+  int size;
+  short mode;
+  unsigned char *cryptobuf;
+  int cryptobufsize;
+  short mac;
 } in_buffer;
 
 typedef struct esocket_packet {
@@ -94,10 +99,14 @@ typedef struct esocket {
   struct esocket *next;
   unsigned short token;
   void *tag;
-  helix_ctx keysend;
-  helix_ctx keyreceive;
-  unsigned char sendnonce[NONCE_LEN];
-  unsigned char recvnonce[NONCE_LEN];
+
+  unsigned char clientkey[32];
+  unsigned char serverkey[32];
+  u_int64_t clientseqno;
+  u_int64_t serverseqno;
+  hmacsha256 clienthmac;
+  rijndaelcbc *clientcrypto;
+  rijndaelcbc *servercrypto;
 } esocket;
 
 struct esocket *esocket_add(int fd, char socket_type, struct esocket_events *events, unsigned short token);
@@ -111,7 +120,7 @@ int esocket_write_line(struct esocket *sock, char *format, ...);
 unsigned short esocket_token(void);
 struct esocket *find_esocket_from_fd(int fd);
 void esocket_clean_by_token(unsigned short token);
-void switch_buffer_mode(struct esocket *sock, char *key, unsigned char *ournonce, unsigned char *theirnonce);
+void switch_buffer_mode(struct esocket *sock, unsigned char *serverkey, unsigned char *serveriv, unsigned char *clientkey, unsigned char *clientiv);
 void esocket_disconnect_when_complete(struct esocket *active);
 int esocket_raw_write(struct esocket *sock, char *buffer, int bytes);
 
index e5580b62927867b5fc6082a5e9eda03aa45ef178..504935ba824b7cc12b9253670d29e103401e7378 100644 (file)
@@ -13,8 +13,8 @@
 
 #include "../core/config.h"
 #include "../lib/irc_string.h"
-#include "../lib/sha1.h"
-#include "../lib/helix.h"
+#include "../lib/sha2.h"
+#include "../lib/rijndael.h"
 
 #include "library.h"
 
@@ -47,10 +47,7 @@ unsigned char hexlookup[256] = {
                        0xff, 0xff, 0xff, 0xff, 0xff, 0xff
                                   };
 
-FILE *challenge_random_fd = NULL;
-
-unsigned char entropybuffer[CHALLENGE_ENTROPYLEN * CHALLENGE_ENTROPYBUF];
-int entropy_remaining = 0;
+FILE *random_fd = NULL;
 
 int getcopyconfigitemint(char *section, char *key, int def, int *value) {
   char buf[50];
@@ -91,51 +88,52 @@ int positive_atoi(char *data) {
 }
 
 char *challenge_response(char *challenge, char *password) {
-  unsigned char buf[20];
+  unsigned char buf[32];
   static char output[sizeof(buf) * 2 + 1];
-  SHA1_CTX context;
+  SHA256_CTX context;
+
+  SHA256_Init(&context);
+  SHA256_Update(&context, (unsigned char *)challenge, strlen(challenge));
+  SHA256_Update(&context, (unsigned char *)":", 1);
+  SHA256_Update(&context, (unsigned char *)password, strlen(password));
+  SHA256_Final(buf, &context);
 
-  SHA1Init(&context);
-  SHA1Update(&context, (unsigned char *)password, strlen(password));
-  SHA1Update(&context, (unsigned char *)" ", 1);
-  SHA1Update(&context, (unsigned char *)challenge, strlen(challenge));
-  SHA1Final(buf, &context);
+  SHA256_Init(&context);
+  SHA256_Update(&context, (unsigned char *)buf, 32);
+  SHA256_Final(buf, &context);
 
-  TwentyByteHex(output, buf);
+  ThirtyTwoByteHex(output, buf);
 
   return output;
 }
 
-/* my entropy function from Q */
-int get_challenge_entropy(unsigned char *data) {
-  if (!challenge_random_fd) {
-    challenge_random_fd = fopen(CHALLENGE_RANDOM_LOCATION, "rb");
-    if(!challenge_random_fd)
-      return 0;
-  }
-  
-  if(!entropy_remaining) {
-    if(fread(entropybuffer, 1, sizeof(entropybuffer), challenge_random_fd) != sizeof(entropybuffer))
+int get_entropy(unsigned char *buf, int bytes) {
+  if (!random_fd) {
+    random_fd = fopen(RANDOM_LOCATION, "rb");
+    if(!random_fd)
       return 0;
-    entropy_remaining = CHALLENGE_ENTROPYBUF;
   }
   
-  memcpy(data, entropybuffer + (CHALLENGE_ENTROPYBUF - entropy_remaining) * CHALLENGE_ENTROPYLEN, CHALLENGE_ENTROPYLEN);
-  entropy_remaining--;
+  fread(buf, 1, bytes, random_fd);
   
   return 1;
 }
 
 int generate_nonce(unsigned char *nonce, int nterfacer) {
-  unsigned char entropy[CHALLENGE_ENTROPYLEN];
+  unsigned char entropy[20], output[32];
   struct timeval tvv;
-  if(!get_challenge_entropy(entropy))
+  SHA256_CTX c;
+
+  if(!get_entropy(entropy, 20))
     return 0;
 
   gettimeofday(&tvv, NULL);
 
-  memcpy(nonce, &tvv, sizeof(struct timeval));
-  memcpy(nonce + sizeof(struct timeval) - 2, entropy, NONCE_LEN - sizeof(struct timeval) + 2);
+  SHA256_Init(&c);
+  SHA256_Update(&c, entropy, 20);
+  SHA256_Update(&c, (unsigned char *)&tvv, sizeof(struct timeval));
+  SHA256_Final(output, &c);
+  memcpy(nonce, output, 16);
 
   if(nterfacer) {
     nonce[7]&=128;
@@ -146,17 +144,6 @@ int generate_nonce(unsigned char *nonce, int nterfacer) {
   return 1;
 }
 
-char *get_random_hex(void) {
-  static char output[CHALLENGE_ENTROPYLEN * 2 + 1];
-  unsigned char stored[CHALLENGE_ENTROPYLEN];
-  if(get_challenge_entropy(stored)) {
-    TwentyByteHex(output, stored);
-  } else {
-    return NULL;
-  }
-  return output;
-}
-
 char *int_to_hex(unsigned char *input, char *buf, int len) {
   int i;
   for(i=0;i<len;i++)
@@ -216,3 +203,87 @@ char *request_error(int errn) {
 
   return err;
 }
+
+rijndaelcbc *rijndaelcbc_init(unsigned char *key, int keybits, unsigned char *iv, int decrypt) {
+  rijndaelcbc *ret = (rijndaelcbc *)malloc(sizeof(rijndaelcbc) + RKLENGTH(keybits) * sizeof(unsigned long));
+  if(!ret)
+    return NULL;
+
+  ret->rk = (unsigned long *)(ret + 1);
+
+  memcpy(ret->prevblock, iv, 16);
+
+  if(decrypt) {
+    ret->nrounds = rijndaelSetupDecrypt(ret->rk, key, keybits);
+  } else {
+    ret->nrounds = rijndaelSetupEncrypt(ret->rk, key, keybits);
+  }
+  return ret;
+}
+
+void rijndaelcbc_free(rijndaelcbc *c) {
+  free(c);
+}
+
+unsigned char *rijndaelcbc_encrypt(rijndaelcbc *c, unsigned char *ptblock) {
+  int i;
+  unsigned char *p = c->prevblock, *p2 = c->scratch;
+  for(i=0;i<16;i++)
+    *p2++ = *p++ ^ *ptblock++;
+
+  rijndaelEncrypt(c->rk, c->nrounds, c->scratch, c->prevblock);
+  return c->prevblock;
+}
+
+unsigned char *rijndaelcbc_decrypt(rijndaelcbc *c, unsigned char *ctblock) {
+  int i;
+  unsigned char *p = c->prevblock, *p2 = c->scratch;
+
+  rijndaelDecrypt(c->rk, c->nrounds, ctblock, c->scratch);
+
+  for(i=0;i<16;i++)
+    *p2++^=*p++;
+
+  memcpy(c->prevblock, ctblock, 16);
+  return c->scratch;
+}
+
+void hmacsha256_init(hmacsha256 *c, unsigned char *key, int keylen) {
+  unsigned char realkey[64], outerkey[64], innerkey[64];
+  SHA256_CTX keyc;
+  int i;
+
+  memset(realkey, 0, sizeof(realkey));
+  if(keylen > 64) {
+    SHA256_Init(&keyc);
+    SHA256_Update(&keyc, key, keylen);
+    SHA256_Final(realkey, &keyc);
+    keylen = 32;
+  } else {
+    memcpy(realkey, key, keylen);
+  }
+
+  /* abusing the cache here, if we do sha256 in between that'll erase it */
+  for(i=0;i<64;i++) {
+    int r = realkey[i];
+    innerkey[i] = r ^ 0x36;
+    outerkey[i] = r ^ 0x5c;
+  }
+
+  SHA256_Init(&c->outer);
+  SHA256_Init(&c->inner);
+  SHA256_Update(&c->outer, outerkey, 64);
+  SHA256_Update(&c->inner, innerkey, 64);
+}
+
+void hmacsha256_update(hmacsha256 *c, unsigned char *message, int messagelen) {
+  SHA256_Update(&c->inner, message, messagelen);
+}
+
+/* digest must be 32 bytes */
+void hmacsha256_final(hmacsha256 *c, unsigned char *digest) {
+  SHA256_Final(digest, &c->inner);
+  SHA256_Update(&c->outer, digest, 32);
+  SHA256_Final(digest, &c->outer);
+}
+
index 6edba000df9127e3771ba98a407ba5f207e9247d..517f85bfb35173f6b97785596b6c3e1b183dda4a 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "../core/error.h"
 
+#include "../lib/sha2.h"
+
 #define RE_OK                  0x00
 #define RE_MEM_ERROR           0x01
 #define RE_BAD_LINE            0x02
 
 #define snc(err, f) strncpy(err, f, sizeof(err) - 1)
 #define TwentyByteHex(output, buf) snprintf(output, sizeof(output), "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", buf[0], buf[1],  buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]);
+#define SixteenByteHex(output, buf) snprintf(output, sizeof(output), "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", buf[0], buf[1],  buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
+#define ThirtyTwoByteHex(output, buf) snprintf(output, sizeof(output), "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", buf[0], buf[1],  buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23], buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]);
 
 #define MemError() Error("nterface", ERR_FATAL, "Memory allocation error, file: %s line: %d", __FILE__, __LINE__);
 
-#define CHALLENGE_ENTROPYLEN 20
-#define CHALLENGE_ENTROPYBUF 10
-#define CHALLENGE_RANDOM_LOCATION "/dev/urandom"
+#define RANDOM_LOCATION "/dev/urandom"
 
 #define MemCheck(x) \
   if(!x) { \
@@ -47,11 +49,29 @@ int getcopyconfigitemintpositive(char *section, char *key, int def);
 int protected_atoi(char *buf, int *value);
 int positive_atoi(char *data);
 char *challenge_response(char *challenge, char *password);
-char *get_random_hex(void);
 char *request_error(int errn);
-int get_challenge_entropy(unsigned char *data);
+int get_entropy(unsigned char *data, int bytes);
 int generate_nonce(unsigned char *nonce, int nterfacer);
 char *int_to_hex(unsigned char *input, char *buf, int len);
 int hex_to_int(char *input, unsigned char *buf, int buflen);
 
+typedef struct {
+  unsigned char prevblock[16];
+  unsigned char scratch[16];
+  int nrounds;
+  unsigned long *rk;
+} rijndaelcbc;
+
+typedef struct {
+  SHA256_CTX outer, inner;
+} hmacsha256;
+
+void hmacsha256_final(hmacsha256 *c, unsigned char *digest);
+void hmacsha256_update(hmacsha256 *c, unsigned char *message, int messagelen);
+void hmacsha256_init(hmacsha256 *c, unsigned char *key, int keylen);
+unsigned char *rijndaelcbc_decrypt(rijndaelcbc *c, unsigned char *ctblock);
+unsigned char *rijndaelcbc_encrypt(rijndaelcbc *c, unsigned char *ptblock);
+void rijndaelcbc_free(rijndaelcbc *c);
+rijndaelcbc *rijndaelcbc_init(unsigned char *key, int keybits, unsigned char *iv, int decrypt);
+
 #endif
index abcbd0fe3180945cb526a1408a3766cabd2bcc06..174970785932a73c161dbf5ba95bbc8268ab8c6e 100644 (file)
@@ -1,24 +1,6 @@
 /*
   nterfacer
-  Copyright (C) 2004-2006 Chris Porter.
-  
-  v1.07a
-    - dumb config bug
-  v1.07
-    - made sure buf[0] = '\0'
-  v1.06
-    - tidy up
-  v1.05
-    - added application level ping support
-  v1.04
-    - modified for new logging system
-  v1.03
-    - newserv seems to unload this module before the ones that depend on us,
-      so deregister_service now checks to see if it's been freed already
-  v1.02
-    - moronic bug in linked lists fixed
-  v1.01
-    - logging
+  Copyright (C) 2004-2007 Chris Porter.
 */
 
 #include <stdio.h>
@@ -43,7 +25,7 @@
 #include "nterfacer.h"
 #include "logging.h"
 
-MODULE_VERSION("");
+MODULE_VERSION("1.1");
 
 struct service_node *tree = NULL;
 struct esocket_events nterfacer_events;
@@ -53,6 +35,9 @@ unsigned short nterfacer_token = BLANK_TOKEN;
 struct nterface_auto_log *nrl;
 
 struct service_node *ping = NULL;
+int accept_fd = -1;
+struct permitted *permits;
+int permit_count = 0;
 
 int ping_handler(struct rline *ri, int argc, char **argv);
 
@@ -146,32 +131,35 @@ void _fini(void) {
 }
 
 int load_permits(void) {
-  int lines, loaded_lines = 0, i, j;
+  int loaded_lines = 0, i, j;
   struct permitted *new_permits, *resized, *item;
   struct hostent *host;
-  char buf[50];
+  array *hostnamesa, *passwordsa;
+  sstring **hostnames, **passwords;
 
-  lines = getcopyconfigitemintpositive("nterfacer", "permits", 0);
-  if(lines < 1) {
-    nterface_log(nrl, NL_ERROR, "No permits found in config file.");
+  hostnamesa = getconfigitems("nterfacer", "hostname");
+  passwordsa = getconfigitems("nterfacer", "password");
+  if(!hostnamesa || !passwordsa) {
+    nterface_log(nrl, NL_ERROR, "Unable to load hostnames/passwords.");
+    return 0;
+  }
+  if(hostnamesa->cursi != passwordsa->cursi) {
+    nterface_log(nrl, NL_ERROR, "Different number of hostnames/passwords in config file.");
     return 0;
   }
-  nterface_log(nrl, NL_INFO, "Loading %d permit%s from config file", lines, lines==1?"":"s");
 
-  new_permits = calloc(lines, sizeof(struct permitted));
+  hostnames = (sstring **)hostnamesa->content;
+  passwords = (sstring **)passwordsa->content;
+
+  new_permits = calloc(hostnamesa->cursi, sizeof(struct permitted));
   item = new_permits;
 
-  for(i=1;i<=lines;i++) {
-    snprintf(buf, sizeof(buf), "hostname%d", i);
-    item->hostname = getcopyconfigitem("nterfacer", buf, "", 100);
-    if(!item->hostname) {
-      nterface_log(nrl, NL_ERROR, "No hostname found for item %d.", i);
-      continue;
-    }
+  for(i=0;i<hostnamesa->cursi;i++) {
+    item->hostname = getsstring(hostnames[i]->content, hostnames[i]->length);
 
     host = gethostbyname(item->hostname->content);
     if (!host) {
-      nterface_log(nrl, NL_WARNING, "Couldn't resolve hostname: %s (item %d).", item->hostname->content, i);
+      nterface_log(nrl, NL_WARNING, "Couldn't resolve hostname: %s (item %d).", item->hostname->content, i + 1);
       freesstring(item->hostname);
       continue;
     }
@@ -179,7 +167,7 @@ int load_permits(void) {
     item->ihost = (*(struct in_addr *)host->h_addr).s_addr;
     for(j=0;j<loaded_lines;j++) {
       if(new_permits[j].ihost == item->ihost) {
-        nterface_log(nrl, NL_WARNING, "Host with items %d and %d is identical, dropping item %d.", j + 1, i, i);
+        nterface_log(nrl, NL_WARNING, "Host with items %d and %d is identical, dropping item %d.", j + 1, i + 1, i + 1);
         host = NULL;
       }
     }
@@ -189,14 +177,7 @@ int load_permits(void) {
       continue;
     }
 
-    snprintf(buf, sizeof(buf), "password%d", i);
-    item->password = getcopyconfigitem("nterfacer", buf, "", 100);
-    if(!item->password) {
-      nterface_log(nrl, NL_ERROR, "No password found for item %d.", item->hostname->content, i);
-      freesstring(item->hostname);
-      continue;
-    }
-
+    item->password = getsstring(passwords[i]->content, passwords[i]->length);
     nterface_log(nrl, NL_DEBUG, "Loaded permit, hostname: %s.", item->hostname->content);
 
     item++;
@@ -411,10 +392,27 @@ void nterfacer_accept_event(struct esocket *socket) {
   esocket_write_line(newsocket, "nterfacer " PROTOCOL_VERSION);
 }
 
+void derive_key(unsigned char *out, char *password, char *segment, unsigned char *noncea, unsigned char *nonceb) {
+  SHA256_CTX c;
+  SHA256_Init(&c);
+  SHA256_Update(&c, (unsigned char *)password, strlen(password));
+  SHA256_Update(&c, (unsigned char *)":", 1);
+  SHA256_Update(&c, (unsigned char *)segment, strlen(segment));
+  SHA256_Update(&c, (unsigned char *)":", 1);
+  SHA256_Update(&c, noncea, 16);
+  SHA256_Update(&c, (unsigned char *)":", 1);
+  SHA256_Update(&c, nonceb, 16);
+  SHA256_Final(out, &c);
+
+  SHA256_Init(&c);
+  SHA256_Update(&c, out, 32);
+  SHA256_Final(out, &c);
+}
+
 int nterfacer_line_event(struct esocket *sock, char *newline) {
   struct sconnect *socket = sock->tag;
-  char *response, *theirnonceh = NULL;
-  unsigned char theirnonce[NONCE_LEN];
+  char *response, *theirnonceh = NULL, *theirivh = NULL;
+  unsigned char theirnonce[16], theiriv[16];
   int number, reason;
 
   switch(socket->status) {
@@ -423,15 +421,18 @@ int nterfacer_line_event(struct esocket *sock, char *newline) {
         nterface_log(nrl, NL_INFO, "Protocol mismatch from %s: %s", socket->permit->hostname->content, newline);
         return 1;
       } else {
-        char *hex, hexbuf[NONCE_LEN * 2 + 1]; /* Vekoma mAD HoUSe */
+        unsigned char challenge[32];
+        char ivhex[16 * 2 + 1], noncehex[16 * 2 + 1];
 
-        hex = get_random_hex();
-        if(!hex) {
-          nterface_log(nrl, NL_ERROR, "Unable to open challenge entropy bin!");
+        if(!get_entropy(challenge, 32) || !get_entropy(socket->iv, 16)) {
+          nterface_log(nrl, NL_ERROR, "Unable to open challenge/IV entropy bin!");
           return 1;
         }
 
-        memcpy(socket->response, challenge_response(hex, socket->permit->password->content), sizeof(socket->response));
+        int_to_hex(challenge, socket->challenge, 32);
+        int_to_hex(socket->iv, ivhex, 16);
+
+        memcpy(socket->response, challenge_response(socket->challenge, socket->permit->password->content), sizeof(socket->response));
         socket->response[sizeof(socket->response) - 1] = '\0'; /* just in case */
 
         socket->status = SS_VERSIONED;
@@ -439,8 +440,9 @@ int nterfacer_line_event(struct esocket *sock, char *newline) {
           nterface_log(nrl, NL_ERROR, "Unable to generate nonce!");
           return 1;
         }
+        int_to_hex(socket->ournonce, noncehex, 16);
 
-        if(esocket_write_line(sock, "%s %s", hex, int_to_hex(socket->ournonce, hexbuf, NONCE_LEN)))
+        if(esocket_write_line(sock, "%s %s %s", socket->challenge, ivhex, noncehex))
            return BUF_ERROR;
         return 0;
       }
@@ -449,12 +451,23 @@ int nterfacer_line_event(struct esocket *sock, char *newline) {
       for(response=newline;*response;response++) {
         if((*response == ' ') && (*(response + 1))) {
           *response = '\0';
-          theirnonceh = response + 1;
+          theirivh = response + 1;
           break;
         }
       }
 
-      if(!theirnonceh || (strlen(theirnonceh) != 32) || !hex_to_int(theirnonceh, theirnonce, sizeof(theirnonce))) {
+      if(theirivh) {
+        for(response=theirivh;*response;response++) {
+          if((*response == ' ') && (*(response + 1))) {
+            *response = '\0';
+            theirnonceh = response + 1;
+            break;
+          }
+        }
+      }
+
+      if(!theirivh || (strlen(theirivh) != 32) || !hex_to_int(theirivh, theiriv, sizeof(theiriv)) ||
+         !theirnonceh || (strlen(theirnonceh) != 32) || !hex_to_int(theirnonceh, theirnonce, sizeof(theirnonce))) {
         nterface_log(nrl, NL_INFO, "Protocol error drop: %s", socket->permit->hostname->content);
         return 1;
       }
@@ -471,7 +484,11 @@ int nterfacer_line_event(struct esocket *sock, char *newline) {
         socket->status = SS_AUTHENTICATED;
         ret = esocket_write_line(sock, "Oauth");
         if(!ret) {
-          switch_buffer_mode(sock, socket->permit->password->content, socket->ournonce, theirnonce);
+          unsigned char theirkey[32], ourkey[32];
+          derive_key(ourkey, socket->permit->password->content, socket->challenge, socket->ournonce, theirnonce);
+          derive_key(theirkey, socket->permit->password->content, socket->response, theirnonce, socket->ournonce);
+
+          switch_buffer_mode(sock, ourkey, socket->iv, theirkey, theiriv);
         } else {
           return BUF_ERROR;
         }
index 8b8798897b44a7dd4d3b1de20b9a0fe1b9339767..9c913bb431e2f2d07985d7e0cf2148e4e9a631b7 100644 (file)
@@ -23,7 +23,7 @@
 
 #define MAX_ARGS 100
 
-#define PROTOCOL_VERSION "2"
+#define PROTOCOL_VERSION "3"
 #define ANTI_FULL_VERSION "service_link " PROTOCOL_VERSION
 
 struct rline;
@@ -63,17 +63,14 @@ typedef struct permitted {
 
 typedef struct sconnect {
   int status;
-  char response[20 * 2 + 1]; /* could store this in binary form but I really can't be assed */
+  char response[32 * 2 + 1], challenge[32 * 2 + 1];
+  unsigned char iv[16];
   struct permitted *permit;
-  unsigned char ournonce[NONCE_LEN];
+  unsigned char ournonce[16];
 } sconnect;
 
 extern struct nterface_auto_log *nrl;
   
-int accept_fd = -1;
-struct permitted *permits;
-int permit_count = 0;
-
 struct service_node *register_service(char *name);
 struct handler *register_handler(struct service_node *service, char *command, int args, handler_function fp);
 void deregister_service(struct service_node *service);
index d630d463476464603eec7cd051732e08ee0ac7ec..eec1c0cb2bc9fd1807da150d5ff5b9b7a83039b1 100644 (file)
@@ -13,7 +13,7 @@
 MODULE_VERSION("");
 
 int handle_chanstats(struct rline *li, int argc, char **argv);
-struct handler *hl = NULL;
+static struct handler *hl = NULL;
 
 void _init(void) {
   if(!n_node) {
index fffe11cca8132312aa635e6fc428fcf8f5221154..654dc41c69c4f940abeca04450be5162ed9f2320 100644 (file)
@@ -33,6 +33,7 @@ int handle_servicesonchan(struct rline *li, int argc, char **argv);
 int handle_counthost(struct rline *li, int argc, char **argv);
 
 struct rline *grli; /* used inline for status */
+struct service_node *n_node;
 
 void _init(void) {
   n_node = register_service("N");
@@ -40,7 +41,7 @@ void _init(void) {
     return;
 
   register_handler(n_node, "ison", 1, handle_ison);
-  register_handler(n_node, "isaccounton", 1, handle_isaccounton);
+/*  register_handler(n_node, "isaccounton", 1, handle_isaccounton); */
   register_handler(n_node, "whois", 1, handle_whois);
   register_handler(n_node, "msg", 2, handle_message);
   register_handler(n_node, "notice", 2, handle_notice);
@@ -64,7 +65,7 @@ int handle_ison(struct rline *li, int argc, char **argv) {
 
   return ri_final(li);
 }
-
+/*
 int handle_isaccounton(struct rline *li, int argc, char **argv) {
   int i;
   for(i=0;i<argc;i++)
@@ -73,7 +74,7 @@ int handle_isaccounton(struct rline *li, int argc, char **argv) {
 
   return ri_final(li);
 }
-
+*/
 int handle_whois(struct rline *li, int argc, char **argv) {
   nick *np = getnickbynick(argv[0]);
   channel **channels;
index d2013af9ae19be7b2e1a7fc24116559b53dec3ea..68440cfc7ac9d2e68c1935793022528ed77d86c1 100644 (file)
@@ -12,7 +12,7 @@
 #define ERR_CHANSTATS_STATS_NOT_FOUND   0x02
 #define ERR_TOO_MANY_ARGS               0x03
 
-struct service_node *n_node;
+extern struct service_node *n_node;
 
 #endif
 
index 9e1d92a44f3a04929f00d99d8a4cd673736be5e0..5717d2372a2120f34a3164d78499f054a0cdc4d5 100644 (file)
@@ -15,7 +15,7 @@ MODULE_VERSION("");
 
 int country_nickext = -1;
 
-struct handler *hl = NULL, *hl2 = NULL;
+static struct handler *hl = NULL, *hl2 = NULL;
 
 int handle_countrytotals(struct rline *li, int argc, char **argv);
 int handle_countrywhois(struct rline *li, int argc, char **argv);
index 838812754becec2cc36d572d9be5c38533b4fe2c..687cdee9159c12589563668e0755cfb1fd4e1c46 100644 (file)
@@ -11,6 +11,7 @@
 #include "../core/hooks.h"
 #include "../lib/irc_string.h"
 #include "../lib/version.h"
+#include "../lib/strlfunc.h"
 #include "pqsql.h"
 
 #include <stdlib.h>
@@ -74,7 +75,7 @@ void connectdb(void) {
     return;
 
   /* stolen from chanserv as I'm lazy */
-  dbhost = getcopyconfigitem("pqsql", "host", "localhost", HOSTLEN);
+  dbhost = getcopyconfigitem("pqsql", "host", "UNIX", HOSTLEN);
   dbusername = getcopyconfigitem("pqsql", "username", "newserv", 20);
   dbpassword = getcopyconfigitem("pqsql", "password", "moo", 20);
   dbdatabase = getcopyconfigitem("pqsql", "database", "newserv", 20);
@@ -89,9 +90,13 @@ void connectdb(void) {
     freesstring(dbport);
     return;
   }
-
-  snprintf(connectstr, sizeof(connectstr), "dbname=%s user=%s password=%s", dbdatabase->content, dbusername->content, dbpassword->content);
   
+  if (!strcmp(dbhost->content,"UNIX")) {
+    snprintf(connectstr, sizeof(connectstr), "dbname=%s user=%s password=%s", dbdatabase->content, dbusername->content, dbpassword->content);
+  } else {
+    snprintf(connectstr, sizeof(connectstr), "host=%s port=%s dbname=%s user=%s password=%s", dbhost->content, dbport->content, dbdatabase->content, dbusername->content, dbpassword->content);
+  }  
+
   freesstring(dbhost);
   freesstring(dbusername);
   freesstring(dbpassword);
@@ -104,7 +109,7 @@ void connectdb(void) {
   dbconn = PQconnectdb(connectstr);
   
   if (!dbconn || (PQstatus(dbconn) != CONNECTION_OK)) {
-    Error("pqsql", ERR_ERROR, "Unable to connect to db.");
+    Error("pqsql", ERR_ERROR, "Unable to connect to db: %s", pqlasterror(dbconn));
     return;
   }
   Error("pqsql", ERR_INFO, "Connected!");
@@ -320,3 +325,17 @@ void dbstatus(int hooknum, void *arg) {
 int pqconnected(void) {
   return dbconnected;
 }
+
+char* pqlasterror(PGconn * pgconn) {
+  static char errormsg[PQ_ERRORMSG_LENGTH + 1];
+  int i;
+  if(!pgconn) 
+    return "PGCONN NULL";
+  strlcpy(errormsg, PQerrorMessage(pgconn), PQ_ERRORMSG_LENGTH);
+  for(i=0;i<errormsg[i];i++) {
+    if((errormsg[i] == '\r') || (errormsg[i] == '\n'))
+      errormsg[i] = ' ';
+    
+  }
+  return errormsg;
+}
index ec988bcc2cff88f43c0614213f753b4ad43255f3..8eb2608f6eb042c925178e92e3e1ac1510a880d6 100644 (file)
@@ -4,6 +4,7 @@
 #include <libpq-fe.h>
 
 #define QH_CREATE 0x01
+#define PQ_ERRORMSG_LENGTH 1024
 
 typedef void (*PQQueryHandler)(PGconn *, void *);
 
@@ -15,5 +16,6 @@ void pqloadtable(char *tablename, PQQueryHandler init, PQQueryHandler data, PQQu
 #define pqquery(format, ...) pqasyncqueryf(NULL, NULL, 0, format , ##__VA_ARGS__)
 
 int pqconnected(void);
+char* pqlasterror(PGconn * pgconn);
 
 #endif
index bce9d75eaa26ea8f3a9aa5f98f31b1c44a9feb24..c2f9997cc43a47128a6599625ef97d2ecebe4a7a 100644 (file)
@@ -3,4 +3,4 @@
 all: proxyscan.so  
 
 proxyscan.so: proxyscan.o proxyscanalloc.o proxyscanconnect.o proxyscancache.o proxyscanqueue.o proxyscanhandlers.o proxyscandb.o
-       ld -shared -Bdynamic ${LIBMYSQL} -o $@ $^
+       ld -shared -Bdynamic ${LIBPGSQL} -o $@ $^
index 5f8a63f3568193984c00659db84e68c00538f904..e9954e5458eac6a9ae787e40e4c17d3cc3b6bfa0 100644 (file)
 #include <string.h>
 #include "../irc/irc.h"
 #include "../lib/irc_string.h"
+#include "../lib/version.h"
+#include "../channel/channel.h"
+#include "../localuser/localuserchannel.h"
+#include "../core/nsmalloc.h"
+
+MODULE_VERSION("")
 
 #define SCANTIMEOUT      60
 
@@ -207,6 +213,7 @@ void _init(void) {
   proxyscan_addscantype(STYPE_HTTP, 808);
   proxyscan_addscantype(STYPE_HTTP, 3332);
   proxyscan_addscantype(STYPE_HTTP, 2282);
+  proxyscan_addscantype(STYPE_SOCKS4, 559);
   proxyscan_addscantype(STYPE_SOCKS4, 1080);
   proxyscan_addscantype(STYPE_SOCKS5, 1080);
   proxyscan_addscantype(STYPE_SOCKS4, 1075);
@@ -215,6 +222,8 @@ void _init(void) {
   proxyscan_addscantype(STYPE_SOCKS5, 2280);
   proxyscan_addscantype(STYPE_SOCKS4, 1180);
   proxyscan_addscantype(STYPE_SOCKS5, 1180);
+  proxyscan_addscantype(STYPE_SOCKS4, 9999);
+  proxyscan_addscantype(STYPE_SOCKS5, 9999);
   proxyscan_addscantype(STYPE_WINGATE, 23);
   proxyscan_addscantype(STYPE_CISCO, 23);
   proxyscan_addscantype(STYPE_WINGATE, 1181);
@@ -225,7 +234,6 @@ void _init(void) {
   proxyscan_addscantype(STYPE_HTTP, 65506);
   proxyscan_addscantype(STYPE_HTTP, 63809);
   proxyscan_addscantype(STYPE_HTTP, 63000);
-  proxyscan_addscantype(STYPE_SOCKS4, 559);
   proxyscan_addscantype(STYPE_SOCKS4, 29992);
   
   /* Schedule saves */
@@ -237,6 +245,7 @@ void _init(void) {
 void registerproxyscannick(void *arg) {
   sstring *psnick,*psuser,*pshost,*psrealname;
   /* Set up our nick on the network */
+  channel *cp;
 
   psnick=getcopyconfigitem("proxyscan","nick","P",NICKLEN);
   psuser=getcopyconfigitem("proxyscan","user","proxyscan",USERLEN);
@@ -252,6 +261,14 @@ void registerproxyscannick(void *arg) {
   freesstring(psuser);
   freesstring(pshost);
   freesstring(psrealname);
+
+  cp=findchannel("#twilightzone");
+  if (!cp) {
+    localcreatechannel(proxyscannick,"#twilightzone");
+  } else {
+    localjoinchannel(proxyscannick,cp);
+    localgetops(proxyscannick,cp);
+  }
 }
 
 void _fini(void) {
@@ -271,7 +288,7 @@ void _fini(void) {
   dumpcachehosts(NULL);
 
   /* free() all our structures */
-  sfreeall();
+  nsfreeall(POOL_PROXYSCAN);
   
   freesstring(ps_mailname);
 #if defined(PROXYSCAN_MAIL)
index dee282a71cfb92ee652509c03a65a996797bd44d..c658c01554c9e09122a34e80f5a8400975c3ea72 100644 (file)
@@ -1,6 +1,7 @@
 /* proxyscanalloc.c */
 
 #include "proxyscan.h"
+#include "../core/nsmalloc.h"
 
 #include <stdlib.h>
 
@@ -11,43 +12,13 @@ cachehost *freecachehosts;
 pendingscan *freependingscans;
 foundproxy *freefoundproxies;
 
-void *mallocs=NULL;
-
-void *smalloc(size_t size) {
-  void **mem;
-
-  /* Get the memory we want, with an extra four bytes for our pointer */
-  mem=(void **)malloc(size+sizeof(void *));
-
-  /* Set the first word to point at the last chunk we got */
-  *mem=mallocs;
-
-  /* Now set the "last chunk" pointer to the address of this one */
-  mallocs=(void *)mem;
-
-  /* Return the rest of the memory to the caller */
-  return (void *)(mem+1);
-}
-
-void sfreeall() {
-  void *vp,**vp2;
-  
-  vp=mallocs;
-
-  while (vp!=NULL) {
-    vp2=(void **)vp;
-    vp=*vp2;
-    free((void *)vp2);
-  }
-}
-
 scan *getscan() {
   int i;
   scan *sp;
   
   if (freescans==NULL) {
     /* Eep.  Allocate more. */
-    freescans=(scan *)smalloc(ALLOCUNIT*sizeof(scan));
+    freescans=(scan *)nsmalloc(POOL_PROXYSCAN,ALLOCUNIT*sizeof(scan));
     for (i=0;i<(ALLOCUNIT-1);i++) {
       freescans[i].next=&(freescans[i+1]);
     }
@@ -70,7 +41,7 @@ cachehost *getcachehost() {
   cachehost *chp;
   
   if (freecachehosts==NULL) {
-    freecachehosts=(cachehost *)smalloc(ALLOCUNIT*sizeof(cachehost));
+    freecachehosts=(cachehost *)nsmalloc(POOL_PROXYSCAN,ALLOCUNIT*sizeof(cachehost));
     for (i=0;i<(ALLOCUNIT-1);i++) {
       freecachehosts[i].next=&(freecachehosts[i+1]);
     }
@@ -93,7 +64,7 @@ pendingscan *getpendingscan() {
   pendingscan *psp;
 
   if (!freependingscans) {
-    freependingscans=(pendingscan *)smalloc(ALLOCUNIT * sizeof(pendingscan));
+    freependingscans=(pendingscan *)nsmalloc(POOL_PROXYSCAN,ALLOCUNIT * sizeof(pendingscan));
     for (i=0;i<(ALLOCUNIT-1);i++)
       freependingscans[i].next = freependingscans+i+1;
     freependingscans[ALLOCUNIT-1].next=NULL;
@@ -115,7 +86,7 @@ foundproxy *getfoundproxy() {
   foundproxy *fpp;
 
   if (!freefoundproxies) {
-    freefoundproxies=(foundproxy *)smalloc(ALLOCUNIT * sizeof(foundproxy));
+    freefoundproxies=(foundproxy *)nsmalloc(POOL_PROXYSCAN,ALLOCUNIT * sizeof(foundproxy));
     for (i=0;i<(ALLOCUNIT-1);i++)
       freefoundproxies[i].next = freefoundproxies+i+1;
     freefoundproxies[ALLOCUNIT-1].next=NULL;
index d26f9f57f6fd25976bda7486bd35f5ca39942b68..a7562139c1e7b8e8db3d37adaa4538bbfd340ad4 100644 (file)
@@ -6,7 +6,7 @@
 
 #include "proxyscan.h"
 
-#include <mysql/mysql.h>
+#include "../pqsql/pqsql.h"
 #include "../core/config.h"
 #include "../lib/sstring.h"
 #include "../irc/irc_config.h"
 #include "../localuser/localuser.h"
 #include <string.h>
 #include <stdio.h>
+#include <libpq-fe.h>
 
-MYSQL proxyscansql;
 unsigned int lastid;
-int sqlconnected;
+int sqlconnected = 0;
+extern nick *proxyscannick;
+
+void proxyscan_get_last_id(PGconn *dbconn, void *arg);
 
 /*
  * proxyscandbinit():
@@ -27,64 +30,45 @@ int sqlconnected;
  */
 
 int proxyscandbinit() {
-  sstring *dbhost,*dbusername,*dbpassword,*dbdatabase,*dbport;
-  MYSQL_RES *myres;
-  MYSQL_ROW myrow;
-  sqlconnected=0;
-
-  dbhost=getcopyconfigitem("proxyscan","dbhost","localhost",HOSTLEN);
-  dbusername=getcopyconfigitem("proxyscan","dbusername","proxyscan",20);
-  dbpassword=getcopyconfigitem("proxyscan","dbpassword","moo",20);
-  dbdatabase=getcopyconfigitem("proxyscan","dbdatabase","proxyscan",20);
-  dbport=getcopyconfigitem("proxyscan","dbport","3306",8);
-  
-  mysql_init(&proxyscansql);
-  if (!mysql_real_connect(&proxyscansql,dbhost->content,dbusername->content,
-                         dbpassword->content,dbdatabase->content,
-                         strtol(dbport->content,NULL,10), NULL, 0)) {
-    Error("proxyscan",ERR_ERROR,"Unable to connect to database");
+  if(!pqconnected())
     return 1;
-  }
 
-  freesstring(dbhost);
-  freesstring(dbusername);
-  freesstring(dbpassword);
-  freesstring(dbdatabase);
-  freesstring(dbport);
   sqlconnected=1;
 
   /* Set up the table */
-  mysql_query(&proxyscansql,"CREATE TABLE openproxies (ID BIGINT not null, IP VARCHAR (20) not null, PM INT not null, TS DATETIME not null, RH TEXT not null, PRIMARY KEY (ID), INDEX (ID), UNIQUE (ID))");
+  pqcreatequery("CREATE TABLE openproxies ("
+                "ID int8 not null,"
+               "IP inet not null,"
+               "PM int4 not null,"
+               "TS int4 not null," 
+               "RH varchar not null,"
+               "PRIMARY KEY (ID))");
 
-  /* Get max ID */
-  if ((mysql_query(&proxyscansql,"SELECT max(ID) FROM openproxies"))!=0) {
-    Error("proxyscan",ERR_ERROR,"Unable to retrieve max ID from database");
-    return 1;
-  }
-    
-  myres=mysql_store_result(&proxyscansql);
-  if (mysql_num_fields(myres)!=1) {
-    Error("proxyscan",ERR_ERROR,"Weird format retrieving max ID");
-    mysql_free_result(myres);
-    return 1;
-  }
+  pqcreatequery("CREATE INDEX openproxies_id_index ON openproxies (ID)");
+
+  pqasyncquery(proxyscan_get_last_id, NULL,
+      "SELECT ID FROM openproxies ORDER BY id DESC LIMIT 1");
 
-  lastid=0;
-  if ((myrow=mysql_fetch_row(myres))) {
-    if (myrow[0]==NULL) {
-      lastid=0; 
-    } else {
-      lastid=strtol(myrow[0],NULL,10);
-    }
-    Error("proxyscan",ERR_INFO,"Retrieved lastid %d from database.",lastid);
-  }
-  mysql_free_result(myres);
   return 0;
 }
 
+void proxyscan_get_last_id(PGconn *dbconn, void *arg) {
+  PGresult *pgres = PQgetResult(dbconn);
+  unsigned int numrows;
+
+  if(PQresultStatus(pgres) != PGRES_TUPLES_OK) {
+    Error("proxyscan", ERR_ERROR, "Error loading last id.");
+  }
+
+  numrows = PQntuples(pgres);
+  if ( numrows )
+    lastid = atoi(PQgetvalue(pgres, 0, 0));
+  else 
+    lastid = 0;
+
+  PQclear(pgres);
+   Error("proxyscan",ERR_INFO,"Retrieved lastid %d from database.",lastid);
+}
 /*
  * scantostr:
  *  Given a scan number, returns the string associated.
@@ -141,8 +125,7 @@ int scantodm(int scannum) {
 
 void loggline(cachehost *chp) {
   char reasonlist[100];
-  char reasonesc[100];
-  char sqlquery[4000];
+  char reasonesc[200 + 1]; /* reasonlist*2+1 */
   int reasonmask=0;
   int reasonpos=0;
   foundproxy *fpp;
@@ -161,15 +144,13 @@ void loggline(cachehost *chp) {
   if (chp->glineid==0) {
     chp->glineid=++lastid;
 
-    mysql_escape_string(reasonesc,reasonlist,strlen(reasonlist));
-    sprintf(sqlquery,"INSERT INTO openproxies VALUES(%u,'%s',%d,NOW(),'%s')",chp->glineid,
-           IPlongtostr(chp->IP),reasonmask,reasonesc);
-    mysql_query(&proxyscansql,sqlquery);
+    PQescapeString(reasonesc,reasonlist,strlen(reasonlist));
+    pqquery("INSERT INTO openproxies VALUES(%u,'%s',%d,%ld,'%s')",chp->glineid,
+           IPlongtostr(chp->IP),reasonmask,getnettime(),reasonesc);
   } else {
-    mysql_escape_string(reasonesc,reasonlist,strlen(reasonlist));
-    sprintf(sqlquery,"UPDATE openproxies SET PM=%d,RH='%s' where ID=%u",
+    PQescapeString(reasonesc,reasonlist,strlen(reasonlist));
+    pqquery("UPDATE openproxies SET PM=%d,RH='%s' where ID=%u",
            reasonmask,reasonesc,chp->glineid);
-    mysql_query(&proxyscansql,sqlquery);
   }
 }
 
@@ -179,9 +160,6 @@ void loggline(cachehost *chp) {
  */
 
 void proxyscandbclose() {
-  if (sqlconnected==1) {
-    mysql_close(&proxyscansql);
-  }
 }
 
 /*
@@ -189,34 +167,41 @@ void proxyscandbclose() {
  *  Lists all the open proxies found since <since> to user usernick.
  */
 
-void proxyscandolistopen(nick *mynick, nick *usernick, time_t snce) {
-  char mysqlquery[2000];
-  char timestmp[30];
-  MYSQL_RES *myres;
-  MYSQL_ROW myrow;
-
-  strftime(timestmp,30,"%Y-%m-%d %H:%M:%S",localtime(&snce));
-  sprintf(mysqlquery,"SELECT IP,TS,RH FROM openproxies WHERE TS>'%s' ORDER BY TS",timestmp);
+void proxyscandolistopen_real(PGconn *dbconn, void *arg) {
+  nick *np=getnickbynumeric((unsigned int)arg);
+  PGresult *pgres;
+  int i, num;
 
-  if ((mysql_query(&proxyscansql,mysqlquery))!=0) {
-    sendnoticetouser(mynick,usernick,"Error performing database query!");
-    Error("proxyscan",ERR_ERROR,"Error performing listopen query");
+  pgres=PQgetResult(dbconn);
+  if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
+    Error("proxyscan", ERR_ERROR, "Error loading data.");
     return;
   }
+  
+  if (PQnfields(pgres) != 3) {
+    Error("proxyscan", ERR_ERROR, "data format error.");
+  }
 
-  myres=mysql_use_result(&proxyscansql);
-  if (mysql_num_fields(myres)!=3) {
-    sendnoticetouser(mynick,usernick,"Error performing database query!");
-    Error("proxyscan",ERR_ERROR,"Error performing listopen query");
+  num=PQntuples(pgres);
+
+  if (!np) {
+    PQclear(pgres);
     return;
   }
 
-  sendnoticetouser(mynick,usernick,"%-20s %-22s %s","IP","Found at","What was open");
-  while ((myrow=mysql_fetch_row(myres))) {
-    sendnoticetouser(mynick,usernick,"%-20s %-22s %s",myrow[0],myrow[1],myrow[2]);
+  sendnoticetouser(proxyscannick,np,"%-20s %-22s %s","IP","Found at","What was open");
+  for (i=0; i<num; i++) {
+    sendnoticetouser(proxyscannick,np, "%-20s %-22s %s",PQgetvalue(pgres, i, 0),
+                                                        PQgetvalue(pgres, i, 1),
+                                                       PQgetvalue(pgres, i, 2));
   }
-  sendnoticetouser(mynick,usernick,"--- End of list ---");
-  mysql_free_result(myres);
+  sendnoticetouser(proxyscannick,np,"--- End of list ---");
+}
+
+void proxyscandolistopen(nick *mynick, nick *usernick, time_t snce) {
+
+  pqasyncquery(proxyscandolistopen_real,(void *)usernick->numeric, 
+               "SELECT IP,TS,RH FROM openproxies WHERE TS>'%lu' ORDER BY TS",snce);
 }
 
 /*
@@ -224,32 +209,42 @@ void proxyscandolistopen(nick *mynick, nick *usernick, time_t snce) {
  *  Check db for open proxies matching the given IP, send to user usernick.
  */
 
-void proxyscanspewip(nick *mynick, nick *usernick, unsigned long a, unsigned long b, unsigned long c, unsigned long d) {
-  char mysqlquery[2000];
-  MYSQL_RES *myres;
-  MYSQL_ROW myrow;
-
-  sprintf(mysqlquery, "SELECT ID,IP,TS,RH FROM openproxies WHERE IP='%lu.%lu.%lu.%lu' ORDER BY TS DESC LIMIT 10",a,b,c,d);
+void proxyscanspewip_real(PGconn *dbconn, void *arg) {
+  nick *np=getnickbynumeric((unsigned int)arg);
+  PGresult *pgres;
+  int i, num;
 
-  if ((mysql_query(&proxyscansql,mysqlquery))!=0) {
-    sendnoticetouser(mynick,usernick,"Error performing database query!");
-    Error("proxyscan",ERR_ERROR,"Error performing spew query");
+  pgres=PQgetResult(dbconn);
+  if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
+    Error("proxyscan", ERR_ERROR, "Error loading data.");
     return;
   }
 
-  myres=mysql_use_result(&proxyscansql);
-  if (mysql_num_fields(myres)!=4) {
-    sendnoticetouser(mynick,usernick,"Error performing database query!");
-    Error("proxyscan",ERR_ERROR,"Error performing spew query");
+  if (PQnfields(pgres) != 4) {
+    Error("proxyscan", ERR_ERROR, "data format error.");
+  }
+
+  num=PQntuples(pgres);
+
+  if (!np) {
+    PQclear(pgres);
     return;
   }
 
-  sendnoticetouser(mynick,usernick,"%-5s %-20s %-22s %s","ID","IP","Found at","What was open");
-  while ((myrow=mysql_fetch_row(myres))) {
-    sendnoticetouser(mynick,usernick,"%-5s %-20s %-22s %s",myrow[0],myrow[1],myrow[2],myrow[3]);
+  sendnoticetouser(proxyscannick,np,"%-5s %-20s %-22s %s","ID","IP","Found at","What was open");
+  for (i=0; i<num; i++) {
+    sendnoticetouser(proxyscannick,np, "%-5s %-20s %-22s %s",PQgetvalue(pgres, i, 0),
+                                                             PQgetvalue(pgres, i, 1),
+                                                             PQgetvalue(pgres, i, 2),
+                                                            PQgetvalue(pgres, i, 3));
   }
-  sendnoticetouser(mynick,usernick,"--- End of list ---");
-  mysql_free_result(myres);
+  sendnoticetouser(proxyscannick,np,"--- End of list ---");
+}
+
+void proxyscanspewip(nick *mynick, nick *usernick, unsigned long a, unsigned long b, unsigned long c, unsigned long d) {
+  pqasyncquery(proxyscanspewip_real,(void *)usernick->numeric,
+               "SELECT ID,IP,TS,RH FROM openproxies WHERE IP='%lu.%lu.%lu.%lu' ORDER BY TS DESC LIMIT 10",a,b,c,d);
+
 }
 
 /*
@@ -257,31 +252,40 @@ void proxyscanspewip(nick *mynick, nick *usernick, unsigned long a, unsigned lon
  *  Check db for open proxies matching the given kill/gline ID, send to user usernick.
  */
 
-void proxyscanshowkill(nick *mynick, nick *usernick, unsigned long a) {
-  char mysqlquery[2000];
-  MYSQL_RES *myres;
-  MYSQL_ROW myrow;
-
-  sprintf(mysqlquery, "SELECT ID,IP,TS,RH FROM openproxies WHERE ID='%lu'",a);
+void proxyscanshowkill_real(PGconn *dbconn, void *arg) {
+  nick *np=getnickbynumeric((unsigned int)arg);
+  PGresult *pgres;
+  int i, num;
 
-  if ((mysql_query(&proxyscansql,mysqlquery))!=0) {
-    sendnoticetouser(mynick,usernick,"Error performing database query!");
-    Error("proxyscan",ERR_ERROR,"Error performing showkill query");
+  pgres=PQgetResult(dbconn);
+  if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
+    Error("proxyscan", ERR_ERROR, "Error loading data.");
     return;
   }
 
-  myres=mysql_use_result(&proxyscansql);
-  if (mysql_num_fields(myres)!=4) {
-    sendnoticetouser(mynick,usernick,"Error performing database query!");
-    Error("proxyscan",ERR_ERROR,"Error performing showkill query");
+  if (PQnfields(pgres) != 4) {
+    Error("proxyscan", ERR_ERROR, "data format error.");
+  }
+
+  num=PQntuples(pgres);
+
+  if (!np) {
+    PQclear(pgres);
     return;
   }
 
-  sendnoticetouser(mynick,usernick,"%-5s %-20s %-22s %s","ID","IP","Found at","What was open");
-  /* even though we should only ever have 1 result, still loop below - who knows eh? */
-  while ((myrow=mysql_fetch_row(myres))) {
-    sendnoticetouser(mynick,usernick,"%-5s %-20s %-22s %s",myrow[0],myrow[1],myrow[2],myrow[3]);
+  sendnoticetouser(proxyscannick,np,"%-5s %-20s %-22s %s","ID","IP","Found at","What was open");
+  for (i=0; i<num; i++) {
+    sendnoticetouser(proxyscannick,np, "%-5s %-20s %-22s %s",PQgetvalue(pgres, i, 0),
+                                                             PQgetvalue(pgres, i, 1),
+                                                             PQgetvalue(pgres, i, 2),
+                                                            PQgetvalue(pgres, i, 3));
   }
-  sendnoticetouser(mynick,usernick,"--- End of list ---");
-  mysql_free_result(myres);
+  sendnoticetouser(proxyscannick,np,"--- End of list ---");
+}
+
+
+void proxyscanshowkill(nick *mynick, nick *usernick, unsigned long a) {
+  pqasyncquery(proxyscanspewip_real,(void *)usernick->numeric,
+               "SELECT ID,IP,TS,RH FROM openproxies WHERE ID='%lu'",a);
 }
index 6bde0a73e6037cbeb93fccc7e541412893329c37..92e2817112148242ecbe54736f87a667da49084c 100644 (file)
@@ -12,6 +12,11 @@ void proxyscan_newnick(int hooknum, void *arg) {
   if (irc_in_addr_is_loopback(&np->p_ipaddr) || !irc_in_addr_is_ipv4(&np->p_ipaddr)) 
     return;
 
+
+  /* ignore newnick for first 120s */
+  if (ps_start_ts+120 > time(NULL))
+    return;
+
   unsigned int ip = irc_in_addr_v4_to_int(&np->p_ipaddr);
 
   /*
index 2ea410af6360349a298717e77a42b102a56fe66b..be5f1b257201702b19750b0d68509ca7094ff420 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "proxyscan.h"
 #include "../irc/irc.h"
+#include "../core/error.h"
 
 pendingscan *ps_normalqueue=NULL;
 pendingscan *ps_prioqueue=NULL;
@@ -53,16 +54,11 @@ void queuescan(unsigned int IP, short scantype, unsigned short port, char class,
   }
 
   /* We have to queue it */
-  psp = (struct pendingscan *) malloc(sizeof(pendingscan));
-  if (!psp)
-  {
-    /* shutdown due to no memory */
-    irc_send("%s SQ %s 0 :Out of memory - exiting.",mynumeric->content,myserver->content);
-    irc_disconnected();
-    exit(0);
-  } else {
-    countpendingscan++;
-  }
+  if (!(psp=(struct pendingscan *)malloc(sizeof(pendingscan))))
+    Error("proxyscan",ERR_STOP,"Unable to allocate memory");
+
+  countpendingscan++;
+
   psp->IP=IP;
   psp->type=scantype;
   psp->port=port;
index 5d2fdfa6cb00023e86366a8aae81df69c735f6ea..8fe98f9d0c0bf79183abbee20e9d082ed6caed4e 100644 (file)
@@ -899,7 +899,7 @@ struct rg_struct *rg_newsstruct(char *id, char *mask, char *setby, char *reason,
     return NULL;
 }
 
-void rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char *matched) { /* PPA: if multiple users match the same user@host or *@host it'll send multiple glines?! */
+int __rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char *matched) { /* PPA: if multiple users match the same user@host or *@host it'll send multiple glines?! */
   char hostname[RG_MASKLEN];
   int usercount = 0;
 
@@ -940,11 +940,11 @@ void rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char *
         nn->punish = rp->type;
       }
     }
-    return;
+    return usercount;
   }
   
   if ((rp->type <= 0) || (rp->type >= 3))
-    return;
+    return 0;
   
   if (rp->type == 1) {
     if (IsAccount(np)) {
@@ -961,6 +961,25 @@ void rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char *
   }
   
   irc_send("%s GL * +%s %d :AUTO: %s (ID: %08lx)\r\n", mynumeric->content, hostname, rg_expiry_time, rp->reason->content, rp->glineid);
+  return usercount;
+}
+
+int floodprotection = 0;
+
+void rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char *matched) {
+  int t = time(NULL);
+
+  if(t > floodprotection) {
+    floodprotection = t;
+  } else if((floodprotection - t) / 8 > RG_NETWORK_WIDE_MAX_GLINES_PER_8_SEC) {
+    channel *cp = findchannel("#twilightzone");
+    if(cp)
+      controlchanmsg(cp, "WARNING! REGEXGLINE DISABLED FOR AN HOUR DUE TO NETWORK WIDE LOOKING GLINE!");
+    controlwall(NO_OPER, NL_MANAGEMENT, "WARNING! REGEXGLINE DISABLED FOR AN HOUR DUE TO NETWORK WIDE LOOKING GLINE!");
+    floodprotection = t + RG_NETWORK_WIDE_MAX_GLINES_PER_8_SEC * 3600 * 8;
+  }
+
+  floodprotection+=__rg_dogline(gll, np, rp, matched);
 }
 
 void rg_logevent(nick *np, char *event, char *details, ...) {
index 8130ec9278d764a4748382e1ec557f246e2880ed..7ccad1de08e9c3af14b6e2e4df428220ce4f6989 100644 (file)
@@ -30,6 +30,7 @@
 #define RG_MINIMUM_DELAY_TIME     5
 #define RG_MAXIMUM_RAND_TIME      15
 #define RG_EXPIRY_TIME_DEFAULT    1800
+#define RG_NETWORK_WIDE_MAX_GLINES_PER_8_SEC 625 /* 5000 / 8 */
 
 #define RGStringise(x)            #x
 #define RGBuildHostname(buf, np)  snprintf(buf, sizeof(buf), "%s!%s@%s\r%s", np->nick, np->ident, np->host->name->content, np->realname->name->content);
index 4576d38170f81bc5026678bc6cf4235f2c0033b5..14cdcb4918793209b3ecf44ee50f941ee68822d6 100644 (file)
@@ -49,7 +49,14 @@ int rq_blocked = 0;
 /* log fd */
 FILE *rq_logfd;
 
+static int extloaded = 0;
+
 void _init(void) {
+  if(!rq_initblocks())
+    return;
+
+  extloaded = 1;
+
   rqcommands = newcommandtree();
 
   addcommandtotree(rqcommands, "showcommands", RQU_ANY, 1, &rqcmd_showcommands);
@@ -67,7 +74,6 @@ void _init(void) {
   addcommandtotree(rqcommands, "changelev", RQU_OPER, 2, &rqcmd_changelev);
   addcommandtotree(rqcommands, "userlist", RQU_OPER, 1, &rqcmd_userlist);
   
-  rq_initblocks();
   qr_initrequest();
   ru_load();
 
@@ -77,6 +83,9 @@ void _init(void) {
 }
 
 void _fini(void) {
+  if(!extloaded)
+    return;
+
   deregisterlocaluser(rqnick, NULL);
 
   deletecommandfromtree(rqcommands, "showcommands", &rqcmd_showcommands);
@@ -185,7 +194,7 @@ void rq_handler(nick *target, int type, void **params) {
 
       break;
     case LU_PRIVNOTICE:
-      qr_handlenotice(params[0], params[1]);
+      qr_handle_notice(params[0], params[1]);
 
       break;
   }
@@ -271,8 +280,18 @@ int rq_genericrequestcheck(nick *np, char *channelname, channel **cp, nick **lni
   block = rq_findblock(channelname);
 
   if (block != NULL) {
-    sendnoticetouser(rqnick, np, "Error: You are not allowed to request a "
+     /* only say when block expires if <7 days */
+     if ( block->expires < getnettime() + 3600 * 24 * 7) {
+       sendnoticetouser(rqnick, np, "Error: You are not allowed to request a "
+            "service to this channel. Keep waiting for at least %s before you try again.",
+            rq_longtoduration(block->expires - getnettime()));
+       /* give them another 5 minutes to think about it */
+       block->expires += 300;
+       rq_saveblocks();
+     } else {
+       sendnoticetouser(rqnick, np, "Error: You are not allowed to request a "
           "service to this channel.");
+     }
     sendnoticetouser(rqnick, np, "Reason: %s", block->reason->content);
 
     rq_blocked++;
index 40d7bc859fecd9e49f318e7560ecb32cea7948b2..fa7f59de0be26d16ad4cb426452563a38a1b2cb7 100644 (file)
@@ -15,7 +15,11 @@ int rq_loading;
 
 void rqhook_lostnick(int hook, void *arg);
 
-void rq_initblocks(void) {
+int rq_initblocks(void) {
+  rqnext = registernickext("request");
+  if(rqnext < 0)
+    return 0;
+
   array_init(&rqblocks, sizeof(rq_block));
   array_setlim1(&rqblocks, 5);
   array_setlim2(&rqblocks, 20);
@@ -29,7 +33,7 @@ void rq_initblocks(void) {
 
   registerhook(HOOK_NICK_LOSTNICK, &rqhook_lostnick);
 
-  rqnext = registernickext("request");
+  return 1;
 }
 
 void rq_finiblocks(void) {
index dac6463416c7ac3e3f1d600610f0918ee034facc..91f68a2b595c2c20df2391b0f07ef8e91eb227c8 100644 (file)
@@ -24,7 +24,7 @@ extern array rqblocks;
 #define RQ_SPAMCOUNT 5
 #define RQ_SPAMBLOCK 3600
 
-void rq_initblocks(void);
+int rq_initblocks(void);
 void rq_finiblocks(void);
 
 int rq_loadblocks(void);
index 790e104e0ceae17109c476175f564a07e23e9e9d..902872e56f8dc6139c409f340cbf15cd25ef825e 100644 (file)
@@ -48,7 +48,7 @@ requestrec *nextreql, *lastreql;
 requestrec *nextreqq, *lastreqq;
 
 
-requestrec *nextqreq, *lastqreq;
+static requestrec *nextqreq, *lastqreq;
 
 extern nick *rqnick;
 int rlstate;
@@ -104,7 +104,7 @@ unsigned int rq_countchanusers(channel *cp) {
  * as part of the process.
  */
 
-void qr_result(requestrec *req, int outcome, char failcode, char *message, ...) {
+static void qr_result(requestrec *req, int outcome, char failcode, char *message, ...) {
   sstring *user, *password;
   requestrec **rh;
   char msgbuf[512];
@@ -299,7 +299,7 @@ void qr_result(requestrec *req, int outcome, char failcode, char *message, ...)
  *  Checks that a channel is beeeeg enough for teh Q
  */
 
-int qr_checksize(chanindex *cip, int what, char *failcode) {
+static int qr_checksize(chanindex *cip, int what, char *failcode) {
   chanstats *csp;
   channel *cp;
   nick *np, *qbot;
@@ -415,7 +415,7 @@ int qr_checksize(chanindex *cip, int what, char *failcode) {
  * 11:12 -L(TheLBot@lightweight.quakenet.org)- End of chanlev for #twilightzone.
  */
 
-void qr_handlenotice(nick *sender, char *message) {
+void qr_handle_notice(nick *sender, char *message) {
   char *ch, *chop;
   chanindex *cip;
   requestrec *rrp1, *rrp2;
index ab2b664271b39970ffa51e726dc89c82c2936763..afe7b3621c8fd5b735d51e9c5ee9ec67709bc852 100644 (file)
@@ -23,4 +23,4 @@ int qr_requestq(nick *rqnick, nick *sender, channel *cp, nick *lnick, nick *qnic
 int qr_instantrequestq(nick *sender, channel *cp);
 int qr_requests(nick *rqnick, nick *sender, channel *cp, nick *lnick, nick *qnick);
 void qr_requeststats(nick *rqnick, nick *np);
-void qr_handlenotice(nick *sender, char *message);
+void qr_handle_notice(nick *sender, char *message);
index 68f96337878f2a239e92e8fff8162ffacddc5d27..79e5fc52f3d5c106aa4c0336d786c829c29e07d0 100644 (file)
@@ -20,7 +20,7 @@ void spamserverstate(int hook, void *servernum) {
   }
 }
 
-void printnick(int hook, void *vp) {
+static void printnick(int hook, void *vp) {
 /*
 //  nick *np=(nick *)vp;
   
index 71a8579bdf3931c405c982abe616c4806ee8d201..f68304646873dcce8adf5472f2cc5555b230e04b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Trojanscan version 2
  *
- * Trojanscan  copyright (C) Chris Porter 2002-2005
+ * Trojanscan  copyright (C) Chris Porter 2002-2007
  * Newserv bits copyright (C) David Mansell 2002-2003
  * 
  * TODO: CHECK::
 #include "../lib/strlfunc.h"
 #include "../lib/version.h"
 
-MODULE_VERSION("");
+MODULE_VERSION(TROJANSCAN_VERSION);
+
+void trojanscan_phrasematch(channel *chp, nick *sender, trojanscan_phrases *phrase, char messagetype, char *matchbuf);
+char *trojanscan_sanitise(char *input);
+void trojanscan_refresh_settings(void);
+static void trojanscan_part_watch(int hook, void *arg);
+
+#define TROJANSCAN_SETTING_SIZE 256
+#define TROJANSCAN_MAX_SETTINGS 50
+
+static struct {
+  char setting[TROJANSCAN_SETTING_SIZE];
+  char value[TROJANSCAN_SETTING_SIZE];
+} trojanscan_settings[TROJANSCAN_MAX_SETTINGS];
+
+static int settingcount = 0;
+static char *versionreply;
+static int hooksregistered = 0;
 
 void _init() {
   trojanscan_cmds = newcommandtree();
@@ -65,6 +82,9 @@ void _fini(void) {
   if(trojanscan_cloneschedule)
     deleteschedule(trojanscan_poolschedule, &trojanscan_registerclones, NULL);
   
+  if(hooksregistered)
+    deregisterhook(HOOK_CHANNEL_PART, trojanscan_part_watch);
+
   while(rp) {
     deleteschedule(rp->schedule, &trojanscan_dopart, (void *)rp);
     oldrp = rp;
@@ -189,14 +209,18 @@ void trojanscan_connect(void *arg) {
   trojanscan_database_query("CREATE TABLE channels (id INT(10) PRIMARY KEY AUTO_INCREMENT, channel VARCHAR(%d) NOT NULL, exempt BOOL DEFAULT 0)", CHANNELLEN);
   trojanscan_database_query("CREATE TABLE users (id INT(10) PRIMARY KEY AUTO_INCREMENT, authname VARCHAR(%d) NOT NULL, authlevel TINYINT(4) NOT NULL)", ACCOUNTLEN);
   trojanscan_database_query("CREATE TABLE hits (id INT(10) PRIMARY KEY AUTO_INCREMENT, nickname VARCHAR(%d) NOT NULL, ident VARCHAR(%d) NOT NULL, host VARCHAR(%d) NOT NULL, phrase INT(10) NOT NULL, ts TIMESTAMP, messagetype VARCHAR(1) NOT NULL DEFAULT 'm', glined BOOL DEFAULT 1)", NICKLEN, USERLEN, HOSTLEN);
-  trojanscan_database_query("CREATE TABLE settings (id INT(10) PRIMARY KEY AUTO_INCREMENT, setting VARCHAR(15) NOT NULL, value VARCHAR(15) NOT NULL)");
+  trojanscan_database_query("CREATE TABLE settings (id INT(10) PRIMARY KEY AUTO_INCREMENT, setting VARCHAR(255) NOT NULL UNIQUE, value VARCHAR(255) NOT NULL)");
   trojanscan_database_query("CREATE TABLE wwwlogs (id INT(10) PRIMARY KEY AUTO_INCREMENT, authid INT(10) NOT NULL, ip VARCHAR(15), action TEXT, ts TIMESTAMP)");
   trojanscan_database_query("CREATE TABLE unknownlog (id INT(10) PRIMARY KEY AUTO_INCREMENT, data TEXT, user VARCHAR(%d) NOT NULL, ts TIMESTAMP)", NICKLEN+USERLEN+HOSTLEN+3);
   
-  trojanscan_database_query("DELETE FROM settings");
+  trojanscan_database_query("DELETE FROM settings WHERE setting = 'rehash' OR setting = 'changed'");
   trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('rehash','0')");
   trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('changed','0')");
+
+  /* assumption: constants aren't supplied by someone evil */
+  trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('versionreply','" TROJANSCAN_DEFAULT_VERSION_REPLY "')");
   
+  trojanscan_refresh_settings();
   trojanscan_read_database(1);
  
   cp = findchannel(TROJANSCAN_OPERCHANNEL);
@@ -239,24 +263,63 @@ void trojanscan_connect(void *arg) {
   
   trojanscan_rehashschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_rehash_schedule, NULL);
 
+  registerhook(HOOK_CHANNEL_PART, trojanscan_part_watch);
+  hooksregistered = 1;
+}
+
+char *trojanscan_get_setting(char *setting) {
+  int i;
+
+  for(i=0;i<settingcount;i++)
+    if(!strcmp(trojanscan_settings[i].setting, setting))
+      return trojanscan_settings[i].value;
+
+  return NULL;
+}
+
+void trojanscan_refresh_settings(void) {
+  trojanscan_database_res *res;
+  trojanscan_database_row sqlrow;
+  int i = 0;
+
+  if(trojanscan_database_query("SELECT setting, value FROM settings"))
+    return;
+
+  if(!(res = trojanscan_database_store_result(&trojanscan_sql)))
+    return;
+
+  if (trojanscan_database_num_rows(res) <= 0)
+    return;
+
+  while((sqlrow = trojanscan_database_fetch_row(res))) {
+    strlcpy(trojanscan_settings[i].setting, sqlrow[0], TROJANSCAN_SETTING_SIZE);
+    strlcpy(trojanscan_settings[i].value, sqlrow[1], TROJANSCAN_SETTING_SIZE);
+
+    trojanscan_sanitise(trojanscan_settings[i].value);
+
+    if(++i == TROJANSCAN_MAX_SETTINGS)
+      break;
+  }
+
+  settingcount = i;
+
+  trojanscan_database_free_result(res);
+
+  /* optimisation hack */
+  versionreply = trojanscan_get_setting("versionreply");
 }
 
 void trojanscan_rehash_schedule(void *arg) {
+  char *v;
   trojanscan_rehashschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_rehash_schedule, NULL);
-  if (!(trojanscan_database_query("SELECT value FROM settings WHERE setting = 'rehash'"))) {
-    trojanscan_database_res *res;
-    if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
-      if (trojanscan_database_num_rows(res) > 0) {
-        trojanscan_database_row sqlrow = trojanscan_database_fetch_row(res);
-        if (sqlrow && (sqlrow[0][0] == '1')) {
-          trojanscan_mainchanmsg("n: rehash initiated by website. . .");
-          trojanscan_read_database(0);
-        }
-      }
-      trojanscan_database_free_result(res);
-    }
-  } 
-    
+
+  trojanscan_refresh_settings();
+
+  v = trojanscan_get_setting("rehash");
+  if(v && v[0] == '1') {
+    trojanscan_mainchanmsg("n: rehash initiated by website. . .");
+    trojanscan_read_database(0);
+  }
 }
 
 void trojanscan_free_database(void) {
@@ -280,6 +343,16 @@ void trojanscan_free_database(void) {
   
 }
 
+char *trojanscan_sanitise(char *input) {
+  char *p;
+
+  for(p=input;*p;p++)
+    if(*p == '\r' || *p == '\n')
+      *p = '!';
+
+  return input;
+}
+
 sstring *trojanscan_getsstring(char *string, int length) {
   int i;
   
@@ -393,7 +466,7 @@ void trojanscan_read_database(int first_time) {
           if ((trojanscan_database.total_channels>0) && trojanscan_database.channels) {
             i = 0;
             while((sqlrow = trojanscan_database_fetch_row(res))) {
-              trojanscan_database.channels[i].name = trojanscan_getsstring(sqlrow[0], strlen(sqlrow[0]));
+              trojanscan_database.channels[i].name = trojanscan_getsstring(trojanscan_sanitise(sqlrow[0]), strlen(sqlrow[0]));
               trojanscan_database.channels[i].exempt = (sqlrow[1][0] == '1');
               i++;
             }
@@ -412,7 +485,7 @@ void trojanscan_read_database(int first_time) {
           i = 0;
           while((sqlrow = trojanscan_database_fetch_row(res))) {
             trojanscan_database.worms[i].id = atoi(sqlrow[0]);
-            trojanscan_database.worms[i].name = trojanscan_getsstring(sqlrow[1], strlen(sqlrow[1]));
+            trojanscan_database.worms[i].name = trojanscan_getsstring(trojanscan_sanitise(sqlrow[1]), strlen(sqlrow[1]));
             tempresult = atoi(sqlrow[2]);
             trojanscan_database.worms[i].glineuser = (tempresult == 0);
             trojanscan_database.worms[i].glinehost = (tempresult == 1);
@@ -463,7 +536,6 @@ void trojanscan_read_database(int first_time) {
   }
 
   trojanscan_database_query("UPDATE settings SET value = '0' where setting = 'rehash'");
-  
 }
 
 void trojanscan_log(nick *np, char *event, char *details, ...) {
@@ -1112,6 +1184,7 @@ int trojanscan_userjoin(void *sender, int cargc, char **cargv) {
 
 int trojanscan_rehash(void *sender, int cargc, char **cargv) {
   nick *np = (void *)sender;
+  trojanscan_refresh_settings();
   trojanscan_read_database(0);
   trojanscan_log(np, "rehash", "");
   trojanscan_reply(np, "Done.");
@@ -1506,7 +1579,7 @@ void trojanscan_donickchange(void *arg) { /* just incase I choose to make this s
       } else {
         trojanscan_gennick(c_nick, trojanscan_minmaxrand(7, TROJANSCAN_MMIN(13, NICKLEN)));
       }
-    } while (c_nick && (getnickbynick(c_nick) != NULL));
+    } while (c_nick[0] && (getnickbynick(c_nick) != NULL));
 
     renamelocaluser(clone->clone, c_nick);
   }
@@ -1574,7 +1647,7 @@ void trojanscan_handlemessages(nick *target, int messagetype, void **args) {
 
       /* Split the line into params */
       cargc = splitline((char *)args[1], cargv, 50, 0);
-      if(cargc == 0 || !cargv || !cargv[0])
+      if(cargc == 0 || !cargv[0])
         return;
 
       cmd=findcommandintree(trojanscan_cmds, cargv[0], 1);
@@ -1647,6 +1720,13 @@ void trojanscan_handlemessages(nick *target, int messagetype, void **args) {
   }
 }
 
+static char trojanscan_getmtfromhooktype(int input) {
+  switch(input) {
+    case HOOK_CHANNEL_PART: return 'P';
+    default:                return '?';
+  }
+}
+
 char trojanscan_getmtfrommessagetype(int input) {
   switch(input) {
     case LU_PRIVMSG:    return 'm';
@@ -1658,16 +1738,78 @@ char trojanscan_getmtfrommessagetype(int input) {
   }
 }
 
+static void trojanscan_process(nick *sender, channel *cp, char mt, char *pretext) {
+  char text[513];
+  unsigned int len;
+  unsigned int i;
+  struct trojanscan_worms *worm;
+  int vector[30], detected = 0;
+
+  trojanscan_strip_codes(text, sizeof(text) - 1, pretext);
+      
+  len = strlen(text);
+      
+  for(i=0;i<trojanscan_database.total_phrases;i++) {
+    if (
+         (
+           (worm = trojanscan_database.phrases[i].worm)
+         ) &&
+         (
+           (
+             (
+               (mt == 'm') || (mt == 's') || (mt == 'n')
+             ) &&
+             (
+               (trojanscan_database.phrases[i].worm->hitpriv)
+             )
+           ) ||
+           (
+             (
+               (mt == 'M') || (mt == 'N') || (mt == 'P')
+             ) &&
+             (
+               (trojanscan_database.phrases[i].worm->hitchans)
+             )
+           )
+         ) &&
+         (trojanscan_database.phrases[i].phrase)
+       ) {
+      int pre = pcre_exec(trojanscan_database.phrases[i].phrase, trojanscan_database.phrases[i].hint, text, len, 0, 0, vector, 30);
+      if(pre >= 0) {
+        char matchbuf[513];
+        matchbuf[0] = 0;
+        matchbuf[512] = 0; /* hmm */
+   
+        if(pre > 1)
+          if(pcre_copy_substring(text, vector, pre, 1, matchbuf, sizeof(matchbuf) - 1) <= 0)
+            matchbuf[0] = 0;
+           
+        trojanscan_phrasematch(cp, sender, &trojanscan_database.phrases[i], mt, matchbuf);
+
+        detected = 1;
+        break;
+      }
+    }
+  }
+  if (!detected && (mt != 'N') && (mt != 'M')) {
+    char etext[TROJANSCAN_QUERY_TEMP_BUF_SIZE], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
+    trojanscan_database_escape_string(etext, text, len);
+    trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
+    trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
+    trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
+    trojanscan_database_query("INSERT INTO unknownlog (data, user) VALUES ('%s','%s!%s@%s')", etext, enick, eident, ehost);
+  }
+}
+
 void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args) {
-  char *pretext = NULL, etext[TROJANSCAN_QUERY_TEMP_BUF_SIZE], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE], text[513], detected = 0;
+  char *pretext = NULL;
   nick *sender;
   struct trojanscan_realchannels *rp;
   struct trojanscan_rejoinlist *rj;
-  unsigned int i, len;
-  struct trojanscan_worms *worm;
-  int vector[30];
   char mt = trojanscan_getmtfrommessagetype(messagetype);
   char *channel_name;
+  channel *cp = NULL;
+  int i;
 
   switch(messagetype) {
     case LU_PRIVMSG:
@@ -1678,13 +1820,15 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
     
     case LU_CHANMSG:
     case LU_CHANNOTICE:
-      
       sender = (nick *)args[0];
+
       if (strlen(sender->nick) < 2)
         break;
       
-      if (!pretext)
+      if (!pretext) {
         pretext = (char *)args[2];  
+        cp = args[1];
+      }
 
       if(strncmp(TROJANSCAN_VERSION_DETECT, pretext, sizeof(TROJANSCAN_VERSION_DETECT)-1)==0) {
         char p = pretext[sizeof(TROJANSCAN_VERSION_DETECT)-1];
@@ -1711,151 +1855,14 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
               sendnoticetouser(target, sender, "\001VERSION T clone, though since T is currently gone you'll have to version me again in a minute for confirmation.\001");
             }
           } else {
-            sendnoticetouser(target, sender,  "\001VERSION " TROJANSCAN_CLONE_VERSION_REPLY "\001");
+            sendnoticetouser(target, sender,  "\001VERSION %s\001", versionreply);
           }
         
           return;
         }
       }
       
-      trojanscan_strip_codes(text, sizeof(text) - 1, pretext);
-      
-      len = strlen(text);
-      
-      for(i=0;i<trojanscan_database.total_phrases;i++) {
-        if (
-             (
-               (worm = trojanscan_database.phrases[i].worm)
-             ) &&
-             (
-               (
-                 (
-                   (messagetype == LU_PRIVMSG) || (messagetype == LU_SECUREMSG) || (messagetype == LU_PRIVNOTICE)
-                 ) &&
-                 (
-                   (trojanscan_database.phrases[i].worm->hitpriv)
-                 )
-               ) ||
-               (
-                 (
-                   (messagetype == LU_CHANMSG) || (messagetype == LU_CHANNOTICE)
-                 ) &&
-                 (
-                   (trojanscan_database.phrases[i].worm->hitchans)
-                 )
-               )
-             ) &&
-             (trojanscan_database.phrases[i].phrase)
-           ) {
-          int pre = pcre_exec(trojanscan_database.phrases[i].phrase, trojanscan_database.phrases[i].hint, text, len, 0, 0, vector, 30);
-          if(pre >= 0) {
-            char glinemask[HOSTLEN + USERLEN + NICKLEN + 4];
-            char *userbit;
-            host *hp;
-            unsigned int j, usercount, frequency;
-            int glining = 1;
-            channel *chp = (channel *)args[1];
-            
-            nick *np = NULL; /* sigh at warnings */
-            
-            detected = 1;
-            
-            trojanscan_database.detections++;
-            
-            if (!(hp=findhost(sender->host->name->content))) {
-              trojanscan_mainchanmsg("w: user %s!%s@%s triggered infection monitor, yet no hosts found at stage 1 -- worm: %s", sender->nick, sender->ident, sender->host->name->content, worm->name->content);
-              break;
-            } 
-
-            usercount = 0; /* stupid warnings */
-            if (worm->monitor) {
-              glining = 0;
-              usercount = -1;
-            } else if (worm->glinehost && (hp->clonecount <= TROJANSCAN_MAX_HOST_GLINE)) {
-              snprintf(glinemask, sizeof(glinemask) - 1, "*@%s", IPtostr(sender->p_ipaddr));
-              usercount = hp->clonecount;
-            }
-            else if (worm->glineuser || (worm->glinehost && hp->clonecount > TROJANSCAN_MAX_HOST_GLINE)) {
-              userbit = sender->ident;
-              if(userbit[0] == '~')
-                userbit++;
-              snprintf(glinemask, sizeof(glinemask) - 1, "*%s@%s", userbit, IPtostr(sender->p_ipaddr));
-              for (j=0;j<NICKHASHSIZE;j++) {
-                for (np=nicktable[j];np;np=np->next) {
-                  if ((np->host==hp) && (!ircd_strcmp(np->ident,sender->ident)))
-                    usercount++;
-                }
-              }
-            }
-            
-            if (!usercount) {
-              trojanscan_mainchanmsg("w: user %s!%s@%s triggered infection monitor, yet no hosts found at stage 2 -- worm: %s", sender->nick, sender->ident, sender->host->name->content, worm->name->content);
-              break;
-            }
-             
-            if (glining && (usercount > trojanscan_maxusers)) {
-              trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too many users (%d) with mask: *!%s -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, usercount, glinemask, worm->name->content);
-              break;
-            }
-
-            if (glining && !worm->datalen) {
-              trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too lack of removal data with mask: *!%s (%d users) -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, glinemask, usercount, worm->name->content);
-              break;
-            }
-                        
-            trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
-            trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
-            trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
-            
-            frequency = 1;
-            
-            if (!(trojanscan_database_query("SELECT COUNT(*) FROM hits WHERE glined = %d AND host = '%s'", glining, ehost))) {
-              trojanscan_database_res *res;
-              if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
-                trojanscan_database_row sqlrow;
-                if ((trojanscan_database_num_rows(res) > 0) && (sqlrow = trojanscan_database_fetch_row(res)))
-                  frequency = atoi(sqlrow[0]) + 1;
-                trojanscan_database_free_result(res);
-              }
-            } 
-
-            if (!glining) {
-              char matchbuf[513];
-              matchbuf[0] = 0;
-              matchbuf[512] = 0; /* hmm */
-              
-              if(pre > 1)
-                if (pcre_copy_substring(text, vector, pre, 1, matchbuf, sizeof(matchbuf) - 1) <= 0)
-                  matchbuf[0] = 0;
-              
-              trojanscan_mainchanmsg("m: t: %c u: %s!%s@%s%s%s w: %s p: %d %s%s", mt, sender->nick, sender->ident, sender->host->name->content, mt=='N'||mt=='M'?" #: ":"", mt=='N'||mt=='M'?chp->index->name->content:"", worm->name->content, trojanscan_database.phrases[i].id, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
-#ifdef TROJANSCAN_PEONCHANNEL
-              trojanscan_peonchanmsg("m: t: %c u: %s!%s@%s%s%s%s w: %s %s%s", mt, sender->nick, sender->ident, (IsHideHost(sender)&&IsAccount(sender))?sender->authname:sender->host->name->content, (IsHideHost(sender)&&IsAccount(sender))?"."HIS_HIDDENHOST:"", mt=='N'||mt=='M'?" #: ":"", mt=='N'||mt=='M'?chp->index->name->content:"", worm->name->content, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
-#endif
-            } else {
-              int glinetime = TROJANSCAN_FIRST_OFFENSE * frequency * (worm->epidemic?TROJANSCAN_EPIDEMIC_MULTIPLIER:1);
-              if(glinetime > 7 * 24)
-                glinetime = 7 * 24; /* can't set glines over 7 days with normal non U:lined glines */
-
-              trojanscan_database_query("INSERT INTO hits (nickname, ident, host, phrase, messagetype, glined) VALUES ('%s', '%s', '%s', %d, '%c', %d)", enick, eident, ehost, trojanscan_database.phrases[i].id, mt, glining);          
-              trojanscan_database.glines++;
-              
-              irc_send("%s GL * +%s %d :You (%s!%s@%s) are infected with a trojan (%s/%d), see %s%d for details - banned for %d hours\r\n", mynumeric->content, glinemask, glinetime * 3600, sender->nick, sender->ident, sender->host->name->content, worm->name->content, trojanscan_database.phrases[i].id, TROJANSCAN_URL_PREFIX, worm->id, glinetime);
-
-              trojanscan_mainchanmsg("g: *!%s t: %c u: %s!%s@%s%s%s c: %d w: %s%s p: %d f: %d", glinemask, mt, sender->nick, sender->ident, sender->host->name->content, mt=='N'||mt=='M'?" #: ":"", mt=='N'||mt=='M'?chp->index->name->content:"", usercount, worm->name->content, worm->epidemic?"(E)":"", trojanscan_database.phrases[i].id, frequency);
-            }
-            
-            break;
-          }
-        }
-      }
-      if (!detected && (mt != 'N') && (mt != 'M')) {
-        trojanscan_database_escape_string(etext, text, len);
-        trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
-        trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
-        trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
-        trojanscan_database_query("INSERT INTO unknownlog (data, user) VALUES ('%s','%s!%s@%s')", etext, enick, eident, ehost);
-      }
+      trojanscan_process(sender, cp, mt, pretext);
       break;         
     case LU_KILLED:
       /* someone killed me?  Bastards */
@@ -1937,6 +1944,103 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
   }
 }
 
+static void trojanscan_part_watch(int hook, void *arg) {
+  void **arglist = (void **)arg;
+  channel *cp = (channel *)arglist[0];
+  nick *np = arglist[1];
+  char *reason = arglist[2];
+
+  if(!cp || !np || !reason || (*reason == '\0'))
+    return;
+
+  trojanscan_process(np, cp, trojanscan_getmtfromhooktype(hook), reason);
+}
+
+void trojanscan_phrasematch(channel *chp, nick *sender, trojanscan_phrases *phrase, char messagetype, char *matchbuf) {
+  char glinemask[HOSTLEN + USERLEN + NICKLEN + 4], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
+  char *userbit;
+  unsigned int j, usercount, frequency;
+  int glining = 1;
+  struct trojanscan_worms *worm = phrase->worm;
+
+  nick *np = NULL; /* sigh at warnings */
+  
+  trojanscan_database.detections++;
+  
+  usercount = 0;
+  if (worm->monitor) {
+    glining = 0;
+    usercount = -1;
+  } else if (worm->glinehost) {
+    snprintf(glinemask, sizeof(glinemask) - 1, "*@%s", IPtostr(sender->p_ipaddr));
+    for (j=0;j<NICKHASHSIZE;j++)
+      for (np=nicktable[j];np;np=np->next)
+        if (np->ipnode==sender->ipnode)
+          usercount++;
+  }
+  if (worm->glineuser || (worm->glinehost && usercount > TROJANSCAN_MAX_HOST_GLINE)) {
+    userbit = sender->ident;
+/*
+    if(userbit[0] == '~')
+      userbit++;
+*/
+    snprintf(glinemask, sizeof(glinemask) - 1, "%s@%s", userbit, IPtostr(sender->p_ipaddr));
+    for (j=0;j<NICKHASHSIZE;j++)
+      for (np=nicktable[j];np;np=np->next)
+        if ((np->ipnode==sender->ipnode) && (!ircd_strcmp(np->ident,sender->ident)))
+          usercount++;
+  }
+  
+  if (!usercount) {
+    trojanscan_mainchanmsg("w: user %s!%s@%s triggered infection monitor, yet no hosts found at stage 2 -- worm: %s", sender->nick, sender->ident, sender->host->name->content, worm->name->content);
+    return;
+  }
+   
+  if (glining && (usercount > trojanscan_maxusers)) {
+    trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too many users (%d) with mask: *!%s -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, usercount, glinemask, worm->name->content);
+    return;
+  }
+
+  if (glining && !worm->datalen) {
+    trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too lack of removal data with mask: *!%s (%d users) -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, glinemask, usercount, worm->name->content);
+    return;
+  }
+    
+  trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
+  trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
+  trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
+  
+  frequency = 1;
+  
+  if (!(trojanscan_database_query("SELECT COUNT(*) FROM hits WHERE glined = %d AND host = '%s'", glining, ehost))) {
+    trojanscan_database_res *res;
+    if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
+      trojanscan_database_row sqlrow;
+      if ((trojanscan_database_num_rows(res) > 0) && (sqlrow = trojanscan_database_fetch_row(res)))
+        frequency = atoi(sqlrow[0]) + 1;
+      trojanscan_database_free_result(res);
+    }
+  } 
+
+  if (!glining) {
+    trojanscan_mainchanmsg("m: t: %c u: %s!%s@%s%s%s w: %s p: %d %s%s", messagetype, sender->nick, sender->ident, sender->host->name->content, messagetype=='N'||messagetype=='M'||messagetype=='P'?" #: ":"", messagetype=='N'||messagetype=='M'||messagetype=='P'?chp->index->name->content:"", worm->name->content, phrase->id, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
+#ifdef TROJANSCAN_PEONCHANNEL
+    trojanscan_peonchanmsg("m: t: %c u: %s!%s@%s%s%s%s w: %s %s%s", messagetype, sender->nick, sender->ident, (IsHideHost(sender)&&IsAccount(sender))?sender->authname:sender->host->name->content, (IsHideHost(sender)&&IsAccount(sender))?"."HIS_HIDDENHOST:"", messagetype=='N'||messagetype=='M'||messagetype=='P'?" #: ":"", messagetype=='N'||messagetype=='M'||messagetype=='P'?chp->index->name->content:"", worm->name->content, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
+#endif
+  } else {
+    int glinetime = TROJANSCAN_FIRST_OFFENSE * frequency * (worm->epidemic?TROJANSCAN_EPIDEMIC_MULTIPLIER:1);
+    if(glinetime > 7 * 24)
+      glinetime = 7 * 24; /* can't set glines over 7 days with normal non U:lined glines */
+
+    trojanscan_database_query("INSERT INTO hits (nickname, ident, host, phrase, messagetype, glined) VALUES ('%s', '%s', '%s', %d, '%c', %d)", enick, eident, ehost, phrase->id, messagetype, glining);
+    trojanscan_database.glines++;
+    
+    irc_send("%s GL * +%s %d :You (%s!%s@%s) are infected with a trojan (%s/%d), see %s%d for details - banned for %d hours\r\n", mynumeric->content, glinemask, glinetime * 3600, sender->nick, sender->ident, sender->host->name->content, worm->name->content, phrase->id, TROJANSCAN_URL_PREFIX, worm->id, glinetime);
+
+    trojanscan_mainchanmsg("g: *!%s t: %c u: %s!%s@%s%s%s c: %d w: %s%s p: %d f: %d", glinemask, messagetype, sender->nick, sender->ident, sender->host->name->content, messagetype=='N'||messagetype=='M'||messagetype=='P'?" #: ":"", messagetype=='N'||messagetype=='M'||messagetype=='P'?chp->index->name->content:"", usercount, worm->name->content, worm->epidemic?"(E)":"", phrase->id, frequency);
+  }
+}
+            
 void trojanscan_rejoin_channel(void *arg) {
   struct trojanscan_rejoinlist *rj2, *lrj, *rj = (struct trojanscan_rejoinlist *)arg;
   
index c7d4ea8eea258f98328759e159c6312ade1449a2..3ff26be62c7cc00ff013375ebcea79f955bbd3b4 100644 (file)
 #include <ctype.h>
 #include <strings.h>
 
-#define TROJANSCAN_VERSION "2.64"
+#define TROJANSCAN_VERSION "2.68"
 
 #define TROJANSCAN_MAX_HOST_GLINE   5
 
-#define TROJANSCAN_CLONE_MAX        150
-#define TROJANSCAN_WATCHCLONE_MAX   100
+#define TROJANSCAN_CLONE_MAX        75
+#define TROJANSCAN_WATCHCLONE_MAX   75
 #define TROJANSCAN_CLONE_TOTAL TROJANSCAN_CLONE_MAX + TROJANSCAN_WATCHCLONE_MAX
 
 #define TROJANSCAN_POOLSIZE 1000
 #define TROJANSCAN_MINIMUM_HOSTS_BEFORE_POOL 5000 /* 5000 */
 
 #define TROJANSCAN_DEFAULT_MAXCHANS 750
-#define TROJANSCAN_DEFAULT_CYCLETIME 800
+#define TROJANSCAN_DEFAULT_CYCLETIME 1600
 
 #define TROJANSCAN_DEFAULT_MINIMUM_CHANNEL_SIZE 100 /* 100 */
 
 #define TROJANSCAN_NICKCHANGE_ODDS 8
 #define TROJANSCAN_INVISIBLE_ODDS 8
 
-#define TROJANSCAN_DEFAULT_PARTTIME 100
+#define TROJANSCAN_DEFAULT_PARTTIME 150
 #define TROJANSCAN_DEFAULT_MAXUSERS 20
 
 #define TROJANSCAN_POOL_REGENERATION 3600
@@ -73,7 +73,7 @@
 #define TROJANSCAN_IPLEN         20
 
 #define TROJANSCAN_VERSION_DETECT "\001VERSION"
-#define TROJANSCAN_CLONE_VERSION_REPLY "mIRC v6.17 Khaled Mardam-Bey"
+#define TROJANSCAN_DEFAULT_VERSION_REPLY "mIRC v6.31 Khaled Mardam-Bey"
 
 typedef struct trojanscan_clones {
   int              remaining, sitting, index;