#!/usr/bin/perl
#
# 	$Id: gopherdconfig,v 1.7 1995/02/05 19:56:06 tedhajek Exp $	

#########################
# gopherdconfig - configuration script for Debian GNU/Linux gopherd package
#
# Written by Ted Hajek <tedhajek@boombox.micro.umn.edu>
#  original (httpd) configuration script written from
#  29 Aug 1994 to 16 Oct 1994 (how's that for productivity?)
#
#  modified for use with gopher on 27 November 1994
#  finished first workable version on  7 December 1994
#
# This script was originally the postinstallation script for the gopherd
# package.  However, because of a problem in the dpkg installation utility,
# I've opted to install this script so that it can be run at any time.
#
# This script only performs very simple configuration of the gopherd server.
# Other functions are left for the advanced user (in other words, more
# advanced than me).
#
# The script sets the following options:
#
# INVOCATION OPTIONS:
#   Port              The port at which gopherd accepts connections
#   AccessLog         Should server access be logged?
#   Mode              Should we use inetd or a standalone server?
#
# Since we can run the server without changing the configuration
# files, we'll let the packaging software deal with 'em.
#
# Here's the deal:  The gopherd package won't hack things if there's
# a ``gopherd'' script in cron.weekly to rotate log files.  The
# only way one would be there (barring extreme coincidence) is if
# the package has already been configured.
# If one already exists, we won't do anything unless we're given the
# option `--force'.
##############################


#######################################################
# GLOBAL CONSTANTS (not really constants, actually...)
#                  (but I won't touch 'em, really!)
#######################################################

$conf_file = "/etc/gopherd.conf";	# Where is the config file?
$default_port = 70;		# Default port on which to run 
$default_nogroup_gid = 65534;	# Need this when getting new GID's
$default_nobody_uid = 65534;	# Need this when getting new UID's
$default_access_logging = "yes";	# Should we log access?
$default_doc_location = "/home/gopher-data"; # Where should docs be stored
$default_use_doc_maint_group = "yes"; # Should we use a doc maint. group?
$default_doc_maint_group = "gopher"; # What should we name it?
$default_dir_mode = 755;	# Use this mode when we're making directories
$default_user = "gopher";	# The server will run as this user.
$default_server_mode = "standalone"; # The server will run standalone
       				     # rather than under inetd

########################################
# Housekeeping...
#######################################

##
## Better make sure that EUID = 0...
##
die "You must be root to run this script." if ($> != 0);

#####################################
# process command line args
####################################

$force = 0;			# don't force update of existing config file

$no_of_args = $#ARGV + 1;
if ($no_of_args > 1) {
    &usage;
    exit;
} elsif ($no_of_args == 1) {
    if ($ARGV[0] eq "--version") {
	&version;
	exit;
    } else {
	&usage;
	exit;
    }
}

###############################################################
## if we've made it this far, we can contiune with aplomb.
## Gather some information...
###############################################################

# welcome the user
&welcome;
&pause;
# see if they agree to the copyright
&copyright_notice;
# find out the root of the tree of served files
$doc_location = &get_and_create_doc_location;
# Should the server run as user ``gopher'' or ``nobody''?
$user = &get_server_user;
# Ask user if they want to use a gopher document maintenance group
$use_doc_maint_group = &check_doc_maint_group;
# should server run standalone or under inetd?
$server_mode = &get_server_mode;
# check whether or not user wants access logging enabled.
# Logging is automatic under inetd configuration (via tcpd).
if ($server_mode eq "standalone") {
    $access_logging = &check_access_logging;
} else {
    $access_logging = "no";
}
# get the port number
if ($server_mode eq "standalone") {
    $port = &get_port;
} else {			# we're running under inetd
    $port = $default_port;
}

# OK.  We have all the necessary information.  Here it is:
#   $port                  port at which server will listen
#   $doc_location          the root directory for served documents.
#   $use_doc_maint_group   should change ownership of the gopher tree to this group?
#   $user                  should server run as ``gopher'' or ``nobody''?
#   $access_logging        should accesses be logged?
#   $server_mode           standalone or inetd?
#
# Furthermore, we're sure that the group for document maintenance exists, provided
# the user wants one, and that the correct user exists.  Good.  

#################################
# CONFIGURE GOPHERD
#################################

# Now, we must:
#    - change group ownership of the $doc_location directory, if necessary (done)
#    - Set the GID bit on the $doc_location directory, if necessary (done)
#    - put something in ``inetd.conf'' or ``rc.misc'' to start daemon, depending on mode 
#    - set up a script to cycle logfiles (done)
# Then, give the user a final message and send them on their merry way.


##
## deal with document maintainance group
##
if ($use_doc_maint_group eq "yes") {
    print "Changing ownership and mode of things in $doc_location...";
    ($name, $passwd, $uid) = getpwnam($user);
    ($name, $passwd, $gid) = getgrnam($default_doc_maint_group);

    # do this for the files and directories in $doc_location
    open (FIND, "find $doc_location -print |") || die "Couldn't run find: $!\n";

    while ($filename = <FIND>) {
	chop $filename;
	chown ($uid, $gid, $filename);
	if (-d $filename) {
	    chmod (02775, $filename); # directories should be SGID
	} else {
	    chmod (0664, $filename); # files should be group-writeable
	}
    }
    close (FIND);

    print "Done.\n";
}

##
## code to start server
##
if ($server_mode eq "standalone") {
    print "Adding file /etc/rc.misc/gopherd to automatically start server...";
    if (-f "/etc/rc.misc/gopherd") {
	print "\nMoving existing /etc/rc.misc/gopherd to /etc/gopherd-start.disabled...\n";
	rename ("/etc/rc.misc/gopherd", "/etc/gopherd-start.disabled");
    }
    open (STARTUP, ">/etc/rc.misc/gopherd");
    print STARTUP "#!/bin/sh\n";
    print STARTUP "#\n";
    print STARTUP "# Start the U of MN gopher daemon.\n";
    print STARTUP "if [ -x /usr/sbin/gopherd ]; then\n";
    print STARTUP "    echo 'Starting gopherd...'\n";
    if ($access_logging eq "yes") {
	print STARTUP "    /usr/sbin/gopherd -u $user -l /var/adm/gopherd.log $doc_location $port &\n";
    } else {
	print STARTUP "    /usr/sbin/gopherd -u $user $doc_location $port &\n";
    }
    print STARTUP "fi\n";

    close (STARTUP);

    chmod (0755, "/etc/rc.misc/gopherd");
    print "Done.\n";
    print "Removing startup line from inetd.conf, if it exists... ";
    &comment_out_gopherd_lines;
    print "Done.\n";
} else {			# we're using inetd mode.
    print "Adding stanza in /etc/inetd.conf to run server... ";
    &hack_inetd_config;
    # get rid of standalone startup file
    if (-f "/etc/rc.misc/gopherd") {
	print "\nMoving existing /etc/rc.misc/gopherd to /etc/gopherd-start.disabled...\n";
	rename ("/etc/rc.misc/gopherd", "/etc/gopherd-start.disabled");
    }
    print "Done.\n";
}

##
## Say goodbye, now...
##
&exit_message;
&pause;

exit (0);


####################################################
####################################################
# END MAIN PROGRAM -- BEGIN SUBROUTINES
####################################################
####################################################
# These are in alphabetical order


##########################################
## check_access_logging
##########################################
# See if user wants access logging enabled
#
sub check_access_logging {
    local ($answer);

    &print_heading ("Access Logging");

    print "Do you want the server to log all server access?  If so, \n";
    print "a line will be generated in the log each time anyone accesses\n";
    print "a file from your server.\n";
    print "\n";
    print "By default, the server will log access.  If you type anything\n";
    print "beginning with a 'n' below, the server will *not* log access.\n";
    print "\n";

    &print_prompt("Access logging", $default_access_logging);
    chop ($answer = <STDIN>);

    if ($answer =~ /^[Nn]/) {
	$answer = "no";
    } else {
	$answer = $default_access_logging;
    }

    return $answer;
}


#####################################
## check_doc_maint_group
#####################################
# Find out if the user wants to use the 'gopher' group to give users
# the appropriate permissions to edit the served document tree.
sub check_doc_maint_group {
    local ($answer);
    local ($name, $passwd, $gid, $members);
    local ($doc_maint_group_num);

    &print_heading ("Use a group for gopher document tree maintainers");

    # check for the group 'gopher'
    ($name, $passwd, $gid, $members) = getgrnam($default_doc_maint_group);

    if ($name) {		# The group already exists.
	print "A group called $default_doc_maint_group exists.\n";
	print "Would you like me to change the group ownership of the gopher document tree\n";
	print "to this group and flag the tree so that any subdirectories created under\n";
	print "it belong to the group?\n";
	print "\n";
	print "The directory and any future subdirectories will also, by default, be\n";
	print "writeable by this group.\n";
	print "\n";
	print "You can change membership in the group by editing the file '/etc/group'.\n";
	print "\n";

	&print_prompt ("Use document maintenance group?", $default_use_doc_maint_group);
	chop ($answer = <STDIN>);

	if ($answer =~ /^[Yy]/) {
	    $answer = "yes";
	} elsif (! $answer) {
	    $answer = $default_use_doc_maint_group;
	} else {
	    $answer = "no";
	}
    } else {			# The group doesn't exist
	print "Would you like to create a group called $default_doc_maint_group?\n";
	print "After I create the group, I will change the ownership of the gopher\n";
	print "document tree to this group and flag the root of the tree so that any\n";
	print "subdirectories created under the tree will be automatically owned\n";
	print "by the group.\n";
	print "\n";
	print "Furthermore, the group will be given write permission to the gopher\n";
	print "document tree.\n";
	print "\n";

	&print_prompt ("Create document maintenance group?", $default_use_doc_maint_group);
	chop ($answer = <STDIN>);

	if ($answer =~ /^[Yy]/) {
	    $answer = "yes";
	} elsif (! $answer) {
	    $answer = $default_use_doc_maint_group;
	} else {
	    $answer = "no";
	}
	
	# create group if user wants to set things up this way:
	if ($answer eq "yes") {
	    print "Creating group $default_doc_maint_group... ";
	    $group_num = &get_new_group_num;
	    open(GROUP, ">>/etc/group") || die "Yipes, couldn't append to /etc/group";
	    print GROUP $default_doc_maint_group . "::" . $group_num . ":\n";
	    close(GROUP);
	    print "done.\n";
	}
    }

    return ($answer);
}


#################################
## check_error_logging
#################################
# See if user wants access logging enabled
#
sub check_error_logging {
    local ($answer);

    &print_heading ("Error Logging");

    print "Do you want the server to log errors?\n";
    print "\n";
    print "By default, the server will not log errors.  If you type anything\n";
    print "beginning with a 'y' below, the server *will* log errors.\n";
    print "\n";

    &print_prompt("Error logging", $default_error_logging);
    chop ($answer = <STDIN>);

    if ($answer =~ /^[Yy]/) {
	$answer = "yes";
    } else {
	$answer = $default_error_logging;
    }

    return $answer;
}
	
#################################
## comment_out_gopherd_lines
#################################
# comment out all lines in inetd.conf that contain the word
# "gopher"
sub comment_out_gopherd_lines {
    local (@inetd_conf);	# the inetd.conf file in an array
    local ($line, $changed);	# the current line in inetd.conf
				# have we changed anything?

    # open the inetd.conf file and load it into an array
    open (INETD, "</etc/inetd.conf") || die "open: couldn't open inetd.conf for reading";
    @inetd_conf = <INETD>;
    close(INETD);

    $changed = 0;		# we haven't changed anything

    # chop trailing newlines, comment out lines w/ "gopher"
    foreach $line (@inetd_conf) {
	chop $line;
	if (($line =~ /gopher/) && ($line !~ /^#/)) {
	   $line = "#" . $line;
	   $changed = 1;
	}
    }

    if ($changed == 1) {
	# write the inetd.conf file
	unlink ("/etc/inetd.conf.old");
	rename ("/etc/inetd.conf", "/etc/inetd.conf.old") || die "rename: couldn't rename existing inetd.conf file";
	open (INETD, ">/etc/inetd.conf") || (rename ("/etc/inetd.conf.old", "/etc/inetd.conf") && die "open: couldn't open inetd.conf for writing");
	foreach $line (@inetd_conf) {
	    print INETD $line . "\n";
	}
	close (INETD);
    }
}


#################################
## copyright_notice
#################################
# Display the copyright; if the user doesn't agree
# with the terms, bail.
sub copyright_notice {
    local ($answer);

    # Display the copyright notice:
    print "\n";
    print "Please read carefully the copyright notice for the gopher software:\n";
    print "\n";
    print <<THE_COPYRIGHT;

 The Internet Gopher(tm) software and documentation is copyright (c)
 1991, 1992, 1993 by the University of Minnesota.

 Permission to use, copy, modify, and distribute this software and
 documentation for non-commercial purposes and without fee is hereby
 granted, provided that the University of Minnesota copyright notices
 and this permission notice appear in all copies, and that the name
 University of Minnesota not be used in advertising or publicity
 pertaining to this software and documentation without specific,
 written prior permission. The University of Minnesota makes no
 representations about the suitability of this software and
 documentation for any purpose.  It is provided ``as is'' without
 express or implied warranty.  Commercial use of Gopher requires
 specific permission from the University of Minnesota; contact the
 internet gopher development team at <gopher\@boombox.micro.umn.edu> for
 further information.
THE_COPYRIGHT

    # ask the user if they agree with the terms:
    print "\n\n";
    print "Do you wish to continue the configuration, subject to these terms?\n";
    print "Anything beginning with the letter `y' will be interpreted as `yes': ";
    chop ($answer = <STDIN>);

    # if they don't agree, bail:
    if (! ($answer =~ /^[Yy]/)) {
	print "\n\n";
	print "OK, configuration aborted.\n";
	print "If you wish to remove the gopher server from your system, type\n";
	print "  dpkg --remove gopherd\n";
	print "at your shell prompt.\n";
	exit 0;
    }
}

#####################################
## create_user_gopher
#####################################
# create a user named ``gopher''.  We already know
# that such a user doesn't exist, otherwise we wouldn't
# be here! (see subroutine &get_server_user()).  Create a group
# `gopher' if one doesn't already exist.
#
# called with the (already chosen by user) root directory of the
# gopher tree.  This is made the gopher user's `home directory'
# for easy changing of directories (to ~gopher).
sub create_user_gopher {
    local ($gopher_root_dir) = @_;
    local ($uid);
    local ($group, $password, $gid);

    # find UID
    $uid = &get_new_user_num;
    # find GID
    # first, check if there's a group `gopher'.
    ($group, $password, $gid) = getgrnam("gopher");
    if (! $gid) {
	print "Creating group $default_doc_maint_group... ";
	$gid = &get_new_group_num;
	open(GROUP, ">>/etc/group") || die "Yipes, couldn't append to /etc/group";
	print GROUP $default_doc_maint_group . "::" . $gid . ":\n";
	close(GROUP);
	print "done.\n";
    }    
    print "Creating user gopher... ";
    open(PASSWD, ">>/etc/passwd") || die "Yipes, couldn't append to /etc/passwd";
    print PASSWD "gopher:*:" . $uid . ":" . $gid . ":gopher:" . $gopher_root_dir . ":\n";
    close(PASSWD);
    print "done\n";
}


#####################################
## exit_message
#####################################
# say goodbye, tell the user what we've done
sub exit_message {
    print <<DONE


------ Configuration complete. -------

Your gopher daemon is ready-to-go; the next time you restart the system,
a stanza of code in `/etc/rc.misc/gopherd' or '/etc/inetd.conf'  will start
the server.  At that point, anyone will be able to retrieve documents from 
your machine.  As such, you should review the setup and make sure that it
is in harmony with  your overall security strategy.

Actually, you should edit the file `/etc/gopherdlocal.conf'; you may want
to change some of the definitions therein.  In particular, it's nice to
specify an email address to which individuals can `gripe' when your server
has problems.  If you are confused by some of the directives used in the
file, see the manual page for `gopherd.conf' in section five.

Under the current setup, the server performs a chroot() system call before
serving documents.  In other words, it makes the root of your document tree
appear as the root of the entire filesystem.  While this is the most secure
way to run the gopher server, it largely precludes using forms ('ask' blocks)
and searchable WAIS indexes.  See the manual page for more details.

Have fun; please populate the net with lots of groovy things.
DONE
}


######################################
## get_and_create_doc_location
######################################
# Get the directory name that represents the root
# of the tree of served files.
#
# This also creates the directory in question.
#
sub get_and_create_doc_location {
    local ($answer, $dir_create);

    &print_heading ("Root of Document Tree");

    print "Please specify the complete name of the directory in which\n";
    print "all the body of documents served will reside.\n";
    print "\n";
    print "If the directory you specify does not exist, it will be created\n";
    print "for you.  The default directory is \"$default_doc_location\".\n";
    print "\n";

    # LOOP:
    # get directory name from user.
    #
    # if the user leaves this one blank, make sure the default directory
    # exists and return it.
    #
    # make sure the answer begins with a slash and doesn't contain
    # double-dots.
    #
    # then, check if the directory exists.  If so, we're fine.  Return
    # the directory.
    #
    # finally, try to create the directory.  If it works, return it.
    # otherwise, try again.
    while (1) {
	&print_prompt ("Document directory", $default_doc_location);
	chop ($answer = <STDIN>);	# get answer from user
	$answer =~ s/\s+//g;	# strip spaces

	# if it's blank, create the default; immediately return.
	if (! $answer) {
	    &mktree ($default_doc_location) if (! -d $default_doc_location);
	    if (-d $default_doc_location) {
		return ($default_doc_location);
	    } else {
		die "Yipes! I couldn't create the default directory.";
	    }
	}
	
	if (! ($answer =~ m%^/%)) {
	    print "The document directory must be specified by an absolute path.\n";
	    print "In other words, it must begin with a slash.\n";
	    next;
	} elsif ($answer =~ /\.\./) {
	    print "You shouldn't have double-dots (..) in your path.\n";
	    next;
	}

	# chop trailing slash if it exists:
	chop ($answer) if ($answer =~ m%/$%);

	# if directory exists, it's OK.  Return the answer.
	return ($answer) if (-d $answer);

	# otherwise, we'll try to create the directory.
	# use another subroutine; this might be useful elsewhere.
	&mktree ($answer);
	if (-d $answer) {
	    return $answer;
	} else {
	    print "I couldn't create that directory.  Try again...\n";
	}
    }
}



########################################
## get_new_group_num
########################################
# Subroutine to generate a unique, unused group number.
# we'll add one to the largest group number, unless the largest number
# is that used for "nogroup" (65534).
#
# in that case, we'll add one to the second-largest group number.
#
sub get_new_group_num {
    local ($new_num, $largest, $second_largest);
    local ($name, $passwd, $gid, $members);
    local (@gid_list);

    $largest = 0;
    $second_largest = 0;

    # reset iteration through the group file
    setgrent;

    # now iterate through the thing.
    # put each GID into an array entry
    while (($name, $passwd, $gid, $members) = getgrent) {
	push (@gid_list, $gid);
    }

    # OK, we're done looking through the group file.
    endgrent;

    # sort the gid's numerically and find the largest:
    # we want the second largest as well in case the largest == GID(nogroup).
    sub numerically { $a <=> $b; }
    foreach $gid (sort numerically @gid_list) {
	if ($gid > $largest) {
	    $second_largest = $largest;
	    $largest = $gid;
	}
    }

    # now, generate the GID for the new group.
    if ($largest == $default_nogroup_gid) {
	$new_num = $second_largest + 1;
    } else {
	$new_num = $largest + 1;
    }

    return ($new_num);
}



########################################
## get_new_user_num
########################################
# Subroutine to generate a unique, unused group number.
# we'll add one to the largest existing UID, unless the largest number
# is that used for "nobody" (65534).
#
# in that case, we'll add one to the second-largest UID.
#
sub get_new_user_num {
    local ($new_num, $largest, $second_largest);
    local ($name, $passwd, $uid);
    local (@uid_list);

    $largest = 0;
    $second_largest = 0;

    # reset iteration through the password file
    setpwent;

    # now iterate through the thing.
    # put each UID into an array entry
    while (($name, $passwd, $uid) = getpwent) {
	push (@uid_list, $uid);
    }

    # OK, we're done looking through the group file.
    endpwent;

    # sort the gid's numerically and find the largest:
    # we want the second largest as well in case the largest == GID(nogroup).
    sub numerically { $a <=> $b; }
    foreach $uid (sort numerically @uid_list) {
	if ($uid > $largest) {
	    $second_largest = $largest;
	    $largest = $uid;
	}
    }

    # now, generate the GID for the new group.
    if ($largest == $default_nobody_uid) {
	$new_num = $second_largest + 1;
    } else {
	$new_num = $largest + 1;
    }

    return ($new_num);
}
	    


####################################
## get_num
####################################
# get a number from the user
#
sub get_num {
    local ($prompt, $default) = @_;
    local ($num);

    # loop until we have a valid number
    while (1) {
	&print_prompt ($prompt, $default);
	chop ($num = <STDIN>);

	# if they hit enter, use default
	if ($num eq "") {
	    $num = $default;
	    last;
	}

	# check if num consists of all digits
	if ($num =~ /^\d+$/) {
	    last;
	}

	print "Hmm... that doesn't look like a number.\n";
	print "Please try again...\n\n";
    }

    return ($num);
}


#################################
## get_port
#################################
# Get the port number
#
sub get_port {
    local ($answer);

    &print_heading ("Port Selection");
    
    print "Please choose a port on which gopherd will listen for requests.\n";
    print "The default port, 70, is the standard location for gopher servers.\n";
    print "You can, however, choose another port if you wish.\n";
    print "\n";
    print "If you choose a port number lower than 1024, you need to be root\n";
    print "to start the server.  This is the normal mode of operation.\n";
    print "\n\n";
    
    $answer = &get_num ("Port", $default_port);

    return ($answer);
}
    
#################################
## get_server_mode
#################################
# Find out whether server should run standalone or
# under inetd.
sub get_server_mode {
    local ($answer);
    
    &print_heading ("Set Server Mode");

    print "The gopherd server can run in one of two modes, ``standalone'' or\n";
    print "``inetd''.\n";
    print "\n";
    print "When running in standalone mode, the server listens on a port for incoming\n";
    print "requests.  On each incoming request, it forks a copy of itself to dispatch\n";
    print "the request.\n";
    print "\n";
    print "When running in inetd mode, on the other hand, the inetd super-server listens\n";
    print "for incoming requests and executes a new copy of gopherd each time a request\n";
    print "is received.\n";
    print "\n";
    print "Standalone mode makes for a faster server under heavy loads, because the\n";
    print "configuration files only have to be parsed once.  On the other hand, inetd mode\n";
    print "works well for a server with a lighter load, since the gopher daemon is only\n";
    print "active when handling a request.\n";
    print "\n";
    print "Please choose either ``inetd'' or ``standalone'' below.\n";
    print "\n";

    # loop until a good answer breaks us out.
    while (1) {
	&print_prompt ("Server mode", $default_server_mode);
	chop ($answer = <STDIN>);
	if (($answer eq "standalone") || ($answer eq "inetd")) {
	    last;
	} elsif (! $answer) {
	    $answer = $default_server_mode;
	    last;
	} else {
	    print "Please enter either 'standalone' or 'inetd'.\n";
	}
    }

    return ($answer);
}

#################################
## get_server_user
#################################
# Find out whether server should run as user
# ``gopher'' or ``nobody''.
sub get_server_user {
    local ($answer, $good_answer);
    $good_answer = 0;

    &print_heading ("Select User");

    print "After binding to the port chosen above, the gopher server\n";
    print "can change its effective user ID to that of some user other\n";
    print "than root.  It is extremely important to exercise this capability;\n";
    print "it greatly reduces the damage that can be caused by an intruder in\n";
    print "the case that your security is compromized.\n";
    print "\n";
    print "You can run the server as the user ``gopher'' or the user ``nobody''.\n";
    print "Because the user ``nobody'' usually owns no files, this is a particularly\n";
    print "secure choice.\n";
    print "\n";
    print "However, you must run the server as some other user (such as ``gopher'')\n";
    print "in order to allow the server to cache the processing of directories.\n";
    print "When directories are cached, the server doesn't have to continually\n";
    print "re-process unchanged directory contents.\n";
    print "\n";
    print "If you choose to run the server as user ``gopher'' and choose below to\n";
    print "make the document tree owned and writeable by the group ``gopher'', caching\n";
    print "will be able to take place.\n";
    print "\n";

    # get an answer of either ``gopher'' or ``nobody''
    while ($good_answer == 0) {
	&print_prompt ("Server user", $default_user);
	chop ($answer = <STDIN>);
	if (! $answer) {
	    $answer = $default_user;
	    $good_answer = 1;
	} elsif (($answer eq "gopher") || ($answer eq "nobody")) {
	    $good_answer = 1;
	} else {
	    print "The user must be ``gopher'' or ``nobody''.\n";
	    print "Case is significant.\n";
	    print "\n";
	}
    }

    # if user has chosen ``gopher'', make sure that user ``gopher'' exists.
    # the user ``nobody'' is defined in the Debian GNU/Linux base package.
    if ($answer eq "gopher") {
	# look up user ``gopher''
	($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) =
	    getpwnam("gopher");
	# if the user ``gopher'' doesn't exist, we need to make one
	if (! $name) {
	    &create_user_gopher;
	}
    }

    # OK, we're done.  We have the answer and the user exists.
    # return the answer and boogie.
    return ($answer);
}

#####################################
## hack_inetd_config
#####################################
# add a line for gopherd to the inetd_config file if there's not
# already one there
sub hack_inetd_config {
    local (@inetd_conf);	# the inetd.conf file in an array
    local ($already_have_line);	# do we already have the necessary line?
    local (@line_nums);		# line numbers of existing lines
    local ($line, $new_line);	# the current line for iteration and the
				# line to be added

    # open the inetd.conf file and load it into an array
    open (INETD, "</etc/inetd.conf") || die "open: couldn't open inetd.conf for reading";
    @inetd_conf = <INETD>;
    close(INETD);

    $already_have_line = 0;
    # chop trailing newlines, see if we need to insert the line
    foreach $line (@inetd_conf) {
	chop $line;
	if ($already_have_line == 0) {
	    if ($line =~ m#^\s+gopher\s+stream\s+tcp\s+nowait\s+root\s+/usr/sbin/tcpd\s+/usr/sbin/gopherd -I -u $user $doc_location#) {
		$already_have_line = 1;
	    }
	}
    }

    return if $already_have_line;

    # if we don't have the line, comment out all lines that have "gopher"
    # in them
    foreach $line (@inetd_conf) {
	if (($line =~ /gopher/) && ($line !~ /^#/)) {
	   $line = "#" . $line;
	}
    }

    # add the line for gopher two lines from the end.
    $new_line = "gopher\tstream\ttcp\tnowait\troot\t/usr/sbin/tcpd\t/usr/sbin/gopherd -I -u $user $doc_location";
    splice (@inetd_conf, $#inetd_conf - 2, 0, $new_line);

    # we have a suitable inetd.conf.  There should only be one line for
    # starting gopherd.  Now, we need to write the file.
    unlink ("/etc/inetd.conf.old");
    rename ("/etc/inetd.conf", "/etc/inetd.conf.old") || die "rename: couldn't rename existing inetd.conf file";
    open (INETD, ">/etc/inetd.conf") || (rename ("/etc/inetd.conf.old", "/etc/inetd.conf") && die "open: couldn't open inetd.conf for writing");
    foreach $line (@inetd_conf) {
	print INETD $line . "\n";
    }
    close (INETD);
}
    

#####################################
## mktree
#####################################
# given a path, create the directory specified, creating all leading
# directories if necessary.  If successful, return 1, otherwise, return 0.
sub mktree {
    local ($requested_path) = @_;
    local (@path);
    local ($done, $attempt);

    # chop off any trailing slash.
    chop ($requested_path) if ($requested_path =~ m%/$%);
    # get rid of leading slash
    $requested_path =~ s@^/(.+)$@$1@;

    # split the path elements into an array
    @path = split(/\//, $requested_path);

    # this'll hold the parts of the path that have already been
    # created.  For example, if we are creating
    #   /usr/local/lib/httpd_data
    # the variable $done will hold
    #   /usr/local
    # after we're sure that /usr and /usr/local exist.
    $done = "";

    # while there are still path elements, create the next.
    while (@path) {
	$attempt = shift(@path);
	mkdir("$done/$attempt", $default_dir_mode);
	if (-d "$done/$attempt") {
	    $done = "$done/$attempt";
	} else {
	    return 0;
	}
    }

    return 1;
}


###########################################
## pause
###########################################
sub pause {
    local ($discard);
   
    print "Press [enter] to continue: ";
    $discard = <STDIN>;
}



#########################################
## print_heading
#########################################
# print a simple heading
#
sub print_heading {
    local ($head) = @_;

    print "\n";
    print "                 ------ $head ------\n";
    print "\n";
}



####################################
## print_prompt
####################################
# print a simple prompt
#
sub print_prompt {
    local ($prompt, $default) = @_;

    print "$prompt ($default): ";
}




############################################
## usage
############################################
# prints usage message
#
sub usage {
   print STDERR "gopherdconfig - gopher daemon configuration script\n";
    print STDERR "\n";
    print STDERR "usage: gopherdconfig [option]\n";
    print STDERR "\n";
    print STDERR "valid options:\n";
    print STDERR "  --help       Display this message\n";
    print STDERR "  --version    Display version and copyright information\n";
}



############################################
## version
############################################
# prints version and copyright information
#
sub version {
    print STDERR "gopherdconfig - gopher daemon configuration script\n";
    print STDERR " version $Id: gopherdconfig,v 1.7 1995/02/05 19:56:06 tedhajek Exp $	\n"; # this should grab RCS version number?
    print STDERR "\n";
    print STDERR "Copyright (C) 1994 by Ted Hajek <tedhajek\@boombox.micro.umn.edu>\n";
    print STDERR "\n";
    print STDERR "This program is free software; you can redistribute it and/or modify\n";
    print STDERR "it under the terms of the GNU General Public License as published by\n";
    print STDERR "the Free Software Foundation; either version 2 of the License, or\n";
    print STDERR "(at your option) any later version.\n";
    print STDERR "\n";
    print STDERR "This program is distributed AS IS in the hope that it will be useful,\n";
    print STDERR "but WITHOUT ANY WARRANTY; without even the implied warranty of\n";
    print STDERR "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n";
    print STDERR "GNU General Public License in the file `/usr/doc/copyright/GPL'.\n";
}


#######################################
## welcome
#######################################
# Welcome the nice user
#
sub welcome {
    &print_heading ("gopherd configuration");
    print "\n";
    print "Welcome to post-installation configuration of the U of MN gopher daemon.\n";
    print "Answering these questions will allow you to configure the daemon\n";
    print "to provide gopher service on a port of your choice.\n";
    print "\n";
    print "You should probably look at the server documentation. After all, by running\n";
    print "this server, you're allowing others to anonymously access files on your \n";
    print "machine.\n";
    print "\n";
    print "The manual page for gopherd should already be installed.  Type \n";
    print "  man gopherd\n";
    print "at your shell prompt for the details.\n";
    print "\n";
}



