370 lines
13 KiB
C
370 lines
13 KiB
C
/*
|
|
* @(#) hostacc.c - Implementation of host access for the
|
|
* experimental FTP daemon developed at
|
|
* Washington University.
|
|
* $Id: hostacc.c,v 1.1 1999/06/30 17:19:34 he Exp $
|
|
*
|
|
* 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; /* 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;
|
|
char *ha_login;
|
|
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");
|
|
endhacc();
|
|
return(0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* user names "ftp" and "anonymous" are equivalent */
|
|
if (!strcasecmp(pcRuser, "anonymous"))
|
|
pcRuser = "ftp";
|
|
|
|
while (((ptHtmp = gethacc()) != (hacc_t *)NULL) && !iLineMatch)
|
|
{
|
|
if (strcasecmp(ptHtmp->ha_login, "anonymous"))
|
|
ha_login = ptHtmp->ha_login;
|
|
else
|
|
ha_login = "ftp";
|
|
|
|
if ((strcasecmp(pcRuser, ha_login)) && strcmp(ha_login, "*"))
|
|
/* 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;
|
|
int iHaMalloc=0; /* how many elem malloced */
|
|
|
|
iHaInd = 0;
|
|
iFirstTim = 1;
|
|
/* Open config file */
|
|
if ((ptFp = fopen(_PATH_FTPHOSTS, "r")) == NULL)
|
|
{
|
|
if (errno == ENOENT)
|
|
return(1);
|
|
else {
|
|
fatal("Can't open host access file");
|
|
iHaSize = iHaInd;
|
|
return (-1);
|
|
}
|
|
}
|
|
ha_arr=(hacc_t*)malloc((iHaMalloc=10)*sizeof(hacc_t));
|
|
|
|
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 */
|
|
|
|
/*
|
|
* Check if we need to expand the array with
|
|
* host access information
|
|
*/
|
|
if (iHaInd >= iHaMalloc)
|
|
{
|
|
ha_arr=(hacc_t*)realloc(ha_arr,(iHaMalloc+=10)*sizeof(hacc_t));
|
|
if (!ha_arr)
|
|
{
|
|
fatal("Failed to realloc host access array");
|
|
iHaSize = iHaInd;
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
/* 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");
|
|
iHaSize = iHaInd;
|
|
return(-1);
|
|
}
|
|
|
|
if((pcColon = strchr(pcBegin, ':')) != NULL)
|
|
ha_arr[iHaInd].ha_login =
|
|
strnsav(pcBegin, (pcColon-pcBegin));
|
|
else
|
|
{
|
|
fatal("Format error in host access file");
|
|
iHaSize = iHaInd;
|
|
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");
|
|
iHaSize = iHaInd;
|
|
return(-1);
|
|
}
|
|
}
|
|
ha_arr[iHaInd].ha_hosts[iHaHind++] =
|
|
strnsav(pcBegin, (pcEnd-pcBegin));
|
|
ha_arr[iHaInd].ha_hosts[iHaHind] = NULL;
|
|
iHaInd++;
|
|
}
|
|
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;
|
|
static hacc_t ptTmp;
|
|
|
|
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;
|
|
|
|
if (ha_arr == (hacc_t*)NULL)
|
|
return(0);
|
|
|
|
for (ptHtmp = ha_arr;
|
|
ptHtmp < ha_arr + iHaSize && ptHtmp->ha_type;
|
|
ptHtmp++)
|
|
{
|
|
ptHtmp->ha_type = 0;
|
|
if (ptHtmp->ha_login) {
|
|
free(ptHtmp->ha_login);
|
|
ptHtmp->ha_login = NULL;
|
|
}
|
|
for(iInd=0;
|
|
iInd < MAXHST && ptHtmp->ha_hosts[iInd];
|
|
iInd++) {
|
|
free(ptHtmp->ha_hosts[iInd]);
|
|
ptHtmp->ha_hosts[iInd] = NULL;
|
|
}
|
|
}
|
|
free(ha_arr);
|
|
ha_arr = NULL;
|
|
|
|
if (ptFp && 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 */
|