/* * kakumei_session.c * * Session handling for kakumei. * * Author: Dario Rodriguez dario@softhome.net * This program is licensed under the terms of the Affero GPL v1+ */ #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> #include <fcntl.h> #include <time.h> #include <mhash.h> #include "loglib.h" #include "kakumei.h" #include "kakumei_session.h" char * session_new(kakumei *ka, char *user, char *session, int sessionsize, char *authid, int authidsize) { static int init=0; MHASH td; struct timeval tv; struct timezone tz; int i,k; long n; char c; char binhash[32]; char filename[1024]; int len; int fd; int authidlen; char oldsession[SESSIONSIZE+1]; if(ka==NULL || user==NULL || session==NULL || sessionsize<(SESSIONSIZE+1) || authidsize<(AUTHIDSIZE+1)|| kakumei_uservalid(ka,user)!=0) return(NULL); if(init==0) { gettimeofday(&tv,&tz); srandom(tv.tv_sec+getpid()+tv.tv_usec); init=1; } /* generate a not-entirely-trivial-to-guess hash */ if((td=mhash_init(MHASH_SHA256))==MHASH_FAILED) return(NULL); gettimeofday(&tv,&tz); mhash(td,&tv,sizeof(tv)); mhash(td,user,strlen(user)); for(i=0;i<20;i++) { n=random(); mhash(td,&n,sizeof(n)); } mhash_deinit(td,&binhash); for(i=0;i<sizeof(binhash) && i<(SESSIONSIZE/2);i++) { c=(((unsigned char *)binhash)[i]>>4); c=(c>=10)?(c-10+'a'):c+'0'; session[i<<1]=c; c=(((unsigned char *)binhash)[i]&0xf); c=(c>=10)?(c-10+'a'):c+'0'; session[(i<<1)+1]=c; } session[SESSIONSIZE]='\0'; for(k=0;i<sizeof(binhash) && k<(AUTHIDSIZE/2);i++,k++) { c=(((unsigned char *)binhash)[i]>>4); c=(c>=10)?(c-10+'a'):c+'0'; authid[k<<1]=c; c=(((unsigned char *)binhash)[i]&0xf); c=(c>=10)?(c-10+'a'):c+'0'; authid[(k<<1)+1]=c; } authid[AUTHIDSIZE]='\0'; /* save the hash */ mkdir(DATADIR,0700); mkdir(SESSIONSDIR,0700); snprintf(filename,sizeof(filename)-1,"%s/%s",SESSIONSDIR,session); filename[sizeof(filename)-1]='\0'; if((fd=open(filename,O_WRONLY|O_TRUNC|O_CREAT,0600))==-1) return(NULL); len=strlen(user); authidlen=strlen(authid); if(write(fd,user,len)!=len || write(fd,"\n",1)!=1 || write(fd,authid,authidlen)!=authidlen) { close(fd),fd=-1; return(NULL); } close(fd),fd=-1; /* delete the previous session of the user */ mkdir(DATADIR,0700); mkdir(USERSDIR,0700); snprintf(filename,sizeof(filename)-1,"%s/%s/session",USERSDIR,user); filename[sizeof(filename)-1]='\0'; if((fd=open(filename,O_RDONLY))!=-1) { memset(oldsession,0,sizeof(oldsession)); read(fd,oldsession,sizeof(oldsession)-1); close(fd),fd=-1; session_del(ka,oldsession); } /* write the current session */ if((fd=open(filename,O_WRONLY|O_TRUNC|O_CREAT,0600))!=-1) { write(fd,session,strlen(session)); close(fd),fd=-1; } /* success */ return(session); } char * session_check(kakumei *ka, char *session, char *authid, char *user, int usersize) { int i; int fd; char filename[1024]; char sesbuf[MAXUSERSIZE+AUTHIDSIZE+2]; char *sep; int len; if(ka==NULL || session==NULL || session[0]=='\0' || user==NULL || usersize<(MAXUSERSIZE+1)) return(NULL); for(i=0;session[i]!='\0';i++) { if(!(session[i]>='0' && session[i]<='9') && !(session[i]>='a' && session[i]<='f')) { return(NULL); } } snprintf(filename,sizeof(filename)-1,"%s/%s",SESSIONSDIR,session); filename[sizeof(filename)-1]='\0'; if((fd=open(filename,O_RDONLY))==-1) return(NULL); memset(sesbuf,0,sizeof(sesbuf)); read(fd,sesbuf,sizeof(sesbuf)); sesbuf[sizeof(sesbuf)-1]='\0'; close(fd),fd=-1; if((sep=strchr(sesbuf,'\n'))==NULL) return(NULL); /* invalid format */ *sep='\0'; memset(user,0,usersize); strncpy(user,sesbuf,usersize); user[usersize-1]='\0'; /* position sep to authid and trim the last '\n' if it exists */ sep++; if((len=strlen(sep))>0 && sep[len-1]=='\n') sep[len-1]='\0'; /* check validity */ if(strcmp(authid,sep)!=0) return(NULL); /* authid doesn't match */ if(kakumei_uservalid(ka,user)!=0) return(NULL); /* invalid user */ return(user); } int session_del(kakumei *ka, char *session) { int i; char filename[1024]; if(ka==NULL || session==NULL || session[0]=='\0') return(-1); for(i=0;session[i]!='\0';i++) { if(!(session[i]>='0' && session[i]<='9') && !(session[i]>='a' && session[i]<='f')) { return(-1); } } snprintf(filename,sizeof(filename)-1,"%s/%s",SESSIONSDIR,session); filename[sizeof(filename)-1]='\0'; unlink(filename); return(0); }