/*
 * 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 <sys/param.h>	/* for MAXPATHLEN */

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


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;
     p = fixfile(path);
     if (p != NULL) {
	  if (*p == '/') {
	       chdir(Data_Dir);
	       return(chdir(p+1));
	  } 
	  else
	       return( chdir( p ) );
     }
     else
	  return(-1);	/* failed */
}


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;
{
     return( chdir( path ) );
}


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

char *
fixfile(name)
char *name;
{
     static char newpathbuf[MAXPATHLEN];
     char *newpath;

     newpath = &newpathbuf[0];

     /* 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);
     while ( *newpath == '/' )	/* make it relative path */
	  newpath++;
     if ( *newpath == '\0' )	/* nothing left - it was "/" */
	  newpath = ".";
     return( newpath );
}
