elemental-ircd/tools/convertilines.c

628 lines
13 KiB
C

/* tools/convertilines.c
* Copyright (c) 2002 Hybrid Development Team
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1.Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2.Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3.The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id: convertilines.c 6 2005-09-10 01:02:21Z nenolod $
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define BUFSIZE 512
#define FLAGS_RESTRICTED 0x001
#define FLAGS_EXCEEDLIMIT 0x002
#define FLAGS_KLINEEXEMPT 0x004
#define FLAGS_GLINEEXEMPT 0x008
#define FLAGS_NEEDIDENT 0x010
#define FLAGS_NOTILDE 0x020
struct flag_table_struct
{
const char *name;
int flag;
};
static struct flag_table_struct flag_table[] =
{
{ "restricted", FLAGS_RESTRICTED },
{ "exceed_limit", FLAGS_EXCEEDLIMIT },
{ "kline_exempt", FLAGS_KLINEEXEMPT },
{ "gline_exempt", FLAGS_GLINEEXEMPT },
{ "need_ident", FLAGS_NEEDIDENT },
{ "no_tilde", FLAGS_NOTILDE },
{ NULL, 0 }
};
struct AuthBlock
{
struct AuthBlock *next;
char **hostname;
int hostnum;
char *spoof;
char *passwd;
int class;
int flags;
/* indicates one of above */
int special;
int specialk;
};
static struct AuthBlock *auth_spoof = NULL;
static struct AuthBlock *auth_special = NULL;
static struct AuthBlock *auth_passwd = NULL;
static struct AuthBlock *auth_general = NULL;
static struct AuthBlock *auth_restricted = NULL;
static void ConvertConf(FILE* file,FILE *out);
static void set_flags(struct AuthBlock *, const char *, const char *);
static void usage(void);
static char *getfield(char *);
static struct AuthBlock *find_matching_conf(struct AuthBlock *);
static void ReplaceQuotes(char *out, char *in);
static void oldParseOneLine(FILE *out, char *in);
static void write_auth_entries(FILE *out);
static void write_specific(FILE *out, struct AuthBlock *);
static int match(struct AuthBlock *, struct AuthBlock *);
int main(int argc,char *argv[])
{
FILE *in;
FILE *out;
if(argc < 3)
usage();
if((in = fopen(argv[1],"r")) == NULL)
{
fprintf(stderr, "Can't open %s for reading\n", argv[1]);
usage();
}
if((out = fopen(argv[2],"w")) == NULL)
{
fprintf(stderr, "Can't open %s for writing\n", argv[2]);
usage();
}
ConvertConf(in, out);
return 0;
}
void usage()
{
fprintf(stderr, "convertilines conf.old conf.new\n");
exit(-1);
}
/*
* ConvertConf()
* Read configuration file.
*
*
* Inputs - FILE* to config file to convert
* - FILE* to output for new style conf
*
*/
#define MAXCONFLINKS 150
static void ConvertConf(FILE* file, FILE *out)
{
char line[BUFSIZE];
char quotedLine[BUFSIZE];
char* p;
while (fgets(line, sizeof(line), file))
{
if ((p = strchr(line, '\n')))
*p = '\0';
ReplaceQuotes(quotedLine,line);
if(!*quotedLine || quotedLine[0] == '#' || quotedLine[0] == '\n' ||
quotedLine[0] == ' ' || quotedLine[0] == '\t')
continue;
if(quotedLine[0] == '.')
{
char *filename;
char *back;
if(!strncmp(quotedLine+1,"include ",8))
{
if( (filename = strchr(quotedLine+8,'"')) )
filename++;
else
{
fprintf(stderr, "Bad config line: %s", quotedLine);
continue;
}
if((back = strchr(filename,'"')))
*back = '\0';
else
{
fprintf(stderr, "Bad config line: %s", quotedLine);
continue;
}
}
}
/* Could we test if it's conf line at all? -Vesa */
if (quotedLine[1] == ':')
oldParseOneLine(out,quotedLine);
}
fclose(file);
write_auth_entries(out);
fclose(out);
}
/*
* ReplaceQuotes
* Inputs - input line to quote
* Output - quoted line
* Side Effects - All quoted chars in input are replaced
* with quoted values in output, # chars replaced with '\0'
* otherwise input is copied to output.
*/
static void ReplaceQuotes(char* quotedLine,char *inputLine)
{
char *in;
char *out;
static char quotes[] = {
0, /* */
0, /* a */
'\b', /* b */
0, /* c */
0, /* d */
0, /* e */
'\f', /* f */
0, /* g */
0, /* h */
0, /* i */
0, /* j */
0, /* k */
0, /* l */
0, /* m */
'\n', /* n */
0, /* o */
0, /* p */
0, /* q */
'\r', /* r */
0, /* s */
'\t', /* t */
0, /* u */
'\v', /* v */
0, /* w */
0, /* x */
0, /* y */
0, /* z */
0,0,0,0,0,0
};
/*
* Do quoting of characters and # detection.
*/
for (out = quotedLine,in = inputLine; *in; out++, in++)
{
if (*in == '\\')
{
in++;
if(*in == '\\')
*out = '\\';
else if(*in == '#')
*out = '#';
else
*out = quotes[ (unsigned int) (*in & 0x1F) ];
}
else if (*in == '#')
{
*out = '\0';
return;
}
else
*out = *in;
}
*out = '\0';
}
/*
* oldParseOneLine
* Inputs - pointer to line to parse
* - pointer to output to write
* Output -
* Side Effects - Parse one old style conf line.
*/
static void oldParseOneLine(FILE *out,char* line)
{
char conf_letter;
char* tmp;
const char* host_field=NULL;
const char* passwd_field=NULL;
const char* user_field=NULL;
const char* port_field = NULL;
const char* classconf_field = NULL;
int class_field = 0;
tmp = getfield(line);
conf_letter = *tmp;
for (;;) /* Fake loop, that I can use break here --msa */
{
/* host field */
if ((host_field = getfield(NULL)) == NULL)
return;
/* pass field */
if ((passwd_field = getfield(NULL)) == NULL)
break;
/* user field */
if ((user_field = getfield(NULL)) == NULL)
break;
/* port field */
if ((port_field = getfield(NULL)) == NULL)
break;
/* class field */
if ((classconf_field = getfield(NULL)) == NULL)
break;
break;
}
if (!passwd_field)
passwd_field = "";
if (!user_field)
user_field = "";
if (!port_field)
port_field = "";
if (classconf_field)
class_field = atoi(classconf_field);
switch( conf_letter )
{
case 'i':
case 'I':
{
struct AuthBlock *ptr;
struct AuthBlock *tempptr;
tempptr = malloc(sizeof(struct AuthBlock));
memset(tempptr, 0, sizeof(*tempptr));
if(conf_letter == 'i')
{
tempptr->flags |= FLAGS_RESTRICTED;
tempptr->specialk = 1;
}
if(passwd_field && *passwd_field)
tempptr->passwd = strdup(passwd_field);
tempptr->class = class_field;
set_flags(tempptr, user_field, host_field);
/* dont add specials/passworded ones to existing auth blocks */
if((ptr = find_matching_conf(tempptr)))
{
int authindex;
authindex = ptr->hostnum;
ptr->hostnum++;
ptr->hostname = realloc((void *)ptr->hostname, ptr->hostnum * sizeof(void *));
ptr->hostname[authindex] = strdup(tempptr->hostname[0]);
free(tempptr->hostname[0]);
free(tempptr->hostname);
free(tempptr);
}
else
{
ptr = tempptr;
if(ptr->spoof)
{
ptr->next = auth_spoof;
auth_spoof = ptr;
}
else if(ptr->special)
{
ptr->next = auth_special;
auth_special = ptr;
}
else if(ptr->passwd)
{
ptr->next = auth_passwd;
auth_passwd = ptr;
}
else if(ptr->specialk)
{
ptr->next = auth_restricted;
auth_restricted = ptr;
}
else
{
ptr->next = auth_general;
auth_general = ptr;
}
}
}
break;
default:
break;
}
}
static void write_auth_entries(FILE *out)
{
struct AuthBlock *ptr;
for(ptr = auth_spoof; ptr; ptr = ptr->next)
write_specific(out, ptr);
for(ptr = auth_special; ptr; ptr = ptr->next)
write_specific(out, ptr);
for(ptr = auth_passwd; ptr; ptr = ptr->next)
write_specific(out, ptr);
for(ptr = auth_general; ptr; ptr = ptr->next)
write_specific(out, ptr);
for(ptr = auth_restricted; ptr; ptr = ptr->next)
write_specific(out, ptr);
}
static void write_specific(FILE *out, struct AuthBlock *ptr)
{
int i;
int prev = 0;
fprintf(out, "auth {\n");
for(i = 0; i < ptr->hostnum; i++)
fprintf(out, "\tuser = \"%s\";\n", ptr->hostname[i]);
if(ptr->spoof)
fprintf(out, "\tspoof = \"%s\";\n", ptr->spoof);
if(ptr->passwd)
fprintf(out, "\tpassword = \"%s\";\n", ptr->passwd);
if(ptr->flags)
{
fprintf(out, "\tflags = ");
for(i = 0; flag_table[i].flag; i++)
{
if(ptr->flags & flag_table[i].flag)
{
fprintf(out, "%s%s",
prev ? ", " : "",
flag_table[i].name);
prev = 1;
}
}
fprintf(out, ";\n");
}
fprintf(out, "\tclass = \"%d\";\n", ptr->class);
fprintf(out, "};\n");
}
/*
* field breakup for ircd.conf file.
*/
static char *getfield(char *newline)
{
static char *line = NULL;
char *end, *field;
if (newline)
line = newline;
if (line == NULL)
return(NULL);
field = line;
if ((end = strchr(line,':')) == NULL)
{
line = NULL;
if ((end = strchr(field,'\n')) == NULL)
end = field + strlen(field);
}
else
line = end + 1;
*end = '\0';
return(field);
}
struct AuthBlock *find_matching_conf(struct AuthBlock *acptr)
{
struct AuthBlock *ptr;
for(ptr = auth_spoof; ptr; ptr = ptr->next)
{
if(match(ptr, acptr))
return ptr;
}
for(ptr = auth_special; ptr; ptr = ptr->next)
{
if(match(ptr, acptr))
return ptr;
}
for(ptr = auth_passwd; ptr; ptr = ptr->next)
{
if(match(ptr, acptr))
return ptr;
}
for(ptr = auth_restricted; ptr; ptr = ptr->next)
{
if(match(ptr, acptr))
return ptr;
}
for(ptr = auth_general; ptr; ptr = ptr->next)
{
if(match(ptr, acptr))
return ptr;
}
return NULL;
}
static int match(struct AuthBlock *ptr, struct AuthBlock *acptr)
{
if((ptr->class == acptr->class) &&
(ptr->flags == acptr->flags))
{
const char *p1, *p2;
/* check the spoofs match.. */
if(ptr->spoof)
p1 = ptr->spoof;
else
p1 = "";
if(acptr->spoof)
p2 = acptr->spoof;
else
p2 = "";
if(strcmp(p1, p2))
return 0;
/* now check the passwords match.. */
if(ptr->passwd)
p1 = ptr->passwd;
else
p1 = "";
if(acptr->passwd)
p2 = acptr->passwd;
else
p2 = "";
if(strcmp(p1, p2))
return 0;
return 1;
}
return 0;
}
void set_flags(struct AuthBlock *ptr, const char *user_field, const char *host_field)
{
for(; *user_field; user_field++)
{
switch(*user_field)
{
case '=':
if(host_field)
ptr->spoof = strdup(host_field);
ptr->special = 1;
break;
case '-':
ptr->flags |= FLAGS_NOTILDE;
ptr->special = 1;
break;
case '+':
ptr->flags |= FLAGS_NEEDIDENT;
ptr->specialk = 1;
break;
case '^': /* is exempt from k/g lines */
ptr->flags |= FLAGS_KLINEEXEMPT;
ptr->special = 1;
break;
case '>':
ptr->flags |= FLAGS_EXCEEDLIMIT;
ptr->special = 1;
break;
case '_':
ptr->flags |= FLAGS_GLINEEXEMPT;
ptr->special = 1;
break;
case '!':
case '$':
case '%':
case '&':
case '<':
break;
default:
{
int authindex;
authindex = ptr->hostnum;
ptr->hostnum++;
ptr->hostname = realloc((void *)ptr->hostname, ptr->hostnum * sizeof(void *));
/* if the IP field contains something useful, use that */
if(strcmp(host_field, "NOMATCH") && (*host_field != 'x') &&
strcmp(host_field, "*") && !ptr->spoof)
ptr->hostname[authindex] = strdup(host_field);
else
ptr->hostname[authindex] = strdup(user_field);
return;
}
}
}
}