adding support for js includes
[koha.git] / C4 / Auth.pm
1 # -*- tab-width: 8 -*-
2 # NOTE: This file uses 8-character tabs; do not change the tab size!
3
4 package C4::Auth;
5
6 # Copyright 2000-2002 Katipo Communications
7 #
8 # This file is part of Koha.
9 #
10 # Koha is free software; you can redistribute it and/or modify it under the
11 # terms of the GNU General Public License as published by the Free Software
12 # Foundation; either version 2 of the License, or (at your option) any later
13 # version.
14 #
15 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
16 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License along with
20 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
21 # Suite 330, Boston, MA  02111-1307 USA
22
23 use strict;
24 use Digest::MD5 qw(md5_base64);
25 use CGI::Session;
26
27
28 require Exporter;
29 use C4::Context;
30 use C4::Output;    # to get the template
31 use C4::Members;
32 use C4::Koha;
33 use C4::Branch; # GetBranches
34
35 # use Net::LDAP;
36 # use Net::LDAP qw(:all);
37
38 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
39
40 # set the version for version checking
41 $VERSION = do { my @v = '$Revision$' =~ /\d+/g;
42     shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v );
43 };
44
45 =head1 NAME
46
47 C4::Auth - Authenticates Koha users
48
49 =head1 SYNOPSIS
50
51   use CGI;
52   use C4::Auth;
53
54   my $query = new CGI;
55
56   my ($template, $borrowernumber, $cookie) 
57     = get_template_and_user(
58         {
59             template_name   => "opac-main.tmpl",
60             query           => $query,
61             type            => "opac",
62             authnotrequired => 1,
63             flagsrequired   => {borrow => 1},
64         }
65     );
66
67   print $query->header(
68     -type => 'utf-8',
69     -cookie => $cookie
70   ), $template->output;
71
72
73 =head1 DESCRIPTION
74
75     The main function of this module is to provide
76     authentification. However the get_template_and_user function has
77     been provided so that a users login information is passed along
78     automatically. This gets loaded into the template.
79
80 =head1 FUNCTIONS
81
82 =over 2
83
84 =cut
85
86 @ISA    = qw(Exporter);
87 @EXPORT = qw(
88   &checkauth
89   &get_template_and_user
90 );
91
92 =item get_template_and_user
93
94   my ($template, $borrowernumber, $cookie)
95     = get_template_and_user(
96         {
97            template_name   => "opac-main.tmpl",
98            query           => $query,
99            type            => "opac",
100            authnotrequired => 1,
101            flagsrequired   => {borrow => 1},
102         }
103     );
104
105     This call passes the C<query>, C<flagsrequired> and C<authnotrequired>
106     to C<&checkauth> (in this module) to perform authentification.
107     See C<&checkauth> for an explanation of these parameters.
108
109     The C<template_name> is then used to find the correct template for
110     the page. The authenticated users details are loaded onto the
111     template in the HTML::Template LOOP variable C<USER_INFO>. Also the
112     C<sessionID> is passed to the template. This can be used in templates
113     if cookies are disabled. It needs to be put as and input to every
114     authenticated page.
115
116     More information on the C<gettemplate> sub can be found in the
117     Output.pm module.
118
119 =cut
120
121 sub get_template_and_user {
122     my $in       = shift;
123     my $template =
124       gettemplate( $in->{'template_name'}, $in->{'type'}, $in->{'query'} );
125     my ( $user, $cookie, $sessionID, $flags ) = checkauth(
126         $in->{'query'},
127         $in->{'authnotrequired'},
128         $in->{'flagsrequired'},
129         $in->{'type'}
130     ) unless ($in->{'template_name'}=~/maintenance/);
131
132     my $borrowernumber;
133     my $insecure = C4::Context->preference('insecure');
134     if ($user or $insecure) {
135
136                 # load the template variables for stylesheets and JavaScript
137                 $template->param( css_libs => $in->{'css_libs'} );
138                 $template->param( css_module => $in->{'css_module'} );
139                 $template->param( css_page => $in->{'css_page'} );
140                 $template->param( css_widgets => $in->{'css_widgets'} );
141
142         $template->param( js_libs => $in->{'js_libs'} );
143         $template->param( js_module => $in->{'js_module'} );
144         $template->param( js_page => $in->{'js_page'} );
145         $template->param( js_widgets => $in->{'js_widgets'} );
146                 $template->param( js_includes => $in->{'js_includes'} );
147
148                 # user info
149         $template->param( loggedinusername => $user );
150         $template->param( sessionID        => $sessionID );
151
152         $borrowernumber = getborrowernumber($user);
153         my ( $borr, $alternativeflags ) =
154           GetMemberDetails( $borrowernumber );
155         my @bordat;
156         $bordat[0] = $borr;
157         $template->param( "USER_INFO" => \@bordat );
158
159         # We are going to use the $flags returned by checkauth
160         # to create the template's parameters that will indicate
161         # which menus the user can access.
162         if (( $flags && $flags->{superlibrarian}==1) or $insecure==1) {
163             $template->param( CAN_user_circulate        => 1 );
164             $template->param( CAN_user_catalogue        => 1 );
165             $template->param( CAN_user_parameters       => 1 );
166             $template->param( CAN_user_borrowers        => 1 );
167             $template->param( CAN_user_permission       => 1 );
168             $template->param( CAN_user_reserveforothers => 1 );
169             $template->param( CAN_user_borrow           => 1 );
170             $template->param( CAN_user_editcatalogue    => 1 );
171             $template->param( CAN_user_updatecharge     => 1 );
172             $template->param( CAN_user_acquisition      => 1 );
173             $template->param( CAN_user_management       => 1 );
174             $template->param( CAN_user_tools            => 1 ); 
175             $template->param( CAN_user_editauthorities  => 1 );
176             $template->param( CAN_user_serials          => 1 );
177             $template->param( CAN_user_reports          => 1 );
178         }
179
180         if ( $flags && $flags->{circulate} == 1 ) {
181             $template->param( CAN_user_circulate => 1 );
182         }
183
184         if ( $flags && $flags->{catalogue} == 1 ) {
185             $template->param( CAN_user_catalogue => 1 );
186         }
187
188         if ( $flags && $flags->{parameters} == 1 ) {
189             $template->param( CAN_user_parameters => 1 );
190             $template->param( CAN_user_management => 1 );
191         }
192
193         if ( $flags && $flags->{borrowers} == 1 ) {
194             $template->param( CAN_user_borrowers => 1 );
195         }
196
197         if ( $flags && $flags->{permissions} == 1 ) {
198             $template->param( CAN_user_permission => 1 );
199         }
200
201         if ( $flags && $flags->{reserveforothers} == 1 ) {
202             $template->param( CAN_user_reserveforothers => 1 );
203         }
204
205         if ( $flags && $flags->{borrow} == 1 ) {
206             $template->param( CAN_user_borrow => 1 );
207         }
208
209         if ( $flags && $flags->{editcatalogue} == 1 ) {
210             $template->param( CAN_user_editcatalogue => 1 );
211         }
212
213         if ( $flags && $flags->{updatecharges} == 1 ) {
214             $template->param( CAN_user_updatecharge => 1 );
215         }
216
217         if ( $flags && $flags->{acquisition} == 1 ) {
218             $template->param( CAN_user_acquisition => 1 );
219         }
220
221         if ( $flags && $flags->{tools} == 1 ) {
222             $template->param( CAN_user_tools => 1 );
223         }
224         
225         if ( $flags && $flags->{editauthorities} == 1 ) {
226             $template->param( CAN_user_editauthorities => 1 );
227         }
228                 
229         if ( $flags && $flags->{serials} == 1 ) {
230             $template->param( CAN_user_serials => 1 );
231         }
232
233         if ( $flags && $flags->{reports} == 1 ) {
234             $template->param( CAN_user_reports => 1 );
235         }
236     }
237     if ( $in->{'type'} eq "intranet" ) {
238         $template->param(
239             intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
240             intranetstylesheet => C4::Context->preference("intranetstylesheet"),
241             IntranetNav        => C4::Context->preference("IntranetNav"),
242             intranetuserjs     => C4::Context->preference("intranetuserjs"),
243             TemplateEncoding   => C4::Context->preference("TemplateEncoding"),
244             AmazonContent      => C4::Context->preference("AmazonContent"),
245             LibraryName        => C4::Context->preference("LibraryName"),
246             LoginBranchcode    => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
247             LoginBranchname    => (C4::Context->userenv?C4::Context->userenv->{"branchname"}:"insecure"),
248             AutoLocation       => C4::Context->preference("AutoLocation"),
249             hide_marc          => C4::Context->preference("hide_marc"),
250             patronimages       => C4::Context->preference("patronimages"),
251             "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
252             advancedMARCEditor      => C4::Context->preference("advancedMARCEditor"),
253             suggestion              => C4::Context->preference("suggestion"),
254             virtualshelves          => C4::Context->preference("virtualshelves"),
255             LibraryName             => C4::Context->preference("LibraryName"),
256             KohaAdminEmailAddress   => "" . C4::Context->preference("KohaAdminEmailAddress"),
257         );
258     }
259     else {
260         warn "template type should be OPAC, here it is=[" . $in->{'type'} . "]"
261           unless ( $in->{'type'} eq 'opac' );
262         my $LibraryNameTitle = C4::Context->preference("LibraryName");
263         $LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi;
264         $LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg;
265         $template->param(
266             KohaAdminEmailAddress  => "" . C4::Context->preference("KohaAdminEmailAddress"),
267             suggestion             => "" . C4::Context->preference("suggestion"),
268             virtualshelves         => "" . C4::Context->preference("virtualshelves"),
269             OpacNav                => "" . C4::Context->preference("OpacNav"),
270             opacheader             => "" . C4::Context->preference("opacheader"),
271             opaccredits            => "" . C4::Context->preference("opaccredits"),
272             opacsmallimage         => "" . C4::Context->preference("opacsmallimage"),
273             opaclargeimage         => "" . C4::Context->preference("opaclargeimage"),
274             opaclayoutstylesheet   => "". C4::Context->preference("opaclayoutstylesheet"),
275             opaccolorstylesheet    => "". C4::Context->preference("opaccolorstylesheet"),
276             opaclanguagesdisplay   => "". C4::Context->preference("opaclanguagesdisplay"),
277             opacuserlogin          => "" . C4::Context->preference("opacuserlogin"),
278             opacbookbag            => "" . C4::Context->preference("opacbookbag"),
279             TemplateEncoding       => "". C4::Context->preference("TemplateEncoding"),
280             AmazonContent          => "" . C4::Context->preference("AmazonContent"),
281             LibraryName            => "" . C4::Context->preference("LibraryName"),
282             LibraryNameTitle       => "" . $LibraryNameTitle,
283             LoginBranchcode        => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
284             LoginBranchname        => C4::Context->userenv?C4::Context->userenv->{"branchname"}:"", 
285             OpacPasswordChange     => C4::Context->preference("OpacPasswordChange"),
286             opacreadinghistory     => C4::Context->preference("opacreadinghistory"),
287             opacuserjs             => C4::Context->preference("opacuserjs"),
288             OpacCloud              => C4::Context->preference("OpacCloud"),
289             OpacTopissue           => C4::Context->preference("OpacTopissue"),
290             OpacAuthorities        => C4::Context->preference("OpacAuthorities"),
291             OpacBrowser            => C4::Context->preference("OpacBrowser"),
292             RequestOnOpac          => C4::Context->preference("RequestOnOpac"),
293             reviewson              => C4::Context->preference("reviewson"),
294             hide_marc              => C4::Context->preference("hide_marc"),
295             patronimages           => C4::Context->preference("patronimages"),
296             "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
297         );
298     }
299     return ( $template, $borrowernumber, $cookie );
300 }
301
302 =item checkauth
303
304   ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
305
306 Verifies that the user is authorized to run this script.  If
307 the user is authorized, a (userid, cookie, session-id, flags)
308 quadruple is returned.  If the user is not authorized but does
309 not have the required privilege (see $flagsrequired below), it
310 displays an error page and exits.  Otherwise, it displays the
311 login page and exits.
312
313 Note that C<&checkauth> will return if and only if the user
314 is authorized, so it should be called early on, before any
315 unfinished operations (e.g., if you've opened a file, then
316 C<&checkauth> won't close it for you).
317
318 C<$query> is the CGI object for the script calling C<&checkauth>.
319
320 The C<$noauth> argument is optional. If it is set, then no
321 authorization is required for the script.
322
323 C<&checkauth> fetches user and session information from C<$query> and
324 ensures that the user is authorized to run scripts that require
325 authorization.
326
327 The C<$flagsrequired> argument specifies the required privileges
328 the user must have if the username and password are correct.
329 It should be specified as a reference-to-hash; keys in the hash
330 should be the "flags" for the user, as specified in the Members
331 intranet module. Any key specified must correspond to a "flag"
332 in the userflags table. E.g., { circulate => 1 } would specify
333 that the user must have the "circulate" privilege in order to
334 proceed. To make sure that access control is correct, the
335 C<$flagsrequired> parameter must be specified correctly.
336
337 The C<$type> argument specifies whether the template should be
338 retrieved from the opac or intranet directory tree.  "opac" is
339 assumed if it is not specified; however, if C<$type> is specified,
340 "intranet" is assumed if it is not "opac".
341
342 If C<$query> does not have a valid session ID associated with it
343 (i.e., the user has not logged in) or if the session has expired,
344 C<&checkauth> presents the user with a login page (from the point of
345 view of the original script, C<&checkauth> does not return). Once the
346 user has authenticated, C<&checkauth> restarts the original script
347 (this time, C<&checkauth> returns).
348
349 The login page is provided using a HTML::Template, which is set in the
350 systempreferences table or at the top of this file. The variable C<$type>
351 selects which template to use, either the opac or the intranet 
352 authentification template.
353
354 C<&checkauth> returns a user ID, a cookie, and a session ID. The
355 cookie should be sent back to the browser; it verifies that the user
356 has authenticated.
357
358 =cut
359
360 sub checkauth {
361     my $query = shift;
362         # warn "Checking Auth";
363     # $authnotrequired will be set for scripts which will run without authentication
364     my $authnotrequired = shift;
365     my $flagsrequired   = shift;
366     my $type            = shift;
367     $type = 'opac' unless $type;
368
369     my $dbh     = C4::Context->dbh;
370     my $timeout = C4::Context->preference('timeout');
371     $timeout = 600 unless $timeout;
372
373     # state variables
374     my $loggedin = 0;
375     my %info;
376     my ( $userid, $cookie, $sessionID, $flags );
377     my $logout = $query->param('logout.x');
378     if ( $userid = $ENV{'REMOTE_USER'} ) {
379         # Using Basic Authentication, no cookies required
380         $cookie = $query->cookie(
381             -name    => 'CGISESSID',
382             -value   => '',
383             -expires => ''
384         );
385         $loggedin = 1;
386     }
387     elsif ( $sessionID = $query->cookie("CGISESSID")) {
388         my $session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
389         C4::Context->_new_userenv($sessionID);
390         if ($session){
391             C4::Context::set_userenv(
392                 $session->param('number'),       $session->param('id'),
393                 $session->param('cardnumber'),   $session->param('firstname'),
394                 $session->param('surname'),      $session->param('branch'),
395                 $session->param('branchname'),   $session->param('flags'),
396                 $session->param('emailaddress'), $session->param('branchprinter')
397             );
398         }
399         my $ip;
400                 my $lasttime;
401                 if ($session) {
402                         $ip = $session->param('ip');
403                         $lasttime = $session->param('lasttime');
404             $userid = $session->param('id');
405                 }
406         
407                 
408         if ($logout) {
409
410             # voluntary logout the user
411             $session->delete;
412             C4::Context->_unset_userenv($sessionID);
413             $sessionID = undef;
414             $userid    = undef;
415             open L, ">>/tmp/sessionlog";
416             my $time = localtime( time() );
417             printf L "%20s from %16s logged out at %30s (manually).\n", $userid,
418               $ip, $time;
419             close L;
420         }
421         if ($userid) {
422             if ( $lasttime < time() - $timeout ) {
423                 # timed logout
424                 $info{'timed_out'} = 1;
425                 $session->delete();
426                 C4::Context->_unset_userenv($sessionID);
427                 $userid    = undef;
428                 $sessionID = undef;
429                 open L, ">>/tmp/sessionlog";
430                 my $time = localtime( time() );
431                 printf L "%20s from %16s logged out at %30s (inactivity).\n",
432                   $userid, $ip, $time;
433                 close L;
434             }
435             elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
436                 # Different ip than originally logged in from
437                 $info{'oldip'}        = $ip;
438                 $info{'newip'}        = $ENV{'REMOTE_ADDR'};
439                 $info{'different_ip'} = 1;
440                                 $session->delete();
441                 C4::Context->_unset_userenv($sessionID);
442                 $sessionID = undef;
443                 $userid    = undef;
444                 open L, ">>/tmp/sessionlog";
445                 my $time = localtime( time() );
446                 printf L
447 "%20s from logged out at %30s (ip changed from %16s to %16s).\n",
448                   $userid, $time, $ip, $info{'newip'};
449                 close L;
450             }
451             else {
452                 $cookie = $query->cookie( CGISESSID => $session->id );
453                 $session->param('lasttime',time());
454                 $flags = haspermission( $dbh, $userid, $flagsrequired );
455                 if ($flags) {
456                     $loggedin = 1;
457                 }
458                 else {
459                     $info{'nopermission'} = 1;
460                 }
461             }
462         }
463     }
464     unless ($userid) {
465         my $session = new CGI::Session("driver:MySQL", undef, {Handle=>$dbh});          
466         my $sessionID;
467                 if ($session) {
468                         $sessionID = $session->id;
469                         }
470         $userid    = $query->param('userid');
471         C4::Context->_new_userenv($sessionID);
472         my $password = $query->param('password');
473         C4::Context->_new_userenv($sessionID);
474         my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
475         if ($return) {
476             open L, ">>/tmp/sessionlog";
477             my $time = localtime( time() );
478             printf L "%20s from %16s logged in  at %30s.\n", $userid,
479               $ENV{'REMOTE_ADDR'}, $time;
480             close L;
481             $cookie = $query->cookie(CGISESSID => $sessionID);
482             if ( $flags = haspermission( $dbh, $userid, $flagsrequired ) ) {
483                 $loggedin = 1;
484             }
485             else {
486                 $info{'nopermission'} = 1;
487                 C4::Context->_unset_userenv($sessionID);
488             }
489             if ( $return == 1 ) {
490                 my (
491                     $borrowernumber, $firstname,  $surname,
492                     $userflags,      $branchcode, $branchname,
493                     $branchprinter,  $emailaddress
494                 );
495                 my $sth =
496                   $dbh->prepare(
497 "select borrowernumber, firstname, surname, flags, borrowers.branchcode, branches.branchname as branchname,branches.branchprinter as branchprinter, email from borrowers left join branches on borrowers.branchcode=branches.branchcode where userid=?"
498                   );
499                 $sth->execute($userid);
500                 (
501                     $borrowernumber, $firstname,  $surname,
502                     $userflags,      $branchcode, $branchname,
503                     $branchprinter,  $emailaddress
504                   )
505                   = $sth->fetchrow
506                   if ( $sth->rows );
507
508 #                               warn "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
509                 unless ( $sth->rows ) {
510                     my $sth =
511                       $dbh->prepare(
512 "select borrowernumber, firstname, surname, flags, borrowers.branchcode, branches.branchname as branchname, branches.branchprinter as branchprinter, email from borrowers left join branches on borrowers.branchcode=branches.branchcode where cardnumber=?"
513                       );
514                     $sth->execute($cardnumber);
515                     (
516                         $borrowernumber, $firstname,  $surname,
517                         $userflags,      $branchcode, $branchname,
518                         $branchprinter,  $emailaddress
519                       )
520                       = $sth->fetchrow
521                       if ( $sth->rows );
522
523 #                                       warn "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
524                     unless ( $sth->rows ) {
525                         $sth->execute($userid);
526                         (
527                             $borrowernumber, $firstname, $surname, $userflags,
528                             $branchcode, $branchname, $branchprinter, $emailaddress
529                           )
530                           = $sth->fetchrow
531                           if ( $sth->rows );
532                     }
533                 }
534
535 # launch a sequence to check if we have a ip for the branch, if we have one we replace the branchcode of the userenv by the branch bound in the ip.
536                 my $ip       = $ENV{'REMOTE_ADDR'};
537                 # if they specify at login, use that
538                 if ($query->param('branch')) {
539                     $branchcode  = $query->param('branch');
540                     $branchname = GetBranchName($branchcode);
541                 }
542                 my $branches = GetBranches();
543                 my @branchesloop;
544                 foreach my $br ( keys %$branches ) {
545                     #           now we work with the treatment of ip
546                     my $domain = $branches->{$br}->{'branchip'};
547                     if ( $domain && $ip =~ /^$domain/ ) {
548                         $branchcode = $branches->{$br}->{'branchcode'};
549
550                         # new op dev : add the branchprinter and branchname in the cookie
551                         $branchprinter = $branches->{$br}->{'branchprinter'};
552                         $branchname    = $branches->{$br}->{'branchname'};
553                     }
554                 }
555                 $session->param('number',$borrowernumber);
556                 $session->param('id',$userid);
557                 $session->param('cardnumber',$cardnumber);
558                 $session->param('firstname',$firstname);
559                 $session->param('surname',$surname);
560                 $session->param('branch',$branchcode);
561                 $session->param('branchname',$branchname);
562                 $session->param('flags',$userflags);
563                 $session->param('emailaddress',$emailaddress);
564                 $session->param('ip',$session->remote_addr());
565                 $session->param('lasttime',time());
566             }
567             elsif ( $return == 2 ) {
568                 #We suppose the user is the superlibrarian
569                         $session->param('number',0);
570                         $session->param('id',C4::Context->config('user'));
571                         $session->param('cardnumber',C4::Context->config('user'));
572                         $session->param('firstname',C4::Context->config('user'));
573                         $session->param('surname',C4::Context->config('user'),);
574                         $session->param('branch','NO_LIBRARY_SET');
575                         $session->param('branchname','NO_LIBRARY_SET');
576                         $session->param('flags',1);
577                         $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
578                         $session->param('ip',$session->remote_addr());
579                         $session->param('lasttime',time());
580                 }
581                 if ($session){
582                     C4::Context::set_userenv(
583                         $session->param('number'),       $session->param('id'),
584                         $session->param('cardnumber'),   $session->param('firstname'),
585                         $session->param('surname'),      $session->param('branch'),
586                         $session->param('branchname'),   $session->param('flags'),
587                         $session->param('emailaddress'), $session->param('branchprinter')
588                     );
589                 }
590         }
591
592         else {
593             if ($userid) {
594                 $info{'invalid_username_or_password'} = 1;
595                 C4::Context->_unset_userenv($sessionID);
596             }
597         }
598     }
599     my $insecure = C4::Context->boolean_preference('insecure');
600
601     # finished authentification, now respond
602     if ( $loggedin || $authnotrequired || ( defined($insecure) && $insecure ) )
603     {
604         # successful login
605         unless ($cookie) {
606             $cookie = $query->cookie( CGISESSID => ''
607             );
608         }
609                 return ( $userid, $cookie, $sessionID, $flags );
610
611     }
612
613 #
614 #
615 # AUTH rejected, show the login/password template, after checking the DB.
616 #
617 #
618     
619     # get the inputs from the incoming query
620     my @inputs = ();
621     foreach my $name ( param $query) {
622         (next) if ( $name eq 'userid' || $name eq 'password' );
623         my $value = $query->param($name);
624         push @inputs, { name => $name, value => $value };
625     }
626     # get the branchloop, which we need for authentication
627     my $branches = GetBranches();
628     my @branch_loop;
629     for my $branch_hash (keys %$branches) {
630                 push @branch_loop, {branchcode => "$branch_hash", branchname => $branches->{$branch_hash}->{'branchname'}, };
631     }
632
633     # check that database and koha version are the same
634     # there is no DB version, it's a fresh install,
635     # go to web installer
636         warn "about to check version";
637     unless (C4::Context->preference('Version')){
638       if ($type ne 'opac'){
639         warn "Install required, redirecting to Installer";
640         print $query->redirect("/cgi-bin/koha/installer/install.pl");
641       } else {
642         warn "OPAC Install required, redirecting to maintenance";
643         print $query->redirect("/cgi-bin/koha/maintenance.pl");
644       }       
645       exit;
646     }
647     # there is a DB version, compare it to the code version
648     my $kohaversion=C4::Context::KOHAVERSION;
649     # remove the 3 last . to have a Perl number
650     $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
651 #     warn "kohaversion : $kohaversion";
652     if (C4::Context->preference('Version') < $kohaversion){
653       if ($type ne 'opac'){
654       warn "Database update needed, redirecting to Installer. Database is ".C4::Context->preference('Version')." and Koha is : ".C4::Context->config("kohaversion");
655         print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3");
656       } else {
657       warn "OPAC :Database update needed, redirecting to maintenance. Database is ".C4::Context->preference('Version')." and Koha is : ".C4::Context->config("kohaversion");
658         print $query->redirect("/cgi-bin/koha/maintenance.pl");
659       }       
660       exit;
661     }
662     my $template_name;
663     if ( $type eq 'opac' ) {
664         $template_name = "opac-auth.tmpl";
665     }
666     else {
667         $template_name = "auth.tmpl";
668     }
669     my $template = gettemplate( $template_name, $type, $query );
670     $template->param(branchloop => \@branch_loop,);
671     $template->param(
672                 login                            => 1,
673         INPUTS               => \@inputs,
674         suggestion           => C4::Context->preference("suggestion"),
675         virtualshelves       => C4::Context->preference("virtualshelves"),
676         opaclargeimage       => C4::Context->preference("opaclargeimage"),
677         LibraryName          => C4::Context->preference("LibraryName"),
678         OpacNav              => C4::Context->preference("OpacNav"),
679         opaccredits          => C4::Context->preference("opaccredits"),
680         opacreadinghistory   => C4::Context->preference("opacreadinghistory"),
681         opacsmallimage       => C4::Context->preference("opacsmallimage"),
682         opaclayoutstylesheet => C4::Context->preference("opaclayoutstylesheet"),
683         opaccolorstylesheet  => C4::Context->preference("opaccolorstylesheet"),
684         opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
685         opacuserjs           => C4::Context->preference("opacuserjs"),
686
687         intranetcolorstylesheet =>
688           C4::Context->preference("intranetcolorstylesheet"),
689         intranetstylesheet => C4::Context->preference("intranetstylesheet"),
690         IntranetNav        => C4::Context->preference("IntranetNav"),
691         intranetuserjs     => C4::Context->preference("intranetuserjs"),
692         TemplateEncoding   => C4::Context->preference("TemplateEncoding"),
693
694     );
695     $template->param( loginprompt => 1 ) unless $info{'nopermission'};
696
697     my $self_url = $query->url( -absolute => 1 );
698     $template->param(
699         url         => $self_url,
700         LibraryName => => C4::Context->preference("LibraryName"),
701     );
702     $template->param( \%info );
703 #    $cookie = $query->cookie(CGISESSID => $session->id
704 #   );
705     print $query->header(
706         -type   => 'utf-8',
707         -cookie => $cookie
708       ),
709       $template->output;
710     exit;
711 }
712
713 sub checkpw {
714
715     my ( $dbh, $userid, $password ) = @_;
716
717     # INTERNAL AUTH
718     my $sth =
719       $dbh->prepare(
720 "select password,cardnumber,borrowernumber,userid,firstname,surname,branchcode,flags from borrowers where userid=?"
721       );
722     $sth->execute($userid);
723     if ( $sth->rows ) {
724         my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
725             $surname, $branchcode, $flags )
726           = $sth->fetchrow;
727         if ( md5_base64($password) eq $md5password ) {
728
729             C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
730                 $firstname, $surname, $branchcode, $flags );
731             return 1, $cardnumber;
732         }
733     }
734     $sth =
735       $dbh->prepare(
736 "select password,cardnumber,borrowernumber,userid, firstname,surname,branchcode,flags from borrowers where cardnumber=?"
737       );
738     $sth->execute($userid);
739     if ( $sth->rows ) {
740         my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
741             $surname, $branchcode, $flags )
742           = $sth->fetchrow;
743         if ( md5_base64($password) eq $md5password ) {
744
745             C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
746                 $firstname, $surname, $branchcode, $flags );
747             return 1, $userid;
748         }
749     }
750     if (   $userid && $userid eq C4::Context->config('user')
751         && "$password" eq C4::Context->config('pass') )
752     {
753
754 # Koha superuser account
755 #               C4::Context->set_userenv(0,0,C4::Context->config('user'),C4::Context->config('user'),C4::Context->config('user'),"",1);
756         return 2;
757     }
758     if (   $userid && $userid eq 'demo'
759         && "$password" eq 'demo'
760         && C4::Context->config('demo') )
761     {
762
763 # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
764 # some features won't be effective : modify systempref, modify MARC structure,
765         return 2;
766     }
767     return 0;
768 }
769
770 sub getuserflags {
771     my $cardnumber = shift;
772     my $dbh        = shift;
773     my $userflags;
774     my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE cardnumber=?");
775     $sth->execute($cardnumber);
776     my ($flags) = $sth->fetchrow;
777     $flags = 0 unless $flags;
778     $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
779     $sth->execute;
780
781     while ( my ( $bit, $flag, $defaulton ) = $sth->fetchrow ) {
782         if ( ( $flags & ( 2**$bit ) ) || $defaulton ) {
783             $userflags->{$flag} = 1;
784         }
785         else {
786             $userflags->{$flag} = 0;
787         }
788     }
789     return $userflags;
790 }
791
792 sub haspermission {
793     my ( $dbh, $userid, $flagsrequired ) = @_;
794     my $sth = $dbh->prepare("SELECT cardnumber FROM borrowers WHERE userid=?");
795     $sth->execute($userid);
796     my ($cardnumber) = $sth->fetchrow;
797     ($cardnumber) || ( $cardnumber = $userid );
798     my $flags = getuserflags( $cardnumber, $dbh );
799     my $configfile;
800     if ( $userid eq C4::Context->config('user') ) {
801
802         # Super User Account from /etc/koha.conf
803         $flags->{'superlibrarian'} = 1;
804     }
805     if ( $userid eq 'demo' && C4::Context->config('demo') ) {
806
807         # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
808         $flags->{'superlibrarian'} = 1;
809     }
810     return $flags if $flags->{superlibrarian};
811     foreach ( keys %$flagsrequired ) {
812         return $flags if $flags->{$_};
813     }
814     return 0;
815 }
816
817 sub getborrowernumber {
818     my ($userid) = @_;
819     my $dbh = C4::Context->dbh;
820     for my $field ( 'userid', 'cardnumber' ) {
821         my $sth =
822           $dbh->prepare("select borrowernumber from borrowers where $field=?");
823         $sth->execute($userid);
824         if ( $sth->rows ) {
825             my ($bnumber) = $sth->fetchrow;
826             return $bnumber;
827         }
828     }
829     return 0;
830 }
831
832 END { }    # module clean-up code here (global destructor)
833 1;
834 __END__
835
836 =back
837
838 =head1 SEE ALSO
839
840 CGI(3)
841
842 C4::Output(3)
843
844 Digest::MD5(3)
845
846 =cut