archie/prospero/lib/psrv/chk_localpth.c
2024-05-27 16:13:40 +02:00

307 lines
11 KiB
C

/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
#include <usc-license.h>
#include <sys/types.h> /* Needed by SCO; doesn't hurt others. */
#include <sys/param.h>
#include <netdb.h>
#include <string.h>
#include <netinet/in.h>
#include <pmachine.h>
#include <pserver.h>
#ifdef SHARED_PREFIXES /* if no SHARED_PREFIXES definition, this is
useless. */
#include <pfs.h>
#include <plog.h> /* log errors in initializing. */
/* isascii() is not provided in POSIX, so we just do it here. */
#ifndef isascii
#define isascii(c) ((unsigned)(c)<=0177)
#endif
extern char *hostname;
/*
* check_localpath - Check whether file is available via the LOCAL access
* method.
*
* CHECK_LOCALPATH takes the name of a file and a network
* address. If possible, it returns a string which is the name for the
* file in the client's filesystem.
*
* ARGS: path - Name of file to be retrieved
* client - IP address of the client
*
* RETURNS: A character pointer to a static buffer containing the new name
* of the file in the client's namespace, or NULL if the file is not
* available to the client by the LOCAL access method.
*
* NOTES: The returned buffer will be reused on the next call.
*/
static struct shared_prefixes {
char **locals; /* array of char *; null terminated */
char *remote; /* string, or NULL indicating not exported. */
/* A network byte order list of ip addresses of clients for which this
entry is meaningful. */
long *includes; /* 0L terminated; octet w/255 means wildcard */
/* A network byte order list of ip addresses of clients for which this
entry is NOT meaningful. Overrides includes. Default (if no match in
either includes or exceptions) is not to include. */
long *exceptions; /* 0L terminated; octet w/255 means wildcard */
} *shared_prefixes = NULL;
extern void p_init_shared_prefixes(void);
char *
check_localpath(char *path, long client)
{
struct shared_prefixes *spp;
AUTOSTAT_CHARPP(rempathp); /* remapped path that we return */
char **locp; /* pointer to locals */
long *ipaddrp; /* pointer to IP addresses */
#ifndef PFS_THREADS
if (!shared_prefixes) p_init_shared_prefixes();
#else
assert(shared_prefixes); /* must have been called from dirsrv */
#endif
/* Try to match local path */
for (spp = shared_prefixes; spp->locals; ++spp)
for (locp = spp->locals; *locp; ++locp)
if (strnequal(*locp, path, p__bstsize(*locp) - 1))
goto prefixmatch; /* prefix match */
prefixmatch:
if (!spp->locals) return NULL; /* no match */
/* Now make sure one of the includes addresses matches. */
for (ipaddrp = spp->includes; *ipaddrp; ++ipaddrp) {
if ((((*ipaddrp & 0xff000000) == 0xff000000)
|| ((*ipaddrp & 0xff000000) == (client & 0xff000000)))
&& (((*ipaddrp & 0x00ff0000) == 0x00ff0000)
|| ((*ipaddrp & 0x00ff0000) == (client & 0x00ff0000)))
&& (((*ipaddrp & 0x0000ff00) == 0x0000ff00)
|| ((*ipaddrp & 0x0000ff00) == (client & 0x0000ff00)))
&& (((*ipaddrp & 0x000000ff) == 0x000000ff)
|| ((*ipaddrp & 0x000000ff) == (client & 0x000000ff))))
break;
}
if (*ipaddrp == 0L) /* no matches */
return NULL;
/* Now make sure none of the exceptions addresses matches. */
for (ipaddrp = spp->exceptions; *ipaddrp; ++ipaddrp) {
if ((((*ipaddrp & 0xff000000) == 0xff000000)
|| ((*ipaddrp & 0xff000000) == (client & 0xff000000)))
&& (((*ipaddrp & 0x00ff0000) == 0x00ff0000)
|| ((*ipaddrp & 0x00ff0000) == (client & 0x00ff0000)))
&& (((*ipaddrp & 0x0000ff00) == 0x0000ff00)
|| ((*ipaddrp & 0x0000ff00) == (client & 0x0000ff00)))
&& (((*ipaddrp & 0x000000ff) == 0x000000ff)
|| ((*ipaddrp & 0x000000ff) == (client & 0x000000ff))))
return NULL; /* found a match */
}
/* We have a match. Map it! */
*rempathp = qsprintf_stcopyr(*rempathp, "%s%s", spp->remote,
path + strlen(*locp));
return *rempathp;
}
static long wcinet_aton(char *ascaddr);
/* Now called from dirsrv() upon initialization, so that we don't have to
initialize it automatically in multithreaded case. */
void
p_init_shared_prefixes(void)
{
char **cp;
int numnulls = 0;
int numentries; /* # of entries in the shared_prefixes array */
int centry; /* index of entry being initialized */
static char *init_sd[] = SHARED_PREFIXES;
int i; /* I is just a reused index variable; value is also used right
after a loop closes, in an assertion check. */
/* Count the # of entries */
for (i = 0; i < sizeof init_sd / sizeof init_sd[0]; ++i)
if (init_sd[i] == NULL) ++numnulls;
/* More efficient version of: if ((numnulls % 4) != 0) */
if (numnulls & 0x3) {
plog(L_DATA_FRM_ERR, NOREQ,
"Incorrectly formatted SHARED_PREFIXES entry in \
the pserver.h configuration file; got %d excess NULLs (out of %d total). The number \
of NULLs will always be an even multiple of 4 in a correctly formatted \
SHARED_PREFIXES configuration file.", numnulls & 0x3, numnulls);
plog(L_DATA_FRM_ERR, NOREQ,
"Please correct this. In the mean time, this server will \
muddle on as best it can.");
}
numentries = (numnulls >> 2);
/* Allocate one extra as a sentinel marking end of the array. */
shared_prefixes =
(struct shared_prefixes *)
stalloc(sizeof *shared_prefixes * (numentries + 1));
shared_prefixes[numentries].locals = NULL;
/* finish initializing */
for (centry = 0, cp = init_sd; centry < numentries; ++centry) {
int subarraynelem;
/* continue to use I above as an index. */
/* count # of entries for locals */
for (subarraynelem = 0; cp[subarraynelem]; ++subarraynelem)
;
shared_prefixes[centry].locals =
(char **) stalloc((1 + subarraynelem) * sizeof (char *));
i = 0;
for(;*cp; ++cp)
shared_prefixes[centry].locals[i++] = stcopy(*cp);
shared_prefixes[centry].locals[i] = NULL;
assert(i == subarraynelem); /* sanity check */
++cp; /* onto remote entry */
if (*cp) {
shared_prefixes[centry].remote = stcopy(*cp);
if (*++cp) {
plog(L_DATA_FRM_ERR, NOREQ,
"Incorrectly formatted SHARED_PREFIXES entry in \
pserver.h configuration file: only one remote prefix should be specified per \
entry. This occurred while scanning the %dth entry.", centry);
plog(L_DATA_FRM_ERR, NOREQ,
"Please correct this. In the mean time, this \
server will muddle on as best it can.");
while (*++cp) /* skip irrelevant entries. */
;
}
}
else
shared_prefixes[centry].remote = NULL;
++cp; /* onto include internet addrs. */
/* count # of entries for includes */
for (subarraynelem = 0; cp[subarraynelem]; ++subarraynelem)
;
shared_prefixes[centry].includes =
(long *) stalloc((1 + subarraynelem) * sizeof (long));
for(i = 0; *cp; ++cp, ++i)
shared_prefixes[centry].includes[i] = wcinet_aton(*cp);
shared_prefixes[centry].includes[i] = 0L;
assert(i == subarraynelem); /* sanity check */
++cp; /* onto exceptions entry */
/* count # of entries for exceptions */
for (subarraynelem = 0; cp[subarraynelem]; ++subarraynelem)
;
shared_prefixes[centry].exceptions =
(long *) stalloc((1 + subarraynelem) * sizeof (long));
for(i = 0; *cp; ++cp, ++i)
shared_prefixes[centry].exceptions[i] = wcinet_aton(*cp);
shared_prefixes[centry].exceptions[i] = 0L;
assert(i == subarraynelem); /* sanity check */
++cp; /* onto next entry, if there is one. */
}
}
/* If there are any problems with the format, return 127.0.0.1, which will
never be useful, since the local AM code will already snag it. Yaay! */
#if BYTE_ORDER == BIG_ENDIAN
#define LOOPBACK_ADDR 0x7f000001
/* octets are numbered 'a' for leftmost in ascii form, 'b', 'c', and 'd' for
rightmost. */
#define octetat(octetnum, value) ((value & 0xff) << ((3 - octetnum) * 8))
#else
#define LOOPBACK_ADDR 0x0100007f
#define octetat(octetnum, value) ((value & 0xff) << (octetnum * 8))
#endif
/* This icky function takes an internet address with exactly 4 octets in it,
* separated by 3 dots. The octets may be exactly one of:
* a) decimal numbers between 0 and 255
* b) * -- indicates wildcard
* c) % -- indicates address of current host.
*/
static long
wcinet_aton(char *asc_addr)
{
char workaddr[30]; /* working copy of ascii address. */
long retval = 0L;
char *thisp, *nextp;
int octetval;
if (strlen(asc_addr) >= sizeof workaddr)
goto malformed;
strcpy(workaddr, asc_addr); /* leave asc_addr for error reporting */
thisp = nextp = workaddr;
nextp = strchr(nextp, '.');
if (!nextp) goto malformed;
*nextp = '\0';
++nextp;
if ((octetval = parse_octet(0, thisp)) < 0)
goto malformed;
retval |= octetat(0, octetval);
thisp = nextp;
nextp = strchr(nextp, '.');
if (!nextp) goto malformed;
*nextp = '\0';
++nextp;
if ((octetval = parse_octet(1, thisp)) < 0)
goto malformed;
retval |= octetat(1, octetval);
thisp = nextp;
nextp = strchr(nextp, '.');
if (!nextp) goto malformed;
*nextp = '\0';
++nextp;
if ((octetval = parse_octet(2, thisp)) < 0)
goto malformed;
retval |= octetat(2, octetval);
thisp = nextp;
if ((octetval = parse_octet(3, thisp)) < 0)
goto malformed;
retval |= octetat(3, octetval);
return retval;
malformed:
plog(L_DATA_FRM_ERR, NOREQ, "Malformed internet address in \
SHARED_PREFIXES initializer: %s\n", asc_addr);
return INADDR_LOOPBACK; /* in <netinet/in.h> */
}
/* 0 to 255, or neg. value for failure/malformed input. */
int
parse_octet(int octetnum, char *asc_octet)
{
static long myaddr = 0L; /* safe; updated atomically (in one instr.) */
int retval;
if (!myaddr) myaddr = myaddress(); /* myaddress() is now safe.
Atomic; can't overwrite*/
if (strequal(asc_octet, "*")) return 255;
if (strequal(asc_octet, "%")) {
#if BYTE_ORDER == BIG_ENDIAN
return (myaddr & (0xff000000 >> (octetnum * 8)))
>> ((3 - octetnum) * 8);
#else
return (myaddr & (0xff << (octetnum * 8))) >> (octetnum * 8);
#endif
}
retval = atoi(asc_octet);
for (;*asc_octet; ++asc_octet)
if (!isascii(*asc_octet) || !isdigit(*asc_octet))
return -1;
return retval;
}
#endif /* SHARED_PREFIXES */