#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/rad_assert.h>
#include <sys/stat.h>
#include <ctype.h>
#include <fcntl.h>
void pairlist_free(PAIR_LIST **pl)
{
PAIR_LIST *p, *next;
for (p = *pl; p; p = next) {
if (p->check) pairfree(&p->check);
if (p->reply) pairfree(&p->reply);
next = p->next;
free(p);
}
*pl = NULL;
}
#define FIND_MODE_NAME 0
#define FIND_MODE_REPLY 1
int pairlist_read(const char *file, PAIR_LIST **list, int complain)
{
FILE *fp;
int mode = FIND_MODE_NAME;
char entry[256];
char buffer[8192];
const char *ptr;
VALUE_PAIR *check_tmp;
VALUE_PAIR *reply_tmp;
PAIR_LIST *pl = NULL, *t;
PAIR_LIST **last = &pl;
int lineno = 0;
int old_lineno = 0;
FR_TOKEN parsecode;
char newfile[8192];
if ((fp = fopen(file, "r")) == NULL) {
if (!complain)
return -1;
radlog(L_CONS|L_ERR, "Couldn't open %s for reading: %s",
file, strerror(errno));
return -1;
}
parsecode = T_EOL;
while(fgets(buffer, sizeof(buffer), fp) != NULL) {
lineno++;
if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
fclose(fp);
radlog(L_ERR, "%s[%d]: line too long", file, lineno);
pairlist_free(&pl);
return -1;
}
if (buffer[0] == '#' || buffer[0] == '\n') continue;
ptr = buffer;
while (isspace((int) *ptr)) ptr++;
if (*ptr == '\0') continue;
parse_again:
if(mode == FIND_MODE_NAME) {
if (isspace((int) buffer[0])) {
if (parsecode != T_EOL) {
radlog(L_ERR|L_CONS,
"%s[%d]: Unexpected trailing comma for entry %s",
file, lineno, entry);
fclose(fp);
return -1;
}
continue;
}
ptr = buffer;
getword(&ptr, entry, sizeof(entry));
if (strcasecmp(entry, "$include") == 0) {
while(isspace((int) *ptr))
ptr++;
if (FR_DIR_IS_RELATIVE(ptr)) {
char *p;
strlcpy(newfile, file,
sizeof(newfile));
p = strrchr(newfile, FR_DIR_SEP);
if (!p) {
p = newfile + strlen(newfile);
*p = FR_DIR_SEP;
}
getword(&ptr, p + 1,
sizeof(newfile) - 1 - (p - buffer));
} else {
getword(&ptr, newfile,
sizeof(newfile));
}
t = NULL;
if (pairlist_read(newfile, &t, 0) != 0) {
pairlist_free(&pl);
radlog(L_ERR|L_CONS,
"%s[%d]: Could not open included file %s: %s",
file, lineno, newfile, strerror(errno));
fclose(fp);
return -1;
}
*last = t;
while (*last)
last = &((*last)->next);
continue;
}
check_tmp = NULL;
reply_tmp = NULL;
old_lineno = lineno;
parsecode = userparse(ptr, &check_tmp);
if (parsecode == T_OP_INVALID) {
pairlist_free(&pl);
radlog(L_ERR|L_CONS,
"%s[%d]: Parse error (check) for entry %s: %s",
file, lineno, entry, fr_strerror());
fclose(fp);
return -1;
} else if (parsecode == T_COMMA) {
radlog(L_ERR|L_CONS,
"%s[%d]: Unexpected trailing comma in check item list for entry %s",
file, lineno, entry);
fclose(fp);
return -1;
}
mode = FIND_MODE_REPLY;
parsecode = T_COMMA;
}
else {
if(*buffer == ' ' || *buffer == '\t') {
if (parsecode != T_COMMA) {
radlog(L_ERR|L_CONS,
"%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s",
file, lineno, entry);
fclose(fp);
return -1;
}
parsecode = userparse(buffer, &reply_tmp);
if (parsecode < 1) {
pairlist_free(&pl);
radlog(L_ERR|L_CONS,
"%s[%d]: Parse error (reply) for entry %s: %s",
file, lineno, entry, fr_strerror());
fclose(fp);
return -1;
}
}
else {
size_t entry_len;
char *q;
entry_len = strlen(entry) + 1;
q = rad_malloc(sizeof(*t) + entry_len);
t = (PAIR_LIST *) q;
memset(t, 0, sizeof(*t));
t->check = check_tmp;
t->reply = reply_tmp;
t->lineno = old_lineno;
check_tmp = NULL;
reply_tmp = NULL;
q += sizeof(*t);
memcpy(q, entry, entry_len);
t->name = q;
*last = t;
last = &(t->next);
mode = FIND_MODE_NAME;
if (buffer[0] != 0)
goto parse_again;
}
}
}
if (mode == FIND_MODE_REPLY) {
buffer[0] = 0;
goto parse_again;
}
fclose(fp);
*list = pl;
return 0;
}
#if 0
static void debug_pair_list(PAIR_LIST *pl)
{
VALUE_PAIR *vp;
while(pl) {
printf("Pair list: %s\n", pl->name);
printf("** Check:\n");
for(vp = pl->check; vp; vp = vp->next) {
printf(" ");
fprint_attr_val(stdout, vp);
printf("\n");
}
printf("** Reply:\n");
for(vp = pl->reply; vp; vp = vp->next) {
printf(" ");
fprint_attr_val(stdout, vp);
printf("\n");
}
pl = pl->next;
}
}
#endif