/********************************************************************
* wilkinson
* 3.6VMS
* 1995/09/25 14:35
* gopher_root1:[gopher.g2.vms2_13.gopherd]openers.c,v
* Exp
*
* Paul Lindner, University of Minnesota CIS.
*
* Copyright 1991, 1992 by the Regents of the University of Minnesota
* see the file "Copyright" in the distribution for conditions of use.
*********************************************************************
* MODULE: openers.c
* See below
*********************************************************************
* Revision History:
* openers.c,v
* Revision 3.6VMS 1995/09/25 14:35    wilkinson
* Consolodate VMS/Unix source code for server as well as client
*
* Revision 3.6  1995/02/07  07:02:46  lindner
* performance fixes
*
* Revision 3.5  1993/09/18  03:26:17  lindner
* Important Security fix
*
* Revision 3.4  1993/07/27  05:27:54  lindner
* Mondo Debug overhaul from Mitra
*
* Revision 3.3  1993/04/09  16:23:12  lindner
* Additional debug stuff
*
* Revision 3.2  1993/02/19  21:22:05  lindner
* Fixed problems with non-chroot() use
*
* Revision 3.1.1.1  1993/02/11  18:02:52  lindner
* Gopher+1.2beta release
*
* Revision 1.2  1993/01/30  23:57:44  lindner
* Fixes so that opening a file doesn't depend on what the current
* directory is.
*
* Revision 1.1  1992/12/10  23:13:27  lindner
* gopher 1.1 release
*
*
*********************************************************************/



/*
* Routines that implement safe "openers" so that we can do without
* the chroot().  This is an advantage because then you can have
* symbolic links from your gopher server directory to other files
* that are elsewhere on your system, without (if we've done this right)
* compromising your security, or allowing access to any files that
* you don't want made available.
*
* The "r" in the names is meant to indicate "restricted".
* The "u" in the names is meant to indicate "unrestricted".
*/

#include "gopherd.h"
#include "Debug.h"

#ifndef VMS_SERVER
#include <sys/param.h>  /* for MAXPATHLEN */
#else
#ifdef MAXPATHLEN
#undef MAXPATHLEN
#endif
#define MAXPATHLEN  512
#endif

/* and restore our real names */
#undef open
#undef fopen
#undef stat
#undef opendir
#undef chdir

#ifdef VMS_SERVER
#define opendir(a) VMS$Wild_Search(a)
#endif

char    *fixfile();

int
ropen( path, flags, mode )
char *path;
int flags, mode;
{
    char *p;
    p = fixfile(path);
    if (p != NULL)
         return( open( p, flags, mode ) );
    return(-1);        /* failed */
}


FILE *
rfopen( filename, type )
char *filename, *type;
{
    char *p;
    p = fixfile(filename);
    if (p != NULL)
         return( fopen( p, type ) );
    return(NULL);      /* failed */
}


int
rstat( path, buf )
char *path;
struct stat *buf;
{
    char *p;
    p = fixfile(path);
    if (p != NULL)
         return( stat( p, buf ) );
    return(-1);        /* failed */
}


DIR *
ropendir( dirname )
char *dirname;
{
    char *p;
    p = fixfile(dirname);
    if (p != NULL)
         return( opendir( p ) );
    return(NULL);      /* failed */
}


/*
* Restricted chdir.
*
* Change to Data_Dir first if it's an absolute path,
* then do a relative chdir from there....
*/

int
rchdir( path )
char *path;
{
    char *p;
#ifdef VMS_SERVER
    if (strcmp(path,"/")==0)
       path = GDCgetDatadir(Config);
#endif
    p = fixfile(path);

    Debug("Changing to directory %s\n", p);
    return( chdir( p ) );
}


int
uopen( path, flags, mode )
char *path;
int flags, mode;
{
    return( open( path, flags, mode ) );
}


FILE *
ufopen( filename, type )
char *filename, *type;
{
    return( fopen( filename, type ) );
}


int
ustat( path, buf )
char *path;
struct stat *buf;
{
    return( stat( path, buf ) );
}


DIR *
uopendir( dirname )
char *dirname;
{
    return( opendir( dirname ) );
}


int
uchdir( path )
char *path;
{
#ifdef VMS_SERVER
    if (strcmp(path,"/")==0)
       path = GDCgetDatadir(Config);
#endif
    Debug("Changing to directory %s\n", path);
    return( chdir( path ) );
}


/* Make sure the pathname they gave us is safe and secure for use */

char *
fixfile(name)
char *name;
{
#ifndef VMS_SERVER
    char newpathbuf[MAXPATHLEN];
    char *newpath;

    newpath = &newpathbuf[0];

    if (!dochroot) {
         strcpy(newpath, Data_Dir);

         newpath += strlen(Data_Dir);
    }
    else {
         strcpy(newpath, "/");
    }
    /* set errno to EPERM in case we reject the request */
    errno = EPERM;

    /*
    ** rip any .. or . entries out, so they can't sneak up out of
    ** the gopher directory.  Need to use dedot2() so we don't clobber
    ** the string they sent us originally.
    */
    dedot2(name,newpath);
    if (*newpath == '/' || *newpath == '\0')
         return(newpathbuf);
    else
         return(newpath);
#else
   return(name);
#endif
}

#ifdef VMS_SERVER

/**********************
*   Emulate functionality of ropendir() and readdir() for VMS wildcarded search
*/
char *

VMS$Wild_Search(char *path)
{
    static struct FAB   wild_fab;  /* Used in wildcard search              */
    static struct NAM   wild_nam;  /* Used in conjunction with wild_fab    */
    static char fullname[256];     /* ropendir() input, readdir() output   */
    static char expanded[256];     /* filespec after logical expansion     */
    static char result[256];       /* result from search                   */
    register    status;
    char *cp;

/* Validate path, initialize for wildcarded search of directory */

    if (path) {                    /* opendir() emulation      */
       wild_fab = cc$rms_fab;
       wild_nam = cc$rms_nam;
       wild_fab.fab$b_fac = FAB$M_GET;
       wild_fab.fab$l_fop = FAB$V_NAM;
       wild_fab.fab$l_nam = &wild_nam;
       wild_fab.fab$l_dna = "*.*";
       wild_fab.fab$b_dns = strlen(wild_fab.fab$l_dna);
       wild_nam.nam$l_esa = expanded;
       wild_nam.nam$l_rsa = result;
       wild_nam.nam$b_ess = wild_nam.nam$b_rss = 255;
       wild_fab.fab$l_fna = fullname;
       wild_fab.fab$b_fns = fullname[0] = expanded[0] = result[0] = 0;


       if (((status = SYS$PARSE(&wild_fab)) &1) != 1) {
           LOGGopher(-1,"Error on parse of pathname %s, %s",path,
                                                   STRerror(errno));
           return(NULL);
       }
       return(fullname);
    }

/* Get next directory entry */          /* readdir() emulation  */

    if ((( status = SYS$SEARCH(&wild_fab)) &1) != 1) {
       if ( (status == RMS$_NMF) || (status == RMS$_FNF) )
          return(NULL);
       LOGGopher(-1,"Error on search next, %s",STRerror(errno));
       return(NULL);
    }

    fullname[0] = expanded[wild_nam.nam$b_esl]
                       = result[wild_nam.nam$b_rsl] = '\0';
    strcpy(fullname, (char*)strchr(result,']') + 1);
    *((char *)strchr(fullname,';')) = '\0';
    return(fullname);
}
#endif