Adding KOHAVERSION management.
[wip/koha-chris_n.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         $template->param( loggedinusername => $user );
136         $template->param( sessionID        => $sessionID );
137
138         $borrowernumber = getborrowernumber($user);
139         my ( $borr, $alternativeflags ) =
140           GetMemberDetails( $borrowernumber );
141         my @bordat;
142         $bordat[0] = $borr;
143         $template->param( "USER_INFO" => \@bordat );
144
145         # We are going to use the $flags returned by checkauth
146         # to create the template's parameters that will indicate
147         # which menus the user can access.
148         if (( $flags && $flags->{superlibrarian}==1) or $insecure==1) {
149             $template->param( CAN_user_circulate        => 1 );
150             $template->param( CAN_user_catalogue        => 1 );
151             $template->param( CAN_user_parameters       => 1 );
152             $template->param( CAN_user_borrowers        => 1 );
153             $template->param( CAN_user_permission       => 1 );
154             $template->param( CAN_user_reserveforothers => 1 );
155             $template->param( CAN_user_borrow           => 1 );
156             $template->param( CAN_user_editcatalogue    => 1 );
157             $template->param( CAN_user_updatecharge     => 1 );
158             $template->param( CAN_user_acquisition      => 1 );
159             $template->param( CAN_user_management       => 1 );
160             $template->param( CAN_user_tools            => 1 ); 
161             $template->param( CAN_user_editauthorities  => 1 );
162             $template->param( CAN_user_serials          => 1 );
163             $template->param( CAN_user_reports          => 1 );
164         }
165
166         if ( $flags && $flags->{circulate} == 1 ) {
167             $template->param( CAN_user_circulate => 1 );
168         }
169
170         if ( $flags && $flags->{catalogue} == 1 ) {
171             $template->param( CAN_user_catalogue => 1 );
172         }
173
174         if ( $flags && $flags->{parameters} == 1 ) {
175             $template->param( CAN_user_parameters => 1 );
176             $template->param( CAN_user_management => 1 );
177         }
178
179         if ( $flags && $flags->{borrowers} == 1 ) {
180             $template->param( CAN_user_borrowers => 1 );
181         }
182
183         if ( $flags && $flags->{permissions} == 1 ) {
184             $template->param( CAN_user_permission => 1 );
185         }
186
187         if ( $flags && $flags->{reserveforothers} == 1 ) {
188             $template->param( CAN_user_reserveforothers => 1 );
189         }
190
191         if ( $flags && $flags->{borrow} == 1 ) {
192             $template->param( CAN_user_borrow => 1 );
193         }
194
195         if ( $flags && $flags->{editcatalogue} == 1 ) {
196             $template->param( CAN_user_editcatalogue => 1 );
197         }
198
199         if ( $flags && $flags->{updatecharges} == 1 ) {
200             $template->param( CAN_user_updatecharge => 1 );
201         }
202
203         if ( $flags && $flags->{acquisition} == 1 ) {
204             $template->param( CAN_user_acquisition => 1 );
205         }
206
207         if ( $flags && $flags->{tools} == 1 ) {
208             $template->param( CAN_user_tools => 1 );
209         }
210         
211         if ( $flags && $flags->{editauthorities} == 1 ) {
212             $template->param( CAN_user_editauthorities => 1 );
213         }
214                 
215         if ( $flags && $flags->{serials} == 1 ) {
216             $template->param( CAN_user_serials => 1 );
217         }
218
219         if ( $flags && $flags->{reports} == 1 ) {
220             $template->param( CAN_user_reports => 1 );
221         }
222     }
223     if ( $in->{'type'} eq "intranet" ) {
224         $template->param(
225             intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
226             intranetstylesheet => C4::Context->preference("intranetstylesheet"),
227             IntranetNav        => C4::Context->preference("IntranetNav"),
228             intranetuserjs     => C4::Context->preference("intranetuserjs"),
229             TemplateEncoding   => C4::Context->preference("TemplateEncoding"),
230             AmazonContent      => C4::Context->preference("AmazonContent"),
231             LibraryName        => C4::Context->preference("LibraryName"),
232             LoginBranchcode    => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
233             LoginBranchname    => (C4::Context->userenv?C4::Context->userenv->{"branchname"}:"insecure"),
234             AutoLocation       => C4::Context->preference("AutoLocation"),
235             hide_marc          => C4::Context->preference("hide_marc"),
236             patronimages       => C4::Context->preference("patronimages"),
237             "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
238             advancedMARCEditor      => C4::Context->preference("advancedMARCEditor"),
239             suggestion              => C4::Context->preference("suggestion"),
240             virtualshelves          => C4::Context->preference("virtualshelves"),
241             LibraryName             => C4::Context->preference("LibraryName"),
242             KohaAdminEmailAddress   => "" . C4::Context->preference("KohaAdminEmailAddress"),
243         );
244     }
245     else {
246         warn "template type should be OPAC, here it is=[" . $in->{'type'} . "]"
247           unless ( $in->{'type'} eq 'opac' );
248         my $LibraryNameTitle = C4::Context->preference("LibraryName");
249         $LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi;
250         $LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg;
251         $template->param(
252             KohaAdminEmailAddress  => "" . C4::Context->preference("KohaAdminEmailAddress"),
253             suggestion             => "" . C4::Context->preference("suggestion"),
254             virtualshelves         => "" . C4::Context->preference("virtualshelves"),
255             OpacNav                => "" . C4::Context->preference("OpacNav"),
256             opacheader             => "" . C4::Context->preference("opacheader"),
257             opaccredits            => "" . C4::Context->preference("opaccredits"),
258             opacsmallimage         => "" . C4::Context->preference("opacsmallimage"),
259             opaclargeimage         => "" . C4::Context->preference("opaclargeimage"),
260             opaclayoutstylesheet   => "". C4::Context->preference("opaclayoutstylesheet"),
261             opaccolorstylesheet    => "". C4::Context->preference("opaccolorstylesheet"),
262             opaclanguagesdisplay   => "". C4::Context->preference("opaclanguagesdisplay"),
263             opacuserlogin          => "" . C4::Context->preference("opacuserlogin"),
264             opacbookbag            => "" . C4::Context->preference("opacbookbag"),
265             TemplateEncoding       => "". C4::Context->preference("TemplateEncoding"),
266             AmazonContent          => "" . C4::Context->preference("AmazonContent"),
267             LibraryName            => "" . C4::Context->preference("LibraryName"),
268             LibraryNameTitle       => "" . $LibraryNameTitle,
269             LoginBranchcode        => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
270             LoginBranchname        => C4::Context->userenv?C4::Context->userenv->{"branchname"}:"", 
271             OpacPasswordChange     => C4::Context->preference("OpacPasswordChange"),
272             opacreadinghistory     => C4::Context->preference("opacreadinghistory"),
273             opacuserjs             => C4::Context->preference("opacuserjs"),
274             OpacCloud              => C4::Context->preference("OpacCloud"),
275             OpacTopissue           => C4::Context->preference("OpacTopissue"),
276             OpacAuthorities        => C4::Context->preference("OpacAuthorities"),
277             OpacBrowser            => C4::Context->preference("OpacBrowser"),
278             RequestOnOpac          => C4::Context->preference("RequestOnOpac"),
279             reviewson              => C4::Context->preference("reviewson"),
280             hide_marc              => C4::Context->preference("hide_marc"),
281             patronimages           => C4::Context->preference("patronimages"),
282             "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
283         );
284     }
285     return ( $template, $borrowernumber, $cookie );
286 }
287
288 =item checkauth
289
290   ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
291
292 Verifies that the user is authorized to run this script.  If
293 the user is authorized, a (userid, cookie, session-id, flags)
294 quadruple is returned.  If the user is not authorized but does
295 not have the required privilege (see $flagsrequired below), it
296 displays an error page and exits.  Otherwise, it displays the
297 login page and exits.
298
299 Note that C<&checkauth> will return if and only if the user
300 is authorized, so it should be called early on, before any
301 unfinished operations (e.g., if you've opened a file, then
302 C<&checkauth> won't close it for you).
303
304 C<$query> is the CGI object for the script calling C<&checkauth>.
305
306 The C<$noauth> argument is optional. If it is set, then no
307 authorization is required for the script.
308
309 C<&checkauth> fetches user and session information from C<$query> and
310 ensures that the user is authorized to run scripts that require
311 authorization.
312
313 The C<$flagsrequired> argument specifies the required privileges
314 the user must have if the username and password are correct.
315 It should be specified as a reference-to-hash; keys in the hash
316 should be the "flags" for the user, as specified in the Members
317 intranet module. Any key specified must correspond to a "flag"
318 in the userflags table. E.g., { circulate => 1 } would specify
319 that the user must have the "circulate" privilege in order to
320 proceed. To make sure that access control is correct, the
321 C<$flagsrequired> parameter must be specified correctly.
322
323 The C<$type> argument specifies whether the template should be
324 retrieved from the opac or intranet directory tree.  "opac" is
325 assumed if it is not specified; however, if C<$type> is specified,
326 "intranet" is assumed if it is not "opac".
327
328 If C<$query> does not have a valid session ID associated with it
329 (i.e., the user has not logged in) or if the session has expired,
330 C<&checkauth> presents the user with a login page (from the point of
331 view of the original script, C<&checkauth> does not return). Once the
332 user has authenticated, C<&checkauth> restarts the original script
333 (this time, C<&checkauth> returns).
334
335 The login page is provided using a HTML::Template, which is set in the
336 systempreferences table or at the top of this file. The variable C<$type>
337 selects which template to use, either the opac or the intranet 
338 authentification template.
339
340 C<&checkauth> returns a user ID, a cookie, and a session ID. The
341 cookie should be sent back to the browser; it verifies that the user
342 has authenticated.
343
344 =cut
345
346 sub checkauth {
347     my $query = shift;
348         # warn "Checking Auth";
349     # $authnotrequired will be set for scripts which will run without authentication
350     my $authnotrequired = shift;
351     my $flagsrequired   = shift;
352     my $type            = shift;
353     $type = 'opac' unless $type;
354
355     my $dbh     = C4::Context->dbh;
356     my $timeout = C4::Context->preference('timeout');
357     $timeout = 600 unless $timeout;
358
359     # state variables
360     my $loggedin = 0;
361     my %info;
362     my ( $userid, $cookie, $sessionID, $flags );
363     my $logout = $query->param('logout.x');
364     if ( $userid = $ENV{'REMOTE_USER'} ) {
365         # Using Basic Authentication, no cookies required
366         $cookie = $query->cookie(
367             -name    => 'CGISESSID',
368             -value   => '',
369             -expires => ''
370         );
371         $loggedin = 1;
372     }
373     elsif ( $sessionID = $query->cookie("CGISESSID")) {
374         my $session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
375         C4::Context->_new_userenv($sessionID);
376         if ($session){
377             C4::Context::set_userenv(
378                 $session->param('number'),       $session->param('id'),
379                 $session->param('cardnumber'),   $session->param('firstname'),
380                 $session->param('surname'),      $session->param('branch'),
381                 $session->param('branchname'),   $session->param('flags'),
382                 $session->param('emailaddress'), $session->param('branchprinter')
383             );
384         }
385         my $ip=$session->param('ip');
386         $userid = $session->param('id');
387         my $lasttime = $session->param('lasttime');
388         if ($logout) {
389
390             # voluntary logout the user
391             $session->delete;
392             C4::Context->_unset_userenv($sessionID);
393             $sessionID = undef;
394             $userid    = undef;
395             open L, ">>/tmp/sessionlog";
396             my $time = localtime( time() );
397             printf L "%20s from %16s logged out at %30s (manually).\n", $userid,
398               $ip, $time;
399             close L;
400         }
401         if ($userid) {
402             if ( $lasttime < time() - $timeout ) {
403                 # timed logout
404                 $info{'timed_out'} = 1;
405                 $session->delete();
406                 C4::Context->_unset_userenv($sessionID);
407                 $userid    = undef;
408                 $sessionID = undef;
409                 open L, ">>/tmp/sessionlog";
410                 my $time = localtime( time() );
411                 printf L "%20s from %16s logged out at %30s (inactivity).\n",
412                   $userid, $ip, $time;
413                 close L;
414             }
415             elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
416                 # Different ip than originally logged in from
417                 $info{'oldip'}        = $ip;
418                 $info{'newip'}        = $ENV{'REMOTE_ADDR'};
419                 $info{'different_ip'} = 1;
420                                 $session->delete();
421                 C4::Context->_unset_userenv($sessionID);
422                 $sessionID = undef;
423                 $userid    = undef;
424                 open L, ">>/tmp/sessionlog";
425                 my $time = localtime( time() );
426                 printf L
427 "%20s from logged out at %30s (ip changed from %16s to %16s).\n",
428                   $userid, $time, $ip, $info{'newip'};
429                 close L;
430             }
431             else {
432                 $cookie = $query->cookie( CGISESSID => $session->id );
433                 $session->param('lasttime',time());
434                 $flags = haspermission( $dbh, $userid, $flagsrequired );
435                 if ($flags) {
436                     $loggedin = 1;
437                 }
438                 else {
439                     $info{'nopermission'} = 1;
440                 }
441             }
442         }
443     }
444     unless ($userid) {
445         my $session = new CGI::Session("driver:MySQL", undef, {Handle=>$dbh});          
446         my $sessionID = $session->id;
447         $userid    = $query->param('userid');
448         C4::Context->_new_userenv($sessionID);
449         my $password = $query->param('password');
450         C4::Context->_new_userenv($sessionID);
451         my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
452         if ($return) {
453             open L, ">>/tmp/sessionlog";
454             my $time = localtime( time() );
455             printf L "%20s from %16s logged in  at %30s.\n", $userid,
456               $ENV{'REMOTE_ADDR'}, $time;
457             close L;
458             $cookie = $query->cookie(CGISESSID => $sessionID);
459             if ( $flags = haspermission( $dbh, $userid, $flagsrequired ) ) {
460                 $loggedin = 1;
461             }
462             else {
463                 $info{'nopermission'} = 1;
464                 C4::Context->_unset_userenv($sessionID);
465             }
466             if ( $return == 1 ) {
467                 my (
468                     $borrowernumber, $firstname,  $surname,
469                     $userflags,      $branchcode, $branchname,
470                     $branchprinter,  $emailaddress
471                 );
472                 my $sth =
473                   $dbh->prepare(
474 "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=?"
475                   );
476                 $sth->execute($userid);
477                 (
478                     $borrowernumber, $firstname,  $surname,
479                     $userflags,      $branchcode, $branchname,
480                     $branchprinter,  $emailaddress
481                   )
482                   = $sth->fetchrow
483                   if ( $sth->rows );
484
485 #                               warn "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
486                 unless ( $sth->rows ) {
487                     my $sth =
488                       $dbh->prepare(
489 "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=?"
490                       );
491                     $sth->execute($cardnumber);
492                     (
493                         $borrowernumber, $firstname,  $surname,
494                         $userflags,      $branchcode, $branchname,
495                         $branchprinter,  $emailaddress
496                       )
497                       = $sth->fetchrow
498                       if ( $sth->rows );
499
500 #                                       warn "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
501                     unless ( $sth->rows ) {
502                         $sth->execute($userid);
503                         (
504                             $borrowernumber, $firstname, $surname, $userflags,
505                             $branchcode, $branchname, $branchprinter, $emailaddress
506                           )
507                           = $sth->fetchrow
508                           if ( $sth->rows );
509                     }
510                 }
511
512 # 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.
513                 my $ip       = $ENV{'REMOTE_ADDR'};
514                 # if they specify at login, use that
515                 if ($query->param('branch')) {
516                     $branchcode  = $query->param('branch');
517                     $branchname = GetBranchName($branchcode);
518                 }
519                 my $branches = GetBranches();
520                 my @branchesloop;
521                 foreach my $br ( keys %$branches ) {
522                     #           now we work with the treatment of ip
523                     my $domain = $branches->{$br}->{'branchip'};
524                     if ( $domain && $ip =~ /^$domain/ ) {
525                         $branchcode = $branches->{$br}->{'branchcode'};
526
527                         # new op dev : add the branchprinter and branchname in the cookie
528                         $branchprinter = $branches->{$br}->{'branchprinter'};
529                         $branchname    = $branches->{$br}->{'branchname'};
530                     }
531                 }
532                 $session->param('number',$borrowernumber);
533                 $session->param('id',$userid);
534                 $session->param('cardnumber',$cardnumber);
535                 $session->param('firstname',$firstname);
536                 $session->param('surname',$surname);
537                 $session->param('branch',$branchcode);
538                 $session->param('branchname',$branchname);
539                 $session->param('flags',$userflags);
540                 $session->param('emailaddress',$emailaddress);
541                 $session->param('ip',$session->remote_addr());
542                 $session->param('lasttime',time());
543             }
544             elsif ( $return == 2 ) {
545                 #We suppose the user is the superlibrarian
546                         $session->param('number',0);
547                         $session->param('id',C4::Context->config('user'));
548                         $session->param('cardnumber',C4::Context->config('user'));
549                         $session->param('firstname',C4::Context->config('user'));
550                         $session->param('surname',C4::Context->config('user'),);
551                         $session->param('branch','NO_LIBRARY_SET');
552                         $session->param('branchname','NO_LIBRARY_SET');
553                         $session->param('flags',1);
554                         $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
555                         $session->param('ip',$session->remote_addr());
556                         $session->param('lasttime',time());
557                 }
558                 if ($session){
559                     C4::Context::set_userenv(
560                         $session->param('number'),       $session->param('id'),
561                         $session->param('cardnumber'),   $session->param('firstname'),
562                         $session->param('surname'),      $session->param('branch'),
563                         $session->param('branchname'),   $session->param('flags'),
564                         $session->param('emailaddress'), $session->param('branchprinter')
565                     );
566                 }
567         }
568
569         else {
570             if ($userid) {
571                 $info{'invalid_username_or_password'} = 1;
572                 C4::Context->_unset_userenv($sessionID);
573             }
574         }
575     }
576     my $insecure = C4::Context->boolean_preference('insecure');
577
578     # finished authentification, now respond
579     if ( $loggedin || $authnotrequired || ( defined($insecure) && $insecure ) )
580     {
581         # successful login
582         unless ($cookie) {
583             $cookie = $query->cookie( CGISESSID => ''
584             );
585         }
586                 return ( $userid, $cookie, $sessionID, $flags );
587
588     }
589
590 #
591 #
592 # AUTH rejected, show the login/password template, after checking the DB.
593 #
594 #
595     
596     # get the inputs from the incoming query
597     my @inputs = ();
598     foreach my $name ( param $query) {
599         (next) if ( $name eq 'userid' || $name eq 'password' );
600         my $value = $query->param($name);
601         push @inputs, { name => $name, value => $value };
602     }
603     # get the branchloop, which we need for authentication
604     my $branches = GetBranches();
605     my @branch_loop;
606     for my $branch_hash (keys %$branches) {
607                 push @branch_loop, {branchcode => "$branch_hash", branchname => $branches->{$branch_hash}->{'branchname'}, };
608     }
609
610     # check that database and koha version are the same
611     # there is no DB version, it's a fresh install,
612     # go to web installer
613     unless (C4::Context->preference('Version')){
614       if ($type ne 'opac'){
615         warn "Install required, redirecting to Installer";
616         print $query->redirect("/cgi-bin/koha/installer/install.pl");
617       } else {
618         warn "OPAC Install required, redirecting to maintenance";
619         print $query->redirect("/cgi-bin/koha/maintenance.pl");
620       }       
621       exit;
622     }
623     # there is a DB version, compare it to the code version
624     my $kohaversion=C4::Context::KOHAVERSION;
625     # remove the 3 last . to have a Perl number
626     $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
627 #     warn "kohaversion : $kohaversion";
628     if (C4::Context->preference('Version') < $kohaversion){
629       if ($type ne 'opac'){
630       warn "Database update needed, redirecting to Installer. Database is ".C4::Context->preference('Version')." and Koha is : ".C4::Context->config("kohaversion");
631         print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3");
632       } else {
633       warn "OPAC :Database update needed, redirecting to maintenance. Database is ".C4::Context->preference('Version')." and Koha is : ".C4::Context->config("kohaversion");
634         print $query->redirect("/cgi-bin/koha/maintenance.pl");
635       }       
636       exit;
637     }
638     my $template_name;
639     if ( $type eq 'opac' ) {
640         $template_name = "opac-auth.tmpl";
641     }
642     else {
643         $template_name = "auth.tmpl";
644     }
645     my $template = gettemplate( $template_name, $type, $query );
646     $template->param(branchloop => \@branch_loop,);
647     $template->param(
648                 login                            => 1,
649         INPUTS               => \@inputs,
650         suggestion           => C4::Context->preference("suggestion"),
651         virtualshelves       => C4::Context->preference("virtualshelves"),
652         opaclargeimage       => C4::Context->preference("opaclargeimage"),
653         LibraryName          => C4::Context->preference("LibraryName"),
654         OpacNav              => C4::Context->preference("OpacNav"),
655         opaccredits          => C4::Context->preference("opaccredits"),
656         opacreadinghistory   => C4::Context->preference("opacreadinghistory"),
657         opacsmallimage       => C4::Context->preference("opacsmallimage"),
658         opaclayoutstylesheet => C4::Context->preference("opaclayoutstylesheet"),
659         opaccolorstylesheet  => C4::Context->preference("opaccolorstylesheet"),
660         opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
661         opacuserjs           => C4::Context->preference("opacuserjs"),
662
663         intranetcolorstylesheet =>
664           C4::Context->preference("intranetcolorstylesheet"),
665         intranetstylesheet => C4::Context->preference("intranetstylesheet"),
666         IntranetNav        => C4::Context->preference("IntranetNav"),
667         intranetuserjs     => C4::Context->preference("intranetuserjs"),
668         TemplateEncoding   => C4::Context->preference("TemplateEncoding"),
669
670     );
671     $template->param( loginprompt => 1 ) unless $info{'nopermission'};
672
673     my $self_url = $query->url( -absolute => 1 );
674     $template->param(
675         url         => $self_url,
676         LibraryName => => C4::Context->preference("LibraryName"),
677     );
678     $template->param( \%info );
679 #    $cookie = $query->cookie(CGISESSID => $session->id
680 #   );
681     print $query->header(
682         -type   => 'utf-8',
683         -cookie => $cookie
684       ),
685       $template->output;
686     exit;
687 }
688
689 sub checkpw {
690
691     my ( $dbh, $userid, $password ) = @_;
692
693     # INTERNAL AUTH
694     my $sth =
695       $dbh->prepare(
696 "select password,cardnumber,borrowernumber,userid,firstname,surname,branchcode,flags from borrowers where userid=?"
697       );
698     $sth->execute($userid);
699     if ( $sth->rows ) {
700         my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
701             $surname, $branchcode, $flags )
702           = $sth->fetchrow;
703         if ( md5_base64($password) eq $md5password ) {
704
705             C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
706                 $firstname, $surname, $branchcode, $flags );
707             return 1, $cardnumber;
708         }
709     }
710     $sth =
711       $dbh->prepare(
712 "select password,cardnumber,borrowernumber,userid, firstname,surname,branchcode,flags from borrowers where cardnumber=?"
713       );
714     $sth->execute($userid);
715     if ( $sth->rows ) {
716         my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
717             $surname, $branchcode, $flags )
718           = $sth->fetchrow;
719         if ( md5_base64($password) eq $md5password ) {
720
721             C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
722                 $firstname, $surname, $branchcode, $flags );
723             return 1, $userid;
724         }
725     }
726     if (   $userid && $userid eq C4::Context->config('user')
727         && "$password" eq C4::Context->config('pass') )
728     {
729
730 # Koha superuser account
731 #               C4::Context->set_userenv(0,0,C4::Context->config('user'),C4::Context->config('user'),C4::Context->config('user'),"",1);
732         return 2;
733     }
734     if (   $userid && $userid eq 'demo'
735         && "$password" eq 'demo'
736         && C4::Context->config('demo') )
737     {
738
739 # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
740 # some features won't be effective : modify systempref, modify MARC structure,
741         return 2;
742     }
743     return 0;
744 }
745
746 sub getuserflags {
747     my $cardnumber = shift;
748     my $dbh        = shift;
749     my $userflags;
750     my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE cardnumber=?");
751     $sth->execute($cardnumber);
752     my ($flags) = $sth->fetchrow;
753     $flags = 0 unless $flags;
754     $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
755     $sth->execute;
756
757     while ( my ( $bit, $flag, $defaulton ) = $sth->fetchrow ) {
758         if ( ( $flags & ( 2**$bit ) ) || $defaulton ) {
759             $userflags->{$flag} = 1;
760         }
761         else {
762             $userflags->{$flag} = 0;
763         }
764     }
765     return $userflags;
766 }
767
768 sub haspermission {
769     my ( $dbh, $userid, $flagsrequired ) = @_;
770     my $sth = $dbh->prepare("SELECT cardnumber FROM borrowers WHERE userid=?");
771     $sth->execute($userid);
772     my ($cardnumber) = $sth->fetchrow;
773     ($cardnumber) || ( $cardnumber = $userid );
774     my $flags = getuserflags( $cardnumber, $dbh );
775     my $configfile;
776     if ( $userid eq C4::Context->config('user') ) {
777
778         # Super User Account from /etc/koha.conf
779         $flags->{'superlibrarian'} = 1;
780     }
781     if ( $userid eq 'demo' && C4::Context->config('demo') ) {
782
783         # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
784         $flags->{'superlibrarian'} = 1;
785     }
786     return $flags if $flags->{superlibrarian};
787     foreach ( keys %$flagsrequired ) {
788         return $flags if $flags->{$_};
789     }
790     return 0;
791 }
792
793 sub getborrowernumber {
794     my ($userid) = @_;
795     my $dbh = C4::Context->dbh;
796     for my $field ( 'userid', 'cardnumber' ) {
797         my $sth =
798           $dbh->prepare("select borrowernumber from borrowers where $field=?");
799         $sth->execute($userid);
800         if ( $sth->rows ) {
801             my ($bnumber) = $sth->fetchrow;
802             return $bnumber;
803         }
804     }
805     return 0;
806 }
807
808 END { }    # module clean-up code here (global destructor)
809 1;
810 __END__
811
812 =back
813
814 =head1 SEE ALSO
815
816 CGI(3)
817
818 C4::Output(3)
819
820 Digest::MD5(3)
821
822 =cut