/* klineParse.c * 1.0 17Dec98 Darkshde -- Initial bug ridden release * 2.0 07Jan99 Darkshde -- added redundant kline checking * 2.1 11Jan99 Darkshde -- added -f made verbose display optional with -v * * This program will take a kline.conf and remove duplicate and redundant * entries from it, creating a kline.conf.parsed file * $Id: klineParse.c,v 1.3 2005/08/27 16:23:50 jpinto Exp $ */ #define kParseVer "2.12" #define KLINEFILE "kline.conf" #include #include #include #include typedef struct { char userid[15]; char domain[128]; char klinedata[256]; char valid; struct KlineList *next; struct KlineList *previous; } KlineList; KlineList *AddKline (KlineList *, KlineList *); KlineList *RemoveKline (KlineList *); KlineList *Read_Kline_File (char *); int Array_Search (KlineList *, KlineList *, short); int RemoveDupes (char *, char *); int RemoveRedundant (char *, char *, short); int strToLower(unsigned char *); void ClearKlines (KlineList * ); int main (int argc, char *argv[]) { char *parsedFile, *klineFile, appName[128]; short dupeCheck, altInput, altOutput, showMatches; dupeCheck = altInput = altOutput = showMatches =0; memset(appName,'\0',128); if (argc > 1) { if (argv[1][0] == '-') { if (strspn(argv[1],"-dvf\0") != strlen(argv[1])) { goto paramReturn; } if (strchr(argv[1], 'f')) { if (argc > 3) { parsedFile = (char *) malloc(strlen(argv[3])+1); strcpy(parsedFile,argv[3]); altOutput =1; } if (argc >2) { klineFile = (char *) malloc(strlen(argv[2])+1); strcpy(klineFile,argv[2]); altInput =1; } } if (strchr(argv[1], 'v')) { showMatches = 1; } if (strchr (argv[1], 'd')) { dupeCheck = 1; } } else { goto paramReturn; } } if (!altOutput) { parsedFile = (char *) malloc(strlen(KLINEFILE)+8); strcpy(parsedFile,KLINEFILE); strcat(parsedFile,".parsed"); } if (!altInput) { klineFile = (char *) malloc(strlen(KLINEFILE)); strcpy(klineFile,KLINEFILE); } if (dupeCheck) { if (!RemoveDupes(klineFile,"kline.conf.parsed.tmp")) { RemoveRedundant("kline.conf.parsed.tmp",parsedFile, showMatches); remove("kline.conf.parsed.tmp"); } else { printf("\n"); goto paramReturn; } } else { if (RemoveRedundant(klineFile,parsedFile, showMatches)) { printf("\n"); goto paramReturn; } } printf("\nklineParse %s has finished mangling %s.\n",kParseVer, klineFile); printf("The new version has been saved as %s.\n",parsedFile); printf("It is a good idea to diff the two files to ensure no insane " "changes were made.\n\n"); free(parsedFile); free(klineFile); return (EXIT_SUCCESS); paramReturn: if (strchr(argv[0],'/')) { strcat(appName, strrchr(argv[0],'/')+1); } else { strcpy(appName,argv[0]); } printf ("usage: %s [-dfv] [] []\n", appName); printf (" -d remove duplicate consecutive klines\n"); printf (" -v verbose display during redundant search\n"); printf (" -f use alterate file names, instead of kline.conf and "); printf ("kline.conf.parsed\n "); if (altOutput) { free(parsedFile); } if (altInput) { free(klineFile); } return (EXIT_FAILURE); } /* * This function will search out klines that are redundant to wider matching * klines. In other words, if you had previously klined *userid@*domain.com, * *@machine.domain.com, ~*@*.domain.com, and then finally *@*domain.com, this * code will remove all the klines except *@*domain.com. * */ int RemoveRedundant (char *KlineFile, char *parsedFile, short showMatches) { KlineList *pKlines, anotherKline, *pKlineList; FILE *outFile; pKlines = NULL; pKlines = Read_Kline_File(KlineFile); if (pKlines == NULL) { return(EXIT_FAILURE); } pKlineList = pKlines; while (pKlines != NULL) { if (pKlines->valid == 1 && (!strcmp(pKlines->userid,"*") && pKlines->domain[0] == '*') || !strcmp(pKlines->domain,"*") || (isdigit(pKlines->domain[0]) && strrchr(pKlines->domain,'*'))){ pKlines->valid == 3; Array_Search(pKlines,pKlineList, showMatches); pKlines->valid == 1; } pKlines = (KlineList *) pKlines->next; } pKlines = pKlineList; outFile = fopen(parsedFile, "w+"); if (outFile == NULL) { printf("Could not open %s for writing.\n",parsedFile); return EXIT_FAILURE; } while (pKlines != NULL) { if (pKlines->valid >= 1) { fputs(pKlines->klinedata, outFile); } pKlines = (KlineList *) pKlines->next; } fclose(outFile); pKlines = pKlineList; ClearKlines (pKlines); return (EXIT_SUCCESS); } /* This was the original (1.0) code, which has now be reduced to a command line * option, since this problem does not appear to be widespread. You only need * to use this if the the following two commands don't return the same value, or * if when doing an unkline on the server you see (2 matches) or some number * other than 1. This procedure only removes the duplicates if they are * consequtive. * * grep K: kline.conf | sort -n | uniq | wc -l * grep K: kline.conf | wc -l */ int RemoveDupes (char *KlineFile, char *parsedFile) { FILE *inFile, *outFile; char sLine1[512], sLine2[512]; char domain1[128],domain2[128],userid1[15],userid2[15]; memset(sLine1,'\0',512); memcpy(sLine2,sLine1,512); memset(domain1,'\0',128); memcpy(domain2,domain1,128); memset(userid1,'\0',15); memcpy(userid2,userid1,15); inFile = fopen(KlineFile, "r+"); if (inFile == NULL) { printf("No %s found\n",KlineFile); return EXIT_FAILURE; } outFile = fopen(parsedFile, "w+"); if (outFile == NULL) { fclose(inFile); printf("Could not open %s.parsed for writing.\n",KlineFile); return EXIT_FAILURE; } if (fgets(sLine1,512,inFile) == NULL) { fclose(inFile); printf("%s is empty.\n",KlineFile); return EXIT_FAILURE; } while (!feof(inFile)) { fgets(sLine2,512,inFile); if (sLine1[0] == 'K' && sLine2[0] == 'K') { strncat(domain1, sLine1+2, strchr(sLine1+2,':')-sLine1-2); strcat(userid1, strrchr(sLine1,':')+1); strncat(domain2, sLine2+2, strchr(sLine2+2,':')-sLine2-2); strcat(userid2, strrchr(sLine2,':')+1); if (strcmp(domain1,domain2) != 0 || strcmp(userid1,userid2) != 0) { fputs(sLine1, outFile); } domain1[0] = userid1[0] = domain2[0] = userid2[0] = '\0'; } else { fputs(sLine1, outFile); } strcpy(sLine1, sLine2); memset(sLine2,'\0',512); } fputs(sLine2, outFile); fclose(inFile); fclose(outFile); return EXIT_SUCCESS; } KlineList *Read_Kline_File (char *KlineFile) { KlineList *pNewKlines, aKline; FILE *inFile, *outFile; char sLine1[256], sLine2[256]; char domain1[128],domain2[128],userid1[15],userid2[15]; char *endOffset; pNewKlines = NULL; memset(sLine1,'\0',256); memcpy(sLine2,sLine1,256); memset(domain1,'\0',128); memcpy(domain2,domain1,128); memset(userid1,'\0',15); memcpy(userid2,userid1,15); inFile = fopen(KlineFile, "r+"); if (inFile == NULL) { printf("No %s found\n",KlineFile); return NULL; } while (!feof(inFile)) { fgets(sLine1,256,inFile); memset(&aKline,'\0',sizeof(aKline)); if (sLine1[0] == 'K') { strncat(aKline.domain, sLine1+2, strchr(sLine1+2,':')-sLine1-2); strToLower(aKline.domain); endOffset = strrchr(sLine1,':')+1; strncat(aKline.userid, endOffset, strrchr(sLine1,'\n')-endOffset); strToLower(aKline.userid); /* the kline.conf I developed this for had about 60 *~*@ klines... * This will change them to ~* for matching purposes only, so they * may well survive if you don't have ~*@* klined. */ if(!strcmp(aKline.userid,"*~*")) { strcpy(aKline.userid,"~*"); } strcpy(aKline.klinedata,sLine1); aKline.valid = 1; aKline.next = NULL; aKline.previous = NULL; pNewKlines = AddKline(pNewKlines,&aKline); } else { memset(aKline.userid,'\0',15); memset(aKline.domain,'\0',128); strcpy(aKline.klinedata,sLine1); aKline.valid = 2; aKline.next = NULL; aKline.previous = NULL; pNewKlines = AddKline(pNewKlines,&aKline); } memset(sLine1,'\0',256); } fclose(inFile); return pNewKlines; } int Array_Search (KlineList *pTargKline, KlineList *pKline, short showMatches) { KlineList *pKlineTop = pKline; char stuff[128], stuff2[128]; while (pKline != NULL) { if (pKline->valid == 1) { if (Tcl_StringMatch(pKline->domain,pTargKline->domain) && Tcl_StringMatch(pKline->userid,pTargKline->userid) && strcmp(pTargKline->klinedata,pKline->klinedata)) { pKline->valid = 0; if (showMatches) { printf("%s@%s ",strcpy(stuff,pKline->userid), strcpy(stuff2,pKline->domain)); printf("is redundant to %s@%s\n",strcpy(stuff, pTargKline->userid),strcpy(stuff2,pTargKline->domain)); } if (pKline->previous != NULL) { pKline = (KlineList *) pKline->previous; if (pKline->klinedata[0] == '#') { pKline->valid = 0; } pKline = (KlineList *) pKline->next; } } else if (Tcl_StringMatch(pTargKline->domain,pKline->domain) && Tcl_StringMatch(pTargKline->userid,pKline->userid) && strcmp(pTargKline->klinedata,pKline->klinedata)) { pTargKline->valid = 0; if (showMatches) { printf("%s@%s ",strcpy(stuff,pTargKline->userid), strcpy(stuff2,pTargKline->domain)); printf("is redundant to %s@%s\n",strcpy(stuff, pKline->userid),strcpy(stuff2,pKline->domain)); } Array_Search(pKline,pKlineTop, showMatches); } } pKline = (KlineList *) pKline->next; } } KlineList *AddKline (KlineList *pKline, KlineList *pKlineData) { KlineList *pCurrentKline, *pOrigKline = pKline; if (pKline != NULL) { if (pKline->previous != NULL) { pKline = (KlineList *) pKline->previous; } pCurrentKline = pKline; pKline->next = (struct KlineList *) malloc (sizeof (KlineList)); pKline = (KlineList *) pKline->next; pKline->next = NULL; *pKline = *pKlineData; pKline->previous = (struct KlineList *) pCurrentKline; pOrigKline->previous = (struct KlineList *) pKline; return pOrigKline; } else { pKline = ( KlineList *) malloc (sizeof (KlineList)); pKline->next = NULL; pKline->previous = NULL; *pKline = *pKlineData; return pKline; } } KlineList *RemoveKline (KlineList *pKline) { KlineList *tempp; tempp = (KlineList *) pKline->next; free (pKline); return tempp; } void ClearKlines (KlineList * listpointer) { while (listpointer != NULL) { listpointer = RemoveKline (listpointer); } } int strToLower(unsigned char *aString) { short i =0; while (aString[i]) { if (isupper(aString[i])) { aString[i] = tolower(aString[i]); } i++; } return 1; } /* The following function is taken from the TCL soure code distribution, * specifically the file tclUtil.c, I did this because most ircd boxes do * not have TCL installed, and it's likely they don't want to install it. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * The file "license.terms" can be found in the tcl source code distribution * at ftp://ftp.scriptics.com/pub/tcl/tcl7_6/tcl7.6p2.tar.gz * */ int Tcl_StringMatch(string, pattern) register char *string; /* String. */ register char *pattern; /* Pattern, which may contain * special characters. */ { char c2; while (1) { /* See if we're at the end of both the pattern and the string. * If so, we succeeded. If we're at the end of the pattern * but not at the end of the string, we failed. */ if (*pattern == 0) { if (*string == 0) { return 1; } else { return 0; } } if ((*string == 0) && (*pattern != '*')) { return 0; } /* Check for a "*" as the next pattern character. It matches * any substring. We handle this by calling ourselves * recursively for each postfix of string, until either we * match or we reach the end of the string. */ if (*pattern == '*') { pattern += 1; if (*pattern == 0) { return 1; } while (1) { if (Tcl_StringMatch(string, pattern)) { return 1; } if (*string == 0) { return 0; } string += 1; } } /* Check for a "?" as the next pattern character. It matches * any single character. */ if (*pattern == '?') { goto thisCharOK; } /* Check for a "[" as the next pattern character. It is followed * by a list of characters that are acceptable, or by a range * (two characters separated by "-"). */ if (*pattern == '[') { pattern += 1; while (1) { if ((*pattern == ']') || (*pattern == 0)) { return 0; } if (*pattern == *string) { break; } if (pattern[1] == '-') { c2 = pattern[2]; if (c2 == 0) { return 0; } if ((*pattern <= *string) && (c2 >= *string)) { break; } if ((*pattern >= *string) && (c2 <= *string)) { break; } pattern += 2; } pattern += 1; } while (*pattern != ']') { if (*pattern == 0) { pattern--; break; } pattern += 1; } goto thisCharOK; } /* If the next pattern character is '/', just strip off the '/' * so we do exact matching on the character that follows. */ if (*pattern == '\\') { pattern += 1; if (*pattern == 0) { return 0; } } /* There's no special character. Just make sure that the next * characters of each string match. */ if (*pattern != *string) { return 0; } thisCharOK: pattern += 1; string += 1; } }