/*
 * user-cgi: this allows users to run cgi scripts from their directories,
 * without placying them in your cgi-bin. If you run your daemon as root, it
 * will change to their userid before running their script.
 *
 * Copyright 1994, ASK, Inc.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pwd.h>

#ifdef ultrix
#define NOSTRDUP
#endif

#ifdef NOSTRDUP
char *strdup();
#endif
/*
 * The directory in the users home directory where we look for CGI executables.
 */
#define	PUBLIC_HTML	"public_html"

#define LF	10

main(argc, argv) char **argv; {
	char *user = getenv("PATH_INFO") ;
	char *script, *path, *p, buffer[MAXPATHLEN], url[MAXPATHLEN] ;
	struct passwd *pwd ;

	/* For errors, build the string they gave us */
	strcpy(url, getenv("SCRIPT_NAME")) ;
	if (!user) complain(url, "") ;
	else strcat(url, user) ;

	/* Figure out what we really want to run */
	if (user[0] != '/' || user[1] != '~') complain(url,"") ;
	user += 2 ;
	if (!(script = strchr(user, '/'))) complain(url,"") ;
	*script++ = '\0' ;

	path = strchr(script, '/') ;
	if (path) *path++ = '\0' ;

	/* Get the user information */
	if (!(pwd = getpwnam(user))) complain(url,script) ;

	/*
	 * Fix the environment variables:
	 *	PATH_INFO - the extra stuff on the path.
	 *	PATH_TRANSLATED - the _real_ path for extra stuff.
	 *	SCRIPT_NAME - the name of the script the URL runs.
	 */
	if (path) sprintf(buffer, "PATH_INFO=/%s", path) ;
	else strcpy(buffer, "PATH_INFO=") ;
	if (!(p = strdup(buffer))) complain(url,script) ;
	putenv(p) ;

	if (!(p = getenv("SCRIPT_NAME"))) complain(url,script) ;
	sprintf(buffer, "SCRIPT_NAME=%s/~%s/%s", p, user, script) ;
	if (!(p = strdup(buffer))) complain(url,script) ;
	putenv(p) ;

	if (path) sprintf(buffer, "PATH_TRANSLATED=%s/%s/%s",
			  pwd->pw_dir, PUBLIC_HTML, path) ;
	else strcpy(buffer, "PATH_TRANSLATED=") ;
	if (!(p = strdup(buffer))) complain(url,script) ;
	putenv(p) ;

	/* Ok, try and run the silly thing now */
	if (setgid(pwd->pw_gid) != 0) complain(url,"SetGid failed") ;
	if (setuid(pwd->pw_uid) != 0) complain(url,"SetUid failed") ;

	sprintf(buffer, "%s/%s/%s", pwd->pw_dir, PUBLIC_HTML, script) ;
	execvp(buffer, argv) ;
     
	/* If it fails, */
	complain(url,script) ;
	}

complain(url,script) char *url, *script; {
	char *server = getenv("SERVER_PROTOCOL") ;

	printf("Content-type: text/html%c%c", LF, LF) ;
	printf("<HTML><HEAD><TITLE>URL Not Found</TITLE></HEAD>%c", LF) ;
	printf("<BODY><H1>Error: URL not found</H1>%c", LF) ;
	printf("The requested URL %s was not found on this server.<P>%c",
	       url, LF) ;
	printf("The Path resolved to: %s.<P>%c",
	       script, LF) ;
	printf("</BODY></HTML>%c", LF) ;
	exit(0) ;
	}

#ifdef NOSTRDUP
char *strdup(char *s)
{
        char *p;

        p = (char *)malloc(strlen(s)+1);
        if (p != NULL) strcpy(p,s);
        return p;
}
#endif

===========================================================================
