/* * Copyright (c) 1996-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ #include #include #include #include #include #include "firewall.h" #include "auth.h" #include "authdb.h" #ifdef AUTHPROTO_SNK #ifdef OpenBSD #include "ssl/des.h" #else #include "openssl/des.h" #endif static char* moduleId ATTR_UNUSED = "$Id: snk.c,v 1.7 2007/09/10 02:49:13 arkenoi Exp $"; extern long randomnumber(); extern size_t strlcat(char*,const char*,size_t); extern size_t strlcpy(char*,const char*,size_t); static int challenged = 0; static char challbuf[32]; int snkchallng(user,buf,bs) char *user; char *buf; int bs; { challenged = 1; strlcpy(buf,"SNK Challenge \"",MAX_STR); snprintf(challbuf,sizeof(challbuf),"%6.6lu",randomnumber() % 999999); strlcat(buf,challbuf,MAX_STR); strlcat(buf,"\": ",MAX_STR); return(0); } /* is this ugly or what? it's late and I don't feel clever */ static int make_key_sched(s,k) char *s; des_cblock k; { unsigned int k0; unsigned int k1; unsigned int k2; unsigned int k3; unsigned int k4; unsigned int k5; unsigned int k6; unsigned int k7; int x; x = sscanf(s, "%o %o %o %o %o %o %o %o", &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7); if(x != 8) return(1); k[0] = k0; k[1] = k1; k[2] = k2; k[3] = k3; k[4] = k4; k[5] = k5; k[6] = k6; k[7] = k7; return(0); } int snkverify(user,pass,ap,rbuf) char *user; char *pass; Auth *ap; char *rbuf; { des_key_schedule keysched; des_cblock kblock; char buf[12]; char cbuf[12]; int i; int j; unsigned long kval = 0; strlcpy(rbuf,"Permission Denied.",MAX_STR); if(!challenged) return(1); challenged = 0; /* lowercase the response code, in case it's hex */ for(i=0; pass[i]; i++) if(isupper(pass[i])) pass[i] = tolower(pass[i]); /* set up a key from the shared secret */ if(make_key_sched(ap->pw,kblock)) { strlcpy(rbuf,"Cannot decode user secret key",MAX_STR); return(1); } des_set_key(&kblock,keysched); /* zeroize the entire buffer */ for(i = 0; i < 9; i++) buf[i] = '\0'; strncpy(buf,challbuf,8); /* push it through the rotating knives */ des_ecb_encrypt((des_cblock*) buf,(des_cblock*) cbuf, keysched,DES_ENCRYPT); /* pull some bits out of the ciphertext into a long */ for(i=0; i<4; i++) for(j = 0; j < 8; j++) kval = (kval << 1) | ((cbuf[i] >> (7 - j)) & 1); /* crunch it into a hex string */ snprintf(buf,sizeof(buf),"%08lx",kval); if(!strcmp(pass,buf)) { strlcpy(rbuf,"ok",MAX_STR); return(0); } /* crunch hex to decimal and try that */ for(i=0; buf[i]; i++) if(buf[i] == 'a' || buf[i] == 'b' || buf[i] == 'c') buf[i] = '2'; else if(buf[i] == 'd' || buf[i] == 'e' || buf[i] == 'f') buf[i] = '3'; if(strcmp(pass,buf)) return(1); strlcpy(rbuf,"ok",MAX_STR); return(0); } int snkset(user,pass,ap,rbuf) char *user; char *pass; Auth *ap; char *rbuf; { des_cblock kblock; if(make_key_sched(pass,kblock)) { strlcpy(rbuf,"Cannot decode user secret key",MAX_STR); return(0); } if(strlen(pass) >= AUTH_PWSIZ) { strlcpy(rbuf,"Secret key too long",MAX_STR); return(0); } strlcpy(ap->pw,pass,MAX_STR); if(auth_dbputu(user,ap) == 0) strlcpy(rbuf,"Secret key changed",MAX_STR); else strlcpy(rbuf,"Database error.",MAX_STR); return(0); } #endif