/* Copyright (C) 2000 Stefan Westerfeld stefan@space.twc.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #if TIME_WITH_SYS_TIME # include # include #elif HAVE_SYS_TIME_H # include #else # include #endif #include "md5.h" #include "md5auth.h" #include "debug.h" // MD5_BINARY_LEN is defined in md5.h #define MD5_COOKIE_LEN (MD5_BINARY_LEN*2) #define MD5_MANGLE_LEN (MD5_COOKIE_LEN*2) struct random_info { struct timeval tv; int pid; struct utsname un; char dev_urandom[MD5_BINARY_LEN]; char seed[MD5_COOKIE_LEN+1]; int number; }; static char md5_seed[MD5_COOKIE_LEN+1]; static char md5_cookie[MD5_COOKIE_LEN+1]; static int md5_init = 0; static int md5_random_cookie_number = 0; static char *md5_to_ascii_overwrite(char *md5) { char outascii[MD5_COOKIE_LEN+1]; char *result; int i; // convert to readable text for(i = 0; i < MD5_BINARY_LEN; i++) { sprintf(&outascii[i*2],"%02x",md5[i] & 0xff); } outascii[MD5_COOKIE_LEN] = 0; result = strdup(outascii); // try to zero out traces memset(md5,0,MD5_BINARY_LEN); memset(outascii,0,MD5_COOKIE_LEN); // well, here it is return result; } char *arts_md5_auth_mangle(const char *cookie) { char mangle[MD5_MANGLE_LEN+1]; char out[MD5_BINARY_LEN]; assert(md5_init); // concat the two cookies and mangle them to a new one strncpy(mangle,md5_cookie, MD5_COOKIE_LEN); mangle[MD5_COOKIE_LEN] = 0; strncat(mangle,cookie, MD5_COOKIE_LEN); mangle[MD5_MANGLE_LEN] = 0; arts_md5sum((unsigned char *)mangle,MD5_MANGLE_LEN,out); // try to zero out traces memset(mangle,0,MD5_MANGLE_LEN); return md5_to_ascii_overwrite(out); } char *arts_md5_auth_mkcookie() { struct random_info r; char out[MD5_BINARY_LEN]; int rndfd; memset(&r,0,sizeof(struct random_info)); // collect some "random" system information gettimeofday(&r.tv,0); r.pid = getpid(); uname(&r.un); // linux random device ; if that works, we have good random anyway, the // above are just helpers for the case that it doesn't rndfd = open("/dev/urandom",O_RDONLY); if(rndfd != -1) { read(rndfd,r.dev_urandom,MD5_BINARY_LEN); close(rndfd); } // ensure that two cookies that are requested very shortly after each // other (so that it looks like "at the same time") won't be the same r.number = ++md5_random_cookie_number; // this is some seed from a file which is updated sometimes with a // new "arts_md5_auth_mkcookie()" after initialization strncpy(r.seed,md5_seed,MD5_COOKIE_LEN); // build hash value of all information arts_md5sum((unsigned char *)&r,sizeof(struct random_info),out); // zero out traces and return memset(&r,0,sizeof(struct random_info)); return md5_to_ascii_overwrite(out); } const char *arts_md5_auth_cookie() { assert(md5_init); return md5_cookie; } static int md5_load_cookie(const char *filename, char *cookie) { int fd = open(filename,O_RDONLY); int i; if(fd != -1) { struct stat st; for(i=0;i<5;i++) { fstat(fd,&st); if(st.st_size == MD5_COOKIE_LEN) { lseek(fd, 0, SEEK_SET); if(read(fd,cookie,MD5_COOKIE_LEN) == MD5_COOKIE_LEN) { cookie[MD5_COOKIE_LEN] = 0; close(fd); return 1; } } arts_warning("MCOP: " "authority file has wrong size (just being written?)"); sleep(1); } } return 0; } void arts_md5_auth_init_seed(const char *seedname) { // don't care if it works - no harm is being done if it doesn't md5_load_cookie(seedname,md5_seed); /* * maxage ensures that not everybody will try to update the seed * at the same time, while it will take at most 5 hours between * updates (if there are any initialization calls) */ struct stat st; int maxage = 300 + (getpid() & 0xfff)*4; int lstat_result = lstat(seedname,&st); if(lstat_result != 0 || (time(0) - st.st_mtime) > maxage) { int fd = open(seedname,O_TRUNC|O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR); if(fd != -1) { char *cookie = arts_md5_auth_mkcookie(); write(fd,cookie,strlen(cookie)); memset(cookie,0,strlen(cookie)); free(cookie); close(fd); } } } bool arts_md5_auth_set_cookie(const char *cookie) { if(strlen(cookie) != MD5_COOKIE_LEN) return false; strncpy(md5_cookie,cookie,MD5_COOKIE_LEN); md5_cookie[MD5_COOKIE_LEN] = 0; md5_init = 1; return true; }