[ic] suid makecat

Mike Heins interchange-users@icdevgroup.org
Fri Jan 17 00:38:01 2003


Quoting Tim Stoakes (tim@ehost.com.au):
> On Thu, 16 Jan 2003 22:10:53 -0500
>  cfm@maine.com wrote:
> > On Fri, Jan 17, 2003 at 01:13:20PM +1030, Tim Stoakes wrote:
> > > On Thu, 16 Jan 2003 21:19:05 -0500
> > >  cfm@maine.com wrote:
> --snip--
> > > > reinventing cpanel? <LOL>
> > > 
> > > After hearing so many bad comments about CPanel we did not go down that road. This is just for internal use anyway, so that we can setup many catalogs quickly with inexperienced staff.
> > 
> > 
> > Just for internal use with inexperienced staff.
> > 
> > Stop.
> > 
> 
> Perhaps a rephrase: staff that are not using the root account or the
> interchange account. They will be shielded from doing anything else by
> the wrapper script, with the only parameters being the catalog name
> and template type (sanity checked of course). Most people *should* be
> able to handle that level of technical skill surely?!
> 

The way it has been done in the past is to actually have the IC server
do it. It is not that hard, and there is even a piece in CVS that
does it.

Basically, you build a catalog that is AllowGlobal and place the
procedure in a page. You authenticate via HTTP basic auth, and
collect the information. Then you build the catalog by calling
makecat.

Since it is already running as the right user ID there are no
issues with tainting.

In fact, if you would make an eg/ style package with HOWTO I would
give you a complete working install. Until then, I will just share
the actual page that builds the catalog, though there is nothing
too difficult there:

@_UI_STD_HEAD_@
[tmp ui_failure][/tmp]
[perl global=1]
	no strict;
	delete $Scratch->{restart};
	delete $Scratch->{ui_failure};
	if (! $CGI->{catname}) {
		$Scratch->{ui_failure} = "No catalog name given.";
		return;
	}
	my $catname   = $CGI->{catname};
	my $demotype  = $CGI->{demotype} || 'cl_foundation';
	my $demomode  = $CGI->{demomode} || $Global::Variable->{SB_DEMOMODE} || 0;
	my $icuser    = $Global::Variable->{SB_ICUSER}    || `cat $Global::VendRoot/_uid` || `cat $Global::VendRoot/.uid` || getpwuid($]);
	my $icgrp     = $Global::Variable->{SB_ICGROUP}   || getgrgid( (getpwnam($icuser))[3] );
	$icuser =~ s/\s+//g;
	my $catbase   = $Global::Variable->{SB_CATBASE}   || '/var/lib/interchange';
	my $tmpbase   = $Global::Variable->{SB_TMPBASE}   || '/var/cache/interchange';
	my $logbase   = $Global::Variable->{SB_LOGBASE}   || '/var/log/interchange';
	my $icbase    = $Global::Variable->{SB_ICBASE}    || $Global::VendRoot;
	my $cgibase   = $Global::Variable->{SB_CGIBASE}   || '/cgi-bin';
	my $cgidir    = $Global::Variable->{SB_CGIDIR}    || '/var/www/cgi-bin';
	my $docroot   = $Global::Variable->{SB_DOCROOT}   || '/var/www/html';
	my $sqluser   = $Global::Variable->{SB_SQLUSER}   || 'root';
	my $sqlpass   = $Global::Variable->{SB_SQLPASS}   || '';
	my $httpdconf = $Global::Variable->{SB_HTTPDCONF} || '/etc/httpd/conf/httpd.conf';
	my $domain    = $CGI->{domainname} || $Global::Variable->{SB_DOMAIN};
	$catname = lc $catname;
	$catname =~ s/-/_/g;
	$catname =~ s/\W+//g;
	my $userstuff = $Global::AdminUser;
	$userstuff =~ s/\s*\n.*//s;
	my ($superuser, $specialcrypt) = split /:/, $userstuff;

	$Scratch->{go_url} = "$domain$cgibase/$catname";
	if(defined $Global::Catalog{$_} and ! $CGI->{overwrite}) {
		$Scratch->{ui_failure} = "Catalog $catname already exists.";
		return;
	}
	push @args, "$Global::VendRoot/bin/makecat";
	push @args,
		'-F',
		"--cgibase=$cgibase",
		"--basedir=$catbase",
		"--documentroot=$docroot",
		"--minivenduser=$icuser",
		"--minivendgroup=$icgrp",
		"--serverconf=$httpdconf",
		"--vendroot=$icbase",
		"--catroot=$catbase/$catname",
		"--cgidir=$cgidir",
		"--servername=$domain",
		"--cgiurl=$cgibase/$catname",
		"--demotype=$demotype",
		"--mailorderto=$icuser\@$domain",
		"--catuser=$icuser",
#		"mysql=1",
		"pgsql=1",
		"demomode=$demomode",
		"sqluser=$sqluser",
		"style=foundation",
		"cryptpw=$specialcrypt",
		"alreadycrypt=1",
		"superuser=$superuser",
		"logdir=$logbase/$catname",
		"cachedir=$tmpbase/$catname",
		"sampdatatype=none",
		"--permtype=user",
		"--samplehtml=$docroot/$catname",
		"--imagedir=$docroot/$catname/images",
		"--imageurl=/$catname/images",
		"--linkmode=UNIX",
		"--sampleurl=http://$domain/$catname",
		"--catalogname=$catname",
	;
	if ($sqlpass) {
		push @args, "sqlpass=$sqlpass", "mysqlcreateopt='-u root -p'";
	} else {
		push @args, "mysqlcreateopt='-u root'";
	}

	my $command_line = join " ", @args;
	my $output = '';
	#open(BUILD, "$command_line 2>/tmp/catman.err.$$ |")
	open(BUILD, "$command_line 2>&1 |")
		or die "can't fork: $!\n";
	while(<BUILD>) {
		$output .= $_;
	}
	close BUILD;

	if($?) {
		my $stat = $? >> 8;
		$output =~ s/^\s+//; $output =~ s/\s+$//;
		HTML::Entities::encode_entities($output);
		$output =~ s/\n/<br>\n/g;
		$Scratch->{ui_failure} = <<EOT;
<p><b>Failed to build, status $stat</b></p>
<p><b>Command line was:</b></p>
<p>$command_line</p>
<p><b>Output was:</b></p>
<p>$output</p>
EOT
	}
	else {
		$Scratch->{ui_message} = $output;
		sleep $Global::HouseKeeping || 3;
		sleep $Global::HouseKeeping || 3;
		$Scratch->{restart} = 1;
	}

[/perl]

[if !scratch ui_failure]
	[if scratch restart]
	[set restart][/set]
	<XMP>
	[perl global=1]
		#my $out = `$Global::VendRoot/bin/restart`;
		my $out = `/usr/sbin/interchange -r`;
		#$Scratch->{bounce_out} = $out;
		$Scratch->{bounce_page} = '@@MV_PAGE@@';
		return;
	[/perl]
	</XMP>
	[/if]
[bounce href="http://[scratch go_url]/admin/wizard/index?give_help=1"]
[/if]

<p>You can [page index]start over</a> and hope things work out better next time.</p>

@_UI_STD_FOOTER_@

-- 
Mike Heins
Perusion -- Expert Interchange Consulting    http://www.perusion.com/
phone +1.513.523.7621      <mike@perusion.com>

Prove you aren't stupid.  Say NO to Passport.