X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2FUID.pm;h=31c2887d3dbd7312048527273c2f7620394dc84c;hp=88d7338290fa59c732566aa26cf00b867b75e348;hb=9b37fb82c94a480ef6af2f7b9a8b889d4381e703;hpb=b4a403644cb80a612dd028882f971bdd20839275 diff --git a/FS/FS/UID.pm b/FS/FS/UID.pm index 88d733829..31c2887d3 100644 --- a/FS/FS/UID.pm +++ b/FS/FS/UID.pm @@ -2,24 +2,35 @@ package FS::UID; use strict; use vars qw( - @ISA @EXPORT_OK $cgi $dbh $freeside_uid $user - $conf_dir $secrets $datasrc $db_user $db_pass %callback $driver_name + @ISA @EXPORT_OK $DEBUG $me $cgi $freeside_uid $user $conf_dir $cache_dir + $secrets $datasrc $db_user $db_pass $schema $dbh $driver_name + $AutoCommit %callback @callback $callback_hack $use_confcompat ); use subs qw( getsecrets cgisetotaker ); use Exporter; -use Carp qw(carp croak cluck); +use Carp qw(carp croak cluck confess); use DBI; -use FS::Conf; +use IO::File; +use FS::CurrentUser; @ISA = qw(Exporter); -@EXPORT_OK = qw(checkeuid checkruid swapuid cgisuidsetup - adminsuidsetup getotaker dbh datasrc getsecrets driver_name ); +@EXPORT_OK = qw(checkeuid checkruid cgisuidsetup adminsuidsetup forksuidsetup + getotaker dbh datasrc getsecrets driver_name myconnect + use_confcompat); + +$DEBUG = 0; +$me = '[FS::UID]'; $freeside_uid = scalar(getpwnam('freeside')); -$conf_dir = "/usr/local/etc/freeside/"; +$conf_dir = "%%%FREESIDE_CONF%%%"; +$cache_dir = "%%%FREESIDE_CACHE%%%"; + +$AutoCommit = 1; #ours, not DBI +$use_confcompat = 1; +$callback_hack = 0; =head1 NAME @@ -28,7 +39,7 @@ FS::UID - Subroutines for database login and assorted other stuff =head1 SYNOPSIS use FS::UID qw(adminsuidsetup cgisuidsetup dbh datasrc getotaker - checkeuid checkruid swapuid); + checkeuid checkruid); adminsuidsetup $user; @@ -62,9 +73,23 @@ Returns the DBI database handle (usually you don't need this). =cut sub adminsuidsetup { + $dbh->disconnect if $dbh; + &forksuidsetup(@_); +} +sub forksuidsetup { $user = shift; - croak "fatal: adminsuidsetup called without arguements" unless $user; + my $olduser = $user; + warn "$me forksuidsetup starting for $user\n" if $DEBUG; + + if ( $FS::CurrentUser::upgrade_hack ) { + $user = 'fs_bootstrap'; + } else { + croak "fatal: adminsuidsetup called without arguements" unless $user; + + $user =~ /^([\w\-\.]+)$/ or croak "fatal: illegal user $user"; + $user = $1; + } $ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin'; $ENV{'SHELL'} = '/bin/sh'; @@ -73,22 +98,102 @@ sub adminsuidsetup { $ENV{'ENV'} = ''; $ENV{'BASH_ENV'} = ''; - croak "Not running uid freeside!" unless checkeuid(); - getsecrets; - $dbh = DBI->connect($datasrc,$db_user,$db_pass, { - 'AutoCommit' => 'true', - 'ChopBlanks' => 'true', - } ) or die "DBI->connect error: $DBI::errstr\n"; + croak "Not running uid freeside (\$>=$>, \$<=$<)\n" unless checkeuid(); - swapuid(); #go to non-privledged user if running setuid freeside + warn "$me forksuidsetup connecting to database\n" if $DEBUG; + if ( $FS::CurrentUser::upgrade_hack && $olduser ) { + $dbh = &myconnect($olduser); + } else { + $dbh = &myconnect(); + } + warn "$me forksuidsetup connected to database with handle $dbh\n" if $DEBUG; + + warn "$me forksuidsetup loading schema\n" if $DEBUG; + use FS::Schema qw(reload_dbdef dbdef); + reload_dbdef("$conf_dir/dbdef.$datasrc") + unless $FS::Schema::setup_hack; + + warn "$me forksuidsetup deciding upon config system to use\n" if $DEBUG; + + if ( ! $FS::Schema::setup_hack && dbdef->table('conf') ) { - foreach ( keys %callback ) { - &{$callback{$_}}; + my $sth = $dbh->prepare("SELECT COUNT(*) FROM conf") or die $dbh->errstr; + $sth->execute or die $sth->errstr; + my $confcount = $sth->fetchrow_arrayref->[0]; + + if ($confcount) { + $use_confcompat = 0; + }else{ + die "NO CONFIGURATION RECORDS FOUND"; + } + + } else { + die "NO CONFIGURATION TABLE FOUND" unless $FS::Schema::setup_hack; } + unless ( $callback_hack ) { + warn "$me calling callbacks\n" if $DEBUG; + foreach ( keys %callback ) { + &{$callback{$_}}; + # breaks multi-database installs # delete $callback{$_}; #run once + } + + &{$_} foreach @callback; + } else { + warn "$me skipping callbacks (callback_hack set)\n" if $DEBUG; + } + + warn "$me forksuidsetup loading user\n" if $DEBUG; + FS::CurrentUser->load_user($user); + $dbh; } +sub myconnect { + my $handle = DBI->connect( getsecrets(@_), { 'AutoCommit' => 0, + 'ChopBlanks' => 1, + 'ShowErrorStatement' => 1, + 'pg_enable_utf8' => 1, + #'mysql_enable_utf8' => 1, + } + ) + or die "DBI->connect error: $DBI::errstr\n"; + + if ( $schema ) { + use DBIx::DBSchema::_util qw(_load_driver ); #quelle hack + my $driver = _load_driver($handle); + if ( $driver =~ /^Pg/ ) { + no warnings 'redefine'; + eval "sub DBIx::DBSchema::DBD::${driver}::default_db_schema {'$schema'}"; + die $@ if $@; + } + } + + $handle; +} + +=item install_callback + +A package can install a callback to be run in adminsuidsetup by passing +a coderef to the FS::UID->install_callback class method. If adminsuidsetup has +run already, the callback will also be run immediately. + + $coderef = sub { warn "Hi, I'm returning your call!" }; + FS::UID->install_callback($coderef); + + install_callback FS::UID sub { + warn "Hi, I'm returning your call!" + }; + +=cut + +sub install_callback { + my $class = shift; + my $callback = shift; + push @callback, $callback; + &{$callback} if $dbh; +} + =item cgisuidsetup CGI_object Takes a single argument, which is a CGI (see L) or Apache (see L) @@ -182,7 +287,8 @@ sub cgisetotaker { } elsif ( $cgi && $cgi->isa('Apache') ) { $user = lc ( $cgi->connection->user ); } else { - die "fatal: Can't get REMOTE_USER! for cgi $cgi"; + die "fatal: Can't get REMOTE_USER! for cgi $cgi - you need to setup ". + "Apache user authentication as documented in httemplate/docs/install.html"; } $user; } @@ -194,6 +300,7 @@ Returns true if effective UID is that of the freeside user. =cut sub checkeuid { + #$> = $freeside_uid unless $>; #huh. mpm-itk hack ( $> == $freeside_uid ); } @@ -207,16 +314,6 @@ sub checkruid { ( $< == $freeside_uid ); } -=item swapuid - -Swaps real and effective UIDs. - -=cut - -sub swapuid { - ($<,$>) = ($>,$<) if $< != $>; -} - =item getsecrets [ USER ] Sets the user to USER, if supplied. @@ -228,35 +325,64 @@ the `/usr/local/etc/freeside/mapsecrets' file. sub getsecrets { my($setuser) = shift; $user = $setuser if $setuser; - die "No user!" unless $user; - my($conf) = new FS::Conf $conf_dir; - my($line) = grep /^\s*$user\s/, $conf->config('mapsecrets'); - die "User not found in mapsecrets!" unless $line; - $line =~ /^\s*$user\s+(.*)$/; - $secrets = $1; - die "Illegal mapsecrets line for user?!" unless $secrets; - ($datasrc, $db_user, $db_pass) = $conf->config($secrets) - or die "Can't get secrets: $!"; - $FS::Conf::default_dir = $conf_dir. "/conf.$datasrc"; + + if ( -e "$conf_dir/mapsecrets" ) { + die "No user!" unless $user; + my($line) = grep /^\s*($user|\*)\s/, + map { /^(.*)$/; $1 } readline(new IO::File "$conf_dir/mapsecrets"); + confess "User $user not found in mapsecrets!" unless $line; + $line =~ /^\s*($user|\*)\s+(.*)$/; + $secrets = $2; + die "Illegal mapsecrets line for user?!" unless $secrets; + } else { + # no mapsecrets file at all, so do the default thing + $secrets = 'secrets'; + } + + ($datasrc, $db_user, $db_pass, $schema) = + map { /^(.*)$/; $1 } readline(new IO::File "$conf_dir/$secrets") + or die "Can't get secrets: $conf_dir/$secrets: $!\n"; undef $driver_name; + ($datasrc, $db_user, $db_pass); } +=item use_confcompat + +Returns true whenever we should use 1.7 configuration compatibility. + +=cut + +sub use_confcompat { + $use_confcompat; +} + =back =head1 CALLBACKS -Warning: this interface is likely to change in future releases. +Warning: this interface is (still) likely to change in future releases. -A package can install a callback to be run in adminsuidsetup by putting a -coderef into the hash %FS::UID::callback : +New (experimental) callback interface: + +A package can install a callback to be run in adminsuidsetup by passing +a coderef to the FS::UID->install_callback class method. If adminsuidsetup has +run already, the callback will also be run immediately. $coderef = sub { warn "Hi, I'm returning your call!" }; - $FS::UID::callback{'Package::Name'}; + FS::UID->install_callback($coderef); -=head1 VERSION + install_callback FS::UID sub { + warn "Hi, I'm returning your call!" + }; -$Id: UID.pm,v 1.3 2000-06-23 12:25:59 ivan Exp $ +Old (deprecated) callback interface: + +A package can install a callback to be run in adminsuidsetup by putting a +coderef into the hash %FS::UID::callback : + + $coderef = sub { warn "Hi, I'm returning your call!" }; + $FS::UID::callback{'Package::Name'} = $coderef; =head1 BUGS @@ -269,7 +395,7 @@ cgisuidsetup will go away as well. Goes through contortions to support non-OO syntax with multiple datasrc's. -Callbacks are inelegant. +Callbacks are (still) inelegant. =head1 SEE ALSO