home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 3
/
Meeting_Pearls_III.iso
/
Pearls
/
tcp
/
Networking
/
TCP
/
Server
/
wu-ftpd
/
src
/
hostacc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-02
|
12KB
|
333 lines
/*
* @(#) hostacc.c - Implementation of host access for the
* experimental FTP daemon developed at
* Washington University.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* AUTHOR
* Bart Muijzer <bartm@cv.ruu.nl>
*
* HISTORY
* 930316 BM Created
* 930317 BM Converted to local naming convention;
* added rhost_ok(), cleanup code in enghacc()
* 930318 BM Ported to BSD; fixed memory leaks
* 930322 BM Changed algorithm: not in configfile = allow
* in configfile and match = allow|deny
* in configfile and no match = deny
*/
#include "config.h"
#ifdef HOST_ACCESS
#include "hostacc.h"
static char linbuf[MAXLEN]; /* Buffer to hold one line of config-file */
static char unibuf[MAXLEN]; /* Buffer to hold unified line */
static hacc_t ha_arr[MAXLIN]; /* Array with host access information */
static FILE *ptFp; /* FILE * into host access config file */
static int iHaInd = 0; /* Index in ha_arr */
static int iHaSize; /* Will hold actual #elems in ha_arr */
static int iFirstTim = 1; /* Used by gethacc() to see if index in */
/* ha_arr needs to be reset */
/* ------------------------------------------------------------------------ *\
* FUNCTION : rhost_ok *
* PURPOSE : Check if a host is allowed to make a connection *
* ARGUMENTS : Remote user name, remote host name, remote host address *
* RETURNS : 1 if host is granted access, 0 if not *
\* ------------------------------------------------------------------------ */
int rhost_ok(pcRuser, pcRhost, pcRaddr)
char *pcRuser,
*pcRhost,
*pcRaddr;
{
hacc_t *ptHtmp;
char *pcHost;
int iInd, iLineMatch = 0, iUserSeen = 0;
switch(sethacc()){
case 1:
/* no hostaccess file; disable mechanism */
return(1);
break;
case -1:
syslog(LOG_INFO, "rhost_ok: sethacc failed");
return(0);
break;
default:
break;
}
while (((ptHtmp = gethacc()) != (hacc_t *)NULL) && !iLineMatch)
{
if ( (strcasecmp(pcRuser, ptHtmp->ha_login)) &&
strcmp(ptHtmp->ha_login, "*") != NULL)
/* wrong user, check rest of file */
continue;
/*
* We have seen a line regarding the current user.
* Remember this.
*/
iUserSeen = 1;
for(iInd=0, pcHost=ptHtmp->ha_hosts[0];
((pcHost != NULL) && !iLineMatch);
pcHost=ptHtmp->ha_hosts[++iInd])
{
if (isdigit(*pcHost))
{
iLineMatch = fnmatch(pcHost, pcRaddr, NULL);
}
else
{
iLineMatch = fnmatch(pcHost, pcRhost, NULL);
}
if (iLineMatch)
{
iLineMatch = (ptHtmp->ha_type == ALLOW) ? 1 : 0;
goto match;
}
}
}
match:
/*
* At this point, iUserSeen == 1 if we've seen lines regarding
* the current user, and 0 otherwise. If we reached the end of
* the config file without a match we allow. Else, we allow or
* deny according to the rule found.
*/
if (endhacc())
{
syslog(LOG_INFO, "rhost_ok: endhacc failed");
return(0);
}
if (iUserSeen)
return(ptHtmp == NULL) ? 0 : iLineMatch;
else
/* Nothing at all about user in configfile, allow */
return(1);
}
/* ------------------------------------------------------------------------ *\
* FUNCTION : sethacc *
* PURPOSE : Initialize data structures for host access *
* ARGUMENTS : None *
* RETURNS : -1 on failure, 1 if host access file doesn't exist, *
* 0 otherwise *
\* ------------------------------------------------------------------------ */
static int sethacc()
{
int iHaHind = 0; /* Index in list of hosts */
char *pcBegin, *pcEnd, *pcColon;
char *pcTmp1, *pcTmp2;
/* Open config file */
if ((ptFp = fopen(_PATH_FTPHOSTS, "r")) == NULL)
{
if (errno == ENOENT)
return(1);
else {
fatal("Can't open host access file");
return (-1);
}
}
while (fgets(linbuf, MAXLEN, ptFp) != NULL)
{
iHaHind = 0;
/* Find first non-whitespace character */
for (pcBegin=linbuf;
((*pcBegin == '\t') || (*pcBegin == ' '));
pcBegin++)
;
/* Get rid of comments */
if ((pcEnd = strchr(linbuf, '#')) != NULL)
*pcEnd = '\0';
/* Skip empty lines */
if ((pcBegin == pcEnd) || (*pcBegin == '\n'))
continue;
/* Substitute all whitespace by a single ":" so we can
* easily break on words later on. The easiest way is
* to copy the result into a temporary buffer (called
* the "unified buffer" because it will store a line in
* the same format, regardless of the format the original
* line was in).
* The result will look like: "allow:name:host:host:host"
*/
for (pcTmp1=pcBegin, pcTmp2=unibuf; *pcTmp1; pcTmp1++)
{
if (*pcTmp1 != '\t' && *pcTmp1 != ' ' && *pcTmp1 != '\n')
*pcTmp2++ = *pcTmp1;
else
/* whitespace */
if (*(pcTmp2-1) == ':')
continue;
else
*pcTmp2++ = ':';
}
/* Throw away trailing whitespace, now indicated by
* the last character of the unified buffer being a
* colon. Remember where the news string ends.
*/
pcEnd = (*(pcTmp2 - 1) == ':') ? (pcTmp2 - 1) : pcTmp2;
*pcEnd = '\0'; /* Terminate new string */
/* Store what's left of the line into the
* hacc_t structure. First the access type,
* then the loginname, and finally a list of
* hosts to which all this applies.
*/
pcBegin = unibuf;
if (!strncmp(pcBegin, "deny", 4))
{
ha_arr[iHaInd].ha_type = DENY;
pcBegin += 5;
} else
if (!strncmp(pcBegin, "allow", 5))
{
ha_arr[iHaInd].ha_type = ALLOW;
pcBegin += 6;
}
else {
fatal("Format error in host access file");
return(-1);
}
if((pcColon = strchr(pcBegin, ':')) != NULL)
ha_arr[iHaInd].ha_login =
strnsav(pcBegin, (pcColon-pcBegin));
else
{
fatal("Format error in host access file");
return(-1);
}
pcBegin = pcColon+1;
while ((pcColon = strchr(pcBegin, ':')) != NULL)
{
ha_arr[iHaInd].ha_hosts[iHaHind++] =
strnsav(pcBegin, (pcColon-pcBegin));
pcBegin = pcColon+1;
if (iHaHind >= MAXHST)
{
fatal("Line too long");
return(-1);
}
}
ha_arr[iHaInd].ha_hosts[iHaHind++] =
strnsav(pcBegin, (pcEnd-pcBegin));
ha_arr[iHaInd].ha_hosts[iHaHind] = NULL;
/*
* Check if we need to expand the array with
* host access information
*/
if (++iHaInd > MAXLIN)
{
fatal("Config file too big!!");
return(-1);
}
}
iHaSize = iHaInd; /* Record current size of ha_arr */
return ((feof(ptFp)) ? 0 : -1);
}
/* ------------------------------------------------------------------------ *\
* FUNCTION : gethacc *
* PURPOSE : return pointer to the next host_access structure *
* ARGUMENTS : None *
* RETURNS : NULL on failure, pointervalue otherwise *
\* ------------------------------------------------------------------------ */
static hacc_t *gethacc()
{
static int iHaInd;
hacc_t *ptTmp;
if ((ptTmp = (hacc_t *)malloc(sizeof(hacc_t))) == NULL)
return(NULL);
if (iFirstTim)
{
iFirstTim = 0;
iHaInd = 0;
}
if (iHaInd >= iHaSize)
return ((hacc_t *)NULL);
else {
#ifdef USG
memmove(ptTmp, &(ha_arr[iHaInd]), sizeof(hacc_t));
#else
bcopy(&(ha_arr[iHaInd]), ptTmp, sizeof(hacc_t));
#endif
iHaInd++;
return(ptTmp);
}
}
/* ------------------------------------------------------------------------ *\
* FUNCTION : endhacc *
* PURPOSE : Free allocated data structures for host access *
* ARGUMENTS : None *
* RETURNS : -1 on failure, 0 otherwise *
\* ------------------------------------------------------------------------ */
static int endhacc()
{
int iInd;
hacc_t *ptHtmp;
for(iInd=0, ptHtmp = ha_arr;
(ptHtmp->ha_hosts[iInd]);
iInd++)
{
free(ptHtmp->ha_login);
free(ptHtmp->ha_hosts[iInd]);
}
if (fclose(ptFp))
return (-1);
return (0);
}
/* ------------------------------------------------------------------------ */
static void fatal(pcMsg)
char *pcMsg;
{
syslog(LOG_INFO, "host_access: %s", pcMsg);
}
static char *strnsav(pcStr,iLen)
char *pcStr;
int iLen;
{
char *pcBuf;
if ((pcBuf = (char *)malloc(iLen+1)) == NULL)
return(NULL);
strncpy(pcBuf,pcStr,iLen);
pcBuf[iLen] = '\0';
return(pcBuf);
}
#endif /* HOST_ACCESS */