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