Intial commit

This commit is contained in:
Mario Fetka
2024-05-27 16:13:40 +02:00
parent f8dc12b10a
commit d71d446104
2495 changed files with 539746 additions and 0 deletions

1
prospero/lib/psrv/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
Makefile

29
prospero/lib/psrv/FILES Normal file
View File

@@ -0,0 +1,29 @@
FILES
Makefile
ad2l_atr.c
archie2
archie3
at_delete.c
change_acl.c
check_acl.c
check_nfs.c
chk_krb_auth.c
chk_localpth.c
dsdir.c
dsrfinfo.c
dsrobject.c
dsrobject_v6.c
dswfinfo.c
dswobject.c
error_reply.c
gopher_gw
magic.c
named_acl.c
optparse.c
plog.c
ppasswd.c
psrv_mutexes.c
replyf.c
retrieve_fp.c
srv_qoprintf.c
wais_gw

243
prospero/lib/psrv/Makefile.in Executable file
View File

@@ -0,0 +1,243 @@
# Makefile for LIB/PSRV
SOURCEBASE = ../..
include $(SOURCEBASE)/Makefile.config
SUBDIRS =
CFILES = \
ad2l_atr.c \
at_delete.c \
change_acl.c \
check_acl.c \
check_nfs.c \
chk_krb_auth.c \
chk_localpth.c \
dsdir.c \
dsrfinfo.c \
dsrobject.c \
dswfinfo.c \
dswobject.c \
error_reply.c \
magic.c \
named_acl.c \
optparse.c \
plog.c \
ppasswd.c \
psrv_mutexes.c \
replyf.c \
retrieve_fp.c \
srv_qoprintf.c
OBJECTS = \
ad2l_atr.o \
at_delete.o \
change_acl.o \
check_acl.o \
check_nfs.o \
chk_krb_auth.o \
chk_localpth.o \
dsdir.o \
dsrfinfo.o \
dsrobject.o \
dswfinfo.o \
dswobject.o \
error_reply.o \
magic.o \
named_acl.o \
optparse.o \
plog.o \
ppasswd.o \
psrv_mutexes.o \
replyf.o \
retrieve_fp.o \
srv_qoprintf.o
all: ${SRV_LIB} all_subdirs
install:
# cp ${SRV_LIB} ${P_BINARIES}/${SRV_LIB}
# ${RANLIB} ${P_BINARIES}/${SRV_LIB}
${SRV_LIB}: ${OBJECTS}
rm -f ${SRV_LIB}
ar r${AR_FLAGS} ${SRV_LIB} ${OBJECTS}
${RANLIB} ${SRV_LIB}
# Dependencies
ad2l_atr.o : \
../../include/pfs.h \
../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h \
../../include/perrno.h
at_delete.o : ../../include/pfs.h \
../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h \
../../include/psrv.h ../../include/pparse.h \
../../include/perrno.h
change_acl.o : \
../../include/ardp.h \
../../include/pfs_threads.h ../../include/pfs_utils.h \
../../include/list_macros.h ../../include/../lib/ardp/flocks.h \
../../include/pfs.h ../../include/pmachine.h \
../../include/implicit_fixes.h \
../../include/psite.h ../../include/pprot.h ../../include/plog.h \
../../include/psrv.h \
../../include/pparse.h ../../include/perrno.h
check_acl.o : \
../../include/ardp.h \
../../include/pfs_threads.h ../../include/pfs_utils.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/pfs.h ../../include/pmachine.h \
../../include/implicit_fixes.h \
../../include/pserver.h \
../../include/pprot.h ../../include/plog.h \
../../include/psrv.h ../../include/pparse.h
check_nfs.o : \
../../include/pfs.h ../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h
chk_krb_auth.o : ../../include/psite.h \
../../include/pfs.h ../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h \
../../include/psrv.h ../../include/pparse.h \
../../include/pserver.h
chk_localpth.o : \
../../include/pmachine.h \
../../include/pserver.h \
../../include/pfs.h ../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/plog.h
dsdir.o : \
../../include/pmachine.h \
../../include/pserver.h \
../../include/ardp.h ../../include/pfs_threads.h ../../include/pfs_utils.h \
../../include/list_macros.h ../../include/../lib/ardp/flocks.h \
../../include/pfs.h \
../../include/implicit_fixes.h \
../../include/plog.h \
../../include/pprot.h ../../include/perrno.h ../../include/pparse.h \
../../include/psrv.h ../../include/posix_signal.h ../../include/mitra_macros.h
dsrfinfo.o : \
../../include/ardp.h \
../../include/pfs_threads.h ../../include/pfs_utils.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/pfs.h ../../include/pmachine.h \
../../include/implicit_fixes.h \
../../include/plog.h \
../../include/pprot.h ../../include/perrno.h ../../include/pparse.h ../../include/psrv.h
dsrobject.o : \
../../include/pmachine.h \
../../include/pserver.h ../../include/pfs.h ../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h ../../include/../lib/ardp/flocks.h \
../../include/implicit_fixes.h \
../../include/perrno.h ../../include/psrv.h ../../include/pparse.h \
../../include/plog.h
dswfinfo.o : ../../include/pfs.h \
../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h \
../../include/pparse.h \
../../include/psrv.h ../../include/perrno.h ../../include/plog.h
dswobject.o : \
../../include/pmachine.h \
../../include/pfs.h ../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h ../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/perrno.h ../../include/psrv.h ../../include/pparse.h \
../../include/plog.h
error_reply.o : ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/pfs_utils.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/pfs.h \
../../include/pmachine.h \
../../include/implicit_fixes.h \
../../include/psrv.h ../../include/pparse.h \
../../include/plog.h ../../include/pprot.h ../../include/perrno.h
magic.o : ../../include/pfs.h ../../include/pfs_utils.h \
../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h
named_acl.o : \
../../include/pfs.h ../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h ../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h \
../../include/perrno.h ../../include/psrv.h ../../include/pparse.h \
../../include/plog.h
optparse.o : ../../include/pfs.h \
../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h \
../../include/pparse.h \
../../include/psrv.h ../../include/perrno.h
plog.o : \
../../include/ardp.h \
../../include/pfs_threads.h ../../include/pfs_utils.h \
../../include/list_macros.h ../../include/../lib/ardp/flocks.h \
../../include/pfs.h ../../include/pmachine.h \
../../include/implicit_fixes.h \
../../include/pserver.h ../../include/plog.h
ppasswd.o : ../../include/pmachine.h \
../../include/pfs.h ../../include/pfs_utils.h ../../include/ardp.h ../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pserver.h ../../include/ppasswd.h \
../../include/perrno.h
psrv_mutexes.o : ../../include/pserver.h \
../../include/pfs.h ../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h \
../../include/psrv.h ../../include/pparse.h
replyf.o : \
../../include/ardp.h \
../../include/pfs_threads.h \
../../include/pfs_utils.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/pfs.h \
../../include/pmachine.h \
../../include/implicit_fixes.h \
../../include/plog.h \
../../include/pprot.h ../../include/psrv.h ../../include/pparse.h
retrieve_fp.o : \
../../include/pfs.h ../../include/pfs_utils.h ../../include/ardp.h \
../../include/pfs_threads.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/implicit_fixes.h \
../../include/pmachine.h \
../../include/psrv.h ../../include/pparse.h \
../../include/perrno.h
srv_qoprintf.o : \
../../include/ardp.h ../../include/pfs_threads.h \
../../include/pfs_utils.h \
../../include/list_macros.h \
../../include/../lib/ardp/flocks.h ../../include/pfs.h ../../include/pmachine.h \
../../include/implicit_fixes.h \
../../include/pparse.h \
../../include/psrv.h

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-copyr.h>.
*
* Written by bcn, 17 January 1993
*/
#include <usc-copyr.h>
#include <stdarg.h>
#include <pfs.h>
#include <perrno.h>
/*
* ad2l_seq1_atr - add single element sequence attribute to link
*
* The routines ad2l_seq1_atr is intended to provide a high level
* interface for adding a common form of attribute to a link,
* adding a sequence attribute. If compiled under ANSI C, it
* allows the addition of sequence attributes. If under non
* ANSI C, it allows the addition of a sequence attribute with
* a single element value.
*
* This functions is intended for use by information service providers
* converting information from their database to link information to be
* returned by a Prospero server.
*/
int
ad2l_seq_atr(VLINK l, /* Link to receive attribute */
char precedence, /* To what the attribute applies */
char nature, /* Nature of the attribute */
char *aname, /* The name of the attribute */
...) /* Elements of the value */
{
va_list ap;
char *seq_elem; /* Element of sequence */
PATTRIB at = atalloc();
if(!at) RETURNPFAILURE;
at->precedence = precedence;
at->nature = nature;
at->aname = stcopy(aname);
at->avtype = ATR_SEQUENCE;
va_start(ap, aname);
while(seq_elem = va_arg(ap, char *)) {
at->value.sequence = tkappend(seq_elem, at->value.sequence);
}
va_end(ap);
APPEND_ITEM(at, l->lattrib);
return(PSUCCESS);
}
/*
* ad2l_am_atr - add access method attribute to link
*
* The routine ad2l_am_atr is intended to provide a high level
* interface for adding the common form of the access method attribute to
* a link, adding an access method attribute with the first four generic
* arguments null (the value will be taken from the link itself).
*
* This function is intended for use by information service providers
* converting information from their database to link information to be
* returned by a Prospero server.
*/
void
ad2l_am_atr(VLINK l, /* Link to receive attribute */
char *am, /* The access method */
...) /* Specific elements of the value */
{
PATTRIB at = atalloc();
va_list ap;
char *arg; /* Arguments to access method */
va_start(ap, am);
arg = va_arg(ap, char *);
va_end(ap);
at->precedence = ATR_PREC_CACHED;
at->nature = ATR_NATURE_FIELD;
at->aname = stcopy("ACCESS-METHOD");
at->avtype = ATR_SEQUENCE;
at->value.sequence = tkappend(am, at->value.sequence);
if(arg) {
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend(arg, at->value.sequence);
}
while(arg = va_arg(ap, char *)) {
at->value.sequence = tkappend(arg,at->value.sequence);
}
APPEND_ITEM(at, l->lattrib);
}

1
prospero/lib/psrv/archie2/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
Makefile

View File

@@ -0,0 +1,10 @@
FILES
Makefile
README
arch_dsdb.c
arch_prioritize.c
atopdate.c
atoplink.c
prarch.h
prarch_host.c
prarch_match.c

View File

@@ -0,0 +1,95 @@
A_INC = -Iarchie_src
INCS += ${A_INC}
# libraries should be relative to this dir, not SRC
DBS_LIB = libpsarchie.a
CFLAGS += -O2 -DMMAP -DSTRFIND -DCLEANUP
CFILES = \
arch_dsdb.c \
arch_prioritize.c \
prarch_match.c \
prarch_host.c \
atopdate.c \
atoplink.c
OBJECTS = \
arch_dsdb.o \
arch_prioritize.o \
prarch_match.o \
prarch_host.o \
atopdate.o \
atoplink.o
ARC_LIB = \
oper.o \
database.o \
misc.o \
error.o \
net.o
ARC_LIBSRC = \
oper.c \
database.c \
misc.c \
error.c \
net.c
CODE = ${CFILES} Makefile
all: ${DBS_LIB}
install:
cp ${DBS_LIB} ${INSTDIR}/${SRV_LIB}
ranlib ${INSTDIR}/${DBS_LIB}
cleandb:
\rm -f db/* /usr/tmp/archie.lock
\cp /dev/null db/file-list
\cp /dev/null db/strings-list
${ARC_LIB}: Makefile
${CC} ${F_CC} ${F_CPP} $*.c
${ARC_LIBSRC}:
ln -s archie_src/$@
${DBS_LIB}: ${OBJECTS} ${ARC_LIB}
rm -f ${DBS_LIB}
ar rv ${DBS_LIB} ${OBJECTS} ${ARC_LIB}
ranlib ${DBS_LIB}
# These Dependencies cannot be automatedly generated by the SWA Prospero
# scripts, unless you're running on a machine with the ARCHIE sources on it.
# Therefore, we treat them specially.
# These dependencies should be updated the next time someone reading this is
# in a position to do so.
# Actually, to set the dependencies, create a dummy archie_src directory
# with archie_defs.h, database.h, structs.h, defines.h, error.h
# This will work unless any archie include files in turn include other
# include files, which we of course don't know.
atoplink.o: prarch.h
atoplink.o: archie_src/database.h
atoplink.o: archie_src/defines.h
atoplink.o: ../../../include/pfs.h
atoplink.o: ../../../include/psite.h
atoplink.o: archie_src/structs.h
prarch_host.o: prarch.h
prarch_host.o: archie_src/archie_defs.h
prarch_host.o: archie_src/database.h
prarch_host.o: archie_src/defines.h
prarch_host.o: ../../../include/perrno.h
prarch_host.o: ../../../include/pfs.h
prarch_host.o: archie_src/structs.h
# Dependencies
arch_prioritize.o : \
../../../include/ardp.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h \
../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/pfs.h ../../../include/pmachine.h \
../../../include/implicit_fixes.h \
../../../include/perrno.h

View File

@@ -0,0 +1,45 @@
This directory contains code needed to integrate the archie 2 release
with a Prospero server.
You should start from the most recent prospero release. You can
obtain information about the release from info-prospero@isi.edu. The
release should be available on prospero.isi.edu in the file
/pub/prospero/prospero.tar.Z.
Here are specific instructions on how to tie Prospero in to Archie:
Retrieve the release, and untar it. Installation instructions are
included, but they are not tailored to Archie. The changes to the
installations instruction for using it with Archie follow:
1) There is probably no need to set up separate user and group IDs
for Prospero, just use those for Archie.
2) In pserver.h, define PSRV_ARCHIE.
3) In server/Makefile uncomment the appropriate DB_LIBS line
for your configuration (archie2 or archie3)
4) In the directory lib/psrv/archie2 or lib/psrv/archie3, create
a symbolic link archie_src in the directory the archie sources. Note,
you must obtain archie sources from the archie group. For archie3,
these sources must have been obtained after 2/22/93. For archie2,
there has been a change to oper.c in the archie sources that should
have been obtained since 2/22/93. Note also that for archie2, the
archie sources must be set up to use the full path of the database
directory, or you will also have to create a db symbolic link from the
directory within which the Prospero server will run.
5) Run make in lib/psrv/archie2 or lib/psrv/archie3 depending
on your configuration. If using archie3, make a link from
libparchie.a to the file libparchie.a in the archie3
distribution. If you want, you can add lib/psrv/archie2
or lib/psrv/archie3 to the list of subdirectories in the
top level Prospero makefile (SUBDIR).
6) Make the other necessary customizations (as per the installation
instructions for prospero) by editing include/pserver.h,
include/pmachine.h, and the top level make file.
7) As per the installation instructions, do a make, make install,
then run pstart (you will probably want to add pstart to your
system startup files).

View File

@@ -0,0 +1,376 @@
/*
* Copyright (c) 1991 by the University of Washington
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the files
* <uw-copyright.h> and <usc-copyr.h>.
*/
#include <uw-copyright.h>
#include <usc-copyr.h>
#define ABSOLUTE_MAX_HITS 2500
#define ABSOLUTE_MAX_GIF 100
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <stdio.h>
#include <sgtty.h>
#include <string_with_strcasecmp.h>
/* Archie defines */
#include <defines.h>
#include <structs.h>
#include <error.h>
#include <database.h>
#include "prarch.h"
#include <pserver.h>
#include <pfs.h>
#include <ardp.h>
#include <psrv.h>
#include <plog.h>
#include <pprot.h>
#include <perrno.h>
#include <pmachine.h>
int archie_supported_version = 2;
extern char hostname[];
extern char hostwport[];
char archie_prefix[] = "ARCHIE";
static int num_slashes(char *s);
static int tkllength(TOKEN tkl);
/*
* dsdb - Make a database query as if it were a directory lookup
*
*/
arch_dsdb(RREQ req, /* Request pointer */
char *name, /* Name of the directory */
char **componentsp, /* Next component of name */
TOKEN *rcompp, /* Additional components */
VDIR dir, /* Directory to be filled in */
int options, /* Options to list command */
const char *rattrib, /* Requested attributes */
FILTER filters) /* Filters to be applied */
{
/* Note that componentspp and rcompp are pointers to */
/* pointers. This is necessary because */
/* this routine must be able to update these values */
/* if more than one component of the name is */
/* resolved. */
char *components = NULL;
int num_unresolvedcomps = 0;
VLINK cur_link = NULL;
char newdirname[MAXPATHLEN];
static int dbopen = 0;
char fullquery[MAXPATHLEN];
char *dbpart;
char dbquery[MAXPATHLEN];
char dbargs[MAXPATHLEN];
char dbarg1[MAXPATHLEN];
char dbarg2[MAXPATHLEN];
char dbarg3[MAXPATHLEN];
char dirlinkname[MAXPATHLEN];
char sep;
char *firstsep;
int tmp;
VLINK dirlink = NULL;
TOKEN tkl_tmp;
/* Make sure NAME, COMPONENTSP, and RCOMPP arguments are correct. */
/* Name components with slashes in them are malformed inputs to the
ARCHIE database. */
if(componentsp && (components = *componentsp)) {
if(index(components, '/'))
RETURNPFAILURE;
for (tkl_tmp = *rcompp; tkl_tmp; tkl_tmp = tkl_tmp->next)
if (index(tkl_tmp->token, '/'))
RETURNPFAILURE;
} else {
if (*rcompp) RETURNPFAILURE; /* ridiculous to specify additional comps
and no initial comps.*/
}
/* Directory already initialized, but note that this */
/* is not a real directory */
dir->version = -1;
dir->inc_native = 3; /* Not really a directory */
/* Note that if we are resolving multiple components */
/* (rcomp!=NULL) the directory will already be empty */
/* since had anything been in it dirsrv would have */
/* already cleared it and moved on to the next comp */
/* Do only once */
if(!dbopen++) {
set_default_dir(DEFAULT_DBDIR);
if((tmp = open_db_files(DB_RDONLY)) != A_OK) {
dbopen = 0;
plog(L_DB_ERROR,NOREQ,"Can't open archie database",0);
RETURNPFAILURE;
}
}
/* For now, if only verifying, indicate success */
/* We don't want to do a DB search. Eventually */
/* we might actually check that the directory */
/* is valid. */
if(options&DSDB_VERIFY) return(PSUCCESS);
/* Construct the full query from the pieces passed to us */
tmp = -1 + qsprintf(fullquery,sizeof fullquery, "%s%s%s",name,
((components && *components) ? "/" : ""),
((components && *components) ? components : ""));
for (tkl_tmp = *rcompp; tkl_tmp; tkl_tmp = tkl_tmp->next)
tmp += -1 + qsprintf(fullquery + tmp, sizeof fullquery - tmp,
"/%s", (*rcompp)->token);
if (tmp + 1 > sizeof fullquery) return DSRDIR_NOT_A_DIRECTORY;
/* The format for the queries is */
/* DATABASE_PREFIX/COMMAND(PARAMETERS)/ARGS */
/* Strip off the database prefix */
dbpart = fullquery + strlen(archie_prefix);
/* And we want to skip the next slash */
dbpart++;
/* Find the query (up to the next /), determine if the */
/* / exists and then read the args */
tmp = sscanf(dbpart,"%[^/]%c%s",dbquery,&sep,dbargs);
/* If no separator, for now return nothing */
/* Eventually, we might return a list of the query */
/* types supported */
if(tmp < 2) return(PSUCCESS);
/* Check query type */
if(strncmp(dbquery,"MATCH",5)==0) {
char stype = 'R'; /* search type */
int maxthit = 100; /* max entries to return */
int maxmatch = 100; /* max strings to match */
int maxhitpm = 100; /* max hits per match */
int offset = 0; /* entries to skip */
search_sel method; /* Search method */
int onlystr = 0; /* Just return strings */
/* In the MATCH querytype, the directory part of the query (the
argument named NAME) may have no more than 3 components.
There are 3 possible formats:
1) DATABASE_PREFIX (one component)
2) (1)/MATCH(...)
3) (2)/query-term (3 total components)
*/
if (num_slashes(name) > 2) return DSRDIR_NOT_A_DIRECTORY;
/* if no strings to match, return nothing */
if(tmp < 3) return(PSUCCESS);
/* Get arguments */
tmp = sscanf(dbquery,"MATCH(%d,%d,%d,%d,%c",&maxthit,
&maxmatch,&maxhitpm,&offset,&stype);
if(tmp < 3) {
sscanf(dbquery,"MATCH(%d,%d,%c",&maxthit,&offset,&stype);
maxmatch = maxthit;
maxhitpm = maxthit;
}
/* Note: in maxhits, 0 means use default, -1 means use max */
/* Don't let the user request more than ABSOLUTE_MAX_HITS */
if((maxthit > ABSOLUTE_MAX_HITS) || (maxthit < 1)) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Legal values for max hits are between 1 and %d ",
ABSOLUTE_MAX_HITS);
return(DIRSRV_NOT_AUTHORIZED);
}
if(maxthit == 0) maxthit = ABSOLUTE_MAX_HITS;
switch(stype) {
case '=':
onlystr = 0;
method = S_EXACT ;
break;
case 'C':
onlystr = 0;
method = S_SUB_CASE_STR ;
break;
case 'c':
onlystr = 0;
method = S_E_SUB_CASE_STR ;
break;
case 'K':
onlystr = 1;
method = S_SUB_CASE_STR ;
break;
case 'k':
onlystr = 1;
method = S_E_SUB_CASE_STR ;
break;
case 'R':
onlystr = 0;
method = S_FULL_REGEX ;
break;
case 'r':
onlystr = 0;
method = S_E_FULL_REGEX ;
break;
case 'X':
onlystr = 1;
method = S_FULL_REGEX ;
break;
case 'x':
onlystr = 1;
method = S_E_FULL_REGEX ;
break;
case 'z':
onlystr = 1;
method = S_E_SUB_NCASE_STR ;
break;
case 'Z':
onlystr = 1;
method = S_SUB_NCASE_STR ;
break;
case 's':
onlystr = 0;
method = S_E_SUB_NCASE_STR ;
break;
case 'S':
default:
onlystr = 0;
method = S_SUB_NCASE_STR ;
break;
}
*dbarg1 = *dbarg2 = *dbarg3 = '\0';
tmp = sscanf(dbargs,"%[^/]%c%[^/]%c%s",dbarg1,&sep,dbarg2,
&sep,dbarg3);
if(tmp < 2) {
/* This specifies a directory, but not a link within it */
/* create a pseudo directory and return a pointer */
/* In other words, listing a MATCH directory by itself yields
an empty directory. */
if(*dbarg1 && (strcmp(dbarg1,"*")!= 0)) {
dirlink = vlalloc();
dirlink->target = stcopyr("DIRECTORY",dirlink->target);
dirlink->name = stcopyr(dbarg1,dirlink->name);
dirlink->host = stcopyr(hostwport,dirlink->host);
sprintf(dirlinkname,"%s/%s/%s",archie_prefix,dbquery,dbarg1);
dirlink->hsoname = stcopyr(dirlinkname,dirlink->hsoname);
vl_insert(dirlink,dir,VLI_ALLOW_CONF);
}
}
else {
if(tmp > 4) {
/* There are remaining components */
num_unresolvedcomps = num_slashes(dbarg3);
}
#ifdef ABSOLUTE_MAX_GIF
/* If looking for GIF files (arrgh) don't allow them */
/* to set an unreasonable number of hits, this is */
/* promted by someone who set max hits to 10,000 */
if((maxthit+offset > ABSOLUTE_MAX_GIF)&&(((strlen(dbarg1) >= 4)&&
(strcasecmp(dbarg1+strlen(dbarg1)-4,".gif") == 0)) ||
(strcasecmp(dbarg1,"gif") == 0))) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Max hits for GIF searches is %d - See archie/doc/giflist.Z on \
archie.mcgill.ca for full gif list",ABSOLUTE_MAX_GIF);
return(DIRSRV_NOT_AUTHORIZED);
}
#endif ABSOLUTE_MAX_GIF
tmp = prarch_match(dbarg1,maxthit,maxmatch,maxhitpm,
offset,method,dir,FALSE,onlystr);
if(tmp) RETURNPFAILURE;
}
}
else if (strncmp(dbquery,"HOST",4)==0) {
/* First component of args is the site name */
/* remaining components are the directory name */
*dbarg1 = *dbarg2 = '\0';
tmp = sscanf(dbargs,"%[^/]%c%s",dbarg1,&sep,dbarg2);
/* If first component is null, return an empty directory */
if(tmp < 1) return(PSUCCESS);
/* if first component exists, but is last component, */
/* then it is the name of the subdirectory for the */
/* host, create a pseudo directory and return a */
/* pointer, If first component is a wildcard, and no */
/* additional components, then return matching list */
/* of sites. */
if(tmp == 1) {
tmp = prarch_host(dbarg1,NULL,dir,A2PL_ARDIR);
if(tmp == PRARCH_TOO_MANY) return(DIRSRV_TOO_MANY);
if(tmp) return(tmp);
}
/* More than one component, Look up the requested directory */
/* Note that the since the full query is passed to us, it */
/* includes the component name, thus the directory name is */
/* what you get when you strip off the last component of the */
/* name */
else {
char *lastsep = rindex(dbarg2,'/');
if(lastsep) *lastsep++ = '\0';
else *dbarg2 = '\0';
tmp = prarch_host(dbarg1,dbarg2,dir,A2PL_ARDIR);
if(tmp == PRARCH_DONT_HAVE_SITE)
return(DSRDIR_NOT_A_DIRECTORY);
if(tmp) RETURNPFAILURE;
}
}
else {
/* Query type not supported */
return(DSRDIR_NOT_A_DIRECTORY);
}
/* We are done, but we need to figure out if we resolved multiple
components and reset *componentsp and *rcompp appropriately. */
if (num_unresolvedcomps) {
int skip = tkllength(*rcompp) - num_unresolvedcomps;
if (skip < 0) return DSRDIR_NOT_A_DIRECTORY; /* shouldn't happen. */
while(skip-- > 0) {
assert(*rcompp);
*componentsp = (*rcompp)->token;
*rcompp = (*rcompp)->next;
}
} else {
while (*rcompp) {
*componentsp = (*rcompp)->token;
*rcompp = (*rcompp)->next;
}
}
return(PSUCCESS);
}
static int
tkllength(TOKEN tkl)
{
int retval = 0;
for (;tkl; tkl = tkl->next)
++retval;
return retval;
}
static
int
num_slashes(char *s)
{
int retval = 0;
for (; *s; ++s) {
if (*s == '/')
++retval;
}
return retval;
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 1991 by the University of Washington
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the files
* <uw-copyright.h> and <usc-copyr.h>.
*/
#include <uw-copyright.h>
#include <usc-copyr.h>
#include <ardp.h>
#include <pfs.h>
#include <perrno.h>
static assign_priority();
arch_prioritize_request(r1,r2)
RREQ r1,r2;
{
if(!r1->pf_priority)
r1->pf_priority = assign_priority(r1);
if(!r2->pf_priority)
r2->pf_priority = assign_priority(r2);
if(r1->pf_priority == r2->pf_priority) return(0);
else if (r1->pf_priority < r2->pf_priority) return(-1);
else return(1);
}
static assign_priority(r1)
RREQ r1;
{
char *arg_ptr;
int maxhit = 0;
int maxmatch = 0;
int maxhitpm = 0;
int offset;
char stype;
int tmp;
int retval;
/* Result is probably cached, use it or lose it */
if(r1->prcvd_thru > 0) return(2);
arg_ptr = sindex(r1->rcvd->start,"ARCHIE");
if(!arg_ptr) return(1);
arg_ptr = sindex(arg_ptr,"MATCH");
if(!arg_ptr) return(3);
tmp = sscanf(arg_ptr,"MATCH(%d,%d,%d,%d,%c",&maxhit,&maxmatch,
&maxhitpm,&offset,&stype);
if(tmp != 5) tmp = sscanf(arg_ptr,"MATCH(%d,%d,%c",&maxhit,
&offset,&stype);
if(tmp < 3) return(4);
if(stype == '=') retval = 0;
else if ((stype == 'r') || (stype == 'x')) retval = 700;
else if ((stype == 'R') || (stype == 'X')) retval = 800;
else retval = 100;
/* If old format request, then add penalty */
if(tmp != 5) retval += 100;
tmp = maxhit;
if(offset > 0) tmp += offset;
if(tmp > 10000) retval += 10000;
else if (tmp > 100) retval+= tmp;
else retval+= 100;
if(sindex(arg_ptr,"gif") || sindex(arg_ptr,"GIF")) retval += 20000;
return(retval);
}

View File

@@ -0,0 +1,31 @@
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <defines.h>
#include <structs.h>
#include <database.h>
extern datestruct unpack_date();
char *atopdate(entry_db)
db_date entry_db;
{
static char result[20] ;
datestruct entry;
entry = unpack_date(entry_db);
if(entry.hour == MAX_HOUR) {
entry.hour = 0;
entry.min = 0;
}
(void) sprintf(result,"%04d%02d%02d%02d%02d00Z",entry.year,entry.month+1,
entry.day,entry.hour,entry.min);
return(result);
}

View File

@@ -0,0 +1,147 @@
#include <stdio.h>
#include <sys/types.h>
#include <database.h>
#include <sys/mman.h>
#include <defines.h>
#include <structs.h>
#include <pfs.h>
#include <psite.h>
#include "prarch.h"
extern FILE *strings_table;
extern char *strings_begin;
extern char hostname[];
extern char hostwport[];
extern char archie_prefix[];
char *perms_itoa();
char *print_date();
char *atopdate();
char *strstr();
VLINK atoplink(site_out *sop, /* Site output pointer */
int flags) /* Flags: see above */
{
VLINK vl = vlalloc(); /* New link */
PATTRIB at; /* Attributes */
PATTRIB last_at; /* Last attribute */
char fullpath[MAX_STRING_LEN];
char namebuf[MAX_STRING_LEN];
char *endname = NULL;
char modestring[20];
char str_ent[256];
char atval[256];
char *nameptr; /* Last component of file name */
char *ptr;
site_rec *srp = &(sop->site_ent); /* Site record pointer */
long strings_pos;
/* For now, all directory pointers are to pseudo-directories */
flags |= A2PL_ARDIR;
if((flags & A2PL_ROOT) || (srp->dir_or_f == 'T')) {
/* It's a directory - we should check to see if the site is */
/* running prospero, and if so return a pointer to the actual */
/* directory. If it isn't then we return a real pointer to */
/* a pseudo-directory maintained by this archie server. */
vl->target = stcopyr("DIRECTORY",vl->target);
}
else {
/* It's a file - we should check to see if the site is */
/* running prospero, and if so return a pointer to the real */
/* file. If it isn't, then we generate an external link */
vl->target = stcopyr("EXTERNAL",vl->target);
ad2l_am_atr(vl,"AFTP","BINARY",NULL);
flags &= (~A2PL_ARDIR);
}
if(flags & A2PL_ARDIR) vl->host = stcopyr(hostwport,vl->host);
else vl->host = stcopyr(sop->site_name,vl->host);
/* Get the the last component of name */
if(flags & A2PL_ROOT) vl->name = stcopyr(sop->site_name,vl->name);
else {
strncpy(namebuf,strings_begin + srp->in_or_addr.strings_ind +
sizeof(strings_header),sizeof(namebuf));
namebuf[sizeof(namebuf)-1] = '\0';
if(endname = strstr(namebuf," -> ")) *endname = '\0';
nameptr = namebuf;
vl->name = stcopyr(nameptr,vl->name);
}
if(flags & A2PL_ARDIR) {
if(flags & A2PL_ROOT)
sprintf(fullpath,"%s/HOST/%s",archie_prefix, sop->site_name);
else
sprintf(fullpath,"%s/HOST/%s%s%s%s",archie_prefix,
sop->site_name, sop->site_path,
((*(sop->site_path + strlen(sop->site_path) - 1) == '/') ?
"" : "/"), (nameptr ? nameptr : ""));
}
else {
if(flags & A2PL_ROOT)
sprintf(fullpath,"/");
else
sprintf(fullpath,"%s%s%s",sop->site_path,
((*(sop->site_path + strlen(sop->site_path) - 1) == '/') ?
"" : "/"), (nameptr ? nameptr : ""));
}
vl->hsoname = stcopyr(fullpath,vl->hsoname);
if(!(flags & A2PL_ROOT)) {
/* Here we can add cached attribute values from the archie */
/* database such as size, protection, and last modified time */
sprintf(atval,"%d bytes",srp->size);
ad2l_seq_atr(vl,ATR_PREC_CACHED,ATR_NATURE_INTRINSIC,
"SIZE",atval,NULL);
/* Directory modes in unix string format */
if(ptr = perms_itoa(srp->perms)) {
if(endname) sprintf(modestring,"%c%s",'l',ptr);
else sprintf(modestring,"%c%s",((srp->dir_or_f=='T')?'d':'-'),ptr);
ad2l_seq_atr(vl,ATR_PREC_CACHED,ATR_NATURE_INTRINSIC,
"UNIX-MODES", modestring, NULL);
}
/* Modified date - in prospero format */
if(ptr = atopdate(srp->mod_time)) {
ad2l_seq_atr(vl,ATR_PREC_CACHED,ATR_NATURE_INTRINSIC,
"LAST-MODIFIED", ptr, NULL);
}
}
if((flags & A2PL_ROOT) || (flags & A2PL_H_LAST_MOD)) {
/* Modified date - in prospero format */
if(ptr = atopdate(sop->site_mod_time))
ad2l_seq_atr(vl,ATR_PREC_CACHED,ATR_NATURE_APPLICATION,
"AR_H_LAST_MOD", ptr, NULL);
}
if((flags & A2PL_ROOT || (flags & A2PL_H_IP_ADDR))) {
/* Host IP Address */
if(sop->site_ipaddr.s_addr)
ad2l_seq_atr(vl,ATR_PREC_CACHED,ATR_NATURE_APPLICATION,
"AR_H_IP_ADDR", inet_ntoa(sop->site_ipaddr),
NULL);
}
return(vl);
}
VLINK atoqlink(char *str,int maxhit,int maxmatch,int maxhitpm)
{
VLINK vl = vlalloc();
char fullpath[MAX_STRING_LEN];
sprintf(fullpath,"%s/MATCH(%d,%d,%d,0,=)/%s", archie_prefix,
maxhit, maxmatch, maxhitpm, str);
vl->name = stcopyr(str,vl->host);
vl->target = stcopyr("DIRECTORY",vl->target);
vl->hsoname = stcopyr(fullpath,vl->hsoname);
vl->host = stcopyr(hostwport,vl->host);
return(vl);
}

View File

@@ -0,0 +1,42 @@
/* Error codes returned by prarch routines */
#define PRARCH_SUCCESS 0 /* Successful completion */
#define PRARCH_BAD_ARG 1 /* Bad argument */
#define PRARCH_OUT_OF_MEMORY 2 /* Can't allocate enough space */
#define PRARCH_BAD_REGEX 3 /* Bad regular expression */
#define PRARCH_DONT_HAVE_SITE 4 /* Can't find site file */
#define PRARCH_CANT_OPEN_FILE 5 /* Can't open DB file */
#define PRARCH_DB_ERROR 6 /* Database Error */
#define PRARCH_CLEANUP 7 /* Cleanup failed */
#define PRARCH_TOO_MANY 8 /* Too many matches */
/* For constructing link attributes */
#define A2PL_H_IP_ADDR 0x001
#define A2PL_HOSTIP 0x001
#define A2PL_H_OS_TYPE 0x002
#define A2PL_H_TIMEZ 0x004
#define A2PL_LK_LAST_MOD 0x020
#define A2PL_LINK_COUNT 0x040
#define A2PL_LINK_SZ 0x080
#define A2PL_NATIVE_MODES 0x100
#define A2PL_H_LAST_MOD 0x200
#define A2PL_SITEDATE 0x200
#define A2PL_UNIX_MODES 0x800
#define A2PL_ROOT 0x10000
#define A2PL_ARDIR 0x40000
/* Structure definitions */
struct site_out_t{
struct in_addr site_ipaddr;
db_date site_mod_time;
char site_name[MAX_HOST_LEN];
char site_update[SMALL_STR_LEN];
char site_path[MAX_FILE_NAME];
site_rec site_ent;
};
typedef struct site_out_t site_out;
char *get_host_file_name();
struct vlink *atoplink();

View File

@@ -0,0 +1,293 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/param.h>
#include <sys/mman.h>
/* Archie definitions */
#include <ndbm.h>
#include <defines.h>
#include <archie_defs.h>
#include <structs.h>
#include <database.h>
#include <error.h>
#include "prarch.h"
#include <pfs.h>
#include <perrno.h>
#include <plog.h>
#include <pmachine.h> /* For bzero */
#define TOO_MANY_HOSTS 200
/*
* prarch_host - Search host for contents of directory
*
* ARGS: site_name - name of host for which search is to be made
* dirname - name of directory to return (NULL if root )
* vd - pointer to directory to be filled in
* archiedir - flag - directory links should be to archie
*/
int prarch_host(char *site_name, /* Name of host to be searched */
char *dirname, /* Name of directory to be listed */
VDIR vd, /* Directory to be filled in */
int flags) /* Flags: Which attributes to use */
{
site_out so;
char *host_name;
char result[MAX_STRING_LEN];
char date_str[SMALL_STR_LEN];
char hostip_str[SMALL_STR_LEN];
site_rec curr_site_rec;
site_rec rootrec;
int recno;
int last_parent = -1;
site_rec *site_ptr;
int correct_dir = 0; /* Scanning the requested directory */
int loopcount = 0; /* To decide when to call ardp_accept */
VLINK clink; /* Current link */
FILE *fp;
caddr_t site_begin;
site_rec *site_end;
struct stat statbuf;
if(!dirname) { /* Find host directory */
char hosttemp[200];
char *p = hosttemp;
char *htemp = site_name;
char tmp1[MAX_STRING_LEN];
char tmp2[MAX_STRING_LEN];
char dirlinkname[MAXPATHLEN];
char **test;
int i;
/* If a single wildcard, then return nothing */
if(strcmp(site_name,"*") == 0) return(PRARCH_SUCCESS);
/* If regular expressions or wildcards */
if((index(site_name,'(') || index(site_name,'?') ||
index(site_name,'*'))) {
if((*htemp == '(') && (*(htemp + strlen(htemp)-1) == ')')) {
strncpy(hosttemp,htemp+1,sizeof(hosttemp));
hosttemp[sizeof(hosttemp)-1] = '\0';
hosttemp[strlen(hosttemp)-1] = '\0';
}
else if(htemp) {
*p++ = '^';
while(*htemp) {
if(*htemp == '*') {*(p++)='.'; *(p++) = *(htemp++);}
else if(*htemp == '?') {*(p++)='.';htemp++;}
else if(*htemp == '.') {*(p++)='\\';*(p++)='.';htemp++;}
else if(*htemp == '[') {*(p++)='\\';*(p++)='[';htemp++;}
else if(*htemp == '$') {*(p++)='\\';*(p++)='$';htemp++;}
else if(*htemp == '^') {*(p++)='\\';*(p++)='^';htemp++;}
else if(*htemp == '\\') {*(p++)='\\';*(p++)='\\';htemp++;}
else *(p++) = *(htemp++);
}
*p++ = '$';
*p++ = '\0';
}
test = (char **) find_sites(hosttemp,&i,tmp1);
if((int) test == BAD_REGEX) {
p_err_string = qsprintf_stcopyr(p_err_string,
"archie find_sites(): bad regular expression");
return(PRARCH_BAD_REGEX);
}
if((int) test == DB_HBYADDR_ERROR) {
p_err_string = qsprintf_stcopyr(p_err_string,
"archie find_sites() hostbyaddr error");
return(PRARCH_DB_ERROR);
}
if((int) test == BAD_MALLOC) {
p_err_string = qsprintf_stcopyyr(p_err_string,
"archie find_sites() out of memory");
return(PRARCH_OUT_OF_MEMORY);
}
if(i > TOO_MANY_HOSTS) {
free(test[i]);
return(PRARCH_TOO_MANY);
}
else while( i-- ) {
get_site_file(test[i],tmp2);
if((fp = fopen(db_file(tmp2),"r")) != (FILE *) NULL) {
if(fstat(fileno(fp),&statbuf) == -1) {
plog(L_DB_ERROR,NOREQ,"can't stat site file %s",db_file(tmp2));
fclose(fp);
continue;
}
site_begin = mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,
fileno(fp),0);
if((site_begin == (caddr_t)-1) || (site_begin == (caddr_t)NULL)){
plog(L_DB_ERROR,NOREQ,"can't map site file %s",db_file(tmp2));
fclose(fp);
continue;
}
bzero(&so,sizeof(so));
if(print_sinfo(site_begin,so.site_name,hostip_str,date_str) != 0) {
plog(L_DB_ERROR,NOREQ,"can't obtain site info from %s",
db_file(tmp2));
munmap(site_begin,statbuf.st_size);
fclose(fp);
continue;
}
/* The root is the first record in the site after site info */
rootrec = *(((site_rec *) site_begin));
bcopy(&rootrec,&(so.site_ent),sizeof(rootrec));
bcopy(&(rootrec.in_or_addr.ipaddress),&(so.site_ipaddr),
sizeof(so.site_ipaddr));
bcopy(&(rootrec.mod_time),&(so.site_mod_time),
sizeof(so.site_mod_time));
clink = atoplink(&so,flags|A2PL_ARDIR|A2PL_ROOT);
if(clink) vl_insert(clink,vd,VLI_NOSORT);
if(munmap(site_begin,statbuf.st_size) == -1) {
plog(L_DB_ERROR,NOREQ,"archie munmap() failed on %s",db_file(tmp2));
return(PRARCH_CLEANUP);
}
fclose(fp);
free(test[i]);
}
else plog(L_DB_ERROR,NOREQ,"fopen failed for %s",db_file(tmp2));
}
return(PRARCH_SUCCESS);
}
/* No regular expression or wildcards */
else {
if(( host_name = get_host_file_name( site_name )) == (char *)NULL )
return(PRARCH_SUCCESS); /* No match */
if((fp = fopen(host_name,"r")) != (FILE *) NULL) {
if(fstat(fileno(fp),&statbuf) == -1) {
plog(L_DB_ERROR,NOREQ,"can't stat site file %s",db_file(tmp2));
fclose(fp);
return(PRARCH_CANT_OPEN_FILE);
}
site_begin = mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,
fileno(fp),0);
if((site_begin == (caddr_t)-1) || (site_begin == (caddr_t)NULL)){
plog(L_DB_ERROR,NOREQ,"can't map site file %s",db_file(tmp2));
fclose(fp);
return(PRARCH_CANT_OPEN_FILE);
}
bzero(&so,sizeof(so));
if(print_sinfo(site_begin,so.site_name,hostip_str,date_str) != 0) {
plog(L_DB_ERROR,NOREQ,"can't obtain site info from %s",
db_file(tmp2));
munmap(site_begin,statbuf.st_size);
fclose(fp);
return(PRARCH_DB_ERROR);
}
/* The root is the first record in the site after site info */
rootrec = *(((site_rec *) site_begin));
bcopy(&rootrec,&(so.site_ent),sizeof(rootrec));
bcopy(&(rootrec.in_or_addr.ipaddress),&(so.site_ipaddr),
sizeof(so.site_ipaddr));
bcopy(&(rootrec.mod_time),&(so.site_mod_time),
sizeof(so.site_mod_time));
clink = atoplink(&so,flags|A2PL_ARDIR|A2PL_ROOT);
if(clink) {
clink->name = stcopyr(site_name,clink->name);
vl_insert(clink,vd,VLI_NOSORT);
}
if(munmap(site_begin,statbuf.st_size) == -1) {
plog(L_DB_ERROR,NOREQ,"archie munmap() failed on %s",db_file(tmp2));
return(PRARCH_CLEANUP);
}
fclose(fp);
return(PRARCH_SUCCESS);
}
else return(PRARCH_CANT_OPEN_FILE);
}
}
bzero(&so,sizeof(so));
if(( host_name = get_host_file_name( site_name )) == (char *)NULL )
return(PRARCH_DONT_HAVE_SITE);
if((fp = fopen(host_name, "r")) == NULL)
return(PRARCH_CANT_OPEN_FILE);
if(fstat(fileno(fp),&statbuf) == -1) {
fclose(fp);
return(PRARCH_CANT_OPEN_FILE);
}
site_begin = mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,
fileno(fp),0);
if((site_begin == (caddr_t) -1) || (site_begin == (caddr_t) NULL)) {
fclose(fp);
return(PRARCH_CANT_OPEN_FILE);
}
if(print_sinfo(site_begin,so.site_name,hostip_str,date_str) != 0) {
munmap(site_begin,statbuf.st_size);
fclose(fp);
return(PRARCH_DB_ERROR);
}
site_end = (site_rec *)site_begin + statbuf.st_size / sizeof(site_rec);
rootrec = *(((site_rec *) site_begin));
bcopy(&(rootrec.in_or_addr.ipaddress),&(so.site_ipaddr),
sizeof(so.site_ipaddr));
bcopy(&(rootrec.mod_time),&(so.site_mod_time),
sizeof(so.site_mod_time));
for(recno = 1;(site_ptr = (site_rec *)site_begin + recno) < site_end;
recno++){
if((loopcount++ & 0x3ff) == 0) ardp_accept();
curr_site_rec = *site_ptr;
if(last_parent != curr_site_rec.parent_ind){
if(find_ancestors(site_begin, recno, result) != 0) {
munmap(site_begin,statbuf.st_size);
fclose(fp);
return(PRARCH_DB_ERROR);
}
last_parent = curr_site_rec.parent_ind;
/* Don't want to check the leading / */
if(strcmp(dirname,result+1) == 0) {
correct_dir++;
strcpy(so.site_path,result);
}
else if(correct_dir) break;
}
bcopy(&curr_site_rec,&(so.site_ent),sizeof(curr_site_rec));
if(correct_dir) {
if((loopcount & 0x7f) == 0) ardp_accept();
clink = atoplink(&so,flags);
if(clink) vl_insert(clink,vd,VLI_NOSORT);
}
}
munmap(site_begin,statbuf.st_size);
fclose(fp);
return(PRARCH_SUCCESS);
}

View File

@@ -0,0 +1,637 @@
/*XXX Note to make this thread safe, need to mutex re_comp and re_exec */
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h> /* For malloc and free */
#define _toupper(c) ((c)-'a'+'A')
#ifdef MMAP
#include <sys/mman.h>
#endif
/* Archie definitions */
#include <ndbm.h>
#include <defines.h>
#include <structs.h>
#include <database.h>
#include <error.h>
#include "prarch.h"
#include <ardp.h>
#include <pfs.h>
#include <perrno.h>
#include <plog.h>
VLINK atoplink();
VLINK atoqlink();
char *re_comp();
char *make_lcase();
int get_match_list();
extern char *strings_begin;
extern long strings_table_size;
extern DBM *fast_strings;
/* So we can adjust our cache policy based on queue length */
extern int pQlen;
static char lowertable[256] = {
'\000','\001','\002','\003','\004','\005','\006','\007',
'\010','\011','\012','\013','\014','\015','\016','\017',
'\020','\021','\022','\023','\024','\025','\026','\027',
'\030','\031','\032','\033','\034','\035','\036','\037',
' ','!','"','#','$','%','&','\'',
'(',')','*','+',',','-','.','/',
'0','1','2','3','4','5','6','7',
'8','9',':',';','<','=','>','?',
'@','a','b','c','d','e','f','g',
'h','i','j','k','l','m','n','o',
'p','q','r','s','t','u','v','w',
'x','y','z','[','\\',']','^','_',
'`','a','b','c','d','e','f','g',
'h','i','j','k','l','m','n','o',
'p','q','r','s','t','u','v','w',
'x','y','z','{','|','}','~','\177',
'\200','\201','\202','\203','\204','\205','\206','\207',
'\210','\211','\212','\213','\214','\215','\216','\217',
'\220','\221','\222','\223','\224','\225','\226','\227',
'\230','\231','\232','\233','\234','\235','\236','\237',
'\240','\241','\242','\243','\244','\245','\246','\247',
'\250','\251','\252','\253','\254','\255','\256','\257',
'\260','\261','\262','\263','\264','\265','\266','\267',
'\270','\271','\272','\273','\274','\275','\276','\277',
'\300','\301','\302','\303','\304','\305','\306','\307',
'\310','\311','\312','\313','\314','\315','\316','\317',
'\320','\321','\322','\323','\324','\325','\326','\327',
'\330','\331','\332','\333','\334','\335','\336','\337',
'\340','\341','\342','\343','\344','\345','\346','\347',
'\350','\351','\352','\353','\354','\355','\356','\357',
'\360','\361','\362','\363','\364','\365','\366','\367',
'\370','\371','\372','\373','\374','\375','\376','\377'};
#define MATCH_CACHE_SIZE 15
struct match_cache {
char *arg; /* Matched regular expression */
int max_hits; /* Maximum matchess <0 = found all */
int offset; /* Offset */
search_sel search_type; /* Search method (the one used) */
search_sel req_type; /* Requested method */
VLINK matches; /* Matches */
VLINK more; /* Additional matches */
int flags; /* Flags: for link attributes */
struct match_cache *next; /* Next entry in cache */
};
static struct match_cache *mcache = NULL;
static int cachecount = 0;
/*
* prarch_match - Search archie database for specified file
*
* PRARCH_MATCH searches the archie database and returns
* a list of files matching the provided regular expression
*
* ARGS: program_name - regular expression for files to match
* max_hits - maximum number of entries to return (max hits)
* offset - start the search after this many hits
* search_type - search method
* vd - pointer to directory to be filled in
* archiedir - flag - directory links should be to archie
* onlystrings - flag - only return strings, not matches
*
* Search method is one of: S_FULL_REGEX
* S_EXACT
* S_SUB_NCASE_STR
* S_SUB_CASE_STR
*/
int prarch_match(char *program_name, /* Regular expression to be matched */
int max_hits, /* Maximum number of entries to rtrn */
int max_match, /* Maximum number of unique strings */
int max_hitspm, /* Maximum hits per match */
int offset, /* Skip # matches before starting */
search_sel search_type, /* Search method */
VDIR vd, /* Directory to be filled in */
int flags, /* Flag for link attributes */
int onlystrings) /* Only return matching strings */
{
/*
* Search the database for the string specified by 'program_name'. Use the
* fast dbm strings database if 'is_exact' is set, otherwise search through
* the strings table. Stop searching after all matches have been found, or
* 'max_hits' matches have been found, whichever comes first.
*/
char s_string[MAX_STRING_LEN];
char *strings_ptr;
char *strings_curr_off;
strings_header str_head;
datum search_key, key_value;
search_sel new_search_type = S_EXACT; /* Alternate search method */
search_sel or_search_type = search_type; /* Original search method */
int nocase = 0;
int hits_exceeded = FALSE; /* should be boolean? */
char *strings_end;
int match_number;
int patlen;
site_out **site_outptr;
site_out site_outrec;
int i;
VLINK cur_link;
int loopcount = 0;
int retval;
int match_rem = max_match;
if(!program_name || !(*program_name)) return(PRARCH_BAD_ARG);
if((0 < max_hits) && (max_hits < match_rem)) match_rem = max_hits;
if((0 < max_hits) && (max_hits < max_hitspm)) max_hitspm = max_hits;
strcpy(s_string, program_name);
/* See if we can use a less expensive search method */
if((search_type == S_FULL_REGEX) || (search_type == S_E_FULL_REGEX)) {
/* Regex search assumes wildcards on both ends, so remove from string */
if(strncmp(program_name,".*",2) == 0)
strcpy(s_string, program_name+2);
if((i = strlen(s_string)) >= 2) {
if(strcmp(s_string+i-2,".*") == 0)
*(s_string+i-2) = '\0';
}
/* If no special characters, then fall back to substring search */
if((search_type == S_FULL_REGEX) &&
(strpbrk(s_string,"\\^$.,[]<>*+?|(){}/") == NULL))
or_search_type = search_type = S_SUB_CASE_STR;
else if((search_type == S_E_FULL_REGEX) &&
(strpbrk(s_string,"\\^$.,[]<>*+?|(){}/") == NULL))
or_search_type = search_type = S_E_SUB_CASE_STR;
}
/* The caching code assumes we are handed an empty directory */
/* if not, return an error for now. Eventually we will get */
/* rid of that assumption */
if(vd->links) {
plog(L_DIR_ERR, NOREQ, "Prarch_match handed non empty dir",0);
return(PRARCH_BAD_ARG);
}
if(!onlystrings && (check_cache(s_string,max_hits,offset,search_type,
flags,&(vd->links)) == TRUE)) {
plog(L_DB_INFO, NOREQ, "Responding with cached data",0);
return(PSUCCESS);
}
site_outptr = (site_out **) malloc((unsigned)(sizeof(site_out) *
(max_hits + offset)));
if(!site_outptr) return(PRARCH_OUT_OF_MEMORY);
startsearch:
strings_ptr = strings_begin;
strings_end = strings_begin + (int) strings_table_size;
match_number = 0;
switch(search_type){
case S_E_SUB_CASE_STR:
new_search_type = S_SUB_CASE_STR;
goto exact_match;
case S_E_SUB_NCASE_STR:
new_search_type = S_SUB_NCASE_STR;
goto exact_match;
case S_E_FULL_REGEX:
new_search_type = S_FULL_REGEX;
exact_match:
case S_EXACT:
search_key.dptr = s_string;
search_key.dsize = strlen(s_string) + 1;
ardp_accept();
key_value = dbm_fetch(fast_strings, search_key) ;
if(key_value.dptr != (char *)NULL){ /* string in table */
int string_pos;
bcopy(key_value.dptr,(char *)&string_pos, key_value.dsize);
strings_ptr += string_pos;
bcopy(strings_ptr,(char *)&str_head,sizeof(strings_header));
ardp_accept();
if(onlystrings) {
cur_link = atoqlink(strings_ptr,max_hits,max_match,max_hitspm);
if(cur_link) vl_insert(cur_link,vd,VLI_NOSORT);
if(--match_rem <= 0) {
hits_exceeded = TRUE;
break;
}
}
else if(str_head.filet_index != -1) {
retval = get_match_list((int) str_head.filet_index, max_hitspm,
&match_number, site_outptr, FALSE);
if((retval != A_OK) && (retval != HITS_EXCEEDED)) {
plog(L_DB_ERROR, NOREQ,"get_match_list failed (%d)",retval,0);
goto cleanup;
}
if( match_number >= max_hits + offset ){
hits_exceeded = TRUE;
break;
}
}
}
else if (search_type != S_EXACT) { /* Not found - but try other method */
search_type = new_search_type;
goto startsearch;
}
break;
case S_FULL_REGEX:
if(re_comp(s_string) != (char *)NULL){
return (PRARCH_BAD_REGEX);
}
str_head.str_len = -1;
ardp_accept();
while((strings_curr_off = strings_ptr + str_head.str_len + 1) < strings_end){
if((loopcount++ & 0x7ff) == 0) ardp_accept();
strings_ptr = strings_curr_off;
bcopy(strings_ptr,(char *)&str_head,sizeof(strings_header));
strings_ptr += sizeof(strings_header);
if(re_exec( strings_ptr ) == 1 ){ /* TRUE */
strings_curr_off = strings_ptr;
ardp_accept();
if(onlystrings) {
if(strstr(strings_ptr," -> ") == NULL) { /* No broken strings */
cur_link = atoqlink(strings_ptr,max_hits,max_match,max_hitspm);
if(cur_link) vl_insert(cur_link,vd,VLI_NOSORT);
if(--match_rem <= 0) {
hits_exceeded = TRUE;
break;
}
}
}
else if(str_head.filet_index != -1){
retval = get_match_list((int) str_head.filet_index, max_hitspm,
&match_number, site_outptr, FALSE);
if((retval != A_OK) && (retval != HITS_EXCEEDED)) {
plog(L_DB_ERROR, NOREQ,"get_match_list failed (%d)",retval,0);
goto cleanup;
}
if( match_number >= max_hits + offset ){
hits_exceeded = TRUE;
break;
}
}
}
}
break;
#define TABLESIZE 256
case S_SUB_NCASE_STR:
nocase++;
case S_SUB_CASE_STR: {
char pattern[MAX_STRING_LEN];
int skiptab[TABLESIZE];
register int pc, tc;
register int local_loopcount = 0xfff;
char *bp1;
int skip;
int plen;
int plen_1;
int tlen;
unsigned char tchar;
plen = strlen(s_string);
plen_1 = plen -1;
/* Old code (replaced by inline code taken from initskip) */
/* patlen = strlen(s_string ) ; */
/* initskip(s_string, patlen, search_type == S_SUB_NCASE_STR) ; */
if(nocase) {
for(pc = 0; s_string[pc]; pc++)
pattern[pc] = lowertable[s_string[pc]];
pattern[pc] = '\0';
}
else strcpy(pattern,s_string);
for( i = 0 ; i < TABLESIZE ; i++ )
skiptab[ i ] = plen;
/* Note that we want both ucase and lcase in this table if nocase */
for( i = 0, tchar = *pattern; i < plen ; i++, tchar = *(pattern + i)) {
skiptab[tchar] = plen - 1 - i;
if(nocase && islower(tchar))
skiptab[_toupper(tchar)] = plen - 1 - i;
}
/* Begin heavily optimized and non portable code */
/* Note that we are depending on str_head being 8 bytes */
tlen = -9; /* str_head.str_len */
strings_curr_off = strings_ptr;
while((strings_curr_off += tlen + 9) < strings_end) {
if(--local_loopcount == 0) {
ardp_accept();
local_loopcount = 0xfff;
}
strings_ptr = strings_curr_off;
/* This is a kludge, non-portable, but it eliminates a pr call */
/* Note that the size is 8 on suns. Is there a better way? */
/* bcopy(strings_ptr,(char *)&str_head,sizeof(strings_header)); */
bp1 = (char *) &str_head;
/* The copying of the file index is done only on a match */
bp1[4] = strings_ptr[4]; bp1[5] = strings_ptr[5];
/* bp1[6] = strings_ptr[6]; bp1[7] = strings_ptr[7]; */
tlen = (unsigned short) str_head.str_len;
/* To catch database corruption, this is a sanity check */
if((tlen < 0) || (tlen > MAX_STRING_LEN)) {
plog(L_DB_ERROR, NOREQ,"Database corrupt: string length out of bounds",0);
break;
}
/* Old code (replaced by inline code taken from strfind) */
/* if(strfind(strings_ptr,str_head.str_len)) */
if( tlen <= plen_1 ) continue;
pc = tc = plen_1;
strings_ptr += 8;
/* Moved the nocase test outside the inner loop for performace */
/* Clauses are identical except for the first if */
if(nocase) do {
tchar = strings_ptr[tc];
/* improve efficiency of this test */
if(lowertable[tchar] == pattern[pc]) {--pc; --tc;}
else {
skip = skiptab[tchar] ;
tc += (skip < plen_1 - pc) ? plen : skip ;
pc = plen_1 ;
}
} while( pc >= 0 && tc < tlen ) ;
else /* (!nocase) */ do {
tchar = strings_ptr[tc];
/* improve efficiency of this test */
if(tchar == pattern[pc]) {--pc; --tc;}
else {
skip = skiptab[tchar] ;
tc += (skip < plen_1 - pc) ? plen : skip ;
pc = plen_1 ;
}
} while( pc >= 0 && tc < tlen ) ;
if(pc >= 0) continue;
/* We have a match */
/* Finish copying str_head - strings_curr_off */
/* is old strings_ptr. */
bp1[0] = strings_curr_off[0]; bp1[1] = strings_curr_off[1];
bp1[2] = strings_curr_off[2]; bp1[3] = strings_curr_off[3];
/* End heavily optimized and non portable code */
ardp_accept();
if(onlystrings) {
if(strstr(strings_ptr," -> ") == NULL) { /* No broken strings */
cur_link = atoqlink(strings_ptr,max_hits,max_match,max_hitspm);
if(cur_link) vl_insert(cur_link,vd,VLI_NOSORT);
if(--match_rem <= 0) {
hits_exceeded = TRUE;
break;
}
}
}
else if(str_head.filet_index != -1){
retval = get_match_list((int) str_head.filet_index, max_hitspm,
&match_number, site_outptr, FALSE);
if((retval != A_OK) && (retval != HITS_EXCEEDED)) {
plog(L_DB_ERROR,NOREQ,"get_match_list failed (%d)",retval,0);
goto cleanup;
}
if( match_number >= max_hits + offset ) {
hits_exceeded = TRUE;
break;
}
}
}
}
break;
default:
return(PRARCH_BAD_ARG);
cleanup:
for(i = 0;i < match_number; i++) free((char *)site_outptr[i]);
free((char *)site_outptr);
return(PRARCH_DB_ERROR);
}
for(i = 0;i < match_number; i++){
if((i & 0x7f) == 0) ardp_accept();
site_outrec = *site_outptr[i];
if(i >= offset) {
cur_link = atoplink(site_outrec,flags);
if(cur_link) vl_insert(cur_link,vd,VLI_NOSORT);
}
free((char *)site_outptr[i]);
}
free((char *)site_outptr);
if(hits_exceeded) {
/* Insert a continuation entry */
}
if((search_type == S_EXACT) && (pQlen > (MATCH_CACHE_SIZE - 5)))
return(PRARCH_SUCCESS);
if(!onlystrings)
add_to_cache(vd->links,s_string, (hits_exceeded ? max_hits : -max_hits),
offset,search_type,or_search_type,flags);
return(PRARCH_SUCCESS);
}
/* Check for cached results */
check_cache(arg,max_hits,offset,qtype,flags,linkpp)
char *arg;
int max_hits;
int offset;
search_sel qtype;
int flags;
VLINK *linkpp;
{
struct match_cache *cachep = mcache;
struct match_cache *pcachep = NULL;
VLINK tmp_link, cur_link;
VLINK rest = NULL;
VLINK next = NULL;
int count = max_hits;
while(cachep) {
if(((qtype == cachep->search_type)||(qtype == cachep->req_type))&&
(cachep->offset == offset) &&
/* All results are in cache - or enough to satisfy request */
((cachep->max_hits < 0) || (max_hits <= cachep->max_hits)) &&
(strcmp(cachep->arg,arg) == 0) &&
(cachep->flags == flags)) {
/* We have a match. Move to front of list */
if(pcachep) {
pcachep->next = cachep->next;
cachep->next = mcache;
mcache = cachep;
}
/* We now have to clear the expanded bits or the links */
/* returned in previous queries will not be returned */
/* We also need to truncate the list of there are more */
/* matches than requested */
cur_link = cachep->matches;
/* IMPORTANT: This code assumes the list is one */
/* dimensional, which is the case because we called */
/* vl_insert with the VLI_NOSORT option */
while(cur_link) {
cur_link->expanded = FALSE;
if((--count == 0) && cur_link->next) {
/* truncate list */
if(cachep->more) {
cur_link->next->previous = cachep->more->previous;
cachep->more->previous = cachep->matches->previous;
cachep->matches->previous->next = cachep->more;
}
else {
cachep->more = cur_link->next;
cachep->more->previous = cachep->matches->previous;
}
cur_link->next = NULL;
cachep->matches->previous = cur_link;
}
else if ((cur_link->next == NULL) && (count != 0) &&
cachep->more) {
/* Merge lists */
cachep->matches->previous = cachep->more->previous;
cur_link->next = cachep->more;
cachep->more->previous = cur_link;
cachep->more = NULL;
}
cur_link = cur_link->next;
}
*linkpp = cachep->matches;
return(TRUE);
}
pcachep = cachep;
cachep = cachep->next;
}
*linkpp = NULL;
return(FALSE);
}
/* Cache the response for later use */
add_to_cache(vl,arg,max_hits,offset,search_type,req_type,flags)
VLINK vl;
char *arg;
int max_hits;
int offset;
search_sel search_type;
search_sel req_type;
int flags;
{
struct match_cache *newresults = NULL;
struct match_cache *pcachep = NULL;
if(cachecount < MATCH_CACHE_SIZE) { /* Create a new entry */
newresults = (struct match_cache *) malloc(sizeof(struct match_cache));
cachecount++;
newresults->next = mcache;
mcache = newresults;
newresults->arg = stcopy(arg);
newresults->max_hits = max_hits;
newresults->offset = offset;
newresults->search_type = search_type;
newresults->req_type = req_type;
newresults->flags = flags;
newresults->matches = NULL;
newresults->more = NULL;
}
else { /* Use last entry - Assumes list has at least two entries */
pcachep = mcache;
while(pcachep->next) pcachep = pcachep->next;
newresults = pcachep;
/* move to front of list */
newresults->next = mcache;
mcache = newresults;
/* Fix the last entry so we don't have a cycle */
while(pcachep->next != newresults) pcachep = pcachep->next;
pcachep->next = NULL;
/* Free the old results */
if(newresults->matches) {
newresults->matches->dontfree = FALSE;
vllfree(newresults->matches);
newresults->matches = NULL;
}
if(newresults->more) {
newresults->more->dontfree = FALSE;
vllfree(newresults->more);
newresults->more = NULL;
}
newresults->arg = stcopyr(arg,newresults->arg);
newresults->max_hits = max_hits;
newresults->offset = offset;
newresults->search_type = search_type;
newresults->req_type = req_type;
newresults->flags = flags;
}
/* Since we are caching the data. If there are any links, */
/* note that they should not be freed when sent back */
if(vl) vl->dontfree = TRUE;
newresults->matches = vl;
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 1992, 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-copyr.h>
*/
#include <usc-copyr.h>
#include <pfs.h> /* def of PATTRIB */
#include <psrv.h> /* prototype for delete_matching_at() */
#include <list_macros.h> /* EXTRACT_ITEM macro */
#include <perrno.h>
/* Looks for an attribute equal to the key according to the equal function.
Deletes & frees it.
Returns: PSUCCESS or PFAILURE
This is currently only used in ed_link_info.c and ed_obj_info.c
*/
int
delete_matching_at(PATTRIB key, PATTRIB *headp, int (*equal)(PATTRIB, PATTRIB))
{
/* ick - this was "index" which is defined as a macro */
PATTRIB ind;
/* Find the match. */
for (ind = *headp; ind; ind = ind->next) {
if ((*equal)(key, ind)) {
EXTRACT_ITEM(ind, (*headp));
atfree(ind);
return PSUCCESS;
}
}
RETURNPFAILURE;
}
int
delete_matching_fl(FILTER key, FILTER *headp)
{
FILTER ind;
/* Find the match. */
for (ind = *headp; ind; ind = ind->next) {
if (equal_filters(key, ind)) {
EXTRACT_ITEM(ind, (*headp));
flfree(ind);
return PSUCCESS;
}
}
RETURNPFAILURE;
}

View File

@@ -0,0 +1,468 @@
/*
* Copyright (c) 1991 by the University of Washington
*
* For copying and distribution information, please see the file
* <uw-copyright.h>.
*/
#include <uw-copyright.h>
#include <string.h> /* No strings.h in SOLARIS */
#include <ardp.h>
#include <pfs.h>
#include <psite.h>
#include <pprot.h>
#include <plog.h>
#include <pmachine.h>
#include <psrv.h>
#include <perrno.h>
static ACL find_aclent();
char *addrights();
char *subtractrights();
extern ACL nulldir_acl;
extern ACL nullobj_acl;
extern ACL nullcont_acl;
extern ACL nulllink_acl;
ACL aclcopy();
/*
* change_acl - change access control list
*
* CHANGE_ACL change an access control list (*aclp)
* by adding, deleting, or modifying the entry
* specified by ae.
*
* ARGS: aclp - pointer to ACL pointer
* ae - a pointer to a single ACL entry to be added or deleted
* id - client identification
* flags - information on the operation to be performed
* diracl - the directory acl (to check if user has access)
*
* NOTE: This code which automatically adds administer (unless noself
* is specified) can be used to upgrade < or [ privs to A. Dirsrv
* include a check which sets noself when admister access is
* allows by virtual of a [ or <.
*/
int
change_acl(aclp,ae,req,flags,diracl)
ACL *aclp; /* Pointer to ACL pointer */
ACL ae; /* ACL entry to change */
RREQ req; /* Client identification */
int flags; /* Operation and flags */
ACL diracl;/* Directory ACL */
{
ACL a = *aclp;
ACL ws;
ACL wacl;
int operation;
int nosystem;
int noself;
int dflag;
int oflag;
int adminflag;
int acltype;
int sca_code;
PAUTH painfo = NULL;
operation = flags & EACL_OP;
nosystem = flags & EACL_NOSYSTEM;
noself = flags & EACL_NOSELF;
dflag = !((flags&EACL_OTYPE)^EACL_DIRECTORY);
oflag = !((flags&EACL_OTYPE)^EACL_OBJECT);
acltype = (flags&EACL_OTYPE);
if(acltype == EACL_LINK) sca_code = SCA_LINK;
else if(acltype == EACL_DIRECTORY) sca_code = SCA_DIRECTORY;
else if(acltype == EACL_OBJECT) sca_code = SCA_OBJECT;
else sca_code = SCA_MISC;
switch(operation) {
case EACL_DEFAULT:
aclfree(a);
acfree(ae);
a = NULL;
/* If adminflag is clear it means that the user would not be */
/* able to administer the new directory or link, and that */
/* such a situation is undesirable */
if(noself) adminflag = 1; /* Ok to clear admin rights for user */
else if(acltype == EACL_LINK)
adminflag = srv_check_acl(a,diracl,req,"a",sca_code,NULL,NULL);
else adminflag = srv_check_acl(a,a,req,"A",sca_code,NULL,NULL);
if(acltype == EACL_LINK) a = aclcopy(nulllink_acl);
else if(acltype == EACL_DIRECTORY) a = aclcopy(nulldir_acl);
else if(acltype == EACL_OBJECT) a = aclcopy(nullobj_acl);
if(adminflag == 0) srv_add_client_to_acl("Aa",req,&(a),acltype);
*aclp = a;
return(PSUCCESS);
case EACL_SET:
aclfree(a);
a = ae;
/* Unless the nosystem flag has been specified, add an */
/* entry for the SYSTEM ACL */
if(!nosystem) {
wacl = acalloc();
wacl->acetype = ACL_SYSTEM;
a->next = wacl;
wacl->previous = a;
}
/* If adminflag is clear it means that the user would not be */
/* able to administer the new directory or link, and that */
/* such a situation is undesirable */
if(noself) adminflag = 1; /* Ok to clear admin rights for user */
else if(acltype == EACL_LINK)
adminflag = srv_check_acl(a,diracl,req,"a",sca_code,NULL,NULL);
else adminflag = srv_check_acl(a,a,req,"A",sca_code,NULL,NULL);
if(adminflag == 0) srv_add_client_to_acl("Aa",req,&(a),acltype);
*aclp = a;
return(PSUCCESS);
eacl_insert:
case EACL_INSERT:
/* Must make sure all required fields are specified */
/* Rights must be included for all but NONE, DEFAULT, */
/* SYSTEM, and DIRECTORY, CONTAINER, and IETF_AAC */
if(!((ae->rights && *(ae->rights))||(ae->acetype==ACL_NONE) ||
(ae->acetype==ACL_DEFAULT)||(ae->acetype==ACL_SYSTEM) ||
(ae->acetype==ACL_DIRECTORY)||(ae->acetype==ACL_CONTAINER)||
(ae->acetype==ACL_IETF_AAC))) {
RETURNPFAILURE;
}
/* No need to make sure the user can still access since */
/* we are only adding rights. This ignores the case of */
/* negative rights, but for now we assume that if the */
/* user is specifying negative rights that they are */
/* intended */
/* If NULL, first add entries for default values. We need */
/* to leave them even if the user said not to add them */
/* Since they were "already there". */
if(!a) {
if(acltype == EACL_LINK) a = aclcopy(nulllink_acl);
else if(acltype == EACL_DIRECTORY) a = aclcopy(nulldir_acl);
else if(acltype == EACL_OBJECT) a = aclcopy(nullobj_acl);
}
/* Check to see if entry already exists */
wacl = find_aclent(a,ae,1);
if(wacl) {
/* Already there */
aclfree(ae);
*aclp = a;
return(PSUCCESS);
}
/* New ACL antries are added a head of list. This means */
/* that any negative rights specified will override any */
/* rights that were already present. Additionaly, any */
/* positive rights specified will override any negative */
/* rights that already existed. */
wacl = ae;
while(wacl->next) wacl = wacl->next;
wacl->next = a;
a->previous = wacl;
a = wacl;
*aclp = a;
return(PSUCCESS);
eacl_delete:
case EACL_DELETE:
/* If NULL, first add entries for default values. We need */
/* to leave them even if the user said not to add them */
/* Since they were "already there". */
if(!a) {
if(acltype == EACL_LINK) a = aclcopy(nulllink_acl);
else if(acltype == EACL_DIRECTORY) a = aclcopy(nulldir_acl);
else if(acltype == EACL_OBJECT) a = aclcopy(nullobj_acl);
}
wacl = find_aclent(a,ae,1);
if(!wacl) RETURNPFAILURE;
if(a == wacl) {
a = a->next;
a->previous = NULL;
acfree(wacl);
}
else {
wacl->previous->next = wacl->next;
if(wacl->next) wacl->next->previous = wacl->previous;
acfree(wacl);
}
if(noself) adminflag = 1; /* Ok to clear admin rights for user */
else if(acltype == EACL_LINK)
adminflag = srv_check_acl(a,diracl,req,"a",sca_code,NULL,NULL);
else adminflag = srv_check_acl(a,a,req,"A",sca_code,NULL,NULL);
if(adminflag == 0) srv_add_client_to_acl("Aa",req,&(a),acltype);
/* If empty, must create a placeholder so that it */
/* doesn't revert to nulldir */
if(!a) {
a = acalloc();
a->acetype = ACL_NONE;
}
acfree(ae);
*aclp = a;
return(PSUCCESS);
case EACL_ADD:
/* If no rights specified must be insert */
if(!(ae->rights)) goto eacl_insert;
/* Havn't figured out how to ADD ><][)(, so go to INSERT */
if(index("><][)(",*(ae->rights))) goto eacl_insert;
/* If NULL, first add entries for default values. We need */
/* to leave them even if the user said not to add them */
/* Since they were "already there". */
if(!a) {
if(acltype == EACL_LINK) a = aclcopy(nulllink_acl);
else if(acltype == EACL_DIRECTORY) a = aclcopy(nulldir_acl);
else if(acltype == EACL_OBJECT) a = aclcopy(nullobj_acl);
}
wacl = find_aclent(a,ae,0);
/* If no other entries, then go to insert */
if(!wacl) goto eacl_insert;
/* Now we must add characters to wacl->rights for */
/* any new characters in ae->rights */
wacl->rights = stcopyr(addrights(wacl->rights,ae->rights),wacl->rights);
acfree(ae);
return(PSUCCESS);
case EACL_SUBTRACT:
/* If no rights specified must delete */
if(!(ae->rights)) goto eacl_delete;
/* Havn't figured out how to DELETE ><][)(, so go to DELETE */
if(index("><][)(",*(ae->rights))) goto eacl_delete;
wacl = find_aclent(a,ae,0);
/* If no other entries, return error */
if(!wacl) {
acfree(ae);
RETURNPFAILURE;
}
/* Now we must subtract characters from wacl->rights */
/* for the characters in ae->rights */
wacl->rights = subtractrights(wacl->rights,ae->rights);
/* If rights are now null, must delete the entry */
if(!wacl->rights || !*(wacl->rights)) {
if(wacl->previous) {
wacl->previous->next = wacl->next;
if(wacl->next) wacl->next->previous = wacl->previous;
acfree(wacl);
}
else { /* It is at start of list */
a = wacl->next;
a->previous = NULL;
acfree(wacl);
}
}
/* Make sure that user can fix his mistakes */
if(noself) adminflag = 1; /* Ok to clear admin rights for user */
else if(acltype == EACL_LINK)
adminflag = srv_check_acl(a,diracl,req,"a",sca_code,NULL,NULL);
else adminflag = srv_check_acl(a,a,req,"A",sca_code,NULL,NULL);
if(adminflag == 0) srv_add_client_to_acl("Aa",req,&(a),acltype);
/* If empty, must create a placeholder so that it */
/* doesn't revert to nulldir */
if(!a) {
a = acalloc();
a->acetype = ACL_NONE;
}
acfree(ae);
*aclp = a;
return(PSUCCESS);
}
RETURNPFAILURE;
}
/*
* This function adds rights to the ACL for all principals identified
* in the clients auth_info structure
*/
void
srv_add_client_to_acl(char *rights, /* Rights to be added */
RREQ req, /* Client identification */
ACL *inoutacl,
int flags) /* Directory ACL */
{
ACL nacl = NULL; /* new ACL entry */
PAUTH painfo = req->auth_info;
int times_thru = 0;
while(painfo) {
/* Defer the weakest method unless it's the only method */
if((painfo->ainfo_type == PFSA_UNAUTHENTICATED) && !check_prvport(req))
{painfo = painfo->next; continue;}
nacl = acalloc();
nacl->rights = stcopyr(rights,nacl->rights);
if(painfo->ainfo_type == PFSA_UNAUTHENTICATED) {
TOKEN p = req->auth_info->principals;
nacl->acetype = ACL_TRSTHOST;
nacl->rights = stcopyr(rights,nacl->rights);
for ( ; p ; p = p->next) {
nacl->principals = tkappend(NULL,nacl->principals);
nacl->principals->previous->token =
qsprintf_stcopyr(NULL,"%s@%s",p->token,
inet_ntoa(req->peer_addr));
}
}
else if(painfo->ainfo_type == PFSA_KERBEROS) {
nacl->acetype = ACL_AUTHENT;
nacl->atype = stcopy("KERBEROS");
}
else if(painfo->ainfo_type == PFSA_P_PASSWORD) {
nacl->acetype = ACL_AUTHENT;
nacl->atype = stcopy("P_PASSWORD");
}
if(!(nacl->principals)) nacl->principals = tkcopy(painfo->principals);
change_acl(inoutacl,nacl,req,EACL_ADD|flags,*inoutacl);
painfo = painfo->next;
}
/* OK, so ASRTHOST is the only method, I guess we'll use it */
if(!nacl && req->auth_info &&
(req->auth_info->ainfo_type == PFSA_UNAUTHENTICATED)) {
TOKEN p = req->auth_info->principals;
nacl = acalloc();
nacl->acetype = ACL_ASRTHOST;
nacl->rights = stcopyr(rights,nacl->rights);
for ( ; p ; p = p->next) {
nacl->principals = tkappend(NULL,nacl->principals);
nacl->principals->previous->token =
qsprintf_stcopyr(NULL,"%s@%s",p->token,
inet_ntoa(req->peer_addr));
}
change_acl(inoutacl,nacl,req,EACL_ADD|flags,*inoutacl);
}
}
/*
* Find an ACL entry matching entry e in list a
*
* r is a flag which if set means the rights must match.
* if clear, then the rights can be different.
*/
static ACL find_aclent(a,e,r)
ACL a;
ACL e;
int r;
{
ACL w;
w = a;
while(w) {
if((w->acetype == e->acetype) &&
((!(w->atype) && !(e->atype)) ||
(w->atype && e->atype && (strcmp(w->atype,e->atype)==0))) &&
((!(w->principals) && !(e->principals)) ||
(w->principals && e->principals
&& equal_sequences(w->principals,e->principals))) &&
((!r && (!(w->rights) || !(index("><)(][",*(w->rights))))) ||
(!(w->rights) && !(e->rights)) ||
(w->rights && e->rights && (strcmp(w->rights,e->rights)==0))))
return(w);
w = w->next;
}
return(NULL);
}
/*
* Add rights returns a string containing those rights
* that are in r or a. For known rights, addrights
* will try to place them in canonical order.
*
* WARNING: Subtractrights frees r. It is expected that
* the string pointed to by r will be replaced
* by the string handed back.
*/
char *addrights(char *r, char *a)
{
/* Don't need to mutex; constant. */
const char canonical[] = "-><)(][STUABVYLlRQGgrWMmwuDKzdEeIiPp";
char *cp; /* index variable */
const char *ccp; /* index variable */
char *newrights;
char *nr; /* newrights */
if(!r) return(stcopy(a));
nr = newrights = stalloc(strlen(r)+strlen(a)+1);
/* First check each known right */
for(ccp = canonical;*ccp;ccp++) {
if(index(r,*ccp)) *(nr++) = *ccp;
else if(index(a,*ccp)) *(nr++) = *ccp;
}
/* Now scan r and include anything that is not canonical */
for(cp = r;*cp;cp++) {
if(index(canonical,*cp)==0) *(nr++) = *cp;
}
/* Now scan a and include anything that is not canonical */
/* and isn't in r */
for(cp = a;*cp;cp++) {
if((index(canonical,*cp)==0)&&
(index(r,*cp)==0)) *(nr++) = *cp;
}
*(nr++) = '\0';
stfree(r);
return(newrights);
}
/*
* Subtract rights returns a string containing those rights
* in r that are not in s.
*
* WARNING: Subtractrights frees r. It is expected that
* the string pointed to by r will be replaced
* by the string handed back.
*/
char *subtractrights(r,s)
char *r;
char *s;
{
char *newrights = stalloc(strlen(r)+1);
char *or; /* oldrights */
char *nr; /* newrights */
for(or = r,nr = newrights;*or;or++) {
if(strchr(s,*or)==NULL) *(nr++) = *or;
}
*(nr++) = '\0';
stfree(r);
return(newrights);
}

View File

@@ -0,0 +1,879 @@
/*
* Copyright (c) 1991 by the University of Washington
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the files
* <uw-copyright.h> and <usc-copyr.h>.
*/
#include <uw-copyright.h>
#include <usc-copyr.h>
#include <string.h>
#include <sys/types.h> /* for decl. of inet_ntoa() */
#include <sys/socket.h> /* for decl. of inet_ntoa() */
#include <netinet/in.h> /* for decl. of inet_ntoa() */
#include <arpa/inet.h> /* for decl. of inet_ntoa() */
#include <ardp.h>
#include <pfs.h>
#include <pserver.h>
#include <pprot.h>
#include <plog.h>
#include <pmachine.h>
#include <psrv.h>
#ifndef IPPORT_RESERVED
#define IPPORT_RESERVED 1024
#endif
/* used to initialize ACLs */
struct aclinit {
int acetype;
char *atype;
char *rights;
char *prin_1; /* principals list */
char *prin_2; /* principals list */
char *prin_3; /* principals list */
char *prin_4; /* principals list */
char *prin_5; /* principals list */
char *prin_6; /* principals list */
char *prin_7; /* principals list */
char *prin_8; /* principals list */
char *prin_9; /* principals list */
char *prin_10; /* principals list */
char *prin_11; /* principals list */
char *prin_12; /* principals list */
char *prin_13; /* principals list */
char *prin_14; /* principals list */
char *prin_15; /* principals list */
char *prin_16; /* principals list */
char *prin_17; /* principals list */
char *prin_18; /* principals list */
char *prin_19; /* principals list */
char *prin_20; /* principals list */
char *prin_21; /* principals list */
char *prin_22; /* principals list */
char *prin_23; /* principals list */
char *prin_24; /* principals list */
char *prin_25; /* principals list */
char *prin_26; /* principals list */
};
static ACL_ST default_iacl = {ACL_DEFAULT, NULL};
static ACL_ST system_iacl = {ACL_SYSTEM, NULL};
static ACL_ST container_iacl = {ACL_CONTAINER, NULL};
static ACL_ST directory_iacl = {ACL_DIRECTORY, NULL};
static struct aclinit default_aclinit[] = DEFAULT_ACL;
static struct aclinit system_aclinit[] = SYSTEM_ACL;
static struct aclinit override_aclinit[] = OVERRIDE_ACL;
static struct aclinit maint_aclinit[] = MAINT_ACL;
/* Only modified in p_srv_check_acl_initialize_defaults(), which is called
before we go multi-threaded. */
ACL default_acl = NULL;
ACL system_acl = NULL;
ACL override_acl = NULL;
ACL nulldir_acl = NULL;
ACL nullobj_acl = NULL;
ACL nullcont_acl = NULL;
ACL nulllink_acl = NULL;
ACL maint_acl = NULL;
static checkl_acl_r();
static check_permissions();
static check_asserted_principal();
ACL get_container_acl();
static ACL aclinit2acl(struct aclinit init[], int nelems);
static int checkl_acl_r(ACL acl, ACL dacl, RREQ req, char *op, int depth, int ld,char *objid,char *itemid);
/* Called before things start to run in psrv. */
void
p_srv_check_acl_initialize_defaults(void)
{
default_acl = aclinit2acl(default_aclinit,
sizeof default_aclinit
/ sizeof default_aclinit[0]);
system_acl = aclinit2acl(system_aclinit,
sizeof system_aclinit
/ sizeof system_aclinit[0]);
override_acl = aclinit2acl(override_aclinit,
sizeof override_aclinit
/ sizeof override_aclinit[0]);
maint_acl = aclinit2acl(maint_aclinit,
sizeof maint_aclinit
/ sizeof maint_aclinit[0]);
default_iacl.next = &system_iacl;
system_iacl.previous = &default_iacl;
nulldir_acl = &default_iacl;
nulllink_acl = &directory_iacl;
nullobj_acl = &container_iacl;
nullcont_acl = nulldir_acl;
}
static ACL aclentryinit2aclentry(struct aclinit *init);
/* constructs a real list of ACL entries out of an array of aclinit
structures. */
static ACL
aclinit2acl(struct aclinit init[], int nelems)
{
ACL rethead = NULL; /* head of list of AC entries being returned */
int i;
for (i = 0; i < nelems; ++i) {
ACL tmp = aclentryinit2aclentry(&init[i]);
APPEND_ITEM(tmp, rethead);
}
return rethead;
}
static ACL
aclentryinit2aclentry(struct aclinit *init)
{
ACL retval;
retval = acalloc();
if (!retval) out_of_memory();
retval->acetype = init->acetype;
retval->atype = init->atype;
retval->rights = init->rights;
retval->principals = NULL;
if (init->prin_1)
retval->principals = tkappend(init->prin_1, retval->principals);
if (init->prin_2)
retval->principals = tkappend(init->prin_2, retval->principals);
if (init->prin_3)
retval->principals = tkappend(init->prin_3, retval->principals);
if (init->prin_4)
retval->principals = tkappend(init->prin_4, retval->principals);
if (init->prin_5)
retval->principals = tkappend(init->prin_5, retval->principals);
if (init->prin_6)
retval->principals = tkappend(init->prin_6, retval->principals);
if (init->prin_7)
retval->principals = tkappend(init->prin_8, retval->principals);
if (init->prin_9)
retval->principals = tkappend(init->prin_9, retval->principals);
if (init->prin_10)
retval->principals = tkappend(init->prin_10, retval->principals);
if (init->prin_11)
retval->principals = tkappend(init->prin_11, retval->principals);
if (init->prin_12)
retval->principals = tkappend(init->prin_12, retval->principals);
if (init->prin_13)
retval->principals = tkappend(init->prin_13, retval->principals);
if (init->prin_14)
retval->principals = tkappend(init->prin_14, retval->principals);
if (init->prin_15)
retval->principals = tkappend(init->prin_15, retval->principals);
if (init->prin_16)
retval->principals = tkappend(init->prin_16, retval->principals);
if (init->prin_17)
retval->principals = tkappend(init->prin_17, retval->principals);
if (init->prin_18)
retval->principals = tkappend(init->prin_18, retval->principals);
if (init->prin_19)
retval->principals = tkappend(init->prin_19, retval->principals);
if (init->prin_20)
retval->principals = tkappend(init->prin_20, retval->principals);
if (init->prin_21)
retval->principals = tkappend(init->prin_21, retval->principals);
if (init->prin_22)
retval->principals = tkappend(init->prin_22, retval->principals);
if (init->prin_23)
retval->principals = tkappend(init->prin_23, retval->principals);
if (init->prin_24)
retval->principals = tkappend(init->prin_24, retval->principals);
if (init->prin_25)
retval->principals = tkappend(init->prin_25, retval->principals);
if (init->prin_26)
retval->principals = tkappend(init->prin_26, retval->principals);
return retval;
}
/*
* srv_check_acl - check access control list
*
* SRV_CHECK_ACL checks an access control list to see if a particular
* user is authorized to perform a particular operation. It returns
* a positive number if the operation is authorized, and zero if
* not authorized. SRV_CHECK_ACL actually checks up to three access
* control lists. First, the access control list associated with
* a link is checked (if specified). If the operation would not
* be authorized, the secondary ACL may be checked if present, and
* depending on the type of ACL check specified in the flags field,
* to see if it applies to or overrides the individual entry. If sill
* not authorized, an override ACL is checked to see if the operation
* is performed.
*
* NOTE on negative rights: Negative rights apply within
* a particular access control list only. Thus, a negative
* entry in the link ACL can override other entries in the
* link ACL, but it will not prevent access if the user
* is authorized to perform the operation by the directory
* or override ACL's.
*/
int
srv_check_acl(ACL pacl, /* Primary ACL */
ACL sacl, /* Secondary ACL */
RREQ req, /* Request; used for client identification */
char *op, /* Operation */
int flags, /* Type of ACL check */
char *objid, /* hsoname of object to which ACL applies */
char *itemid) /* Name of item to be manipulated */
{
int answer = 0;
/* Now called from dirsrv */
#if 0
if(!initialized) initialize_defaults();
#endif
if(flags == SCA_LINK) {
if(!pacl) pacl = nulllink_acl;
if(!sacl) sacl = nulldir_acl;
answer = checkl_acl_r(pacl,sacl,req,op,ACL_NESTING,
SCA_LINK,objid,itemid);
if(!answer) answer = checkl_acl_r(sacl,sacl,req,op,ACL_NESTING,
SCA_DIRECTORY,objid,itemid);
}
else if(flags == SCA_LINKDIR) {
if(!pacl) pacl = nulllink_acl;
if(!sacl) sacl = nulldir_acl;
answer = checkl_acl_r(pacl,sacl,req,op,ACL_NESTING,
SCA_LINK,objid,itemid);
if(!answer) answer = checkl_acl_r(sacl,sacl,req,op,ACL_NESTING,
SCA_DIRECTORY,objid,itemid);
}
else if(flags == SCA_DIRECTORY) {
if(!pacl) pacl = nulldir_acl;
answer = checkl_acl_r(pacl,pacl,req,op,ACL_NESTING,
SCA_DIRECTORY,objid,itemid);
}
else if (flags == SCA_OBJECT) {
ACL cacl = NULL;
if(!pacl) pacl = nullobj_acl;
if(!sacl) {
if(objid && (cacl = get_container_acl(objid))) {
answer = checkl_acl_r(pacl,cacl,req,op,ACL_NESTING,
SCA_OBJECT,objid,itemid);
aclfree(cacl);
}
else answer = checkl_acl_r(pacl,nullcont_acl,req,op,ACL_NESTING,
SCA_OBJECT,objid,itemid);
}
else answer = checkl_acl_r(pacl,sacl,req,op,ACL_NESTING,SCA_OBJECT,
objid,itemid);
}
else if (flags == SCA_MISC) {
if(!pacl) pacl = maint_acl;
answer = checkl_acl_r(pacl,NULL,req,op,ACL_NESTING,
SCA_MISC,objid,itemid);
}
if(answer) return(answer);
/* Check to see if absolute override applies */
return(checkl_acl_r(override_acl,NULL,req,op,ACL_NESTING,
SCA_MISC, objid,itemid));
}
static int
checkl_acl_r(acl,sacl,req,op,depth,ld,objid,itemid)
ACL acl; /* Access control list */
ACL sacl; /* Secondary access control list */
char *op; /* Operation */
RREQ req; /* Client identification */
int depth; /* Maximum nesting */
int ld; /* 0 = link, 1 = dir, 2 = both, 4=misc */
char *objid; /* Object associated with ACL */
char *itemid; /* Name of item to manipulate */
{
int retval = 0; /* Would this entry authorize op */
int answer = 1; /* How to answer if match */
if(depth == 0) return(NOT_AUTHORIZED);
while(acl) {
retval = check_permissions(op,acl->rights,ld);
if(retval||((acl->rights==NULL)&&((acl->acetype == ACL_DEFAULT)
||(acl->acetype == ACL_SYSTEM)
||(acl->acetype == ACL_DIRECTORY)
||(acl->acetype == ACL_CONTAINER)
||(acl->acetype == ACL_IETF_AAC)))) {
if(retval == NEG_AUTHORIZED) answer = NOT_AUTHORIZED;
else answer = AUTHORIZED;
switch(acl->acetype) {
case ACL_NONE:
break;
case ACL_DEFAULT:
retval = checkl_acl_r(default_acl,sacl,req,op,depth-1,ld,objid,itemid);
if(retval) return(answer);
break;
case ACL_SYSTEM:
retval = checkl_acl_r(system_acl,sacl,req,op,depth-1,ld,objid,itemid);
if(retval) return(answer);
break;
case ACL_OWNER:
/* Check if user is the owner of the dirtectory */
#if 0
/* We need to find the owner of the file/directory */
/* for which this ACL applies and check whether it */
/* is the current principal. For now, we don't */
/* know the name of the file or directory. When */
/* the interface is changed so we do know it, we */
/* will check against the current host address and */
/* the TRSTHOST authentication type. Alternatively */
/* we will use an OBJECT-OWNER attribute from the */
/* object attribute list which will be in the form */
/* of an ACL entry, but without a rights field */
#endif
break;
case ACL_DIRECTORY:
if(ld == SCA_LINK) {
retval = checkl_acl_r(sacl,sacl,req,op,depth-1,
SCA_LINKDIR,objid,itemid);
if(retval) return(answer);
}
break;
case ACL_CONTAINER:
if(ld == SCA_OBJECT) {
retval = checkl_acl_r(sacl,sacl,req,op,depth-1,
SCA_CONTAINER,objid,itemid);
if(retval) return(answer);
}
break;
case ACL_ANY:
return(answer);
case ACL_AUTHENT:
if (acl->atype && strequal(acl->atype, "KERBEROS")) {
PAUTH pap; /* Iteration variable for PAUTH. */
TOKEN prin; /* principals */
/* Loop through all of the Kerberos authenticated
principals. (This is upward-compatible with future
versions of Kerberos that will allow one to be
registered as multiple principals simultaneously.)
*/
for (pap = req->auth_info; pap; pap = pap->next) {
if (pap->ainfo_type == PFSA_KERBEROS) {
for (prin = pap->principals; prin;
prin = prin->next) {
if (member(prin->token, acl->principals))
return answer;
}
}
}
}
else if (acl->atype && strequal(acl->atype, "P_PASSWORD")) {
PAUTH pap; /* Iteration variable for PAUTH. */
TOKEN prin; /* principals */
/* Loop through all of the principals. */
for (pap = req->auth_info; pap; pap = pap->next) {
if (pap->ainfo_type == PFSA_P_PASSWORD) {
for (prin = pap->principals; prin;
prin = prin->next) {
if (member(prin->token, acl->principals))
return answer;
}
}
}
}
break;
case ACL_LGROUP: /* Not yet implemented */
break;
case ACL_GROUP: /* Not yet implemented */
break;
case ACL_TRSTHOST: /* Check host and userid */
if (!check_prvport(req))
break;
/* DELIBERATE FALLTHROUGH */
case ACL_ASRTHOST: /* Check host and asserted userid */
{
PAUTH pap;
TOKEN prin; /* principals */
/* Loop through all of the asserted principals. */
for (pap = req->auth_info; pap; pap = pap->next) {
if (pap->ainfo_type == PFSA_UNAUTHENTICATED) {
for (prin = pap->principals; prin;
prin = prin->next) {
if (check_asserted_principal(prin->token,
acl->principals,
req->peer_addr))
return answer;
}
}
}
}
break;
case ACL_IETF_AAC:
/* This ACL entry type is not yet implemented */
break;
default: /* Not implemented */
break;
}
}
acl = acl->next;
}
return(NOT_AUTHORIZED);
}
/*
* check_permissions - Check if operation is authorized
*
* CHECK_PERMISIONS takes a string with letters representing
* the permissions required for the current opration, and
* a string listing operating authorized by the current ACL
* entry. It returns a 1 if the operation would be
* authorized by the current entry, a 0 if not, and a -1
* if the ACL entry would have authorized the operation,
* but began with a "-" indicating negative authorization.
*
* ARGS: op - String with operations to be performed
* p - Permissions from ACL entry
* ld - Whther ACL entry is for directory or link (or both)
*
* RETURNS: 1 if authorized
* 0 if not authorized
* -1 if negative authorization
*
* Protections
*
* The more common entry appears first if multiple rights allow an
* operation. The operation identifier appears second.
*
* Object File Directory Link* Meaning
* AB AB AB Aa Administer ACL
* VYAB VYAB VYAB VvAa View ACL
* - - L Ll List link
* Rg RG RQ RrQ Read link, get attribute or file
* Wu Ww WM WmM Modify attribute, data, links
* EiWu EeWw EIWM - Insert attributes links, append (extend)
* DzWu - DKWM DdKWMm Delete link or attribute
*
* The following will eventually be replaced by restricted forms of
* Administer (A or B).
*
* > > > ] Add rights
* < < < [ Remove rights
* ) ) ) - Add rights
* ( ( ( - Remove rights
*
* The following only appear on the server maintenance ACL
*
* S Restart server
* T Terminate server
* U Update system information
* P Administer passwords
* p Add new password entry
*
* A - sign in an ACL means that the specified rights are explicitly
* denied. In the table, it means not applicable.
*
* * A capital letter on a link ACL means that this right exists in the
* direcory ACL for the directory containing the link.
*
* ** When restrictions are supported, they can be used to restrict the
* specific attributes to which a right applies, or to restrict the
* interpretation of an ACL entry to only the Object, File, or Directory,
* or link.
*
* When a small letter is associated with a directory, it is the default
* used for those links in the directory which do not otherwise specify
* protections. The large letter for a directory indicates that the
* right applies to ALL entries in the directory, regardless of the ACLs
* associated with the individual link.
*
* These rights apply to the directory and individual links. The ability
* to read a link does not grant any rights to read the file that the
* link points to. Instead, it grants the right to read the binding
* of the link. The protection mechanisms for the objects themselves
* depend on the underlying access mechanism.
*
* The Administer right is required to change the ACL. "A" allows one
* to change the ACLs for the directory as a whole, as well as those
* for individual links. It does not, however, grant any rights to
* the object pointed to by those links (e.g. it doesn't allow one
* to change the permissions on subdirectories.
*
* List allows one to list an entry in a wildcarded search. Read allows
* one to learn the binding of a link. If one can read a link, but
* not list it, then it can only be seen when the user specifies the
* exact name of the link in a query.
*
* Modify allows one to change the binding of a link. It does not
* allow one to create a new link or delete an existing one. Insert
* or delete access are necessary for that.
*
* View allows one to view the contents of the ACL. Administer implies view.
* Add rights and remove rights, ><][)(, allow one to add or remove the
* other rights that are specified as part of the same ACL entry. It is
* a limited form of administer. The other rights included in the
* same ACL entry do not apply, but only restrict which rights may be
* added or removed. The add or remove indicators must appear in the
* first one or two positions in the rights field, and can not themselves
* be added or removed unless they also appear later in the rights field.
*
* If the permission string begins with a "-" and if the specified operation
* would otherwise be authorized, check_permissions returns -1 indicating
* that an applicable negative right has been found, and that the operation
* should be denied even if subsequent ACL entries authorizing it are found.
* If an ACL entry preceding this one has already authorized the operation,
* the operation will be performed.
*
* BUGS: For now, only the first character in ><][])( means add or
* delete the following rights, and all rights included in the
* entry including the first ><][)( may be added or deleted.
* Eventually, we will check the first two positions to see
* if adding and deleting is allowed, and the matching
* characters in those positions will be removed before
* checking subsequent characters.
*/
int
static check_permissions(op,p,ld)
char *op; /* Operation */
char *p; /* Permissions */
int ld; /* 0 =link, 1 =directory, 2=both, 4=misc */
{
char *tp = p;
int polarity = 1; /* -1 = neg authorization */
if(!p || !(*p)) return(NOT_AUTHORIZED);
if(*p == '-') polarity = -1;
/* Reject if ACL entry for insert or delete rights, but not operation */
if(index("><][)(",*p) && !index("><][",*op))
return(NOT_AUTHORIZED);
/* Insert or delete rights must be first in ACL permissions */
while(*(++tp)) if(index("><][)(",*tp)) return(NOT_AUTHORIZED);
while(*op) {
switch(*(op++)) {
case 'a':
if((ld != 1) && index(p,'a')) continue;
if((ld != 0) && index(p,'A')) continue;
else return(NOT_AUTHORIZED);
case 'A':
case 'B':
if((ld != 0) && index(p,'A')) continue;
if((ld != 0) && index(p,'B')) continue;
else return(NOT_AUTHORIZED);
case 'v':
if((ld != 1) && index(p,'v')) continue;
if((ld != 0) && index(p,'V')) continue;
if((ld != 1) && index(p,'a')) continue;
if((ld != 0) && index(p,'A')) continue;
else return(NOT_AUTHORIZED);
case 'V':
case 'Y':
if((ld != 0) && index(p,'V')) continue;
if((ld != 0) && index(p,'Y')) continue;
if((ld != 0) && index(p,'A')) continue;
if((ld != 0) && index(p,'B')) continue;
else return(NOT_AUTHORIZED);
case 'l':
if((ld != 1) && index(p,'l')) continue;
case 'L': /* and fall through */
if((ld != 0) && index(p,'L')) continue;
else return(NOT_AUTHORIZED);
case 'r':
if((ld != 1) && index(p,'r')) continue;
case 'R': /* and fall through */
case 'Q': /* and fall through */
if((ld != 0) && index(p,'R')) continue;
if((ld != 0) && index(p,'Q')) continue;
else return(NOT_AUTHORIZED);
case 'G':
if((ld != 0) && index(p,'G')) continue;
if((ld != 0) && index(p,'R')) continue;
else return(NOT_AUTHORIZED);
case 'g':
if((ld != 0) && index(p,'g')) continue;
if((ld != 0) && index(p,'R')) continue;
else return(NOT_AUTHORIZED);
case 'm':
if((ld != 1) && index(p,'m')) continue;
case 'M': /* and fall through */
if((ld != 0) && index(p,'M')) continue;
if((ld != 0) && index(p,'W')) continue;
else return(NOT_AUTHORIZED);
case 'w': /* and fall through */
if((ld != 0) && index(p,'w')) continue;
if((ld != 0) && index(p,'W')) continue;
else return(NOT_AUTHORIZED);
case 'u': /* and fall through */
if((ld != 0) && index(p,'u')) continue;
if((ld != 0) && index(p,'W')) continue;
else return(NOT_AUTHORIZED);
case 'I':
if((ld != 0) && index(p,'I')) continue;
if((ld != 0) && index(p,'E')) continue;
if((ld != 0) && index(p,'W')) continue;
if((ld != 0) && index(p,'M')) continue;
else return(NOT_AUTHORIZED);
case 'e':
if((ld != 0) && index(p,'e')) continue;
if((ld != 0) && index(p,'E')) continue;
if((ld != 0) && index(p,'W')) continue;
if((ld != 0) && index(p,'w')) continue;
else return(NOT_AUTHORIZED);
case 'i':
if((ld != 0) && index(p,'i')) continue;
if((ld != 0) && index(p,'E')) continue;
if((ld != 0) && index(p,'W')) continue;
if((ld != 0) && index(p,'u')) continue;
else return(NOT_AUTHORIZED);
case 'd':
if((ld != 1) && index(p,'d')) continue;
if((ld != 1) && index(p,'m')) continue;
case 'D': /* and fall through */
if((ld != 0) && index(p,'D')) continue;
if((ld != 0) && index(p,'K')) continue;
if((ld != 0) && index(p,'W')) continue;
if((ld != 0) && index(p,'M')) continue;
else return(NOT_AUTHORIZED);
case 'z': /* and fall through */
if((ld != 0) && index(p,'D')) continue;
if((ld != 0) && index(p,'z')) continue;
if((ld != 0) && index(p,'W')) continue;
if((ld != 0) && index(p,'u')) continue;
else return(NOT_AUTHORIZED);
case ']':
if((ld != 1) && index(p,']')) continue;
if((ld != 0) && index(p,'>')) continue;
else return(NOT_AUTHORIZED);
case '>':
if((ld != 0) && index(p,'>')) continue;
if((ld != 0) && index(p,')')) continue;
else return(NOT_AUTHORIZED);
case '[':
if((ld != 1) && index(p,'[')) continue;
if((ld != 0) && index(p,'<')) continue;
else return(NOT_AUTHORIZED);
case '<':
if((ld != 0) && index(p,'<')) continue;
if((ld != 0) && index(p,'(')) continue;
else return(NOT_AUTHORIZED);
/* Maintenance operations. */
case 'S':
if (index(p, 'S')) continue;
else return NOT_AUTHORIZED;
case 'T':
if (index(p, 'T')) continue;
else return NOT_AUTHORIZED;
case 'U':
if (index(p, 'U')) continue;
else return NOT_AUTHORIZED;
case 'P':
if (index(p, 'P')) continue;
else return NOT_AUTHORIZED;
case 'p':
if (index(p, 'p')) continue;
if (index(p, 'P')) continue;
else return NOT_AUTHORIZED;
default:
return(NOT_AUTHORIZED);
}
}
return(polarity);
}
#ifdef NOTDEF
/* Unused. Make this thread-safe before commenting it out. */
static char *inet_ntoa(a)
struct in_addr a;
{
static char astring[20];
#if BYTE_ORDER == BIG_ENDIAN
sprintf(astring,"%d.%d.%d.%d",(a.s_addr >> 24) & 0xff,
(a.s_addr >> 16) & 0xff,(a.s_addr >> 8) & 0xff,
a.s_addr & 0xff);
#else
sprintf(astring,"%d.%d.%d.%d", a.s_addr & 0xff,
(a.s_addr >> 8) & 0xff,(a.s_addr >> 16) & 0xff,
(a.s_addr >> 24) & 0xff);
#endif
return(astring);
}
#endif NOTDEF
/* Only used locally in a context where it returns static data overwritten by
each call. */
static char *
inet_def_local(char *s)
{
AUTOSTAT_CHARPP(adstringp);
static long myaddr = 0; /* look below to see how this is mutexed */
char intstring[10];
static long o[4]; /* look below to see how this is mutexed */
char *ads;
long *octet;
if (!*adstringp) *adstringp = stalloc(50); /* effectively, an array of size
50. */
if (!myaddr) {
p_th_mutex_lock(p_th_mutexPSRV_CHECK_ACL_INET_DEF_LOCAL);
/* Now that we have a mutex, check adstring again, since it might
have changed since we tested it. This tests whether another
initialization successfully completed since we called this. */
if (!myaddr) {
long local_myaddr = myaddress();
#if BYTE_ORDER == BIG_ENDIAN
o[0] = (local_myaddr >> 24) & 0xff;
o[1] = (local_myaddr >> 16) & 0xff;
o[2] = (local_myaddr >> 8) & 0xff;
o[3] = local_myaddr & 0xff;
#else
o[0] = local_myaddr & 0xff;
o[1] = (local_myaddr >> 8) & 0xff;
o[2] = (local_myaddr >> 16) & 0xff;
o[3] = (local_myaddr >> 24) & 0xff;
#endif
myaddr = local_myaddr; /* change done; commit. */
}
p_th_mutex_unlock(p_th_mutexPSRV_CHECK_ACL_INET_DEF_LOCAL);
}
octet = o;
ads = *adstringp;
while(*s && ((ads - *adstringp) < 40) ) {
switch(*s) {
case '.':
octet++;
*ads++ = *s;
break;
case '%':
qsprintf(intstring,sizeof intstring, "%d",*octet);
bcopy(intstring,ads,strlen(intstring));
ads += strlen(intstring);
break;
default:
*ads++ = *s;
break;
}
s++;
}
*ads++ = '\0';
return(*adstringp);
}
/* Are we logged into a privileged port? 1 if yes, zero if no. */
int
check_prvport(req)
RREQ req;
{
return PEER_PORT(req) <= IPPORT_RESERVED;
}
/*
* check_asserted_principal - check for membership in list of principals
* and check optional host ID. The principals have the format used by ASRTHOST
* and TRSTHOST.
*/
static int
check_asserted_principal(username,principals, hostaddr)
char username[];
struct in_addr hostaddr;
TOKEN principals;
{
for(; principals; principals = principals->next) {
char *host;
/* principal specified in the ACL entry. We copy it because we can't
modify the principals structure, since the principals structure
might contain strings that are in readonly memory. */
AUTOSTAT_CHARPP(aclprinp);
*aclprinp = stcopyr(principals->token, *aclprinp);
host = strchr(*aclprinp,'@');
if(host == NULL) {
if(wcmatch(username,*aclprinp)) return(TRUE);
else continue;
}
*(host++) = '\0';
if(!wcmatch(username,*aclprinp)) continue;
if(index("%123456789.",*host)) { /* Host address */
if(wcmatch(inet_ntoa(hostaddr),inet_def_local(host)))
return(TRUE);
continue;
}
else if(*host == '0') { /* Host address with leading 0 */
if(wcmatch(inet_ntoa(hostaddr),inet_def_local(host+1)))
return(TRUE);
continue;
}
else { /* Host name - not implemented */
continue;
}
}
return(FALSE);
}
ACL get_container_acl(char *path)
{
PFILE container;
ACL cont_acl = NULL;
ACL tacl = NULL;
ACL tacl2 = NULL;
char cpath[MAXPATHLEN];
char *slash;
strcpy(cpath,path);
slash = strrchr(cpath,'/');
if(slash) {
*slash = '\0';
container = pfalloc();
dsrfinfo(cpath,0,container);
cont_acl = container->oacl; container->oacl = NULL;
pffree(container);
tacl = cont_acl;
while(tacl) {
if(tacl->acetype == ACL_CONTAINER) {
tacl2 = tacl;
tacl = tacl->next;
EXTRACT_ITEM(tacl2,cont_acl);
acfree(tacl2);
}
else tacl = tacl->next;
}
return(cont_acl);
}
return(NULL);
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 1989, 1990, 1991 by the University of Washington
* Copyright (c) 1992 by the University of Southern California
*
* For copying and distribution information, please see the files
* <uw-copyright.h> and <usc-copyr.h>.
*/
#include <uw-copyright.h>
#include <usc-copyr.h>
#include <sys/param.h>
#include <netdb.h>
#include <string.h>
#include <pfs.h>
#include <pmachine.h>
extern char *hostname;
/*
* check_nfs - Check whether file is available by NFS
*
* CHECK_NFS takes the name of a file and a network address.
* It returns the name of the filesystem (prefix of the file)
* which may be exported by NFS to the client. The prefix is
* followed by a space and the suffix. This is the form of the
* paramters to be returned for access by NFS.
*
* ARGS: path - Name of file to be retrieved
* client - IP address of the client
*
* RETURNS: A newly allocated sequence containing NFS access method for that
* file, or NULL if the file is not available to the client by NFS.
*
* NOTES: The returned memory must be freed by the caller.
*
* BUGS: The procedure should check the NFS exports file. Right now
* it only guesses at the prefix and check to make sure the
* request is from the local subnet. It also incorrectly assumes that
* the file must be exported by the local host. Ugh.
*/
#ifdef PFS_THREADS
extern p_th_mutex p_th_mutexPSRV_CHECK_NFS_MYADDR;
#endif
TOKEN
check_nfs(char *path, long client)
{
TOKEN nfs_am = NULL;
static long myaddr = 0; /* MUTEXED below */
char prefix[MAXPATHLEN];
char *suffix;
char *slash;
/* First time called, find out hostname and remember it */
if(!myaddr) {
#ifdef PFS_THREADS
p_th_mutex_lock(p_th_mutexPSRV_CHECK_NFS_MYADDR);
if (!myaddr) { /* check again */
#endif
myaddr = myaddress();
#ifdef PFS_THREADS
}
p_th_mutex_unlock(p_th_mutexPSRV_CHECK_NFS_MYADDR);
#endif
}
#if BYTE_ORDER == BIG_ENDIAN
if((myaddr ^ client) & 0xffffff00) return(NULL);
#else
if((myaddr ^ client) & 0x00ffffff) return(NULL);
#endif
strcpy(prefix,path);
slash = strchr(prefix+1,'/');
if(slash) {*slash = '\0'; suffix = slash + 1;}
else return(NULL);
nfs_am = tkappend("NFS", nfs_am);
nfs_am = tkappend("INTERNET-D", nfs_am);
nfs_am = tkappend(hostname, nfs_am);
nfs_am = tkappend("ASCII", nfs_am);
nfs_am = tkappend(suffix, nfs_am);
nfs_am = tkappend(prefix, nfs_am);
return nfs_am;
}

View File

@@ -0,0 +1,112 @@
/* Checks Kerberos authentication, and returns authenticated client name.
Returns non-zero on error. */
/* Copyright (c) 1992 by the University of Southern California.
* For copying and distribution information, please see the file
* <usc-copyr.h>.
*/
/* Author: Prasad Upasani (prasad@isi.edu)
* Modifications by swa@isi.edu.
*/
#include <psite.h> /* must precede pfs.h for PSRV_KERBEROS
compilation option. */
#include <pfs.h>
#include <psrv.h> /* prototypes this function */
#include <pserver.h>
#ifdef PSRV_KERBEROS /* Only compile this file if we are using
Kerberos, since it refers to files in the
Kerberos libraries. */
/* This is currently actually used only by the server. It is in libpsrv. */
#include <stdio.h>
#include <krb5/krb5.h>
#include <netinet/in.h>
/* Returns 0 (PSUCCESS) on success; any other value on failure (should make
this be PFAILURE, just for consistency. */
int
check_krb_auth(char *auth, struct sockaddr_in client,
char **ret_client_namep /* Stores the name to be returned.
Either NULL or memory previously
allocated with stalloc() or
stcopy(). */)
{
krb5_data inbuf;
krb5_principal server;
krb5_address *sender_addr;
char service_name[255], hostname[255];
int retval;
krb5_address client_addr;
krb5_tkt_authent *authdat;
char *client_name;
char *srvtab = NULL; /* NULL means to use the default Kerberos srvtab */
#ifdef KERBEROS_SRVTAB
int srvtabsiz;
#endif
/* Create a server principal structure. */
if (retval = gethostname(hostname, sizeof(hostname)))
RETURNPFAILURE;
strcpy(service_name, KERBEROS_SERVICE);
strcat(service_name, "/");
strcat(service_name, hostname);
if (krb5_parse_name(service_name, &server))
RETURNPFAILURE;
/* Put auth data into a krb5_data structure. */
inbuf.data = stalloc(AUTHENTICATOR_SZ); /* starting value */
again:
if (inbuf.data == NULL) out_of_memory();
retval = bindecode(auth, inbuf.data, p__bstsize(inbuf.data));
if (retval > p__bstsize(inbuf.data)) {
stfree(inbuf.data);
inbuf.data = stalloc(retval);
goto again;
}
/* Successfully decoded. */
inbuf.length = retval;
/* Put client address in a krb5_address structure. */
client_addr.addrtype = client.sin_family;
client_addr.length = sizeof(client.sin_addr);
client_addr.contents = (krb5_octet *) &client.sin_addr;
#ifdef KERBEROS_SRVTAB
srvtab =
stalloc(srvtabsiz = sizeof("FILE:") + sizeof(KERBEROS_SRVTAB) + 1);
assert(qsprintf(srvtab, srvtabsiz, "FILE:%s", KERBEROS_SRVTAB) <= srvtabsiz);
#endif
/* Check authentication. */
retval = krb5_rd_req(&inbuf,
server,
&client_addr,
srvtab,
0, 0, 0,
&authdat);
stfree(inbuf.data);
#ifdef KERBEROS_SRVTAB
stfree(srvtab);
#endif
if (retval) RETURNPFAILURE; /* Authentication failed. */
/* Get client name. */
/* client_name points to memory allocated with malloc() by
krb5_unparse_name(). The caller is supposed to free it. */
if (retval = krb5_unparse_name(authdat->authenticator->client,
&client_name))
RETURNPFAILURE;
*ret_client_namep = stcopyr(client_name, *ret_client_namep);
free(client_name);
return PSUCCESS;
}
#endif /* PSRV_KERBEROS */

View File

@@ -0,0 +1,306 @@
/*
* 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 */

845
prospero/lib/psrv/dsdir.c Normal file
View File

@@ -0,0 +1,845 @@
/*
* Copyright (c) 1991-1994 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
#include <usc-license.h>
#include <sys/param.h>
#include <sys/stat.h> /* sys/types.h included already */
/* sys/dir.h on SCO_UNIX doesnt define DIR */
#include <pmachine.h>
#if defined(SCOUNIX) || defined(SOLARIS) || !defined(USE_SYS_DIR_H)
#if defined(PFS_THREADS_SOLARIS) && !defined(_REENTRANT)
#define _REENTRANT /* needed to get prototype for readdir_r() */
#endif /* defined(PFS_THREADS_SOLARIS) && !defined(_REENTRANT) */
#include <dirent.h>
#else
#include <sys/dir.h>
#endif
#if defined(SOLARIS) /* seems true on pand05.prod.aol.net */
#define SOLARIS_GCC_BROKEN_LIMITS_H
#endif
#include <stdio.h>
#include <sgtty.h>
#include <string.h>
#include <pserver.h>
#include <ardp.h>
#include <pfs.h>
#include <plog.h>
#include <pprot.h>
#include <perrno.h>
#include <pmachine.h>
#include <pparse.h>
#include <psrv.h> /* For dsrfinfo etc */
#include <posix_signal.h> /* Needed on SOLARIS for sigset_t etc */
#include <mitra_macros.h> /* For L2 */
#define DIR_VNO 5 /* version # of the directory format. */
extern char root[];
extern char shadow[];
extern char dirshadow[];
extern char dircont[];
#define TMP_DIRNAME_SUFFIX ".TMP"
extern char pfsdat[];
extern char aftpdir[];
extern char hostname[];
extern char hostwport[];
extern char *acltypes[];
static int indsrdir_v5(INPUT in, char vfs_dirname[], VDIR dir, VLINK ul);
static int reload_native_cache(char native_dirname[], VDIR dir);
static int check_vfs_dir_forwarding(VDIR dir, char name[], long magic);
static size_t canonicalize_prefix(char *native_name, char canon_buf[],
size_t canon_bufsiz);
size_t nativize_prefix(char *hsoname, char native_buf[], size_t native_bufsiz);
/*
Policy for caching native links:
1) If a native directory is converted to NONATIVE (The only case in which
this happens in the current code is if a native link was
deleted in it), then it's now entirely virtual, and all native links are
saved.
2) If the compilation option PSRV_CACHE_NATIVE is set, then
all native links and their attributes are cached. The cache is reloaded
whenever the native MTIME has changed. The CACHED attributes on a link will
also be reloaded whenever an UPDATE protocol message is sent (that mechanism
is not handled in dsdir). If no special compilation option is defined,
NATIVE-ONLY directories are guaranteed to be not cached unless at least one
link attribute is set on a link in that directory.
3) In any case, a entry will be written out for a directory if any attribute
is set (via EDIT-LINK-INFO) on an entry in that directory. NATIVE links with
LINK attributes on them WILL be written out, but other NATIVE links in the
directory may or may not be.
4) For the current implementation, all directories that are not NATIVE-ONLY
are always written out and NATIVE-ONLY directories with links with non-OBJECT
and non-CACHED attributes are always written out.
*/
/* Thoughts on this:
This will break if we start caching partial attribute reads. Therefore, the
solution for THAT is to have a new attribute value type called UNSET. This
will always be CACHED and means that the corresponding OBJECT attribute is
UNSET and therefore need not be verified. This can become a part of the
protocol.
We'll also still have the problem of partially-cached reads not containing
all values. E.g.: checking of INTRINSIC+ should probably be disabled, no?
So, CONTENTS is special. So perhaps a special tag on the cached data saying
whether it contains all INTRINSIC attributes. Also, a test whether a
particular attribute is INTRINSIC+ or just INTRINSIC.
A quicker solution is not to cache partial attribute reads.
*/
/*
* New policy: the PFSDAT directory must be NONATIVE. This is enforced.
* Fixes some old bugs.
*/
/*
* dsrdir - Read the contents of a directory from disk
*
* DSRDIR is used by the directory server to read the contents of
* a directory off disk. It takes the host specific part of the system
* level name of the directory as an argument, and a directory structure
* which it fills in.
* If the directory is forwarded, it returns DSRFINFO_FORWARDED.
* On error, it returns an error code and logs the circumstances to plog().
* It may also return a warning code.
*
* dsrdir() is frequently called to expand union links. Therefore,
* it must be careful about caching. */
int
dsrdir(hsoname,magic,dir,ul,flags)
char *hsoname; /* hsoname */
int magic; /* magic # specified in DIRECTORY command */
VDIR dir; /* dir to fill in */
VLINK ul; /* Pointer to the vlink currently being expanded */
/* used for location to insert new union links */
int flags; /* DSRD_ATTRIBUTES = get attributes for files */
/* Or DSRD_VERIFY_DIR -- see psrv.h */
{
FILE *vfs_dir;
char vfs_dirname[MAXPATHLEN]; /* name of .directory#contents file */
char native_dirname[MAXPATHLEN]; /* name of physical directory
corresponding to 'hsoname'. Only
differs from 'hsoname' if "AFTP" or
other special prefix in use. */
int tmp;
int vfs_dir_problem = 0; /* 1 if failure while reading VFS dir. */
time_t native_dir_mtime; /* mtime of native dir. */
int return_value = DSRDIR_NOT_A_DIRECTORY;
int pfsdatlen = strlen(pfsdat);
nativize_prefix(hsoname, native_dirname, sizeof native_dirname);
strcpy(vfs_dirname,shadow);
strcat(vfs_dirname,native_dirname);
strcat(vfs_dirname,"/");
strcat(vfs_dirname,dircont);
/* vfs_dirname is now the name of a file which, if it exists, means we are
guaranteed that the virtual directory exists. */
/* native_dirname is the name of a local UNIX directory which, if it
exists, will be read to produce a virtual directory. */
/* Special case code for common case of verifying */
if (flags & DSRD_VERIFY_DIR) {
if (is_file(vfs_dirname) || is_dir(native_dirname))
return PSUCCESS; /* VERIFIED the directory exists */
else
return PFAILURE;
}
dir->version = -1;
dir->magic_no = 0;
dir->inc_native = VDIN_INCLREAL; /* Include native if can't read */
dir->f_info = NULL;
dir->dacl = NULL;
/* XXX This should no longer be necessary. */
if(ul == NULL) { /* Don't clear links if expanding */
dir->links = NULL;
dir->ulinks = NULL;
}
/* Check whether cacheing will be ok. */
/* Special code in dump_links to handle ULINK_PLACEHOLDER */
if (!dir->links &&
(!dir->ulinks ||
!dir->ulinks->next && dir->ulinks->expanded == ULINK_PLACEHOLDER))
dir->flags |= VDIR_FIRST_READ;
else
dir->flags &= ~VDIR_FIRST_READ;
/* NOTE: A temporary inefficient directory format is */
/* in use. It will be changed. */
/* Read the contents of the VFS directory */
if((vfs_dir = locked_fopen(vfs_dirname,"r")) != NULL) {
INPUT_ST in_st;
INPUT in = &in_st;
if(tmp = wholefiletoin(vfs_dir, in)) {
locked_fclose_A(vfs_dir, vfs_dirname, TRUE);
plog(L_DIR_ERR,NOREQ,"%s",p_err_string);
return tmp;
}
if (ferror(vfs_dir)) vfs_dir_problem++;
if (locked_fclose_A(vfs_dir, vfs_dirname, TRUE)) vfs_dir_problem++;
VLDEBUGBEGIN;
return_value = indsrdir_v5(in, vfs_dirname, dir, ul);
VLDEBUGDIR(dir);
VLDEBUGEND;
/* What it means when indsrdir_v5 returns an error is not fully
clearly defined. */
if (return_value) vfs_dir_problem++;
} else /* Note that this directory is entirely native */
(dir->inc_native = VDIN_ONLYREAL);
/* (Re)load the contents of the native directory into the current cached
listing if cache is out of date or not present. */
/* This comment is from MITRA and I disavow it. --swa, 5/17/94 */
/* mitra: I havent corrected this behaviour for VDIN_PSEUDO yet
behaviour if their is a real directory is unpredictable */
if(dir->inc_native != VDIN_NONATIVE &&
(native_dir_mtime = mtime(native_dirname)) > dir->native_mtime) {
/* Report an error if we couldn't read the native directory. */
return_value = reload_native_cache(native_dirname, dir);
if (!return_value && !vfs_dir_problem
&& (dir->flags & VDIR_FIRST_READ)) {
/* XXX Need to set a don't-ever-write flag if there are problems so
that we know we can't support updates to this directory. */
/* if we successfully reloaded the cache */
/* update mod time. Use a value of mtime guaranteed to be before
reload_native_cache() started reading. */
dir->native_mtime = native_dir_mtime;
#ifndef PSRV_CACHE_NATIVE /* don't bother writing out changes if not
cacheing. */
if (dir->inc_native != VDIN_ONLYREAL)
#endif
/* Write out the changes. Failure to write out the updated
cache is not an error, but does yield a warning. */
if (tmp = dswdir(hsoname, dir)) {
p_warn_string = qsprintf_stcopyr(p_warn_string,
"Failed to update native cache for directory %'s:\
Prospero error %d", hsoname, tmp);
}
}
}
/* Handle directory forwarding. */
if((return_value != PSUCCESS) || (dir->magic_no != magic))
if (check_vfs_dir_forwarding(dir, hsoname, magic)
== DSRFINFO_FORWARDED)
return DSRFINFO_FORWARDED;
/* Directories in the pfsdat area must be NONATIVE */
if (strnequal(hsoname, pfsdat, pfsdatlen)
&& (hsoname[pfsdatlen] == '/' || hsoname[pfsdatlen] == '\0'))
dir->inc_native = VDIN_NONATIVE;
return(return_value);
}
/* Returns PSUCCESS if no forwarding, DSRFINFO_FORWARDING if forwarding
occurred. This is only called if the directory's magic number has a
mismatch. */
static int
check_vfs_dir_forwarding(VDIR dir, char hsoname[], long magic)
{
PFILE dfi = pfalloc();
int tmp = dsrfinfo(hsoname,magic,dfi);
if(tmp == DSRFINFO_FORWARDED) {
dir->f_info = dfi;
return(DSRFINFO_FORWARDED);
}
/* This bit of code may not be necessary. Anyway, this stuff is
getting replaced soon. --swa@isi.edu */
else if((dir->magic_no < 0) && dfi->forward) {
dir->f_info = dfi;
return(DSRFINFO_FORWARDED);
}
pffree(dfi);
return PSUCCESS;
}
/* Returns PFAILURE if it attempts to read a malformed directory;
PSUCCESS if all went well. */
static
int
indsrdir_v5(INPUT in, char vfs_dirname[], VDIR dir, VLINK ul)
{
char *command, *next_word;
char include_native[30];
char *cp; /* dummy pointer */
VLINK cur_link = NULL; /* set this when we see a link. */
int seen_version = 0; /* seen directory format version #? */
while(in_nextline(in)) {
char t_timestring[30];
if(in_line(in, &command, &next_word)) {
plog(L_DATA_FRM_ERR, NOREQ, "Couldn't read line from %s: %s",
vfs_dirname, p_err_string);
RETURNPFAILURE;
}
if (qsscanf(command, "VERSION %d %r", &(dir->version), &cp) == 1) {
if (dir->version != DIR_VNO) {
plog(L_DATA_FRM_ERR, NOREQ,
"Bad directory info format: %s: Encountered VERSION %d; \
dirsrv can only interpret version %d", vfs_dirname, dir->version, DIR_VNO);
RETURNPFAILURE;
}
seen_version++;
continue;
}
if (!seen_version) {
plog(L_DATA_FRM_ERR, NOREQ,
"Bad directory info format: %s: VERSION line not found; must \
appear at the start of the file.", vfs_dirname);
RETURNPFAILURE;
}
if (qsscanf(command, "MAGIC-NUMBER %d %r", &(dir->magic_no), &cp) == 1)
continue;
if (qsscanf(command, "INCLUDE-NATIVE %!!s %r",
include_native, sizeof include_native, &cp) == 1) {
if(strequal(include_native, "INCLNATIVE"))
dir->inc_native = VDIN_INCLNATIVE;
else if (strequal(include_native, "INCLREAL"))
dir->inc_native = VDIN_INCLREAL;
else if (strequal(include_native, "NONATIVE"))
dir->inc_native = VDIN_NONATIVE;
else if (strequal(include_native, "PSEUDO"))
dir->inc_native = VDIN_PSEUDO;
else {
plog(L_DATA_FRM_ERR, NOREQ,
"Bad directory info format %s: %s", vfs_dirname, command);
RETURNPFAILURE;
}
continue;
}
if (qsscanf(command, "NATIVE-MTIME %!!s %r",
t_timestring, sizeof t_timestring, &cp) == 1) {
dir->native_mtime = asntotime(t_timestring);
continue;
}
if (qsscanf(command, "ACL %r", &cp) == 1) {
if (cur_link) {
if(in_ge1_acl(in, command, next_word, &cur_link->acl)) {
plog(L_DATA_FRM_ERR, NOREQ,
"Bad directory info format %s: %s",
vfs_dirname, p_err_string);
RETURNPFAILURE;
}
} else {
if(in_ge1_acl(in, command, next_word, &dir->dacl)) {
plog(L_DATA_FRM_ERR, NOREQ,
"Bad directory info format %s: %s",
vfs_dirname, p_err_string);
RETURNPFAILURE;
}
}
continue;
}
/* in_link() will automatically call in_atrs. */
if (qsscanf(command, "LINK %r", &next_word) == 1) {
if(in_link(in, command, next_word, 0, &cur_link,
(TOKEN *) NULL)) {
plog(L_DATA_FRM_ERR, NOREQ,
"Bad directory info format %s: %s",
vfs_dirname, p_err_string);
RETURNPFAILURE;
}
/* if union link without UL variable set, then vl_insert will
insert it at the end of the list of union links. */
/* This call to ul_insert() makes sure that, *if*
list() is in the process of expanding union links, any new
union links are inserted in the right position (i.e., right
after the link we're currently expanding). This makes sure
that nested union links are expanded in the proper order,
whereas calling vl_insert() would instead mean that the
new union link CUR_LINK was stuck at the end of the
directory's list of union links; this would be wrong.
Also, ul_insert() checks for conflicts if given an insertion
positon. */
if(ul && cur_link->linktype == 'U') {
int tmp = ul_insert(cur_link,dir,ul);
if(!tmp) ul = cur_link; /* A subsequent identical link in this
directory won't supersede this one.
*/
} else {
/* vl_insert(cur_link, dir, VLI_ALLOW_CONF); */
/* this is an experiment in efficiency. */
vl_insert(cur_link, dir, VLI_NOSORT);
}
/* By this point cur_link should be inserted so dont free */
/* If it's a native link, then set the flags appropriately. */
if (cur_link->linktype == 'n') {
cur_link->linktype = 'I';
cur_link->flags |= VLINK_NATIVE;
} else if (cur_link->linktype == 'N') {
cur_link->linktype = 'L';
cur_link->flags |= VLINK_NATIVE;
}
continue;
}
/* Gee, nothing seems to match. Guess it must be an error. */
plog(L_DATA_FRM_ERR, NOREQ, "Bad directory info format %s: %s",
vfs_dirname, command);
RETURNPFAILURE;
}
return PSUCCESS;
}
/*
* dswdir - Write directory contents to disk
*
* On success, returns PSUCCESS. On error, returns an error code but does
* not set p_err_string.
*
* The contents of the
* Any OBJECT attributes to be written will be automatically downgraded to
* CACHED.
* Any INTRINSIC namespace attributes will not be written.
*/
int
dswdir(char *name,VDIR dir)
{
char vfs_dirname[MAXPATHLEN];
char tmp_vfs_dirname[MAXPATHLEN];
FILE *vfs_dir;
int retval;
/* if a VFS directory, then create it if necessary */
if(strnequal(pfsdat,name,strlen(pfsdat)))
if(mkdirs(name)) RETURNPFAILURE;
/* Determine name of shadow */
strcpy(vfs_dirname,shadow);
#if 1
nativize_prefix(name, vfs_dirname + strlen(shadow),
sizeof vfs_dirname - strlen(shadow));
#else
if((*name != '/') && *aftpdir && (strncmp(name,"AFTP",4) == 0)) {
/* Special file name */
strcat(vfs_dirname,aftpdir);
strcat(vfs_dirname,name+4);
}
else strcat(vfs_dirname,name);
#endif
/* Create the shadow directory if necessary */
if(mkdirs(vfs_dirname)) RETURNPFAILURE;
/* Determine name of directory contents */
strcat(vfs_dirname,"/");
strcat(vfs_dirname,dircont);
/* NOTE: A temporary inefficient directory format is */
/* in use. For this reason, the code supporting it */
/* is also interim code, and does not do any checking */
/* to make sure that the directory actually follows */
/* the format. This, a munged directory will result */
/* in unpredictable results. */
/* A name to write a temporary directory to. We write to a temporary
file and then rename it after it's been successfully written. We do
this so that we're guaranteed that if the disk fills up we don't lose
any data. */
if(qsprintf(tmp_vfs_dirname, sizeof tmp_vfs_dirname, "%s%s",
vfs_dirname, TMP_DIRNAME_SUFFIX) > sizeof tmp_vfs_dirname)
RETURNPFAILURE;
/* Write the contents of the VFS directory */
filelock_obtain(vfs_dirname,FALSE); /* Make sure can write original */
if((vfs_dir = locked_fopen(tmp_vfs_dirname,"w")) == NULL) {
filelock_release(vfs_dirname,FALSE);
return(PFAILURE);
}
fdswdir_v5(vfs_dir, dir);
retval = locked_fclose_and_rename(vfs_dir, tmp_vfs_dirname,
vfs_dirname,FALSE);
return(retval);
}
static void dump_links(OUTPUT out, VLINK cur_link);
/* Actually returns no useful return value. We check for failures using
ferror(). */
int fdswdir_v5(FILE *vfs_dir, VDIR dir)
{
OUTPUT_ST out_st;
OUTPUT out = &out_st;
VLINK vl;
filetoout(vfs_dir, out);
qoprintf(out, "VERSION %d\n", DIR_VNO);
if (dir->magic_no)
qoprintf(out, "MAGIC-NUMBER %d\n", dir->magic_no);
qoprintf(out, "INCLUDE-NATIVE ");
if(dir->inc_native == VDIN_INCLREAL || dir->inc_native == VDIN_ONLYREAL) {
qoprintf(out,"INCLREAL\n");
} else if(dir->inc_native == VDIN_INCLNATIVE) {
qoprintf(out,"INCLNATIVE\n");
} else if (dir->inc_native == VDIN_NONATIVE) {
qoprintf(out,"NONATIVE\n");
/* If directory is not native, shouldn't be any links which are NATIVE
*/
for (vl = dir->links; vl; vl = vl->next) {
vl->flags &= ~VLINK_NATIVE;
}
} else if (dir->inc_native == VDIN_PSEUDO) {
qoprintf(out,"PSEUDO\n");
} else
internal_error("unknown value of dir->inc_native");
if (dir->native_mtime && dir->inc_native != VDIN_NONATIVE) {
char *cp = NULL;
qoprintf(out, "NATIVE-MTIME %s\n",
cp = p_timetoasn_stcopyr(dir->native_mtime, cp));
stfree(cp);
}
/* print out the directory ACL. */
out_acl(out, dir->dacl);
dump_links(out, dir->links);
dump_links(out, dir->ulinks);
return PSUCCESS;
}
static void
dump_links(OUTPUT out, VLINK cur_link)
{
for (; cur_link; cur_link = cur_link->next) {
PATTRIB ca;
FILTER cur_fil;
/* Special case for ULINK_PLACEHOLDER. */
if (cur_link->expanded == ULINK_PLACEHOLDER) continue;
/* don't output native links to directory unless we just converted
it to NONATIVE, or unless caching is enabled for the native
directory, or unless they have attributes beyond the OBJECT ones. */
if (cur_link->flags & VLINK_NATIVE) {
cur_link->linktype = cur_link->linktype == 'I' ? 'n' : 'N';
}
qoprintf(out, "LINK ");
out_link(out, cur_link, 0, (TOKEN) NULL);
for (ca = cur_link->lattrib; ca; ca = ca->next) {
if (ca->nature != ATR_NATURE_INTRINSIC) {
if (ca->precedence == ATR_PREC_OBJECT)
ca->precedence = ATR_PREC_CACHED;
out_atr(out, ca, 0);
}
}
for (cur_fil = cur_link->filters; cur_fil; cur_fil = cur_fil->next) {
qoprintf(out, "ATTRIBUTE LINK FIELD FILTER FILTER ");
out_filter(out, cur_fil, 0);
}
out_acl(out, cur_link->acl);
if (cur_link->flags & VLINK_NATIVE) {
cur_link->linktype = cur_link->linktype == 'N' ? 'L' : 'I';
}
}
}
static VLINK read_native_dir(char native_dirname[], int inc_native_flag,
int read_attributes, int read_basetype);
static void merge_native(VLINK links, VDIR dir);
/* PSUCCESS if all went well; anything else if problems. */
static int
reload_native_cache(char native_dirname[], VDIR dir)
{
VLINK links = read_native_dir(native_dirname, dir->inc_native, 1, 1);
if (!links & perrno) return perrno;
merge_native(links, dir); /* can't fail */
return PSUCCESS; /* done! */
}
static void replace_cached(PATTRIB *nativeatlp, PATTRIB *vdiratlp);
/* Merge the native directory listing with the links read in from disk (if
ANY!). Free the unused LINKS. */
static void
merge_native(VLINK links, VDIR dir)
{
register VLINK curl, nxtl; /* do a for loop with CURrent and NeXT link
references since we may delete the current
link. */
/* Optimize a common case. This will be the case for every directory that
is pure VDIN_ONLYREAL */
if (!dir->links) {
dir->links = links;
return;
}
/* Each native link we confirm in DIR is tagged as CONFIRMED. */
for (curl = links, nxtl = curl ? curl->next : NULL;
curl;
curl = nxtl, nxtl = curl ? curl->next : NULL) {
VLINK vl;
/* Search in the existing directory for a VLINK that matches CURL */
for (vl = dir->links; vl; vl = vl->next) {
if (!(vl->flags & VLINK_CONFIRMED) /* only do ones from this
directory */
&& (vl->flags & VLINK_NATIVE) && vl_equal(curl, vl)) {
/* match found. Update any CACHED attributes on the link in
the directory from those in the native link. Note that
vl_equal() ignores the L/I LINKTYPE distinction. */
vl->flags |= VLINK_CONFIRMED;
replace_cached(&curl->lattrib, &vl->lattrib);
EXTRACT_ITEM(curl, links);
vlfree(curl);
goto next_native; /* on to the next native link. */
}
}
/* No match found for CURL. Plop it on the list. */
EXTRACT_ITEM(curl, links); /* so we don't munge pointers in the list
links. (This was a PERNICIOUS bug). */
APPEND_ITEM(curl, dir->links);
curl->flags |= VLINK_CONFIRMED | VLINK_NATIVE;
next_native:
}
/* Remove any NATIVE links that are not CONFIRMED */
/* We do not again use VLINK_CONFIRMED. Don't bother turning it off on the
links, since that would just be more expensive. */
for (curl = dir->links, nxtl = L2(curl,next);
curl;
curl = nxtl, nxtl = L2(curl,next)) {
if ((curl->flags & VLINK_NATIVE) && !(curl->flags & VLINK_CONFIRMED)) {
EXTRACT_ITEM(curl, dir->links);
vlfree(curl);
}
}
}
/* Replace all the CACHED and OBJECT attributes on VLATL with all OBJECT
attributes from the list on NATIVEATLP. Make sure that *nativeatlp does not
point to memory that we don't want to be freed. */
static void
replace_cached(PATTRIB *nativeatlp, PATTRIB *vlatlp)
{
PATTRIB ca, ca_temp;
/* Flush all CACHED attributes on VLATL */
for (ca = *vlatlp; ca; ca = ca_temp) {
ca_temp = ca->next;
if (ca->precedence == ATR_PREC_CACHED
|| ca->precedence == ATR_PREC_OBJECT) {
EXTRACT_ITEM(ca, *vlatlp);
atfree(ca);
}
}
/* Put the OBJECT attributes on the VLATL. They will be sent out as
OBJECT attributes. Code in dswdir() converts them to CACHED attributes
upon write. */
/* Future efficiency speedup: Replace this loop with the CONCATENATE_LISTS
macro. */
CONCATENATE_LISTS(*vlatlp, *nativeatlp);
/* *nativeatlp will automatically be set to NULL by the CONCATENATE_LISTS
macro. */
}
#include <limits.h> /* for _POSIX_PATH_MAX for readdir_result. */
#ifndef SOLARIS_GCC_BROKEN_LIMITS_H
#include <limits.h> /* for _POSIX_PATH_MAX for readdir_result. */
#else
#ifndef _POSIX_PATH_MAX
#undef _LIMITS_H
#include "/usr/include/limits.h"
/* XXX why on earth is this not defining _POSIX_PATH_MAX? At any rate,
pick a really large number that will certainly work well enough for now. */
#ifndef _POSIX_PATH_MAX
#define _POSIX_PATH_MAX 2048
#endif
#endif /* not _POSIX_PATH_MAX */
#endif /* SOLARIS_GCC_BROKEN_LIMITS_H */
/* Return a linked list of files with the VLINK_NATIVE flag set on them. */
/* The flags are both always set for now. They will be useful later if various
degrees of #FAST are specified. */
/* Error reporting: return NULL and set perrno. */
static VLINK
read_native_dir(char native_dirname[],
int inc_native_flag,
int read_attributes, /* implies read_basetype. */
int read_basetype) /* make sure basetype is correct in
listing */
{
DIR *dirp;
struct dirent *dp;
#ifdef PFS_THREADS
struct {
struct dirent a;
char b[_POSIX_PATH_MAX];
} readdir_result_st;
struct dirent *readdir_result = (struct dirent *) &readdir_result_st;
#endif
char *slash;
char vl_hsoname[MAXPATHLEN];
VLINK retval = NULL; /* list of links to return. */
VLINK cur_link;
int tmp;
if(is_dir(native_dirname) != 1) {
perrno = DSRDIR_NOT_A_DIRECTORY;
return NULL;
}
if((dirp = opendir(native_dirname)) == NULL) {
perrno = PFAILURE;
p_err_string = qsprintf_stcopyr(p_err_string,"%s",unixerrstr());
return NULL;
}
#ifdef PFS_THREADS
for (dp = readdir_r(dirp, readdir_result); dp != NULL;
dp = readdir_r(dirp, readdir_result)) {
#else /* PFS_THREADS */
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
#endif /* PFS_THREADS */
canonicalize_prefix(native_dirname, vl_hsoname, sizeof vl_hsoname);
/* We must special case unix concept of . and .. */
/* if we want to eliminate useless parts of path */
/* If the filename is "..", then */
if(strequal(dp->d_name,"..")) {
#ifdef NODOTDOT
continue;
#else
if(inc_native_flag == VDIN_INCLREAL ||
inc_native_flag == VDIN_ONLYREAL) continue;
slash = rindex(vl_hsoname,'/');
if(slash) *slash = '\0';
else strcpy(vl_hsoname,"/");
if(!(*vl_hsoname)) strcpy(vl_hsoname,"/");
#endif
}
/* Else if ".", do nothing. If not "." add to */
/* vl_hsoname */
else if(!strequal(dp->d_name,".")) {
if(*(vl_hsoname + strlen(vl_hsoname) - 1)!='/')
strcat(vl_hsoname,"/");
strcat(vl_hsoname,dp->d_name);
}
/* If ".", must still decide if we include it */
else if(inc_native_flag == VDIN_INCLREAL ||
inc_native_flag == VDIN_ONLYREAL) {
continue;
}
cur_link = vlalloc();
cur_link->name = stcopy(dp->d_name);
cur_link->hsoname = stcopy(vl_hsoname);
cur_link->host = stcopy(hostwport);
cur_link->flags = VLINK_NATIVE;
#define INVISIBLE_DOT_FILES
#ifdef INVISIBLE_DOT_FILES
/* Native . files are initially invisible. We do special things to
make sure that linktype is not important in comparing two links
during a cache reload, since this could be reset after the link
is loaded. */
if (*cur_link->name == '.')
cur_link->linktype = 'I';
else
cur_link->linktype = 'L';
#else
cur_link->linktype = 'L';
#endif
if (read_attributes) {
PFILE fi = pfalloc();
tmp = dsrfinfo(cur_link->hsoname, cur_link->f_magic_no,fi);
if(tmp == -1)
cur_link->target = stcopyr("DIRECTORY",cur_link->target);
/* 5/16/94: is this the attribute deletion bug? */
if(tmp <= 0) {
cur_link->lattrib = fi->attributes;
fi->attributes = NULL;
}
pffree(fi);
} else if (read_basetype) {
char native_filename_buf[MAXPATHLEN];
char *native_filename;
/* This code saves us the hassle of a trip through nativize_prefix
if it is not necessary. */
if (cur_link->hsoname[0] != '/') {
nativize_prefix(cur_link->hsoname, native_filename,
sizeof native_filename);
native_filename = native_filename_buf;
} else {
native_filename = cur_link->hsoname;
}
if(tmp = is_dir(native_filename)) {
if (tmp == 1) {
cur_link->target =
stcopyr("DIRECTORY",cur_link->target);
} else if (tmp == -1) {
/* Maybe we should report an error to plog?? */
vlfree(cur_link);
continue;
}
}
}
APPEND_ITEM(cur_link, retval);
}
closedir(dirp);
perrno = PSUCCESS;
return retval;
}
/* Turns a name of the form /usr/ftp/... (or whatever) into AFTP/... (or
whatever). Returns the # of characters it needed to write out the new
canonical version of the name. This is the canonical form of the HSONAME.
*/
static size_t
canonicalize_prefix(char *native_name, char canon_buf[], size_t canon_bufsiz)
{
int aftpdirsiz = strlen(aftpdir);
if (*aftpdir && strnequal(native_name, aftpdir, aftpdirsiz)
&& (native_name[aftpdirsiz] == '/' ||
native_name[aftpdirsiz] == '\0')) {
return qsprintf(canon_buf, canon_bufsiz, "AFTP%s",
native_name + aftpdirsiz);
}
return qsprintf(canon_buf, canon_bufsiz, "%s", native_name);
}
size_t
nativize_prefix(char *hsoname, char native_buf[], size_t native_bufsiz)
{
int aftpdirsiz = strlen(aftpdir);
if (*aftpdir && strnequal(hsoname, "AFTP", 4)
&& (hsoname[4] == '/' || hsoname[4] == '\0')) {
return qsprintf(native_buf, native_bufsiz, "%s%s",
aftpdir, hsoname + 4);
}
#ifdef DIRECTORYCACHING
/* MITRAISM -- this is used exclusively for the DIRECTORYCACHING stuff.
/* This should handle all other prefixes, without breaking any
other code, which wont call this if it has a prefix */
if (*hsoname != '/')
return qsprintf(native_buf, native_bufsiz, "/%s", hsoname);
#endif
return qsprintf(native_buf, native_bufsiz, "%s", hsoname);
}

View File

@@ -0,0 +1,481 @@
/*
* Copyright (c) 1989, 1990, 1991 by the University of Washington
* Copyright (c) 1992, 1993 by the University of Southern California
*
* For copying and distribution information, please see the files
* <uw-copyright.h> and <usc-copyr.h>
*/
#include <uw-copyright.h>
#include <usc-copyr.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef USE_SYS_DIR_H
#include <sys/dir.h>
#else
#include <dirent.h>
#endif
#include <stdio.h>
#include <sgtty.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#define FILE_VNO 5 /* version # of the file format. */
#include <ardp.h>
#include <pfs.h>
#include <plog.h>
#include <pprot.h>
#include <perrno.h>
#include <pmachine.h>
#include <pparse.h>
#include <psrv.h> /* For nativize_prefix etc */
extern char shadow[];
extern char dirshadow[];
extern char dircont[];
extern char aftpdir[];
PATTRIB atalloc();
VLINK check_fwd();
/* Temporary hack. This will go away when the interface to dsrfinfo() and
dsrobject() changes. Note that the attributes returned depend upon the
client address; this will have to be resolved when we try caching this kind
of directory service information. */
PERFILE_STATIC_LONG_DEF(client_addr); /* set client address. Initially
0. */
#define client_addr p_th_arclient_addr[p__th_self_num()]
void
set_client_addr(long client_addr_arg)
{
client_addr = client_addr_arg;
}
/*
* dsrfinfo - Read file info from disk
*
* DSRFINFO is used by the directory server to read file information from
* disk. It takes the host specific part of the system level name of the
* file about which information is to be read, and a pointer to the file
* structure which it fills in. It returns 0 or -1 on success, 0 if a file
* and -1 if a directory. On errors with some corrupt lines in the shadow
* file, it logs the bad data format to the Prospero logfile, and attempts to
* continue. On other errors, it returns PFAILURE. If unable to find the
* object, it returns DSRFINFO_NOT_A_FILE. If it finds useful forwarding
* information, it will return DSRFINFO_FORWARDED.
*/
int
dsrfinfo(char *nm,long magic,PFILE fi)
{
struct requested_attributes req_obj_ats_st;
ZERO(&req_obj_ats_st);
req_obj_ats_st.all = 1;
return dsrfinfo_with_attribs(nm, magic, fi, &req_obj_ats_st);
}
/*
* For now, we have turned off the magic # matching features. Forwarding is
* no longer magic number based, pending a determination on the role of magic
* numbers in object creation. See /nfs/pfs/notes/forwarding.
*/
int
dsrfinfo_with_attribs(char *nm,long magic,PFILE fi,
struct requested_attributes *req_obj_ats)
{
FILE *pfs_fi = NULL;
char *pfs_fi_name = NULL;
char name[MAXPATHLEN];
char shadow_fname[MAXPATHLEN];
char dirshadow_fname[MAXPATHLEN];
VLINK cur_fp; /* current forwarding poiner */
int tmp;
char *ls; /* Last slash */
struct passwd *ownpw;
struct group *owngr;
struct tm *mt;
char mtime_str[20];
char mode_str[15];
PATTRIB at;
PATTRIB ap; /* Temp attribute pointer */
struct stat file_stat_dat;
struct stat *file_stat = &file_stat_dat;
/* This may be reset to -1 once we determine it's a directory. If we go up
the directory tree looking for forwarding information, it will be reset
to DSRFINFO_FORWARDED. */
int retval = PSUCCESS;
INPUT_ST in_st;
INPUT in = &in_st;
/* Expand special file names */
if((*nm != '/') && *aftpdir && (strncmp(nm,"AFTP",4) == 0)) {
strcpy(name,aftpdir);
strcat(name,nm+4);
}
else strcpy(name,nm);
/* Need to canonicalize the file or directory name (strip out any
symbolic links. */
/* XXX Find the real name of the file and use it */
/* rnl = readlink(filename,rname,MAXPATHLEN); */
/* if(rnl >= 0) *(rname+rnl) = '\0'; */
fi->version = -1; /* sentinel value in case not found. */
fi->f_magic_no = 0;
/* No need to initialize rest of fi, its already initialized */
startover:
/* Determine name of shadow file */
strcpy(shadow_fname,shadow);
nativize_prefix(name, shadow_fname + strlen(shadow),
sizeof shadow_fname - strlen(shadow));
qsprintf(dirshadow_fname,sizeof dirshadow_fname,"%s/%s",shadow_fname,dirshadow);
/* NOTE: A temporary inefficient shadow file format is*/
/* in use. For this reason, the code supporting it */
/* is also interim code, and does not do any checking */
/* to make sure that the file actually follows */
/* the format. Thus, a munged file will result */
/* in unpredictable results. */
/* Read the contents of the shadow file */
/* First find out if it is a directory */
if(stat(shadow_fname,file_stat) == 0) {
if(file_stat->st_mode & S_IFDIR)
pfs_fi = locked_fopen(pfs_fi_name = dirshadow_fname,"r");
else pfs_fi = locked_fopen(pfs_fi_name = shadow_fname,"r");
}
if(pfs_fi != NULL) {
#define RETURN(rv) { retval = (rv); goto cleanup ; }
char *line, *next_word;
tmp = wholefiletoin(pfs_fi, in);
locked_fclose_A(pfs_fi, pfs_fi_name, TRUE);
if(tmp) {
plog(L_DIR_ERR,NOREQ,"%s",p_err_string);
return tmp;
}
while(in_nextline(in)) {
if (in_line(in, &line, &next_word)) {
/* If we cannot parse it, do not use it. */
plog(L_DATA_FRM_ERR,NOREQ,
"Unreadable file info format in %s.", shadow_fname);
RETURN(PFAILURE);
}
CHECK_PTRinBUFF(line,next_word);
switch(*line) {
case 'V': /* Version Number */
tmp = sscanf(line,"VERSION %d",&(fi->version));
if(tmp != 1) {
plog(L_DATA_FRM_ERR,NOREQ,"Bad file info format %s: %s",
shadow_fname,line,0);
}
if (fi->version != FILE_VNO) {
plog(L_DATA_FRM_ERR, NOREQ, "Bad file info format %s: \
unknown version %d, expected %d", shadow_fname, fi->version, FILE_VNO);
RETURN(PFAILURE);
}
break;
case 'M': /* Magic Number */
tmp = sscanf(line,"MAGIC-NUMBER %ld",&(fi->f_magic_no));
if(tmp != 1) {
fi->f_magic_no = 0;
plog(L_DATA_FRM_ERR,NOREQ,"Bad file info format %s: %s",
shadow_fname,line);
}
break;
case 'E': /* Expiration Date */
break;
case 'T': /* Time to live */
break;
case 'L': /* Time of last reference */
break;
case 'F': /* Forwarding Pointer */
/* A forwarding pointer has its NAME member set to the old
hosname of the object (now being forwarded). the NAME
member may terminate in a *, indicating a wildcarded match.
The HOST is the new host of the object and the HSONAME is
its new HSONAME. A trailing * in the HSONAME is replaced
by whatever matched the trailing * in the NAME member
of the object being forwarded. Yes, this means that it is
difficult to forward an object whose real HSONAME ends in
'*'. We do not currently create such objects, although we
might. */
if (strnequal(line, "FORWARD", 7)
&& in_link(in, line, next_word, 0, &cur_fp,
(TOKEN *) NULL) == PSUCCESS) {
APPEND_ITEM(cur_fp, fi->forward);
} else {
plog(L_DATA_FRM_ERR,NOREQ,"Bad file info format %s: %s",
shadow_fname,line);
}
break;
case 'B': /* Back Link */
break;
case 'A': /* Attribute or ACL*/
if (strnequal(line, "ACL", 3)) {
if(in_ge1_acl(in, line, next_word, &fi->oacl)) {
plog(L_DATA_FRM_ERR,NOREQ,"Bad file info format %s: %s",
shadow_fname,line);
RETURN(PFAILURE);
}
}
else if (!strnequal(line, "ATTRIBUTE", 9)
|| in_ge1_atrs(in, line, next_word, &fi->attributes))
plog(L_DATA_FRM_ERR,NOREQ,"Bad file info format %s: %s",
shadow_fname,line);
break;
/*default will skip on to next line - prob reasonable*/
}
}
#ifdef SERVER_DO_NOT_SUPPORT_FORWARDING
#if 0 /* This code is inconsistent; was murdered from
older working code */
/* Explicitly setting the magic # of an object to a negative number
indicates that 'this object is not really here; it's just
a placeholder for forwarding pointers'. */
/* Comparing the magic #s is a fast operation; faster than scanning
though a list of forwarding pointers. Therefore, if the magic #s
match, all is well. */
/* Check_above sets the return value to DSRFINFO_FORWARDED to indicate
that we're searching up the UNIX directory hierarchy for a matching
FORWARD message */
/* Determine if the file has been forwarded, and if so return, */
/* indicating that fact */
/* A file is assumed to have been forwarded if (a) an explicit magic #
was requested and it doesn't match the current magic # and matching
forwarding data was found here for it
if (((fi->f_magic_no && magic && (fi->f_magic_no != magic)) ||
(fi->f_magic_no < 0))
&& check_fwd(fi->forward,nm,magic))
return(DSRFINFO_FORWARDED);
/* Otherwise, this isn't the object that we thought it was (or it
has 'I am not really here' set on it, but no forwarding
informatin found. */
else
return DSRFINFO_NOT_A_FILE;
#else
/* Test: is this object marked indicating that it's the ghost of a
forwarded object? */
if (fi->f_magic_no < 0) retval = DSRFINFO_FORWARDED;
if (retval == DSRFINFO_FORWARDED) {
if (check_fwd(fi->forward, nm, magic)) /* if not locally forwarded.
*/
return DSRFINFO_FORWARDED;
else
return DSRFINFO_NOT_A_FILE;
}
#endif
#endif /* SERVER_DO_NOT_SUPPORT_FORWARDING */
}
/* Fill in attributes from the real file, if it exists and if we are not
just running up the hierarchy for forwarding information, and if we
actually want any of these attributes. */
if((retval == PSUCCESS) && was_attribute_requested("CONTENTS", req_obj_ats))
return(retval);
if ((retval == PSUCCESS)
&& ( was_attribute_requested("SIZE", req_obj_ats)
|| was_attribute_requested("NATIVE-OWNER", req_obj_ats)
|| was_attribute_requested("NATIVE-GROUP", req_obj_ats)
|| was_attribute_requested("LAST-MODIFIED", req_obj_ats)
|| was_attribute_requested("UNIX-MODES", req_obj_ats))
&& (stat(name,file_stat) == 0)) {
if (was_attribute_requested("SIZE", req_obj_ats)) {
/* off_t st_size; /* total size of file */
at = atalloc();
at->aname = stcopy("SIZE");
at->avtype = ATR_SEQUENCE;
at->nature = ATR_NATURE_INTRINSIC;
at->value.sequence = tkalloc(NULL);
at->value.sequence->token =
qsprintf_stcopyr((char *) NULL, "%d bytes", file_stat->st_size);
APPEND_ITEM(at, fi->attributes);
}
#ifndef PFS_THREADS
if (was_attribute_requested("NATIVE-OWNER", req_obj_ats)) {
/* short st_uid; /* user-id of owner */
ownpw = getpwuid(file_stat->st_uid); /* not MT safe */
if(ownpw) {
at = atalloc();
at->aname = stcopy("NATIVE-OWNER");
at->avtype = ATR_SEQUENCE;
at->nature = ATR_NATURE_INTRINSIC;
at->value.sequence = tkalloc(ownpw->pw_name);
APPEND_ITEM(at, fi->attributes);
}
}
#endif
#ifndef PFS_THREADS
if (was_attribute_requested("NATIVE-GROUP", req_obj_ats)) {
/* short st_gid; /* group-id of owner */
owngr = getgrgid(file_stat->st_gid); /* not MT safe */
if(owngr) {
at = atalloc();
at->aname = stcopy("NATIVE-GROUP");
at->avtype = ATR_SEQUENCE;
at->nature = ATR_NATURE_INTRINSIC;
at->value.sequence = tkalloc(owngr->gr_name);
APPEND_ITEM(at, fi->attributes);
}
}
#endif
if (was_attribute_requested("LAST-MODIFIED", req_obj_ats)) {
/* time_t st_atime; /* file last access time */
/* time_t st_mtime; /* file last modify time */
if(file_stat->st_mtime) {
at = atalloc();
at->aname = stcopy("LAST-MODIFIED");
at->avtype = ATR_SEQUENCE;
at->nature = ATR_NATURE_INTRINSIC;
at->value.sequence = tkalloc(NULL);
at->value.sequence->token =
p_timetoasn_stcopyr(file_stat->st_mtime,
at->value.sequence->token);
APPEND_ITEM(at, fi->attributes);
}
}
if (was_attribute_requested("UNIX-MODES", req_obj_ats)) {
/* u_short st_mode; /* protection */
at = atalloc();
at->aname = stcopy("UNIX-MODES");
at->avtype = ATR_SEQUENCE;
at->nature = ATR_NATURE_INTRINSIC;
strcpy(mode_str,"----------");
if((file_stat->st_mode & S_IFLNK) == S_IFLNK) mode_str[0] = 'l';
if(file_stat->st_mode & S_IREAD) mode_str[1] = 'r';
if(file_stat->st_mode & S_IWRITE) mode_str[2] = 'w';
if(file_stat->st_mode & S_IEXEC) mode_str[3] = 'x';
if(file_stat->st_mode & S_ISUID) mode_str[3] = 's';
if(file_stat->st_mode & (S_IREAD>>3)) mode_str[4] = 'r';
if(file_stat->st_mode & (S_IWRITE>>3)) mode_str[5] = 'w';
if(file_stat->st_mode & (S_IEXEC>>3)) mode_str[6] = 'x';
if(file_stat->st_mode & S_ISGID) mode_str[6] = 's';
if(file_stat->st_mode & (S_IREAD>>6)) mode_str[7] = 'r';
if(file_stat->st_mode & (S_IWRITE>>6)) mode_str[8] = 'w';
if(file_stat->st_mode & (S_IEXEC>>6)) mode_str[9] = 'x';
if(file_stat->st_mode & S_IFDIR) {
mode_str[0] = 'd';
if(retval == PSUCCESS) retval = -1;
}
at->value.sequence = tkalloc(mode_str);
APPEND_ITEM(at, fi->attributes);
}
}
/* If no native file AND no PFS file info, then look for forwarding */
else if(fi->version < 0) goto check_above;
/* Stick on the INTRINSIC ACCESS-METHOD attributes. */
if (retval == 0 /* if it's a file */
&& was_attribute_requested("ACCESS-METHOD", req_obj_ats)) {
PATTRIB at1 = NULL;
PATTRIB nextat;
get_access_method(name, client_addr, &at1);
for ( ; at1; at1 = nextat) {
nextat = at1->next;
EXTRACT_HEAD_ITEM(at1);
APPEND_ITEM(at1, fi->attributes);
}
}
return(retval);
/* Check above looks for forwarding pointers in directories */
/* above the named file. It is reached when we have been passed
an hsoname for a nonexistent object.
We might be passed an hsoname for a nonexistent object either
(a) if the object has been forwarded or (b) the object has not
yet been created. So we look for forwarding information or
for a real superior object. Once we make a hit (or hit the root of the
tree), we return either DSRFINFO_FORWARDED or DSRFINFO_NOT_A_FILE.
*/
/* Look up, in case the object has moved, but a forwarding address does not
exist in the corresponding file info, but might exist further up. */
check_above:
retval = DSRFINFO_NOT_A_FILE; /* If the forwarded test succeeds, will
return DSRFINFO_FORWARDED instead. */
ls = strrchr(name,'/');
/* If we have used up all components, return failure */
if((ls == 0) || (ls == name)) return(DSRFINFO_NOT_A_FILE);
*ls = '\0';
goto startover;
cleanup: /* used for abnormal exit */
/* input file is closed in code above. */
return retval;
}
/* check_fwd takes a list of forwarding pointers, checks to see */
/* if any apply to the object with the specified magic number */
/* and returns the appropiate link, or none if not forwarded */
/* If the match is a widarded match, the returned link will be */
/* modified so that the matched wildcard is replaced by the */
/* text that matched it */
/* */
/* BUGS only a trailing * wildcard is allowed */
VLINK
check_fwd(fl,name,magic)
VLINK fl;
char *name;
int magic;
{
char *sp; /* Star pointer */
while(fl) {
if(((magic == 0) || (fl->f_magic_no == 0) ||
(fl->f_magic_no == magic)) && (wcmatch(name,fl->name))) {
sp = strchr(fl->hsoname,'*');
if(sp) *sp = '\0';
sp = strchr(fl->name,'*');
if(sp) {
int n;
sp = name + (sp - fl->name);
fl->name = stcopyr(name,fl->name);
fl->hsoname = qsprintf_stcopyr(fl->hsoname,
"%s%s",fl->hsoname,sp);
}
return(fl);
}
fl = fl->next;
}
return(NULL);
}

View File

@@ -0,0 +1,555 @@
/*
* 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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pmachine.h>
#ifndef SOLARIS /* if not posix, need MAXPATHLEN still */
#include <sys/param.h>
#endif
#include <pserver.h> /* For DIRECTORYCACHING and for PLOG
overrides. */
#include <pfs.h>
#include <perrno.h>
#include <psrv.h>
#include <plog.h>
#ifdef DSROBJECT_SPEEDUP_IS_EXPERIMENTAL
int dsrobject_speedup = 1; /* speed up DSROBJECT. This can be set to 0 to
use the old code. These changes made by SWA
during the week of 5/9/94 */
#endif
static PATTRIB newamat(void);
#ifdef DIRECTORYCACHING
/* One day */
#define SECONDSPERDAY (60*60*24)
#define MAXDIRCACHEAGE (1*SECONDSPERDAY)
int cache_attempt = 0; int cache_can = 0; int cache_yes = 0;
/* Used to see how many times dsrobject() failed in a retrieval request. */
int dsrobject_fail = 0;
int
vdir_outofdate(VDIR dir, char *hsoname)
{
char native_dirname[MAXPATHLEN];
char vfs_dirname[MAXPATHLEN];
nativize_prefix(hsoname, native_dirname, sizeof native_dirname);
strcpy(vfs_dirname,shadow);
strcat(vfs_dirname,native_dirname);
strcat(vfs_dirname,"/");
strcat(vfs_dirname,dircont);
return (stat_age(vfs_dirname) > MAXDIRCACHEAGE);
}
#endif /*DIRECTORYCACHING */
/* Union links are expanded at a higher level.
* The only message dsrobject() sends to the client is an ardp_rwait().
* dsrobject() logs NOT-AUTHORIZED failures via plog, but doesn't send messages
to the client; the caller does that.
* Checks to make sure hsoname is within the space we're allowed to discuss.
* Does check to make sure you have r, G, or g rights on a database before it
lets you scan that database for information.
*/
/* flags honored::
DRO_VERIFY_DIR
*/
/*
Returns:
DSRFINFO_FORWARDED
DIRSRV_NOT_AUTHORIZED
DIRSRV_NOT_FOUND
PFAILURE
PSUCCESS
*/
/* If called with the DRO_VERIFY flag, will set the P_OBJECT_FILE and
P_OBJECT_DIRECTORY flags in the ob structure, but will not *necessarily* put
any other information into the ob structure. Caller is still responsible
for freeing any links pointed to by the ob structure. */
/* If called with the DRO_VERIFY_DIR flag, will return PSUCCESS only if object
is a directory. Will not necessarily put any other information into the OB
structure. Caller is still responsible for freeing any links pointed to by
the ob structure. */
/* dsrobject(), if it returns anything other than DSRFINFO_FORWARDED or
PSUCCESS, may leave the ob structure with arbitrary data in it. The caller
should not expect the ob structure to remain untouched. */
/* At the moment, the only option we look at in dsrobject_list_options is the
requested_attributes one, and that only to test for the CONTENTS
attribute. */
/* The database ACL itself may be obtained by using an HSONAME that is just the
root prefix of the database. */
int requested_contents(struct dsrobject_list_options *listopts);
PATTRIB read_contents(char hsoname[]);
int
dsrobject(RREQ req, char hsoname_type[], char hsoname[], long version,
long magic_no,
int flags, struct dsrobject_list_options *listopts, P_OBJECT ob)
{
VDIR_ST dir_st;
register VDIR dir = &dir_st;
register PFILE fi = NULL; /* Only set if it needs to be. */
int retval; /* Integer return value from subfunctions */
int dirretval = PFAILURE; /* Save initial dsrdir result*/
#ifdef DIRECTORYCACHING
int cancache = TRUE;
#endif
#ifdef DSROBJECT_SPEEDUP_IS_EXPERIMENTAL
if (!dsrobject_speedup)
flags &= ~DRO_VERIFY; /* if not speedup, turn off DRO_VERIFY flag. */
#endif
VLDEBUGBEGIN;
vdir_init(dir); /* empty directory. */
set_client_addr(req->peer_addr.s_addr); /* temporary hack. */
/* Check whether HSONAME-TYPE and HSONAME are valid. */
if (!strequal(hsoname_type, "ASCII")) {
plog(L_DIR_ERR, req, "dsrobject(): got invalid hsoname-type: %s",
hsoname_type, 0);
vdir_freelinks(dir);
RETURNPFAILURE;
}
if (check_handle(hsoname) == FALSE) {
plog(L_AUTH_ERR, req, "Got an HSONAME outside the part of the \
filesystem that this server is authorized to publish information about: %s",
hsoname);
/* Free the directory links */
vdir_freelinks(dir);
return DIRSRV_NOT_AUTHORIZED;
}
if ( *hsoname != '/') {
/* Database or special prefix in use */
register int i;
#ifdef DIRECTORYCACHING /* mitracode */
cache_attempt++;
/* SWA bug fix: this assumes listopts is always set, which it need not
be. */
/* mitra: Can not cache if specifying a component (other than"*") */
/* swa added: Can not cache if #ALL attributes not set. This prevents
us from blowing it badly. */
if (!listopts
|| (listopts->thiscompp && strcmp(*(listopts->thiscompp),"*"))
|| !listopts->req_link_ats.all)
cancache = FALSE;
if (cancache) {
cache_can++;
VLDEBUGBEGIN;
if (!(dirretval
= dsrdir(hsoname, magic_no, dir, NULL, DSRD_ATTRIBUTES)))
cache_yes++;
VLDEBUGDIR(dir);
VLDEBUGEND;
}
#endif
if (dirretval != PSUCCESS
#ifdef DIRECTORYCACHING
|| vdir_outofdate(dir,hsoname)
#endif
|| !(dir->links) ) {
for (i = 0; i < db_num_ents; i++) {
if (strnequal(hsoname, db_prefixes[i].prefix,
strlen(db_prefixes[i].prefix))
&& strequal(db_prefixes[i].hsoname_type, hsoname_type)) {
ACL dbacl;
VLDEBUGBEGIN;
get_named_acl(db_prefixes[i].named_acl, &dbacl);
VLDEBUGEND;
if (dbacl
&& !srv_check_acl(dbacl, NULL, req, "r",
SCA_LINKDIR,db_prefixes[i].prefix,NULL)
&& !srv_check_acl(dbacl, NULL, req, "g",
SCA_LINKDIR,db_prefixes[i].prefix,NULL)
&& !srv_check_acl(dbacl, NULL, req, "G",
SCA_LINKDIR,db_prefixes[i].prefix,NULL)) {
plog(L_AUTH_ERR, req,
"Unauthorized database request: %s %s",
hsoname, listopts? *(listopts->thiscompp) : "");
vdir_freelinks(dir);
return DIRSRV_NOT_AUTHORIZED;
}
/* This could take a while, tell client not to retry.
This should be customized on a per-database basis. */
ardp_rwait(req, 180, 0, 0);
VLDEBUGBEGIN;
retval= db_prefixes[i].read_function(req, hsoname,
version, magic_no, flags, listopts, ob);
VLDEBUGOB(ob);
VLDEBUGEND;
#ifdef DIRECTORYCACHING
if (retval == PSUCCESS && ob->links) {
if (cancache) {
VLDEBUGBEGIN;
dswobject(hsoname_type,hsoname,ob);
VLDEBUGEND;
}
vdir_freelinks(dir);
return(retval);
} else if (dirretval == PSUCCESS) {
/* Must just have been old*/
/*drop through and reread dir and file*/
break;
} else { /* Neither old nor new version available */
/* Or directory is really empty */
vdir_freelinks(dir);
return(retval);
}
#else
vdir_freelinks(dir);
return retval;
#endif /*DIRECTORYCACHING*/
}
} /*for*/
} /*PSUCCESS*/
/* Here we have a prefix that is not a database, */
/* but not a normal filename either */
/* If normal file names need not begin with / */
/* fall through and try a normal query */
}
/* Local directories can have associated finfo too. */
if (dirretval == PSUCCESS) { /* No need to reread if did already */
retval = dirretval;
} else {
VLDEBUGBEGIN;
retval = dsrdir(hsoname, magic_no, dir, NULL,
/* Set DSRD_VERIFY_DIR iff DRO_VERIFY_DIR is set. */
((flags & DRO_VERIFY_DIR) ? DSRD_VERIFY_DIR : 0)
/* Note that dsrdir() curently always returns all
object attributes. This costs us some potentially
unnecessary MALLOC()s. */
| ((listopts && listopts->requested_attrs) ?
DSRD_ATTRIBUTES : 0));
VLDEBUGDIR(dir);
VLDEBUGEND;
}
if (retval == PSUCCESS) ob->flags |= P_OBJECT_DIRECTORY;
if (retval == PSUCCESS || retval == DSRDIR_NOT_A_DIRECTORY ||
retval == DIRSRV_NOT_DIRECTORY || retval == DIRSRV_NOT_FOUND) {
int dsrfinfo_retval;
#ifdef SERVER_DO_NOT_SUPPORT_FORWARDING
/* Don't bother with the dsrfinfo() unless a specific attribute or set
of attributes was requested, or unless a directory was not found. */
if (listopts->req_obj_ats.all
|| listopts->req_obj_ats.interesting
|| listopts->req_obj_ats.specific) {
fi = pfalloc();
dsrfinfo_retval = dsrfinfo_with_attribs(hsoname, magic_no, fi,
&listopts->req_obj_ats);
} else {
dsrfinfo_retval = PFAILURE;
}
#else
VLDEBUGBEGIN;
dsrfinfo_retval = dsrfinfo(hsoname,magic_no,fi);
VLDEBUGFI(fi);
VLDEBUGEND;
if (dsrfinfo_retval == DSRFINFO_FORWARDED) {
ob->inc_native = VDIN_MUNGED;
ob->forward = fi->forward; fi->forward = NULL;
pffree(fi);
vdir_freelinks(dir);
return dsrfinfo_retval;
}
#endif
if (dsrfinfo_retval < 0) { /* dsrfinfo returns <0 to mean
directory */
ob->flags |= P_OBJECT_DIRECTORY;
retval = PSUCCESS;
} else if (dsrfinfo_retval == PSUCCESS) {
ob->flags |= P_OBJECT_FILE;
if (requested_contents(listopts)) {
PATTRIB at = read_contents(hsoname);
/* Append it to fi->attributes since ob->attributes will get
set from that. */
if (at) APPEND_ITEM(at, fi->attributes);
}
retval = PSUCCESS;
}
}
#ifndef SERVER_DO_NOT_SUPPORT_FORWARDING
if (retval == DSRFINFO_FORWARDED) {
/* Only get here if dsrdir() or dsdb() returned DSRFINFO_FORWARDED */
ob->inc_native = VDIN_MUNGED;
ob->forward = dir->f_info->forward; dir->f_info->forward = NULL;
vdir_freelinks(dir);
return retval;
}
#endif
if (retval) {
vdir_freelinks(dir);
if (fi) pffree(fi);
if (retval == DIRSRV_NOT_DIRECTORY || retval == DSRDIR_NOT_A_DIRECTORY
|| retval == DSRFINFO_NOT_A_FILE)
return DIRSRV_NOT_FOUND;
return retval;
}
/* Now for some manly calisthenics!
Merge f_info and directory info. */
/* Note this is the model for the VERSION5 version dswobject
so, if you change this, probably need to change that - Mitra */
/* Only potential conflict here: ACL. Handle it by appending the two
ACLs if both are set. (DIRECTORY first; why not). If one is unset,
use the default (DEFAULT SYSTEM for DIRECTORY, CONTAINER for OBJECT).
If directory and object both have magic numbers set use one from
directory.
*/
if (ob->flags & P_OBJECT_DIRECTORY) {
ob->version = dir->version; /* always 0 */
ob->inc_native = dir->inc_native;
ob->magic_no = dir->magic_no;
ob->acl = dir->dacl; dir->dacl = NULL;
assert(!dir->f_info); /* should have already been handled */
ob->links = dir->links; dir->links = NULL;
ob->ulinks = dir->ulinks; dir->ulinks = NULL;
ob->native_mtime = dir->native_mtime;
} else {
ob->inc_native = VDIN_NOTDIR;
}
/* If FINFO present (will not always need to be present), merge it in. */
if (fi) {
/* Magic # on directory, if present, supersedes magic # on finfo. */
if (!ob->magic_no) ob->magic_no = fi->f_magic_no;
/* Append object ACLs. */
if (fi->oacl) {
CONCATENATE_LISTS(ob->acl, fi->oacl); fi->oacl = NULL;
}
ob->exp = fi->exp;
ob->ttl = fi->ttl;
ob->last_ref = fi->last_ref;
ob->forward = fi->forward; fi->forward = NULL;
ob->backlinks = fi->backlinks; fi->backlinks = NULL;
ob->attributes = fi->attributes; fi->attributes = NULL;
/* Done merging in attributes from FINFO structure. */
}
/* Clean up and return. */
vdir_freelinks(dir);
if (fi) pffree(fi); fi = NULL;
VLDEBUGOB(ob);
VLDEBUGEND;
return retval;
}
/* Return a list of OBJECT INTRINSIC ACCESS-METHOD attributes for the local
real file FILENAME. These attributes should be usable by the client coming
from the address client_addr. One day this function will no longer be
necessary when we have the Prospero access method working.
Allocates pattribs and puts them into RETVAL.
Note that FILENAME has already been expanded from any HSONAME.
*/
/* Called by dsrfinfo at the moment. */
void
get_access_method(char filename[], long client_addr, PATTRIB *retval)
{
PATTRIB at; /* temporary working attribute. */
TOKEN nfs_am; /* Access method for NFS (if any) */
*retval = NULL; /* return list starts empty. */
/* Check for PROSPERO-CONTENTS access method */
/* Always true for any local file. */
at = newamat();
at->value.sequence = tkappend("PROSPERO-CONTENTS", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
APPEND_ITEM(at, *retval);
/* Check for LOCAL access method. */
if (myaddress() == client_addr ||
/* Check for loopback net. */
#if BYTE_ORDER == BIG_ENDIAN
(client_addr & 0xff000000) == (127 << 24)
#else
(client_addr & 0x000000ff) == 127
#endif
) {
/* This may not return information for multi-homed hosts.
But it will never return incorrect information. */
at = newamat();
at->value.sequence = tkappend("LOCAL", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
APPEND_ITEM(at, *retval);
} else {
#ifdef SHARED_PREFIXES
char *cp; /* this memory doesn't need to be freed. */
if (cp = check_localpath(filename, client_addr)){
at = newamat();
at->value.sequence = tkappend("LOCAL", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend(cp, at->value.sequence);
APPEND_ITEM(at, *retval);
}
#endif
}
/* Check for NFS access method. */
#ifdef NFS_EXPORT
if(nfs_am = check_nfs(filename,client_addr)) {
at = newamat();
at->value.sequence = nfs_am;
APPEND_ITEM(at, *retval);
}
#endif NFS_EXPORT
/* Check for AFS access method. Note that the hostname is irrelevant. */
if(*afsdir && strnequal(filename, afsdir, strlen(afsdir))) {
char *suffix = filename + strlen(afsdir);
at = newamat();
at->value.sequence = tkappend("AFS", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("ASCII", at->value.sequence);
at->value.sequence = tkappend(suffix, at->value.sequence);
APPEND_ITEM(at, *retval);
#ifdef AFS_AFTP_GATEWAY /* provide additional access method for sites
that don't run AFS. */
at = newamat();
at->value.sequence = tkappend("AFTP", at->value.sequence);
at->value.sequence = tkappend("INTERNET-D", at->value.sequence);
at->value.sequence = tkappend(hostname, at->value.sequence);
at->value.sequence = tkappend("ASCII", at->value.sequence);
at->value.sequence =
tkappend(qsprintf_stcopyr((char *) NULL,
"%s%s", AFS_AFTP_GATEWAY, suffix),
at->value.sequence);
at->value.sequence = tkappend("BINARY", at->value.sequence);
APPEND_ITEM(at, *retval);
#endif
}
/* Check for AFTP access method. */
if(*aftpdir && strnequal(filename,aftpdir, strlen(aftpdir))) {
char *suffix = filename + strlen(aftpdir);
at = newamat();
at->value.sequence = tkappend("AFTP", at->value.sequence);
at->value.sequence = tkappend("INTERNET-D", at->value.sequence);
at->value.sequence = tkappend(hostname, at->value.sequence);
at->value.sequence = tkappend("ASCII", at->value.sequence);
at->value.sequence = tkappend(suffix, at->value.sequence);
at->value.sequence = tkappend("BINARY", at->value.sequence);
APPEND_ITEM(at, *retval);
}
}
/* Allocate a new ACCESS-METHOD attribute. */
static
PATTRIB
newamat(void)
{
PATTRIB retval = atalloc();
retval->aname = stcopyr("ACCESS-METHOD", retval->aname);
retval->precedence = ATR_PREC_OBJECT;
retval->nature = ATR_NATURE_INTRINSIC;
retval->avtype = ATR_SEQUENCE;
return retval;
}
/* Was the CONTENTS attribute requested on the object itself? CONTENTS is an
INTRINSIC- attribute. Return non-zero (C language "true") if true, zero (C
language "false") if false. */
int
requested_contents(struct dsrobject_list_options *listopts)
{
return listopts
&& was_attribute_requested("CONTENTS", &listopts->req_obj_ats);
}
/* Return the CONTENTS attribute. */
PATTRIB
read_contents(char hsoname[])
{
char *filename;
PATTRIB retval;
int fd; /* file descriptor to read from. */
struct stat file_stat_st;
struct stat * file_stat = &file_stat_st;
TOKEN tk; /* working token */
/* Code modified from dsrfinfo() */
/* Expand special file names */
if((*hsoname != '/') && *aftpdir && strnequal(hsoname,"AFTP",4))
filename = qsprintf_stcopyr("%s%s", aftpdir, hsoname + 4);
else
filename = stcopy(hsoname);
fd = open(filename, 0); /* open for reading */
if (fd < 0) {
stfree(filename);
return NULL;
}
if (stat(filename,file_stat) != 0) {
close(fd);
stfree(filename);
return NULL;
}
retval = atalloc();
retval->aname = stcopyr("CONTENTS", retval->aname);
retval->precedence = ATR_PREC_OBJECT;
retval->nature = ATR_NATURE_INTRINSIC;
retval->avtype = ATR_SEQUENCE;
/* Build a two-element sequence, DATA and a byte stream of the data. */
retval->value.sequence = tkappend("DATA", retval->value.sequence);
tk = tkalloc(NULL);
/* allocate one extra space for the trailing null. */
tk->token = stalloc(file_stat->st_size + 1);
/* tk->token is the buffer we fill in. It remains a valid reference even
after the APPEND_ITEM. We call APPEND_ITEM() first so that it's easy
to abort in case of an error (one less freeing operation to call). */
APPEND_ITEM(tk, retval->value.sequence);
/* Read whole contents and close the file. If either fails, don't set the
CONTENTS attribute. */
/* This might fail IF the file size changes between the stat() and the
read. Oh well. */
if(read(fd, tk->token, file_stat->st_size) != file_stat->st_size
|| close(fd)) {
atfree(retval);
close(fd);
return NULL;
}
p_bst_set_buffer_length_nullterm(tk->token, file_stat->st_size);
/* Automatically null terminates it for us too. */
return retval;
}

View File

@@ -0,0 +1,292 @@
/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-copyr.h>.
*/
#include <usc-copyr.h>
#include <pfs.h>
#include <perrno.h>
#include <psrv.h>
#include <plog.h>
static PATTRIB newamat(void);
/* Union links are expanded at a higher level.
* The only message dsrobject() sends to the client is an ardp_rwait().
* dsrobject() logs NOT-AUTHORIZED failures via plog, but doesn't send messages
to the client; the caller does that.
* Checks to make sure hsoname is within the space we're allowed to discuss.
* Does check to make sure you have r, G, or g rights on a database before it
lets you scan that database for information.
*/
/* flags:
DRO_VERIFY
*/
/*
Returns:
DSRFINFO_FORWARDED
DIRSRV_NOT_AUTHORIZED
PFAILURE
PSUCCESS
*/
/* If called with the DRO_VERIFY flag, will set the P_OBJECT_FILE and
P_OBJECT_DIRECTORY flags in the ob structure, but will not *necessarily* put
any other information into the ob structure. Caller is still responsible
for freeing any links pointed to by the ob structure. */
/* dsrobject(), if it returns anything other than DSRFINFO_FORWARDED or
PSUCCESS, may leave the ob structure with arbitrary data in it.
The caller should not expect the ob structure to remain
*/
/* The database ACL itself may be obtained by using an HSONAME that is just the
root prefix of the database. */
int
dsrobject(RREQ req, char hsoname_type[], char hsoname[], long version,
long magic_no,
int flags, struct dsrobject_list_options *listopts, P_OBJECT ob)
{
VDIR_ST dir_st;
register VDIR dir = &dir_st;
register PFILE fi = NULL; /* Only set if it needs to be. */
int retval; /* Integer return value from subfunctions */
vdir_init(dir); /* empty directory. */
set_client_addr(req->peer_addr.s_addr); /* temporary hack. */
/* Check whether HSONAME-TYPE and HSONAME are valid. */
if (!strequal(hsoname_type, "ASCII")) {
plog(L_DIR_ERR, req, "dsrobject(): got invalid hsoname-type: %s",
hsoname_type, 0);
vdir_freelinks(dir);
RETURNPFAILURE;
}
if (check_handle(hsoname) == FALSE) {
plog(L_AUTH_ERR, req, "Got an HSONAME outside the part of the \
filesystem that this server is authorized to publish information about: %s",
hsoname);
/* Free the directory links */
vdir_freelinks(dir);
return DIRSRV_NOT_AUTHORIZED;
}
if (*hsoname != '/') { /* Database or special prefix in use */
register int i;
for (i = 0; i < db_num_ents; i++) {
if (strnequal(hsoname, db_prefixes[i].db_prefix,
strlen(db_prefixes[i].db_prefix))) {
if (db_prefixes[i].db_acl
&& !srv_check_acl(db_prefixes[i].db_acl, NULL, req, "r",
SCA_LINKDIR,db_prefixes[i].db_prefix,NULL)
&& !srv_check_acl(db_prefixes[i].db_acl, NULL, req, "g",
SCA_LINKDIR,db_prefixes[i].db_prefix,NULL)
&& !srv_check_acl(db_prefixes[i].db_acl, NULL, req, "G",
SCA_LINKDIR,db_prefixes[i].db_prefix,NULL)) {
plog(L_AUTH_ERR, req,
"Unauthorized database request: %s %s",
hsoname, listopts? *(listopts->thiscompp) : "");
vdir_freelinks(dir);
return DIRSRV_NOT_AUTHORIZED;
}
/* This could take a while, tell client not to retry */
ardp_rwait(req, 180, 0, 0);
retval = db_prefixes[i].db_function(req, hsoname,
listopts? listopts->thiscompp : NULL,
listopts? listopts->remcompp : NULL, dir,
(flags & DRO_VERIFY) ? DSDB_VERIFY : 0,
"#INTERESTING" /* requested attributes */,
listopts ? listopts->filters : NULL);
goto dbquery_done;
}
}
/* Here we have a prefix that is not a database, */
/* but not a normal filename either */
/* If normal file names need not begin with / */
/* fall through and try a normal query */
}
/* Local directories can have associated finfo too. */
retval = dsrdir(hsoname, magic_no, dir, NULL, DSRD_ATTRIBUTES);
if (retval == PSUCCESS) ob->flags |= P_OBJECT_DIRECTORY;
if (retval == PSUCCESS || retval == DIRSRV_NOT_DIRECTORY) {
fi = pfalloc();
retval = dsrfinfo(hsoname,magic_no,fi);
if (retval == DSRFINFO_FORWARDED) {
ob->inc_native = VDIN_MUNGED;
ob->forward = fi->forward; fi->forward = NULL;
pffree(fi);
vdir_freelinks(dir);
return retval;
}
if (retval < 0) { /* dsrfinfo returns <0 to mean directory */
ob->flags |= P_OBJECT_DIRECTORY;
retval = PSUCCESS;
} else if (retval == PSUCCESS) {
ob->flags |= P_OBJECT_FILE;
}
}
dbquery_done:
if (retval == DSRFINFO_FORWARDED) {
/* Only get here if dsrdir() or dsdb() returned DSRFINFO_FORWARDED */
ob->inc_native = VDIN_MUNGED;
ob->forward = dir->f_info->forward; dir->f_info->forward = NULL;
vdir_freelinks(dir);
return retval;
}
if (retval) {
vdir_freelinks(dir);
if (fi) pffree(fi);
return retval;
}
/* Now for some manly calisthenics!
Merge f_info and directory info. */
/* Only potential conflict here: ACL. Handle it by appending the two
ACLs if both are set. (DIRECTORY first; why not). If one is unset,
use the default (DEFAULT SYSTEM for DIRECTORY, CONTAINER for OBJECT).
If directory and object both have magic numbers set use one from
directory.
*/
if (ob->flags & P_OBJECT_DIRECTORY) {
ob->version = dir->version; /* always 0 */
ob->inc_native = dir->inc_native;
ob->magic_no = dir->magic_no;
ob->acl = dir->dacl; dir->dacl = NULL;
assert(!dir->f_info); /* should have already been handled */
ob->links = dir->links; dir->links = NULL;
ob->ulinks = dir->ulinks; dir->ulinks = NULL;
ob->native_mtime = dir->native_mtime;
} else {
ob->inc_native = VDIN_NOTDIR;
}
if (ob->flags & P_OBJECT_FILE) {
if (fi->f_magic_no) ob->magic_no = fi->f_magic_no;
if (fi->oacl) {
CONCATENATE_LISTS(ob->acl, fi->oacl); fi->oacl = NULL;
}
ob->exp = fi->exp;
ob->ttl = fi->ttl;
ob->last_ref = fi->last_ref;
ob->forward = fi->forward; fi->forward = NULL;
ob->backlinks = fi->backlinks; fi->backlinks = NULL;
ob->attributes = fi->attributes; fi->attributes = NULL;
}
vdir_freelinks(dir);
if (fi) pffree(fi); fi = NULL;
return retval;
}
/* Return a list of OBJECT INTRINSIC ACCESS-METHOD attributes for the local
real file FILENAME. These attributes should be usable by the client coming
from the address client_addr. One day this function will no longer be
necessary when we have the Prospero access method working.
Allocates pattribs and puts them into RETVAL.
Note that FILENAME has already been expanded from any HSONAME.
*/
void
get_access_method(char filename[], long client_addr, PATTRIB *retval)
{
PATTRIB at; /* temporary working attribute. */
TOKEN nfs_am; /* Access method for NFS (if any) */
*retval = NULL; /* return list starts empty. */
/* Check for LOCAL access method. */
if (myaddress() == client_addr ||
/* Check for loopback net. */
#if BYTE_ORDER == BIG_ENDIAN
(client_addr & 0xff000000) == (127 << 24)
#else
(client_addr & 0x000000ff) == 127
#endif
) {
/* This may not return information for multi-homed hosts.
But it will never return incorrect information. */
at = newamat();
at->value.sequence = tkappend("LOCAL", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
APPEND_ITEM(at, *retval);
} else {
#ifdef SHARED_PREFIXES
char *cp; /* this memory doesn't need to be freed. */
if (cp = check_localpath(filename, client_addr)){
at = newamat();
at->value.sequence = tkappend("LOCAL", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend(cp, at->value.sequence);
APPEND_ITEM(at, *retval);
}
#endif
}
/* Check for NFS access method. */
#ifdef NFS_EXPORT
if(nfs_am = check_nfs(filename,client_addr)) {
at = newamat();
at->value.sequence = nfs_am;
APPEND_ITEM(at, *retval);
}
#endif NFS_EXPORT
/* Check for AFS access method. Note that the hostname is irrelevant. */
if(*afsdir && strnequal(filename, afsdir, strlen(afsdir))) {
char *suffix = filename + strlen(afsdir);
at = newamat();
at->value.sequence = tkappend("AFS", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("", at->value.sequence);
at->value.sequence = tkappend("ASCII", at->value.sequence);
at->value.sequence = tkappend(suffix, at->value.sequence);
APPEND_ITEM(at, *retval);
#ifdef AFS_AFTP_GATEWAY /* provide additional access method for sites
that don't run AFS. */
at = newamat();
at->value.sequence = tkappend("AFTP", at->value.sequence);
at->value.sequence = tkappend("INTERNET-D", at->value.sequence);
at->value.sequence = tkappend(hostname, at->value.sequence);
at->value.sequence = tkappend("ASCII", at->value.sequence);
at->value.sequence =
tkappend(qsprintf_stcopyr((char *) NULL,
"%s%s", AFS_AFTP_GATEWAY, suffix),
at->value.sequence);
at->value.sequence = tkappend("BINARY", at->value.sequence);
APPEND_ITEM(at, *retval);
#endif
}
/* Check for AFTP access method. */
if(*aftpdir && strnequal(filename,aftpdir, strlen(aftpdir))) {
char *suffix = filename + strlen(aftpdir);
at = newamat();
at->value.sequence = tkappend("AFTP", at->value.sequence);
at->value.sequence = tkappend("INTERNET-D", at->value.sequence);
at->value.sequence = tkappend(hostname, at->value.sequence);
at->value.sequence = tkappend("ASCII", at->value.sequence);
at->value.sequence = tkappend(suffix, at->value.sequence);
at->value.sequence = tkappend("BINARY", at->value.sequence);
APPEND_ITEM(at, *retval);
}
}
/* Allocate a new ACCESS-METHOD attribute. */
static
PATTRIB
newamat(void)
{
PATTRIB retval = atalloc();
retval->aname = stcopyr("ACCESS-METHOD", retval->aname);
retval->precedence = ATR_PREC_OBJECT;
retval->nature = ATR_NATURE_INTRINSIC;
retval->avtype = ATR_SEQUENCE;
return retval;
}

View File

@@ -0,0 +1,124 @@
/* Copyright (c) 1992, 1993 by the University of Southern California
* For copying and distribution information, please see the file
* <usc-copyr.h>
*/
#include <usc-copyr.h>
#include <pfs.h>
#include <pparse.h>
#include <psrv.h>
#include <stdio.h>
#include <perrno.h>
#include <plog.h>
#ifndef MAXPATHLEN
#include <sys/param.h>
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
#endif
#include <sys/stat.h>
extern char *rindex();
extern char shadow[];
extern char dirshadow[];
extern char dircont[];
extern char pfsdat[];
extern char aftpdir[];
#define FILE_VNO 5 /* version # of the file format. Appears in
this file and in dsrfinfo.c */
/* Forward definitions */
static FILE *open_shadow_outfile_A(char nm[], char **shadow_fnamep);
static int write_data(FILE * outf, PFILE fi);
/* Logs errors to plog() and returns an error code. */
int
dswfinfo(char *nm, PFILE fi)
{
int retval;
FILE *outf;
AUTOSTAT_CHARPP(shadow_fnamep);
assert(fi); /* write_data cant handle null fi*/
if (outf = open_shadow_outfile_A(nm,shadow_fnamep)) {
retval = write_data(outf, fi);
} else {
return perrno;
}
locked_fclose_A(outf, *shadow_fnamep, FALSE);
return retval;
}
static FILE *
open_shadow_outfile_A(char nm[], char **shadow_fnamep)
{
char real_fname[MAXPATHLEN]; /* Filename after expansion */
char shadow_dirname[MAXPATHLEN]; /* directory we create */
char *sp; /* pointer to slash */
FILE *outf;
struct stat file_stat_dat;
struct stat *file_stat = &file_stat_dat;
nativize_prefix(nm, real_fname, sizeof(real_fname));
/* Create the directory to contain the shadow file, if it doesn't already
exist. */
/* Is the shadow file a directory? */
if ((stat(real_fname, file_stat) == 0) || (*nm != '/')) {
if ((file_stat->st_mode & S_IFDIR) || (*nm != '/')) {
*shadow_fnamep = qsprintf_stcopyr(*shadow_fnamep,
"%s%s/%s", shadow, real_fname, dirshadow);
} else {
*shadow_fnamep = qsprintf_stcopyr(*shadow_fnamep,
"%s%s", shadow, real_fname);
}
} else {
plog(L_DATA_FRM_ERR, NOREQ, "Output data file doesnt already exist: %s",
real_fname);
perrno = PFAILURE;
return NULL;
}
strcpy(shadow_dirname, *shadow_fnamep);
assert(sp = rindex(shadow_dirname, '/')); /* must be true. */
*sp = '\0';
mkdirs(shadow_dirname);
if ((outf = locked_fopen(*shadow_fnamep, "w")) == NULL) {
plog(L_DATA_FRM_ERR, NOREQ, "Couldn't open the output data file %s",
*shadow_fnamep);
perrno = PFAILURE;
}
return outf;
}
static int
write_data(FILE * outf, PFILE fi)
{
OUTPUT_ST out_st;
OUTPUT out = &out_st;
PATTRIB at;
VLINK cur_fp;
assert(fi);
filetoout(outf, out);
qoprintf(out, "VERSION %d\n", FILE_VNO);
qoprintf(out, "MAGIC-NUMBER %d\n", fi->f_magic_no);
/* Any forwarding pointers. */
for (cur_fp = fi->forward; cur_fp; cur_fp = cur_fp->next) {
qoprintf(out, "FORWARD ");
out_link(out, cur_fp, 0, (TOKEN) NULL);
}
/* print out the object ACL if present */
out_acl(out, fi->oacl);
for (at = fi->attributes; at; at = at->next) {
if (at->nature != ATR_NATURE_INTRINSIC) /* INTRINSIC attributes are
written specially */
out_atr(out, at, 0);
}
return PSUCCESS;
}

View File

@@ -0,0 +1,311 @@
/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-copyr.h>.
*/
#include <usc-copyr.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pmachine.h>
#include <pfs.h>
#include <perrno.h>
#include <psrv.h>
#include <plog.h>
#if (OBJECT_VNO == 5)
/* Note this is modeled on the "manly calisthenics" in dsrobject, if this
is wrong, then that probably is and vica versa */
void
ob2dir(P_OBJECT ob, VDIR dir)
{
assert(dir);
if (ob->flags & P_OBJECT_DIRECTORY) {
dir->version = ob->version; /* always 0 */
dir->inc_native = ob->inc_native;
dir->magic_no = ob->magic_no;
dir->dacl = aclcopy(ob->acl);
dir->links = vlcopy(ob->links,TRUE);
dir->ulinks = vlcopy(ob->ulinks,TRUE);
dir->native_mtime = ob->native_mtime;
}
if (TRUE) { /* (ob->flags & P_OBJECT_FILE) { */
/* I'm not sure this is the best way, but since we have f_info field*/
register PFILE fi = dir->f_info;
if (!dir->f_info) { fi = pfalloc(); dir->f_info = fi; }
if (ob->magic_no) fi->f_magic_no = ob->magic_no;
/* acl copied above */
fi->exp = ob->exp;
fi->ttl = ob->ttl;
fi->last_ref = ob->last_ref;
fi->forward = vlcopy(ob->forward,TRUE);
fi->backlinks = vlcopy(ob->backlinks,TRUE);
fi->attributes = atlcopy(ob->attributes);
}
}
void
dswobject(char hsonametype[], char hsoname[], P_OBJECT ob)
{
VDIR_ST dir_st;
register VDIR dir = &dir_st;
int tmp;
vdir_init(dir);
ob2dir(ob,dir);
if (tmp = dswdir(hsoname, dir)) {
p_warn_string = qsprintf_stcopyr(p_warn_string,
"Failed to update cache for directory %'s: Prospero error %d",
hsoname, tmp);
}
if (dir->f_info) {
if (tmp = dswfinfo(hsoname, dir->f_info)) {
p_warn_string = qsprintf_stcopyr(p_warn_string,
"Failed to update finfo for %'s: Prospero error %d",
hsoname, tmp);
}
}
vdir_freelinks(dir);
}
#endif /*VERSION5*/
#if (OBJECT_VNO == 6)
/* XXX This code is untested and does not work at the moment.
I am currently working on it. -swa@ISI.EDU, April 13, 1994. */
static int write_data(FILE * outf, P_OBJECT ob);
static FILE *open_shadow_outfile_A(char nm[], char *shadow_fname,
char **objshadownamep);
static size_t canonicalize_prefix(char *native_name, char canon_buf[], size_t canon_bufsiz);
static size_t nativize_prefix(char *hsoname, char native_buf[], size_t native_bufsiz);
extern int dswobject(char hsonametype[], char hsoname[], P_OBJECT ob)
{
static int write_data(FILE * outf, P_OBJECT ob);
char *objshadowname;
int retval;
FILE *outf;
char shadow_fname[MAXPATHLEN];
assert(strequal(hsonametype, "ASCII"));
filelock_obtain(objshadowname,FALSE); /* Obtain write lock on rel dir */
if (!(outf =
open_shadow_outfile_A(hsoname, &shadow_fname, &objshadowname)))
{ filelock_release(objshadowname, FALSE);
return(perrno);
}
retval = write_data(outf, ob);
retval = locked_fclose_and_rename(outf, shadow_fname, objshadowname,retval);
return(retval);
}
/* XXX This routine will have to be changed. XXX BAD XXX */
static FILE *
open_shadow_outfile_A(char nm[], char *shadow_fname, char **objshadowname)
{
char real_fname[MAXPATHLEN]; /* Filename after expansion */
char shadow_dirname[MAXPATHLEN]; /* directory we create. */
char *sp; /* pointer to slash */
FILE *outf;
int retval; /* return value from subfunctions */
struct stat file_stat_dat;
struct stat *file_stat = &file_stat_dat;
/* If special file name, change to real file name */
nativize_prefix(nm, real_fname, sizeof real_fname);
/* Create the directory to contain the shadow file, if it doesn't already
exist. */
/* Is the shadow file a directory? */
if ((retval = is_dir(real_fname)) == 0) {
if (stat(real_fname, file_stat) == 0) {
if(file_stat->st_mode & S_IFDIR) {
qsprintf(shadow_fname, sizeof shadow_fname,
"%s%s/%s", shadow, real_fname, dirshadow);
} else {
qsprintf(shadow_fname, sizeof shadow_fname,
"%s%s", shadow, real_fname);
}
}
strcpy(shadow_dirname, shadow_fname);
assert(sp = rindex(shadow_dirname, '/')); /* must be true. */
*sp = '\0';
mkdirs(shadow_dirname);
if ((outf = locked_fopen(shadow_fname, "w")) == NULL) {
plog(L_DATA_FRM_ERR, NOREQ, "Couldn't open the output data file %s",
shadow_fname);
perrno = PFAILURE;
}
return outf;
}
static void dump_links(OUTPUT out, VLINK cur_link);
static int
write_data(FILE * outf, P_OBJECT ob)
{
OUTPUT_ST out_st;
OUTPUT out = &out_st;
PATTRIB at;
VLINK cur_fp;
filetoout(outf, out);
qoprintf(out, "VERSION %d\n", OBJECT_VNO);
if (ob->version) qoprintf("OBJECT-VERSION %d\n", ob->version);
qoprintf(out, "MAGIC-NUMBER %d\n", ob->f_magic_no);
assert(ob->inc_native != VDIN_UNINITIALIZED);
if (ob->inc_native != VDIN_NOTDIR) {
qoprintf(out, "INCLUDE-NATIVE ");
if(dir->inc_native == VDIN_INCLREAL || dir->inc_native == VDIN_ONLYREAL)
qoprintf(out,"INCLREAL\n");
else if(dir->inc_native == VDIN_INCLNATIVE)
qoprintf(out,"INCLNATIVE\n");
else if (dir->inc_native == VDIN_NONATIVE)
qoprintf(out,"NONATIVE\n");
else
internal_error("unknown value of dir->inc_native");
}
/* print out the ACL if present */
out_acl(out, ob->acl);
if (ob->exp) {
char *cp = NULL;
qoprintf(out, "EXP %s\n", cp = p_timetoasn_stcopyr(ob->exp, cp));
stfree(cp);
}
if (ob->ttl) qoprintf(out, "TTL %ld\n", ob->ttl);
if (ob->last_ref) {
char *cp = NULL;
qoprintf(out, "LAST-REF %s\n",
cp = p_timetoasn_stcopyr(ob->last_ref, cp));
stfree(cp);
}
/* Any forwarding pointers. */
for (cur_fp = ob->forward; cur_fp; cur_fp = cur_fp->next) {
qoprintf(out, "FORWARD ");
out_link(out, cur_fp, 0, (TOKEN) NULL);
}
/* Back links */
for (cur_fp = ob->backlinks; cur_fp; cur_fp = cur_fp->next) {
qoprintf(out, "BACKLINK ");
out_link(out, cur_fp, 0, (TOKEN) NULL);
}
/* Object attributes */
for (at = ob->attributes; at; at = at->next) {
if (at->nature != ATR_NATURE_INTRINSIC) /* INTRINSIC attributes are
written specially */
out_atr(out, at, 0);
}
#if 0 /* need to see if this is still necessary. */
/* If directory was, shouldn't be any links which are NATIVE */
for (vl = dir->links; vl; vl = vl->next) {
vl->flags &= ~VLINK_NATIVE;
}
#endif
dump_links(out, dir->links);
dump_links(out, dir->ulinks);
if (ob->native_mtime && ob->inc_native != VDIN_NONATIVE) {
char *cp = NULL;
qoprintf(out, "NATIVE-MTIME %s\n",
cp = p_timetoasn_stcopyr(dir->native_mtime, cp));
stfree(cp);
}
return PSUCCESS;
}
static void
dump_links(OUTPUT out, VLINK cur_link)
{
for (; cur_link; cur_link = cur_link->next) {
PATTRIB ca;
FILTER cur_fil;
/* Special case for ULINK_PLACEHOLDER. */
if (cur_link->expanded == ULINK_PLACEHOLDER) continue;
/* don't output native links to directory unless we just converted
it to NONATIVE, or unless caching is enabled for the native
directory, or unless they have attributes beyond the OBJECT ones. */
if (cur_link->flags & VLINK_NATIVE) {
cur_link->linktype = cur_link->linktype == 'I' ? 'n' : 'N';
}
qoprintf(out, "LINK ");
out_link(out, cur_link, 0, (TOKEN) NULL);
for (ca = cur_link->lattrib; ca; ca = ca->next) {
if (ca->nature != ATR_NATURE_INTRINSIC) {
if (ca->precedence == ATR_PREC_OBJECT)
ca->precedence = ATR_PREC_CACHED;
out_atr(out, ca, 0);
}
}
for (cur_fil = cur_link->filters; cur_fil; cur_fil = cur_fil->next) {
qoprintf(out, "ATTRIBUTE LINK FIELD FILTER FILTER ");
out_filter(out, cur_fil, 0);
}
out_acl(out, cur_link->acl);
if (cur_link->flags & VLINK_NATIVE) {
cur_link->linktype = cur_link->linktype == 'N' ? 'L' : 'I';
}
}
}
/* Stat and get a modification time. Returns 0 upon failure. */
static time_t
mtime(char native_dirname[])
{
struct stat st_buf;
if(stat(native_dirname, &st_buf) == 0)
return st_buf.st_mtime;
else
return 0;
}
/* Is it a directory? 1 = yes, 0 = no, -1 = failure? */
static int
is_dir(char native_filename[])
{
struct stat st_buf;
if(stat(native_filename, &st_buf) == 0)
return S_ISDIR(st_buf.st_mode) ? 1 : 0;
else
return -1;
}
/* Turns a name of the form /usr/ftp/... (or whatever) into AFTP/... (or
whatever). Returns the # of characters it needed to write out the new
canonical version of the name. This is the canonical form of the HSONAME.
*/
static size_t
canonicalize_prefix(char *native_name, char canon_buf[], size_t canon_bufsiz)
{
int aftpdirsiz = strlen(aftpdir);
if (*aftpdir && strnequal(native_name, aftpdir, aftpdirsiz)
&& (native_name[aftpdirsiz] == '/' ||
native_name[aftpdirsiz] == '\0')) {
return qsprintf(canon_buf, canon_bufsiz, "AFTP%s",
native_name + aftpdirsiz);
}
return qsprintf(canon_buf, canon_bufsiz, "%s", native_name);
}
static size_t
nativize_prefix(char *hsoname, char native_buf[], size_t native_bufsiz)
{
int aftpdirsiz = strlen(aftpdir);
if (*aftpdir && strnequal(hsoname, "AFTP", 4)
&& (hsoname[4] == '/' || hsoname[4] == '\0')) {
return qsprintf(native_buf, native_bufsiz, "%s%s",
aftpdir, hsoname + 4);
}
return qsprintf(native_buf, native_bufsiz, "%s", hsoname);
}
#endif /* 0 */

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 1992 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-copyr.h>
*/
#include <ardp.h>
#include <psrv.h>
#include <plog.h>
#include <pprot.h>
#include <perrno.h>
/* This function will execute both a vplog() and an vsendmqf() in order to
report on an erroneous condition.
It makes error returns easier. It returns PFAILURE, since it should only be
used if an error has occurred.
It also automatically prefixes the word ERROR to the error reply packets.
It appends the appropriate newlines, so you don't have to.
*/
int
error_reply(RREQ req, char *format, ...)
{
va_list ap;
char *bufp;
va_start(ap, format);
bufp = vplog(L_DIR_PERR, req, format, ap); /* return formatted string */
reply(req, "ERROR ");
reply(req, bufp);
creply(req, "\n");
va_end(ap);
RETURNPFAILURE;
}

View File

@@ -0,0 +1 @@
Makefile

View File

@@ -0,0 +1,6 @@
FILES
Makefile
glalloc.c
goph_gw_dsdb.c
goph_gw_mutex.c
gopher.h

View File

@@ -0,0 +1,47 @@
SOURCEBASE = ../../..
include $(SOURCEBASE)/Makefile.config
CFILES = \
glalloc.c \
goph_gw_dsdb.c \
goph_gw_mutex.c
OBJECTS = \
glalloc.o \
goph_gw_dsdb.o \
goph_gw_mutex.o
OTHERTARGETS = ${GOPHER_GW_LIB}
all: ${GOPHER_GW_LIB}
${GOPHER_GW_LIB}: ${OBJECTS}
rm -f ${GOPHER_GW_LIB}
ar r${AR_FLAGS} ${GOPHER_GW_LIB} ${OBJECTS}
$(RANLIB) ${GOPHER_GW_LIB}
# Dependencies
glalloc.o : ../../../include/pfs.h \
../../../include/pfs_utils.h ../../../include/ardp.h \
../../../include/pfs_threads.h \
../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/implicit_fixes.h \
../../../include/pmachine.h \
../../../include/psrv.h ../../../include/pparse.h \
gopher.h ../../../include/mitra_macros.h
goph_gw_dsdb.o : \
../../../include/pmachine.h \
../../../include/pserver.h \
../../../include/ardp.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h \
../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/pfs.h \
../../../include/implicit_fixes.h \
../../../include/psrv.h ../../../include/pparse.h \
../../../include/perrno.h ../../../include/plog.h gopher.h
goph_gw_mutex.o : gopher.h \
../../../include/pfs_threads.h \
../../../include/pfs_utils.h ../../../include/pfs.h ../../../include/ardp.h \
../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/implicit_fixes.h \
../../../include/pmachine.h

View File

@@ -0,0 +1,58 @@
/*
* 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 <pfs.h>
#include <psrv.h>
#include "gopher.h"
#include <mitra_macros.h>
static GLINK lfree = NULL;
int glink_count = 0;
int glink_max = 0;
/*
glalloc(): Allocate and initialize GLINK structure.
Signal out_of_memory() on failure.
*/
GLINK
glalloc(void)
{
GLINK gl;
TH_STRUC_ALLOC(glink,GLINK,gl);
/* Initialize and fill in default values */
gl->type = '0';
gl->name = NULL;
gl->selector = NULL;
gl->host = NULL;
gl->port = 0;
gl->protocol_mesg = NULL;
return gl;
}
void
glfree(GLINK gl)
{
/* Free any bits of memory pointed to by members of the structure. */
if (gl->name) stfree(gl->name);
if (gl->host) stfree(gl->host);
if (gl->selector) stfree(gl->selector);
if (gl->protocol_mesg) stfree(gl->protocol_mesg);
/* Free the structure itself. */
TH_STRUC_FREE(glink,GLINK,gl);
}
void
gllfree(GLINK gl)
{
TH_STRUC_LFREE(GLINK,gl,glfree)
}

View File

@@ -0,0 +1,867 @@
/*
* 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>
/* Definitions of constants */
#define MAX_NUM_GOPHER_LINKS 3000 /* maximum # of directory links to
return before giving up. */
/* Archie server we redirect ftp:hostname@ queries to. */
/* Don't define this for now, since it can lead to odd results. */
/* #define ARCHIE_SERVER "ARCHIE.SURA.NET" */
#include <sys/types.h>
#include <sys/socket.h> /* includes SOL_SOCKET */
#include <netinet/in.h>
#include <sys/uio.h> /* for writev(), struct iovec */
#include <netdb.h>
#include <errno.h>
#include <pmachine.h>
#include <pserver.h>
#include <ardp.h> /* unixerrstr() prototype. */
#include <pfs.h> /* assert, internal_error, prototypes */
#include <psrv.h>
#include <perrno.h>
#include <plog.h>
#include "gopher.h"
#include <string.h>
#ifdef PSRV_WAIS_GW
#include <wais-source.h>
#include <psite.h> /* For WAIS_SOURCE_DIR */
#endif
/* 5 secs seems a bit short for this */
#ifndef G_OPEN_TIMEOUT
#define G_OPEN_TIMEOUT 10
#endif
#ifndef G_READ_TIMEOUT
#define G_READ_TIMEOUT 10
#endif
#ifndef GFTP_READ_TIMEOUT
#define GFTP_READ_TIMEOUT 20
#endif
#ifndef GSEARCH_READ_TIMEOUT
#define GSEARCH_READ_TIMEOUT 30
#endif
extern char hostwport[];
extern int quick_open_tcp_stream(char host[], int port, int timeout);
extern char *quick_fgets(char *s, int n, FILE *stream, int timeout);
static GLINK quick_get_menu(char *host, int port, char *selector, int tme);
static void glinks_to_dirob(GLINK glist, P_OBJECT ob);
static void atput(VLINK vl, char *name,...);
static void ftp_check_am(GLINK gl, VLINK r, char *textorbin);
static void ftp_check_dir(GLINK gl, VLINK r);
static int wais_check_dir(GLINK gl, VLINK r);
static void zap_trailing_spaces(char *host);
/* This function is passed an empty object which has been initialized with
oballoc(). It returns a possibly populated directory and
DIRSRV_NOT_FOUND or PSUCCESS. Note that the directory will need
to have links within it freed, even if an error code is returned. */
/* This sets p_warn_string and pwarn if an unrecognized gopher line is
received. That is good. */
/* This code needs to return attributes in response to a GET-OBJECT-INFO query.
*/
int
gopher_gw_dsdb(RREQ req, /* Request pointer (unused) */
char *hsoname, /* Name of the directory */
long version,/* Version #; currently ignored */
long magic_no, /* Magic #; currently ignored */
int flags, /* Currently only recognize DRO_VERIFY */
struct dsrobject_list_options *listopts, /* options (use *remcompp
and *thiscompp) */
P_OBJECT ob)
{ /* Object to be filled in */
int tmp;
char *cp;
AUTOSTAT_CHARPP(hostp); /* For threads. */
int port;
char type;
char *selectorcp; /* a character pointer that might point to the
first part of the selector or possibly the
complete selector. */
char *selector; /* the final selector */
GLINK glist; /* list of gopher links */
int timeout; /* Timeout for lines (not connect) */
ob->version = 0; /* unversioned */
ob->inc_native = VDIN_PSEUDO;
ob->flags = P_OBJECT_DIRECTORY;
ob->magic_no = 0;
ob->acl = NULL;
tmp = qsscanf(hsoname, "GOPHER-GW/%&[^(](%d)/%c%r/%r",
hostp, &port, &type, &cp, &selectorcp);
if (tmp < 4)
return DIRSRV_NOT_FOUND;
if (type == '1') {
if (tmp < 5)
return DIRSRV_NOT_FOUND;
selector = selectorcp;
} else if (type == '7') {
AUTOSTAT_CHARPP(sp); /* Memory allocated for selector */
if (tmp < 4)
return DIRSRV_NOT_FOUND;
else if (tmp == 4) {
selectorcp = "";
} /* if tmp = 5, selectorcp already set. */
/* Now set the selector. */
if (!listopts || !listopts->thiscompp || !*listopts->thiscompp ||
strequal(*listopts->thiscompp, "")
|| strequal(*listopts->thiscompp, "*"))
/* last test against * might be inappropriate */
return PSUCCESS; /* Display no contents for the directory */
/* Set the selector. */
selector = *sp = qsprintf_stcopyr(*sp, "%s%s%s", selectorcp,
(*selectorcp) ? "\t" : "", *listopts->thiscompp);
/* We just used up thiscompp, so we'd better reset it. */
/* Oops - && here was meaningless */
/* I changed this so that the else is not done if listopts->remcompp
is null, in that case (as in when called by get_object_info)
listopts->thiscompp is also null so "*listopts->thiscompp = NULL"
generates a segment violation, if this is the case then we didnt
use a component anyway, so no need to advance to the next */
if (listopts->remcompp) {
if (*listopts->remcompp) {
*listopts->thiscompp = (*listopts->remcompp)->token;
*listopts->remcompp = (*listopts->remcompp)->next;
} else {
*listopts->thiscompp = NULL;
}
}
/* Now that the selector is set, fall through. */
} else { /* unknown type for gatewaying */
return DIRSRV_NOT_FOUND;
}
/* don't bother retrieving the contents if just verifying. */
if (flags & DRO_VERIFY)
return PSUCCESS;
if (type == '7') {
timeout = GSEARCH_READ_TIMEOUT;
} else {
if (strncmp(selector,"ftp:",4)== 0 ) {
timeout = GFTP_READ_TIMEOUT;
} else {
timeout = G_READ_TIMEOUT;
}
}
if ((glist = quick_get_menu(*hostp, port, selector, timeout))
== NULL && perrno)
return perrno;
glinks_to_dirob(glist, ob);
gllfree(glist);
return PSUCCESS;
}
static GLINK quick_next_menu_item(FILE * fp, int timeout);
extern int p_open_tcp_stream(const char host[], int port);
/* Returns NULL & sets perrno on error. */
static GLINK
quick_get_menu(char *host, int port, char *selector, int timeout)
{
GLINK retval = NULL;
GLINK gl;
FILE *fp; /* used for reading only. Tried to use it for
reading & writing without success; see
comment below. */
int fd;
int tmp; /* return value from write() and read()*/
int nlinks = 0; /* # of links in directory */
#ifndef NO_IOVEC
struct iovec iov[2];
#endif
fd = quick_open_tcp_stream(host, port, G_OPEN_TIMEOUT);
/* Copied from vcache */
if (fd < 0) {
perrno = DIRSRV_GOPHER; /* work on error reporting */
return NULL;
}
#if ! defined(NO_IOVEC) && ! defined(PFS_THREADS)
/* Current implementation of threads does not include writev(). */
iov[0].iov_base = selector;
iov[0].iov_len = strlen(selector);
iov[1].iov_base = "\r\n";
iov[1].iov_len = 2;
tmp = writev(fd, iov, 2);
if (tmp != iov[0].iov_len + iov[1].iov_len) {
#else
tmp = write(fd, selector, strlen(selector));
if (tmp != strlen(selector)) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Couldn't send selector to gopher \
connection to %s: Call to write(%d,%s,%d) failed: errno %d: \
%s", host, fd, selector, strlen(selector), errno, unixerrstr());
redo_close:
if(close(fd) == -1 && errno == EINTR) goto redo_close;
perrno = DIRSRV_GOPHER;
return NULL;
}
tmp = write(fd, "\r\n", 2);
if (tmp != 2) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Couldn't send selector to gopher \
connection to %s: Call to write(%d, \"\\r\\n\", 2) failed: errno %d: %s",
host, fd, errno, unixerrstr());
#endif
redo_close2:
if(close(fd) == -1 && errno == EINTR) goto redo_close2;
perrno = DIRSRV_GOPHER;
return NULL;
}
fp = fdopen(fd, "r"); /* open fp just for reading */
/* Comment from Alan Emtage of Bunyip Information Systems which explains
why I'm treating the writing end as a raw file descriptor and the
reading end through the stdio library:
From: bajan@bunyip.com (Alan Emtage)
Date: Sat, 28 Aug 1993 10:01:32 -0400
Hi Steve,
You have a comment in the gopher GW code to the effect that "this
experiment didn't work.... if you know why, tell me". Well I will :-)
For some reason which I haven't figured out, you can't a _socket_ file
descriptor with fdopen in any form of update mode (you were trying to do
it with "r+"). However it can be done if you open the fd _twice_. One
FILE * for reading one for writing. Then everything works fine. What is
going on in the underlying layers I don't know, but I'd bet that the
symptoms you got was that you were reading things that you had
previously written to the FILE * (and thought had just gone down the
pipe to the remote connection).
Hope this helps.
-Alan
*/
perrno = PSUCCESS;
while (gl = quick_next_menu_item(fp,timeout)) {
if (++nlinks > MAX_NUM_GOPHER_LINKS) {
perrno = DIRSRV_TOO_MANY;
gllfree(retval);
fclose(fp);
return NULL;
}
APPEND_ITEM(gl, retval);
}
fclose(fp);
redo_close3:
if(close(fd) == -1 && errno == EINTR) goto redo_close3;
if (perrno != PSUCCESS) {
gllfree(retval);
return(NULL); /* Return error code from next_menu_item*/
}
return retval;
}
#if 0
/* This client opens a TCP stream to the host/port & returns a FILE pointer. */
/* Returns NULL on failure; sets p_err_string */
FILE *
fopen_stream(char *host, int port)
{
int fd = quick_open_tcp_stream(host, port, G_OPEN_TIMEOUT);
if (fd < 0)
return NULL;
return fdopen(fd, "r+");
}
#endif
/* Reads the next valid menu item from the stream FP. Returns NULL if
no more, or if more than 3 erroneous lines go by. If a line is sent
longer than 1024 characters, it is definitely illegal according to the
Gopher spec, which requests no more than 255 chars for the selector and 80
for the description. */
/* Need to work on the error reporting. */
static GLINK
quick_next_menu_item(FILE * fp, int timeout)
{
GLINK r;
char buf[1024];
int buflen; /* # of characters in this buffer. */
int nbad = 0;
again:
if (nbad > 3)
return NULL;
if (!quick_fgets(buf, sizeof buf, fp, timeout)) {
if (errno = ETIMEDOUT) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Timed out after %d secs waiting for response", timeout);
perrno = DIRSRV_GOPHER;
return NULL;
}
assert(FALSE);
}
buflen = strlen(buf);
if (sizeof buf - 1 == buflen) { /* line too long; missed CRLF */
++nbad;
goto again;
}
r = glalloc();
/* The standard specifies a trailing CR, but apparantly
e.g. archive.egr.msu.edu(70) this is not guarranteed */
assert(buf[buflen -1] == '\n');
if (buf[buflen - 1] == '\n')
buf[--buflen] = '\0';
if (buf[buflen - 1] == '\r')
buf[--buflen] = '\0';
/* Check for end of menu */
if (strequal(buf, ".")) {
glfree(r);
return NULL; /* the end has been spotted. */
}
#if 0
if (qsscanf(buf, "%c%&[^\t]%*1[\t]%&(^\t)%*1[\t]%&[^\t]%*1[\t]%d",
&r->type, &r->name, &r->selector, &r->host, &r->port) < 5) {
/* Note that %&( is not yet implemented, so we're doing it this way
instead. */
#else
if ((qsscanf(buf, "%c%&[^\t]%*1[\t]%&[^\t]%*1[\t]%&[^\t]%*1[\t]%d",
&r->type, &r->name, &r->selector, &r->host, &r->port) < 5)
&& ((r->selector = stcopyr("", r->selector)),
(qsscanf(buf, "%c%&[^\t]%*1[\t]%*1[\t]%&[^\t]%*1[\t]%d",
&r->type, &r->name, &r->host, &r->port) < 4))) {
#endif
++nbad;
p_warn_string = qsprintf_stcopyr(p_warn_string,
"Encountered unrecognized Gopher message: %s", buf);
pwarn = PWARNING;
glfree(r);
goto again;
}
nbad = 0;
/* Some special cases, for error messages that appear to be menus */
if(strncmp(r->name,"Server error",12) == 0) {
p_err_string = qsprintf_stcopyr(p_err_string,r->name);
perrno = DIRSRV_GOPHER;
return NULL;
}
r->protocol_mesg = stcopy(buf);
return r;
}
static VLINK gltovl(GLINK gl);
static void add_collation_order(int linknum, VLINK vl);
/* It is ok to modify the GLINKs, as long as glist is left at the head of a
list of stuff to be freed with gllfree() by the caller of this function.
A lot of the hair in this function is here because we must make sure that
Gopher replicas are returned as Prospero replicas. For now, the only way to
make sure two objects are treated as replicas is for them to be links with
the same positive ID REMOTE value. */
static void
glinks_to_dirob(GLINK glist, P_OBJECT ob)
{
int menu_entry_number = 0; /* # of menu entries read */
int replica_list = 0; /* nonzero if handling replica list */
long current_magic_no = 0L; /* set magic starting hash */
VLINK vl = NULL; /* last vlink processed */
GLINK gl; /* index */
for (gl = glist; gl; gl = gl->next) {
/* If we found this link is a replica, put a magic # on the head of the
list. */
if (!replica_list && gl->type == '+') {
if (!vl)
continue; /* no previous gopher link for this to be a
replica of; perhaps we could not convert the
gopher link to a virtual link. */
if (!current_magic_no)
current_magic_no = generate_magic(vl);
while (magic_no_in_list(++current_magic_no, ob->links)) {
/* Check for numeric overflow */
if (current_magic_no <= 0)
current_magic_no = 1;
}
vl->f_magic_no = ++current_magic_no; /* new magic no */
}
if (gl->type != '+')
replica_list = 0;
else {
assert(gl->previous);
gl->type = gl->previous->type; /* gets type from head of list. */
}
if ((vl = gltovl(gl)) == NULL) {
replica_list = 0; /* break the chain of replicas */
continue; /* can't convert it */
}
if (replica_list) {
vl->f_magic_no = current_magic_no;
add_collation_order(menu_entry_number, vl);
} else {
add_collation_order(++menu_entry_number, vl);
}
APPEND_ITEM(vl, ob->links);
}
}
#ifdef NEVERDEFINED
/* I intend using this to return attributes for GIET-OBJECT-INFO calsl
but I need docs on what to return first */
/* Converts a hsoname back to a gl */
static GLINK
hsoname2gl(char *hsoname)
{
GLINK gl = glalloc();
tmp = qsscanf(hsoname, "GOPHER-GW/%&[^(](%d)/%c/%r",
&gl->host, &gl->port, &gl->type, &gl->selectorcp);
switch (&gl->type) {
'0': if (tmp < 4) goto hsoname2gl_bad;
break;
'1': if (tmp < 4) goto hsoname2gl_bad;
break;
'7': if (tmp < 3) goto hsoname2gl_bad;
break;
default:
return NULL; /* Unsupported type */
}
/* name,selector,protocol_mesg arent set by this */
return gl;
hsoname2gl_bad:
glfree(gl);
return gl;
}
#endif
/* Returns NULL if couldn't convert the gopher link GL to a Prospero link VL.
Otherwise returns a new VLINK. */
static VLINK
gltovl(GLINK gl)
{
VLINK r = vlalloc();
PATTRIB at;
/* check if something is an AFTP link. If so, handle it appropriately.*/
/* add AFTP Access method */
r->name = gl->name;
gl->name = NULL;
atput(r, "GOPHER-MENU-ITEM", gl->protocol_mesg, (char *) 0);
switch (gl->type) {
case '0': /* Text files */
case 'c': /* Calendar Text files (not in RFC1436) */
case 'e': /* Event Text files (not in RFC1436) */
/* This comes first because, in the current client implementation,
the server is expected to return access methods in what it believes
the preferred order is. We prefer direct AFTP connections to
overloading the intermediary Gopher gateways. */
r->target = stcopyr("EXTERNAL", r->target);
ftp_check_am(gl, r, "TEXT");
atput(r, "ACCESS-METHOD", "GOPHER", "", "", "", "", "TEXT",
(char *) 0);
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
r->hsoname = gl->selector;
gl->selector = NULL;
atput(r, "OBJECT-INTERPRETATION", "DOCUMENT", "TEXT", "ASCII",
(char *) 0);
break;
case '1': /* Directories */
r->host = stcopy(hostwport);
r->target = stcopyr("DIRECTORY", r->target);
r->hsoname = qsprintf_stcopyr(r->hsoname,
"GOPHER-GW/%s(%d)/%c/%s", gl->host,
gl->port, gl->type, gl->selector);
atput(r, "OBJECT-INTERPRETATION", "DIRECTORY", (char *) 0);
ftp_check_dir(gl, r);
break;
case '4': /* Macintosh BinHex (.hqx) text file */
r->target = stcopyr("EXTERNAL", r->target);
ftp_check_am(gl, r, "TEXT");
atput(r, "ACCESS-METHOD", "GOPHER", "", "", "", "", "TEXT",
(char *) 0);
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
r->hsoname = gl->selector;
gl->selector = NULL;
atput(r, "OBJECT-INTERPRETATION", "EMBEDDED", "BINHEX", "DATA",
(char *) 0);
break;
case '5': /* PC-Dos binary files. */
case '9': /* Generic binary files */
r->target = stcopyr("EXTERNAL", r->target);
ftp_check_am(gl, r, "BINARY");
atput(r, "ACCESS-METHOD", "GOPHER", "", "", "", "", "BINARY",
(char *) 0);
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
r->hsoname = gl->selector;
gl->selector = NULL;
atput(r, "OBJECT-INTERPRETATION", "DATA", (char *) 0);
break;
case '6': /* UNIX UUencoded file. */
r->target = stcopyr("EXTERNAL", r->target);
ftp_check_am(gl, r, "TEXT");
atput(r, "ACCESS-METHOD", "GOPHER", "", "", "", "", "TEXT",
(char *) 0);
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
r->hsoname = gl->selector;
gl->selector = NULL;
atput(r, "OBJECT-INTERPRETATION", "EMBEDDED", "UUENCODE", "DATA",
(char *) 0);
break;
case '7': /* Gopher searches */
r->target = stcopyr("DIRECTORY", r->target);
r->host = stcopy(hostwport);
atput(r, "OBJECT-INTERPRETATION", "SEARCH", (char *) 0);
#ifdef PSRV_WAIS_GW
/* wais_check_dir() rewrites wais searches as appropriate, and
reformats the link to be a WAIS one. */
if (wais_check_dir(gl, r))
break; /* done */
#endif
/* Write the link as a gopher search link. */
r->hsoname =
qsprintf_stcopyr(r->hsoname, "GOPHER-GW/%s(%d)/7/%s",
gl->host, gl->port, gl->selector);
atput(r, "QUERY-METHOD", "gopher-query(search-words)",
"${search-words}", "", (char *) 0);
atput(r, "QUERY-ARGUMENT", "search-words",
"Index word(s) to search for", "mandatory char*", "%s", "",
(char *) 0);
atput(r, "QUERY-DOCUMENTATION", "gopher-query()", "This is a Gopher \
protocol query exported through Prospero. Since it is not a native Prospero \
query, we have very little documentation available for you.", (char *) 0);
atput(r, "QUERY-DOCUMENTATION", "search-words", "This string says \
what you're searching for or what information you're specifying.",
"Type any string. Sometimes SPACEs are treated as implied \
'and' operators. Sometimes the words 'and', 'or', and 'not' are recognized \
as boolean operators.", (char *) 0);
break;
case '8':{ /* TELNET session */
char *m = ""; /* message */
r->target = stcopyr("EXTERNAL", r->target);
if (*(gl->selector))
m = qsprintf_stcopyr((char *) NULL,
"Use the account name \"%s\" to log in",
gl->selector);
atput(r, "ACCESS-METHOD", "TELNET", "", "", "", "", m, (char *) 0);
zap_trailing_spaces(gl->host);
/* Gopher uses a telnet port of 0 to mean the default telnet port. */
if (gl->port == 0) {
r->host = gl->host;
gl->host = NULL;
} else {
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
}
atput(r, "OBJECT-INTERPRETATION", "PORTAL", (char *) 0);
if (*m)
stfree(m);
break;
}
case 'I': /* Generic Image. */
case ':': /* Gopher+ bitmap image type; not in RFC1436 */
r->target = stcopyr("EXTERNAL", r->target);
ftp_check_am(gl, r, "BINARY");
atput(r, "ACCESS-METHOD", "GOPHER", "", "", "", "", "BINARY",
(char *) 0);
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
r->hsoname = gl->selector;
gl->selector = NULL;
atput(r, "OBJECT-INTERPRETATION", "IMAGE", (char *) 0);
break;
case 'M': /* MIME. Not in RFC1436. */
r->target = stcopyr("EXTERNAL", r->target);
ftp_check_am(gl, r, "TEXT");
atput(r, "ACCESS-METHOD", "GOPHER", "", "", "", "", "TEXT", (char *) 0);
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
r->hsoname = gl->selector;
gl->selector = NULL;
atput(r, "OBJECT-INTERPRETATION", "DOCUMENT", "MIME", (char *) 0);
break;
case 'T':{ /* TN3270 session */
char *m = ""; /* message */
r->target = stcopyr("EXTERNAL", r->target);
zap_trailing_spaces(gl->host);
/* Gopher uses a telnet port of 0 to mean the default telnet port. */
if (gl->port == 0) {
r->host = gl->host;
gl->host = NULL;
} else {
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
}
if (*(gl->selector))
m = qsprintf_stcopyr((char *) NULL,
"Use the account name \"%s\" to log in",
gl->selector);
atput(r, "ACCESS-METHOD", "TN3270", "", "", "", "", m, (char *) 0);
atput(r, "OBJECT-INTERPRETATION", "PORTAL", (char *) 0);
if (*m)
stfree(m);
break;
}
case 'g': /* Gif */
r->target = stcopyr("EXTERNAL", r->target);
ftp_check_am(gl, r, "BINARY");
atput(r, "ACCESS-METHOD", "GOPHER", "", "", "", "", "BINARY",
(char *) 0);
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
r->hsoname = gl->selector;
gl->selector = NULL;
atput(r, "OBJECT-INTERPRETATION", "IMAGE", "GIF", (char *) 0);
break;
case 's': /* SOUND. Not in RFC1436. */
case '<': /* Gopher+ sound type; not in RFC1436 */
r->target = stcopyr("EXTERNAL", r->target);
ftp_check_am(gl, r, "BINARY");
atput(r, "ACCESS-METHOD", "GOPHER", "", "", "", "", "BINARY",
(char *) 0);
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
r->hsoname = gl->selector;
gl->selector = NULL;
atput(r, "OBJECT-INTERPRETATION", "SOUND", (char *) 0);
break;
case 'i': /* the uncommon i type exists in the University
of Iowa gopher variant, Panda. */
r->name = gl->name;
gl->name = NULL;
r->target = stcopyr("NULL", r->target);
r->hosttype = stcopyr("NULL", r->hosttype);
r->host = stcopyr("NULL", r->host);
r->hsonametype = stcopyr("NULL", r->hsonametype);
r->hsoname = stcopyr("NULL", r->hsoname);
r->target = stcopyr("NULL", r->target);
atput(r, "OBJECT-INTERPRETATION", "VOID", (char *) 0);
break;
case ';': /* Gopher+ MOVIE type. It is not at all clear
whether this is being used yet.*/
r->target = stcopyr("EXTERNAL", r->target);
ftp_check_am(gl, r, "BINARY");
atput(r, "ACCESS-METHOD", "GOPHER", "", "", "", "", "BINARY",
(char *) 0);
r->host = qsprintf_stcopyr(r->host, "%s(%d)", gl->host, gl->port);
r->hsoname = gl->selector;
gl->selector = NULL;
atput(r, "OBJECT-INTERPRETATION", "VIDEO", (char *) 0);
break;
case '.': /* End of directory. */
goto ignore;
break; /* go on */
case '2': /* CSO nameserver; No gateway (yet) */
p_warn_string = qsprintf_stcopyr(p_warn_string,
"Encountered gopher link to CSO nameserver; we don't support \
this type yet: %s", gl->protocol_mesg);
pwarn = PWARNING;
goto ignore;
break;
case '3': /* Mitra thinks the error type should be
ignored. I am willing to go along with
this, given that the standard UNIX Gopher
client ignores it. */
goto ignore;
break;
case 'w': /* whois server */
p_warn_string = qsprintf_stcopyr(p_warn_string,
"Encountered gopher link to WHOIS server; we don't support \
this type yet: %s", gl->protocol_mesg);
case '-': /* error message type? */
default: /* unknown type or type we can't process */
p_warn_string = qsprintf_stcopyr(p_warn_string,
"Encountered unrecognized Gopher message: %s",
gl->protocol_mesg);
pwarn = PWARNING;
ignore:
vlfree(r);
r = NULL;
break;
}
return r;
}
/* Check if we're an AFTP link. If so, add an AFTP access method. */
/* This check should be made before other access methods are added.
The server is expected to return access methods in what it believes the
preferred order is. We prefer direct AFTP connections to overloading the
intermediary Gopher gateways. */
/* Gopher AFTP links to files use the HSONAME format:
ftp:<aftp-hostname>@/file-path (no trailing slash) */
static void
ftp_check_am(GLINK gl, VLINK r, char *textorbin)
{
static char *ftp_hostname = NULL;
char *ftp_rest; /* rest of string */
if (qsscanf(gl->selector, "ftp:%&[^@]@%r", &ftp_hostname, &ftp_rest) == 2) {
int len = strlen(ftp_rest);
if (ftp_rest[len - 1] != '/')
atput(r, "ACCESS-METHOD", "AFTP", "", ftp_hostname, "", ftp_rest,
textorbin, (char *) 0);
}
}
/* Check if we're an AFTP link. If so, rewrite the HOST and HSONAME to go
through the Prospero server at ARCHIE_SERVER (this can be changed). */
/* Gopher AFTP links to directories use the HSONAME format:
ftp:<aftp-hostname>@/directory.../ */
static void
ftp_check_dir(GLINK gl, VLINK r)
{
static char *ftp_hostname = NULL;
int len;
char *ftp_rest; /* rest of string */
if (qsscanf(gl->selector, "ftp:%&[^@]@%r", &ftp_hostname, &ftp_rest) == 2
#if 0
/* Commented out, doesnt need to be / after @ if gatewaying thru gopher*/
&& *ftp_rest == '/'
#endif
) {
len = strlen(ftp_rest);
if (ftp_rest[len - 1] == '/') {
#if 0 /* commented out because of problem:not all
archie servers index all AFTP sites. */
#ifdef ARCHIE_SERVER
ftp_rest[len - 1] = '\0';
r->host = stcopyr(ARCHIE_SERVER, r->host);
r->hsoname = qsprintf_stcopyr(r->hsoname, "ARCHIE/HOST/%s%s",
ftp_hostname, ftp_rest);
#endif
#endif
#ifdef GOPHER_GW_NEARBY_GOPHER_SERVER
r->hsoname = qsprintf_stcopyr(r->hsoname,
"GOPHER-GW/%s/1/ftp:%s@%s", GOPHER_GW_NEARBY_GOPHER_SERVER,
ftp_hostname, ftp_rest);
#endif
}
}
}
#ifdef PSRV_WAIS_GW
static int
wais_check_dir(GLINK gl, VLINK r)
{
char *w_db = NULL; /* Pointer into gl->selector e.g. zzz */
char *w_path = NULL; /* Pointer into gl->selector e.g. xxx/yyy/zzz */
AUTOSTAT_CHARPP(w_db_srcp); /* e.g. zzz.src */
char *cp = NULL; /* temporary pointer */
WAISSOURCE thissource; /* Points to source structure */
if (qsscanf(gl->selector, "waissrc:%r", &w_path) != 1) {
return FALSE;
}
if ((w_db = strrchr(w_path, '/')) == NULL) {
w_db = w_path;
} else {
w_db++;
}
if ((cp = strstr(w_db, ".src")) == NULL) {
*w_db_srcp = qsprintf_stcopyr(*w_db_srcp, "%s%s", w_db, ".src");
} else {
*w_db_srcp = stcopyr(w_db, *w_db_srcp); /* *w_db_srcp = zzz.src */
}
/*!! Open and parse local src file */
/* While this may s_alloc the source DONT free it, its on
a linked list of sources which persists while the server is up*/
if ((thissource = findsource(*w_db_srcp, WAIS_SOURCE_DIR)) == NULL)
return FALSE;
if ((cp = strstr(w_db, ".src")) != NULL) {
/* Need to do this AFTER findsource, otherwise can modify gl->selector
of non matching source */
cp[0] = '\0'; /* w_db = zzz */
}
r->hsoname = qsprintf_stcopyr(r->hsoname, "WAIS-GW/%s(%s)/QUERY/%s",
thissource->server, thissource->service, w_db);
if (thissource->subjects)
atput(r, "WAIS-SUBJECTS", thissource->subjects, (char *) 0);
if (thissource->cost)
atput(r, "WAIS-COST-NUM", thissource->cost, (char *) 0);
if (thissource->units)
atput(r, "WAIS-COST-UNIT", thissource->units, (char *) 0);
if (thissource->maintainer)
atput(r, "WAIS-COST-MAINTAINER", thissource->maintainer, (char *) 0);
atput(r, "QUERY-METHOD", "wais-query(search-words)",
"${search-words}", "", (char *) 0);
atput(r, "QUERY-ARGUMENT", "search-words",
"Index word(s) to search for", "mandatory char*", "%s", "",
(char *) 0);
if (thissource->description)
atput(r, "QUERY-DOCUMENTATION", "wais-query()",
thissource->description, (char *) 0);
atput(r, "QUERY-DOCUMENTATION", "search-words", "This string says \
what you're searching for or what information you're specifying.",
"Type any string. Sometimes SPACEs are treated as implied \
'and' operators. Sometimes the words 'and', 'or', and 'not' are recognized \
as boolean operators.", (char *) 0);
return (TRUE);
}
#endif
static void
zap_trailing_spaces(char *host)
{
int len = strlen(host);
while (--len >= 0) {
if (host[len] == ' ')
host[len] = '\0';
else
break;
}
}
/* Add a collation-order attribute of the form NUMERIC <linknum> to the link
VL */
static void
add_collation_order(int linknum, VLINK vl)
{
PATTRIB ca = atalloc();
char buf[40]; /* long enough to hold the ASCII
representation of any int for the
foreseeable future. */
ca->precedence = ATR_PREC_LINK;
ca->nature = ATR_NATURE_APPLICATION;
ca->avtype = ATR_SEQUENCE;
ca->aname = stcopy("COLLATION-ORDER");
ca->value.sequence = tkappend("NUMERIC", ca->value.sequence);
assert(qsprintf(buf, sizeof buf, "%d", linknum) <= sizeof buf);
ca->value.sequence = tkappend(buf, ca->value.sequence);
APPEND_ITEM(ca, vl->lattrib);
}
static void
atput(VLINK vl, char *name,...)
{
va_list ap;
char *s;
PATTRIB at = atalloc();
va_start(ap, name);
at->aname = stcopy(name);
at->avtype = ATR_SEQUENCE;
if (strequal(name, "ACCESS-METHOD"))
at->nature = ATR_NATURE_FIELD;
else
at->nature = ATR_NATURE_APPLICATION;
if (strequal(vl->target, "EXTERNAL"))
at->precedence = ATR_PREC_REPLACE; /* still not clear what to use */
else
at->precedence = ATR_PREC_OBJECT;
while (s = va_arg(ap, char *)) {
at->value.sequence =
tkappend(s, at->value.sequence);
}
APPEND_ITEM(at, vl->lattrib);
va_end(ap);
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 1991-1994 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
#include <usc-license.h>
#include "gopher.h"
#include <pfs.h>
#include <pfs_threads.h>
/* This file is used by lib/psrv. So libpgoph_gw.a should follow psrv. */
#ifdef PFS_THREADS
p_th_mutex p_th_mutexGLINK; /* declaration */
#endif
void
gopher_gw_init_mutexes(void)
{
#ifdef PFS_THREADS
p_th_mutex_init(p_th_mutexGLINK);
#endif
}
#ifndef NDEBUG
void
gopher_gw_diagnose_mutexes(void)
{
printf("{gopher_gw_init_mutexes ");
#ifdef PFS_THREADS
DIAGMUTEX(GLINK,"GLINK");
#endif
printf("}");
}
#endif /*NDEBUG*/

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-copyr.h>.
*/
#include <usc-copyr.h>
#include <pfs_threads.h>
struct glink {
#ifdef ALLOCATOR_CONSISTENCY_CHECK
int consistency;
#endif
char type;
char *name;
char *selector;
char *host;
int port;
char *protocol_mesg; /* raw item description -- the Gopher
protocol message. */
struct glink *previous;
struct glink *next;
};
typedef struct glink *GLINK;
typedef struct glink GLINK_ST;
extern GLINK glalloc(void);
extern void glfree(GLINK);
extern void gllfree(GLINK);
#ifdef PFS_THREADS
extern p_th_mutex p_th_mutexGLINK; /* declared in goph_gw_mutex.c */
#endif

39
prospero/lib/psrv/magic.c Normal file
View File

@@ -0,0 +1,39 @@
/*
* 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 <pfs.h> /* assert, internal_error, prototypes */
/* Generate a unique magic number (positive long). This is based upon hashing
the vlink VL's HSONAME field. */
long
generate_magic(VLINK vl)
{
long retval = 0L;
int n = p_bstlen(vl->hsoname);
int rvoffset = 0; /* offset for xoring with the return value. */
while(n--) {
rvoffset += 8;
if (rvoffset >= 8 * sizeof retval) rvoffset = 0;
retval ^= ((vl->hsoname[n]) << rvoffset);
}
if (retval < 0) return ~retval;
if (retval == 0) return 1;
return retval;
}
/* Is the magic number MAGIC anywhere in use in the list of vlinks LINKS? */
int
magic_no_in_list(long magic, VLINK links)
{
for ( ;links ; links = links->next) {
if (links->f_magic_no == magic) return TRUE;
}
return FALSE;
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file <usc-copyr.h>
*/
#include <usc-copyr.h>
#include <stdio.h>
#include <string.h>
#include <pfs.h>
#include <perrno.h>
#include <psrv.h>
#include <plog.h>
extern char security[]; /* full pathname of security directory. */
#define NAMED_ACL_SECURITY_SUBDIR "named" /* subdirectory of security for named
ACLs. */
/* Get a named ACL with a name from the database, or write it. */
/* Returns: DIRSRV_NOT_FOUND, PFAILURE, or PSUCCESS */
static void set_cached_named_acl(char *aclname, ACL wacl);
static int get_cached_named_acl(char *aclname, ACL *waclp);
extern int
get_named_acl(char *t_name, ACL *waclp)
{
AUTOSTAT_CHARPP(filenamep);
INPUT_ST in_st;
INPUT in = &in_st;
int tmp;
FILE *fp;
if(get_cached_named_acl(t_name, waclp) == PSUCCESS)
return PSUCCESS;
*waclp = NULL; /* start off empty */
*filenamep = qsprintf_stcopyr(*filenamep, "%s/%s/%s", security,
NAMED_ACL_SECURITY_SUBDIR, t_name);
fp = locked_fopen(*filenamep, "r");
if (!fp) return DIRSRV_NOT_FOUND;
if (wholefiletoin(fp, in)) {
plog(L_DIR_ERR,NOREQ,"%s",p_err_string);
locked_fclose_A(fp,*filenamep,TRUE);
RETURNPFAILURE;
}
tmp = in_acl(in, waclp);
if(tmp)
plog(L_DATA_FRM_ERR, NOREQ, "Bad NAMED ACL info format %s: %s",
*filenamep, p_err_string);
if (locked_fclose_A(fp,*filenamep, TRUE) && !tmp) {
plog(L_DATA_FRM_ERR, NOREQ, "Error closing NAMED ACL file %s",
*filenamep);
RETURNPFAILURE;
}
if (tmp) RETURNPFAILURE;
return PSUCCESS;
}
/* Returns: PFAILURE, or PSUCCESS */
extern int
set_named_acl(char *t_name, ACL wacl)
{
AUTOSTAT_CHARPP(filenamep);
AUTOSTAT_CHARPP(tmpfilenamep);
FILE *fp;
OUTPUT_ST out_st;
OUTPUT out = &out_st;
set_cached_named_acl(t_name, wacl);
*filenamep = qsprintf_stcopyr(*filenamep, "%s/%s/%s", security,
NAMED_ACL_SECURITY_SUBDIR, t_name);
*tmpfilenamep = qsprintf_stcopyr(*tmpfilenamep, "%s.TMP", *filenamep);
filelock_obtain(*filenamep,FALSE); /* Obtain write lock on rel dir */
fp = locked_fopen(*tmpfilenamep, "w");
if (!fp) {
char *sp;
/* couldn't open file for writing. Maybe a subdirectory needs to be
created? This could happen if there's a slash in the named acl or
if the security directory wasn't created yet. */
sp = strrchr(*tmpfilenamep, '/');
if (sp) {
*sp = '\0';
mkdirs(*tmpfilenamep);
*sp = '/';
fp = locked_fopen(*tmpfilenamep, "w");
}
if (!fp) {
filelock_release(*filenamep,FALSE);
return(PFAILURE);
}
}
filetoout(fp, out);
out_acl(out, wacl);
return(locked_fclose_and_rename(fp, *tmpfilenamep,*filenamep,FALSE));
}
static void
set_cached_named_acl(char *aclname, ACL wacl)
{
}
static int
get_cached_named_acl(char *aclname, ACL *waclp)
{
RETURNPFAILURE; /* does nothing for now. */
}

View File

@@ -0,0 +1,133 @@
/* optparse.c */
/*
* Copyright (c) 1992 by the University of Southern California
*
* For copying and distribution information, please see the file <usc-copyr.h>
*/
/* Ground out by swa@isi.edu */
#include <usc-copyr.h>
#include <pfs.h>
#include <pparse.h>
#include <psrv.h>
#include <perrno.h>
#include <stdlib.h> /* For malloc and free */
#ifndef NULL
#define NULL 0
#endif
#if 0
static OPT free = NULL;
#endif
int opt_count = 0;
int opt_max = 0;
#if 0 /* XXX Options parsing isn't great; but it
turns out that we don't need to get fancy
yet. What we have will suffice.*/
/* Initialize option parsing. Feed it an unquoted string containing a
+ or , -separated list of options. It assumes that it may freely overwrite
the string, and make memory references to it. */
OPT
#ifdef __STDC__
optparse(char *optionstr)
#else
optparse(optionstr)
char *optionstr;
#endif
{
extern int perrno;
perrno = PSUCCESS;
OPT retval = NULL;
while(*optionstr) {
OPT nopt = optalloc();
char buf[MAX_DIR_LINESIZE];
char *bufp;
}
}
static struct opt *
optalloc(char * name)
{
OPT retval;
if (free) {
retval = free;
free = free->next;
} else {
retval = malloc(sizeof (OPT_ST));
if (!retval) return NULL;
++opt_max;
}
++opt_count;
retval->name= name;
retval->used = 0;
retval->args = NULL;
retval->argstring = NULL;
retval->next = NULL;
return retval;
}
static
#ifdef __STDC__
optfree(OPT opt)
#else
optfree(opt)
OPT opt;
#endif
{
optlfree(opt->args);
free(opt);
}
void
#ifdef __STDC__
optlfree(OPT opts)
#else
optlfree(opts)
OPT opts;
#endif
{
while (opts) {
nextop = opts->next;
optfree(opts);
opts = nextop;
}
}
int
optquery(opts, optname)
OPT opts;
char optname[];
{
}
/* # of arguments to the option. 0 if none specified. */
int
optnargs(opts, optname)
OPT opts;
char optname[];
{
}
/* Any options which haven't been queried yet. Check for leftovers!
This needs to be freed.
*/
OPT
optremaining()
{
}
#endif

350
prospero/lib/psrv/plog.c Normal file
View File

@@ -0,0 +1,350 @@
/*
* Copyright (c) 1991-1994 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*
* Credits: Originally written by Clifford Neuman (University of Washington)
* Syslog support added by Jonathan Kamens (MIT Project Athena)
* Much code mangling by Steven Augart (USC/ISI)
*/
#include <usc-license.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdarg.h>
#include <ardp.h>
#include <pfs.h>
#include <pserver.h>
#include <plog.h>
#include <pmachine.h>
/* This definition has to be after pmachine.h so that SCOUNIX gets defined */
#if defined(AIX) || defined (SCOUNIX)
#include <time.h>
#endif
#define logfile P_logfile /* So as not to conflict with WAIS variable --- bajan */
/* this array contains info on the type of entries to be printed */
static int logtype_array[NLOGTYPE+1] = INITIAL_LOG_VECTOR;
/* info on the filename and open file */
static char *log_name = PSRV_LOGFILE;
FILE *logfile;
static int is_open = 0; /* Mutexed below */
#if 0
/* not currently used */
static int syslog_open = 0;
#endif
static char *pr_inet_ntoa();
static FILE *plog_additional_outfile = NULL;
/*VARARGS4*/
/*
* plog - Add entry to logfile
*
* PLOG is used to add entries to the logfile. Note that
* it is probably not portable since is makes assumptions
* about what the compiler will do when it is called with
* less than the correct number of arguments which is the
* way it is usually called.
*
* PLOG returns a pointer to the logged entry. If an error
* occurs, vlog returns immediately, but does not indicate
* that the log operating failed.
*
* ARGS: type - Type of entry (to decide if we should log it)
* req - Pointer to request info including host address,
* and useride. (NULL if should not be printed)
* format - Format as for qsprintf
* remaining arguments -- as for qsprintf
* RETURNS: Pointer to a string containing the log entry
*
* BUGS: The non-ANSI implementation is not portable. It should really use
* another mechanism to support a variable number of arguments.
* Unfortunately, these mechanisms are not easily available.
*
* Currently, the log file is opened and closed on each
* call.
*/
EXTERN_MUTEX_DECL(PSRV_LOG);
/* Call this if mutexed, but not open */
#define LEAVEOPEN 1
char *
vplog(int type, RREQ req, char *format, va_list ap)
{
time_t now, systime, svctime, wttime;
int log_username = 0;
int notfirstfield = 0;
char *month_sname();
char usertxt[MXPLOGENTRY];
char fieldtxt[MXPLOGENTRY];
AUTOSTAT_CHARPP(logtxtp);
CHECK_MEM();
*logtxtp = vqsprintf_stcopyr(*logtxtp, format, ap);
/* If we don't log this type of message, don't write to log */
if (!logtype_array[type])
return(*logtxtp);
/* get the time */
#ifndef NDEBUG
{ int retval =
#endif
time(&now);
#ifndef NDEBUG
assert(retval != -1);
}
#endif
svctime = systime = wttime = 0;
if(req) {
if(req->rcvd_time.tv_sec)
wttime = systime = now - req->rcvd_time.tv_sec;
if(req->svc_start_time.tv_sec) {
svctime = now - req->svc_start_time.tv_sec;
wttime = req->svc_start_time.tv_sec - req->rcvd_time.tv_sec;
}
}
if ((type == L_QUEUE_COMP) && (systime < L_COMP_SYS_THRESHOLD))
return(*logtxtp);
if ((type == L_QUEUE_COMP) && (svctime < L_COMP_SVC_THRESHOLD))
return(*logtxtp);
*usertxt = '\0';
if(req && req->peer_addr.s_addr &&(logtype_array[L_FIELDS]&L_FIELDS_HADDR))
strncat(usertxt, pr_inet_ntoa(req->peer_addr.s_addr),sizeof(usertxt));
if(type == L_DIR_UPDATE) {
if(logtype_array[L_FIELDS] & L_FIELDS_USER_U) log_username++;
}
else if(type == L_DIR_REQUEST) {
if(logtype_array[L_FIELDS] & L_FIELDS_USER_R) log_username++;
}
else if(logtype_array[L_FIELDS] & L_FIELDS_USER_I) log_username++;
if(req && req->client_name && *(req->client_name) && log_username) {
strncat(usertxt, "(",sizeof(usertxt));
strncat(usertxt, req->client_name,sizeof(usertxt));
strncat(usertxt, ")",sizeof(usertxt));
}
if(req && req->peer_sw_id && *(req->peer_sw_id) &&
(logtype_array[L_FIELDS] & L_FIELDS_SW_ID)) {
strncat(usertxt, "[",sizeof(usertxt));
strncat(usertxt, req->peer_sw_id,sizeof(usertxt));
strncat(usertxt, "]",sizeof(usertxt));
}
if(req && (logtype_array[L_FIELDS] & L_FIELDS_PORT)){
qsprintf(fieldtxt, sizeof fieldtxt, "[udp/%d]", PEER_PORT(req));
strncat(usertxt, fieldtxt,sizeof(usertxt));
}
if(req && req->cid &&(logtype_array[L_FIELDS] & L_FIELDS_CID)) {
qsprintf(fieldtxt, sizeof fieldtxt, "[cid=%d]", ntohs(req->cid));
strncat(usertxt, fieldtxt,sizeof(usertxt));
}
if(req && (logtype_array[L_FIELDS] & L_FIELDS_STIME) &&
((systime>=L_SYSTIME_THRESHOLD) || (svctime>=L_SVCTIME_THRESHOLD) ||
(wttime>=L_WTTIME_THRESHOLD))) {
strncat(usertxt, "[",sizeof(usertxt));
if(wttime >= L_WTTIME_THRESHOLD) {
if(notfirstfield++) strncat(usertxt, ",",sizeof(usertxt));
qsprintf(fieldtxt, sizeof fieldtxt, "%d:%02dwt", wttime / 60, wttime % 60);
strncat(usertxt, fieldtxt,sizeof(usertxt));
}
if(svctime >= L_SVCTIME_THRESHOLD) {
if(notfirstfield++) strncat(usertxt, ",",sizeof(usertxt));
qsprintf(fieldtxt, sizeof fieldtxt,
"%d:%02dsvc", svctime / 60, svctime % 60);
strncat(usertxt, fieldtxt,sizeof(usertxt));
}
if(systime >= L_SYSTIME_THRESHOLD) {
if(notfirstfield++) strncat(usertxt, ",",sizeof(usertxt));
qsprintf(fieldtxt, sizeof fieldtxt, "%d:%02dsys", systime / 60, systime % 60);
strncat(usertxt, fieldtxt,sizeof(usertxt));
}
strncat(usertxt, "]",sizeof(usertxt));
}
#ifdef P_LOGTO_SYSLOG
if(!syslog_open++) openlog("prospero",LOG_PID|LOG_ODELAY,LOG_PROSPERO);
if (logtype_array[type] & ~PLOG_TOFILE_ENABLED) {
syslog(logtype_array[type] & ~PLOG_TOFILE_ENABLED,
"%s%s%s", usertxt, (*usertxt ? " " : ""), *logtxtp);
}
#endif
/* If not printing to file return */
if (! (logtype_array[type] & PLOG_TOFILE_ENABLED)) return(*logtxtp);
#ifndef LEAVEOPEN
p_th_mutex_lock(p_th_mutexPSRV_LOG);
#endif
if (!is_open) {
#ifdef LEAVEOPEN
p_th_mutex_lock(p_th_mutexPSRV_LOG);
#endif
if (!is_open) { /* Check still open, now we have mutex*/
if ((logfile = fopen(log_name,"a")) != NULL) {
is_open = 1;
}
}
#ifdef LEAVEOPEN
p_th_mutex_unlock(p_th_mutexPSRV_LOG);
#endif
}
if (is_open) {
/* print the log entry */
AUTOSTAT_CHARPP(bufp);
#ifndef PFS_THREADS
struct tm *tm = localtime(&now);
#else
struct tm tmstruc;
struct tm *tm = &tmstruc;
localtime_r(&now, tm);
#endif
*bufp = qsprintf_stcopyr(*bufp, "%2d-%s-%02d %02d:%02d:%02d %s%s%s\n",
tm->tm_mday,
month_sname(tm->tm_mon + 1),tm->tm_year,
tm->tm_hour, tm->tm_min, tm->tm_sec,
usertxt, (*usertxt ? " - " : ""), *logtxtp);
#ifndef NDEBUG
{ /* variable scope start */
int retval =
#endif
fputs(*bufp, logfile);
#ifndef NDEBUG
assert(retval == strlen(*bufp));
} /* variable scope end */
#endif
}
/* even if the primary logfile couldn't be opened, go ahead and log to
the manual (additional) logfile. */
if(plog_additional_outfile) {
#if 0
/* This is old equivalent code. Leaving it in here just for historical
reasons -- no real reason to keep it, unless one is concerned about
runnuing out of memory. */
fprintf(plog_additional_outfile,
"%s%s%s\n", usertxt, (*usertxt ? " - " : ""), *logtxtp));
#else
AUTOSTAT_CHARPP(bufp);
*bufp = qsprintf_stcopyr(*bufp, "%s%s%s\n",
usertxt, (*usertxt ? " - " : ""), *logtxtp);
#ifndef NDEBUG
{ int retval =
#endif
fputs(*bufp, plog_additional_outfile);
#ifndef NDEBUG
assert(retval == strlen(*bufp));
}
#endif
#endif
zz(fflush(plog_additional_outfile)); /* must be zero */
}
#ifndef LEAVEOPEN
if (is_open) {
zz(fclose(logfile));
is_open = 0;
}
p_th_mutex_unlock(p_th_mutexPSRV_LOG);
#else
zz(fflush(logfile));
#endif /*LEAVEOPEN*/
return(*logtxtp);
}
char *
plog(int type, /* Type of log entry */
RREQ req, /* Optional info on request */
char *format, ...) /* format string */
{
char *retval;
va_list ap;
va_start(ap, format);
retval = vplog(type, req, format, ap);
va_end(ap);
return retval;
}
/*
* set_logfile - Change the name of the logfile
*
* SET_LOGFILE changes the name of the file to which
* messages are logged. If set_logfile is not called,
* the logfile defaults to PFSLOG.
*
* ARGS: filename - Name of new logfile
* Returns: success always
*/
/* Does not need to be mutexed; set only upon initialization */
int
set_logfile(char *filename)
{
assert(P_IS_THIS_THREAD_MASTER());
log_name = filename;
if(is_open) (void) fclose(logfile);
is_open = 0;
return(PSUCCESS);
}
static char *
pr_inet_ntoa(long a)
{
AUTOSTAT_CHARPP(astringp);
#if BYTE_ORDER == BIG_ENDIAN
*astringp = qsprintf_stcopyr(*astringp,"%d.%d.%d.%d",(a >> 24) & 0xff,
(a >> 16) & 0xff,(a >> 8) & 0xff, a & 0xff);
#else
*astringp = qsprintf_stcopyr(*astringp,"%d.%d.%d.%d", a & 0xff,
(a >> 8) & 0xff,(a >> 16) & 0xff,
(a >> 24) & 0xff);
#endif
return(*astringp);
}
void
close_plog(void)
{
if(is_open) fclose(logfile);
is_open = 0;
#ifdef P_LOGTO_SYSLOG
if(syslog_open) closelog();
syslog_open = 0;
#endif
}
void
plog_manual(FILE *outf)
{
plog_additional_outfile = outf;
}

261
prospero/lib/psrv/ppasswd.c Normal file
View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 1991-1994 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
#include <usc-license.h>
#include <pmachine.h> /* for SOLARIS */
#ifdef CRYPT_FUNCTION_PROTOTYPE_IN_CRYPT_H /* defined currently only
when SOLARIS is active. */
#include <crypt.h> /* Solaris: for the crypt() function. */
/* Note that the crypt() function is not part of the 1989 ANSI C standard,
nor in the 1990 POSIX 1 standard.
Therefore, different vendors will treat it differently. */
#endif
#include <stdio.h>
#include <pfs.h>
#include <pserver.h>
#include <errno.h>
#ifdef PSRV_P_PASSWORD
#include <ppasswd.h>
#include <perrno.h>
static int write_ppw_to_file();
static char *get_salt(void);
extern int pfs_debug;
/* Get password file entry for principal. Returns pointer to p_passwd */
/* structure if found, else returns NULL. */
p_passwd *
get_ppw_entry(char *principal)
{
FILE *passwd_fp;
char line[255];
char princ_name[255], encrypted_passwd[255];
p_passwd *p_pwd = NULL;
if (!(passwd_fp = locked_fopen(PSRV_PW_FILE, "r")))
return NULL;
while (fgets(line, sizeof(line), passwd_fp)) {
sscanf(line, "%s %s\n",
princ_name, encrypted_passwd);
if (!strcmp(princ_name, principal)) {
p_pwd = (p_passwd *) stalloc(sizeof(p_passwd));
p_pwd->principal = stcopy(princ_name);
p_pwd->encrypted_passwd = stcopy(encrypted_passwd);
}
}
(void) locked_fclose_A(passwd_fp,PSRV_PW_FILE, TRUE);
return p_pwd;
}
/* Write password entry in structure p_pwd to password file, */
/* overwriting old entry if one exists for the principal */
static int write_ppw_to_file(p_passwd *p_pwd)
{
FILE *passwd_fp;
char in_line[255], out_line[255];
char princ_name[255], encrypted_passwd[255];
long pos;
if (!(passwd_fp = locked_fopen(PSRV_PW_FILE, "r+"))) {
/* Cannot open password file, so create */
if (!(passwd_fp = locked_fopen(PSRV_PW_FILE, "w+"))) {
if (pfs_debug)
fprintf(stderr, "Cannot create file %s\n",
PSRV_PW_FILE);
RETURNPFAILURE;
}
if (chmod(PSRV_PW_FILE, 0600)) {
if (pfs_debug)
perror("Could not change permissions of passwd file");
locked_fclose_A(passwd_fp,PSRV_PW_FILE,FALSE);
RETURNPFAILURE;
}
fprintf(passwd_fp, "# Prospero Server Password File.\n");
fprintf(passwd_fp, "%-32s %-32s\n\n",
"# <principal>", "<encrypted password>");
fseek(passwd_fp, 0L, 1); /* To allow input after output */
}
/* Check if entry exists for principal */
while (pos = ftell(passwd_fp), /* Remember position of line */
fgets(in_line, sizeof(in_line), passwd_fp)) {
if (in_line[0] == '#')
continue;
sscanf(in_line, "%s %s\n",
princ_name, encrypted_passwd);
if (!strcmp(princ_name, p_pwd->principal)) {
/* Entry found; set file pointer to overwrite */
fseek(passwd_fp, pos, 0);
break;
}
}
/* If entry not found, write new entry to end of file, else overwrite */
fprintf(passwd_fp, "%-32s %-32s\n",
p_pwd->principal, p_pwd->encrypted_passwd);
(void) locked_fclose_A(passwd_fp,PSRV_PW_FILE,FALSE);
return PSUCCESS;
}
/* Set password for principal in password file, overwriting old */
/* entry if one exists. */
int
set_passwd(char *principal, char *passwd)
{
p_passwd p_pwd;
char *salt = get_salt();
p_pwd.principal = stcopy(principal);
p_pwd.encrypted_passwd = (char *) crypt(passwd, salt);
if (write_ppw_to_file(&p_pwd))
RETURNPFAILURE;
stfree(p_pwd.principal);
stfree(salt);
return PSUCCESS;
}
/* Returns TRUE if password specified for the principal matches */
/* password in entry for principal in password file, and FALSE */
/* otherwise */
int passwd_correct(char * principal, char *passwd)
{
p_passwd *p_pwd;
char *salt, *p;
int correct;
/* Get password file entry */
if (!(p_pwd = get_ppw_entry(principal)))
return FALSE;
/* Salt stored as first two characters of encrypted password */
salt = p_pwd->encrypted_passwd;
/* Encrypt supplied password and compare to encrypted password */
/* stored in password file */
p = (char *) crypt(passwd, salt);
correct = strequal(p, p_pwd->encrypted_passwd);
stfree(p_pwd);
return correct;
}
/* Constructs and returns a random two-character salt. */
/* Salt needed by crypt() is two characters from the set [a-zA-Z0-9./] */
static char *get_salt(void)
{
time_t tim = time(NULL); /* Use current time to achieve */
/* randomness between sessions */
char *salt;
salt = stalloc(2);
salt[0] = 'a' + (tim % 26); /* Letter between 'a' and 'z' */
salt[1] = '.' + (tim % 12); /* One of '.', '/', and '0'-'9' */
return salt;
}
#define RETURN(rv) do { retval = rv; goto cleanup ; }
/* Deletes principal's password entry from file */
int delete_ppw_entry(char *principal)
{
FILE *passwd_fp = NULL;
FILE *tmp_fp = NULL;
int retval;
char line[255];
char princ_name[255], encrypted_passwd[255];
char tmp_filename[255];
int found = 0;
assert(P_IS_THIS_THREAD_MASTER());
/* XXX !! This is MT-UNSAFE, two writers will totally screw up the
pw file, needs mutexing*/
if (!get_ppw_entry(principal))
RETURNPFAILURE;
if (!(passwd_fp = locked_fopen(PSRV_PW_FILE, "r")))
RETURNPFAILURE;
qsprintf(tmp_filename, sizeof(tmp_filename), "%s_tmp", PSRV_PW_FILE);
if (!(tmp_fp = locked_fopen(tmp_filename, "w"))) {
if (pfs_debug) { /* Old code was hosed, only closed if pfs_debug set*/
fprintf(stderr, "Could not create temporary file %s\n",
tmp_filename);
}
if (passwd_fp) locked_fclose_A(passwd_fp,PSRV_PW_FILE,TRUE);
RETURNPFAILURE;
}
while (fgets(line, sizeof(line), passwd_fp)) {
sscanf(line, "%s %s\n",
princ_name, encrypted_passwd);
if (strcmp(princ_name, principal))
fputs(line, tmp_fp);
}
(void) locked_fclose_A(tmp_fp,tmp_filename,FALSE);
(void) locked_fclose_A(passwd_fp,PSRV_PW_FILE,TRUE);
if (rename(tmp_filename, PSRV_PW_FILE)) {
unlink(tmp_filename);
if (pfs_debug)
perror("Could not overwrite password file");
RETURNPFAILURE;
}
if (chmod(PSRV_PW_FILE, 0600)) {
if (pfs_debug)
perror("Could not change permissions of passwd file");
RETURNPFAILURE;
}
return PSUCCESS;
}
/* Lists the principals in the Prospero password file */
int list_ppw_file(void)
{
FILE *passwd_fp;
char line[255];
char princ_name[255], encrypted_passwd[255];
int num;
if (!(passwd_fp = locked_fopen(PSRV_PW_FILE, "r")))
RETURNPFAILURE;
while (fgets(line, sizeof(line), passwd_fp)) {
if (line[0] == '#')
continue;
num = sscanf(line, "%s %s\n",
princ_name, encrypted_passwd);
if (num == 2)
printf("%s\n", princ_name);
}
(void) locked_fclose_A(passwd_fp,PSRV_PW_FILE,TRUE);
return PSUCCESS;
}
#endif /* PSRV_P_PASSWORD */

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 1991-1994 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
#include <usc-license.h>
#include <pserver.h>
#include <pfs.h>
#include <psrv.h>
void
psrv_init_mutexes(void)
{
/* retrieve_fp() is not currently called by the server, so doesn't need
mutexing. */
p_th_mutex_init(p_th_mutexPSRV_CHECK_ACL_INET_DEF_LOCAL);
p_th_mutex_init(p_th_mutexPSRV_CHECK_NFS_MYADDR);
p_th_mutex_init(p_th_mutexPSRV_LOG);
}
#ifndef NDEBUG
void
psrv_diagnose_mutexes(void)
{
printf("{psrv_diagnose_mutexes");
DIAGMUTEX(PSRV_CHECK_ACL_INET_DEF_LOCAL,"PSRV_CHECK_ACL_INET_DEF_LOCAL");
DIAGMUTEX(PSRV_CHECK_NFS_MYADDR,"PSRV_CHECK_NFS_MYADDR");
DIAGMUTEX(PSRV_LOG,"PSRV_LOG");
printf("}");
}
#endif

View File

@@ -0,0 +1,74 @@
/* replyf.c */
/*
* Copyright (c) 1992, 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>
*/
#include <usc-license.h>
#include <stdarg.h>
#include <ardp.h>
#include <pfs.h>
#include <plog.h>
#include <pprot.h>
#include <psrv.h> /* includes prototypes of vreplyf(),
vcreplyf(), replyf(), and creplyf() */
/*
* Note: If you are looking for the definitions of reply and creply
* they are defined as macros that call ardp_reply with
* the ARDP_R_COMPLETE or ARDP_R_INCOMPLETE flags.
* This file defines the formatted versions of these
* commands, replyf and creplyf.
*/
int
replyf(RREQ req, const char *format, ...)
{
va_list ap;
int retval;
va_start(ap, format);
retval = vreplyf(req, format, ap);
va_end(ap);
return retval;
}
int
vreplyf(RREQ req, const char *format, va_list ap)
{
AUTOSTAT_CHARPP(bufp);
*bufp = vqsprintf_stcopyr(*bufp, format, ap);
/* Perform the reply and pass through any error codes */
return(ardp_breply(req, ARDP_R_INCOMPLETE, *bufp, p_bstlen(*bufp)));
}
int
creplyf(RREQ req, const char *format, ...)
{
va_list ap;
int retval;
va_start(ap, format);
retval = vcreplyf(req, format, ap);
va_end(ap);
return retval;
}
int
vcreplyf(RREQ req, const char *format, va_list ap)
{
AUTOSTAT_CHARPP(bufp);
*bufp = vqsprintf_stcopyr(*bufp, format, ap);
/* Perform the reply and pass through any error codes */
return(ardp_breply(req, ARDP_R_COMPLETE, *bufp, p_bstlen(*bufp)));
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (c) 1989, 1990, 1991 by the University of Washington
*
* For copying and distribution information, please see the file
* <uw-copyright.h>.
*/
#include <uw-copyright.h>
#include <netdb.h>
#include <pfs.h>
#include <psrv.h> /* For dsrfinfo */
#include <perrno.h>
VLINK check_fwd();
extern char hostname[];
/* retrieve_fp will retrieve a forwarding pointer and will
* replace the changed fields of the link it is passed.
* Retrieve will use pget_at to retriev the forwarding
* pointer if it is on a remote host. If the same host,
* it will retrieve the forwarding pointer directly.
* Retrieve fp returs PSUCCESS on success and PFAILURE
* on failure.
*/
#define RETURN(val) { retval = (val) ; goto cleanup; }
int
retrieve_fp(l)
VLINK l;
{
struct hostent *h_ent;
static int firsttime = 0;
static char thishost[100];
char lhost[100];
PATTRIB fa = NULL; /* Forward attribute */
VLINK fp; /* Forwarding Pointer */
PFILE fi = pfalloc(); /* Pointer to fi_st */
int tmp;
int retval;
assert(P_IS_THIS_THREAD_MASTER()); /* not yet converted. Not used currently
either. gethostbyname MT-Unsafe */
if(firsttime++ == 0) {
h_ent = gethostbyname(hostname);
strcpy(thishost,h_ent->h_name);
}
/* We should check port numbers too */
/* Find out if link is on this host */
h_ent = gethostbyname(l->host);
if(h_ent) strcpy(lhost,h_ent->h_name);
else RETURNPFAILURE;
if(strcmp(lhost,thishost) == 0) { /* Local */
tmp = dsrfinfo(l->hsoname,l->f_magic_no,fi);
if((tmp == DSRFINFO_FORWARDED) &&
(fp = check_fwd(fi->forward,l->hsoname,l->f_magic_no))) {
l->hosttype = stcopyr(fp->hosttype,l->hosttype);
l->host = stcopyr(fp->host,l->host);
l->hsonametype = stcopyr(fp->hsonametype,l->hsonametype);
l->hsoname = stcopyr(fp->hsoname,l->hsoname);
l->version = fp->version;
l->f_magic_no = fp->f_magic_no;
RETURN(PSUCCESS);
}
RETURN(PFAILURE);
}
else { /* Remote */
/* fa could memory leak if pget_at succeeds, but its not ATR_LINK*/
fa = pget_at(l,"FORWARDING-POINTER");
if(fa && fa->avtype == ATR_LINK && fa->value.link) {
fp = fa->value.link;
l->hosttype = stcopyr(fp->hosttype,l->hosttype);
l->host = stcopyr(fp->host,l->host);
l->hsonametype = stcopyr(fp->hsonametype,l->hsonametype);
l->hsoname = stcopyr(fp->hsoname,l->hsoname);
l->version = fp->version;
l->f_magic_no = fp->f_magic_no;
RETURN(PSUCCESS);
}
else RETURN(PFAILURE);
}
cleanup:
pffree(fi);
if (fa) atlfree(fa);
return(retval);
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 1992 by the University of Southern California
*
* For copying and distribution information, please see the file <usc-copyr.h>
*/
#include <usc-copyr.h>
#include <stdio.h> /* for fputs() and EOF */
#include <ardp.h>
#include <pfs.h>
#include <pparse.h>
#include <psrv.h>
/* Returns PFAILURE or PSUCCESS. */
int
srv_qoprintf(OUTPUT out, const char fmt[], ...)
{
va_list ap;
int retval;
assert(out->req || out->f);
va_start(ap, fmt);
if (out->f) {
retval = vqfprintf(out->f, fmt, ap);
} else {
retval = vreplyf(out->req, fmt, ap);
}
va_end(ap);
return retval;
}
void
reqtoout(RREQ req, OUTPUT out)
{
out->f = NULL;
out->request = NULL;
out->req = req;
}
void
filetoout(FILE *file, OUTPUT out)
{
out->req = NULL;
out->request = NULL;
out->f = file;
}

View File

@@ -0,0 +1,8 @@
#include <pfs.h>
#include <psrv.h>
/* Run STAT on the object OB. */
int
stat_object(OBJECT ob)
{
}

1
prospero/lib/psrv/wais_gw/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
Makefile

View File

@@ -0,0 +1,49 @@
FILES
Makefile
buffalloc.c
buffalloc.h
cdialect.h
cutil.c
cutil.h
docid.h
futil.c
futil.h
ietftype.c
ietftype.h
ietftype_parse.c
ietftype_parse.h
ietftypes
inface.c
inface.h
irfileio.c
irfileio.h
list.c
list.h
main.c
panic.c
panic.h
sockets.c
sockets.h
source.c
source.h
sourcealloc.c
sourceparse.c
ustubs.c
ustubs.h
wais_gw_dsdb.c
wais_gw_dsdb.h
wais_gw_mutex.c
waislog.c
waislog.h
wmessage.c
wmessage.h
wprot.c
wprot.h
wutil.c
wutil.h
zprot.c
zprot.h
ztype1.c
ztype1.h
zutil.c
zutil.h

View File

@@ -0,0 +1,234 @@
#*****************************************************************************
# (c) Copyright 1992,1993 Wide Area Information Servers, Inc *
# of California. All rights reserved. *
# *
# This notice is intended as a precaution against inadvertent publication *
# and does not constitute an admission or acknowledgement that publication *
# has occurred or constitute a waiver of confidentiality. *
# *
# Wide Area Information Server software is the proprietary and *
# confidential property of Wide Area Information Servers, Inc. *
#*****************************************************************************
# this file has different configuration ideas from the rest of Prospero.
# this is a problem.
SOURCEBASE=../../..
include $(SOURCEBASE)/Makefile.config
# Note that not all versions of make will support this construct.
CFLAGS += $(WCFLAGS)
# These are needed by the Prospero 'setdependencies' script.
CFILES = buffalloc.c \
ustubs.c \
list.c \
cutil.c \
futil.c \
panic.c \
waislog.c \
irfileio.c \
wutil.c \
wprot.c \
zprot.c \
zutil.c \
ztype1.c \
source.c \
sourcealloc.c \
sockets.c \
inface.c \
wmessage.c \
ietftype.c \
ietftype_parse.c \
wais_gw_mutex.c \
wais_gw_dsdb.c \
sourceparse.c
# the z3950 protocol and tcp communications
UTIL = \
buffalloc.o \
ustubs.o \
list.o \
cutil.o \
futil.o \
panic.o \
waislog.o \
irfileio.o
OBJS = \
wutil.o \
wprot.o \
zprot.o \
zutil.o \
ztype1.o \
source.o \
sourcealloc.o \
sockets.o \
inface.o \
wmessage.o
GW = \
ietftype.o \
ietftype_parse.o \
wais_gw_mutex.o \
wais_gw_dsdb.o
OBJECTS = ${UTIL} ${OBJS} ${GW} sourceparse.o
all: ${WAIS_GW_LIB} sourceparse
${WAIS_GW_LIB}: ${OBJS} ${UTIL} ${GW}
$(RM) -f $@
$(AR) $(ARFLAGS) $@ $(OBJS) $(UTIL) $(GW)
$(RANLIB) $@
install: sourceparse ietftypes
-for i in sourceparse ietftypes ; do \
${INSTALL} -c -m 755 -o ${OWNER} -g ${GROUP} $$i ${P_BINARIES}/$$i${GENERATIONSUFFIX}; \
${GENERATION} ${P_BINARIES}/$$i ; \
done
sourceparse: sourceparse.o ${WAIS_GW_LIB} $(PFS_LIBS_DEPENDENCIES)
${CC} ${CFLAGS} -o $@ sourceparse.o $(WAIS_GW_LIB) $(PFS_LIBS)
# Not clear why this is necessary. --swa
#-u ${COMPILER_PREPENDS_C_SYMBOLS_WITH_UNDERSCORE}gopher_gw_init_mutexes ${SPLIBS}
# Dependencies
buffalloc.o : buffalloc.h inface.h \
wprot.h cdialect.h zprot.h zutil.h cutil.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h ztype1.h ../../../include/pfs.h \
../../../include/ardp.h \
../../../include/list_macros.h ../../../include/../lib/ardp/flocks.h \
../../../include/implicit_fixes.h \
../../../include/pmachine.h \
../../../include/mitra_macros.h ../../../include/psrv.h \
../../../include/pparse.h
ustubs.o : ustubs.h cdialect.h futil.h cutil.h \
../../../include/pmachine.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h
list.o : list.h cutil.h \
cdialect.h
cutil.o : \
../../../include/pfs.h \
../../../include/pfs_utils.h ../../../include/ardp.h \
../../../include/pfs_threads.h \
../../../include/list_macros.h ../../../include/../lib/ardp/flocks.h \
../../../include/implicit_fixes.h \
../../../include/pmachine.h \
../../../include/perrno.h cutil.h cdialect.h futil.h
futil.o : \
futil.h \
cdialect.h cutil.h \
panic.h ../../../include/pfs_threads.h ../../../include/pfs_utils.h
panic.o : \
panic.h cdialect.h waislog.h \
cutil.h \
../../../include/pfs.h ../../../include/pfs_utils.h \
../../../include/ardp.h ../../../include/pfs_threads.h \
../../../include/list_macros.h ../../../include/../lib/ardp/flocks.h \
../../../include/implicit_fixes.h \
../../../include/pmachine.h \
../../../include/perrno.h
waislog.o :
irfileio.o : \
../../../include/pfs.h ../../../include/pfs_utils.h \
../../../include/ardp.h \
../../../include/pfs_threads.h \
../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/implicit_fixes.h \
../../../include/pmachine.h \
../../../include/perrno.h irfileio.h cdialect.h futil.h cutil.h zprot.h zutil.h
wutil.o : futil.h cdialect.h cutil.h \
zprot.h \
zutil.h ../../../include/pfs_threads.h ../../../include/pfs_utils.h \
wprot.h ztype1.h \
wutil.h
wprot.o : wprot.h cdialect.h zprot.h zutil.h cutil.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h \
ztype1.h panic.h
zprot.o : zprot.h cdialect.h zutil.h cutil.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h
zutil.o : \
zutil.h \
cdialect.h cutil.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h
ztype1.o : ztype1.h cdialect.h zutil.h cutil.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h \
panic.h waislog.h
source.o : ../../../include/string_with_strcasecmp.h \
cutil.h \
cdialect.h \
futil.h \
irfileio.h zprot.h zutil.h ../../../include/pfs_threads.h \
../../../include/pfs_utils.h source.h ../../../include/pfs.h ../../../include/ardp.h \
../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/implicit_fixes.h \
../../../include/pmachine.h \
../../../include/mitra_macros.h ../../../include/psrv.h \
../../../include/pparse.h
sourcealloc.o : buffalloc.h inface.h wprot.h cdialect.h zprot.h \
zutil.h cutil.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h \
ztype1.h ../../../include/pfs.h ../../../include/ardp.h \
../../../include/list_macros.h ../../../include/../lib/ardp/flocks.h \
../../../include/implicit_fixes.h \
../../../include/pmachine.h \
../../../include/mitra_macros.h source.h
sockets.o : sockets.h cdialect.h cutil.h \
../../../include/posix_signal.h \
panic.h waislog.h
inface.o : zutil.h cdialect.h cutil.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h \
zprot.h wprot.h ztype1.h wmessage.h inface.h sockets.h \
waislog.h \
../../../include/pfs.h ../../../include/ardp.h ../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/implicit_fixes.h \
../../../include/pmachine.h \
../../../include/perrno.h buffalloc.h
wmessage.o : \
wmessage.h cdialect.h cutil.h
ietftype.o : ietftype.h ../../../include/pfs.h \
../../../include/pfs_utils.h ../../../include/ardp.h \
../../../include/pfs_threads.h \
../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/implicit_fixes.h \
../../../include/pmachine.h \
../../../include/mitra_macros.h ../../../include/psrv.h \
../../../include/pparse.h
ietftype_parse.o : \
../../../include/pfs.h ../../../include/pfs_utils.h \
../../../include/ardp.h ../../../include/pfs_threads.h \
../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/implicit_fixes.h \
../../../include/pmachine.h \
ietftype.h ../../../include/mitra_macros.h
wais_gw_mutex.o : ../../../include/pfs_threads.h \
../../../include/pfs_utils.h \
ietftype_parse.h ietftype.h ../../../include/pfs.h ../../../include/ardp.h \
../../../include/list_macros.h \
../../../include/../lib/ardp/flocks.h ../../../include/implicit_fixes.h \
../../../include/pmachine.h
wais_gw_dsdb.o : \
../../../include/pmachine.h \
../../../include/psite.h \
../../../include/ardp.h \
../../../include/pfs_threads.h ../../../include/pfs_utils.h \
../../../include/list_macros.h ../../../include/../lib/ardp/flocks.h \
../../../include/pfs.h \
../../../include/implicit_fixes.h \
../../../include/pserver.h ../../../include/psrv.h \
../../../include/pparse.h \
../../../include/perrno.h ../../../include/plog.h wprot.h cdialect.h zprot.h \
zutil.h cutil.h ztype1.h source.h inface.h wais_gw_dsdb.h ietftype.h ietftype_parse.h
sourceparse.o : \
source.h ../../../include/pfs.h ../../../include/pfs_utils.h \
../../../include/ardp.h ../../../include/pfs_threads.h \
../../../include/list_macros.h ../../../include/../lib/ardp/flocks.h \
../../../include/implicit_fixes.h \
../../../include/pmachine.h

View File

@@ -0,0 +1,137 @@
/* Copyright (c) 1993, by Pandora Systems */
/* Author: Mitra <mitra@path.net> */
/* Allocation code copied and adapted from:
prospero/alpha.5.2a+/lib/pfs/flalloc */
/*
* Original allocation code Copyright (c) 1991-1993 by the University of
* Southern California
* Modifications to Pandora code copyright (c) 1994 by the University
* of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
#include <usc-license.h>
#include "buffalloc.h"
#include <pfs.h>
#include <mitra_macros.h>
#define Channel_Illegal 0;
#include <psrv.h> /* includes global declarations of
waismsgbuff_count and waismsgbuff_max to be
read by dirsrv.c. */
static WAISMSGBUFF lfree = NULL; /* Free waismsgbuffs */
/* These are global variables which will be read by dirsrv.c
Too bad C doesn't have better methods for structuring such global data. */
int waismsgbuff_count = 0;
int waismsgbuff_max = 0;
/************* Standard routines to alloc, free and copy *************/
/*
* waismsgbuff_alloc - allocate and initialize WAISMSGBUFF structure
*
* returns a pointer to an initialized structure of type
* WAISMSGBUFF. If it is unable to allocate such a structure, it
* signals out_of_memory();
*/
WAISMSGBUFF
waismsgbuff_alloc()
{
WAISMSGBUFF msgbuff;
TH_STRUC_ALLOC(waismsgbuff,WAISMSGBUFF,msgbuff);
return(msgbuff);
}
/*
* waismsgbuff_free - free a WAISMSGBUFF structure
*
* waismsgbuff_free takes a pointer to a WAISMSGBUFF structure and adds it to
* the free list for later reuse.
*/
void
waismsgbuff_free(WAISMSGBUFF msgbuff)
{
TH_STRUC_FREE(waismsgbuff,WAISMSGBUFF,msgbuff);
}
/*
* waismsgbuff_lfree - free a linked list of WAISMSGBUFF structures.
*
* waismsgbuff_lfree takes a pointer to a waismsgbuff structure frees it and
* any linked
* WAISMSGBUFF structures. It is used to free an entire list of WAISMSGBUFF
* structures.
*/
void
waismsgbuff_lfree(msgbuff)
WAISMSGBUFF msgbuff;
{
TH_STRUC_LFREE(WAISMSGBUFF,msgbuff,waismsgbuff_free);
}
void
waismsgbuff_freespares()
{
TH_FREESPARES(waismsgbuff,WAISMSGBUFF);
}
#ifdef NEVERDEFINED
/*
* waismsgbuff_copy - allocates a new waismsgbuff structure and
* initializes it with a copy of another
* waismsgbuff, v.
*
* If r is non-zero, successive waismsgbuffs will be
* iteratively copied.
*
* msgbuff-previous will always be null on the first link, and
* will be appropriately filled in for iteratively copied links.
*
* waismsgbuff_copy returns a pointer to the new structure of type
* WAISMSGBUFF. If it is unable to allocate such a structure, it
* returns NULL.
*
* waismsgbuff_copy will recursively copy the link associated with
* a waismsgbuff and
* its associated attributes.
*/
WAISMSGBUFF
waismsgbuff_copy(f,r)
WAISMSGBUFF f;
int r; /* Currently ignored. */
{
WAISMSGBUFF nf;
WAISMSGBUFF snf; /* Start of the chain of new links */
WAISMSGBUFF tf; /* Temporary link pointer */
nf = waismsgbuff_alloc();
snf = nf;
copyeach:
/* Copy f into nf */
#ifdef ALLOCATOR_CONSISTENCY_CHECK
assert(f->consistency == INUSE_PATTERN);
#endif
LOCAL STUFF NOT DEFINED
if(r && f->next) {
f = f->next;
tf = nf;
nf = waismsgbuff_alloc();
nf->previous = tf;
tf->next = nf;
goto copyeach;
}
return(snf);
}
#endif

View File

@@ -0,0 +1,27 @@
#ifndef wais_buffalloc_h
#define wais_buffalloc_h
#include "inface.h" /* For MAX_MESSAGE_LENGTH */
#include <pfs.h>
#include <pfs_threads.h>
struct waismsgbuff {
#ifdef ALLOCATOR_CONSISTENCY_CHECK
int consistency;
#endif
char buff[(size_t)MAX_MESSAGE_LENGTH * sizeof(char)];
struct waismsgbuff *next;
struct waismsgbuff *previous;
};
typedef struct waismsgbuff *WAISMSGBUFF;
typedef struct waismsgbuff WAISMSGBUFF_ST;
extern WAISMSGBUFF waismsgbuff_alloc();
extern void waismsgbuff_free(WAISMSGBUFF msgbuff);
extern void waismsgbuff_lfree(WAISMSGBUFF msgbuff);
extern void waismsgbuff_freespares();
/*extern WAISMSGBUFF waismsgbuff_copy(WAISMSGBUFF f, int r);*/
EXTERN_ALLOC_DECL(WAISMSGBUFF);
#endif /*wais_buffalloc_h*/

View File

@@ -0,0 +1,117 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*---------------------------------------------------------------------------*/
/* there are three kinds of C that we have encountered so far:
1. ANSI_LIKE - full prototypes and stdargs and ansi includes
2. PROTO_ANSI - full prototypes, varargs and misc includes
3. K_AND_R - k&r prototypes, varargs and misc includes
This file is a mess because some compilers do not handle elif. sorry.
defined symbols for other machines:
hp: hpux
Next: NeXT
*/
#ifndef C_DIALECT
#define C_DIALECT
/*----------------------------------------------------------------------*/
#define _AP(args) args
#ifdef STDC
#define ANSI_LIKE
#endif /* def STDC */
#ifdef __STDC__
#ifndef M_XENIX /* for some reason XENIX defines __STDC__ */
#define ANSI_LIKE
#endif /* ndef M_XENIX */
#endif /* __STDC__ */
#ifdef __alpha
#define ANSI_LIKE
#endif /* def __alpha */
#ifdef THINK_C
#define ANSI_LIKE
#endif /* THINK_C */
#ifdef MPW
#define ANSI_LIKE
#endif /* MPW */
#ifdef VAX_C /* vms */
#define ANSI_LIKE
#endif /* VAX_C */
#ifdef MSC /* XXX not sure if this is correct */
#define ANSI_LIKE
#endif /* MSC */
#ifndef ANSI_LIKE
#ifdef SABER /* c interpreter/debugger */
#define PROTO_ANSI
#endif /* SABER */
#ifdef cstar /* parallel C on the CM */
#define PROTO_ANSI
#endif /* cstar */
#ifndef PROTO_ANSI
#ifdef SUN_C /* XXX not sure if this is correct */
#define K_AND_R
#endif /* SUN_C */
#ifdef __GNUC__ /* gcc in traditional mode */
#define K_AND_R /* gcc in ansi mode defines __STDC__ */
#endif /* __GNUC__ */
#ifdef M_XENIX
#define K_AND_R
#define NOTCPIP /* doesn't support TCP */
#define SYSV /* is based on system V */
#endif /* M_XENIX */
/* otherwise */
#define K_AND_R /* default to the stone age */
#endif /* ndef PROTO_ANSI */
#endif /* ndef ANSI_LIKE */
/* if you are not k_and_r, then load in ustubs always */
#ifdef K_AND_R
#include "ustubs.h"
#endif /* def K_AND_R */
/* Comment this back in to figure out what the compiler thinks we are */
/*
#ifdef ANSI_LIKE
WeareAnsiLike
#endif
#ifdef PROTO_ANSI
WeareProtoAnsi
#endif
#ifdef K_AND_R
WeareKandR
#endif
Crash-and-Burn
*/
/* End of chunk to comment back in */
#ifdef SCOUNIX
#define getdomainname(str,len) sprintf(str,"")
#endif /*SCOUNIX*/
#endif /* ndef C_DIALECT */
/*----------------------------------------------------------------------*/

View File

@@ -0,0 +1,777 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
#define cutil_c
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <pfs.h>
#include <perrno.h>
#include "cutil.h"
#include "futil.h"
#ifdef NOTUSEDANDNOTTHREADSAFE
long myPID = -1;
#endif /*NOTUSEDANDNOTTHREADSAFE*/
typedef long (longfunc)(long c);
/*---------------------------------------------------------------------------*/
char*
s_strdup(char* s)
{
unsigned long len;
char* copy = NULL;
if (s == NULL)
return(NULL);
len = strlen(s);
copy = (char*)s_malloc((size_t)(sizeof(char)*(len + 1)));
strncpy(copy,s,len + 1);
return(copy);
}
/*---------------------------------------------------------------------------*/
#if !defined(IN_RMG) && !defined(PFS_THREADS)
char*
strtokf(char* s1,longfunc *isDelimiter)
{
static char* searchStr = NULL;
static longfunc *delimiterFunc;
long i;
char* startTok = NULL;
if (s1 != NULL)
searchStr = s1;
if (isDelimiter != NULL)
delimiterFunc = isDelimiter;
if (searchStr == NULL || searchStr[0] == '\0')
return(NULL);
if (delimiterFunc == NULL)
return(NULL);
for (i = 0; searchStr[i] != '\0'; i++)
{ if ((*delimiterFunc)((long)searchStr[i]) == NOT_DELIMITER)
break;
}
if (searchStr[i] == '\0')
return(NULL);
else
startTok = searchStr + i;
for (; searchStr[i] != '\0'; i++)
{ if ((*delimiterFunc)((long)searchStr[i]) == IS_DELIMITER)
break;
}
if (searchStr[i] != '\0')
{ searchStr[i] = '\0';
searchStr = searchStr + i + 1;
}
else
searchStr = searchStr + i;
return(startTok);
}
/*---------------------------------------------------------------------------*/
char*
strtokf_isalnum(char* s1)
{
static char* searchStr = NULL;
long i;
char* startTok = NULL;
if (s1 != NULL)
searchStr = s1;
if (searchStr == NULL || searchStr[0] == '\0')
return(NULL);
for (i = 0; searchStr[i] != '\0'; i++)
{ if (safeIsAlNum(searchStr[i]))
break;
}
if (searchStr[i] == '\0')
return(NULL);
else
startTok = searchStr + i;
for (; searchStr[i] != '\0'; i++)
{ if (!safeIsAlNum(searchStr[i]))
break;
}
if (searchStr[i] != '\0')
{ searchStr[i] = '\0';
searchStr = searchStr + i + 1;
}
else
searchStr = searchStr + i;
return(startTok);
}
#endif /*NOTUSEDANDNOTTHREADSAFE*/
/*---------------------------------------------------------------------------*/
boolean
substrcmp(char* string1,char* string2)
/* return true if they match up to the length of the smaller (but not if the
smaller is empty)
*/
{
register char *a, *b;
a = string1;
b = string2;
/* see if they are both empty - if so them match */
if (*a == '\0' && *b == '\0')
return(true);
/* see if either is empty (but not both) - no match */
if (*a == '\0' || *b == '\0')
return(false);
/* otherwise we need to look through each byte */
while (*a && *b)
{ if (*a++ != *b++)
return(false);
}
return(true);
}
/*---------------------------------------------------------------------------*/
char
char_downcase(unsigned long long_ch)
{
unsigned char ch = long_ch & 0xFF;
return(((ch >= 'A') && (ch <= 'Z')) ? (ch + 'a' -'A') : ch);
}
/*---------------------------------------------------------------------------*/
char*
string_downcase(char *word)
{
long i = 0;
if (word == NULL)
return(NULL);
while (word[i] != '\0')
{ word[i] = char_downcase((unsigned long)word[i]);
i++;
}
return(word);
}
/*---------------------------------------------------------------------------*/
long
cprintf(boolean print, char* format, ...)
{
va_list ap;
if (print == 1)
{ long res;
va_start(ap,format);
res = vprintf(format,ap);
va_end(ap);
return(res);
}
else
return(0);
}
/*---------------------------------------------------------------------------*/
void
printHexByte(unsigned char h)
{
if (h < 0x10)
printf("0%x",h);
else
printf("%x",h);
}
/*---------------------------------------------------------------------------*/
#ifdef NOTUSEDANDNOTTHREADSAFE
char*
commafy(long val,char* buf)
/*
prints the value using format, then adds commas separating every
three orders of magnitude on the left side of the decimal point.
limitations
- there needs to be a buffer to write the result into. We provide
one for convenience, but of course that's not reentrant, so if you
are calling this is multiple times before using the result you'll
need to pass in your own buffer
- only works on longs
- only works on positive nums
- no other formatting allowed
*/
{
static char myBuf[100];
if (buf == NULL)
buf = myBuf;
if (val < 1000) /* 1 thousand */
sprintf(buf,"%ld",val);
else if (val < 1000000) /* 1 millon */
{ long lessThanAGrand = val%1000;
long moreThanAGrand = val - lessThanAGrand;
sprintf(buf,"%ld,%03ld",moreThanAGrand/1000,lessThanAGrand);
}
else if (val < 1000000000) /* 1 trillion, 1 gig */
{ long lessThanAGrand = val%1000;
long lessThanAMil = (val%1000000) - lessThanAGrand;
long moreThanAMil = val - lessThanAMil - lessThanAGrand;
sprintf(buf,"%ld,%03ld,%03ld",moreThanAMil/1000000,lessThanAMil/1000,
val%1000);
}
return(buf);
}
#endif NOTUSEDANDNOTTHREADSAFE
/*---------------------------------------------------------------------------*/
#ifdef NOTUSEDANDNOTTHREADSAFE
char*
printable_time(void)
{
static char *string;
time_t tptr;
time(&tptr);
string = ctime(&tptr);
if (string)
{ if (string[strlen(string)-1] == '\n')
string[strlen(string)-1] = '\0';
return(string+4);
}
else
return("Time Unknown");
}
#endif /*NOTUSEDANDNOTTHREADSAFE*/
/*---------------------------------------------------------------------------*/
#ifdef BSD
#define NEED_VPRINTF
#endif
#ifdef NEED_VPRINTF
#ifdef OSK
#define LONGINT
#define INTSPRINTF
#endif
#ifdef NOVOID
typedef char *pointer;
#else
typedef void *pointer;
#endif
#ifdef INTSPRINTF
#define Sprintf(string,format,arg) (sprintf((string),(format),(arg)))
#else
#define Sprintf(string,format,arg) (\
sprintf((string),(format),(arg)),\
strlen(string)\
)
#endif
typedef int *intp;
int vsprintf(dest, format, args)
char *dest;
register char *format;
va_list args;
{
register char *dp = dest;
register char c;
register char *tp;
char tempfmt[64];
#ifndef LONGINT
int longflag;
#endif
tempfmt[0] = '%';
while( (c = *format++) != 0) {
if(c=='%') {
tp = &tempfmt[1];
#ifndef LONGINT
longflag = 0;
#endif
continue_format:
switch(c = *format++) {
case 's':
*tp++ = c;
*tp = '\0';
dp += Sprintf(dp, tempfmt, va_arg(args, char *));
break;
case 'u':
case 'x':
case 'o':
case 'X':
#ifdef UNSIGNEDSPECIAL
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
dp += Sprintf(dp, tempfmt, va_arg(args, unsigned long));
else
#endif
dp += Sprintf(dp, tempfmt, va_arg(args, unsigned));
break;
#endif
case 'd':
case 'c':
case 'i':
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
dp += Sprintf(dp, tempfmt, va_arg(args, long));
else
#endif
dp += Sprintf(dp, tempfmt, va_arg(args, int));
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
*tp++ = c;
*tp = '\0';
dp += Sprintf(dp, tempfmt, va_arg(args, double));
break;
case 'p':
*tp++ = c;
*tp = '\0';
dp += Sprintf(dp, tempfmt, va_arg(args, pointer));
break;
case '-':
case '+':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case ' ':
case '#':
case 'h':
*tp++ = c;
goto continue_format;
case 'l':
#ifndef LONGINT
longflag = 1;
*tp++ = c;
#endif
goto continue_format;
case '*':
tp += Sprintf(tp, "%d", va_arg(args, int));
goto continue_format;
case 'n':
*va_arg(args, intp) = dp - dest;
break;
case '%':
default:
*dp++ = c;
break;
}
} else *dp++ = c;
}
*dp = '\0';
return dp - dest;
}
int vfprintf(dest, format, args)
FILE *dest;
register char *format;
va_list args;
{
register char c;
register char *tp;
register int count = 0;
char tempfmt[64];
#ifndef LONGINT
int longflag;
#endif
tempfmt[0] = '%';
while(c = *format++) {
if(c=='%') {
tp = &tempfmt[1];
#ifndef LONGINT
longflag = 0;
#endif
continue_format:
switch(c = *format++) {
case 's':
*tp++ = c;
*tp = '\0';
count += fprintf(dest, tempfmt, va_arg(args, char *));
break;
case 'u':
case 'x':
case 'o':
case 'X':
#ifdef UNSIGNEDSPECIAL
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
count += fprintf(dest, tempfmt, va_arg(args, unsigned long));
else
#endif
count += fprintf(dest, tempfmt, va_arg(args, unsigned));
break;
#endif
case 'd':
case 'c':
case 'i':
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
count += fprintf(dest, tempfmt, va_arg(args, long));
else
#endif
count += fprintf(dest, tempfmt, va_arg(args, int));
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
*tp++ = c;
*tp = '\0';
count += fprintf(dest, tempfmt, va_arg(args, double));
break;
case 'p':
*tp++ = c;
*tp = '\0';
count += fprintf(dest, tempfmt, va_arg(args, pointer));
break;
case '-':
case '+':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case ' ':
case '#':
case 'h':
*tp++ = c;
goto continue_format;
case 'l':
#ifndef LONGINT
longflag = 1;
*tp++ = c;
#endif
goto continue_format;
case '*':
tp += Sprintf(tp, "%d", va_arg(args, int));
goto continue_format;
case 'n':
*va_arg(args, intp) = count;
break;
case '%':
default:
putc(c, dest);
count++;
break;
}
} else {
putc(c, dest);
count++;
}
}
return count;
}
vprintf(format, args)
char *format;
va_list args;
{
return vfprintf(stdout, format, args);
}
#endif
/*---------------------------------------------------------------------------*/
void
fs_checkPtr(void* ptr)
{
if (ptr == NULL)
p_err_string = qsprintf_stcopyr(p_err_string,
"checkPtr found a NULL pointer");
}
/*---------------------------------------------------------------------------*/
void*
fs_malloc(size_t size)
{
void* ptr = NULL;
if (size <= 0) {
/* Define error message - even though caller may change it */
p_err_string = qsprintf_stcopyr(p_err_string,
"Allocating zero or -ve size %d", size);
return(NULL);
}
#ifdef THINK_C
ptr = (void*)NewPtr((long)size);
s_checkPtr(ptr);
memset(ptr,0,(size_t)size);
#else
ptr = (void*)calloc((size_t)size,(size_t)1);
s_checkPtr(ptr);
if (!ptr) out_of_memory();
#endif
return(ptr);
}
/*---------------------------------------------------------------------------*/
void*
fs_realloc(void* ptr,size_t size)
{
register void* nptr = NULL;
if (size <= 0)
return(NULL);
if (ptr == NULL)
return(s_malloc(size));
#ifdef THINK_C
nptr = NewPtr(size);
s_checkPtr(nptr);
BlockMove(ptr,nptr,size);
DisposPtr(ptr);
#else
nptr = (void*)realloc(ptr,size);
s_checkPtr(ptr);
if (!ptr) out_of_memory();
#endif
return(nptr);
}
/*---------------------------------------------------------------------------*/
void
fs_free(void* ptr)
{
if (ptr != NULL)
{
#ifdef THINK_C
DisposPtr(ptr);
#else
free(ptr);
#endif
}
}
/*---------------------------------------------------------------------------*/
char*
fs_strncat(char* dst,char* src,size_t maxToAdd,size_t maxTotal)
{
size_t dstSize = strlen(dst);
size_t srcSize = strlen(src);
if (dstSize + srcSize < maxTotal)
return(strncat(dst,src,maxToAdd));
else
{ size_t truncateTo = maxTotal - dstSize - 1;
char saveChar;
char* result = NULL;
saveChar = src[truncateTo];
src[truncateTo] = '\0';
result = strncat(dst,src,maxToAdd);
src[truncateTo] = saveChar;
return(result);
}
}
/*---------------------------------------------------------------------------*/
char*
fs_strncpy(char* s1,char* s2,long n)
{
s1[n-1] = '\0';
return(strncpy(s1, s2, n - 1));
}
/*---------------------------------------------------------------------------*/
#ifdef NOTUSEDANDNOTTHREADSAFE
void
initMyPID(void)
{
if (myPID == -1)
myPID = getpid();
}
#endif /*NOTUSEDANDNOTTHREADSAFE*/
/*---------------------------------------------------------------------------*/
void
warn(char* message)
{
#ifdef THINK_C
Debugger();
#else
printf("%s\n<press return to continue>\n",message);
getchar();
#endif
}
/*---------------------------------------------------------------------------*/
char*
next_arg(long* argc,char*** argv)
{
if ((*argc)-- > 0)
{ char* arg = *((*argv)++);
return(arg);
}
else
{ return(NULL);
}
}
/*---------------------------------------------------------------------------*/
char*
peek_arg(long* argc,char*** argv)
{
if ((*argc) > 0)
return(**argv);
else
return(NULL);
}
/*---------------------------------------------------------------------------*/
#ifdef NOTUSEDANDNOTTHREADSAFE
char*
readNextArg(long* argc,char*** argv,boolean* useFile,FILE* file)
/*
Like next_arg(), but can read arguments from a file (one line per arg).
Note you must copy the returned value if you need access to more
than one argument at a time.
*/
{
static char buf[300];
if (file != NULL && useFile != NULL && *useFile)
{ if (fgets(buf,300,file) == NULL) /* nothing more on the file */
{ *useFile = false;
return(next_arg(argc,argv)); /* start reading regular args again */
}
else /* return a line from the file */
{ buf[strlen(buf) - 1] = '\0'; /* get rid of newline */
return(buf);
}
}
else /* just read regular args from the command line */
{ return(next_arg(argc,argv));
}
}
#endif /*NOTUSEDANDNOTTHREADSAFE*/
/*---------------------------------------------------------------------------*/
#ifdef THINK_C
#if THINK_C == 1
#include <EventMgr.h>
#endif
#if THINK_C == 5
#include <Events.h>
#endif
#ifdef WAIStation
#include "CRetrievalApp.h"
#endif
#endif
#ifdef NOTUSEDANDNOTTHREADSAFE
void
beFriendly()
{
#ifdef never
#ifdef THINK_C
EventRecord macEvent;
static RgnHandle mouseRgn = NULL;
long sleepTime;
#ifdef WAIStation
gApplication->FrobWaitCursor();
#endif
if (mouseRgn == NULL)
mouseRgn = NewRgn();
sleepTime = 5;
WaitNextEvent(everyEvent,&macEvent,sleepTime,mouseRgn);
#endif
#endif
}
#endif /*NOTUSEDANDNOTTHREADSAFE*/
/*---------------------------------------------------------------------------*/

View File

@@ -0,0 +1,151 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
#ifndef cutil_h
#define cutil_h
#include <stdarg.h>
#include <stdio.h>
#ifndef EXIT_SUCCESS
/* #include <stdlib.h> */ /* Commented out so compiles on SCO */
#endif /* ndef EXIT_SUCCESS */
#include "cdialect.h"
#if defined(THINK_C) || defined(SCOUNIX)
#include <time.h>
#else
#include <sys/time.h>
#endif
#define byte char
#ifndef cutil_c
extern long myPID;
#endif /* ndef cutil_c */
/*---------------------------------------------------------------------------*/
/* Math utilities */
/*---------------------------------------------------------------------------*/
#ifndef MAXLONG
#define MAXLONG ((long)0x7FFFFFFF)
#endif
#undef MAX
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#undef MIN
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#undef ABS
#define ABS(x) (((x) < 0) ? (-(x)) : (x))
/*---------------------------------------------------------------------------*/
/* Define boolean data type */
/*---------------------------------------------------------------------------*/
#ifndef boolean
#define boolean unsigned long
#endif /* ndef boolean */
#ifndef true
#define true ((boolean)1)
#endif /* ndef true */
#ifndef false
#define false ((boolean)0)
#endif /* ndef false */
#ifndef TRUE
#define TRUE true
#endif /* ndef TRUE */
#ifndef FALSE
#define FALSE false
#endif /* ndef FALSE */
#ifndef NULL
#define NULL (0L)
#endif /* ndef NULL */
/*---------------------------------------------------------------------------*/
/* String utlities */
/*---------------------------------------------------------------------------*/
#define IS_DELIMITER (1L)
#define NOT_DELIMITER !IS_DELIMITER
#define STREQ(s1,s2) ((*(s1)==*(s2)) && !strcmp(s1,s2))
#define STRNCMP(s1,s2,n) \
((*(s1)==*(s2)) ? strncmp(s1,s2,n) : (*(s1) - *(s2)))
#define s_strncat(dst,src,maxToAdd,maxTotal) \
fs_strncat((dst),(src),(maxToAdd),(maxTotal))
#define s_strncpy(s1,s2,n) fs_strncpy((s1), (s2), (n))
#define safeIsAlNum(c) ((c > '`' && c < '{') || \
(c > '/' && c < ':') || \
(c > '@' && c < '['))
char* s_strdup(char* s);
char* strtokf(char* s1,long (*isDelimiter)(long c));
char* strtokf_isalnum(char* s1);
boolean substrcmp(char *string1, char *string2);
char char_downcase(unsigned long ch);
char* string_downcase(char* word);
/*---------------------------------------------------------------------------*/
/* Printing utilities */
/*---------------------------------------------------------------------------*/
#define NL() printf("\n")
long cprintf(boolean print,char* format,...);
void printHexByte(unsigned char h);
char* commafy(long val,char* buf);
char* printable_time(void);
/*---------------------------------------------------------------------------*/
/* Heap utilities */
/*---------------------------------------------------------------------------*/
#define s_checkPtr(ptr) fs_checkPtr(ptr)
#define s_malloc(size) fs_malloc(size)
#define s_realloc(ptr,size) fs_realloc((ptr),(size))
#define s_free(ptr) { fs_free((char*)ptr); ptr = NULL; }
void fs_checkPtr(void* ptr);
void* fs_malloc(size_t size);
void* fs_realloc(void* ptr,size_t size);
void fs_free(void* ptr);
char* fs_strncat(char* dst,char* src,size_t maxToAdd,size_t maxTotal);
char* fs_strncpy(char* s1,char* s2, long n);
/*---------------------------------------------------------------------------*/
/* Miscelaneous Utilities */
/*---------------------------------------------------------------------------*/
void initMyPID(void);
void warn(char* message);
char* next_arg(long* argc, char*** argv);
char* peek_arg(long* argc, char*** argv);
char* readNextArg(long* argc,char*** argv,boolean* useFile,FILE* file);
void beFriendly(void);
/*---------------------------------------------------------------------------*/
#endif /* ndef cutil_h */

View File

@@ -0,0 +1,41 @@
#ifndef docid_h
#define docid_h
#include "cdialect.h"
#include "zprot.h"
#define COPY_WITHOUT_RESTRICTION (0L)
#define ALL_RIGHTS_RESERVED (1L)
#define DISTRIBUTION_RESTRICTIONS_APPLY (2L)
/*---------------------------------------------------------------------------*/
typedef struct DocID
{ any* originalServer;
any* originalDatabase;
any* originalLocalID;
any* distributorServer;
any* distributorDatabase;
any* distributorLocalID;
long copyrightDisposition;
} DocID;
DocID* makeDocID(void);
DocID* copyDocID(DocID* doc);
void freeDocID(DocID* doc);
any* GetServer(DocID* doc);
DocID* docIDFromAny(any* rawDocID);
any* anyFromDocID(DocID* docID);
any* GetDatabase(DocID* doc);
any* GetLocalID(DocID* doc);
long GetCopyrightDisposition(DocID* doc);
long ReadDocID(DocID* doc, FILE* file);
long WriteDocID(DocID* doc, FILE* file);
boolean cmpDocIDs(DocID* d1,DocID* d2);
/*---------------------------------------------------------------------------*/
#endif

View File

@@ -0,0 +1,564 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
/*-------------------------------------------------------------------------- */
/*-------------------------------------------------------------------------- */
#ifdef THINK_C
#include <pascal.h>
#if THINK_C == 1
#include <FileMgr.h>
#endif
#if THINK_C == 5
#include <Files.h>
#endif
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/file.h>
#if defined(__svr4__) || defined(SCOUNIX)
#include <unistd.h>
#endif
#endif
#include <string.h>
#include "futil.h"
#include "panic.h"
#include <pfs_threads.h> /* For locked_fopen etc */
/*---------------------------------------------------------------------------*/
/* Shared by all threads */
static long numFilesCurrentlyOpen = 0;
static long maxNumFilesOpenAtOneTime = 0;
#if 0
FILE*
doSafeFOpen(char* filename,char* mode)
{
FILE* file = NULL;
char realMode[100];
file = locked_fopen(filename,mode);
if (file != NULL)
{ numFilesCurrentlyOpen++;
if (numFilesCurrentlyOpen > maxNumFilesOpenAtOneTime)
maxNumFilesOpenAtOneTime = numFilesCurrentlyOpen;
/*cprintf(dbg,"fopen %ld %s\n",fileno(file),filename);*/
}
return(file);
}
/*---------------------------------------------------------------------------*/
long
doSafeFClose(FILE* file)
{
if (file != NULL)
{ numFilesCurrentlyOpen--;
return(locked_fclose(file));
}
else
return(0L);
}
#endif
/*---------------------------------------------------------------------------*/
long
doSafeFSeek(FILE* file,long offset,long fromWhere)
{
long result;
if (file == NULL)
return -1;
/*cprintf(dbg,"seek %ld %ld %ld\n",fileno(file),offset,fromWhere);*/
if (offset == 0 && fromWhere == SEEK_CUR) /* this is a nop */
return(0);
result = fseek(file,offset,fromWhere);
/* if (result != 0)
cprintf(dbg,"seek failed: file %ld offset %ld, fromWhere %d\n",
fileno(file),offset,fromWhere);
*/
return(result);
}
/*---------------------------------------------------------------------------*/
long
doSafeFTell(FILE* file)
{
long result;
if (file == NULL)
return(0);
result = ftell(file);
if (result == EOF)
panic("A seek on an index file failed.\n");
return(result);
}
/*---------------------------------------------------------------------------*/
long
doSafeRename(char* path1,char* path2)
{
#ifdef THINK_C
remove(path2);
#endif
return(rename(path1,path2));
}
/*---------------------------------------------------------------------------*/
long
writeBytes(long value,long size,FILE* stream)
{
long i;
long answer;
if ((size < sizeof(long)) && ((value >> (size * 8)) != 0))
panic("In a call to writeBytes, the value %ld can not be represented in %ld bytes",value,size);
for (i = size - 1; i >= 0; i--)
answer = putc((value >> (i * 8)) & 0xFF,stream);
if (ferror(stream) != 0)
panic("Write failed");
return(answer);
}
/*---------------------------------------------------------------------------*/
#ifdef NEVERDEFINEDUNUSED
long
readBytes(long n,FILE* stream)
{
long answer = 0;
unsigned long ch;
long i;
for (i = 0; i < n; i++)
{ ch = fgetc(stream); /* Note - no timeout */
if (ch == EOF)
return(EOF);
answer = (answer << 8) + (unsigned char)ch;
}
return(answer);
}
#endif
/*---------------------------------------------------------------------------*/
long
readBytesFromMemory(long n,unsigned char* block)
{
long answer = 0;
unsigned char ch;
long i;
for (i = 0; i < n; i++)
{ ch = *(block++);
answer = (answer << 8) + ch;
}
return(answer);
}
/*---------------------------------------------------------------------------*/
static char*
cleanPath(char* filename)
{
#ifdef THINK_C
return(filename);
#endif /* def THINK_C */
char* beginningPtr = strstr(filename,"/../");
if (beginningPtr != NULL)
{ char *ptr;
for (ptr = beginningPtr - 1; ptr >= filename; ptr--)
{ if (*ptr == '/')
{ strcpy(ptr,beginningPtr + strlen("/../") - 1);
cleanPath(filename);
break;
}
}
}
beginningPtr = strstr(filename,"/./");
if (beginningPtr != NULL)
{ strcpy(beginningPtr,beginningPtr + strlen("/./") - 1);
cleanPath(filename);
}
return(filename);
}
/*---------------------------------------------------------------------------*/
char*
truename(char* filename,char* fullPath)
{
#ifdef THINK_C
strcpy(fullPath,filename);
return(fullPath);
#else
if (filename[0] == '/')
{ strcpy(fullPath,filename);
cleanPath(fullPath);
return(fullPath);
}
else
{ getwd(fullPath);
s_strncat(fullPath,"/",MAX_FILENAME_LEN,MAX_FILENAME_LEN);
s_strncat(fullPath,filename,MAX_FILENAME_LEN,MAX_FILENAME_LEN);
cleanPath(fullPath);
return(fullPath);
}
#endif
}
/*---------------------------------------------------------------------------*/
char*
pathnameName(char* pathname)
{
#ifdef THINK_C
char *answer = strrchr(pathname,':');
#else
char *answer = strrchr(pathname,'/');
#endif
if (answer == NULL)
return(pathname);
return(answer + 1);
}
/*---------------------------------------------------------------------------*/
char*
pathnameDirectory(char* pathname,char* destination)
{
#ifdef THINK_C
n char *dirptr = strrchr(pathname,':');
#else
char *dirptr = strrchr(pathname,'/');
#endif
if (dirptr == NULL)
{
#ifdef THINK_C
strncpy(destination,pathname,MAX_FILENAME_LEN);
#else
strncpy(destination,"./",MAX_FILENAME_LEN);
#endif
}
else
{ strncpy(destination,pathname,MAX_FILENAME_LEN);
destination[dirptr - pathname + 1] = '\0';
}
return(destination);
}
/*---------------------------------------------------------------------------*/
#ifdef NOTUSEDANDNOTTHREADSAFE
char*
mergePathnames(char* pathname,char* directory)
{
static char answer[MAX_FILENAME_LEN + 1];
if ((pathname[0] == '/') || (NULL == directory) || directory[0] == '\0')
return(pathname);
else
{ answer[0] = '\0';
strncat(answer,directory,MAX_FILENAME_LEN);
#ifdef THINK_C
if (directory[strlen(directory) - 1] != ':')
strncat(answer,":",MAX_FILENAME_LEN);
#else
if (directory[strlen(directory) - 1] != '/')
strncat(answer,"/",MAX_FILENAME_LEN);
#endif
strncat(answer,pathname,MAX_FILENAME_LEN);
}
return(answer);
}
#endif /*NOTUSEDANDNOTTHREADSAFE*/
/*---------------------------------------------------------------------------*/
boolean
directoryP(char* f)
/* XXX strangely, this fails if f = "". It says that f is a directory */
{
#ifdef THINK_C
return(false);
#else
struct stat stbuf;
if (f == NULL)
return(FALSE);
else if (stat(f,&stbuf) == -1)
return(FALSE);
else if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
return(true);
else
return(FALSE);
#endif
}
/*---------------------------------------------------------------------------*/
boolean
fileP(char* f)
{
if (f == NULL)
return(false);
#ifdef THINK_C
return(probeFile(f));
#else
{ struct stat stbuf;
if (stat(f,&stbuf) == -1)
return(FALSE);
else if (!((stbuf.st_mode & S_IFMT) == S_IFDIR))
return(true);
else
return(FALSE);
}
#endif
}
/*---------------------------------------------------------------------------*/
boolean
probeFile(char* filename)
{
if (filename == NULL)
return(false);
#ifdef THINK_C
{ FILE* f;
f = locked_fopen(filename,"r");
if (f == NULL)
return(false);
else
{ locked_fclose_A(f,filename,TRUE);
return(true);
}
}
#else
if (access(filename,R_OK) == 0)
return(true);
else
return(false);
#endif
}
/*---------------------------------------------------------------------------*/
boolean
probeFilePossiblyCompressed(char* filename)
{
if (filename == NULL)
return(false);
else if (!probeFile(filename))
{ char buffer[MAX_FILENAME_LEN * 2];
strcpy(buffer,filename);
strcat(buffer,".Z");
return(probeFile(buffer));
}
else
return(true);
}
/*---------------------------------------------------------------------------*/
boolean
touchFile(char* filename)
{
FILE *stream = NULL;
if (filename == NULL)
return(false);
stream = locked_fopen(filename,"a");
if (stream == NULL)
return(false);
else
{ locked_fclose_A(stream,filename,FALSE);
return(true);
}
}
/*---------------------------------------------------------------------------*/
long
fileLength(FILE* stream)
{
long position;
long end = -1;
if (stream == NULL)
return(-1);
position = ftell(stream);
safeFSeek(stream,0L,SEEK_END);
end = ftell(stream);
safeFSeek(stream,position,SEEK_SET);
return(end);
}
/*---------------------------------------------------------------------------*/
void
getFileDates(char* filename,time_t* createDate,time_t* modDate)
{
#ifdef THINK_C
*createDate = *modDate = 0;
#else
struct stat buf;
if (stat(filename,&buf) != 0)
panic("could not stat %s",filename);
*modDate = buf.st_mtime;
*createDate = buf.st_mtime; /* no separate creation date maintained in
unix! */
#endif
}
/*---------------------------------------------------------------------------*/
#ifdef NOTUSEDANDNOTTHREADSAFE
char*
currentUserName(void)
{
static char answer[200];
char hostname[120];
#ifdef THINK_C
strcpy(answer,"MAC");
#else
#include <pwd.h>
assert(MASTER_IS_ONLY_UNTHREAD); /*getpwuid MT-Unsafe*/
struct passwd *pwent = getpwuid(getuid());
strncpy(answer,pwent->pw_name,200);
strncat(answer,"@",200);
gethostname(hostname,120);
strncat(answer,hostname,200);
#endif
return(answer);
}
#endif /*NOTUSEDANDNOTTHREADSAFE*/
/*---------------------------------------------------------------------------*/
#ifdef NOTUSEDANDNOTIMEOUTONREAD
boolean
readStringFromFile(FILE* stream,char* array,long arrayLength)
{
long ch;
long count = 0;
array[0] = '\0';
while (true)
{ ch = fgetc(stream); /* Note no timeout */
if(ch == EOF)
{ array[count] = '\0';
return(false);
}
else if (count == arrayLength)
{ array[count] = '\0';
return(false);
}
else if('\0' == ch)
{ array[count] = '\0';
return(true);
}
else
array[count++] = ch;
}
}
#endif
/*---------------------------------------------------------------------------*/
/* Probably works, but unused */
#if 0
FILE*
openTempFile(char* dir,char* root,char* fullName,char* mode)
/* given dir and mode, return a file pointer to the file, fullName is the
full name of the file including dir. The leaf of the name begins with
root. Only makes sense if mode is a write or append mode
*/
{
FILE* f;
if (dir == NULL)
dir = ".";
if (root == NULL)
root = "temp";
if (!directoryP(dir))
return(NULL);
assert(P_IS_THIS_THREAD_MASTER()); /* random is MT-Unsafe */
for(;;) {
sprintf(fullName,"%s/%s%d.%d",dir,root,getpid(),random() % 10000);
if ((f = locked_fopen(fullName,"r")) == NULL) {
/* no file there to read, we're ok */
return locked_fopen(fullName, mode);
}
else
locked_fclose(f,fullName, TRUE);
}
}
#endif
/*---------------------------------------------------------------------------*/
void
growFile(FILE* file,long length)
{
long currentLength;
safeFSeek(file,0L,SEEK_END);
currentLength = safeFTell(file);
safeFSeek(file,length - currentLength,SEEK_END);
}
/*---------------------------------------------------------------------------*/

View File

@@ -0,0 +1,97 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
/*-------------------------------------------------------------------------- */
#ifndef futil_h
#define futil_h
#include "cdialect.h"
#include "cutil.h"
/*-------------------------------------------------------------------------- */
/* the maximum length of any filename in the system */
#define MAX_FILENAME_LEN (255L)
/* arguments for fseek, which aren't defined on all systems */
#ifndef SEEK_SET
#define SEEK_SET (0L)
#define SEEK_CUR (1L)
#define SEEK_END (2L)
#endif /* ndef SEEK_SET */
/* allow NeXT's to check if the file's mode indicates it's a directory */
#if (defined(NeXT) && !(defined(S_ISDIR)))
#define S_ISDIR(f_mode) ((f_mode) & S_IFDIR)
#endif
/*-------------------------------------------------------------------------- */
/* the following functions are "safe" versions of the standard fileio
utilities. They should be called through the macros rather than
actually calling the functions themselves
*/
/* Replaced by locked_{fopen,fclose} */
#if 0
#define safeFOpen(name,mode) doSafeFOpen((name),(mode))
#define safeFClose(file) { doSafeFClose((FILE*)(file)); \
(file) = NULL;}
#endif
#define safeFSeek(file,offset,whereFrom) \
doSafeFSeek((file),(offset),(whereFrom))
#define safeFTell(file) doSafeFTell((file))
#define safeRename(path1,path2) doSafeRename((path1),(path2))
#if 0
FILE* doSafeFOpen(char* fileName,char* mode);
long doSafeFClose(FILE* file);
#endif
long doSafeFSeek(FILE* file,long offset,long wherefrom);
long doSafeFTell(FILE* file);
/* these functions read and write arbitrary numbers of bytes in
an architecture independent fashion
*/
long writeBytes(long value,long numBytes,FILE* stream);
long readBytes(long numBytes,FILE *stream);
long readBytesFromMemory(long numBytes,unsigned char* block);
/* these routines help manage unix style path names */
char *truename(char *filename,char *full_path);
char *pathnameName(char *pathname);
char *pathnameDirectory(char *pathname,char *destination);
char *mergePathnames(char *pathname,char *directory);
/* set and get characteristics of a file or directory*/
boolean directoryP(char* f);
boolean fileP(char* f);
boolean probeFile(char *filename);
boolean probeFilePossiblyCompressed(char *filename);
boolean touchFile(char *filename);
long fileLength(FILE* stream);
void getFileDates(char* filename,time_t* createDate,time_t* modDate);
/* miscellanious routines */
char *currentUserName(void);
boolean readStringFromFile(FILE* stream,char* array,long array_length);
#if 0
FILE* openTempFile(char* dir,char* root,char* fullName,char* mode);
#endif
void growFile(FILE* file,long len);
/*-------------------------------------------------------------------------- */
#endif /* ndef futil_h */

View File

@@ -0,0 +1,101 @@
/* Copyright (c) 1993, by Pandora Systems */
/* Author: Mitra <mitra@path.net> */
/* Allocation code copied and adapted from:
prospero/alpha.5.2a+/lib/pfs/flalloc */
#include "ietftype.h"
#include <pfs.h>
#include <mitra_macros.h>
#include <psrv.h> /* includes global declarations of
ietftype_count and ietftype_max to be read.
*/
static IETFTYPE lfree = NULL; /* Free ietftypes */
/* These are global shared variables which will be read by dirsrv.c
Too bad C doesn't have better methods for structuring such global data. */
int ietftype_count = 0;
int ietftype_max = 0;
/* Syntactically same as atput in goph_gw_dsdb.c */
PATTRIB ietftype_atput(IETFTYPE it, char *name)
{
PATTRIB at;
/* Fails if no arguments -- at = vatbuild(name, ap); */
at = atalloc();
at->aname = stcopy(name);
at->avtype = ATR_SEQUENCE;
at->nature = ATR_NATURE_APPLICATION;
at->precedence = ATR_PREC_OBJECT;
APPEND_ITEM(at, it->prosperotype);
return at;
}
/************* Standard routines to alloc, free and copy *************/
/*
* ietftype_alloc - allocate and initialize IETFTYPE structure
*
* returns a pointer to an initialized structure of type
* IETFTYPE. If it is unable to allocate such a structure, it
* signals out_of_memory();
*/
IETFTYPE
ietftype_alloc()
{
IETFTYPE thistype;
TH_STRUC_ALLOC(ietftype,IETFTYPE,thistype);
thistype->standardtype=NULL;
thistype->waistype=NULL;
thistype->prosperotype=NULL;
return(thistype);
}
/*
* ietftype_free - free a IETFTYPE structure
*
* ietftype_free takes a pointer to a IETFTYPE structure and adds it to
* the free list for later reuse.
*/
void
ietftype_free(IETFTYPE thistype)
{
if (thistype->standardtype)
{ stfree(thistype->standardtype); thistype->standardtype = NULL;}
if (thistype->waistype)
{ stfree(thistype->waistype); thistype->waistype = NULL;}
if (thistype->prosperotype)
{ atfree(thistype->prosperotype); thistype->prosperotype = NULL;}
TH_STRUC_FREE(ietftype,IETFTYPE,thistype);
}
/*
* ietftype_lfree - free a linked list of IETFTYPE structures.
*
* ietftype_lfree takes a pointer to a ietftype structure frees it and
* any linked
* IETFTYPE structures. It is used to free an entire list of IETFTYPE
* structures.
*/
void
ietftype_lfree(IETFTYPE thistype)
{
TH_STRUC_LFREE(IETFTYPE,thistype,ietftype_free);
}
void
ietftype_freespares()
/* This is used for ietftypes to free up space in the child */
{
IETFTYPE instance;
while((instance = lfree) != NULL) {
/* Note this is slightly lazy, the thistype list is broken during loop*/
lfree = instance->next;
free(lfree); /* Matches malloc in STRUC_ALLOC1*/
ietftype_max--;
}
}

View File

@@ -0,0 +1,32 @@
#ifndef _rmg_ietftype_h
#define _rmg_ietftype_h
#include <pfs.h> /* For ALLOCATOR_CONSISTENCY_CHECK*/
#include <pfs_threads.h>
struct ietftype {
#ifdef ALLOCATOR_CONSISTENCY_CHECK
int consistency;
#endif
char *standardtype;
char *waistype;
PATTRIB prosperotype;
struct ietftype *next;
struct ietftype *previous;
};
typedef struct ietftype *IETFTYPE;
typedef struct ietftype IETFTYPE_ST;
extern PATTRIB ietftype_atput(IETFTYPE it, char *name);
extern IETFTYPE ietftype_alloc();
extern void ietftype_free(IETFTYPE it);
extern void ietftype_lfree(IETFTYPE it);
extern IETFTYPE ietftype_copy(IETFTYPE f,int r);
#ifdef PFS_THREADS
extern p_th_mutex p_th_mutexIETFTYPE;
#endif
#endif /*_rmg_ietftype_h*/

View File

@@ -0,0 +1,90 @@
#define IETFTYPEFILE "/usr/local/lib/ietftypes"
#include <stdio.h>
#include <pfs.h>
#include "ietftype.h"
#include <string.h>
#include <pfs_threads.h>
#include <mitra_macros.h>
/* Shared across threads */
IETFTYPE IETFTypes = NULL;
void ietftype_init();
/* Return the IETF type corresponding to the waistype - or NULL if not found*/
IETFTYPE wais_2_ietftype(char *waistype)
{
IETFTYPE thistype;
if (IETFTypes == NULL) {
#ifndef PFS_THREADS
/* In threaded version, this is done at init time */
ietftype_init();
if (IETFTypes == NULL)
#endif
return NULL;
}
thistype = IETFTypes;
TH_FIND_STRING_LIST_CASE(thistype, waistype, waistype, IETFTYPE);
/* temp = NULL or ietftype to return */
return (thistype);
}
/* Open file of types and initialise data structure */
void ietftype_init() {
FILE *st;
IETFTYPE thistype = NULL;
char ourlinebuf[1024];
int i;
char *tag = NULL;
char *value = NULL;
char *cp;
assert(P_IS_THIS_THREAD_MASTER());
if ((st = fopen(IETFTYPEFILE, "r")) == NULL) /* Not locked_fclose - before mutexes */
/* Should set an error string */
return;
while ((cp = fgets(ourlinebuf, sizeof(ourlinebuf), st)) != NULL) {
if (ourlinebuf[0] == '\n')
continue;
if (ourlinebuf[0] == '#') { /* Seperator & comment*/
thistype = NULL;
continue;
}
if (thistype == NULL) {
thistype = ietftype_alloc();
APPEND_ITEM(thistype, IETFTypes);
}
/*Would be nice if could skip trailing white space in qsscanf*/
for ( i = strlen(ourlinebuf) - 1;
strchr(" \t\n\r",ourlinebuf[i]);
i--)
ourlinebuf[i] = '\0';
if (qsscanf(ourlinebuf, "%&[^:= \t]%*[:= \t]%r",&tag,&value) == 2) {
#define tt1(tgstr,field) \
if (stcaseequal(tag,tgstr)) { \
thistype->field = stcopyr(value,thistype->field); \
continue; \
}
tt1("ietf",standardtype);
tt1("wais",waistype);
if (stcaseequal(tag,"prospero")) {
PATTRIB at=ietftype_atput(thistype,"OBJECT-INTERPRETATION");
assert(P_IS_THIS_THREAD_MASTER());
for(cp=strtok(value,"/");cp != NULL; cp=strtok(NULL,"/"))
tkappend(cp,at->value.sequence);
}
/* Add other fields here as we need them */
/* Ignores unrecognized fields */
}
/* Ignores syntactically incorrect lines */
}
stfree(tag);
fclose(st);
}

View File

@@ -0,0 +1,6 @@
#ifndef IETFTYPE_PARSE_H
#define IETFTYPE_PARSE_H
#include "ietftype.h"
extern IETFTYPE wais_2_ietftype(char *waistype);
extern void ietftype_init(void);
#endif /*IETFTYPE_PARSE_H*/

View File

@@ -0,0 +1,127 @@
# This file defines the relationships between different types
# new records can be added anywhere,
# Order is insignificant, except that this file is searched in order,
# so converting x=a to y will return the value for y, from the first record
# where x=a
#
ietf text/plain
wais TEXT
prospero DOCUMENT/TEXT/ASCII
gopher0 0
#
ietf application/gopher-menu
prospero DOCUMENT
gopher0 1
#
gopher0 4
prospero EMBEDDED/BINHEX/DATA
#
# The Generic Binaries should be Gopher type 9
gopher0 9
prospero DATA
#
gopher0 5
prospero DATA
#
gopher0 6
prospero EMBEDDED/UUENCODE/DATA
#
gopher0 7
prospero SEARCH
#
gopher0 8
prospero PORTAL
#
gopher0 I
prospero IMAGE
#
gopher0 :
prospero IMAGE
#
gopher0 M
ietf multipart/composite?
wais MIME
prospero DOCUMENT/MIME
#
gopher0 T
prospero PORTAL
#
gopher0 g
prospero IMAGE/GIF
wais GIF
#
gopher0 s
prospero SOUND
#
gopher0 <
prospero SOUND
#
# Uncommon type in Iowa gopher - Panda
gopher0 i
prospero VOID
#
gopher0 !
prospero VOID
#
gopher0 ;
prospero VIDEO
#
# CSO
gopher0 2
#
# Error
gopher0 3
#
# Whois
gopher0 w
#
# Possibly an error message type
gopher0 -
#########################################################################
# WAIS types for which incomplete information is available #
#########################################################################
#
#
wais EXCEL
#
wais DVI
#
wais MS-EXCEL
#
wais MS-POWERPOINT
#
wais MS-WORD
# Aldus Persuasion
wais PERSUASION
#
wais PICT
#
wais PS
#
wais QUICKTIME
#
wais TEXT-FTP
#
wais TIFF
# Wais question format
wais WQST
# Wais Source format
# this may end up being special cased to generate appropriate pointers
wais WSRC
ietf text/plain
prospero DOCUMENT/TEXT/ASCII
gopher0 0
#
#########################################################################
# GOPHER0 #
# #
# The next bunch are gopher0 types that correspond to other #
# types that are already listed above. #
#########################################################################
gopher0 e
ietf text/plain
wais TEXT
#
gopher0 c
ietf text/plain
wais TEXT

View File

@@ -0,0 +1,896 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
#define INPROSPERO
#include "zutil.h"
#include "zprot.h"
#include "wprot.h"
#include "wmessage.h"
#include "inface.h"
#include "sockets.h"
#include "waislog.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef INPROSPERO
#include <pfs.h>
#include <perrno.h>
#include "buffalloc.h"
#endif
#include <stdlib.h> /* For malloc and free */
/* from the Prospero library. Also prototyped in <pfs.h> */
extern const char *unixerrstr(void);
static char Err_Connect[]="WAIS gateway unable to connect to: %s(%s)";
#define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
#define RETURN(val) {retval = val; goto cleanup; }
#define WAIS_verbose FALSE
#define TIMEOUT_WAIS_READ 20
#ifdef COMMENT
main()
{
char* server = "server.wais.com";
char* service = "210";
char* database = "smithsonian-pictures";
char* query = "gorilla";
WAISSearchResponse* response;
WAISDocumentHeader* header;
any* text;
response = waisQuery(server, service, database, query);
printf("%s\n",
p_err_string;
);
if (response != NULL) {
header = response->DocHeaders[1];
text =
waisRetrieve(server, service, database,
header->DocumentID,
"TEXT", /* JFIF, THNL */
header->DocumentLength);
printf("%s", text->bytes);
printf("%s\n", p_err_string);
}
}
#endif
static void showDiags(diagnosticRecord **d);
static long interpret_message(char* request_message,
long request_length, /* length of the buffer */
char* response_message,
long response_buffer_length,
FILE* connection,
boolean verbose);
static long transport_message(FILE* connection,
char* request_message,
long request_length,
char* response_message,
long response_buffer_length);
static long initConnection(char* inBuffer,
char* outBuffer,
long bufferSize,
FILE* connection,
char* userInfo);
static char* generate_search_apdu(char* buff,
long* buff_len,
char* seed_words,
char* database_name,
DocObj** docobjs,
long maxDocsRetrieved);
static char* generate_retrieval_apdu(char* buff,
long* buff_len,
any* docID,
long chunk_type,
long start,
long end,
char* type,
char* database_name);
/* return NULL pointer in event of an error */
WAISSearchResponse* waisQuery (char* server_name,
char* service,
char* database,
char* keywords)
{
/*FIX:Mitra:leaks, malloc,p_err_string */
char userInfo[500];
char hostname[80];
char domainname[80];
WAISMSGBUFF request_msg = NULL; /* arbitrary message limit */
WAISMSGBUFF response_msg = NULL; /* arbitrary message limit */
char *request_message = NULL;
char *response_message = NULL;
long request_buffer_length; /* how of the request is left */
SearchResponseAPDU *query_response;
WAISSearchResponse *query_response_info;
long Max_Docs = 40, message_length = MAX_MESSAGE_LENGTH;
FILE *connection = NULL;
WAISSearchResponse *retval;
if (server_name[0] == '\0' && service[0] == '\0')
connection = NULL; /* do local searching */
else { /* remote search, fill in defaults*/
if (server_name[0] == '\0')
/*default to local machine*/
gethostname(server_name,MAX_SERVER_LENGTH);
if (service[0] == '\0')
strcpy(service, Z39_50_SERVICE); /* default */
if ((connection = connectToServer(server_name,atoi(service))) == NULL){
p_err_string = qsprintf_stcopyr(p_err_string,
Err_Connect,
server_name, service);
RETURN(NULL);
}
}
request_msg = waismsgbuff_alloc(); request_message = request_msg->buff;
response_msg = waismsgbuff_alloc(); response_message = response_msg->buff;
gethostname(hostname, 80);
getdomainname(domainname, 80);
sprintf(userInfo, "prospero gateway from host: %s.%s", hostname, domainname);
if((message_length =
initConnection(request_message,
response_message,
message_length,
connection,
userInfo)) <= 0) {
p_err_string = qsprintf_stcopyr(p_err_string, Err_Connect,
server_name, service);
RETURN(NULL);
}
request_buffer_length = message_length; /* how of the request is left */
if(NULL ==
generate_search_apdu(request_message + HEADER_LENGTH,
&request_buffer_length,
keywords, database, NULL, Max_Docs)) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Error creating search APDU: request too large");
RETURN(NULL);
}
if(0 ==
interpret_message(request_message,
message_length - request_buffer_length,
response_message,
message_length,
connection,
WAIS_verbose /* true verbose */
)) { /* perhaps the server shut down on us */
p_err_string = qsprintf_stcopyr(p_err_string,
"Unable to deliver message");
RETURN(NULL);
}
readSearchResponseAPDU(&query_response, response_message + HEADER_LENGTH);
query_response_info =
((WAISSearchResponse *)query_response->DatabaseDiagnosticRecords);
freeSearchResponseAPDU( query_response);
RETURN (query_response_info);
cleanup:
if (connection) fclose(connection);
waismsgbuff_free(request_msg);
waismsgbuff_free(response_msg);
return(retval);
}
/* Retrieve next part of DocumentID, assumes open connection to host */
int
waisRequestNext(FILE *connection,
char *request_message, char *response_message,
long message_length, any *DocumentID,
char *DocumentType, char *database,
long count)
{
long request_buffer_length; /* how of the request is left */
request_buffer_length = message_length; /* how often the request is left */
if(0 ==
generate_retrieval_apdu(request_message + HEADER_LENGTH,
&request_buffer_length,
DocumentID,
CT_byte,
count * CHARS_PER_PAGE,
(count + 1) * CHARS_PER_PAGE,
DocumentType,
database)) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Error generating retrieval APDU: request too long");
return(-1);
}
if(0 ==
interpret_message(request_message,
message_length - request_buffer_length,
response_message,
message_length,
connection,
WAIS_verbose /* true verbose */
)) { /* perhaps the server shut down, let's see: */
p_err_string = qsprintf_stcopyr(p_err_string,
"Error delivering message");
return(-1);
}
return(0);
}
any* waisRetrieve(char* server_name,
char* service,
char* database,
any* DocumentID,
char* DocumentType,
long DocumentLength)
{
/* docHeader = query_info->DocHeaders[document_number]; */
char userInfo[500];
char hostname[80];
char domainname[80];
WAISMSGBUFF request_msg = NULL;
WAISMSGBUFF response_msg = NULL;
SearchResponseAPDU* retrieval_response = NULL;
WAISDocumentText* fragmentText;
any* fragment = NULL;
any* document_text = NULL;
long count = 0, message_length = MAX_MESSAGE_LENGTH;
FILE *connection = NULL;
any *retval;
if (server_name[0] == '\0' && service[0] == '\0')
connection = NULL; /* do local searching */
else /* remote search, fill in defaults*/
{ if (server_name[0] == '\0')
/*default to local machine*/
gethostname(server_name,MAX_SERVER_LENGTH);
if (service[0] == '\0')
strcpy(service, Z39_50_SERVICE); /* default */
if ((connection = connectToServer(server_name,atoi(service))) == NULL)
{ p_err_string = qsprintf_stcopyr(p_err_string, Err_Connect,
server_name, service);
RETURN (NULL);
}
}
request_msg = waismsgbuff_alloc();
response_msg = waismsgbuff_alloc();
gethostname(hostname, 80);
getdomainname(domainname, 80);
sprintf(userInfo, "prospero gateway from host: %s.%s", hostname, domainname);
if((message_length =
initConnection(request_msg->buff,
response_msg->buff,
message_length,
connection,
userInfo)) <= 0) {
p_err_string = qsprintf_stcopyr(p_err_string, Err_Connect,
server_name, service);
RETURN(NULL);
}
if (DocumentType == NULL) DocumentType = s_strdup("TEXT");
/* we must retrieve the document in parts since it might be very long*/
while (TRUE) {
if (waisRequestNext(connection, request_msg->buff,
response_msg->buff,
message_length, DocumentID, DocumentType, database, count)) {
freeAny(document_text);
RETURN(NULL);
}
readSearchResponseAPDU(&retrieval_response,
response_msg->buff + HEADER_LENGTH);
if(NULL ==
((WAISSearchResponse *)
retrieval_response->DatabaseDiagnosticRecords)->Text) {
p_err_string = qsprintf_stcopyr(p_err_string,
"No text was returned");
freeAny(document_text);
return(NULL);
} else {
fragmentText = ((WAISSearchResponse *)
retrieval_response->DatabaseDiagnosticRecords)->Text[0];
fragment = fragmentText->DocumentText;
if (count == 0) {
document_text = duplicateAny(fragment);
} else {
/* Increase document_text size to accomodate fragment. */
if (!(document_text->bytes =
s_realloc(document_text->bytes,
(size_t)(document_text->size + fragment->size) * sizeof(char)))) {
/* May never get here, since can abort if no memory */
p_err_string = qsprintf_stcopyr(p_err_string,
"Unable to allocate space for %d bytes",
document_text->size+fragment->size * sizeof(char));
freeAny(document_text);
RETURN(NULL);
}
/* Copy the fragment into the document_text. */
memcpy(&(document_text->bytes[document_text->size]),
fragment->bytes,
(size_t) fragment->size * sizeof(char));
/* Adjust the size field of document_text. */
document_text->size = fragment->size + document_text->size;
}
}
/* Under normal behaviour it will loop until it encounters a diagnostic
saying read beyond end of document, and then return */
if(((WAISSearchResponse *)
retrieval_response->DatabaseDiagnosticRecords)->Diagnostics != NULL) {
showDiags(((WAISSearchResponse *)
retrieval_response->DatabaseDiagnosticRecords)->Diagnostics);
p_err_string = qsprintf_stcopyr(p_err_string, "Diagnostic records received");
RETURN(document_text);
}
count++;
freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords);
freeSearchResponseAPDU( retrieval_response);
retrieval_response = NULL;
}
RETURN(document_text);
cleanup:
freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords);
freeSearchResponseAPDU( retrieval_response);
if (connection) fclose(connection);
waismsgbuff_free(request_msg);
waismsgbuff_free(response_msg);
return(retval);
}
int waisRetrieveFile(
char* server_name,
char* service,
char* database,
any* DocumentID,
char* DocumentType,
long DocumentLength,
char* local)
{
/* docHeader = query_info->DocHeaders[document_number]; */
char userInfo[500];
char hostname[80];
char domainname[80];
WAISMSGBUFF request_msg = NULL;
WAISMSGBUFF response_msg = NULL;
SearchResponseAPDU* retrieval_response = NULL;
WAISDocumentText* fragmentText;
any* fragment = NULL;
any* document_text = NULL;
long count = 0, message_length = MAX_MESSAGE_LENGTH;
FILE *connection = NULL;
int retval;
int fd = -1;
if (server_name[0] == '\0' && service[0] == '\0')
connection = NULL; /* do local searching */
else /* remote search, fill in defaults*/
{ if (server_name[0] == '\0')
/*default to local machine*/
gethostname(server_name,MAX_SERVER_LENGTH);
if (service[0] == '\0')
strcpy(service, Z39_50_SERVICE); /* default */
if ((connection = connectToServer(server_name,atoi(service))) == NULL)
{ p_err_string = qsprintf_stcopyr(p_err_string, Err_Connect,
server_name, service);
RETURN (-1);
}
}
request_msg = waismsgbuff_alloc();
response_msg = waismsgbuff_alloc();
gethostname(hostname, 80);
getdomainname(domainname, 80);
sprintf(userInfo, "prospero gateway from host: %s.%s", hostname, domainname);
if((message_length =
initConnection(request_msg->buff,
response_msg->buff,
message_length,
connection,
userInfo)) <= 0) {
p_err_string = qsprintf_stcopyr(p_err_string, Err_Connect,
server_name, service);
RETURN(-1);
}
if (DocumentType == NULL) DocumentType = s_strdup("TEXT");
/* we must retrieve the document in parts since it might be very long*/
while (TRUE) {
if (waisRequestNext(connection, request_msg->buff,
response_msg->buff,
message_length, DocumentID, DocumentType, database, count)) {
freeAny(document_text);
RETURN(-1);
}
readSearchResponseAPDU(&retrieval_response,
response_msg->buff + HEADER_LENGTH);
if(NULL ==
((WAISSearchResponse *)
retrieval_response->DatabaseDiagnosticRecords)->Text) {
p_err_string = qsprintf_stcopyr(p_err_string,
"No text was returned");
freeAny(document_text);
RETURN(-1);
} else {
fragmentText = ((WAISSearchResponse *)
retrieval_response->DatabaseDiagnosticRecords)->Text[0];
fragment = fragmentText->DocumentText;
if (fd == -1) {
if ((fd = open(local,O_WRONLY|O_CREAT|O_TRUNC,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH))
== -1) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Unable to open %s: %s", local, unixerrstr());
RETURN(-1);
}
}
if ((write(fd,fragment->bytes,fragment->size * sizeof(char))) == -1) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Unable to write %d characters to %s: %s",
fragment->size,local,unixerrstr());
RETURN(-1);
}
}
/* Under normal behaviour it will loop until it encounters a diagnostic
saying read beyond end of document, and then return */
if(((WAISSearchResponse *)
retrieval_response->DatabaseDiagnosticRecords)->Diagnostics != NULL) {
showDiags(((WAISSearchResponse *)
retrieval_response->DatabaseDiagnosticRecords)->Diagnostics);
p_err_string = qsprintf_stcopyr(p_err_string, "Diagnostic records received");
RETURN(0);
}
count++;
freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords);
freeSearchResponseAPDU( retrieval_response);
retrieval_response = NULL;
}
RETURN(0);
cleanup:
if (fd != -1) close(fd);
/* Dont check error - may fail if other error)*/
if (retrieval_response) {
freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords);
freeSearchResponseAPDU( retrieval_response);
}
if (connection) fclose(connection);
waismsgbuff_free(request_msg);
waismsgbuff_free(response_msg);
return(retval);
}
/* returns a pointer into the buffer of the next free byte.
if it overflowed, then NULL is returned
*/
char *
generate_retrieval_apdu(buff,
buff_len,
docID,
chunk_type,
start,
end,
type,
database_name)
char *buff;
long *buff_len; /* length of the buffer changed to reflect new data written */
any *docID;
long chunk_type;
long start;
long end;
char *type;
char *database_name;
{
SearchAPDU *search;
char *end_ptr;
char *database_names[2];
char *element_names[3];
any refID;
DocObj *DocObjs[2];
any *query; /* changed from char* by brewster */
if(NULL == type)
type = s_strdup("TEXT");
database_names[0] = database_name;
database_names[1] = NULL;
element_names[0] = " ";
element_names[1] = ES_DocumentText;
element_names[2] = NULL;
refID.size = 1;
refID.bytes = "3";
switch(chunk_type){
case CT_line:
DocObjs[0] = makeDocObjUsingLines(docID, type, start, end);
break;
case CT_byte:
DocObjs[0] = makeDocObjUsingBytes(docID, type, start, end);
break;
}
DocObjs[1] = NULL;
query = makeWAISTextQuery(DocObjs);
search = makeSearchAPDU( 10L, 16L, 15L,
1L, /* replace indicator */
"FOO", /* result set name */
database_names, /* database name */
QT_TextRetrievalQuery, /* query_type */
element_names, /* element name */
&refID, /* reference ID */
query);
end_ptr = writeSearchAPDU(search, buff, buff_len);
/* s_free(DocObjs[0]->Type); it's a copy of the input, don't free it! */
CSTFreeDocObj(DocObjs[0]);
CSTFreeWAISTextQuery(query);
freeSearchAPDU(search);
return(end_ptr);
}
long initConnection(char* inBuffer, /*!! Large malloced buffer */
char* outBuffer, /*!! Large malloced bugger */
long bufferSize,
FILE* connection,
char* userInfo)
{
InitAPDU* init = NULL;
InitResponseAPDU* reply = NULL;
long result;
long retval;
/* construct an init APDU */
init = makeInitAPDU(true,false,false,false,false,bufferSize,bufferSize,
userInfo,defaultImplementationID(),
defaultImplementationName(),
defaultImplementationVersion(),
NULL,userInfo);
/* write it to the buffer */
if ((result =
writeInitAPDU(init,inBuffer+HEADER_LENGTH,&bufferSize) - inBuffer
) <0)
RETURN(-1);
if (interpret_message(inBuffer,
result - HEADER_LENGTH,
outBuffer,
bufferSize,
connection,
WAIS_verbose /* true verbose */
) == 0)
/* error making a connection */
RETURN (-1);
if ((readInitResponseAPDU(&reply,outBuffer + HEADER_LENGTH) == NULL) ||
(reply->Result == false))
RETURN(-1);
/* we got a response back */
result = reply->MaximumRecordSize;
RETURN(result);
cleanup:
if (reply) {
freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
freeInitResponseAPDU(reply);
}
freeInitAPDU(init);
return(retval);
}
/* returns a pointer in the buffer of the first free byte.
if it overflows, then NULL is returned
*/
char*
generate_search_apdu(char* buff, /* buffer to hold the apdu */
long* buff_len, /* buffer length changed for new data */
char* seed_words, /* string of the seed words */
char* database_name, /* copied */
DocObj** docobjs,
long maxDocsRetrieved)
{
/* local variables */
SearchAPDU *search3;
char *end_ptr;
/* This is copied, nothing gained if static*/
char *database_names[2] = {"", 0};
any refID;
WAISSearch *query;
refID.size = 1;
refID.bytes = "3";
database_names[0] = database_name;
query = makeWAISSearch(seed_words, /*pointed at */
docobjs, /* DocObjsPtr */
0L,
1L, /* DateFactor */
0L, /* BeginDateRange */
0L, /* EndDateRange */
maxDocsRetrieved
);
search3 = makeSearchAPDU(30L,
5000L, /* should be large */
30L,
1L, /* replace indicator */
"", /* result set name */
database_names, /* database name (copied)*/
QT_RelevanceFeedbackQuery, /* query_type */
0L, /* element name */
NULL, /* reference ID */
query);
end_ptr = writeSearchAPDU(search3, buff, buff_len);
CSTFreeWAISSearch(query);
freeSearchAPDU(search3); /* frees copy of database_names */
return(end_ptr);
}
/* returns the number of bytes written. 0 if an error */
long
interpret_message(char* request_message,
long request_length, /* length of the buffer */
char* response_message,
long response_buffer_length,
FILE* connection,
boolean verbose)
{
long response_length;
writeWAISPacketHeader(request_message,
request_length,
(long)'z', /* Z39.50 */
"wais ", /* server name */
(long)NO_COMPRESSION, /* no compression */
(long)NO_ENCODING,(long)HEADER_VERSION);
if(connection != NULL) {
if(0 ==
(response_length =
transport_message(connection, request_message,
request_length,
response_message,
response_buffer_length)))
return(0);
}
else{
p_err_string = qsprintf_stcopyr(p_err_string,
"Local search not supported in this version");
return(0);
}
#if !defined(IN_RMG) && !defined(PFS_THREADS)
if(verbose){
printf ("decoded %ld bytes: \n", response_length);
twais_dsply_rsp_apdu(response_message + HEADER_LENGTH,
request_length);
}
#endif
return(response_length);
}
/* this is a safe version of unix 'read' it does all the checking
* and looping necessary
* to those trying to modify the transport code to use non-UNIX streams:
* This is the function to modify!
*/
long read_from_stream(d,buf,nbytes)
long d; /* this is the stream */
char *buf;
long nbytes;
{
long didRead;
long toRead = nbytes;
long totalRead = 0; /* paranoia */
while (toRead > 0){
didRead = quick_read (d, buf, toRead, TIMEOUT_WAIS_READ);
if(didRead == -1) /* error*/
return(-1);
if(didRead == 0) /* eof */
return(-2); /* maybe this should return 0? */
toRead -= didRead;
buf += didRead;
totalRead += didRead;
}
if(totalRead != nbytes) /* we overread for some reason */
return(- totalRead); /* bad news */
return(totalRead);
}
/* returns the length of the response, 0 if an error */
long
transport_message(FILE* connection,
char* request_message,
long request_length,
char* response_message,
long response_buffer_length)
{
WAISMessage header;
long response_length;
/* Write out message. Read back header. Figure out response length. */
if( request_length + HEADER_LENGTH
!= fwrite (request_message, 1L, request_length + HEADER_LENGTH, connection))
return 0;
fflush(connection);
/* read for the first '0' */
while(1){
if(0 > read_from_stream(fileno(connection), response_message, 1))
return 0;
if('0' == response_message[0])
break;
}
if(0 > read_from_stream(fileno(connection),
response_message + 1,
HEADER_LENGTH - 1))
return 0;
readWAISPacketHeader(response_message, &header);
{
char length_array[11];
strncpy(length_array, header.msg_len, 10);
length_array[10] = '\0';
response_length = atol(length_array);
/*
if(verbose){
printf("WAIS header: '%s' length_array: '%s'\n",
response_message, length_array);
}
*/
if(response_length > response_buffer_length){
/* we got a message that is too long, therefore empty the message out,
and return 0 */
long i;
for(i = 0; i < response_length; i++){
read_from_stream(fileno(connection),
response_message + HEADER_LENGTH,
1);
}
return(0);
}
}
if(0 > read_from_stream(fileno(connection),
response_message + HEADER_LENGTH,
response_length))
return 0;
return(response_length);
}
/* modified from Jonny G's version in ui/question.c */
void showDiags(d)
diagnosticRecord **d;
{
long i;
for (i = 0; d[i] != NULL; i++) {
if (d[i]->ADDINFO != NULL) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Code: %s, %s", d[i]->DIAG, d[i] ->ADDINFO);
}
}
}
/* Convert docid into newly stalloc-ed DocumentId */
any *
un_urlascii(char *docid)
{
int i=0;
int j=0; /* Pointer into string for writing */
any *DocumentId;
DocumentId = (any *)malloc(sizeof(any));
if (!DocumentId) out_of_memory();
/* Converted string cant be longer than docid */
DocumentId->bytes = stalloc(strlen(docid)+1);
while (docid[i]) {
if (docid[i] != '%') {
DocumentId->bytes[j++]=docid[i++];
} else {
int conv;
i++;
sscanf(&docid[i],"%2x",&conv);
DocumentId->bytes[j++] = (char)conv;
i += 2;
}
}
DocumentId->size = j;
return DocumentId;
}
int
waisRetrieveFileByHsoname(char *local,char *hsoname)
{
any *DocumentId = NULL;
char *host = NULL;
char *port = NULL;
char *type = NULL;
char *database = NULL;
char *query = NULL;
int tmp;
int retval;
tmp = qsscanf(hsoname, "WAIS-GW/%&[^(](%&[^)])/%&[^/]/%&[^/]/%&[^/]/%[^\n]",
&host, &port, &type, &database, &query);
if (tmp != 5) {
p_err_string = qsprintf_stcopyr(p_err_string,
"Invalid WAIS hsoname: %s", hsoname);
RETURN(-1);
}
DocumentId = un_urlascii(query);
RETURN(waisRetrieveFile(host,port,database,
DocumentId,type,0,local));
cleanup:
if (DocumentId) {
stfree(DocumentId->bytes);
free(DocumentId);
}
stfree(host);
stfree(port);
stfree(type);
stfree(database);
stfree(query);
return(retval);
}

View File

@@ -0,0 +1,35 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
#ifndef interface_h
#define interface_h
#include "wprot.h" /* For WAISSearchResponse */
#define Z39_50_SERVICE "210"
#define MAX_MESSAGE_LENGTH 100000
#define MAX_SERVER_LENGTH 1000
WAISSearchResponse* waisQuery (char* server_name,
char* service,
char* database,
char* keywords);
any* waisRetrieve(char* server_name,
char* service,
char* database,
any* DocumentID,
char* DocumentType,
long DocumentLength);
extern any *un_urlascii(char *docid);
#endif
/*---------------------------------------------------------------------------*/

View File

@@ -0,0 +1,772 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*---------------------------------------------------------------------------*/
/********************************************************
* Writing and reading structures to files. *
* *
* These use the Lisp printer format with the *
* lisp naming conventions. You ask: "Why would *
* you want to use that?". Well, we need an *
* easily readable data syntax that can handle *
* a large number of different data types. *
* Further, we need it to be tagged so that *
* run time tagged languages can read it and *
* it is flexible. We need one that supports *
* optional fields so that the format can *
* grow backcompatibly. And (the kicker), *
* it must be read from many languages since *
* user interfaces may be written in anything *
* from smalltalk to hypercard. *
* *
* -brewster 5/10/90 *
********************************************************/
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <pfs.h>
#include <perrno.h>
#include "irfileio.h"
#include "cutil.h"
#define INDENT_SPACES (2L)
#define MAX_INDENT (40L)
#ifdef NOTUSEDANDNOTTHREADSAFE
static long indent_level;
#endif /*NOTUSEDANDNOTTHREADSAFE
#define RETURN(val) {retval = val; goto cleanup; }
/**********************/
/**********************/
#ifdef NOTUSEDANDNOTTHREADSAFE
static void indent(FILE* file);
static void indent(file)
FILE* file;
{
long i;
for(i = 0; i <= MIN(MAX_INDENT, MAX(0L, indent_level * INDENT_SPACES)); i++){
putc(' ', file);
}
}
long WriteStartOfList(file)
FILE* file;
{
indent_level++;
return(fprintf(file, " ( "));
}
long WriteEndOfList(file)
FILE* file;
{
indent_level--;
return(fprintf(file, " ) "));
}
long WriteStartOfStruct(name,file)
char* name;
FILE* file;
{
indent_level++;
return(fprintf(file, " (:%s ", name));
}
long WriteEndOfStruct(file)
FILE* file;
{
indent_level--;
return(fprintf(file, " ) "));
}
long WriteSymbol(name,file)
char* name;
FILE* file;
{
return(fprintf(file, " %s ", name));
}
long WriteNewline(file)
FILE* file;
{
long return_value = fprintf(file, "\n");
indent(file);
return(return_value);
}
long WriteLong(number,file)
long number;
FILE* file;
{
return(fprintf(file, " %ld ", number));
}
long WriteDouble(number,file)
double number;
FILE* file;
{
return(fprintf(file, " %f ", number));
}
long WriteString(string,file)
char* string;
FILE* file;
{
long i;
putc('\"', file);
for(i = 0; i < strlen(string); i++){
if(string[i] == '\\' || string[i] == '\"')
putc('\\', file);
putc(string[i], file);
}
putc('\"', file);
return(1);
}
long WriteAny(value,file)
any* value;
FILE* file;
{
WriteStartOfStruct("any", file);
WriteSymbol(":size", file); WriteLong(value->size, file);
WriteSymbol(":bytes", file);
Write8BitArray(value->size, value->bytes, file);
return(WriteEndOfStruct(file));
}
long Write8BitArray(length,array,file)
long length;
char* array;
FILE* file;
{
long i;
fprintf(file, " #( ");
for(i=0; i<length; i++){
WriteLong((long)array[i], file);
}
return(fprintf(file, " ) "));
}
long WriteTM(atime,file)
struct tm* atime;
FILE* file;
{
WriteStartOfStruct("tm", file);
WriteSymbol(":tm-sec", file); WriteLong(atime->tm_sec, file);
WriteSymbol(":tm-min", file); WriteLong(atime->tm_min, file);
WriteSymbol(":tm-hour", file); WriteLong(atime->tm_hour, file);
WriteSymbol(":tm-mday", file); WriteLong(atime->tm_mday, file);
WriteSymbol(":tm-mon", file); WriteLong(atime->tm_mon, file);
WriteNewline(file);
WriteSymbol(":tm-year", file); WriteLong(atime->tm_year, file);
WriteSymbol(":tm-wday", file); WriteLong(atime->tm_wday, file);
WriteNewline(file);
WriteSymbol(":tm-yday", file); WriteLong(atime->tm_yday, file);
WriteSymbol(":tm-isdst", file); WriteLong(atime->tm_isdst, file);
WriteEndOfStruct(file);
return(WriteNewline(file));
}
boolean
writeAbsoluteTime(atime,file)
struct tm* atime;
FILE* file;
{
WriteStartOfStruct("absolute-time",file);
WriteNewline(file);
WriteSymbol(":year",file); WriteLong((long)atime->tm_year,file);
WriteNewline(file);
WriteSymbol(":month",file); WriteLong((long)atime->tm_mon,file);
WriteNewline(file);
WriteSymbol(":mday",file); WriteLong((long)atime->tm_mday,file);
WriteNewline(file);
WriteSymbol(":hour",file); WriteLong((long)atime->tm_hour,file);
WriteNewline(file);
WriteSymbol(":minute",file); WriteLong((long)atime->tm_min,file);
WriteNewline(file);
WriteSymbol(":second",file); WriteLong((long)atime->tm_sec,file);
WriteNewline(file);
return(WriteEndOfStruct(file));
}
#endif /*NOTUSEDANDNOTTHREADSAFE*/
/************************/
/************************/
#define BEFORE (1L)
#define DURING (2L)
#define HASH (3L)
#define S (4L)
#define QUOTE (5L)
#if !defined(IN_RMG)
boolean ReadStartOfList(file)
FILE* file;
{
long ch;
while(TRUE){
ch = getc(file);
if(ch == '(')
return(TRUE);
if(!isspace(ch)){
if(ch == 'N' || ch == 'n'){
ch = getc(file);
if(ch == 'I' || ch == 'i'){
ch = getc(file);
if(ch == 'L' || ch == 'l'){
ungetc(')', file);
return(TRUE);
}
}
}
return(FALSE);
}
}
}
boolean ReadEndOfList(file)
FILE* file;
{
long ch;
while(TRUE){
ch = getc(file);
if(ch == ')')
return(TRUE);
if(!isspace(ch))
return(FALSE);
}
}
#endif /*!IN_RMG*/
#define STRING_ESC '\\'
long
SkipObject(file)
FILE* file;
{
long ch;
while (true)
{ ch = getc(file);
if (ch == EOF)
return (EOF);
else
{ if (isspace(ch))
continue;
else if (ch == '"')
{ long escapeCount = 0;
while (true)
{ ch = getc(file);
if (ch == EOF)
return (EOF);
else
{ if (ch == STRING_ESC)
{ escapeCount++;
escapeCount = escapeCount % 2;
}
if (ch == '"' && escapeCount == 0)
break;
}
}
break;
}
else if ((isdigit(ch) || ch == '-' || ch == '.') ||
(ch == ':'))
{ while (!isspace(ch))
{ ch = getc(file);
if (ch == EOF)
return(EOF);
}
break;
}
else if ((ch == '#') ||
(ch == '('))
{ long parenCount = 1;
if (ch == '#')
ch = getc(file);
while (parenCount > 0)
{ ch = getc(file);
if (ch == EOF)
return(EOF);
else if (ch == '"')
{
ungetc(ch,file);
SkipObject(file);
}
else if (ch == '(')
parenCount++;
else if (ch == ')')
parenCount--;
}
break;
}
}
}
return(true);
}
long ReadLong(file,answer)
FILE* file;
long* answer;
{
long ch;
long state = BEFORE;
boolean isNegative = false;
long count = 0;
*answer = 0;
while(TRUE){
ch = getc(file);
if (ch == EOF){
break;
}
else if (isdigit(ch)){
if(state == BEFORE){
state = DURING;
}
count++;
if(count == 12){
return(false);
}
*answer = *answer * 10 + (ch - '0');
}
else if (ch == '-') {
if (isNegative)
return(false);
if (state == BEFORE) {
isNegative = true;
state = DURING;
}
else {
ungetc(ch,file);
break;
}
}
else if(ch == ')' && (state == DURING)){
ungetc(ch, file);
return(true);
}
else if(!isspace(ch)){
return(false);
}
else if(state == DURING){
ungetc(ch, file);
break;
}
}
if (isNegative)
*answer *= -1;
return(true);
}
long ReadDouble(file,answer)
FILE* file;
double* answer;
{
long ch;
long state = BEFORE;
long count = 0;
long decimal_count = 0;
*answer = 0.0;
while(TRUE){
ch = getc(file);
if (ch == EOF){
return(true);
}
else if (ch == '.'){
decimal_count ++;
}
else if (isdigit(ch)){
if(state == BEFORE){
state = DURING;
}
count++;
if(count == 12){
return(false);
}
if (decimal_count == 0){
*answer = *answer * 10 + (ch - '0');
}
else{
double fraction = (ch - '0');
long internal_count;
for(internal_count = 0; internal_count < decimal_count;
internal_count++){
fraction = fraction / 10.0;
}
*answer = *answer + fraction;
decimal_count++;
}
}
else if(!isspace(ch)){
return(false);
}
else if(state == DURING){
ungetc(ch, file);
return(true);
}
}
}
static boolean issymbolchar(long ch);
static
boolean issymbolchar(ch)
long ch;
{
return(!( isspace(ch) || ch == ')' || ch == '(' || ch == EOF));
}
long ReadSymbol(string,file,string_size)
char* string;
FILE* file;
long string_size;
{
long ch;
long state = BEFORE;
long position = 0;
while(TRUE){
ch = getc(file);
if((state == BEFORE) && (ch == ')'))
return(END_OF_STRUCT_OR_LIST);
if(issymbolchar((long)ch)){
if(state == BEFORE)
state = DURING;
string[position] = ch;
position++;
if(position >= string_size){
string[string_size - 1] = '\0';
return(FALSE);
}
}
else if((state == DURING) || ch == EOF){
if(ch != EOF) ungetc(ch, file);
string[position] = '\0';
return(TRUE);
}
}
}
#if !defined(IN_RMG)
long ReadEndOfListOrStruct(file)
FILE* file;
{
long ch;
while(TRUE){
ch = getc(file);
if (EOF == ch)
return(FALSE);
else if(')' == ch)
return(TRUE);
else if(!isspace(ch))
return(FALSE);
}
}
#endif
long ReadString(string,file,string_size)
char* string;
FILE* file;
long string_size;
{
long ch;
long state = BEFORE;
long position = 0;
string[0] = '\0';
while(TRUE){
ch = getc(file);
if((state == BEFORE) && (ch == '\"'))
state = DURING;
else if (EOF == ch){
string[position] = '\0';
return(FALSE);
}
else if ((state == BEFORE) && (ch == ')'))
return(END_OF_STRUCT_OR_LIST);
else if ((state == DURING) && (ch == '\\'))
state = QUOTE;
else if ((state == DURING) && (ch == '"')){
string[position] = '\0';
return(TRUE);
}
else if ((state == QUOTE) || (state == DURING)){
if(state == QUOTE)
state = DURING;
string[position] = ch;
position++;
if(position >= string_size){
string[string_size - 1] = '\0';
return(FALSE);
}
}
}
}
long ReadStartOfStruct(name,file)
char* name;
FILE* file;
{
int ch;
long state = BEFORE;
name[0] = '\0';
while(TRUE){
ch = getc(file);
if((state == BEFORE) && (ch == '#'))
state = HASH;
if((state == BEFORE) && (ch == '('))
state = DURING;
else if((state == BEFORE) && (ch == ')'))
return(END_OF_STRUCT_OR_LIST);
else if((state == BEFORE) && !isspace(ch))
return(FALSE);
else if(state == HASH){
if (ch == 's')
state = S;
else{
fprintf(stderr,"Expected an 's' but got an %c\n", ch);
return(FALSE);
}
}
else if(state == S){
if (ch == '(')
state = DURING;
else{
fprintf(stderr,"Expected an '(' but got an an %c\n",ch);
return(FALSE);
}
}
else if(state == DURING){
return(ReadSymbol(name, file, MAX_SYMBOL_SIZE));
}
}
}
long CheckStartOfStruct(name,file)
char* name;
FILE* file;
{
char temp_string[MAX_SYMBOL_SIZE];
long result = ReadStartOfStruct(temp_string, file);
if(result == END_OF_STRUCT_OR_LIST)
return(END_OF_STRUCT_OR_LIST);
else if(result == FALSE)
return(FALSE);
else if(0 == strcmp(temp_string, name))
return(TRUE);
else
return(FALSE);
}
#if !defined(IN_RMG)
long ReadAny(destination,file)
any* destination;
FILE* file;
{
char temp_string[MAX_SYMBOL_SIZE];
long retval;
destination->size = 0;
if(FALSE == CheckStartOfStruct("any", file)){
fprintf(stderr,"An 'any' structure was not read from the disk");
return(FALSE);
}
while(TRUE){
long check_result;
check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
if(FALSE == check_result)
return(FALSE);
if(END_OF_STRUCT_OR_LIST == check_result)
RETURN(TRUE);
if(0 == strcmp(temp_string, ":size")) {
long size;
ReadLong(file,&size);
destination->size = (unsigned long)size;
}
else if(0 == strcmp(temp_string, ":bytes")){
long result;
destination->bytes = (char*)s_malloc(destination->size);
if(NULL == destination->bytes){
/* May never get here, s_malloc may abort if no space */
p_err_string = qsprintf_stcopyr(p_err_string,
"Error on reading file. Malloc couldnt allocate %d bytes",
destination->size );
RETURN(FALSE);
}
result = Read8BitArray(destination->bytes, file, destination->size);
if(FALSE == result)
RETURN(FALSE);
}
else{
p_err_string = qsprintf_stcopyr(p_err_string,
"Unknown keyword for ANY %s\n", temp_string);
RETURN(FALSE);
}
} /*while*/
cleanup:
/* For now, not freeing destination->bytes on error, let caller do it*/
return(retval);
}
long
Read8BitArray(char *destination, FILE *file,long len)
{
int ch; /* don't use a long, because %c conversion
isn't defined for longs. */
long state = BEFORE;
while(TRUE){
ch = getc(file);
if((state == BEFORE) && ((ch == '#') || (ch == '('))) {
if (ch == '(') state = DURING;
else state = HASH;
}
else if((state == BEFORE) && !isspace(ch)){
fprintf(stderr,"error in reading array. Expected # and got %c", ch);
return(FALSE);
}
else if(state == HASH){
if (ch == '(')
state = DURING;
else{
fprintf(stderr,"Expected an '(' but got an %c\n", ch);
return(FALSE);
}
}
else if(state == DURING){
long i;
ungetc(ch, file);
for(i = 0; i < len; i++){
long value;
if(ReadLong(file,&value) == false){
fprintf(stderr,"Error in reading a number from the file.");
return(FALSE);
}
if(value > 255){
fprintf(stderr,"Error in reading file. Expected a byte in an ANY, but got %ld", value);
return(FALSE);
}
destination[i] = (char)value;
}
if(FALSE == ReadEndOfListOrStruct(file)){
fprintf(stderr,"array was wrong length");
return(FALSE);
}
return(TRUE);
}
}
}
boolean
readAbsoluteTime(atime,file)
struct tm* atime;
FILE* file;
{
if (CheckStartOfStruct("absolute-time",file) == FALSE)
return(false);
while (true)
{ long result;
long val;
char temp_string[MAX_SYMBOL_SIZE + 1];
result = ReadSymbol(temp_string,file,MAX_SYMBOL_SIZE);
if (result == END_OF_STRUCT_OR_LIST)
break;
else if (result == false)
return(false);
if (strcmp(temp_string,":second") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_sec = val;
}
else if (strcmp(temp_string,":minute") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_min = val;
}
else if (strcmp(temp_string,":hour") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_hour = val;
}
else if (strcmp(temp_string,":mday") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_mday = val;
}
else if (strcmp(temp_string,":month") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_mon = val;
}
else if (strcmp(temp_string,":year") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_year = val;
}
else
SkipObject(file);
}
return(true);
}
#endif

View File

@@ -0,0 +1,46 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*---------------------------------------------------------------------------*/
#ifndef IRCFILEIO_H
#define IRCFILEIO_H
#include "cdialect.h"
#include "futil.h"
#include "zprot.h"
#define MAX_SYMBOL_SIZE (255L)
#define END_OF_STRUCT_OR_LIST (6L)
long SkipObject(FILE* file);
long ReadLong(FILE* file,long* num);
long ReadDouble(FILE* file,double* num);
long ReadSymbol(char* string, FILE* file, long string_size);
long ReadString(char* string, FILE* file, long string_size);
long CheckStartOfStruct(char* name, FILE* file);
long ReadAny(any* destination, FILE* file);
long ReadTM(struct tm* /* time */, FILE* file);
long Read8BitArray(char* destination, FILE* file, long /* length */);
long ReadEndOfListOrStruct(FILE* file);
long ReadStartOfStruct(char* name, FILE* file);
boolean ReadStartOfList(FILE* file);
boolean ReadEndOfList(FILE* file);
boolean readAbsoluteTime(struct tm* /* time */,FILE* file);
long WriteStartOfStruct(char* name, FILE* file);
long WriteEndOfStruct(FILE* file);
long WriteSymbol(char* name, FILE* file);
long WriteString(char* string, FILE* file);
long WriteNewline(FILE* file);
long WriteLong(long number, FILE* file);
long WriteDouble(double number, FILE* file);
long WriteAny(any* value, FILE* file);
long Write8BitArray(long /* length */, char* array, FILE* file);
long WriteTM(struct tm* /* time */, FILE* file);
long WriteStartOfList(FILE* file);
long WriteEndOfList(FILE* file);
boolean writeAbsoluteTime(struct tm* /* time */,FILE* file);
#endif

View File

@@ -0,0 +1,217 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
#include "list.h"
/*---------------------------------------------------------------------------*/
void
mapcar(list l,void (*function)())
{
long i;
if (null(l))
return;
for (i = 0; i < length(l); i++)
{ (*function)(nth(l,i));
}
}
/*---------------------------------------------------------------------------*/
list
collecting(list l,void *item)
{
if (l == NULL)
if (!(l = (list)s_malloc(sizeof(listStruct))))
return NULL;
if (l->rlen < length(l) + 1)
{ l->rlen = length(l) + 2;
l->elems = (void**)s_realloc(l->elems,l->rlen * sizeof(void*));
}
l->elems[length(l)] = item;
l->len++;
return(l);
}
/*---------------------------------------------------------------------------*/
void
freeList(list l)
{
if (l != NULL)
{ s_free(l->elems);
s_free(l);
}
}
/*---------------------------------------------------------------------------*/
static long
cmpStrings(void* arg1,void* arg2)
{
return(strcmp(*(char**)arg1,*(char**)arg2));
}
/*---------------------------------------------------------------------------*/
void
sortList(list l,long (*cmp)())
{
if (cmp == NULL)
cmp = cmpStrings;
if (length(l) > 1)
qsort(l->elems,length(l),sizeof(void*),cmp);
}
/*---------------------------------------------------------------------------*/
list
insertNth(list l,long n,void* elem)
{
if (null(l))
return(NULL);
if (n > length(l))
return(NULL);
if (l->rlen < length(l) + 1)
{ l->rlen = length(l) + 2;
l->elems = (void**)s_realloc(l->elems,l->rlen*sizeof(void*));
}
memmove(l->elems+n+1,l->elems+n,(length(l)-n)*sizeof(void*));
l->elems[n] = elem;
l->len++;
return(l);
}
/*---------------------------------------------------------------------------*/
list
removeNth(list l,long n)
{
if (null(l))
return(NULL);
if (n >= length(l))
return(NULL);
memmove(l->elems+n,l->elems+n+1,(length(l)-n-1)*sizeof(void*));
l->len--;
if (l->rlen > 4 && l->rlen > length(l) * 2)
{ l->rlen = length(l);
l->elems = (void**)s_realloc(l->elems,l->rlen * sizeof(void*));
}
return(l);
}
/*---------------------------------------------------------------------------*/
boolean
lookupInSortedList(list l,void* val,long (*cmpFunc)(void* arg1,void* arg2),
long* posInList)
{
long pos;
long upperBound = length(l);
long lowerBound = 0;
long cmp;
void* data;
if (null(l))
{ if (posInList != NULL)
*posInList = 0;
return(false);
}
if (cmpFunc == NULL)
cmpFunc = cmpStrings;
while (upperBound >= lowerBound)
{
pos = lowerBound + ((upperBound - lowerBound) / 2);
if (pos == length(l))
cmp = -1;
else
{ data = nth(l,pos);
cmp = (*cmpFunc)(&val,&data);
}
if (cmp == 0)
{ if (posInList != NULL)
*posInList = pos;
return(true);
}
else if (cmp < 0)
{ if (pos == lowerBound)
{ if (posInList != NULL)
*posInList = pos;
return(false);
}
else
upperBound = pos;
}
else
{ if (pos >= length(l))
{ if (posInList != NULL)
*posInList = pos;
return(false);
}
else
lowerBound = pos + 1;
}
}
if (posInList != NULL)
*posInList = length(l);
return(false);
}
/*---------------------------------------------------------------------------*/
void*
pop(list* l)
{
void* ans;
if (l == NULL || *l == NULL)
return(NULL);
ans = first(*l);
*l = removeNth(*l,0);
return(ans);
}
/*---------------------------------------------------------------------------*/
void
push(list* l,void* elem)
{
if (l == NULL)
return;
*l = insertNth(*l,0,elem);
}
/*---------------------------------------------------------------------------*/

View File

@@ -0,0 +1,57 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
#ifndef list_h
#define list_h
#include "cutil.h"
/*---------------------------------------------------------------------------*/
typedef struct listStruct
{ void** elems;
long len;
long rlen;
} listStruct;
#define list listStruct*
#define length(l) (long)(((l) == NULL) ? 0L : (l)->len)
#define nth(l,n) \
(((l) == NULL || length((l)) <= (n)) ? NULL : (l)->elems[(n)])
#define car(l) (nth((l),0L))
#define cadr(l) (nth((l),2L))
#define cdr(l) (removeNth((l),0L))
#define first(l) (car(l))
#define last(l) (nth((l),length((l))-1L))
#define rest(l) (cdr(l))
#define setfNth(l,n,elem) \
(((l) == NULL || length((l)) <= (n)) ? 0 : ((l)->elems[(n)] = (elem)))
#define setfCar(l,elem) (setfNth((l),0L,(elem)))
#define null(l) (((l) == NULL || length((l)) == 0L) ? true : false)
void mapcar(list l,void function (void* argument));
list collecting(list l,void *item);
void freeList(list l);
void sortList(list l,long (*cmp)(void* arg1,void* arg2));
list insertNth(list l,long n,void* elem);
list removeNth(list l,long n);
boolean lookupInSortedList(list l,void* val,
long (*cmpFunc)(void* arg1,void* arg2),
long* posInList);
void* pop(list* l);
void push(list* l,void* elem);
/*---------------------------------------------------------------------------*/
#endif

View File

@@ -0,0 +1,4 @@
main()
{
}

View File

@@ -0,0 +1,53 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*---------------------------------------------------------------------------*/
#include <ctype.h>
#include "panic.h"
#include "waislog.h"
#include "cutil.h"
#include <pfs.h> /* for stcopyr() */
#include <perrno.h>
extern int fault_count;
/*----------------------------------------------------------------------*/
void
panic(char* formatString,...)
/* something bad and unexpected has happened, print out a log message
and abort the program in such a way that it can be debugged.
*/
{
va_list ap;
char msg[2000];
va_start(ap,formatString);
vsprintf(msg,formatString,ap);
#if !defined(IN_RMG)
#if !defined(PFS_THREADS)
waislog(WLOG_HIGH,WLOG_ERROR,msg);
#else
#error NO WAY TO LOG - DONT COMPILE LIKE THIS
#endif
#else
p_err_string = stcopyr(p_err_string, msg);
/* restart_server(fault_count, msg); */
#endif
va_end(ap);
#ifdef THINK_C
Debugger();
#endif
abort();
}
/*----------------------------------------------------------------------*/

View File

@@ -0,0 +1,15 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*---------------------------------------------------------------------------*/
#ifndef panic_h
#define panic_h
#include "cdialect.h"
void panic(char* formatString,...);
#endif

View File

@@ -0,0 +1,184 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*---------------------------------------------------------------------------*/
#define sockets_c
#include "sockets.h"
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <posix_signal.h>
#include "panic.h"
#include "waislog.h"
/* In theory this is defined in stdio.h, but its hosed on SOLARIS */
extern FILE *fdopen(const int fd, const char *opt);
extern char *sys_errlist[];
#define QUEUE_SIZE (3L)
#define HOSTNAME_BUFFER_SIZE (120L)
#define MAX_RETRYS (10L)
#define TIMEOUT_CONNECT 5
/*---------------------------------------------------------------------------*/
#if !defined(IN_RMG) && !defined(PFS_THREADS)
static boolean
clrSocket(struct sockaddr_in *address,long portnumber,long *sock)
{
if (errno == EADDRINUSE)
{ if (connect(*sock, address, sizeof (struct sockaddr_in)) == 0)
{ close(*sock);
waislog(WLOG_HIGH,WLOG_ERROR,
"cannot bind port %ld (address already in use)",
portnumber);
waislog(WLOG_HIGH,WLOG_ERROR,
"waisserver is already running on this system");
panic("Exiting");
}
else
{ int one = 1;
close(*sock);
if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
panic("Open socket failed in trying to clear the port.");
if (setsockopt(*sock,SOL_SOCKET,SO_REUSEADDR,&one,sizeof(one)) < 0)
; /* do nothing? */
address->sin_family = AF_INET;
address->sin_addr.s_addr = INADDR_ANY;
address->sin_port = htons(portnumber);
if (bind(*sock, address, sizeof(*address)) == 0)
; /* do nothing? */
}
}
return(true);
}
/*---------------------------------------------------------------------------*/
void
openServer(long port,long* fd,long size)
{
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
if ((*fd = socket(AF_INET,SOCK_STREAM,0)) < 0)
{ panic("can't get file descriptor for socket: %s", sys_errlist[errno]);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(port);
if (bind(*fd,(struct sockaddr*)&address,sizeof(struct sockaddr)) < 0)
clrSocket(&address, port, fd);
if (listen(*fd,QUEUE_SIZE) < 0)
panic("can't open server: %s", sys_errlist[errno]);
}
/*---------------------------------------------------------------------------*/
void
fdAcceptClientConnection(long socket,long* fd)
{
struct sockaddr_in source;
int sourcelen;
#ifdef BSD
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
u_long S_addr;
} S_un;
} addr_p;
#endif
sourcelen = sizeof(struct sockaddr_in);
do {
errno = 0;
*fd = accept(socket, &source, &sourcelen);
} while (*fd < 0 && errno == EINTR);
if (source.sin_family == AF_INET)
{ struct hostent *peer = NULL;
peer = gethostbyaddr((char*)&source.sin_addr, 4, AF_INET);
waislog(WLOG_MEDIUM,WLOG_CONNECT,"accepted connection from: %s [%s]",
(peer == NULL) ? "" : peer->h_name,
#if defined(sparc) && defined(__GNUC__) && !defined(__svr4__)
inet_ntoa(&source.sin_addr));
#else
inet_ntoa(source.sin_addr));
#endif /* sparc */
}
if (*fd < 0)
panic("can't accept connection");
}
/*---------------------------------------------------------------------------*/
void
acceptClientConnection(long socket,FILE** file)
{
long fd;
fdAcceptClientConnection(socket,&fd);
if ((*file = fdopen(fd,"r+")) == NULL)
panic("can't accept connection");
}
/*---------------------------------------------------------------------------*/
void
closeClientConnection(FILE* file)
{
fclose(file);
}
/*---------------------------------------------------------------------------*/
void
closeServer(long socket)
{
close(socket);
}
#endif /*!IN_RMG && !PFS_THREADS*/
/*---------------------------------------------------------------------------*/
FILE *
connectToServer(char* host_name,long port)
{
FILE* file;
int fd;
if ((fd = quick_open_tcp_stream(host_name, port, TIMEOUT_CONNECT)) == -1)
return(NULL);
if ((file = fdopen(fd,"r+")) == NULL)
{ perror("Connect to socket did not work, fdopen failure");
close(fd);
return(NULL);
}
return(file);
}
/*---------------------------------------------------------------------------*/
void
closeConnectionToServer(FILE* file)
{
fclose(file);
}
/*---------------------------------------------------------------------------*/

View File

@@ -0,0 +1,37 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*---------------------------------------------------------------------------*/
#ifndef sockets_h
#define sockets_h
#include "cdialect.h"
#include "cutil.h"
#ifndef THINK_C
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
/*---------------------------------------------------------------------------*/
void openServer(long port,long* socket,long size);
void acceptClientConnection(long socket,FILE** file);
void closeClientConnection(FILE* file);
void closeServer(long socket);
FILE *connectToServer(char* hostname,long port);
void closeConnectionToServer(FILE* file);
/*---------------------------------------------------------------------------*/
#endif

View File

@@ -0,0 +1,835 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
This is part of the shell user-interface tools for the WAIS software.
*/
/*---------------------------------------------------------------------------*/
#define _C_SOURCE
#include <string_with_strcasecmp.h>
#include <stdio.h>
#include "cutil.h"
#include "futil.h"
#include "irfileio.h"
#include "source.h"
#include <list_macros.h> /* For TH_APPEND_LIST*/
#include <mitra_macros.h> /* For TH_FIND_LIST */
#include <psrv.h> /* includes global declarations of
waissource_count and waissource_max to be
read. */
#define DESC_SIZE 65535
extern int alphasort();
#if !defined(IN_RMG) && !defined(PFS_THREADS)
SList Sources;
/* I'm not sure why this is all commented out, looks like its been
superceeded by "SList Sources" */
char **Source_items = NULL;
#else
WAISSOURCE WaisSources = NULL;
#endif /*!IN_RMG && !PFS_THREADS*/
char *sourcepath = NULL;
#if !defined(IN_RMG) && !defined(PFS_THREADS)
void
freeSourceID(sid)
SourceID sid;
{
if (sid != NULL) {
if (sid->filename != NULL) s_free(sid->filename);
s_free(sid);
}
}
SourceID
copysourceID(sid)
SourceID sid;
{
SourceID result = NULL;
if(sid != NULL) {
if((result = (SourceID) s_malloc(sizeof(_SourceID))) != NULL) {
result->filename = s_strdup(sid->filename);
}
}
return result;
}
char **
buildSourceItemList(sourcelist)
SourceList sourcelist;
{
char **result;
int num, i;
SourceList source;
/* find the length of the sidlist in the question */
for (num = 0, source = sourcelist;
source != NULL && source->thisSource != NULL;
num++, source = source->nextSource);
result = (char**)s_malloc((1+num)*sizeof(char*));
if(num > 0)
for(i =0, source = sourcelist; i<num; i++, source = source->nextSource)
result[i] = source->thisSource->filename;
result[num] = NULL;
return(result);
}
char **
buildSItemList(sourcelist)
SList sourcelist;
{
char **result;
int num, i;
SList source;
/* find the length of the sidlist in the question */
for(num = 0, source = sourcelist;
source != NULL;
num++, source = source->nextSource);
result = (char**) s_malloc((1+num)*sizeof(char*));
if(num > 0)
for(i =0, source = sourcelist; i<num; i++, source = source->nextSource)
if(source->thisSource != NULL)
result[i] = source->thisSource->name;
result[num] = NULL;
return(result);
}
static short
ReadSourceID(file, sid)
FILE *file;
SourceID sid;
{
char temp_string[MAX_SYMBOL_SIZE];
char filename[MAX_SYMBOL_SIZE];
short check_result;
check_result = CheckStartOfStruct("source-id", file);
filename[0] = '\0';
if(FALSE == check_result){
return(false);
}
if(END_OF_STRUCT_OR_LIST == check_result)
{
return(FALSE);
}
/* read the slots: */
while(TRUE){
short check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
if(END_OF_STRUCT_OR_LIST == check_result) break;
if(FALSE == check_result){
return(false);
}
if(0 == strcmp(temp_string, ":filename")) {
if (FALSE == ReadString(filename, file, MAX_SYMBOL_SIZE))
return(false);
sid->filename = s_strdup(filename);
}
else
SkipObject(file);
}
return(TRUE);
}
SourceList ReadListOfSources(file)
FILE *file;
{
short check_result;
SourceID sid = NULL;
SourceList result, this, last;
/* initialize */
this = last = result = NULL;
if(ReadStartOfList(file) == FALSE)
return(NULL);
while(TRUE) {
sid = (SourceID)s_malloc(sizeof(_SourceID));
check_result = ReadSourceID(file, sid);
if(check_result == END_OF_STRUCT_OR_LIST) {
s_free(sid);
return(result);
}
else if(check_result == FALSE)
return(result);
else if(check_result == TRUE) {
if(result == NULL)
result = this = (SourceList)s_malloc(sizeof(_SourceList));
else
this = (SourceList)s_malloc(sizeof(_SourceList));
this->thisSource = sid;
if(last != NULL)
last->nextSource = this;
last = this;
}
}
}
#endif /*!defined(IN_RMG) && !defined(PFS_THREADS)*/
/* from util.c */
void find_value(source, key, value, value_size)
char *source, *key, *value;
int value_size;
{
char ch;
long position = 0; /* position in value */
char *pos =(char*)strstr(source, key); /* address into source */
value[0] = '\0'; /* initialize to nothing */
if(NULL == pos)
return;
pos = pos + strlen(key);
ch = *pos;
/* skip leading quotes and spaces */
while((ch == '\"') || (ch == ' ')) {
pos++; ch = *pos;
}
for(position = 0; pos < source + strlen(source); pos++){
if((ch = *pos) == ' ') {
value[position] = '\0';
return;
}
value[position] = ch;
position++;
if(position >= value_size){
value[value_size - 1] = '\0';
return;
}
}
value[position] = '\0';
}
static boolean
ReadSource(WAISSOURCE source, FILE *file)
{
char temp_string[MAX_SYMBOL_SIZE];
char desc_string[DESC_SIZE];
short check_result;
long port;
long version;
/* make sure it's a Source */
check_result = CheckStartOfStruct("source", file);
if(FALSE == check_result){
return(false);
}
if(END_OF_STRUCT_OR_LIST == check_result)
{
return(FALSE);
}
strcpy(source->server, "");
strcpy(source->service, "");
/* read the slots: */
while(TRUE){
short check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
if((END_OF_STRUCT_OR_LIST == check_result) ||
(EOF == check_result))
break;
if(FALSE == check_result){
return(false);
}
if(0 == strcmp(temp_string, ":version")) {
if(FALSE == ReadLong(file, &version))
return(false);
}
else if(0 == strcmp(temp_string, ":ip-name")) {
if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
return(false);
strcpy(source->server, temp_string);
}
else if(0 == strcmp(temp_string, ":ip-address")) {
if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
return(false);
strcpy(source->server, temp_string);
}
else if(0 == strcmp(temp_string, ":configuration")) {
if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
return(false);
find_value(temp_string, "IPAddress", source->server, STRINGSIZE);
find_value(temp_string, "RemotePort", source->service, STRINGSIZE);
}
else if(0 == strcmp(temp_string, ":tcp-port")) {
if(FALSE == ReadLong(file, &port))
return(false);
sprintf(source->service,"%d", port);
}
else if(0 == strcmp(temp_string, ":port")) {
if(FALSE == ReadLong(file, &port))
return(false);
sprintf(source->service,"%d", port);
}
else if(0 == strcmp(temp_string, ":maintainer")) {
if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
return(false);
if(source->maintainer != NULL) s_free(source->maintainer);
source->maintainer = s_strdup(temp_string);
}
else if(0 == strcmp(temp_string, ":database-name")) {
if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
return(false);
strcpy(source->database, temp_string);
}
else if(0 == strcmp(temp_string, ":cost")) {
double cost;
if(FALSE == ReadDouble(file, &cost))
return(false);
sprintf(source->cost, "%.2f", cost);
}
else if(0 == strcmp(temp_string, ":cost-unit")) {
if(FALSE == ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE))
return(false);
strcpy(source->units, temp_string);
}
else if(0 == strcmp(temp_string, ":subjects")) {
if(FALSE == ReadString(desc_string, file, DESC_SIZE))
return(false);
if(source->subjects != NULL) s_free(source->subjects);
source->subjects = s_strdup(desc_string);
}
else if(0 == strcmp(temp_string, ":description")) {
if(FALSE == ReadString(desc_string, file, DESC_SIZE))
return(false);
if(source->description != NULL) s_free(source->description);
source->description = s_strdup(desc_string);
}
else if(0 == strcmp(temp_string, ":update-time")) {
if(EOF == SkipObject(file)) break;
}
else
if(EOF == SkipObject(file)) break; /* we don't know the key, so we don't know how
to interpret the value, skip it */
}
return(TRUE);
}
static boolean
ReadSourceFile(WAISSOURCE asource, char *filename, char *directory)
{
FILE *fp;
char pathname[MAX_FILENAME_LEN+1];
boolean result;
strncpy(pathname, directory, MAX_FILENAME_LEN);
strncat(pathname, filename, MAX_FILENAME_LEN);
if((fp = locked_fopen(pathname, "r")) == NULL)
return FALSE;
asource->name = s_strdup(filename);
asource->directory = s_strdup(directory);
result = ReadSource(asource, fp);
locked_fclose_A(fp,pathname,TRUE);
return(result);
}
/* Read sourcefile "name" from one of the directories in "sourcepath"
and add to Sources (creating that if neccessary). Return source found
to make it quicker next time */
static WAISSOURCE
loadSource(name, sourcepath)
char *name;
char *sourcepath;
{
char *i, *p, source_dir[MAX_FILENAME_LEN];
WAISSOURCE source = waissource_alloc();
/*
if(sourcepath == NULL || sourcepath[0] == 0) {
if((sourcepath = (char*)getenv("WAISSOURCEPATH")) == NULL)
return NULL;
}
*/
for (p = sourcepath, i = p;
i != NULL;
p = i+1) {
if((i = (char*)strchr(p, ':')) == NULL)
strcpy(source_dir, p);
else {
strncpy(source_dir, p, i-p);
source_dir[i-p] = 0;
}
if(ReadSourceFile(source, name, source_dir)) {
set_connection(source);
TH_APPEND_ITEM(source,WaisSources,WAISSOURCE);
return (source);
}
}
s_free(source);
source = NULL;
return (source);
}
static int
match_connection(WAISSOURCE asource, WAISSOURCE bsource)
{
return (!strcmp(asource->server,bsource->server) &&
!strcmp(asource->service,bsource->service));
}
/* Try and copy parameters from another source we've already looked at */
static void
set_connection(WAISSOURCE source)
{
WAISSOURCE s = WaisSources;
TH_FIND_OBJFNCTN_LIST(s,source,match_connection,WAISSOURCE)
if (s) {
source->connection = s->connection;
source->buffer_length = s->buffer_length;
source->initp = s->initp;
}
}
#if !defined(IN_RMG) && !defined(PFS_THREADS)
#ifdef NEVERDEFINED
boolean newSourcep(name)
char *name;
{
SList s;
for (s = Sources; s != NULL; s = s->nextSource)
if((s->thisSource != NULL) &&
!strcmp(name, s->thisSource->name))
return FALSE;
return TRUE;
}
#endif
boolean is_source(name, test)
char *name;
boolean test;
{
char lastchar;
lastchar = name[strlen(name)-1];
if(test)
return ((strlen(name) > 4) &&
strstr(name, ".src") &&
(!strcmp(".src", strstr(name, ".src"))));
else
return (lastchar != '~' &&
lastchar != '#' &&
strcmp(name, ".") &&
strcmp(name, ".."));
}
#ifdef USINGSOURCEITEMS
static boolean newSource(name)
char *name;
{
int i;
for(i =0; i < NumSources; i++)
if(!strcmp(name, Source_items[i]))
return FALSE;
return TRUE;
}
static int
issfile(dp)
struct dirent *dp;
{
return(is_source(dp->d_name, TRUE) &&
newSource(dp->d_name));
}
void SortSourceNames(n)
int n;
{
boolean Changed = TRUE;
int i;
char *qi;
while(Changed) {
Changed = FALSE;
for(i = 0; i < n-1; i++)
if(0 < strcasecmp(Source_items[i], Source_items[i+1])) {
Changed = TRUE;
qi = Source_items[i];
Source_items[i] = Source_items[i+1];
Source_items[i+1] = qi;
}
}
}
void
GetSourceNames(directory)
char *directory;
{
/* Note result is returned in global Source_items */
struct dirent **list;
int i, j;
assert(P_IS_THIS_THREAD_MASTER());
if ((j = scandir(directory, &list, issfile, alphasort)) < 0) {
PrintStatus(STATUS_INFO, STATUS_HIGH, "Error on open of source directory: %s.\n", directory);
return;
}
if(NumSources > 0)
Source_items = (char**) s_realloc(Source_items, (NumSources+j+1) * sizeof(char*));
else {
if(Source_items != NULL) {
for (i = 0; Source_items[i] != NULL; i++) s_free(Source_items[i]);
s_free(Source_items);
}
Source_items = (char**) s_malloc((j+1) * sizeof(char*));
}
for (i = 0; i < j; i++) {
Source_items[i+NumSources] = s_strdup(list[i]->d_name);
s_free(list[i]);
}
NumSources+=j;
SortSourceNames(NumSources);
Source_items[NumSources] = NULL;
s_free(list);
}
#endif /*USINGSOURCEITEMS*/
/* read all the sources from a directory. If test is true, only files ending
in .src are valid
*/
/* Not used */
#if !defined(IN_RMG)
static void
ReadSourceDirectory(directory, test)
char *directory;
boolean test;
{
char filename[MAX_FILENAME_LEN];
FILE *fp;
int i, j , newNumSources;
SList Last;
Source source;
struct dirent **list;
assert(P_IS_THIS_THREAD_MASTER());
if ((j = scandir(directory, &list, NULL, NULL)) < 0) {
return;
}
if(Sources == NULL)
Sources = makeSList(NULL, NULL);
for(Last = Sources; Last->nextSource != NULL; Last = Last->nextSource);
for (i = 0; i < j; i++) {
if (is_source(list[i]->d_name, test)) {
if(newSourcep(list[i]->d_name)) {
strcpy(filename, directory);
strcat(filename, list[i]->d_name);
if ((fp = locked_fopen(filename, "r")) != NULL) {
source = (Source)s_malloc(sizeof(_Source));
memset(source, 0, sizeof(_Source));
source->initp = FALSE;
source->name = s_strdup(list[i]->d_name);
source->directory = s_strdup(directory);
ReadSource(source, fp);
locked_fclose_A(fp,filename,TRUE);
if(Last->thisSource == NULL)
Last->thisSource = source;
else {
Last->nextSource = makeSList(source, NULL);
Last = Last->nextSource;
}
NumSources++;
}
}
}
}
free((char *)list);
}
#endif
void WriteSource(directory, source, overwrite)
char *directory;
Source source;
boolean overwrite;
{
char filename[MAX_FILENAME_LEN];
FILE *fp;
strcpy(filename, directory);
strcat(filename, source->name);
if (overwrite == FALSE)
if ((fp = locked_fopen(filename, "r")) != NULL) {
PrintStatus(STATUS_INFO, STATUS_HIGH,
"File %s exists, click again to overwrite.\n", filename);
locked_fclose_A(fp,filename,TRUE);
return;
}
if ((fp = locked_fopen(filename, "w")) == NULL) {
PrintStatus(STATUS_INFO, STATUS_HIGH, "Error opening %s.\n", filename);
return;
}
fprintf(fp, "(:source\n :version 3\n");
if(source->server != NULL)
if(source->server[0] != 0)
if(isdigit(source->server[0]))
fprintf(fp, " :ip-address \"%s\"\n", source->server);
else
fprintf(fp, " :ip-name \"%s\"\n", source->server);
if(source->service != NULL)
if(source->service[0] != 0)
fprintf(fp, " :tcp-port %s\n", source->service);
fprintf(fp, " :database-name \"%s\"\n", source->database);
if(source->cost != NULL)
if(source->cost[0] != 0)
fprintf(fp, " :cost %s \n", source->cost);
else
fprintf(fp, " :cost 0.00 \n");
if(source->units != NULL)
if(source->units[0] != 0)
fprintf(fp, " :cost-unit %s \n", source->units);
else
fprintf(fp, " :cost-unit :free \n");
if(source->maintainer != NULL)
if(source->maintainer[0] != 0)
fprintf(fp, " :maintainer \"%s\"\n",
source->maintainer);
else
fprintf(fp, " :maintainer \"%s\"\n",
current_user_name());
if(source->description != NULL)
if(source->description[0] != 0) {
fprintf(fp, " :description ");
WriteString(source->description, fp);
}
else
fprintf(fp, " :description \"Created with %s by %s on %s.\"\n",
command_name, current_user_name(), printable_time());
fprintf(fp, "\n)");
locked_fclose_A(fp,filename,FALSE);
}
SourceList
makeSourceList(source, rest)
SourceID source;
SourceList rest;
{
SourceList result;
if((result = (SourceList)s_malloc(sizeof(_SourceList))) != NULL) {
result->thisSource = source;
result->nextSource = rest;
}
return(result);
}
SList
makeSList(source, rest)
Source source;
SList rest;
{
SList result;
if((result = (SList)s_malloc(sizeof(_SList))) != NULL) {
result->thisSource = source;
result->nextSource = rest;
}
return(result);
}
void FreeSource(source)
Source source;
{
if (source != NULL) {
if(source->name != NULL)
s_free (source->name);
if(source->directory != NULL)
s_free (source->directory);
if(source->description != NULL)
s_free (source->description);
if(source->maintainer != NULL)
s_free (source->maintainer);
s_free(source);
}
}
#endif /*!IN_RMG && !PFS_THREADS*/
/* Find the source name, in either Sources, or it not found try and load it
from anywhere in sourcepath */
WAISSOURCE
findsource(char *name, char *sourcepath)
{
WAISSOURCE asource = WaisSources;
TH_FIND_STRING_LIST(asource,name,name,WAISSOURCE);
if (asource)
return asource;
return (loadSource(name, sourcepath));
}
#if !defined(IN_RMG) && !defined(PFS_THREADS)
void
format_source_cost(str,source)
char *str;
Source source;
{
sprintf(str,"Free");
if ((source->units != NULL) && (source->cost != NULL)) {
if(0 == strcmp(source->units, ":dollars-per-query"))
sprintf(str,"$%s/query",source->cost);
if(0 == strcmp(source->units, ":dollars-per-minute"))
sprintf(str,"$%s/minute",source->cost);
if(0 == strcmp(source->units, ":dollars-per-retrieval"))
sprintf(str,"$%s/retrieval",source->cost);
if(0 == strcmp(source->units, ":dollars-per-session"))
sprintf(str,"$%s/session",source->cost);
if(0 == strcmp(source->units, ":other"))
sprintf(str,"Special",source->cost);
}
}
void
freeSourceList(slist)
SourceList slist;
{
SourceList sl;
while(slist != NULL) {
sl = slist;
freeSourceID(sl->thisSource);
slist = sl->nextSource;
s_free(sl);
}
}
/*
#include <sockets.h>
*/
/*#define FORWARDER_SERVER "quake"*/
/* send an init message to the source. A side effect is that the
negotiation of buffer sizes. The final size is put in
source->buffer_length
*/
#ifdef NEVERDEFINED
boolean init_for_source(source, request, length, response)
Source source;
char *request;
long length;
char *response;
{
char userInfo[500];
char message[500];
char hostname[80];
char domain[80];
gethostname(hostname, 80);
getdomainname(domain, 80);
#ifdef TELL_USER
sprintf(userInfo, "%s %s, from host: %s.%s, user: %s",
command_name, VERSION, hostname, domain, getenv("USER"));
#else
sprintf(userInfo, "%s %s, from host: %s.%s",
command_name, VERSION, hostname, domain);
#endif
if(source->initp == FALSE) {
if(source->server[0] == 0)
source->connection = NULL;
else {
source->connection = connect_to_server(source->server,
atoi(source->service));
#ifdef FORWARDER_SERVER
#ifndef FORWARDER_SERVICE
#define FORWARDER_SERVICE "210"
#endif
if(source->connection == NULL) {
strncat(source->database, "@", STRINGSIZE);
strncat(source->database, source->server, STRINGSIZE);
strncat(source->database, ":", STRINGSIZE);
strncat(source->database, source->service, STRINGSIZE);
strncpy(source->server, FORWARDER_SERVER, STRINGSIZE);
strncpy(source->service, FORWARDER_SERVICE, STRINGSIZE);
source->connection = connect_to_server(source->server,
atoi(source->service));
}
#endif
if (source->connection == NULL) {
PrintStatus(STATUS_URGENT, STATUS_HIGH, "Bad Connection to server.");
source->initp = FALSE;
return source->initp;
}
}
source->buffer_length =
init_connection(request, response,
length,
source->connection,
userInfo);
if (source->buffer_length < 0) {
PrintStatus(STATUS_URGENT, STATUS_HIGH,
"\nError connecting to server: %s service: %s.",
source->server, source->service);
source->initp = FALSE;
}
else {
SList s;
source->initp = TRUE;
for (s = Sources; s != NULL; s = s->nextSource) {
if (s->thisSource != source) {
if (strcmp(s->thisSource->server, source->server) == 0 &&
strcmp(s->thisSource->service, source->service) == 0) {
s->thisSource->connection = source->connection;
s->thisSource->buffer_length = source->buffer_length;
s->thisSource->initp = TRUE;
}
}
}
}
return source->initp;
}
return source->initp;
}
#endif
#endif /*!IN_RMG && PFS_THREADS*/

View File

@@ -0,0 +1,104 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
This is part of the user-interface for the WAIS software.
*/
/*---------------------------------------------------------------------------*/
#ifndef _H_SOURCE
#define _H_SOURCE
#define STRINGSIZE 256
#ifndef boolean
#define boolean int
#endif
/* #include <cdialect.h> */
#ifdef IN_RMG
#include <pfs.h> /* for ALLOCATOR_CONSISTENCY_CHECK*/
#endif
typedef struct SourceID {
char *filename;
} _SourceID, *SourceID;
struct waissource{
#ifdef ALLOCATOR_CONSISTENCY_CHECK
int consistency;
#endif
char *name;
char *directory;
char server[STRINGSIZE];
char service[STRINGSIZE];
char database[STRINGSIZE];
char cost[STRINGSIZE];
char units[STRINGSIZE];
char *description;
FILE *connection;
long buffer_length;
boolean initp;
char *maintainer;
char *subjects;
#ifdef IN_RMG
struct waissource *next;
struct waissource *previous;
#endif
};
typedef struct waissource *WAISSOURCE;
typedef struct waissource WAISSOURCE_ST;
/* functions */
extern WAISSOURCE waissource_alloc();
extern void waissource_free(WAISSOURCE source);
extern void waissource_lfree(WAISSOURCE source);
extern void waissource_freespares();
#ifdef PFS_THREADS
extern p_th_mutex p_th_mutexWAISSOURCE;
#endif
#ifdef NEVERDEFINED
/* Uses SourceList which is obsoleted by waissource
rebuild if need these functions in Prospero */
#if !defined(IN_RMG) && !defined(PFS_THREADS)
void freeSourceID (SourceID sid);
SourceID copysourceID (SourceID sid);
char** buildSourceItemList (SourceList sourcelist);
char** buildSItemList (SList sourcelist);
static short ReadSourceID (FILE* file, SourceID sid);
SourceList ReadListOfSources (FILE* fp);
#endif
#endif
static boolean ReadSource (WAISSOURCE source, FILE* file);
static boolean ReadSourceFile (WAISSOURCE asource, char* filename, char* directory);
static WAISSOURCE loadSource (char* name, char* sourcepath);
static void set_connection (WAISSOURCE source);
#ifdef NEVERDEFINED
#if !defined(IN_RMG) && !defined(PFS_THREADS)
boolean newSourcep (char* name);
boolean is_source (char* name, boolean test);
void SortSourceNames (int n);
void GetSourceNames (char* directory);
static void ReadSourceDirectory (char* directory, boolean test);
void WriteSource (char* directory, Source source, boolean overwrite);
SourceList makeSourceList (SourceID source, SourceList rest);
SList makeSList (Source source, SList rest);
void FreeSource (Source source);
void FreeSources (SList sources);
#endif
#endif
WAISSOURCE findsource (char* name, char* sourcepath);
#ifdef NEVERDEFINED
#if !defined(IN_RMG) && !defined(PFS_THREADS)
Source findSource (int n);
void format_source_cost (char* str, Source source);
void freeSource (SourceID sourceID);
void freeSourceList (SourceList slist);
boolean init_for_source (Source source, char* request,
long length, char* response);
#endif /*!IN_RMG && !PFS_THREADS */
#endif
#endif

View File

@@ -0,0 +1,138 @@
/* Copyright (c) 1993, by Pandora Systems */
/* Author: Mitra <mitra@path.net> */
/* Allocation code copied and adapted from:
prospero/alpha.5.2a+/lib/pfs/flalloc */
#include "buffalloc.h"
#include <pfs.h>
#include <pfs_threads.h>
#include <mitra_macros.h>
#include "source.h"
#define Channel_Illegal 0;
EXTERN_ALLOC_DECL(WAISSOURCE);
static WAISSOURCE lfree = NULL; /* Free waissources */
/* These are global variables which will be read by dirsrv.c
Too bad C doesn't have better methods for structuring such global data. */
int waissource_count = 0;
int waissource_max = 0;
/************* Standard routines to alloc, free and copy *************/
/*
* waissource_alloc - allocate and initialize WAISSOURCE structure
*
* returns a pointer to an initialized structure of type
* WAISSOURCE. If it is unable to allocate such a structure, it
* signals out_of_memory();
*/
WAISSOURCE
waissource_alloc()
{
WAISSOURCE awaissource;
TH_STRUC_ALLOC(waissource,WAISSOURCE,awaissource);
awaissource->name = NULL;
awaissource->directory = NULL;
awaissource->description = NULL;
awaissource->connection = NULL;
awaissource->maintainer = NULL;
awaissource->subjects = NULL;
return(awaissource);
}
/*
* waissource_free - free a WAISSOURCE structure
*
* waissource_free takes a pointer to a WAISSOURCE structure and adds it to
* the free list for later reuse.
*/
void
waissource_free(WAISSOURCE awaissource)
{
stfree(awaissource->name); awaissource->name = NULL;
stfree(awaissource->directory); awaissource->directory = NULL;
stfree(awaissource->description); awaissource->description = NULL;
stfree(awaissource->connection); awaissource->connection = NULL;
stfree(awaissource->maintainer); awaissource->maintainer = NULL;
stfree(awaissource->subjects); awaissource->subjects = NULL;
TH_STRUC_FREE(waissource,WAISSOURCE,awaissource);
}
/*
* waissource_lfree - free a linked list of WAISSOURCE structures.
*
* waissource_lfree takes a pointer to a waissource structure frees it and
* any linked
* WAISSOURCE structures. It is used to free an entire list of WAISSOURCE
* structures.
*/
void
waissource_lfree(awaissource)
WAISSOURCE awaissource;
{
TH_STRUC_LFREE(WAISSOURCE,awaissource,waissource_free);
}
void
waissource_freespares()
{
TH_FREESPARES(waissource,WAISSOURCE);
}
#ifdef NEVERDEFINED
/*
* waissource_copy - allocates a new waissource structure and
* initializes it with a copy of another
* waissource, v.
*
* If r is non-zero, successive waissources will be
* iteratively copied.
*
* awaissource-previous will always be null on the first link, and
* will be appropriately filled in for iteratively copied links.
*
* waissource_copy returns a pointer to the new structure of type
* WAISSOURCE. If it is unable to allocate such a structure, it
* returns NULL.
*
* waissource_copy will recursively copy the link associated with
* a waissource and
* its associated attributes.
*/
WAISSOURCE
waissource_copy(f,r)
WAISSOURCE f;
int r; /* Currently ignored. */
{
WAISSOURCE nf;
WAISSOURCE snf; /* Start of the chain of new links */
WAISSOURCE tf; /* Temporary link pointer */
nf = waissource_alloc();
snf = nf;
copyeach:
/* Copy f into nf */
#ifdef ALLOCATOR_CONSISTENCY_CHECK
assert(f->consistency == INUSE_PATTERN);
#endif
LOCAL STUFF NOT DEFINED
if(r && f->next) {
f = f->next;
tf = nf;
nf = waissource_alloc();
nf->previous = tf;
tf->next = nf;
goto copyeach;
}
return(snf);
}
#endif

Binary file not shown.

View File

@@ -0,0 +1,20 @@
#include <sys/types.h>
#include <stdio.h>
#include "source.h"
void
main(int argc, char *argv[])
{
char sourcename[512];
WAISSOURCE source = waissource_alloc();
sprintf(sourcename,"%s.src", argv[1]);
source = findsource(sourcename,
"/usr/local/wais/wais-sources/");
if (source == NULL) { fprintf(stderr,"Error finding source.\n"); }
else {
printf("%s %s %s\n",source->server, source->name, source->service);
}
}

View File

@@ -0,0 +1,186 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
#ifndef lint
static char *RCSid = "$Header: /buzza/cvsroot/technologies/archie-support/prospero/lib/psrv/wais_gw/ustubs.c,v 1.1.1.1 1999/03/18 16:50:52 pedro Exp $";
#endif
/* Change log:
* $Log: ustubs.c,v $
* Revision 1.1.1.1 1999/03/18 16:50:52 pedro
* This modules includes the prosper server and the berkeley db code used
* in Archie
*
* Revision 1.1.1.1 1994/08/31 16:33:09 bajan
* New Prospero release
*
* Revision 1.2 94/04/19 00:29:17 swa
* (mitra) assert(P_IS_THIS_THREAD_MASTER()) added in places.
* Added tests for SOLARIS
*
* Revision 1.1 93/11/10 13:35:08 swa
* Initial revision
*
* Revision 1.4 92/05/06 17:35:13 jonathan
* Modified some #if's for NeXT and Mach.
*
* Revision 1.3 92/03/06 11:08:49 jonathan
* fixed incompatible return type error in HP version of getwd. Thanks to
* cshotton@oac.hsc.uth.tmc.edu.
*
* Revision 1.2 92/02/12 13:54:29 jonathan
* Added "$Log" so RCS will put the log message in the header
*
*
*/
/*----------------------------------------------------------------------*/
/* stubs for silly non-ansi c compilers */
/*----------------------------------------------------------------------*/
#include "ustubs.h"
#include "futil.h" /* for MAX_FILENAME_LEN */
#include "cutil.h" /* for substrcmp and NULL */
#include <pmachine.h> /* For Solaris */
#include <stdlib.h> /* SOLARIS: for rand and srand */
#include <pfs_threads.h> /* For P_IS_THIS_THREAD_MASTER */
/*----------------------------------------------------------------------*/
#if (defined(__svr4__) || defined(hpux) || defined(SCOUNIX)) && !defined(SOLARIS)
char*
getwd(char* pathname)
{
return((char*)getcwd(pathname, MAX_FILENAME_LEN));
}
long
random(void)
{
assert(P_IS_THIS_THREAD_MASTER()); /*SOLARIS: rand, srand & random MT-Unsafe */
return(rand());
}
long
srandom(unsigned long seed)
{
assert(P_IS_THIS_THREAD_MASTER()); /*SOLARIS: rand, srand & random MT-Unsafe */
srand(seed);
return(0);
}
long
sigmask(long sig)
{
}
long
sigblock(long mask)
{
}
long
sigsetmask(long mask)
{
}
#endif
#if (defined(__svr4__) || defined(hpux))
#include <sys/systeminfo.h>
long
gethostname(char* hostname,long len)
{
return(sysinfo(SI_HOSTNAME,hostname,len));
}
#endif /* def SYSV */
/*----------------------------------------------------------------------*/
#ifndef ANSI_LIKE /* memmove is an ANSI function not defined by K&R */
#ifndef hpux /* but HP defines it */
void*
memmove(void* str1,void* str2,size_t n)
{
#ifdef M_XENIX
memcpy((char*)str2,(char*)str1,(long)n); /* hope it works! */
#else /* ndef M_XENIX */
bcopy((char*)str2,(char*)str1,(long)n);
#endif /* ndef M_XENIX */
return(str1);
}
#endif /* ndef hpux */
#else /* ansi is defined */
#ifdef __GNUC__ /* we are ansi like, are we gcc */
#if !(defined(NeXT) || defined(Mach) || defined(__svr4__))
/* and we are not on a next or solaris ! */
void*
memmove(void* str1,void* str2,size_t n)
{
bcopy((char*)str2,(char*)str1,(long)n);
return(str1);
}
#endif /* not NeXT or Mach */
#endif /* __GNUC__ */
#endif /* else ndef ANSI_LIKE */
/*----------------------------------------------------------------------*/
#ifndef ANSI_LIKE
/* atoi is not defined k&r. copied from the book */
long
atol(char* s)
{
long i, n, sign;
for(i=0; s[i]==' ' || s[i]== 'n' || s[i]=='t'; i++)
; /* skip white space */
sign = 1;
if (s[i] == '+' || s[i] == '-')
sign = (s[i++]=='+') ? 1 : -1;
for (n=0; s[i] >= '0' && s[i] <= '9'; i++)
n= 10 * n + s[i] - '0';
return(sign * n);
}
/*----------------------------------------------------------------------*/
char*
strstr(char* src,char* sub)
{
/* this is a poor implementation until the ANSI version catches on */
char *ptr;
for(ptr = src; (long)ptr <= (long)src + strlen(src) - strlen(sub); ptr++){
if(substrcmp(ptr, sub))
return(ptr);
}
return(NULL);
}
/*----------------------------------------------------------------------*/
int
remove(char* filename)
{
return(unlink(filename));
}
/*----------------------------------------------------------------------*/
#endif /* ndef ANSI_LIKE */

View File

@@ -0,0 +1,94 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*----------------------------------------------------------------------*/
/* definitions that non-ansi (aka sun) C doesn't provide */
#ifndef USTUBS_H
#define USTUBS_H
#include "cdialect.h"
#ifndef ANSI_LIKE
#include <sys/types.h>
#ifdef M_XENIX
#include <string.h>
#endif /* ndef M_XENIX */
#ifndef size_t
#ifndef M_XENIX
#define size_t unsigned long
#endif /* ndf M_XENIX */
#endif /* ndef size_t */
#ifndef ANSI_LIKE
#ifndef M_XENIX
#define time_t long
#endif /* ndef M_XENIX */
#endif /* ndef ANSI_LIKE */
#ifdef K_AND_R /* this might be too general, but it is needed on vaxen */
#define void char
#endif /* ndef K_AND_R */
#ifdef __cplusplus
/* declare these as C style functions */
extern "C"
{
#endif /* def __cplusplus */
#ifndef SCOUNIX
char *strstr(char *src, char *sub);
#endif
#ifdef SYSV
char *getwd (char *pathname);
long random(void);
long srandom(unsigned long seed);
#ifndef SCOUNIX
#define rename(f1,f2) {link((f1),(f2)); unlink((f1)); }
#endif /*SCOUNIX*/
#endif /* defu SYSV */
#if !(defined(NeXT) || defined(Mach))
#ifndef M_XENIX
#ifndef cstar
char* malloc(size_t size);
char* calloc(size_t nelem,size_t elsize);
#ifndef SCOUNIX
void free(char* ptr);
#endif
char* realloc(char* ptr,size_t size);
#ifndef mips
#ifndef hpux
#ifndef vax
#ifndef SCOUNIX
char* memcpy(char* s1,char* s2,size_t c);
#endif
void* memmove(void* s1,void* s2,size_t n);
#endif /* ndef vax */
#endif /* ndef hpux */
#endif /* ndef mips */
char *strcat(char *s1, char *s2);
#endif /* ndef cstar */
#endif /* ndef M_XENIX */
#endif /* not NeXT or Mach */
long atol(char *s);
#ifdef __cplusplus
}
#endif /* def __cplusplus */
#else /* def ANSI_LIKE */
#endif /* else ndef ANSI_LIKE */
/*----------------------------------------------------------------------*/
#endif /* ndef USTUBS_H */

View File

@@ -0,0 +1,331 @@
/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
#include <string.h>
#include <pmachine.h>
#include <psite.h> /* for WAIS_SOURCE_DIR */
#include <ardp.h>
#include <pfs.h>
#include <pserver.h>
#include <psrv.h>
#include <perrno.h>
#include <plog.h>
/* Could be local files. */
#include "wprot.h"
#include "zutil.h" /* for "any" */
#include "source.h" /* for Source */
#include "inface.h"
#include "wais_gw_dsdb.h"
#include "ietftype.h"
#include "ietftype_parse.h"
/* Definitions of constants */
#define MAX_NUM_WAIS_LINKS 3000 /* maximum # of directory links to
return before giving up. */
/* ======= Some forward definitions ============ */
static void
wsr_to_dirobj(WAISSearchResponse *wsr, P_OBJECT ob, char *host, char *port);
static VLINK DocHeader2vl(WAISDocumentHeader *wdh, char *host, char *port);
char *
read_wais_contents(char *host, char *port, char *type,
char *database, char *docid);
/* This function is passed an empty object which has been initialized with
oballoc(). It returns a possibly populated directory and
DIRSRV_NOT_FOUND or PSUCCESS. Note that the directory will need
to have links within it freed, even if an error code is returned. */
/* This sets p_warn_string and pwarn if a unrecognized record
or diagnostic record is received. That is good. */
/* Currently this routine doesnt handle all possible combinations of arguments*/
/* It handles:
Do a search
hsoname= "WAIS-GW/<host>(<port>)/QUERY/<database>/<query>"
Do a search - alternative
hsoname= "WAIS-GW/<host>(<port>)/QUERY/<database>"
listopts.thiscompp[0] = <query>
Retrieve a document
hsoname= "WAIS-GW/<host>(<port>)/<type>/<database>/<docid>"
listopts.requested_attrs="+CONTENTS+"
Get attribute information about database
hsoname= "WAIS-GW/<host>(<port>)/QUERY/<database>"
listopts.requested_attrs="+#ALL+"
listopts.thiscompp[0] = NULL
*/
int
wais_gw_dsdb(RREQ req, /* Request pointer (unused) */
char *hsoname, /* Name of the directory */
long version, /* Version #; currently ignored */
long magic_no, /* Magic #; currently ignored */
int flags, /* Currently only recognize DRO_VERIFY */
struct dsrobject_list_options *listopts, /* options (use *remcompp
and *thiscompp) */
P_OBJECT ob) /* Object to be filled in */
{
int tmp;
AUTOSTAT_CHARPP(hostp);
AUTOSTAT_CHARPP(portp);
AUTOSTAT_CHARPP(queryp);
AUTOSTAT_CHARPP(typep);
AUTOSTAT_CHARPP(databasep);
WAISSearchResponse *wsr;
char *str = NULL;
ob->version = 0; /* unversioned */
ob->magic_no = 0;
ob->inc_native = VDIN_PSEUDO;
ob->acl = NULL;
tmp = qsscanf(hsoname, "WAIS-GW/%&[^(](%&[^)])/%&[^/]/%&[^/]/%&[^/]/%[^\n]",
hostp, portp, typep, databasep, queryp);
if (requested_contents(listopts)) {
if (tmp == 4 && stequal(*typep,"HELP")) {
char *db_src = NULL;
WAISSOURCE thissource;
db_src = qsprintf_stcopyr(db_src,"%s.src",*databasep);
/* Dont free the source, its on a linked list for the duration*/
if (!(thissource = findsource(db_src,WAIS_SOURCE_DIR)))
return DIRSRV_WAIS;
ob_atput(ob,"CONTENTS","DATA",
thissource->description, (char *)0);
stfree(db_src);
return PSUCCESS;
}
if (tmp <5)
return DIRSRV_WAIS;
ob->flags = P_OBJECT_FILE;
if (!(str = read_wais_contents(*hostp,*portp,*typep,*databasep,*queryp)))
return DIRSRV_WAIS;
/* (char *)1 prevents copying of potentially huge str*/
ob_atput(ob, "CONTENTS", "DATA", (char *)1, str, (char *)0);
return PSUCCESS;
}
ob->flags = P_OBJECT_DIRECTORY;
if (tmp < 4)
return DIRSRV_NOT_FOUND;
/* For now only handle QUERY */
if (strcmp(*typep,"QUERY") != 0)
return DIRSRV_NOT_FOUND;
if (tmp <5) { /* look for query in components */
if (!listopts || !listopts->thiscompp || !*listopts->thiscompp ||
strequal(*listopts->thiscompp, "")
|| strequal(*listopts->thiscompp, "*")) {
/* last test against * might be inappropriate */
if (listopts->requested_attrs) {
char *w_db_src = NULL;
WAISSOURCE thissource; /* DONT free this */
w_db_src = qsprintf_stcopyr(w_db_src,"%s.src",*databasep);
ob_atput(ob,"OBJECT-INTERPRETATION", "SEARCH", NULL);
if (thissource = findsource(w_db_src,WAIS_SOURCE_DIR)) {
if (thissource->subjects)
ob_atput(ob,"WAIS-SUBJECTS", thissource->subjects, NULL);
if (thissource->cost)
ob_atput(ob,"WAIS-COST-NUM", thissource->cost, NULL);
if (thissource->units)
ob_atput(ob,"WAIS-COST-UNIT", thissource->units, NULL);
if (thissource->maintainer)
ob_atput(ob,"WAIS-MAINTAINER", thissource->maintainer, NULL);
ob_atput(ob, "QUERY-METHOD", "wais-query(search-words)",
"${search-words}", "", (char *) 0);
ob_atput(ob, "QUERY-ARGUMENT", "search-words",
"Index word(s) to search for", "mandatory char*",
"%s", "", (char *) 0);
if (thissource->description)
ob_atput(ob, "QUERY-DOCUMENTATION", "wais-query()",
thissource->description, (char *) 0);
ob_atput(ob, "QUERY-DOCUMENTATION", "search-words",
"This string says \
what you're searching for or what information you're specifying.",
"Type any string. Sometimes SPACEs are treated as implied \
'and' operators. Sometimes the words 'and', 'or', and 'not' are recognized \
as boolean operators.", (char *) 0);
}
stfree(w_db_src);
}
return PSUCCESS; /* Display no contents for the directory */
}
/* Set the selector. */
*queryp = stcopyr(*listopts->thiscompp, *queryp);
/* We just used up thiscompp, so we'd better reset it. */
if (listopts->remcompp && *listopts->remcompp) {
*listopts->thiscompp = (*listopts->remcompp)->token;
*listopts->remcompp = (*listopts->remcompp)->next;
} else {
*listopts->thiscompp = NULL;
}
}
if (flags & DRO_VERIFY) return PSUCCESS;
if ((wsr = waisQuery(*hostp,*portp,*databasep,*queryp)) == NULL)
return DIRSRV_WAIS; /* Need to decode wais errors sensibly */
wsr_to_dirobj(wsr,ob,*hostp,*portp);
freeWAISSearchResponse(wsr); wsr=NULL;
return PSUCCESS;
}
static void
wsr_to_dirobj(WAISSearchResponse *wsr, P_OBJECT ob, char *host, char *port)
{
/* Dont need to fuss around with magic numbers, these cant be replicas*/
PATTRIB at = atalloc();
VLINK vl = NULL;
int i;
long current_magic_no = 0L; /* set magic starting hash */
VLINK tempvl = NULL;
ob_atput(ob,"WAIS_SEED_WORDS",wsr->SeedWordsUsed, (char *)0);
if ( wsr->ShortHeaders
|| wsr->LongHeaders
|| wsr->Text
|| wsr->Headlines
|| wsr->Codes
|| wsr->Diagnostics
) {
pwarn = PWARNING;
p_warn_string = qsprintf_stcopyr(p_warn_string,
"Unrecognized search response");
}
/*!! Need to handle diagnostics - ignore others */
if (wsr->DocHeaders) {
for (i=0; wsr->DocHeaders[i]; i++) {
if (vl = DocHeader2vl(wsr->DocHeaders[i],host,port)) {
/* Add new magic no to all the links returned */
current_magic_no = generate_magic(vl);
while (magic_no_in_list(++current_magic_no, ob->links));
for (tempvl = vl; tempvl != NULL; tempvl= tempvl->next)
#ifdef NEVERDEFINED
tempvl->f_magic_no = current_magic_no;
#else
tempvl->f_magic_no = 0; /*clients dont understand result !!*/
#endif
APPEND_LISTS(ob->links, vl);
}
}
}
}
char *
urlascii(any *docid) {
char *str = stalloc(3 * docid->size);
int i;
int j;
for (i=0, j=0; i< docid->size; i++)
{
int c = docid->bytes[i];
if ((c < ' ') || (c > (char)126) || strchr("/\\{}|[]^~<>#%'",c)) {
str[j++] = '%' ;
sprintf(str+(j++),"%02x",c);
j++;
} else
str[j++] = c;
}
str[j] = '\0'; /* Null terminated */
return str;
};
static VLINK
DocHeader2vl(WAISDocumentHeader *wdh, char *host, char *port)
{
int i; /* Index into types */
VLINK vl;
VLINK head = NULL; /* Head of links being constructed */
char *str = NULL; /* thisstring can be stalloc-ed or stfree-ed*/
char *cp = NULL; /* this one cant */
IETFTYPE it;
PATTRIB at;
for (i=0; wdh->Types[i]; i++) {
vl = vlalloc();
vl->host = stcopy(hostwport);
str = urlascii(wdh->DocumentID); /* stalloc's string */
if ((cp=strrchr(wdh->Source,'/')) == NULL) {
cp = wdh->Source;
} else {
cp++;
}
vl->hsoname = qsprintf_stcopyr(vl->hsoname,"WAIS-GW/%s(%s)/%s/%s/%s",
host, port, wdh->Types[i], cp, str);
/*!! Check that Source always has a reasonable format */
if (it = wais_2_ietftype(wdh->Types[i])) {
if (at = atcopy(it->prosperotype)) {
APPEND_ITEM(at,vl->lattrib);
}
}
vl->name = stcopy(wdh->Headline);
if (wdh->VersionNumber)
vl->version = wdh->VersionNumber;
if (wdh->Score) {
vl_atput(vl, "WAIS-SCORE",
(str = qsprintf_stcopyr(str,"%d",wdh->Score)), (char *)0);
vl_atput(vl, "COLLATION-ORDER",
(str = qsprintf_stcopyr(str,"-%d",wdh->Score)), (char *)0);
}
if (wdh->BestMatch)
vl_atput(vl, "WAIS-BESTMATCH",
(str = qsprintf_stcopyr(str,"%d",wdh->BestMatch)), (char *)0);
vl_atput(vl, "SIZE",
(str = qsprintf_stcopyr(str,"%d",wdh->BestMatch)), (char *)0);
if (wdh->Lines)
vl_atput(vl, "WAIS-LINES",
(str = qsprintf_stcopyr(str,"%d",wdh->Lines)), (char *)0);
/*!! Should convert this date to asn (timetoasn & lib/psrv/dsrfinfo*/
/* and stuff in LAST-MODIFIED */
if (wdh->Date)
vl_atput(vl, "WAIS-DATE", wdh->Date, (char *)0);
if (wdh->OriginCity)
vl_atput(vl, "WAIS-ORIGINCITY", wdh->OriginCity, (char *)0);
/* Route all accesses through the host for now */
vl_atput(vl,"ACCESS-METHOD","WAIS","","","","", (char *)0);
/*vl_atput(vl,"ACCESS-METHOD","PROSPERO-CONTENTS","","","","", (char *)0);*/
if (strncmp("Search produced no result. Here's the Catalog",
vl->name, 45) == 0) {
vlfree(vl);
} else {
APPEND_ITEM(vl,head);
}
stfree(str);
} /*for*/
return(head);
}
char *
read_wais_contents(char *host, char *port, char *type,
char *database, char *docid)
{
any *dt;
char *str = NULL;
int len;
any *DocumentId;
DocumentId = un_urlascii(docid); /* Allocates DocumentID (throws length)*/
len = 0 ;
if (dt = waisRetrieve(host,port,database,DocumentId,type,len)) {
str = dt->bytes;
dt->bytes = NULL;
freeAny(dt);
}
stfree(DocumentId->bytes);
free(DocumentId);
return (str);
}

View File

@@ -0,0 +1,8 @@
extern int wais_gw_dsdb(RREQ req, /* Request pointer (unused) */
char *hsoname, /* Name of the directory */
long version, /* Version #; currently ignored */
long magic_no, /* Magic #; currently ignored */
int flags, /* Currently only recognize DRO_VERIFY */
struct dsrobject_list_options *listopts, /* options (use *remcompp
and *thiscompp) */
P_OBJECT ob); /* Object to be filled in */

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 1991-1994 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
#include <usc-license.h>
#include <pfs_threads.h>
#include "ietftype_parse.h"
#ifdef PFS_THREADS
p_th_mutex p_th_mutexWAISMSGBUFF; /* declaration */
p_th_mutex p_th_mutexIETFTYPE; /* declaration */
p_th_mutex p_th_mutexWAISSOURCE; /* declaration */
#endif
void
wais_gw_init_mutexes(void)
{
#ifdef PFS_THREADS
p_th_mutex_init(p_th_mutexWAISMSGBUFF);
p_th_mutex_init(p_th_mutexIETFTYPE);
p_th_mutex_init(p_th_mutexWAISSOURCE);
ietftype_init(); /* Safer than mutexing it */
#endif
}
#ifndef NDEBUG
void
wais_gw_diagnose_mutexes(void)
{
#ifdef PFS_THREADS
DIAGMUTEX(WAISMSGBUFF,"WAISMSGBUFF");
DIAGMUTEX(IETFTYPE,"IETFTYPE");
DIAGMUTEX(WAISSOURCE,"WAISSOURCE");
#endif
}
#endif /*NDEBUG*/

View File

@@ -0,0 +1,84 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
#define waislog_c
#if !defined(IN_RMG) && !defined(PFS_THREADS)
#include "waislog.h"
#include "futil.h"
void waisLogInternal(long priority,long pid,long lineNum,long code,
char* format,va_list ap);
long log_line = 0;
long wais_log_level = 10;
char* logFile = NULL;
boolean expertUser = false;
/*----------------------------------------------------------------------*/
void
waislog(long priority,long code,char* format,...)
{
va_list ap;
va_start(ap,format);
initMyPID();
waisLogInternal(priority,myPID,log_line++,code,format,ap);
va_end(ap);
}
/*----------------------------------------------------------------------*/
void
waisLogDetailed(long priority,long pid,long lineNum,long code,
char* format,...)
{
va_list ap;
va_start(ap,format);
waisLogInternal(priority,pid,lineNum,code,format,ap);
va_end(ap);
}
/*----------------------------------------------------------------------*/
void
waisLogInternal(long priority,long pid,long lineNum,long code,
char* format,va_list ap)
{
if (priority <= wais_log_level)
{
FILE* log = NULL;
if (logToStderr(logFile))
log = stderr;
else if (logToStdout(logFile))
log = stdout;
else
log = locked_fopen(logFile,"a");
if (log)
{
fprintf(log,"%d: %d: %s: %d: ",pid,lineNum,
printable_time(),code);
vfprintf(log,format,ap);
fprintf(log,"\n");
fflush(log);
if (logToStderr(logFile) == false && logToStdout(logFile) == false)
locked_fclose(log,logFile,FALSE);
}
}
}
#endif /* !defined(IN_RMG) && !defined(PFS_THREADS)*/
/*-------------------------------------------------------------------------- */

View File

@@ -0,0 +1,58 @@
/*****************************************************************************
* (c) Copyright 1992 Wide Area Information Servers, Inc *
* of California. All rights reserved. *
* *
* This notice is intended as a precaution against inadvertent publication *
* and does not constitute an admission or acknowledgement that publication *
* has occurred or constitute a waiver of confidentiality. *
* *
* Wide Area Information Server software is the proprietary and *
* confidential property of Wide Area Information Servers, Inc. *
*****************************************************************************/
#ifndef waislog_h
#define waislog_h
#include <stdarg.h>
#include "cutil.h"
/*-------------------------------------------------------------------------- */
/*-------------------------------------------------------------------------- */
#define WLOG_HIGH (1L)
#define WLOG_MEDIUM (5L)
#define WLOG_LOW (9L)
#define WLOG_CONNECT (1L)
#define WLOG_CLOSE (2L)
#define WLOG_SEARCH (3L)
#define WLOG_RESULTS (4L)
#define WLOG_RETRIEVE (5L)
#define WLOG_INDEX (6L)
#define WLOG_PARSE (7L)
#define WLOG_INFO (100L)
#define WLOG_ERROR (-1L)
#define WLOG_WARNING (-2L)
#define logToStderr(log) (log == NULL || log[0] == '\0')
#define logToStdout(log) (log[0] == '-' && log[1] == '\0')
#define dbg (expertUser && (logToStderr(logFile) || logToStdout(logFile)))
void waislog(long priority, long code, char* format,...);
void waisLogDetailed(long priority,long pid,long lineNum,long code,
char* format,...);
#ifndef waislog_c
extern long log_line;
extern wais_log_level;
extern char* logFile;
extern boolean expertUser;
#endif /* ndef waislog_c */
/*-------------------------------------------------------------------------- */
#endif /* ndef waislog_h */

View File

@@ -0,0 +1,109 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*----------------------------------------------------------------------*/
#include <string.h>
#include "wmessage.h"
#include "cutil.h"
/*---------------------------------------------------------------------*/
void
readWAISPacketHeader(msgBuffer,header_struct)
char* msgBuffer;
WAISMessage *header_struct;
{
memmove(header_struct->msg_len,msgBuffer,(size_t)10);
header_struct->msg_type = char_downcase((unsigned long)msgBuffer[10]);
header_struct->hdr_vers = char_downcase((unsigned long)msgBuffer[11]);
memmove(header_struct->server,(void*)(msgBuffer + 12),(size_t)10);
header_struct->compression = char_downcase((unsigned long)msgBuffer[22]);
header_struct->encoding = char_downcase((unsigned long)msgBuffer[23]);
header_struct->msg_checksum = char_downcase((unsigned long)msgBuffer[24]);
}
/*---------------------------------------------------------------------*/
long
getWAISPacketLength(header)
WAISMessage* header;
{
char lenBuf[11];
memmove(lenBuf,header->msg_len,(size_t)10);
lenBuf[10] = '\0';
return(atol(lenBuf));
}
/*---------------------------------------------------------------------*/
#ifdef NOTUSEDYET
static char checkSum _AP((char* string,long len));
static char
checkSum(string,len)
char* string;
long len;
{
register long i;
register char chSum = '\0';
for (i = 0; i < len; i++)
chSum = chSum ^ string[i];
return(chSum);
}
#endif
void
writeWAISPacketHeader(header,
dataLen,
type,
server,
compression,
encoding,
version)
char* header;
long dataLen;
long type;
char* server;
long compression;
long encoding;
long version;
{
char lengthBuf[11];
char serverBuf[11];
long serverLen = strlen(server);
if (serverLen > 10)
serverLen = 10;
sprintf(lengthBuf, "%010ld", dataLen);
strncpy(header,lengthBuf,10);
header[10] = type & 0xFF;
header[11] = version & 0xFF;
strncpy(serverBuf,server,serverLen);
strncpy((char*)(header + 12),serverBuf,serverLen);
header[22] = compression & 0xFF;
header[23] = encoding & 0xFF;
header[24] = '0';
}
/*---------------------------------------------------------------------*/

View File

@@ -0,0 +1,58 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*----------------------------------------------------------------------*/
#ifndef WMESSAGE_H
#define WMESSAGE_H
#include "cdialect.h"
typedef struct wais_header {
char msg_len[10];
char msg_type;
char hdr_vers;
char server[10];
char compression;
char encoding;
char msg_checksum;
} WAISMessage;
#define HEADER_LENGTH 25
#define HEADER_VERSION (long)'2'
#define Z3950 'z'
#define ACK 'a'
#define NAK 'n'
#define NO_COMPRESSION ' '
#define UNIX_COMPRESSION 'u'
#define NO_ENCODING ' '
#define HEX_ENCODING 'h'
#define IBM_HEXCODING 'i'
#define UUENCODE 'u'
#ifdef __cplusplus
extern "C"
{
#endif
void readWAISPacketHeader _AP((char* msgBuffer,WAISMessage *header_struct));
long getWAISPacketLength _AP((WAISMessage* header));
void writeWAISPacketHeader _AP((char* header,long dataLen,long type,
char* server,long compression,
long encoding,long version));
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,298 @@
/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*----------------------------------------------------------------------*/
#ifndef _H_WAIS_protocol_
#define _H_WAIS_protocol_
#include "cdialect.h"
#include "zprot.h"
#include "ztype1.h"
/*----------------------------------------------------------------------*/
#ifndef DF_INDEPENDENT
#define DF_INDEPENDENT 1
#define DF_LATER 2
#define DF_EARLIER 3
#define DF_SPECIFIED_RANGE 4
#endif
#define CT_document 0
#define CT_byte 1
#define CT_line 2
#define CT_paragraph 3
#define QT_RelevanceFeedbackQuery "3"
#define QT_TextRetrievalQuery QT_BooleanQuery
#define DT_UserInformationLength (data_tag)99
#define DT_ChunkCode (data_tag)100
#define DT_ChunkIDLength (data_tag)101
#define DT_ChunkMarker (data_tag)102
#define DT_HighlightMarker (data_tag)103
#define DT_DeHighlightMarker (data_tag)104
#define DT_NewlineCharacters (data_tag)105
#define DT_SeedWords (data_tag)106
#define DT_DocumentIDChunk (data_tag)107
#define DT_ChunkStartID (data_tag)108
#define DT_ChunkEndID (data_tag)109
#define DT_TextList (data_tag)110
#define DT_DateFactor (data_tag)111
#define DT_BeginDateRange (data_tag)112
#define DT_EndDateRange (data_tag)113
#define DT_MaxDocumentsRetrieved (data_tag)114
#define DT_SeedWordsUsed (data_tag)115
#define DT_DocumentID (data_tag)116
#define DT_VersionNumber (data_tag)117
#define DT_Score (data_tag)118
#define DT_BestMatch (data_tag)119
#define DT_DocumentLength (data_tag)120
#define DT_Source (data_tag)121
#define DT_Date (data_tag)122
#define DT_Headline (data_tag)123
#define DT_OriginCity (data_tag)124
#define DT_PresentStartByte (data_tag)125
#define DT_TextLength (data_tag)126
#define DT_DocumentText (data_tag)127
#define DT_StockCodes (data_tag)128
#define DT_CompanyCodes (data_tag)129
#define DT_IndustryCodes (data_tag)130
#define DT_DocumentHeaderGroup (data_tag)150
#define DT_DocumentShortHeaderGroup (data_tag)151
#define DT_DocumentLongHeaderGroup (data_tag)152
#define DT_DocumentTextGroup (data_tag)153
#define DT_DocumentHeadlineGroup (data_tag)154
#define DT_DocumentCodeGroup (data_tag)155
#define DT_Lines (data_tag)131
#define DT_TYPE_BLOCK (data_tag)132
#define DT_TYPE (data_tag)133
#define ES_DocumentHeader "Document Header"
#define ES_DocumentShortHeader "Document Short Header"
#define ES_DocumentLongHeader "Document Long Header"
#define ES_DocumentText "Document Text"
#define ES_DocumentHeadline "Document Headline"
#define ES_DocumentCodes "Document Codes"
typedef struct DocObj {
any* DocumentID;
char* Type;
long ChunkCode;
union {
long Pos;
any* ID;
} ChunkStart;
union {
long Pos;
any* ID;
} ChunkEnd;
} DocObj;
/*----------------------------------------------------------------------*/
typedef struct WAISInitResponse {
long ChunkCode;
long ChunkIDLength;
char* ChunkMarker;
char* HighlightMarker;
char* DeHighlightMarker;
char* NewlineCharacters;
} WAISInitResponse;
typedef struct WAISSearch {
char* SeedWords;
DocObj** Docs;
char** TextList;
long DateFactor;
char* BeginDateRange;
char* EndDateRange;
long MaxDocumentsRetrieved;
} WAISSearch;
typedef struct WAISDocumentHeader {
any* DocumentID;
long VersionNumber;
long Score;
long BestMatch;
long DocumentLength;
long Lines;
char** Types;
char* Source;
char* Date;
char* Headline;
char* OriginCity;
} WAISDocumentHeader;
typedef struct WAISDocumentShortHeader {
any* DocumentID;
long VersionNumber;
long Score;
long BestMatch;
long DocumentLength;
long Lines;
} WAISDocumentShortHeader;
typedef struct WAISDocumentLongHeader {
any* DocumentID;
long VersionNumber;
long Score;
long BestMatch;
long DocumentLength;
long Lines;
char** Types;
char* Source;
char* Date;
char* Headline;
char* OriginCity;
char* StockCodes;
char* CompanyCodes;
char* IndustryCodes;
} WAISDocumentLongHeader;
typedef struct WAISDocumentText {
any* DocumentID;
long VersionNumber;
any* DocumentText;
} WAISDocumentText;
typedef struct WAISDocumentHeadlines {
any* DocumentID;
long VersionNumber;
char* Source;
char* Date;
char* Headline;
char* OriginCity;
} WAISDocumentHeadlines;
typedef struct WAISDocumentCodes {
any* DocumentID;
long VersionNumber;
char* StockCodes;
char* CompanyCodes;
char* IndustryCodes;
} WAISDocumentCodes;
typedef struct WAISSearchResponse {
char* SeedWordsUsed;
WAISDocumentHeader** DocHeaders;
WAISDocumentShortHeader** ShortHeaders;
WAISDocumentLongHeader** LongHeaders;
WAISDocumentText** Text;
WAISDocumentHeadlines** Headlines;
WAISDocumentCodes** Codes;
diagnosticRecord** Diagnostics;
} WAISSearchResponse;
/*----------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C"
{
#endif
DocObj* makeDocObjUsingWholeDocument _AP((any* aDocID,char* type));
DocObj* makeDocObjUsingBytes _AP((any* aDocID,char* type,long start,long end));
DocObj* makeDocObjUsingLines _AP((any* aDocID,char* type,long start,long end));
DocObj* makeDocObjUsingParagraphs _AP((any* aDocID,char* type,any* start,any* end));
void freeDocObj _AP((DocObj* doc));
WAISInitResponse* makeWAISInitResponse _AP((long chunkCode,long chunkIDLen,
char* chunkMarker,char* highlightMarker,
char* deHighlightMarker,char* newLineChars));
void freeWAISInitResponse _AP((WAISInitResponse* init));
WAISSearch* makeWAISSearch _AP((
char* seedWords,DocObj** docs,char** textList,
long dateFactor,char* beginDateRange,char* endDateRange,
long maxDocsRetrieved));
void freeWAISSearch _AP((WAISSearch* query));
WAISDocumentHeader* makeWAISDocumentHeader _AP((
any* aDocID,long versionNumber,long score,long bestMatch,long docLen,
long lines,char** types,char* source,char* theDate,char* headline,char* originCity));
void freeWAISDocumentHeader _AP((WAISDocumentHeader* header));
char* writeWAISDocumentHeader _AP((WAISDocumentHeader* header,char* buffer,long* len));
char* readWAISDocumentHeader _AP((WAISDocumentHeader** header,char* buffer));
WAISDocumentShortHeader* makeWAISDocumentShortHeader _AP((
any* aDocID,long versionNumber,long score,long bestMatch,long docLen,long lines));
void freeWAISDocumentShortHeader _AP((WAISDocumentShortHeader* header));
char* writeWAISDocumentShortHeader _AP((WAISDocumentShortHeader* header,
char* buffer,long* len));
char* readWAISDocumentShortHeader _AP((WAISDocumentShortHeader** header,char* buffer));
WAISDocumentLongHeader* makeWAISDocumentLongHeader _AP((
any* aDocID,long versionNumber,long score,long bestMatch,long docLen,
long lines,char** types,char* source,char* theDate, char* headline,char* originCity,
char* stockCodes,char* companyCodes,char* industryCodes));
void freeWAISDocumentLongHeader _AP((WAISDocumentLongHeader* header));
char* writeWAISDocumentLongHeader _AP((WAISDocumentLongHeader* header,char* buffer,long* len));
char* readWAISDocumentLongHeader _AP((WAISDocumentLongHeader** header,char* buffer));
WAISSearchResponse* makeWAISSearchResponse _AP((
char* seedWordsUsed,WAISDocumentHeader** docHeaders,
WAISDocumentShortHeader** shortHeaders,
WAISDocumentLongHeader** longHeaders,
WAISDocumentText** text,WAISDocumentHeadlines** headlines,
WAISDocumentCodes** codes,
diagnosticRecord** diagnostics));
void freeWAISSearchResponse _AP((WAISSearchResponse* response));
WAISDocumentText* makeWAISDocumentText _AP((any* aDocID,long versionNumber,
any* documentText));
void freeWAISDocumentText _AP((WAISDocumentText* docText));
char* writeWAISDocumentText _AP((WAISDocumentText* docText,char* buffer,long* len));
char* readWAISDocumentText _AP((WAISDocumentText** docText,char* buffer));
WAISDocumentHeadlines* makeWAISDocumentHeadlines _AP((
any* aDocID,long versionNumber,char* source,char* theDate,
char* headline,char* originCity));
void freeWAISDocumentHeadlines _AP((WAISDocumentHeadlines* docHeadline));
char* writeWAISDocumentHeadlines _AP((WAISDocumentHeadlines* docHeadline,char* buffer,long* len));
char* readWAISDocumentHeadlines _AP((WAISDocumentHeadlines** docHeadline,char* buffer));
WAISDocumentCodes* makeWAISDocumentCodes _AP((
any* aDocID,long versionNumber,char* stockCodes,char* companyCodes,
char* industryCodes));
void freeWAISDocumentCodes _AP((WAISDocumentCodes* docCodes));
char* writeWAISDocumentCodes _AP((WAISDocumentCodes* docCodes,char* buffer,long* len));
char* readWAISDocumentCodes _AP((WAISDocumentCodes** docCodes,char* buffer));
any* makeWAISTextQuery _AP((DocObj** docs));
DocObj** readWAISTextQuery _AP((any* terms));
void CSTFreeWAISInitResponse _AP((WAISInitResponse* init));
void CSTFreeWAISSearch _AP((WAISSearch* query));
void CSTFreeDocObj _AP((DocObj* doc));
void CSTFreeWAISDocumentHeader _AP((WAISDocumentHeader* header));
void CSTFreeWAISDocumentShortHeader _AP((WAISDocumentShortHeader* header));
void CSTFreeWAISDocumentLongHeader _AP((WAISDocumentLongHeader* header));
void CSTFreeWAISSearchResponse _AP((WAISSearchResponse* response));
void CSTFreeWAISDocumentText _AP((WAISDocumentText* docText));
void CSTFreeWAISDocumentHeadlines _AP((WAISDocumentHeadlines* docHeadline));
void CSTFreeWAISDocumentCodes _AP((WAISDocumentCodes* docCodes));
void CSTFreeWAISTextQuery _AP(( any* query));
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------*/
#endif

Some files were not shown because too many files have changed in this diff Show More