This repository has been archived on 2025-02-12. You can view files and clone it, but cannot push or open issues or pull requests.
NeoStats-NeoIRCd/iauth/source/conf.c
2002-08-13 14:45:13 +00:00

695 lines
13 KiB
C

/************************************************************************
* IRC - Internet Relay Chat, iauth/conf.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: conf.c,v 1.2 2002/08/13 14:45:09 fishwaldo Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "auth.h"
#include "class.h"
#include "conf.h"
#include "iauth.h"
#include "log.h"
#include "match.h"
#include "misc.h"
#include "mtree.h"
#include "setup.h"
/*
* Configuration file
*/
char *ConfigFile = CONFFILE;
/*
* List of banned users (K-lines)
*/
struct ServerBan *ServerBanList = NULL;
/*
* List of allowed users
*/
struct Iline *IlineList = NULL;
/*
* List of listen ports
*/
struct Port *PortList = NULL;
/*
* List of nickname quarantines
*/
struct Quarantine *QuarantineList = NULL;
static int ParseConfig(char *filename);
static char *getfield (char *newline);
static void GetUserAndHost(char **user, char **host);
static struct ServerBan *AddServerBan(char *user, char *host,
char *reason, time_t expires);
static void DeleteServerBan(struct ServerBan *kptr);
static char *ParseIlineFlags(struct Iline *iptr, char *user);
static struct Iline *AddIline(char *spoofhost, char *password,
char *user, char *host, int class);
static void AddPort(int portnum);
static void AddQuarantine(char *nick, char *reason, char *user, char *host);
/*
ParseConfig()
Parse configuration file 'filename'
Return: 1 if successful
0 if unsuccessful
*/
static int
ParseConfig(char *filename)
{
FILE *fp;
char buffer[BUFSIZE];
char *key;
int linenum;
if (!(fp = fopen(filename, "r")))
{
log(L_ERROR,
"ParseConfig(): Unable to open configuration file: %s",
filename);
return 0;
}
linenum = 0;
while (fgets(buffer, sizeof(buffer) - 1, fp) && ++linenum)
{
if (*buffer == '#')
continue; /* comment */
if (!(key = getfield(buffer)))
continue;
switch (*key)
{
/*
* K-lines (bans)
*/
case 'k':
case 'K':
{
char *user,
*host,
*reason;
user = getfield(NULL);
reason = getfield(NULL);
if (!user || !reason)
{
log(L_ERROR,
"%s:%d Invalid configuration line",
filename,
linenum);
continue;
}
GetUserAndHost(&user, &host);
AddServerBan(user, host, reason, 0);
break;
} /* case 'K' */
/*
* I-lines (authorization)
*/
case 'i':
case 'I':
{
char *spoofhost,
*password,
*user,
*host,
*class;
spoofhost = getfield(NULL);
password = getfield(NULL);
user = getfield(NULL);
(void) getfield(NULL); /* unused field */
class = getfield(NULL);
if (!user || !class)
{
log(L_ERROR,
"%s:%d Invalid configuration line",
filename,
linenum);
continue;
}
GetUserAndHost(&user, &host);
AddIline(spoofhost, password, user, host, atoi(class));
break;
} /* case 'I' */
/*
* Y-lines (class lines)
*/
case 'y':
case 'Y':
{
break;
} /* case 'Y' */
/*
* P-lines (listen ports)
*/
case 'p':
case 'P':
{
char *port;
port = getfield(NULL);
if (!port)
{
log(L_ERROR,
"%s:%d Invalid configuration line",
filename,
linenum);
continue;
}
AddPort(atoi(port));
break;
} /* case 'P' */
/*
* Nickname quarantine lines
*/
case 'q':
case 'Q':
{
char *nick,
*reason,
*user,
*host;
nick = getfield(NULL);
reason = getfield(NULL);
user = getfield(NULL);
if (!nick)
{
log(L_ERROR,
"%s:%d Invalid configuration line",
filename,
linenum);
continue;
}
if (user)
GetUserAndHost(&user, &host);
AddQuarantine(nick, reason, user, host);
} /* case 'Q' */
} /* switch (*key) */
}
fclose(fp);
return 1;
} /* ParseConfig() */
/*
LoadConfig()
Call ParseConfig() to load configuration file
*/
void
LoadConfig()
{
if (!ParseConfig(ConfigFile))
{
fprintf(stderr,
"Unable to parse configuration file: %s\n",
ConfigFile);
exit (-1);
}
} /* LoadConfig() */
/*
getfield()
Get next field separated by a : in the line
*/
static char *
getfield (char *newline)
{
static char *line = NULL;
char *end, *field;
if (newline)
line = newline;
if (!line)
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';
if (strlen(field))
return (field);
else
return (NULL);
} /* getfield() */
/*
GetUserAndHost()
Called from ParseConfig() when a possible string fitting
"user@host" is read. Set the 'user' variable to "user" and
the 'host' variable to "host".
Assume 'user' initially points to the entire string "user@host".
*/
static void
GetUserAndHost(char **user, char **host)
{
char *ch;
if ((ch = strchr(*user, '@')))
{
*ch++ = '\0';
*host = ch;
}
else
{
*host = *user;
*user = NULL;
}
} /* GetUserAndHost() */
/*
AddServerBan()
Add a kline to the list with the given information. Return
pointer to new kline.
*/
static struct ServerBan *
AddServerBan(char *user, char *host, char *reason, time_t expires)
{
struct ServerBan *ptr;
ptr = (struct ServerBan *) MyMalloc(sizeof(struct ServerBan));
memset(ptr, 0, sizeof(struct ServerBan));
if (user)
ptr->username = MyStrdup(user);
else
ptr->username = MyStrdup("*");
ptr->hostname = MyStrdup(host);
if (reason)
ptr->reason = MyStrdup(reason);
else
ptr->reason = MyStrdup("No reason");
ptr->expires = expires;
ptr->prev = NULL;
ptr->next = ServerBanList;
if (ptr->next)
ptr->next->prev = ptr;
ServerBanList = ptr;
TreeAddKline(ptr);
return (ptr);
} /* AddServerBan() */
/*
DeleteServerBan()
Remove kptr from the kline list
*/
static void
DeleteServerBan(struct ServerBan *kptr)
{
} /* DeleteServerBan() */
/*
FindServerBan()
Determine if 'user' and 'host' match a kline, if so,
return a pointer to it.
*/
struct ServerBan *
FindServerBan(char *user, char *host)
{
struct ServerBan *tmp;
tmp = (struct ServerBan *) SearchKlineTree(user, host);
if (tmp)
fprintf(stderr, "FOUND KLINE: [%s@%s]\n", tmp->username, tmp->hostname);
return (tmp);
#if 0
for (tmp = ServerBanList; tmp; tmp = tmp->next)
{
if (match(tmp->username, user) && match(tmp->hostname, host))
return (tmp);
}
return (NULL);
#endif /* 0 */
} /* FindServerBan() */
/*
ParseIlineFlags()
Determine if iptr has any special flags in it's user field.
If so, update iptr->flags accordingly.
Valid flags:
= : spoof their ip
! : limit to 1 client per ip
- : don't give them a ~ even if they have no identd
+ : don't let them connect unless they have an ident
$ :
% :
^ : user is exempt from K/G lines
> : user is also exempt from connection limits
*/
static char *
ParseIlineFlags(struct Iline *iptr, char *user)
{
while (*user)
{
switch (*user)
{
case '=':
SetIlineSpoof(iptr);
break;
case '!':
SetIlineLimit(iptr);
break;
case '-':
SetIlineNoTilde(iptr);
break;
case '+':
SetIlineForceId(iptr);
break;
#ifdef bingo
case '$':
SetIlinePassIdent(iptr);
break;
case '%':
SetIlineNoMatch(iptr);
break;
#endif /* bingo */
case '^':
SetIlineExempt(iptr);
break;
case '>':
SetIlineExempt(iptr);
SetIlineSuperExempt(iptr);
break;
default:
return (user);
}
++user;
}
return (user);
} /* ParseIlineFlags() */
/*
AddIline()
Allocate a new Iline structure with the given information.
Return a pointer to it.
Assume everything is NON-NULL, except for user and password. user
may be null in case there was no @ in the userhost field.
*/
static struct Iline *
AddIline(char *spoofhost, char *password, char *user, char *host,
int class)
{
struct Iline *ptr;
char *tmpuser;
ptr = (struct Iline *) MyMalloc(sizeof(struct Iline));
memset(ptr, 0, sizeof(struct Iline));
if (password)
ptr->password = MyStrdup(password);
if (user)
{
/*
* If this Iline has any special flags, they would
* be in the user field - parse them
*/
tmpuser = ParseIlineFlags(ptr, user);
ptr->username = MyStrdup(tmpuser);
}
else
ptr->username = MyStrdup("*");
if (spoofhost && IsIlineSpoof(ptr))
ptr->spoofhost = MyStrdup(spoofhost);
ptr->hostname = MyStrdup(host);
ptr->class = FindClass(class);
ptr->classnum = class;
ptr->prev = NULL;
ptr->next = IlineList;
if (ptr->next)
ptr->next->prev = ptr;
IlineList = ptr;
/*
* Add ptr to the Iline tree
*/
TreeAddIline(ptr);
return (ptr);
} /* AddIline() */
/*
FindIline()
Determine if user and host match an I line, if so return
a pointer to it.
*/
struct Iline *
FindIline(char *user, char *host)
{
struct Iline *iptr;
for (iptr = IlineList; iptr; iptr = iptr->next)
{
if (match(iptr->username, user) && match(iptr->hostname, host))
return (iptr);
}
return (NULL);
} /* FindIline() */
/*
CheckIline()
Called when a client connects to an ircd server to determine
if they have a valid I: line.
Return values:
IL_ERR_NOTAUTHORIZED - An I-line could not be found matching
the given user.
IL_ERR_FULL - The given Iline is full - no more clients
may use it.
IL_ERR_NEEDIDENT - The given Iline requires identd, and the
client did not have an ident reply.
IL_ERR_BADPASS - The given Iline requires a password, which
was not correctly supplied by the client.
IL_ERR_GOODMATCH - Not actually an error - the client is an
acceptable match for the given Iline.
If the client matches an Iline, the Iline structure is stored
in 'imatch'
*/
int
CheckIline(char *user, char *host, char *pass, struct Iline **imatch)
{
struct Iline *iptr;
iptr = (struct Iline *) SearchIlineTree(user, host);
if (iptr)
fprintf(stderr, "FOUND IN TREE: [%s@%s]\n", iptr->username, iptr->hostname);
if (!iptr)
return (IL_ERR_NOTAUTHORIZED);
if (iptr->class)
{
if ((iptr->class->links >= iptr->class->maxLinks) &&
!IsIlineSuperExempt(iptr))
return (IL_ERR_FULL);
++iptr->class->links;
}
if (IsIlineForceId(iptr) && (*user == '~'))
return (IL_ERR_NEEDIDENT);
if (iptr->password && (strcmp(iptr->password, pass) != 0))
return (IL_ERR_BADPASS);
*imatch = iptr;
return (IL_ERR_GOODMATCH);
} /* CheckIline() */
/*
AddPort()
Add a port number to the list of listen ports
*/
static void
AddPort(int portnum)
{
struct Port *ptr;
ptr = (struct Port *) MyMalloc(sizeof(struct Port));
memset(ptr, 0, sizeof(struct Port));
ptr->port = portnum;
ptr->sockfd = NOSOCK;
ptr->next = PortList;
PortList = ptr;
} /* AddPort() */
/*
AddQuarantine()
Add a nickname quarantine with the given information
*/
static void
AddQuarantine(char *nick, char *reason, char *user, char *host)
{
struct Quarantine *ptr;
ptr = (struct Quarantine *) MyMalloc(sizeof(struct Quarantine));
memset(ptr, 0, sizeof(struct Quarantine));
ptr->nickname = MyStrdup(nick);
if (reason)
ptr->reason = MyStrdup(reason);
else
ptr->reason = MyStrdup("No reason");
if (host)
{
ptr->hostname = MyStrdup(host);
if (user)
ptr->username = MyStrdup(user);
else
ptr->username = MyStrdup("*");
}
ptr->next = QuarantineList;
QuarantineList = ptr;
} /* AddQuarantine() */
/*
FindQuarantine()
Attempt to locate the given nickname in the quarantine list -
return a pointer to it if found
*/
struct Quarantine *
FindQuarantine(char *nick, char *user, char *host)
{
struct Quarantine *qptr;
for (qptr = QuarantineList; qptr; qptr = qptr->next)
{
if (match(qptr->nickname, nick))
{
/*
* The user may be exempt from this quarantine if
* their username and hostname match qptr's
*/
if (qptr->username && qptr->hostname)
{
if (match(qptr->username, user) && match(qptr->hostname, host))
continue;
}
return (qptr);
}
}
return (NULL);
} /* FindQuarantine() */