#include #include #include #include #include #include #include "userfirewall.m" #include "userfirewall.h" #include static char misc_tohex(unsigned n) { if (n >= 10){ return n-10+'A'; }else{ return n+'0'; } } /* Compute the SHA digest of a string and store it in hex form in res */ void misc_sha ( const char *s, SSTRING &res) { unsigned char tmp[SHA_DIGEST_LENGTH]; SHA1 ((const unsigned char*)s,strlen(s),tmp); char tmphex[SHA_DIGEST_LENGTH*2+1]; for (int i=0; i>4); tmphex[i*2+1] = misc_tohex(byte&0xf); } tmphex[2*SHA_DIGEST_LENGTH] = '\0'; res.setfrom (tmphex); } static const char *statefile = "/var/run/userfirewall.state"; static const char *statefile_tmp = "/var/run/userfirewall.state-TMP"; static const char *lockfile = "/var/run/userfirewall.lock"; static FILE *f_lock=NULL; int misc_lock() { int ret = -1; f_lock = fopen (lockfile,"w"); if (f_lock != NULL){ ret = flock(fileno(f_lock),LOCK_EX); if (ret == -1) misc_unlock(); } return ret; } int misc_unlock() { if (f_lock != NULL){ fclose (f_lock); f_lock = NULL; } return 0; } /* Update, delete or add a record. The state file maintains a reference count for logins. So multiple logins must be undone by multiple logouts. This function is called both by login(addcnt=1) and logout (addcnt=-1) This function returns -1 if any error while updating 0 no record changed 1 one record changed, but only the reference count 2 The content of a record change, or a record was deleted or added */ static int misc_update( int addcnt, const char *logid, const char *logip, const char *loggroups) { int ret = -1; if (misc_lock()!=-1){ FILE *fout = fopen (statefile_tmp,"w"); if (fout != NULL){ FILE *fin = fopen (statefile,"r"); ret = 0; if (fin != NULL){ char line[1000]; bool anyuser = strcmp(logid,"-")==0; bool anyip = strcmp(logip,"-")==0; while (fgets(line,sizeof(line)-1,fin)!=NULL){ strip_end (line); char id[100],ip[100]; const char *pt = str_copyword (id,line); pt = str_copyword (ip,pt); pt = str_skip(pt); int count = atoi(pt); pt = str_skipdig(pt); const char *groups = str_skip(pt); if (count > 0){ if ((strcmp(logid,id)!=0 && !anyuser) || (strcmp(logip,ip)!=0 && !anyip)){ fprintf (fout,"%s\n",line); }else{ // Ok we have a match count += addcnt; if (count > 0){ if (addcnt > 0){ ret = strcmp(loggroups,groups)==0 ? 1 : 2; fprintf (fout,"%s\t%s\t%d\t%s\n" ,id,ip,count,loggroups); }else{ fprintf (fout,"%s\t%s\t%d\t%s\n" ,id,ip,count,groups); ret = 1; } }else{ // Record is deleted ret = 2; } } } } fclose (fin); } if (ret == 0 && addcnt > 0){ fprintf (fout,"%s\t%s\t%d\t%s\n" ,logid,logip,addcnt,loggroups); ret = 2; } fclose (fout); rename (statefile_tmp,statefile); } misc_unlock(); } return ret; } int misc_logout(const char *logid, const char *logip) { return misc_update (-1,logid,logip,""); } int misc_login ( const char *id, const char *ip, const char *groups) { return misc_update (1,id,ip,groups); #if 0 misc_logout ("-",ip); if (misc_lock()!=-1){ FILE *fout = fopen (statefile,"a"); if (fout == NULL){ xconf_error (MSG_U(E_OPENSTATE,"Can't update state file")); }else{ fprintf (fout,"%s\t%s\t%s\n",id,ip,groups); fclose (fout); } misc_unlock(); } #endif } /* A little line str_splitline, except that the delimitor occurs once at the end of a field. So if two delimiter occurs together, this means an empty field. */ int misc_splitline( const char *line, const char delim, SSTRINGS &tb) { int ret = 0; while (*line != '\0'){ const char *start = line; while (*line != '\0' && *line != delim) line++; SSTRING *s = new SSTRING; int len = (int)(line-start); if (len > 0) s->setfrom (start,len); ret++; tb.add (s); if (*line == delim){ line++; if (*line == '\0'){ tb.add (new SSTRING); ret++; } } } return ret; }