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