UserDB: log timestamps to second granularity
[interchange.git] / code / UI_Tag / su.coretag
1 # Copyright 2002-2007 Interchange Development Group and others
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.  See the LICENSE file for details.
7
8 # $Id: su.coretag,v 1.8 2007-03-30 23:40:54 pajamian Exp $
9
10 UserTag su Description  Switch User Tag for catalog superuser
11 UserTag su Order        username
12 UserTag su attrAlias    user username
13 UserTag su addAttr
14 UserTag su Version      $Revision: 1.8 $
15 UserTag su Routine      <<EOR
16 sub {
17         my ($user, $opt) = @_;
18         use vars qw/$Session $Tag $ready_safe $Scratch/;
19
20         # Note: If adding any new %$opt keys, make sure to also add them to
21         # the list of options to be stripped before passing the remainder
22         # to tag userdb; search below for $new_user.
23
24         $opt->{profile} = 'ui'     if $opt->{admin} and ! $opt->{profile};
25
26         my $u;
27         if($opt->{profile}) {
28                 $u = $Vend::Cfg->{UserDB_repository}{$opt->{profile}};
29         }
30         else {
31                 $u = $Vend::Cfg->{UserDB};
32         }
33
34         if(! $u) {
35                 my $place = $opt->{profile} || 'default';
36                 ::logError("Can't find UserDB repository, profile '%s'", $place);
37                 return undef;
38         }
39         my $table  = $u->{database} || 'userdb';
40         my $ufield = $u->{user_field} || 'username';
41         my $going_to_admin = $u->{admin} || $opt->{admin};
42 #::logDebug("user table=$table ufield=$ufield");
43
44         if ($opt->{create_user}) {
45                 # these settings must be done before any access to the table
46                 $Vend::WriteDatabase{$table} = 1;
47         }
48
49         my $super  = $Tag->if_mm('super');
50         my $former = $Vend::username;
51
52         if($user and $going_to_admin and ! $super) {
53                 ::logError("attempt to su to admin user %s by non-super user %s",
54                                                 $user,
55                                                 $former,
56                                         );
57                 return undef;
58         }
59         elsif($user and ! $Vend::admin) {
60                 ::logError("attempt to su to user %s by non-admin user %s",
61                                                 $user,
62                                                 $former,
63                                         );
64                 return undef;
65         }
66
67         my $dir = "$Global::ConfDir/tmp";
68         if (! -d $dir) {
69                 if(-e $dir) {
70                         logGlobal("Global tmp directory exists as file, aborting su");
71                         return undef;
72                 }
73                 File::Path::mkpath($dir);
74         }
75
76         if($opt->{exit}) {
77                 if(! $Session->{su}) {
78                         logError("attempt to return to superuser without saved session.");
79                         return;
80                 }
81                 my $string = delete $Session->{su};
82                 my $key = $Tag->read_cookie({ name => 'MV_SU_KEY'})
83                         or do {
84                                 logError("no session key in cookie, cannot exit");
85                                 return;
86                         };
87                 my $fn = "$dir/$Session->{id}";
88                 open(MDCHECK, "< $fn")
89                         or do {
90                                 logError("no saved session key in %s, cannot exit", $fn);
91                                 return;
92                         };
93                 my $rand = <MDCHECK>;
94                 close MDCHECK;
95                 if(generate_key($rand . $string) ne $key) {
96                         logError("mismatched session key with saved session, cannot exit");
97                         return;
98                 }
99
100                 my $former = $Session->{username};
101                 ## Authenticated
102                 undef $Vend::Session;
103                 undef $Session;
104                 $Vend::Session = $ready_safe->reval($string);
105                 $Session = $Vend::Session;
106                 delete $Session->{su};
107                 $Vend::admin = $Vend::Session->{admin};
108                 $Vend::username = $Vend::Session->{username};
109                 $Tag->if_mm('logged_in')
110                         and logError(
111                                         "Admin user %s returned from login as %s",
112                                         $Session->{username},
113                                         $former,
114                                 )
115                         and return 1;
116                 return;
117         }
118         elsif ($user) {
119                 my $new_user;
120                 if(! $Tag->data($table, $ufield, $user) ) {
121                         if ($opt->{create_user}) {
122                                 $new_user = 1;
123                         }
124                         else {
125                                 $Scratch->{ui_error} = errmsg("attempt to su to non-existent user %s", $user);
126                                 return undef;
127                         }
128                 }
129
130                 my $rand        = random_string();
131                 my $sess        = uneval_it($Session);
132 #::logDebug("sess is $sess");
133                 my $sesskey     = generate_key($rand . $sess);
134
135                 open(MDIT, "> $dir/$Session->{id}")
136                         or die errmsg("Can't create check file for su: %s\n", $!);
137                 print MDIT $rand;
138                 close MDIT;
139                 $Tag->set_cookie( { name => 'MV_SU_KEY', value => $sesskey } );
140                 my $former = $Session->{username};
141
142                 undef $Vend::admin;
143                 undef $Vend::superuser;
144                 undef $Vend::UI_entry;
145
146                 Vend::Session::init_session();
147                 $Session = $Vend::Session;
148
149                 if ($new_user) {
150                         # pass on any non-su options to userdb tag
151                         my $newopt = { %$opt };
152                         delete @{$newopt}{qw( admin exit create_user )};
153                         $newopt->{username} = $user;
154                         my $result = $Tag->userdb('new_account', $newopt);
155                         unless ($result) {
156                                 my $error = errmsg("Failed to create new user '%s' in su tag", $user);
157                                 logError($error);
158                                 $Scratch->{ui_error} = $error;
159                                 return undef;
160                         }
161                         $Session->{su} = $sess;
162                 }
163                 else {
164                         $Vend::username = $Session->{username} = $user;
165                         $Vend::admin    = $Session->{admin}    = $going_to_admin;
166                         $Session->{logged_in} = 1;
167                         $Session->{su} = $sess;
168                         $Tag->userdb('load');
169                 }
170
171                 ## Reconnect session variables
172                 Vend::Interpolate::init_calc;
173
174                 my $dest = $Tag->if_mm('logged_in') ? 'admin user' : 'regular user';
175                 logError(
176                         "superuser %s switched user to %s %s",
177                         $former,
178                         $dest,
179                         $Session->{username},
180                         );
181                 return 1;
182         }
183         else {
184                 ::logError("unknown su operation: " . uneval_it($opt));
185                 return undef;
186         }
187 }
188 EOR