/*
* DREADERD/DNS.C - dns resolution and authentication task
*
* DNS authenticator for new connections.
*
* (c)Copyright 1998, Matthew Dillon, All Rights Reserved. Refer to
* the COPYRIGHT file in the base directory of this distribution
* for specific rights granted.
*/
#include "defs.h"
#ifdef LDAP_ENABLED
#define LDAP_COMPARE
#include <lber.h>
#include <ldap.h>
#endif
#ifdef DB_ENABLED
#include <db.h>
#endif
#ifdef PERL_ENABLED
#include <EXTERN.h>
#include <perl.h>
#endif
Prototype void DnsTask(int fd, const char *id);
Prototype void InstallAccessCache(void);
Prototype int ReadAccessCache(void);
Prototype void UpdateAuthDetails(ForkDesc *desc);
Prototype void SetAuthDetails(DnsRes *dres, char *which);
Prototype void PrintAuthDetails(DnsRes *dres);
Prototype void ClearOldAccessMap(void);
void DnsTest(DnsReq *dreq, DnsRes *dres, char *fqdn, char **ary, const char *ipname);
void getAuthUser(const struct sockaddr *lsin, const struct sockaddr *rsin, char *ubuf, int ulen);
int readExactly(int fd, void *buf, int bytes);
void sigSegVDNS(int sigNo);
int readtoeof(int fd, void *buf, int bytes, int secs);
int readAccessLine(FILE *af, char *fname, AccessDef *adef);
int xread(int fd, char *buf, int siz);
void getRateLimitCmds(char *opt, ReaderDef *rd);
/*
* The various authentication methods
*
* The current interface to the authentication methods is the passing
* of 3 strings as the parms: user, passwd, conf string from authdef
* Returns a string:
* NULL = failed
* 100 Success - use readerdef from access file
* 110 readerdef = Use this readerdef (unimplemented)
*/
char *fileAuthenticate(char *user, char *pass, char *conf);
#ifdef RADIUS_ENABLED
char *radiusAuthenticate(char *user, char *pass, char *conf);
#endif
#ifdef CDB_ENABLED
extern int cdb_seek(int, char*, unsigned int, unsigned int*);
char *cdbAuthenticate(char *user, char *pass, char *conf);
#endif
#ifdef DB_ENABLED
char *dbAuthenticate(char *user, char *pass, char *conf);
#endif
#ifdef NETREMOTE_ENABLED
void netRemoteAccounting(DnsReq *dreq);
char *netRemoteAuthenticate(char *user, char *pass, char *conf, char *localip);
#endif
#ifdef LDAP_ENABLED
#ifdef NEW_LDAP
char * LDAPAuthenticate(char *user, char *pass, char *realm, char *conf);
#else
char * LDAPAuthenticate(char *user, char *pass, char *conf);
#endif
#endif /* LDAP_ENABLED */
#ifdef PERL_ENABLED
char * PerlAuthenticate(char *user, char *pass, char *conf);
#endif
#ifdef PAM_ENABLED
#include <security/pam_appl.h>
char *PamAuthenticate(char *user, char *pass, char *conf);
#endif
int DFd = -1;
MemPool *DnsMemPool;
time_t Access_LastUpdate = 0;
time_t Cache_LastUpdate = 0;
AccessMap accessmap;
AccessMap oldaccessmap;
/* -------------------------------------------------------------------*/
/*
* This is the process that loops handling DNS and authentication requests
*
* It listens in a UNIX SOCKET for a dreq structure and responds with a
* dres structure.
*
*/
void
DnsTask(int fd, const char *id)
{
/*
* read remote address to resolve. Note: fd is not set to non-blocking
*/
DnsReq dreq;
int n;
DFd = fd;
if (CoreDebugOpt)
signal(SIGSEGV, sigSegVDNS);
/*
* Make dummy call to lock buffer so we do not inefficiently free and
* reallocate it for every DNS request.
*/
(void)zalloc(&DnsMemPool, 8);
/*
* Loop on DNS requests, resolve them, and respond.
*/
while ((n = readExactly(fd, &dreq, sizeof(dreq))) == sizeof(dreq)) {
DnsRes dres;
bzero(&dres, sizeof(dres));
stprintf("reverse auth %s", NetAddrToSt(0, (struct sockaddr *)&dreq.dr_RSin, 1, 0, 1));
if (ReadAccessCache() == 1)
ClearOldAccessMap();
if (dreq.dr_ResultFlags == DR_SESSEXIT_RPT) {
/*
* This handles session termination reporting, from a
* dreaderd NNTP thread. The idea is to allow one of the
* authentication methods to get information upon the
* termination of a session. Currently, most auth methods
* do not support this - NetRemote does. JG200106061320
*
* Note that this all requires some additional work anyways
*/
dres.dr_ResultFlags = DR_SESSEXIT_RPT;
#ifdef NETREMOTE_ENABLED
if (*dreq.dr_AuthUser && *dreq.dr_AuthPass) {
netRemoteAccounting(&dreq);
}
#endif
} else {
/*
* This handles both initial connect and AUTHINFO stuff
* by means that should probably be explicitly clarified
* at some point. JG200106061204
*/
char hname[NI_MAXHOST];
char ipname[NI_MAXHOST];
GetIPHost((struct sockaddr *)&dreq.dr_RSin, hname, sizeof(hname),
ipname, sizeof(ipname));
bcopy(&dreq.dr_RSin, &dres.dr_Addr, sizeof(dres.dr_Addr));
/* Do forward DNS doublecheck */
if (hname[0] == 0)
snprintf(dres.dr_Host, sizeof(dres.dr_Host), "%s", ipname);
else if (TestForwardLookup(hname, ipname,
(struct sockaddr *)&dreq.dr_RSin) < 0)
dres.dr_DnsMismatch = 1;
else
snprintf(dres.dr_Host, sizeof(dres.dr_Host), "%s", hname);
/*
* call test
*/
if (DebugOpt)
printf("call test, DnsTest %s (%s)\n", ipname, hname);
if (hname[0])
DnsTest(&dreq, &dres, hname, NULL, ipname);
else
DnsTest(&dreq, &dres, NULL, NULL, ipname);
}
write(fd, &dres, sizeof(dres));
stprintf("dns idle");
}
logit(LOG_NOTICE, "DNS process exiting n=%d/%d", n, sizeof(dreq));
}
/*
* Search a file of username:password pairs for a matching username/passord
*
* Returns: NULL failure
* "100 Sucess" success
*
*/
char *
fileAuthenticate(char *user, char *pass, char *conf)
{
static char result[DEFNAMELEN + 16];
char *r = NULL;
FILE *fp;
char buffer[1024];
char *bptr;
char *ptr;
int negate = 0;
if (*conf == '!') {
negate = 1;
conf++;
}
if (! ((fp = fopen(conf, "r")))) {
logit(LOG_ERR, "unable to open auth file %s", conf);
return(NULL);
}
while (!feof(fp)) {
fgets(buffer, sizeof(buffer), fp);
if ((ptr = strrchr(buffer, '\n'))) {
*ptr = '\0';
}
bptr = buffer;
ptr = strsep(&bptr, ":");
if (ptr && ! strcmp(ptr, user)) {
if (negate)
return(NULL);
ptr = strsep(&bptr, ":");
if (ptr && !strcmp(ptr, pass)) {
ptr = strsep(&bptr, ":");
if (ptr)
snprintf(result, sizeof(result), "110 %s", ptr);
else
strcpy(result, "100 Success");
r = result;
}
break;
}
}
fclose(fp);
if (r == NULL && negate) {
strcpy(result, "100 Success");
r = result;
}
return(r);
}
#ifdef RADIUS_ENABLED
/*
* Send an authenticate request to a radius server
*
* Returns: NULL failure
* "100 Sucess" success
*/
char *
radiusAuthenticate(char *user, char *pass, char *conf)
{
static char result[DEFNAMELEN + 16];
char *r = NULL;
struct rad_handle *h;
int rval;
if (! ((h = rad_open()))) {
logit(LOG_ERR, "unable to rad_auth_open");
return(NULL);
}
if (rad_config(h, conf) < 0) {
logit(LOG_ERR, "rad_config(%s) failed: %s", conf, rad_strerror(h));
rad_close(h);
return(NULL);
}
if (rad_create_request(h, RAD_ACCESS_REQUEST) < 0) {
logit(LOG_ERR, "rad_create_request failed: %s", rad_strerror(h));
rad_close(h);
return(NULL);
}
if (rad_put_string(h, RAD_USER_NAME, user) < 0) {
logit(LOG_ERR, "rad_put_string(RAD_USER_NAME) failed: %s", rad_strerror(h));
rad_close(h);
return(NULL);
}
if (rad_put_string(h, RAD_USER_PASSWORD, pass) < 0) {
logit(LOG_ERR, "rad_put_string(RAD_USER_PASSWORD) failed: %s", rad_strerror(h));
rad_close(h);
return(NULL);
}
if (((rval = rad_send_request(h))) < 0) {
logit(LOG_ERR, "rad_send_request failed: %s", rad_strerror(h));
rad_close(h);
return(NULL);
}
rad_close(h);
if (rval == RAD_ACCESS_ACCEPT) {
strcpy(result, "100 Success");
r = result;
} else
r = NULL;
return(r);
}
#endif
#ifdef CDB_ENABLED
/*
* Search a CDB database for a matching username/passord
*
* Returns: NULL failure
* "100 Sucess" success
*
*/
char *
cdbAuthenticate(char *user, char *pass, char *conf)
{
static char result[DEFNAMELEN + 16];
char *r = NULL;
unsigned int pwlen = 0;
int fd;
int negate = 0;
if (*conf == '!')
negate = 1;
fd = open(conf, O_RDONLY);
if (fd < 0) {
logit(LOG_ERR, "unable to open auth cdb %s", conf);
return(NULL);
}
if (cdb_seek(fd, user, strlen(user), &pwlen) > 0) {
if (negate)
return(NULL);
if (pwlen > 0) {
char pw[64];
if (pwlen > sizeof(pw) - 1) pwlen = sizeof(pw) - 1;
if (read(fd, pw, pwlen) == pwlen) {
pw[pwlen] = 0;
if (!strcmp(pw, pass)) {
strcpy(result, "100 Success");
r = result;
}
}
}
}
close(fd);
if (r == NULL && negate) {
strcpy(result, "100 Success");
r = result;
}
return(r);
}
#endif /* CDB_ENABLED */
#ifdef DB_ENABLED
/*
* Search a DB database for a matching username/passord
*
* Returns: NULL failure
* "100 Sucess" success
*
*/
char *
dbAuthenticate(char *user, char *pass, char *conf)
{
static char result[DEFNAMELEN + 16];
char *r = NULL;
DB *db = NULL;
DBT key;
DBT data;
int negate = 0;
int dbtype = DB_BTREE;
if (*conf == '!') {
negate = 1;
conf++;
}
if (strncmp(conf, "hash_", 5) == 0) {
dbtype = DB_HASH;
conf += 5;
} else if (strncmp(conf, "btree_", 6) == 0) {
dbtype = DB_BTREE;
conf += 6;
} else if (strncmp(conf, "recno_", 6) == 0) {
dbtype = DB_RECNO;
conf += 6;
}
db = dbopen(conf, O_RDONLY, 0, dbtype, NULL);
if (db == NULL) {
logit(LOG_ERR, "unable to open auth db %s (%s)", conf, strerror(errno));
return(NULL);
}
key.data = user;
key.size = strlen(user);
if (db->get(db, &key, &data, 0) == 0) {
char *p = data.data;
int i = 0;
if (negate)
return(NULL);
if (*pass) {
if (strcmp(pass, p) != 0)
return(NULL);
while (i < data.size && *p) {
p++;
i++;
}
if (!*p && i < data.size)
p++;
i++;
i = data.size - i;
} else {
i = data.size;
}
if (i > 0 && *p) {
if (i > sizeof(result) - 5)
i = sizeof(result) - 5;
snprintf(result, i + 5, "110 %s", p);
} else {
strcpy(result, "100 Success");
}
r = result;
} else if (negate) {
strcpy(result, "100 Success");
r = result;
}
db->close(db);
return(r);
}
#endif /* DB_ENABLED */
#ifdef NETREMOTE_ENABLED
/*
* Send an authenticate request to a NetRemote server
*
* This is Yet Another Famous Joe Greco Simple Stupid Protocol
*
* My intended use was, due to a large number of reader machines that
* maintained strong firewalls, to be able to centralize authentication
* operations on a core set of servers so that maintenance would be
* easier.
*
* Protocol is simple. Server starts by sending the time as a 12-digit
* integer. Client responds with a packet length as a 12-digit integer,
* and a DES-encrypted packet containing a random number, the server-sent
* time, the encryption password, username being auth'd, and password
* being auth'd. The server then returns 1-digit integer, 0 or 1, for
* status.
*
* Returns: NULL failure
* "100 Sucess" success
*/
/* really needs to be a multiple of 8 for DES encrypt */
#define NETREMOTE_DATASIZE 1432
int xread(fd, buf, siz)
int fd;
char *buf;
int siz;
{
int rval;
int chrs = 0;
while (siz) {
if ((rval = read(fd, buf, siz)) <= 0) {
return(rval);
}
chrs += rval;
siz -= rval;
buf += rval;
}
return(chrs);
}
/*
* This needs a rework.
*
* Since we do not record what authenticator gave us access, or
* the parameters to it, this really stinks.
*
* Ideally the whole dns module should be retrofitted a bit to
* allow future callbacks...
*/
void
netRemoteAccounting(DnsReq *dreq)
{
char *conf = "Password@accounting.server:8998";
int fd = -1, port = 8998;
char buffer[NETREMOTE_DATASIZE], output[NETREMOTE_DATASIZE], *ptr, *optr;
char confpw[1024], confhn[1024], *colon;
long theirtime;
des_cblock key;
des_key_schedule sched;
struct sockaddr_in sin;
struct hostent *hptr;
snprintf(confpw, sizeof(confpw), "%s", conf);
if ((ptr = strchr(confpw, '@'))) {
*ptr = '\0';
snprintf(confhn, sizeof(confhn), "%s", ptr + 1);
} else {
snprintf(confpw, sizeof(confpw), "%s", "none");
snprintf(confhn, sizeof(confhn), "%s", conf);
}
if ((colon = strrchr(confhn, ':'))) {
int bad = 0;
*colon = '\0';
ptr = colon + 1;
if (! *ptr) {
bad++;
}
while (*ptr) {
if (! isdigit(*ptr)) {
bad++;
}
ptr++;
}
if (! bad) {
port = atoi(colon + 1);
} else {
logit(LOG_ERR, "Invalid NetRemote port %s", colon + 1);
}
}
/* attach to remote server(s) */
if (isdigit(*confhn)) {
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
logit(LOG_ERR, "NetRemote socket create: %m");
return;
}
bzero((void *)&sin, sizeof(&sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(0);
if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(fd);
logit(LOG_ERR, "NetRemote socket bind: %m");
return;
}
bzero((void *)&sin, sizeof(&sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = inet_addr(confhn);
if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(fd);
logit(LOG_ERR, "NetRemote socket connect: %s(%s:%d): %m", confhn, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
return;
}
} else {
int i = 0, connected = 0;
if (! (hptr = gethostbyname(confhn))) {
close(fd);
logit(LOG_ERR, "NetRemote gethostbyname: %s: %m", confhn);
return;
}
while (! connected) {
if (! hptr->h_addr_list[i]) {
return;
}
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
logit(LOG_ERR, "NetRemote socket create: %m");
return;
}
bzero((void *)&sin, sizeof(&sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(0);
if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(fd);
logit(LOG_ERR, "NetRemote socket bind: %m");
return;
}
bzero((void *)&sin, sizeof(&sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
bcopy(hptr->h_addr_list[i], (char *)&sin.sin_addr.s_addr, sizeof(sin.sin_addr.s_addr));
if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
if (errno != ETIMEDOUT && errno != ECONNREFUSED && errno != ENETUNREACH) {
close(fd);
logit(LOG_ERR, "NetRemote fatal socket connect: %s: %m", confhn);
return;
}
close(fd);
logit(LOG_ERR, "NetRemote socket connect: %s(%s:%d): %m", confhn, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
i++;
} else {
connected++;
}
}
}
/* Read the server's idea of time. 12 byte int plus \n */
if (xread(fd, buffer, 13) != 13) {
close(fd);
return;
}
theirtime = atol(buffer);
des_string_to_key(confpw, &key);
des_set_key(&key, sched);
bzero(buffer, sizeof(buffer));
snprintf(buffer, sizeof(buffer), "%ld\n%ld\n%s\n%c\n%s\n%.0f\n%d\n%d\n%.0f\n%d\n%d\n%.0f\n%.0f\n%.0f\n%.0f\n%.0f\n%.0f\n%.0f\n%d\n%s\n", random(), theirtime, confpw, '2',
dreq->dr_AuthUser,
dreq->dr_ByteCount,
dreq->dr_GrpCount,
dreq->dr_ArtCount,
dreq->dr_PostBytes,
dreq->dr_PostCount,
dreq->dr_PostFailCount,
dreq->dr_ByteCountArticle,
dreq->dr_ByteCountHead,
dreq->dr_ByteCountBody,
dreq->dr_ByteCountList,
dreq->dr_ByteCountXover,
dreq->dr_ByteCountXhdr,
dreq->dr_ByteCountOther,
(int)dreq->dr_SessionLength,
NetAddrToSt(0, (struct sockaddr *)&dreq->dr_RSin, 1, 0, 1));
ptr = buffer;
optr = output;
while (ptr < buffer + sizeof(buffer)) {
des_ecb_encrypt((des_cblock *)ptr,(des_cblock *)optr, sched, 1);
bzero(ptr, 8);
ptr += 8;
optr += 8;
}
/* Send the encrypted request, prefixed by size of packet */
snprintf(buffer, sizeof(buffer), "%012d\n", sizeof(output));
write(fd, buffer, strlen(buffer));
write(fd, output, sizeof(output));
/* No response to read */
close(fd);
return;
}
char *
netRemoteAuthenticate(char *user, char *pass, char *conf, char *localip)
{
static char result[DEFNAMELEN + 16];
char *r = NULL;
int fd = -1, port = 8998;
char buffer[NETREMOTE_DATASIZE], output[NETREMOTE_DATASIZE], *ptr, *optr;
char confpw[1024], confhn[1024], *colon;
long theirtime;
des_cblock key;
des_key_schedule sched;
struct sockaddr_in sin;
struct hostent *hptr;
snprintf(confpw, sizeof(confpw), "%s", conf);
if ((ptr = strchr(confpw, '@'))) {
*ptr = '\0';
snprintf(confhn, sizeof(confhn), "%s", ptr + 1);
} else {
snprintf(confpw, sizeof(confpw), "%s", "none");
snprintf(confhn, sizeof(confhn), "%s", conf);
}
if ((colon = strrchr(confhn, ':'))) {
int bad = 0;
*colon = '\0';
ptr = colon + 1;
if (! *ptr) {
bad++;
}
while (*ptr) {
if (! isdigit(*ptr)) {
bad++;
}
ptr++;
}
if (! bad) {
port = atoi(colon + 1);
} else {
logit(LOG_ERR, "Invalid NetRemote port %s", colon + 1);
}
}
/* attach to remote server(s) */
if (isdigit(*confhn)) {
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
logit(LOG_ERR, "NetRemote socket create: %m");
return(NULL);
}
bzero((void *)&sin, sizeof(&sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(0);
if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(fd);
logit(LOG_ERR, "NetRemote socket bind: %m");
return(NULL);
}
bzero((void *)&sin, sizeof(&sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = inet_addr(confhn);
if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(fd);
logit(LOG_ERR, "NetRemote socket connect: %s(%s:%d): %m", confhn, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
return(NULL);
}
} else {
int i = 0, connected = 0;
if (! (hptr = gethostbyname(confhn))) {
close(fd);
logit(LOG_ERR, "NetRemote gethostbyname: %s: %m", confhn);
return(NULL);
}
while (! connected) {
if (! hptr->h_addr_list[i]) {
return(NULL);
}
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
logit(LOG_ERR, "NetRemote socket create: %m");
return(NULL);
}
bzero((void *)&sin, sizeof(&sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(0);
if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(fd);
logit(LOG_ERR, "NetRemote socket bind: %m");
return(NULL);
}
bzero((void *)&sin, sizeof(&sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
bcopy(hptr->h_addr_list[i], (char *)&sin.sin_addr.s_addr, sizeof(sin.sin_addr.s_addr));
if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
if (errno != ETIMEDOUT && errno != ECONNREFUSED && errno != ENETUNREACH) {
close(fd);
logit(LOG_ERR, "NetRemote fatal socket connect: %s: %m", confhn);
return(NULL);
}
close(fd);
logit(LOG_ERR, "NetRemote socket connect: %s(%s:%d): %m", confhn, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
i++;
} else {
connected++;
}
}
}
/* Read the server's idea of time. 12 byte int plus \n */
if (xread(fd, buffer, 13) != 13) {
close(fd);
return(NULL);
}
theirtime = atol(buffer);
des_string_to_key(confpw, &key);
des_set_key(&key, sched);
bzero(buffer, sizeof(buffer));
snprintf(buffer, sizeof(buffer), "%ld\n%ld\n%s\n%c\n%s\n%s\n%s\n", random(), theirtime, confpw, '1', user, pass, localip);
ptr = buffer;
optr = output;
while (ptr < buffer + sizeof(buffer)) {
des_ecb_encrypt((des_cblock *)ptr,(des_cblock *)optr, sched, 1);
bzero(ptr, 8);
ptr += 8;
optr += 8;
}
/* Send the encrypted request, prefixed by size of packet */
snprintf(buffer, sizeof(buffer), "%012d\n", sizeof(output));
write(fd, buffer, strlen(buffer));
write(fd, output, sizeof(output));
/* Read the server's response. 1 byte int plus \n */
if (read(fd, buffer, sizeof(buffer)) < 2) {
close(fd);
return(NULL);
}
close(fd);
if (*buffer == '1') {
snprintf(result, sizeof(result), "%s", buffer);
if ((r = strrchr(result, '\n'))) {
*r = '\0';
}
r = result;
} else
r = NULL;
return(r);
}
#endif
#ifdef LDAP_ENABLED
#ifdef NEW_LDAP
/*
* Send an authenticate request to an LDAP server
*
* Returns: NULL failure
* "100 Sucess" success
*
* Configuration is done via an LDAP URL of the form:
*
* ldap://hostname[:port]/dn?userPassword?scope?filter [username:passwd]
*
* where:
* userPassword is the attribute that contains the clear text password,
* usually called "userPassword".
*
* scope is probably normally "sub" or "base".
*
* filter consists of the username and password attributes and any
* other site specific search options required to narrow a search
* to a single user. The following values can be used and will
* be replaced by the corresponding value supplied from Diablo.
*
* $USER$ username
* $PASS$ password
* $REALM$ authentication domain, if realms are used
*
* username:passwd is the username and password with which to
* authenticate to the LDAP server. If they are not specified,
* anonymous authentication is done.
*
* Example:
*
* ldap://host.example.com/dc=$REALM$,dn=example.com?userPassword?sub?(userName=$USER$)
*
*/
char *
LDAPAuthenticate(char *user, char *pass, char *realm, char *conf)
{
static LDAP *ld = NULL;
char *result = NULL;
char url[1024];
LDAPURLDesc *ludp;
char *confst = NULL;
char *r;
char *p;
LDAPMessage *res;
LDAPMessage *m;
int msgid;
int rcode;
char *ldapuser = NULL;
char *ldappass = NULL;
/*
* Parse the configuration options to extract the URL and the
* LDAP auth options
*/
r = strdup(conf);
confst = strsep(&r, " \t");
if (confst != NULL) {
p = r;
while ((p = strsep(&r, " \t")) != NULL) {
ldapuser = p;
p = strchr(p, ':');
if (p != NULL) {
*p++ = 0;
ldappass = p;
}
}
} else {
confst = r;
}
if (ld != NULL && (confst == NULL || strcmp(confst, conf) != 0)) {
ldap_unbind_s(ld);
ld = NULL;
}
/*
* Make a new connection to the LDAP server if one isn't already there
*/
if (ld == NULL) {
if (ldap_is_ldap_url(confst) == 0) {
logit(LOG_ERR, "Not an LDAP URL: %s\n", conf);
free(confst);
return(NULL);
}
if (ldap_url_parse(confst, &ludp) != 0) {
logit(LOG_ERR,"Unable to parse LDAP URL: %s\n", confst);
free(confst);
return(NULL);
}
/* Open LDAP connection */
if ((ld = ldap_init(ludp->lud_host, ludp->lud_port)) == NULL) {
/* Couldn't contact server - fail authentication attempt */
logit(LOG_ERR,"Unable to connect to LDAP server: %s\n", confst);
free(confst);
ldap_free_urldesc(ludp);
return(NULL);
}
ldap_free_urldesc(ludp);
if ((msgid = ldap_bind_s(ld, ldapuser, ldappass, LDAP_AUTH_SIMPLE)) !=
LDAP_SUCCESS) {
/* Bind failed - fail auth attempt */
logit(LOG_ERR,"LDAP bind failed: %s\n", confst);
free(confst);
ldap_unbind_s(ld);
ld = NULL;
return(NULL);
}
if (DebugOpt)
printf("Connection to LDAP server established\n");
}
/*
* Setup the search parameters and substitute the user, pass and domain
* fields into the search URL
*/
{
char *src = confst;
char *dst = url;
while (*src) {
if (user && strncmp(src, "$USER$", 6) == 0) {
src += 6;
strcpy(dst, user);
dst += strlen(user);
} else if (pass && strncmp(src, "$PASSWD$", 8) == 0) {
src += 8;
strcpy(dst, pass);
dst += strlen(pass);
} else if (realm && strncmp(src, "$REALM$", 7) == 0) {
src += 7;
strcpy(dst, realm);
dst += strlen(realm);
} else {
*dst++ = *src++;
}
}
*dst = 0;
if (DebugOpt)
printf("URL: %s\n", url);
}
if (ldap_url_parse(url, &ludp) != 0) {
logit(LOG_ERR,"Unable to parse LDAP URL: %s\n", url);
free(confst);
return(NULL);
}
/*
* Perform the search
*/
if ((rcode = ldap_search_s(ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, 0, &res)) != LDAP_SUCCESS) {
logit(LOG_ERR,"LDAP search for %s failed: %s\n", url, ldap_err2string(rcode));
free(confst);
ldap_unbind_s(ld);
ldap_free_urldesc(ludp);
ld = NULL;
return(NULL);
}
ldap_free_urldesc(ludp);
/*
* Parse the results.
*/
if (DebugOpt)
printf("Results:\n");
for (m = ldap_first_entry(ld, res); m != NULL;
m = ldap_next_entry(ld, m)) {
BerElement *ber;
char *attr;
int i;
for (attr = ldap_first_attribute(ld, m, &ber); attr != NULL;
attr = ldap_next_attribute(ld, m, ber)) {
char **vals;
if (DebugOpt)
printf("attr: %s\n", attr);
if ((vals = ldap_get_values(ld, m, attr)) != NULL) {
for (i = 0; vals[i] != NULL; ++i) {
if (strcmp(pass,vals[i])==0) result="100 Success";
if (DebugOpt)
printf(" val: %s\n", vals[i]);
}
ldap_value_free(vals);
}
}
}
ldap_msgfree(res);
#ifdef LDAP_DO_UNBIND
ldap_unbind_s(ld);
ld = NULL;
#endif
free(confst);
return(result);
}
#else
/*
* Send an authenticate request to an LDAP server
*
* Returns: NULL failure
* "100 Sucess" success
*/
char *
LDAPAuthenticate(char *user, char *pass, char *conf)
{
static char result[DEFNAMELEN + 16];
char *r;
static LDAP *ld = NULL;
static LDAPURLDesc *ludp;
LDAPMessage *res;
LDAPMessage *mptr;
char *ldappassattr = "userpassword";
int msgid;
int rcode;
char *filter;
#ifndef LDAP_COMPARE
char **bv_val;
#else
char *dn;
#endif
if (ld == NULL) {
if (ldap_is_ldap_url(conf) == 0) {
logit(LOG_ERR, "No LDAP URL: %s\n", conf);
ld = NULL;
return(NULL);
}
if (ldap_url_parse(conf, &ludp) != 0) {
logit(LOG_ERR, "Unable to parse LDAP URL: %s\n", conf);
ldap_free_urldesc(ludp);
ld = NULL;
return(NULL);
}
/* Open LDAP connection */
if ((ld = ldap_init(ludp->lud_host, ludp->lud_port)) == NULL) {
/* Couldn't contact server - fail authentication attempt */
logit(LOG_ERR, "Unable to connect to LDAP server: %s\n", conf);
ldap_free_urldesc(ludp);
ld = NULL;
return(NULL);
}
if ((msgid = ldap_bind_s(ld, NULL, NULL, LDAP_AUTH_SIMPLE)) !=
LDAP_SUCCESS) {
/* Bind failed - fail auth attempt */
logit(LOG_ERR, "LDAP bind failed: %s\n", conf);
ldap_free_urldesc(ludp);
ld = NULL;
return(NULL);
}
if (DebugOpt)
printf("Connection to LDAP server established\n");
}
/* Build the filter string and attributes */
if ((filter = (char *)malloc(strlen(ludp->lud_filter) + strlen(user) + 1)) == NULL) {
/* Malloc failed - fail auth attempt */
logit(LOG_ERR, "LDAP malloc failed: %s\n", conf);
ldap_unbind_s(ld);
ldap_free_urldesc(ludp);
ld = NULL;
return(NULL);
}
sprintf(filter, ludp->lud_filter, user);
/* Perform the search */
if ((rcode = ldap_search_s(ld, ludp->lud_dn, ludp->lud_scope, filter, ludp->lud_attrs, 0, &res)) != LDAP_SUCCESS) {
/* Search failed - fail auth attempt */
logit(LOG_INFO, "LDAP search failed (%s): %s\n",
user, ldap_err2string(rcode));
free(filter);
ldap_unbind_s(ld);
ldap_free_urldesc(ludp);
ld = NULL;
return(NULL);
}
/* See what we got back - we only care about the first response */
if ((mptr = ldap_first_entry(ld, res)) == NULL) {
/* Error - fail auth attempt */
logit(LOG_INFO, "LDAP auth failed: %s\n", user);
free(filter);
ldap_unbind_s(ld);
ldap_free_urldesc(ludp);
return(NULL);
}
r = NULL;
#ifdef LDAP_COMPARE
dn = ldap_get_dn(ld, mptr);
if (ldap_compare_s(ld, dn, ldappassattr, pass) == LDAP_COMPARE_TRUE) {
strcpy(result, "100 Success");
r = result;
} else {
logit(LOG_INFO, "LDAP auth failed: %s\n", user);
r = NULL;
}
free(dn);
#else
/* Read the password and compare it */
bv_val = ldap_get_values(ld, mptr, ldappassattr);
if (ldap_count_values(bv_val) == 0) {
/* No password value returned - fail auth attempt */
logit(LOG_INFO, "LDAP auth failed: %s\n", user);
r = NULL;
ldap_value_free(bv_val);
}
if (strcmp(bv_val[0], pass) == 0) {
strcpy(result, "100 Success");
r = result;
} else {
r = NULL;
}
#endif
return(r);
}
#endif /* NEW_LDAP */
#endif /* LDAP_ENABLED */
#ifdef PERL_ENABLED
EXTERN_C void xs_init (pTHXo);
EXTERN_C void boot_DynaLoader (pTHXo_ CV* cv);
EXTERN_C void xs_init(pTHXo)
{
char *file = __FILE__;
dXSUB_SYS;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
}
char *call_checkuser(char *auth_args[])
{
static char buff[DEFNAMELEN + 16];
dSP;
SV *sv;
char *str;
STRLEN len;
char *result = NULL;
ENTER;
SAVETMPS;
call_argv("checkuser", G_SCALAR, auth_args);
SPAGAIN;
sv = POPs;
if (SvTRUE(sv) && (str = SvPV(sv, len)) && len < DEFNAMELEN + 16)
result = strcpy(buff, str);
FREETMPS;
LEAVE;
return result;
}
char *PerlAuthenticate(char *user, char *pass, char *conf)
{
char *embedding[] = { "", conf };
char *auth_args[] = { user, pass, NULL };
char *result;
char *reslog;
static PerlInterpreter *perl = NULL;
int exitstatus = 0;
if (perl == NULL) {
if((perl = perl_alloc()) == NULL) {
fprintf(stderr, "perl_alloc no memory\n");
exit(1);
}
PL_perl_destruct_level = 0;
perl_construct(perl);
exitstatus = perl_parse(perl, xs_init, 2, embedding, NULL);
if (!exitstatus) {
exitstatus = perl_run(perl);
}
if (exitstatus) {
fprintf(stderr, "perl_parse or perl_run failed\n");
perl_destruct(perl);
perl_free(perl);
exit(exitstatus);
}
}
reslog = result = call_checkuser(auth_args);
if (reslog == NULL)
reslog = "FAILED";
logit(LOG_INFO, "PERL auth request for %s: %s\n", user, reslog);
return result;
}
#endif /* PERL_ENABLED */
#ifdef PAM_ENABLED
static char *PAM_user;
static char *PAM_password;
static int PAM_error = 0;
static int PAM_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata)
{
int count;
int replies = 0;
struct pam_response *reply = NULL;
for (count = 0; count < num_msg; count++) {
switch (msg[count]->msg_style) {
case PAM_PROMPT_ECHO_ON:
reply = (struct pam_response *)realloc(reply,
sizeof(struct pam_response));
reply[replies].resp_retcode = PAM_SUCCESS;
reply[replies++].resp = strdup(PAM_user);
break;
case PAM_PROMPT_ECHO_OFF:
reply = (struct pam_response *)realloc(reply,
sizeof(struct pam_response));
reply[replies].resp_retcode = PAM_SUCCESS;
reply[replies++].resp = strdup(PAM_password);
break;
case PAM_TEXT_INFO:
break;
case PAM_ERROR_MSG:
default:
PAM_error = 1;
if (reply != NULL) {
free(reply);
reply = NULL;
}
return PAM_CONV_ERR;
}
}
if (reply != NULL)
*resp = reply;
return PAM_SUCCESS;
}
static struct pam_conv conv = {
PAM_conv, NULL
};
char *PamAuthenticate(char *user, char *pass, char *conf)
{
static char result[DEFNAMELEN + 16];
pam_handle_t *pamh = NULL;
int retval;
char *r = NULL;
PAM_user = user;
PAM_password = pass;
retval = pam_start(conf, PAM_user, &conv, &pamh);
if (retval == PAM_SUCCESS)
retval = pam_authenticate(pamh, 0);
if (retval == PAM_SUCCESS) {
strcpy(result, "100 Success");
r = result;
}
if (pam_end(pamh, retval) != PAM_SUCCESS) {
pamh = NULL;
logit(LOG_CRIT, "Unable to release PAM authentication\n");
}
return(r);
}
#endif /* PAM_ENABLE */
/*
* DnsTest() - test access file entry against host.
*
* fqdn reverse lookup of name, if known, or NULL
* ary aliases, if known, or NULL
* ipname name of host as dotted quad
*/
void DnsTest(DnsReq *dreq, DnsRes *dres, char *fqdn, char **ary, const char *ipname)
{
int AuthNeeded;
int MatchedAuthNeeded = 0;
int Authenticated = 0;
int MatchedAuthenticated = 0;
int MatchType;
char *AuthReader = NULL;
Vserver *vsp = NULL;
AccessDef *alp;
AccessDef *matchedalp = NULL;
AccessDef accessdef;
AccessDef matchedaccessdef;
int acount;
int DoneIdent = 0;
int accessok;
int accessfile;
int firstmatch;
FILE *af = NULL;
char *realm = NULL;
/* This got trashed, so reset it */
if (*dreq->dr_AuthUser) {
dres->dr_ResultFlags = DR_REQUIRE_DNS;
strcpy(dres->dr_AuthUser, dreq->dr_AuthUser);
strcpy(dres->dr_AuthPass, dreq->dr_AuthPass);
}
/* XXX Doesn't work after INET6 addition!! */
for (vsp = accessmap.VServerList, acount = 0;
acount < accessmap.VServerCount; acount++, vsp++) {
#ifdef INET6
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&dreq->dr_LSin;
struct sockaddr_in6 *vsa = (struct sockaddr_in6 *)&vsp->vs_Interface;
if (memcmp(&sa->sin6_addr, &vsa->sin6_addr,
sizeof(sa->sin6_addr)) == 0) {
#else
struct sockaddr_in *sa = (struct sockaddr_in *)&dreq->dr_LSin;
struct sockaddr_in *vsa = (struct sockaddr_in *)&vsp->vs_Interface;
if (sa->sin_addr.s_addr == vsa->sin_addr.s_addr) {
#endif
strcpy(dres->dr_VServer, vsp->vs_Name);
dres->dr_VServerDef = vsp;
break;
}
}
accessok = 1;
accessfile = 0;
/*
* Not sure if this is still needed as we only ever call DnsTest()
* from DnsTask(), which hopefully sets this up correctly.
*/
if (!ipname)
if (fqdn && IsIpAddr(fqdn))
ipname = fqdn;
/*
* For logging purposes, put something here
*/
snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", ipname);
/*
* If we have specified a separate access file for a vserver,
* then load it into memory for scanning.
*/
if (*dres->dr_VServer && *dres->dr_VServerDef->vs_AccessFile) {
accessfile = 1;
strcpy(accessdef.ad_Reader, "DEFAULT");
if (DebugOpt)
printf("Using accessfile: %s\n",
PatLibExpand(dres->dr_VServerDef->vs_AccessFile));
if ((af = fopen(PatLibExpand(dres->dr_VServerDef->vs_AccessFile), "r")) == NULL) {
logit(LOG_CRIT, "Unable to open %s",
PatLibExpand(dres->dr_VServerDef->vs_AccessFile));
accessok = 0;
}
}
/*
* Go through interations of the access list or read a vserver
* access file and look for matches. Last match wins.
*
* We use the following logic for a match:
* - if no match -> fail
* - if last match with no auth required -> pass
* - if last match with auth required (and no auth details) and no
* previous match -> pass (requires auth to do things)
* - if last match with auth required (and no auth details) and prev
* match -> pass with prev match
* - if last match with auth required (with matching auth details) -> pass
* - if no auth required and no read,post,feed or status -> fail
*/
alp = accessmap.AccessList;
matchedalp = NULL;
acount = 0;
firstmatch = 1;
while (accessok) {
stprintf("dns auth search %s", ipname);
if (accessfile == 1) {
if (readAccessLine(af,
(char *)PatLibExpand(dres->dr_VServerDef->vs_AccessFile),
&accessdef) != 1)
break;
alp = &accessdef;
} else if (accessfile == 2) {
if (acount++ > 1)
break;
} else {
if (!firstmatch)
alp++;
firstmatch = 0;
if (acount++ >= accessmap.AccessCount || alp == NULL)
break;
}
/*
* First we test the hostname or IP.
*/
MatchType = 0;
if (IsIpAddr(alp->ad_Pattern)) {
if (!ipname || !*ipname)
continue;
if (strchr(alp->ad_Pattern, '*') ||
strchr(alp->ad_Pattern, '?')) {
/* Wildmatch */
if (WildCaseCmp(alp->ad_Pattern, ipname) != 0)
continue;
} else if (strchr(alp->ad_Pattern, '/')) {
/* CIDR notation */
if (!CidrMatch(alp->ad_Pattern, ipname))
continue;
} else {
/* Default - exact match */
if (strcasecmp(ipname, alp->ad_Pattern) != 0)
continue;
}
snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", ipname);
MatchType = 1;
} else if (strncmp(alp->ad_Pattern, "db:", 3) == 0) {
/*
* If we have specified a DB for IP address lookup, then do
* the lookup.
*/
#ifdef DB_ENABLED
char *conf = alp->ad_Pattern + 3;
char *res;
if (DebugOpt)
printf("Using accessdb: %s\n", conf);
res = dbAuthenticate((char *)ipname, "", conf);
if (DebugOpt)
printf("accessdb result: %s\n", res ? res : "(NULL)");
if (res == NULL || strcmp(res, "110 0") == 0)
continue;
MatchType = 1;
snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", ipname);
#else
logit(LOG_ERR, "db: option in dreader.access not enabled - ignoring");
continue;
#endif
} else {
if (!fqdn || !*fqdn)
continue;
if (strchr(alp->ad_Pattern, '*') ||
strchr(alp->ad_Pattern, '?')) {
/* Wildmatch */
if (WildCaseCmp(alp->ad_Pattern, fqdn) != 0)
continue;
} else {
/* Default - exact match */
if (strcasecmp(fqdn, alp->ad_Pattern) != 0)
continue;
}
MatchType = 2;
snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", fqdn);
}
if (*alp->ad_IdentUser) {
if (!DoneIdent && !*dres->dr_IdentUser) {
/*
* this isn't an option where the user can actually
* enter something to pass the test; it is gained from
* identd info. therefore it is an all-pass or all-fail
* type thing.
*/
getAuthUser((struct sockaddr *)&dreq->dr_LSin,
(struct sockaddr *)&dreq->dr_RSin, dres->dr_IdentUser,
sizeof(dres->dr_IdentUser));
stprintf("dns auth ident %s", ipname);
stprintf("dns auth search %s", ipname);
DoneIdent = 1;
}
/* We don't need to go further if we fail the ident check */
if (strcmp(alp->ad_IdentUser, dres->dr_IdentUser) != 0)
continue;
}
/*
* Now me are matching an access line, check some of the
* user details
*/
if (DebugOpt)
printf("Matched access line: %s%s%s (%s)\n",
*alp->ad_IdentUser ? alp->ad_IdentUser : "",
*alp->ad_IdentUser ? "@" : "",
alp->ad_Pattern,
alp->ad_Reader);
SetAuthDetails(dres, alp->ad_Reader);
/*
* Do we log with the hostname
*/
if (dres->dr_ReaderDef->rd_UseVerifiedDns && fqdn && *fqdn)
snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", fqdn);
/*
* We can optionally deny an entry that doesn't have a DNS entry
*/
if (dres->dr_ReaderDef->rd_DenyNoDns && (!fqdn || !*fqdn)) {
logit(LOG_ERR, "Denying host with no DNS entry: %s", ipname);
continue;
}
/*
* If we mismatch Fwd/Rev and we matched against a domain
* then reject the connection for security reasons
*/
if (dres->dr_DnsMismatch && (dres->dr_ReaderDef->rd_DenyMismatchedDns
|| (dres->dr_DnsMismatch && MatchType != 1))) {
if (DebugOpt)
printf("Not allowing DNS Fwd/Rev Mismatch for: %s matching %s%s%s\n",
ipname,
*alp->ad_IdentUser ? alp->ad_IdentUser : "",
*alp->ad_IdentUser ? "@" : "",
alp->ad_Pattern);
continue;
}
/*
* We can optionally use the FQDN for logging even when
* matched with an IP
*/
if (dres->dr_ReaderDef->rd_UseVerifiedDns && !dres->dr_DnsMismatch &&
fqdn && *fqdn)
snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", fqdn);
/*
* Ok. Now at this point, we either don't have a match on this
* line, in which case we've already skipped to the next line,
* or we have a match... but we may still need to authenticate.
*/
Authenticated = 0;
AuthNeeded = 0;
if (*dres->dr_AuthDef->au_Radius ||
*dres->dr_AuthDef->au_LDAP ||
*dres->dr_AuthDef->au_Perl ||
*dres->dr_AuthDef->au_PAM ||
*dres->dr_AuthDef->au_NetRemote ||
*dres->dr_AuthDef->au_File ||
*dres->dr_AuthDef->au_Cdb ||
*dres->dr_AuthDef->au_Db ||
*dres->dr_AuthDef->au_External ||
*dres->dr_AuthDef->au_User)
AuthNeeded = 1;
if (dres->dr_AuthDef->au_Ident && !DoneIdent && !*dres->dr_IdentUser) {
/*
* this isn't an option where the user can actually
* enter something to pass the test; it is gained from
* identd info. therefore it is an all-pass or all-fail
* type thing.
*/
getAuthUser((struct sockaddr *)&dreq->dr_LSin,
(struct sockaddr *)&dreq->dr_RSin, dres->dr_IdentUser,
sizeof(dres->dr_IdentUser));
stprintf("dns auth search %s", ipname);
DoneIdent = 1;
}
/*
* The user has used the AUTHINFO comamnd - check the details
* against various authentication mechanisms.
*
* All methods specified in the auth block are used and any of
* them can match
*/
if (AuthNeeded) {
char user[128];
int authok;
/*
* Add a default realm, if one not already specified
*/
if (*dres->dr_AuthDef->au_AddRealm) {
realm = strchr(dreq->dr_AuthUser, '@');
if (*dreq->dr_AuthUser && ! realm) {
int offset;
offset = strlen(dres->dr_AuthUser);
if (offset < sizeof(dres->dr_AuthUser) - 4) {
snprintf(dres->dr_AuthUser + offset,
sizeof(dres->dr_AuthUser) - offset,
"@%s", dres->dr_AuthDef->au_AddRealm);
snprintf(dreq->dr_AuthUser, sizeof(dreq->dr_AuthUser),
"%s", dres->dr_AuthUser);
}
}
}
strncpy(user, dreq->dr_AuthUser, sizeof(user) - 1 );
user[sizeof(user) - 1] = '\0';
authok = 1;
/*
* The realm is anything after the '@' in a username
* Make sure this matches, otherwise the others won't
* match. Note: this strips the realm
*/
if (*dres->dr_AuthDef->au_Realm) {
authok = 0;
realm = strchr(user, '@');
if (realm != NULL) {
*realm++ = '\0';
if (strcmp(dres->dr_AuthDef->au_Realm,"*") == 0 ||
strcmp(dres->dr_AuthDef->au_Realm, realm) == 0)
authok = 1;
}
}
/*
* If the user was set in auth and we have Ident, we just compare
*/
if (authok && DoneIdent && *dres->dr_IdentUser &&
*dres->dr_AuthDef->au_User &&
!strcmp(dres->dr_IdentUser, dres->dr_AuthDef->au_User)) {
Authenticated = 2;
if (DebugOpt)
printf("Authenticated via ident+user\n");
}
#ifdef REJECT_DB
{
DBT key;
DBT data;
DB *db = NULL;
if((db = dbopen(REJECT_DB, O_RDONLY , 0, DB_BTREE, NULL)) != NULL) {
key.data = user;
key.size = strlen(user);
if((db->get(db, &key, &data, 0) == 0)) {
logit(LOG_NOTICE, "User %s found in reject db, denying access",user);
if(DebugOpt)
printf("User %s found in reject db, denying access\n",user);
Authenticated = -1;
authok = 0;
}
db->close(db);
}
}
#endif /* REJECT_DB */
/*
* Check for the user+pass in a file
*/
if (authok && *dres->dr_AuthDef->au_File && *user &&
*dreq->dr_AuthPass) {
stprintf("dns auth file %s@%s", user, ipname);
AuthReader = fileAuthenticate(user, dreq->dr_AuthPass,
dres->dr_AuthDef->au_File);
stprintf("dns auth search %s", ipname);
if (AuthReader != NULL && *AuthReader == '1') {
if (*dres->dr_AuthDef->au_File != '!')
Authenticated = 1;
if (DebugOpt)
printf("Authenticated via file (%s)\n", AuthReader);
} else if (*dres->dr_AuthDef->au_File == '!') {
Authenticated = -1;
authok = 0;
if (DebugOpt)
printf("Authentication via file REJECTED\n");
} else {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via file FAILED\n");
}
}
#ifdef RADIUS_ENABLED
/*
* Check user+pass with radius server
*/
if (authok && *dres->dr_AuthDef->au_Radius && *user &&
*dreq->dr_AuthPass) {
stprintf("dns auth radius %s@%s", user, ipname);
AuthReader = radiusAuthenticate(user, dreq->dr_AuthPass,
dres->dr_AuthDef->au_Radius);
stprintf("dns auth search %s", ipname);
if (AuthReader != NULL && *AuthReader == '1') {
Authenticated = 1;
if (DebugOpt)
printf("Authenticated via radius\n");
} else {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via radius FAILED\n");
}
}
#else
if (authok && *dres->dr_AuthDef->au_Radius && *user &&
*dreq->dr_AuthPass) {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via radius FAILED\n");
logit(LOG_ERR, "Radius authentication requested, but not enabled");
}
#endif
#ifdef CDB_ENABLED
/*
* Check for the user+pass in a CDB
*/
if (authok && *dres->dr_AuthDef->au_Cdb && *user &&
*dreq->dr_AuthPass) {
stprintf("dns auth cdb %s@%s", user, ipname);
AuthReader = cdbAuthenticate(user, dreq->dr_AuthPass,
dres->dr_AuthDef->au_Cdb);
stprintf("dns auth search %s", ipname);
if (AuthReader != NULL && *AuthReader == '1') {
if (*dres->dr_AuthDef->au_Cdb != '!')
Authenticated = 1;
if (DebugOpt)
printf("Authenticated via cdb\n");
} else if (*dres->dr_AuthDef->au_Cdb == '!') {
authok = 0;
Authenticated = -1;
if (DebugOpt)
printf("Authentication via cdb REJECTED\n");
} else {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via cdb FAILED\n");
}
}
#else
if (authok && *dres->dr_AuthDef->au_Cdb && *user &&
*dreq->dr_AuthPass) {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via cdb FAILED\n");
logit(LOG_ERR, "CDB authentication requested, but not enabled");
}
#endif /* CDB_ENABLED */
#ifdef DB_ENABLED
/*
* Check for the user+pass in a DB
*/
if (authok && *dres->dr_AuthDef->au_Db && *user &&
*dreq->dr_AuthPass) {
stprintf("dns auth db %s@%s", user, ipname);
AuthReader = dbAuthenticate(user, dreq->dr_AuthPass,
dres->dr_AuthDef->au_Db);
stprintf("dns auth search %s", ipname);
if (AuthReader != NULL && *AuthReader == '1') {
if (*dres->dr_AuthDef->au_Db != '!')
Authenticated = 1;
if (DebugOpt)
printf("Authenticated via db\n");
} else if (*dres->dr_AuthDef->au_Db == '!') {
authok = 0;
Authenticated = -1;
if (DebugOpt)
printf("Authentication via db REJECTED\n");
} else {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via db FAILED\n");
}
}
#else
if (authok && *dres->dr_AuthDef->au_Db && *user &&
*dreq->dr_AuthPass) {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via db FAILED\n");
logit(LOG_ERR, "DB authentication requested, but not enabled");
}
#endif /* DB_ENABLED */
#ifdef NETREMOTE_ENABLED
/*
* Check user+pass with NetRemote server
*/
if (authok && *dres->dr_AuthDef->au_NetRemote && *user &&
*dreq->dr_AuthPass) {
stprintf("dns auth netremote %s@%s", user, ipname);
AuthReader = netRemoteAuthenticate(user, dreq->dr_AuthPass,
dres->dr_AuthDef->au_NetRemote,
NetAddrToSt(0, (struct sockaddr *)&dreq->dr_LSin, 1, 0, 1));
stprintf("dns auth search %s", ipname);
if (AuthReader != NULL && *AuthReader == '1') {
Authenticated = 1;
if (DebugOpt)
printf("Authenticated via NetRemote: %s\n", AuthReader);
} else {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via NetRemote FAILED\n");
}
}
#else
if (authok && *dres->dr_AuthDef->au_NetRemote && *user &&
*dreq->dr_AuthPass) {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via NetRemote FAILED\n");
logit(LOG_ERR, "NetRemote authentication requested, but not enabled");
}
#endif
#ifdef LDAP_ENABLED
/*
* Check user+pass with LDAP server
*/
if (authok && *dres->dr_AuthDef->au_LDAP && *user &&
*dreq->dr_AuthPass) {
stprintf("dns auth ldap %s@%s", user, ipname);
#ifdef NEW_LDAP
AuthReader = LDAPAuthenticate(user, dreq->dr_AuthPass, realm,
dres->dr_AuthDef->au_LDAP);
#else
AuthReader = LDAPAuthenticate(user, dreq->dr_AuthPass,
dres->dr_AuthDef->au_LDAP);
#endif
stprintf("dns auth search %s", ipname);
if (AuthReader != NULL && *AuthReader == '1') {
Authenticated = 1;
if (DebugOpt)
printf("Authenticated via LDAP\n");
} else {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via LDAP FAILED\n");
}
}
#else
if (authok && *dres->dr_AuthDef->au_LDAP && *user &&
*dreq->dr_AuthPass) {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via LDAP FAILED\n");
logit(LOG_ERR, "LDAP authentication requested, but not enabled");
}
#endif
#ifdef PERL_ENABLED
if (authok && *dres->dr_AuthDef->au_Perl && *user &&
*dreq->dr_AuthPass) {
stprintf("dns auth perl %s@%s", user, ipname);
AuthReader = PerlAuthenticate(user, dreq->dr_AuthPass,
dres->dr_AuthDef->au_Perl);
stprintf("dns auth search %s", ipname);
if (AuthReader != NULL && *AuthReader == '1') {
Authenticated = 1;
if (DebugOpt)
printf("Authenticated via Perl\n");
} else {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via Perl FAILED\n");
}
}
#else
if (authok && *dres->dr_AuthDef->au_Perl && *user &&
*dreq->dr_AuthPass) {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via Perl FAILED\n");
logit(LOG_ERR, "Perl authentication requested, but not enabled");
}
#endif
#ifdef PAM_ENABLED
/*
* Check user+pass with radius server
*/
if (authok && *dres->dr_AuthDef->au_PAM && *user &&
*dreq->dr_AuthPass) {
stprintf("dns auth PAM %s@%s", user, ipname);
AuthReader = PamAuthenticate(user, dreq->dr_AuthPass,
dres->dr_AuthDef->au_PAM);
stprintf("dns auth search %s", ipname);
if (AuthReader != NULL && *AuthReader == '1') {
Authenticated = 1;
if (DebugOpt)
printf("Authenticated via PAM\n");
} else {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via PAM FAILED\n");
}
}
#else
if (authok && *dres->dr_AuthDef->au_PAM && *user &&
*dreq->dr_AuthPass) {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via PAM FAILED\n");
logit(LOG_ERR, "PAM authentication requested, but not enabled");
}
#endif
/*
* Check a user+pass specified in the auth config
*/
if (authok && *dres->dr_AuthDef->au_User && *user &&
*dres->dr_AuthDef->au_Pass && *dreq->dr_AuthPass) {
if (!strcmp(user, dres->dr_AuthDef->au_User) &&
!strcmp(dreq->dr_AuthPass, dres->dr_AuthDef->au_Pass)) {
Authenticated = 1;
if (DebugOpt)
printf("Authenticated via user+pass\n");
} else {
Authenticated = -1;
if (DebugOpt)
printf("Authentication via user+pass FAILED\n");
}
}
}
if (!AuthNeeded ||
/* AUTHINFO and matched */
(Authenticated > 0 && *dreq->dr_AuthPass) ||
/* Ident + user only */
(Authenticated == 2) ||
/* AUTHINFO and not failed auth, but no other match */
(Authenticated == 0 && (matchedalp == NULL))
) {
if (accessfile == 1) {
memcpy(&matchedaccessdef, &accessdef, sizeof(accessdef));
matchedalp = &matchedaccessdef;
MatchedAuthenticated = Authenticated;
MatchedAuthNeeded = AuthNeeded;
} else {
matchedalp = alp;
MatchedAuthenticated = Authenticated;
MatchedAuthNeeded = AuthNeeded;
}
}
if (matchedalp && matchedalp->ad_MatchExit)
break;
}
if (accessfile == 1)
fclose(af);
if (matchedalp == NULL) {
if (DebugOpt)
printf("No access match\n");
dres->dr_Code = 0;
return;
}
if (!dres->dr_ReaderDef->rd_IgnoreAuthInfo && *dreq->dr_AuthPass &&
MatchedAuthenticated <= 0) {
if (DebugOpt)
printf("Authentication failed\n");
dres->dr_Code = 0;
return;
}
if (AuthReader && strncmp(AuthReader, "110 ", 4) == 0) {
AuthReader += 4;
strncpy(dres->dr_ReaderName, AuthReader, sizeof(dres->dr_ReaderName) - 1);
dres->dr_ReaderName[sizeof(dres->dr_ReaderName) - 1] = '\0';
} else {
strncpy(dres->dr_ReaderName, matchedalp->ad_Reader, sizeof(dres->dr_ReaderName) - 1);
dres->dr_ReaderName[sizeof(dres->dr_ReaderName) - 1] = '\0';
}
SetAuthDetails(dres, dres->dr_ReaderName);
/*
* Now we have checked against all the access lines and matchedalp
* points to the last match
*/
if (DebugOpt > 1)
PrintAuthDetails(dres);
/*
* okay, if this was an authentication request, and we didn't auth,
* then return a failure
*/
dres->dr_Flags &= ~DF_AUTHREQUIRED;
if (MatchedAuthNeeded && !MatchedAuthenticated) {
dres->dr_Flags |= DF_AUTHREQUIRED;
}
/*
* If we authenticated with AUTHUSER, mark that we have done so as
* we would like to log the correct info in log lines
*/
if (MatchedAuthenticated <= 0) {
dres->dr_AuthUser[0] = 0;
dres->dr_Flags &= ~DF_AUTH;
} else {
dres->dr_Flags |= DF_AUTH;
}
dres->dr_Code = 1;
if ((dres->dr_Flags & (DF_FEED|DF_READ|DF_POST|DF_STATUS|DF_AUTHREQUIRED)) == 0)
dres->dr_Code = 0;
}
/*
* IDENT
*
* getAuthUser() - authenticate the remote username by connecting to port
* 113 and requesting the user id of the remote port. This
* is used by X-Trace: and some authentication.
*/
void
getAuthUser(const struct sockaddr *plsin, const struct sockaddr *prsin, char *ubuf, int ulen)
{
#ifdef INET6
/*
* XXX This needs to be updated to do INET6 ident requests
*/
#else
int cfd;
int lport;
int rport;
int n;
char buf[256];
struct sockaddr_in lsin;
struct sockaddr_in rsin;
memcpy(&lsin, plsin, sizeof(lsin));
memcpy(&rsin, prsin, sizeof(rsin));
rport = ntohs(rsin.sin_port);
lport = ntohs(lsin.sin_port);
lsin.sin_port = 0;
lsin.sin_family = AF_INET;
if ((cfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return;
}
if (bind(cfd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) {
perror("bind");
close(cfd);
return;
}
rsin.sin_port = htons(113);
rsin.sin_family = AF_INET;
/*
* Do asynchronous connection with 10 second timeout. The timeout is
* necessary to deal with broken clients or firewalls.
*/
fcntl(cfd, F_SETFL, O_NONBLOCK);
errno = 0;
if (connect(cfd, (struct sockaddr *)&rsin, sizeof(rsin)) < 0) {
fd_set wfds;
struct timeval tv = { 10, 0 };
if (errno != EINPROGRESS) {
close(cfd);
return;
}
FD_ZERO(&wfds);
FD_SET(cfd, &wfds);
if (select(cfd + 1, NULL, &wfds, NULL, &tv) == 0) {
close(cfd);
cfd = -1;
}
}
/*
* Send query, interpret response
*
* write() may fail if connect() failed to establish a connection.
*/
if (cfd >= 0) {
fcntl(cfd, F_SETFL, 0);
sprintf(buf, "%d, %d\r\n", rport, lport);
if (DebugOpt)
printf("IDENTD COMMAND %s\n", buf);
if (write(cfd, buf, strlen(buf)) != strlen(buf)) {
n = -1;
} else {
fcntl(cfd, F_SETFL, O_NONBLOCK);
n = readtoeof(cfd, buf, sizeof(buf) - 1, 10);
}
} else {
n = -1;
}
if (n > 0) {
char *uid;
buf[n] = 0;
if (DebugOpt)
printf("IDENTD RESPONSE %s\n", buf);
if ((uid = strstr(buf, "USERID")) != NULL) {
uid = strchr(uid + 1, ':');
if (uid) {
uid = strchr(uid + 1, ':');
if (uid) {
uid = strtok(uid + 1, "\r\n: \t");
if (uid && strlen(uid) < ulen) {
strncpy(ubuf, uid, sizeof(ubuf) - 1);
ubuf[sizeof(ubuf) - 1] = '\0';
SanitizeString(ubuf);
}
}
}
}
}
if (cfd >= 0)
close(cfd);
#endif
}
int
readExactly(int fd, void *buf, int bytes)
{
int r = 0;
while (bytes > 0) {
int n = read(fd, buf, bytes);
if (n <= 0) {
if (n < 0 && r == 0)
r = -1;
break;
}
buf = (char *)buf + n;
bytes -= n;
r += n;
}
return(r);
}
int
readtoeof(int fd, void *buf, int bytes, int secs)
{
fd_set rfds;
int r = 0;
FD_ZERO(&rfds);
for (;;) {
struct timeval tv = { 0, 0 };
int n;
tv.tv_sec = secs;
FD_SET(fd, &rfds);
if (select(fd + 1, &rfds, NULL, NULL, &tv) == 0)
break;
errno = 0;
n = read(fd, buf, bytes);
if (n == 0)
break;
if (n < 0) {
if (errno == EWOULDBLOCK ||
errno == EINTR ||
errno == EAGAIN
) {
continue;
}
break;
}
r += n;
buf = (char *)buf + n;
bytes -= n;
}
return(r);
}
void
sigSegVDNS(int sigNo)
{
if (DFd >= 0)
close(DFd);
nice(20);
for (;;)
;
}
int
readAccessLine(FILE *af, char *fname, AccessDef *adef)
{
static int needread = 1;
static int linecount = 0;
static char buf[8192] = "";
static char *opt;
static char *val;
char *p;
while (needread) {
if (fgets(buf, sizeof(buf), af) == NULL)
return(0);
linecount++;
opt = buf;
while (isspace((int)*opt))
opt++;
if (*opt == '#' || *opt == '\n' || *opt == '\0')
continue;
p = opt + 6;
*p = '\0';
if (strcmp(opt, "access") == 0) {
opt += 7;
while (isspace((int)*opt))
opt++;
bzero(adef, sizeof(AccessDef));
break;
} else {
logit(LOG_ERR, "%s: Invalid command %s in line %d",
fname, opt, linecount);
return(0);
}
}
/*
* At this point we should be pointing to the wildmat pattern
*/
if (opt == NULL) {
logit(LOG_ERR, "%s: Missing wildmat in line %d",
fname, linecount);
needread = 1;
return(0);
}
if (needread) {
val = strtok(opt, " \t");
val = strtok(NULL, " \t");
if (val == NULL) {
logit(LOG_ERR, "%s: Invalid readerdef in line %d",
fname, linecount);
needread = 1;
return(0);
}
while (isspace((int)*val))
val++;
if (*val == '#' || *val == '\n' || *val == '\0') {
logit(LOG_ERR, "%s: Invalid readerdef in line %d",
fname, linecount);
needread = 1;
return(0);
}
p = strchr(val, '\n');
if (p)
*p = '\0';
strncpy(adef->ad_Reader, val, sizeof(adef->ad_Reader) - 1);
adef->ad_Reader[sizeof(adef->ad_Reader) - 1] = '\0';
}
p = strchr(opt, ',');
if (p != NULL) {
*p++ = '\0';
needread = 1;
} else {
p = opt;
}
{
/*
* Check for identuser@
*/
char *q;
if (*opt && (q = strchr(opt, '@')) != NULL) {
*q++ = '\0';
strncpy(adef->ad_IdentUser, opt, sizeof(adef->ad_IdentUser) - 1);
adef->ad_IdentUser[sizeof(adef->ad_IdentUser) - 1] = '\0';
opt = q;
}
}
if (*opt && strlen(opt) < sizeof(adef->ad_Pattern)) {
strncpy(adef->ad_Pattern, opt, sizeof(adef->ad_Pattern) - 1);
adef->ad_Pattern[sizeof(adef->ad_Pattern) - 1] = '\0';
opt = p;
return(1);
}
logit(LOG_ERR, "%s: Bad length for access %s in line %d",
fname, opt, linecount);
needread = 1;
return(0);
}
/*
* Install a new copy of the access cache
* This is done by creating the new cache files first, locking and then
* renaming the files.
*/
void
InstallAccessCache() {
struct stat st;
char buf[1024];
int linecount = 0;
int tfp;
FILE *fp;
FILE *vsf;
FILE *grf;
FILE *auf;
FILE *rdf;
FILE *raf;
char *opt;
char *val;
Vserver vserver;
GroupDef groupdef;
AuthDef authdef;
ReaderDef readerdef;
GroupList *groupptr = NULL;
AccessDef accessdef;
int copt = OPT_NONE;
char vsnewbuf[PATH_MAX];
char grnewbuf[PATH_MAX];
char aunewbuf[PATH_MAX];
char rdnewbuf[PATH_MAX];
char ranewbuf[PATH_MAX];
if ((stat(PatLibExpand(DReaderAccessPat), &st) == 0) &&
(st.st_mtime <= Access_LastUpdate))
return;
logit(LOG_INFO, "Installing access cache");
if ((fp = fopen(PatLibExpand(DReaderAccessPat), "r")) == NULL) {
logit(LOG_CRIT, "Unable to open %s (%s)",
PatLibExpand(DReaderAccessPat), strerror(errno));
return;
}
if (fstat(fileno(fp), &st) != 0) {
fclose(fp);
return;
}
Access_LastUpdate = st.st_mtime;
snprintf(vsnewbuf, sizeof(vsnewbuf), "%s.new",
PatDbExpand(DRVserverCachePat));
snprintf(grnewbuf, sizeof(grnewbuf), "%s.new",
PatDbExpand(DRGroupCachePat));
snprintf(aunewbuf, sizeof(aunewbuf), "%s.new",
PatDbExpand(DRAuthCachePat));
snprintf(rdnewbuf, sizeof(rdnewbuf), "%s.new",
PatDbExpand(DRReaderCachePat));
snprintf(ranewbuf, sizeof(ranewbuf), "%s.new",
PatDbExpand(DRAccessCachePat));
if ((vsf = fopen(vsnewbuf, "w+")) == NULL) {
logit(LOG_CRIT, "Unable to create %s (%s)", vsnewbuf, strerror(errno));
fclose(fp);
return;
}
if ((grf = fopen(grnewbuf, "w+")) == NULL) {
logit(LOG_CRIT, "Unable to create %s (%s)", grnewbuf, strerror(errno));
fclose(fp);
fclose(vsf);
return;
}
if ((auf = fopen(aunewbuf , "w+")) == NULL) {
logit(LOG_CRIT, "Unable to create %s (%s)", aunewbuf, strerror(errno));
fclose(fp);
fclose(vsf);
fclose(grf);
return;
}
if ((rdf = fopen(rdnewbuf, "w+")) == NULL) {
logit(LOG_CRIT, "Unable to create %s (%s)", rdnewbuf, strerror(errno));
fclose(fp);
fclose(vsf);
fclose(grf);
fclose(auf);
return;
}
if ((raf = fopen(ranewbuf, "w+")) == NULL) {
logit(LOG_CRIT, "Unable to create %s (%s)", ranewbuf, strerror(errno));
fclose(fp);
fclose(vsf);
fclose(grf);
fclose(auf);
fclose(rdf);
return;
}
/* The first entry is the default */
bzero(&vserver, sizeof(vserver));
strcpy(vserver.vs_Name, "DEFAULT");
if (DOpts.ReaderHostName != NULL)
strncpy(vserver.vs_HostName, DOpts.ReaderHostName, sizeof(vserver.vs_HostName) - 1);
if (DOpts.ReaderHostName != NULL)
strncpy(vserver.vs_ClusterName, DOpts.ReaderHostName, sizeof(vserver.vs_ClusterName) - 1);
if (DOpts.ReaderPathHost != NULL)
strncpy(vserver.vs_PostPath, DOpts.ReaderPathHost, sizeof(vserver.vs_PostPath) - 1);
if (DOpts.NewsAdmin != NULL)
strncpy(vserver.vs_NewsAdm, DOpts.NewsAdmin, sizeof(vserver.vs_NewsAdm) - 1);
fwrite(&vserver, sizeof(vserver), 1, vsf);
fwrite("DEFAULT\0", 8, 1, grf);
groupdef.gr_Count = 1;
fwrite("1\0", 2, 1, grf);
fwrite("*\0", 2, 1, grf);
bzero(&authdef, sizeof(authdef));
strcpy(authdef.au_Name, "DEFAULT");
fwrite(&authdef, sizeof(authdef), 1, auf);
bzero(&readerdef, sizeof(readerdef));
strcpy(readerdef.rd_Name, "DEFAULT");
strcpy(readerdef.rd_Auth, "DEFAULT");
strcpy(readerdef.rd_Groups, "DEFAULT");
strcpy(readerdef.rd_ListGroups, "DEFAULT");
strcpy(readerdef.rd_PostGroups, "DEFAULT");
strcpy(readerdef.rd_Vserver, "DEFAULT");
fwrite(&readerdef, sizeof(readerdef), 1, rdf);
while (fgets(buf, sizeof(buf), fp) != NULL) {
linecount++;
opt = buf;
while (isspace((int)*opt))
opt++;
opt = strtok(opt, " \t\n");
if (opt == NULL || *opt == '#' || *opt == '\n' || *opt == '\0')
continue;
val = strtok(NULL, "\n");
if (val == NULL || *val == '#')
val = "";
else
while (isspace((int)*val))
val++;
if (strcmp(opt, "end") == 0) {
switch (copt) {
case OPT_NONE:
logit(LOG_ERR, "Found 'end' without define in line %d", linecount);
break;
case OPT_VSERVER:
if (!*vserver.vs_ClusterName)
strcpy(vserver.vs_ClusterName, vserver.vs_HostName);
if (strcmp(vserver.vs_Name, "DEFAULT") == 0) {
long fpos;
fpos = ftell(vsf);
fseek(vsf, 0L, SEEK_SET);
fwrite(&vserver, sizeof(vserver), 1, vsf);
fseek(vsf, fpos, SEEK_SET);
} else {
fwrite(&vserver, sizeof(vserver), 1, vsf);
}
bzero(&vserver, sizeof(vserver));
break;
case OPT_GROUPS:
fwrite(groupdef.gr_Name, strlen(groupdef.gr_Name) + 1, 1, grf);
zfreeStr(&DnsMemPool, &groupdef.gr_Name);
{
char buf[10];
struct GroupList *gpp;
struct GroupList *gp;
sprintf(buf, "%d", groupdef.gr_Count);
fwrite(&buf, strlen(buf) + 1, 1, grf);
gp = groupdef.gr_Groups;
while (gp != NULL) {
fwrite(gp->group, strlen(gp->group) + 1, 1, grf);
gpp = gp;
gp = gp->next;
zfreeStr(&DnsMemPool, &gpp->group);
zfree(&DnsMemPool, gpp, sizeof(GroupList));
}
}
bzero(&groupdef, sizeof(groupdef));
break;
case OPT_AUTH:
if (strcmp(authdef.au_Name, "DEFAULT") == 0) {
long fpos;
fpos = ftell(auf);
fseek(auf, 0L, SEEK_SET);
fwrite(&authdef, sizeof(authdef), 1, auf);
fseek(auf, fpos, SEEK_SET);
} else {
fwrite(&authdef, sizeof(authdef), 1, auf);
}
bzero(&authdef, sizeof(authdef));
break;
case OPT_READERGRP:
if (strcmp(readerdef.rd_Name, "DEFAULT") == 0) {
long fpos;
fpos = ftell(rdf);
fseek(rdf, 0L, SEEK_SET);
fwrite(&readerdef, sizeof(readerdef), 1, rdf);
fseek(rdf, fpos, SEEK_SET);
} else {
fwrite(&readerdef, sizeof(readerdef), 1, rdf);
}
bzero(&readerdef, sizeof(readerdef));
break;
}
copt = OPT_NONE;
continue;
}
if (!*val) {
logit(LOG_ERR, "dreader.access: Missing value/label for %s in line %d", opt, linecount);
Access_LastUpdate = 0;
continue;
}
/* Handle the definition options */
switch (copt) {
case OPT_NONE: break;
case OPT_VSERVER:
if (*val && strcmp(opt, "clustername") == 0) {
strncpy(vserver.vs_ClusterName, val, sizeof(vserver.vs_ClusterName) - 1);
continue;
}
if (*val && strcmp(opt, "hostname") == 0) {
strncpy(vserver.vs_HostName, val, sizeof(vserver.vs_HostName) - 1);
continue;
}
if (*val && strcmp(opt, "postpath") == 0) {
strncpy(vserver.vs_PostPath, val, sizeof(vserver.vs_PostPath) - 1);
if (strcmp(val, "0") == 0)
vserver.vs_PostPath[0] = 0;
continue;
}
if (*val && strcmp(opt, "newsadmin") == 0) {
strncpy(vserver.vs_NewsAdm, val, sizeof(vserver.vs_NewsAdm) - 1);
continue;
}
if (*val && ((strcmp(opt, "organisation") == 0) ||
(strcmp(opt, "organization") == 0))) {
strncpy(vserver.vs_Org, val, sizeof(vserver.vs_Org) - 1);
continue;
}
if (*val && strcmp(opt, "abuseto") == 0) {
strncpy(vserver.vs_AbuseTo, val, sizeof(vserver.vs_AbuseTo) - 1);
continue;
}
if (*val && strcmp(opt, "cryptpw") == 0) {
strncpy(vserver.vs_CryptPw, val, sizeof(vserver.vs_CryptPw) - 1);
continue;
}
if (*val && strcmp(opt, "accessfile") == 0) {
strncpy(vserver.vs_AccessFile, val, sizeof(vserver.vs_AccessFile) - 1);
continue;
}
if (*val && strcmp(opt, "welcome") == 0) {
strncpy(vserver.vs_Welcome, val, sizeof(vserver.vs_Welcome) - 1);
continue;
}
if (*val && strcmp(opt, "interface") == 0) {
#ifdef INET6
int error;
struct addrinfo *res;
error = getaddrinfo(val, 0, NULL, &res);
if (error != 0)
logit(LOG_ERR, "getaddrinfo: %s: %s\n",
val, gai_strerror(error));
else
memcpy(&vserver.vs_Interface, &res->ai_addr,
res->ai_addrlen);
#else
struct sockaddr_in *sin = (struct sockaddr_in *)&vserver.vs_Interface;
bzero(&vserver.vs_Interface, sizeof(vserver.vs_Interface));
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr(val);
#endif
continue;
}
if (*val && strcmp(opt, "noxrefhostupdate") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
vserver.vs_NoXrefHostUpdate = 1;
else
vserver.vs_NoXrefHostUpdate = 0;
continue;
}
if (*val && strcmp(opt, "noreadpath") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
vserver.vs_NoReadPath = 1;
else
vserver.vs_NoReadPath = 0;
continue;
}
if (*val && strcmp(opt, "postcomments") == 0) {
strncpy(vserver.vs_Comments, val, sizeof(vserver.vs_Comments) - 1);
continue;
}
if (*val && strcmp(opt, "posttrailer") == 0) {
strncpy(vserver.vs_PostTrailer, val, sizeof(vserver.vs_PostTrailer) - 1);
continue;
}
logit(LOG_ERR, "dreader.access: Invalid vserverdef option : %s in line %d\n", opt, linecount);
continue;
case OPT_GROUPS:
if (*val && strcmp(opt, "group") == 0) {
if (groupdef.gr_Groups == NULL) {
groupptr = zalloc(&DnsMemPool, sizeof(GroupList));
groupptr->group = zallocStr(&DnsMemPool, val);
groupptr->next = NULL;
groupdef.gr_Groups = groupptr;
groupdef.gr_Count++;
} else {
groupptr->next = zalloc(&DnsMemPool, sizeof(GroupList));
groupptr = groupptr->next;
groupptr->group = zallocStr(&DnsMemPool, val);
groupptr->next = NULL;
groupdef.gr_Count++;
}
continue;
}
logit(LOG_ERR, "dreader.access: Invalid groupdef option : %s in line %d\n", opt, linecount);
continue;
case OPT_AUTH:
if (*val && strcmp(opt, "file") == 0) {
strncpy(authdef.au_File, val, sizeof(authdef.au_File) - 1);
continue;
}
if (*val && strcmp(opt, "cdb") == 0) {
strncpy(authdef.au_Cdb, val, sizeof(authdef.au_Cdb) - 1);
continue;
}
if (*val && strcmp(opt, "db") == 0) {
strncpy(authdef.au_Db, val, sizeof(authdef.au_Db) - 1);
continue;
}
if (*val && strcmp(opt, "external") == 0) {
strncpy(authdef.au_External, val, sizeof(authdef.au_External) - 1);
continue;
}
if (*val && strcmp(opt, "radius") == 0) {
strncpy(authdef.au_Radius, val, sizeof(authdef.au_Radius) - 1);
continue;
}
if (*val && strcmp(opt, "netremote") == 0) {
strncpy(authdef.au_NetRemote, val, sizeof(authdef.au_NetRemote) - 1);
continue;
}
if (*val && strcmp(opt, "ldap") == 0) {
strncpy(authdef.au_LDAP, val, sizeof(authdef.au_LDAP) - 1);
continue;
}
if (*val && strcmp(opt, "perl") == 0) {
strncpy(authdef.au_Perl, val, sizeof(authdef.au_Perl) - 1);
continue;
}
if (*val && strcmp(opt, "pam") == 0) {
strncpy(authdef.au_PAM, val, sizeof(authdef.au_PAM) - 1);
continue;
}
if (*val && strcmp(opt, "user") == 0) {
strncpy(authdef.au_User, val, sizeof(authdef.au_User) - 1);
continue;
}
if (*val && strcmp(opt, "pass") == 0) {
strncpy(authdef.au_Pass, val, sizeof(authdef.au_Pass) - 1);
continue;
}
if (*val && strcmp(opt, "addrealm") == 0) {
strncpy(authdef.au_AddRealm, val, sizeof(authdef.au_AddRealm) - 1);
continue;
}
if (*val && strcmp(opt, "realm") == 0) {
strncpy(authdef.au_Realm, val, sizeof(authdef.au_Realm) - 1);
continue;
}
if (*val && strcmp(opt, "ident") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
authdef.au_Ident = 1;
else
authdef.au_Ident = 0;
continue;
}
logit(LOG_ERR, "dreader.access: Invalid authdef option : %s in line %d\n", opt, linecount);
continue;
case OPT_READERGRP:
if (*val && strcmp(opt, "auth") == 0) {
strncpy(readerdef.rd_Auth, val, sizeof(readerdef.rd_Auth) - 1);
continue;
}
if (*val && strcmp(opt, "groups") == 0) {
strncpy(readerdef.rd_Groups, val, sizeof(readerdef.rd_Groups) - 1);
if (strcmp(readerdef.rd_ListGroups, "DEFAULT") == 0)
strncpy(readerdef.rd_ListGroups, val, sizeof(readerdef.rd_Groups) - 1);
if (strcmp(readerdef.rd_PostGroups, "DEFAULT") == 0)
strncpy(readerdef.rd_PostGroups, val, sizeof(readerdef.rd_Groups) - 1);
continue;
}
if (*val && strcmp(opt, "listgroups") == 0) {
strncpy(readerdef.rd_ListGroups, val, sizeof(readerdef.rd_Groups) - 1);
continue;
}
if (*val && strcmp(opt, "postgroups") == 0) {
strncpy(readerdef.rd_PostGroups, val, sizeof(readerdef.rd_Groups) - 1);
continue;
}
if (*val && strcmp(opt, "vserver") == 0) {
strncpy(readerdef.rd_Vserver, val, sizeof(readerdef.rd_Vserver) - 1);
continue;
}
if (*val && strcmp(opt, "read") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_Read = 1;
else
readerdef.rd_Read = 0;
continue;
}
if (*val && strcmp(opt, "post") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_Post = 1;
else
readerdef.rd_Post = 0;
continue;
}
if (*val && strcmp(opt, "feed") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_Feed = 1;
else
readerdef.rd_Feed = 0;
continue;
}
if (*val && strcmp(opt, "status") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_Status = 1;
else
readerdef.rd_Status = 0;
continue;
}
if (*val && strcmp(opt, "quiet") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_Quiet = 1;
else
readerdef.rd_Quiet = 0;
continue;
}
if (*val && strcmp(opt, "controlpost") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_ControlPost = 1;
else
readerdef.rd_ControlPost = 0;
continue;
}
if (*val && strcmp(opt, "maxconn") == 0) {
readerdef.rd_MaxConnTotal = atoi(val);
continue;
}
if (*val && strcmp(opt, "maxconnperhost") == 0) {
readerdef.rd_MaxConnPerHost = atoi(val);
continue;
}
if (*val && strcmp(opt, "maxconnperuser") == 0) {
readerdef.rd_MaxConnPerUser = atoi(val);
continue;
}
if (*val && strcmp(opt, "maxconnpergroup") == 0) {
readerdef.rd_MaxConnPerGroup = atoi(val);
continue;
}
if (*val && strcmp(opt, "maxconnpervs") == 0) {
readerdef.rd_MaxConnPerVs = atoi(val);
continue;
}
if (*val && strcmp(opt, "ratelimit") == 0) {
getRateLimitCmds(val, &readerdef);
continue;
}
if (*val && strcmp(opt, "ratelimittax") == 0) {
readerdef.rd_RateLimitTax = atoi(val);
continue;
}
if (*val && strcmp(opt, "bytelimit") == 0) {
readerdef.rd_ByteLimit = atoi(val);
continue;
}
if (*val && strcmp(opt, "pathcomponents") == 0) {
readerdef.rd_PathComponents = atoi(val);
continue;
}
if (*val && strcmp(opt, "idletimeout") == 0) {
readerdef.rd_IdleTimeout = atoi(val);
continue;
}
if (*val && strcmp(opt, "sessiontimeout") == 0) {
readerdef.rd_SessionTimeout = atoi(val);
continue;
}
if (*val && strcmp(opt, "allowdnsmismatch") == 0) {
/* Historical option - ignore it */
logit(LOG_NOTICE, "dreader.access: Ignoring historical option 'allowdnsmismatch' in line %d", linecount);
continue;
}
if (*val && strcmp(opt, "useverifieddns") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_UseVerifiedDns = 1;
else
readerdef.rd_UseVerifiedDns = 0;
continue;
}
if (*val && strcmp(opt, "denymismatcheddns") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_DenyMismatchedDns = 1;
else
readerdef.rd_DenyMismatchedDns = 0;
continue;
}
if (*val && strcmp(opt, "denynodns") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_DenyNoDns = 1;
else
readerdef.rd_DenyNoDns = 0;
continue;
}
if (*val && strcmp(opt, "allownewnews") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_AllowNewnews = 1;
else
readerdef.rd_AllowNewnews = 0;
continue;
}
if (*val && strcmp(opt, "grouplog") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_GroupLog = 1;
else
readerdef.rd_GroupLog = 0;
continue;
}
if (*val && strcmp(opt, "spoolheaders") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_SpoolHeaders = 1;
else
readerdef.rd_SpoolHeaders = 0;
continue;
}
if (*val && strcmp(opt, "ignoreauthinfo") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_IgnoreAuthInfo = 1;
else
readerdef.rd_IgnoreAuthInfo = 0;
continue;
}
if (*val && strcmp(opt, "checkpostgroups") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_CheckPostGroups = 1;
else
readerdef.rd_CheckPostGroups = 0;
continue;
}
if (*val && strcmp(opt, "logcmd") == 0) {
if (*val == 'y' || *val == 'Y' || *val == '1')
readerdef.rd_LogCmd = 1;
else
readerdef.rd_LogCmd = 0;
continue;
}
logit(LOG_ERR, "dreader.access: Invalid readerdef option : %s in line %d\n", opt, linecount);
continue;
}
/* Start of a new definition */
if (strcmp(opt, "vserverdef") == 0) {
copt = OPT_VSERVER;
bzero(&vserver, sizeof(vserver));
strncpy(vserver.vs_Name, val, sizeof(vserver.vs_Name) - 1);
continue;
}
if (strcmp(opt, "groupdef") == 0) {
copt = OPT_GROUPS;
bzero(&groupdef, sizeof(groupdef));
groupdef.gr_Name = zallocStr(&DnsMemPool, val);
groupdef.gr_Count = 0;
groupdef.gr_Groups = NULL;
continue;
}
if (strcmp(opt, "authdef") == 0) {
copt = OPT_AUTH;
bzero(&authdef, sizeof(authdef));
strncpy(authdef.au_Name, val, sizeof(authdef.au_Name) - 1);
continue;
}
if (strcmp(opt, "readerdef") == 0) {
copt = OPT_READERGRP;
bzero(&readerdef, sizeof(readerdef));
strncpy(readerdef.rd_Name, val, sizeof(readerdef.rd_Name) - 1);
readerdef.rd_ControlPost = 1;
readerdef.rd_GroupLog = 1;
readerdef.rd_CheckPostGroups = 1;
readerdef.rd_LogCmd = -1;
strcpy(readerdef.rd_Auth, "DEFAULT");
strcpy(readerdef.rd_Groups, "DEFAULT");
strcpy(readerdef.rd_ListGroups, "DEFAULT");
strcpy(readerdef.rd_PostGroups, "DEFAULT");
strcpy(readerdef.rd_Vserver, "DEFAULT");
continue;
}
if (strcmp(opt, "access") == 0) {
char *p;
char *q;
bzero(&accessdef, sizeof(accessdef));
copt = OPT_NONE;
p = strtok(val, " \t");
p = strtok(NULL, " \t");
if (p == NULL) {
logit(LOG_ERR, "dreader.access: Invalid readerdef for access %s in line %d", val, linecount);
continue;
}
while (*p == ' ' || *p == '\t')
p++;
if (!*p || strlen(p) > sizeof(accessdef.ad_Reader)) {
logit(LOG_ERR, "dreader.access: Invalid readerdef for access %s in line %d", val, linecount);
continue;
}
if (*p == '|') {
p++;
accessdef.ad_MatchExit = 1;
}
strncpy(accessdef.ad_Reader, p, sizeof(accessdef.ad_Reader) - 1);
p = strtok(val, ",");
p = strtok(NULL, ",");
for (q = val; q != NULL; q = p, p = strtok(NULL, ",")) {
char *pp = q;
if ((q = strchr(pp, '@')) != NULL) {
*q++ = '\0';
if (!*pp || strlen(pp) > sizeof(accessdef.ad_Pattern)) {
logit(LOG_ERR, "dreader.access: Bad length for ident user %s in line %d", q, linecount);
continue;
}
strncpy(accessdef.ad_IdentUser, pp,
sizeof(accessdef.ad_IdentUser) - 1);
} else {
q = pp;
}
if (!*q || strlen(q) > sizeof(accessdef.ad_Pattern)) {
logit(LOG_ERR, "dreader.access: Bad length for access %s in line %d", q, linecount);
continue;
}
strncpy(accessdef.ad_Pattern, q, sizeof(accessdef.ad_Pattern) - 1);
fwrite(&accessdef, sizeof(accessdef), 1, raf);
}
continue;
}
logit(LOG_ERR, "dreader.access: Invalid access definition : %s in line %d\n", opt, linecount);
Access_LastUpdate = 0;
}
fclose(fp);
fclose(vsf);
fclose(grf);
fclose(auf);
fclose(rdf);
fclose(raf);
if (Access_LastUpdate == 0) {
logit(LOG_ERR, "Errors in dreader.access file - not updating");
return;
}
/*
* We create a lock file that means no other processes should make
* updates from the cache. The lock file time is also checked to
* cater for possible race conditions.
*/
if ((tfp = open(PatDbExpand(DRAccessLockPat), O_RDWR|O_CREAT, 0644)) <= 0) {
logit(LOG_CRIT, "Cannot create access lock %s",
PatDbExpand(DRAccessLockPat));
Access_LastUpdate = 0;
return;
}
if (xflock(tfp, XLOCK_SH) < 0) {
if (DebugOpt)
printf("Unable to obtain access lock (%s)\n", strerror(errno));
Access_LastUpdate = 0;
return;
}
rename(vsnewbuf, PatDbExpand(DRVserverCachePat));
rename(grnewbuf, PatDbExpand(DRGroupCachePat));
rename(aunewbuf, PatDbExpand(DRAuthCachePat));
rename(rdnewbuf, PatDbExpand(DRReaderCachePat));
rename(ranewbuf, PatDbExpand(DRAccessCachePat));
write(tfp, &tfp, 1);
xflock(tfp, XLOCK_UN);
close(tfp);
}
/*
* ReadAccessCache(): mmap the various access cache files into memory
* and set the pointers in the accessmap structure. This will be
* used to set the pointers for each thread.
*
* This has amazing performance benefits and saves memory because
* we use the static mmap area for all threads
*/
int
ReadAccessCache() {
int vsf;
int grf;
int auf;
int rdf;
int raf;
int tfp;
struct stat st;
int i;
time_t lastmod;
int fail;
if (DebugOpt > 1)
printf("Checking access cache\n");
if (stat(PatDbExpand(DRAccessLockPat), &st) != 0 ||
st.st_mtime <= Cache_LastUpdate) {
if (DebugOpt)
printf("No lock or not changed\n");
return(0);
}
lastmod = st.st_mtime;
/* Obtain a lock so that we know it won't disappear from under us */
if ((tfp = open(PatDbExpand(DRAccessLockPat), O_RDONLY)) <= 0) {
logit(LOG_ERR, "Cannot open access lock %s",
PatDbExpand(DRAccessLockPat));
return(0);
}
if (hflock(tfp, 0, XLOCK_SH) < 0) {
if (DebugOpt)
printf("No lock or not changed\n");
return(0);
}
if (DebugOpt)
printf("Loading access cache\n");
fail = 0;
/* We must be able to load all the files at the same time */
if ((vsf = open(PatDbExpand(DRVserverCachePat), O_RDONLY)) <= 0) {
logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRVserverCachePat));
fail = 1;
}
if ((grf = open(PatDbExpand(DRGroupCachePat), O_RDONLY)) <= 0) {
logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRGroupCachePat));
close(vsf);
fail = 1;
}
if ((auf = open(PatDbExpand(DRAuthCachePat), O_RDONLY)) <= 0) {
logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRAuthCachePat));
close(vsf);
close(grf);
fail = 1;
}
if ((raf = open(PatDbExpand(DRAccessCachePat), O_RDONLY)) <= 0) {
logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRAccessCachePat));
close(vsf);
close(grf);
close(auf);
fail = 1;
}
if ((rdf = open(PatDbExpand(DRReaderCachePat), O_RDONLY)) <= 0) {
logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRReaderCachePat));
close(vsf);
close(grf);
close(auf);
close(raf);
fail = 1;
}
/* Now that the files are open, we can clear the lock */
hflock(tfp, 0, XLOCK_UN);
close(tfp);
if (fail) {
if (accessmap.AccessList == NULL)
return(-2);
return(-1);
}
/*
* Preserve the old accessmap for later munmap
* We do this in case there is a race condition that removes the
* map too early. (????)
*/
memcpy(&oldaccessmap, &accessmap, sizeof(accessmap));
oldaccessmap.VServerList = accessmap.VServerList;
oldaccessmap.GroupsList = accessmap.GroupsList;
oldaccessmap.AuthList = accessmap.AuthList;
oldaccessmap.ReaderList = accessmap.ReaderList;
oldaccessmap.GroupMap = accessmap.GroupMap;
oldaccessmap.AccessList = accessmap.AccessList;
accessmap.VServerList = NULL;
accessmap.VServerCount = 0;
accessmap.GroupsList = NULL;
accessmap.GroupCount = 0;
accessmap.GroupMap = NULL;
accessmap.AuthList = NULL;
accessmap.AuthCount = 0;
accessmap.ReaderList = NULL;
accessmap.ReaderCount = 0;
accessmap.AccessList = NULL;
accessmap.AccessCount = 0;
fstat(vsf, &st);
accessmap.VServerList = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, vsf, 0);
accessmap.VServerCount = st.st_size / sizeof(Vserver);
close(vsf);
fstat(grf, &st);
if (st.st_size > 0) {
char *mapptr;
GroupDef *gp;
GroupDef *pgp = NULL;
GroupList *gl;
GroupList *pgl = NULL;
accessmap.GroupMap = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, grf, 0);
mapptr = accessmap.GroupMap;
while (*mapptr) {
gp = zalloc(&DnsMemPool, sizeof(GroupDef));
gp->gr_Groups = NULL;
gp->gr_Next = NULL;
if (accessmap.GroupsList == NULL)
accessmap.GroupsList = gp;
if (pgp)
pgp->gr_Next = gp;
gp->gr_Name = mapptr;
mapptr += strlen(gp->gr_Name) + 1;
gp->gr_Count = atoi(mapptr);
mapptr += strlen(mapptr) + 1;
pgl = NULL;
for (i=0; i < gp->gr_Count; i++) {
gl = zalloc(&DnsMemPool, sizeof(GroupList));
if (gp->gr_Groups == NULL)
gp->gr_Groups = gl;
if (pgl)
pgl->next = gl;
gl->group = zallocStr(&DnsMemPool, mapptr);
mapptr += strlen(gl->group) + 1;
gl->next = NULL;
pgl = gl;
}
pgp = gp;
accessmap.GroupCount++;
}
}
close(grf);
fstat(auf, &st);
accessmap.AuthList = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, auf, 0);
accessmap.AuthCount = st.st_size / sizeof(AuthDef);
close(auf);
fstat(rdf, &st);
accessmap.ReaderList = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, rdf, 0);
accessmap.ReaderCount = st.st_size / sizeof(ReaderDef);
close(rdf);
fstat(raf, &st);
accessmap.AccessList = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, raf, 0);
accessmap.AccessCount = st.st_size / sizeof(AccessDef);
close(raf);
Cache_LastUpdate = lastmod;
return(1);
}
/*
* Remove the old mmap entries now that all the threads have been updated
*/
void
ClearOldAccessMap(void) {
if (DebugOpt)
printf("Clearing old accessmap\n");
if (oldaccessmap.VServerList != NULL)
xunmap(oldaccessmap.VServerList, oldaccessmap.VServerCount * sizeof(Vserver));
if (oldaccessmap.GroupMap != NULL) {
xunmap(oldaccessmap.GroupMap, oldaccessmap.GroupMapSize);
zfree(&DnsMemPool, oldaccessmap.GroupsList, sizeof(GroupDef));
}
if (oldaccessmap.AuthList != NULL)
xunmap(oldaccessmap.AuthList, oldaccessmap.AuthCount * sizeof(AuthDef));
if (oldaccessmap.ReaderList != NULL)
xunmap(oldaccessmap.ReaderList, oldaccessmap.ReaderCount * sizeof(ReaderDef));
if (oldaccessmap.AccessList != NULL)
xunmap(oldaccessmap.AccessList, oldaccessmap.AccessCount * sizeof(AccessDef));
bzero(&oldaccessmap, sizeof(oldaccessmap));
}
/*
* Update all the mmap'ed authentication pointers because something chanaged
*/
void
SetAuthDetails(DnsRes *dres, char *which)
{
int i;
ReaderDef *rdp;
Vserver *vsp;
GroupDef *gdp;
AuthDef *adp;
if (DebugOpt)
printf("Setting Auth Details for %s\n", which);
for (rdp = accessmap.ReaderList, i = 0; i < accessmap.ReaderCount;
i++, rdp++)
if (strcmp(which, rdp->rd_Name) == 0)
break;
/* The first reader access line is the default */
if (i >= accessmap.ReaderCount)
rdp = accessmap.ReaderList;
dres->dr_ReaderDef = rdp;
for (vsp = accessmap.VServerList, i = 0; i < accessmap.VServerCount;
i++, vsp++)
/*
* If we are on a virtual interface, only check for the specified
* vserver.
*/
if (*dres->dr_VServer) {
if (strcmp(dres->dr_VServer, vsp->vs_Name) == 0)
break;
} else if (strcmp(rdp->rd_Vserver, vsp->vs_Name) == 0)
break;
/* The first VServer is always the default one */
if (i >= accessmap.VServerCount)
vsp = accessmap.VServerList;
dres->dr_VServerDef = vsp;
for (gdp = accessmap.GroupsList, i = 0; i < accessmap.GroupCount;
i++, gdp = gdp->gr_Next) {
if (strcmp(rdp->rd_Groups, gdp->gr_Name) == 0)
break;
}
/* The first group list is always everything */
if (i >= accessmap.GroupCount)
gdp = accessmap.GroupsList;
dres->dr_GroupDef = gdp;
for (gdp = accessmap.GroupsList, i = 0; i < accessmap.GroupCount;
i++, gdp = gdp->gr_Next) {
if (strcmp(rdp->rd_ListGroups, gdp->gr_Name) == 0)
break;
}
/* The first group list is always everything */
if (i >= accessmap.GroupCount)
gdp = accessmap.GroupsList;
dres->dr_ListGroupDef = gdp;
for (gdp = accessmap.GroupsList, i = 0; i < accessmap.GroupCount;
i++, gdp = gdp->gr_Next) {
if (strcmp(rdp->rd_PostGroups, gdp->gr_Name) == 0)
break;
}
/* The first group list is always everything */
if (i >= accessmap.GroupCount)
gdp = accessmap.GroupsList;
dres->dr_PostGroupDef = gdp;
for (adp = accessmap.AuthList, i = 0; i < accessmap.AuthCount; i++, adp++)
if (strcmp(rdp->rd_Auth, adp->au_Name) == 0)
break;
/* The first auth list is no access */
if (i >= accessmap.AuthCount)
adp = accessmap.AuthList;
dres->dr_AuthDef = adp;
if (dres->dr_ReaderDef->rd_Read)
dres->dr_Flags |= DF_READ;
else
dres->dr_Flags &= ~DF_READ;
if (dres->dr_ReaderDef->rd_Post)
dres->dr_Flags |= DF_POST;
else
dres->dr_Flags &= ~DF_POST;
if (dres->dr_ReaderDef->rd_Feed)
dres->dr_Flags |= DF_FEED;
else
dres->dr_Flags &= ~DF_FEED;
if (dres->dr_ReaderDef->rd_Status)
dres->dr_Flags |= DF_STATUS;
else
dres->dr_Flags &= ~DF_STATUS;
if (dres->dr_ReaderDef->rd_Quiet)
dres->dr_Flags |= DF_QUIET;
else
dres->dr_Flags &= ~DF_QUIET;
if (dres->dr_ReaderDef->rd_GroupLog)
dres->dr_Flags |= DF_GROUPLOG;
else
dres->dr_Flags &= ~DF_GROUPLOG;
if (dres->dr_ReaderDef->rd_ControlPost)
dres->dr_Flags |= DF_CONTROLPOST;
else
dres->dr_Flags &= ~DF_CONTROLPOST;
}
/*
* This gets called for each thread to update the pointers if the
* mmapped info had been updated
*/
void
UpdateAuthDetails(ForkDesc *desc)
{
Connection *conn = desc->d_Data;
if (DebugOpt)
printf("Updating auth details\n");
if (conn && !conn->co_Auth.dr_StaticAuth)
SetAuthDetails(&conn->co_Auth, conn->co_Auth.dr_ReaderName);
}
void
getRateLimitCmds(char *opt, ReaderDef *rd)
{
int i;
int rl;
char *p;
rl = atoi(opt);
while (*opt && !isspace((int)*opt))
opt++;
while (*opt && isspace((int)*opt))
opt++;
if (!*opt)
for (i = 0; i < DRBC_XXXX; i++)
rd->rd_RateLimit[i] = rl;
else for (p = strtok(opt, " ,"); p != NULL; p = strtok(NULL, " ,")) {
if (strcmp(p, "other") == 0)
rd->rd_RateLimit[DRBC_NONE] = rl;
else if (strcmp(p, "article") == 0)
rd->rd_RateLimit[DRBC_ARTICLE] = rl;
else if (strcmp(p, "head") == 0)
rd->rd_RateLimit[DRBC_HEAD] = rl;
else if (strcmp(p, "body") == 0)
rd->rd_RateLimit[DRBC_BODY] = rl;
else if (strcmp(p, "list") == 0)
rd->rd_RateLimit[DRBC_LIST] = rl;
else if (strcmp(p, "xover") == 0)
rd->rd_RateLimit[DRBC_XOVER] = rl;
else if (strcmp(p, "xhdr") == 0)
rd->rd_RateLimit[DRBC_XHDR] = rl;
}
}
/*
* PrintAuthDetails(): Used for debugging - print all auth info for a thread
*/
void
PrintAuthDetails(DnsRes *dres)
{
int i;
printf("dr_ReaderName: %s\n", dres->dr_ReaderName);
printf("dr_Flags: %x\n", dres->dr_Flags);
printf("rd_Name: %s\n", dres->dr_ReaderDef->rd_Name);
printf(" rd_Read: %d\n", dres->dr_ReaderDef->rd_Read);
printf(" rd_Post: %d\n", dres->dr_ReaderDef->rd_Post);
printf(" rd_Auth: %s\n", dres->dr_ReaderDef->rd_Auth);
printf(" rd_Groups: %s\n", dres->dr_ReaderDef->rd_Groups);
printf(" rd_ListGroups: %s\n", dres->dr_ReaderDef->rd_ListGroups);
printf(" rd_PostGroups: %s\n", dres->dr_ReaderDef->rd_PostGroups);
printf(" rd_Vserver: %s\n", dres->dr_ReaderDef->rd_Vserver);
printf(" rd_MaxConnTotal: %d\n", dres->dr_ReaderDef->rd_MaxConnTotal);
printf(" rd_MaxConnPerHost: %d\n", dres->dr_ReaderDef->rd_MaxConnPerHost);
printf(" rd_MaxConnPerUser: %d\n", dres->dr_ReaderDef->rd_MaxConnPerUser);
printf(" rd_MaxConnPerGroup: %d\n", dres->dr_ReaderDef->rd_MaxConnPerGroup);
printf(" rd_MaxConnPerVs: %d\n", dres->dr_ReaderDef->rd_MaxConnPerVs);
printf(" rd_RateLimitTax: %d\n", dres->dr_ReaderDef->rd_RateLimitTax);
printf(" rd_RateLimit: ");
for (i = 0; i < DRBC_XXXX; i++)
printf("%d ", dres->dr_ReaderDef->rd_RateLimit[i]);
printf("\n");
printf(" rd_ByteLimit: %d\n", dres->dr_ReaderDef->rd_ByteLimit);
printf(" rd_IdleTimeout: %d\n", dres->dr_ReaderDef->rd_IdleTimeout);
printf(" rd_SessionTimeout: %d\n", dres->dr_ReaderDef->rd_SessionTimeout);
printf(" rd_GroupLog: %d\n", dres->dr_ReaderDef->rd_GroupLog);
printf(" rd_UseVerifiedDns: %d\n", dres->dr_ReaderDef->rd_UseVerifiedDns);
printf(" rd_DenyMismatchedDns: %d\n", dres->dr_ReaderDef->rd_DenyMismatchedDns);
printf(" rd_DenyNoDns: %d\n", dres->dr_ReaderDef->rd_DenyNoDns);
printf(" rd_CheckPostGroups: %d\n", dres->dr_ReaderDef->rd_CheckPostGroups);
printf(" rd_LogCmd: %d\n", dres->dr_ReaderDef->rd_LogCmd);
printf("vs_Name: %s\n", dres->dr_VServerDef->vs_Name);
printf(" vs_HostName: %s\n", dres->dr_VServerDef->vs_HostName);
printf(" vs_ClusterName: %s\n", dres->dr_VServerDef->vs_ClusterName);
printf(" vs_PostPath: %s\n", dres->dr_VServerDef->vs_PostPath);
printf(" vs_NoXrefHostUpdate: %d\n", dres->dr_VServerDef->vs_NoXrefHostUpdate);
printf(" vs_NoReadPath: %d\n", dres->dr_VServerDef->vs_NoReadPath);
printf(" vs_NewsAdm: %s\n", dres->dr_VServerDef->vs_NewsAdm);
printf(" vs_Org: %s\n", dres->dr_VServerDef->vs_Org);
printf(" vs_AbuseTo: %s\n", dres->dr_VServerDef->vs_AbuseTo);
printf(" vs_CryptPw: %s\n", dres->dr_VServerDef->vs_CryptPw);
printf(" vs_Interface: %s\n", "XXX"); /* dres->dr_VServerDef->vs_Interface); */
printf(" vs_AccessFile: %s\n", dres->dr_VServerDef->vs_AccessFile);
printf("au_Name: %s\n", dres->dr_AuthDef->au_Name);
printf(" au_File: %s\n", dres->dr_AuthDef->au_File);
printf(" au_Cdb: %s\n", dres->dr_AuthDef->au_Cdb);
printf(" au_Db: %s\n", dres->dr_AuthDef->au_Db);
printf(" au_External: %s\n", dres->dr_AuthDef->au_External);
printf(" au_Radius: %s\n", dres->dr_AuthDef->au_Radius);
printf(" au_NetRemote: %s\n", dres->dr_AuthDef->au_NetRemote);
printf(" au_LDAP: %s\n", dres->dr_AuthDef->au_LDAP);
printf(" au_Perl: %s\n", dres->dr_AuthDef->au_Perl);
printf(" au_PAM: %s\n", dres->dr_AuthDef->au_PAM);
printf(" au_User: %s\n", dres->dr_AuthDef->au_User);
printf(" au_Pass: %s\n", dres->dr_AuthDef->au_Pass);
printf(" au_AddRealm: %s\n", dres->dr_AuthDef->au_AddRealm);
printf(" au_Realm: %s\n", dres->dr_AuthDef->au_Realm);
printf(" au_Ident: %d\n", dres->dr_AuthDef->au_Ident);
printf("gr_Name: %s (%d)\n", dres->dr_GroupDef->gr_Name, dres->dr_GroupDef->gr_Count);
{
GroupList *gp;
int i;
for (gp = dres->dr_GroupDef->gr_Groups, i = 0;
i < dres->dr_GroupDef->gr_Count; i++, gp = gp->next)
printf(" group: %s\n", gp->group);
}
}
syntax highlighted by Code2HTML, v. 0.9.1