bugfix; $user is a global (yuck)
[freeside.git] / site_perl / UID.pm
1 package FS::UID;
2
3 use strict;
4 use vars qw(
5   @ISA @EXPORT_OK $cgi $dbh $freeside_uid $user 
6   $conf_dir $secrets $datasrc $db_user $db_pass %callback
7 );
8 use subs qw(
9   getsecrets cgisetotaker
10 );
11 use Exporter;
12 use Carp;
13 use DBI;
14 use FS::Conf;
15
16 @ISA = qw(Exporter);
17 @EXPORT_OK = qw(checkeuid checkruid swapuid cgisuidsetup
18                 adminsuidsetup getotaker dbh datasrc);
19
20 $freeside_uid = scalar(getpwnam('freeside'));
21
22 $conf_dir = "/usr/local/etc/freeside/";
23
24 =head1 NAME
25
26 FS::UID - Subroutines for database login and assorted other stuff
27
28 =head1 SYNOPSIS
29
30   use FS::UID qw(adminsuidsetup cgisuidsetup dbh datasrc getotaker
31   checkeuid checkruid swapuid);
32
33   adminsuidsetup $user;
34
35   $cgi = new CGI;
36   $dbh = cgisuidsetup($cgi);
37
38   $dbh = dbh;
39
40   $datasrc = datasrc;
41
42 =head1 DESCRIPTION
43
44 Provides a hodgepodge of subroutines. 
45
46 =head1 SUBROUTINES
47
48 =over 4
49
50 =item adminsuidsetup USER
51
52 Sets the user to USER (see config.html from the base documentation).
53 Cleans the environment.
54 Make sure the script is running as freeside, or setuid freeside.
55 Opens a connection to the database.
56 Swaps real and effective UIDs.
57 Runs any defined callbacks (see below).
58 Returns the DBI database handle (usually you don't need this).
59
60 =cut
61
62 sub adminsuidsetup {
63
64   $user = shift;
65   croak "fatal: adminsuidsetup called without arguements" unless $user;
66
67   $ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
68   $ENV{'SHELL'} = '/bin/sh';
69   $ENV{'IFS'} = " \t\n";
70   $ENV{'CDPATH'} = '';
71   $ENV{'ENV'} = '';
72   $ENV{'BASH_ENV'} = '';
73
74   croak "Not running uid freeside!" unless checkeuid();
75   getsecrets;
76   $dbh = DBI->connect($datasrc,$db_user,$db_pass, {
77                           'AutoCommit' => 'true',
78                           'ChopBlanks' => 'true',
79   } ) or die "DBI->connect error: $DBI::errstr\n";
80
81   swapuid(); #go to non-privledged user if running setuid freeside
82
83   foreach ( keys %callback ) {
84     &{$callback{$_}};
85   }
86
87   $dbh;
88 }
89
90 =item cgisuidsetup CGI_object
91
92 Stores the CGI (see L<CGI>) object for later use. (CGI::Base is depriciated)
93 Runs adminsuidsetup.
94
95 =cut
96
97 sub cgisuidsetup {
98   $cgi=shift;
99   if ( $cgi->isa('CGI::Base') ) {
100     carp "Use of CGI::Base is depriciated";
101   } elsif ( ! $cgi->isa('CGI') ) {
102     croak "Pass a CGI object to cgisuidsetup!";
103   }
104   cgisetotaker; 
105   adminsuidsetup($user);
106 }
107
108 =item cgi
109
110 Returns the CGI (see L<CGI>) object.
111
112 =cut
113
114 sub cgi {
115   $cgi;
116 }
117
118 =item dbh
119
120 Returns the DBI database handle.
121
122 =cut
123
124 sub dbh {
125   $dbh;
126 }
127
128 =item datasrc
129
130 Returns the DBI data source.
131
132 =cut
133
134 sub datasrc {
135   $datasrc;
136 }
137
138 #hack for web demo
139 #sub setdbh {
140 #  $dbh=$_[0];
141 #}
142
143 sub suidsetup {
144   croak "suidsetup depriciated";
145 }
146
147 =item getotaker
148
149 Returns the current Freeside user.
150
151 =cut
152
153 sub getotaker {
154   $user;
155 }
156
157 =item cgisetotaker
158
159 Sets and returns the CGI REMOTE_USER.  $cgi should be defined as a CGI.pm
160 object.  Support for CGI::Base and derived classes is depriciated.
161
162 =cut
163
164 sub cgisetotaker {
165   if ( $cgi && $cgi->isa('CGI::Base') && defined $cgi->var('REMOTE_USER')) {
166     carp "Use of CGI::Base is depriciated";
167     $user = lc ( $cgi->var('REMOTE_USER') );
168   } elsif ( $cgi && $cgi->isa('CGI') && defined $cgi->remote_user ) {
169     $user = lc ( $cgi->remote_user );
170   } else {
171     die "fatal: Can't get REMOTE_USER!";
172   }
173   $user;
174 }
175
176 =item checkeuid
177
178 Returns true if effective UID is that of the freeside user.
179
180 =cut
181
182 sub checkeuid {
183   ( $> == $freeside_uid );
184 }
185
186 =item checkruid
187
188 Returns true if the real UID is that of the freeside user.
189
190 =cut
191
192 sub checkruid {
193   ( $< == $freeside_uid );
194 }
195
196 =item swapuid
197
198 Swaps real and effective UIDs.
199
200 =cut
201
202 sub swapuid {
203   ($<,$>) = ($>,$<) if $< != $>;
204 }
205
206 =item getsecrets [ USER ]
207
208 Sets the user to USER, if supplied.
209 Sets and returns the DBI datasource, username and password for this user from
210 the `/usr/local/etc/freeside/mapsecrets' file.
211
212 =cut
213
214 sub getsecrets {
215   my($setuser) = shift;
216   $user = $setuser if $setuser;
217   die "No user!" unless $user;
218   my($conf) = new FS::Conf $conf_dir;
219   my($line) = grep /^\s*$user\s/, $conf->config('mapsecrets');
220   die "User not found in mapsecrets!" unless $line;
221   $line =~ /^\s*$user\s+(.*)$/;
222   $secrets = $1;
223   die "Illegal mapsecrets line for user?!" unless $secrets;
224   ($datasrc, $db_user, $db_pass) = $conf->config($secrets)
225     or die "Can't get secrets: $!";
226   $FS::Conf::default_dir = $conf_dir. "/conf.$datasrc";
227   ($datasrc, $db_user, $db_pass);
228 }
229
230 =back
231
232 =head1 CALLBACKS
233
234 Warning: this interface is likely to change in future releases.
235
236 A package can install a callback to be run in adminsuidsetup by putting a
237 coderef into the hash %FS::UID::callback :
238
239     $coderef = sub { warn "Hi, I'm returning your call!" };
240     $FS::UID::callback{'Package::Name'};
241
242 =head1 VERSION
243
244 $Id: UID.pm,v 1.10 1999-04-12 22:41:09 ivan Exp $
245
246 =head1 BUGS
247
248 Too many package-global variables.
249
250 Not OO.
251
252 No capabilities yet.  When mod_perl and Authen::DBI are implemented, 
253 cgisuidsetup will go away as well.
254
255 Goes through contortions to support non-OO syntax with multiple datasrc's.
256
257 Callbacks are inelegant.
258
259 =head1 SEE ALSO
260
261 L<FS::Record>, L<CGI>, L<DBI>, config.html from the base documentation.
262
263 =head1 HISTORY
264
265 ivan@voicenet.com 97-jun-4 - 9
266  
267 untaint otaker ivan@voicenet.com 97-jul-7
268
269 generalize and auto-get uid (getotaker still needs to be db'ed)
270 ivan@sisd.com 97-nov-10
271
272 &cgisuidsetup logs into database.  other cleaning.
273 ivan@sisd.com 97-nov-22,23
274
275 &adminsuidsetup logs into database with otaker='freeside' (for
276 automated tasks like billing)
277 ivan@sisd.com 97-dec-13
278
279 added sub datasrc for fs-setup ivan@sisd.com 98-feb-21
280
281 datasrc, user and pass now come from conf/secrets ivan@sisd.com 98-jun-28
282
283 added ChopBlanks to DBI call (see man DBI) ivan@sisd.com 98-aug-16
284
285 pod, use FS::Conf, implemented cgisuidsetup as adminsuidsetup,
286 inlined suidsetup
287 ivan@sisd.com 98-sep-12
288
289 $Log: UID.pm,v $
290 Revision 1.10  1999-04-12 22:41:09  ivan
291 bugfix; $user is a global (yuck)
292
293 Revision 1.9  1999/04/12 21:09:39  ivan
294 force username to lowercase
295
296 Revision 1.8  1999/02/23 07:23:23  ivan
297 oops, don't comment out &swapuid in &adminsuidsetup!
298
299 Revision 1.7  1999/01/18 09:22:40  ivan
300 changes to track email addresses for email invoicing
301
302 Revision 1.6  1998/11/15 05:27:48  ivan
303 bugfix for new configuration layout
304
305 Revision 1.5  1998/11/15 00:51:51  ivan
306 eliminated some warnings on certain fatal errors (well, it is less confusing)
307
308 Revision 1.4  1998/11/13 09:56:52  ivan
309 change configuration file layout to support multiple distinct databases (with
310 own set of config files, export, etc.)
311
312 Revision 1.3  1998/11/08 10:45:42  ivan
313 got sub cgi for FS::CGI
314
315 Revision 1.2  1998/11/08 09:38:43  ivan
316 cgisuidsetup complains if you pass it a isa CGI::Base instead of an isa CGI
317 (first step in migrating from CGI-modules to CGI.pm)
318
319
320 =cut
321
322 1;
323