adds the ability to set the branch at login,
[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         warn "GET Template";
118     my $template =
119       gettemplate( $in->{'template_name'}, $in->{'type'}, $in->{'query'} );
120     my ( $user, $cookie, $sessionID, $flags ) = checkauth(
121         $in->{'query'},
122         $in->{'authnotrequired'},
123         $in->{'flagsrequired'},
124         $in->{'type'}
125     ) unless ($in->{'template_name'}=~/maintenance/);
126
127     my $borrowernumber;
128     my $insecure = C4::Context->preference('insecure');
129     if ($user or $insecure) {
130         $template->param( loggedinusername => $user );
131         $template->param( sessionID        => $sessionID );
132
133         $borrowernumber = getborrowernumber($user);
134         my ( $borr, $alternativeflags ) =
135           GetMemberDetails( $borrowernumber );
136         my @bordat;
137         $bordat[0] = $borr;
138         $template->param( "USER_INFO" => \@bordat );
139
140         # We are going to use the $flags returned by checkauth
141         # to create the template's parameters that will indicate
142         # which menus the user can access.
143         if (( $flags && $flags->{superlibrarian}==1) or $insecure==1) {
144             $template->param( CAN_user_circulate        => 1 );
145             $template->param( CAN_user_catalogue        => 1 );
146             $template->param( CAN_user_parameters       => 1 );
147             $template->param( CAN_user_borrowers        => 1 );
148             $template->param( CAN_user_permission       => 1 );
149             $template->param( CAN_user_reserveforothers => 1 );
150             $template->param( CAN_user_borrow           => 1 );
151             $template->param( CAN_user_editcatalogue    => 1 );
152             $template->param( CAN_user_updatecharge     => 1 );
153             $template->param( CAN_user_acquisition      => 1 );
154             $template->param( CAN_user_management       => 1 );
155             $template->param( CAN_user_tools            => 1 ); 
156             $template->param( CAN_user_editauthorities  => 1 );
157             $template->param( CAN_user_serials          => 1 );
158             $template->param( CAN_user_reports          => 1 );
159         }
160
161         if ( $flags && $flags->{circulate} == 1 ) {
162             $template->param( CAN_user_circulate => 1 );
163         }
164
165         if ( $flags && $flags->{catalogue} == 1 ) {
166             $template->param( CAN_user_catalogue => 1 );
167         }
168
169         if ( $flags && $flags->{parameters} == 1 ) {
170             $template->param( CAN_user_parameters => 1 );
171             $template->param( CAN_user_management => 1 );
172         }
173
174         if ( $flags && $flags->{borrowers} == 1 ) {
175             $template->param( CAN_user_borrowers => 1 );
176         }
177
178         if ( $flags && $flags->{permissions} == 1 ) {
179             $template->param( CAN_user_permission => 1 );
180         }
181
182         if ( $flags && $flags->{reserveforothers} == 1 ) {
183             $template->param( CAN_user_reserveforothers => 1 );
184         }
185
186         if ( $flags && $flags->{borrow} == 1 ) {
187             $template->param( CAN_user_borrow => 1 );
188         }
189
190         if ( $flags && $flags->{editcatalogue} == 1 ) {
191             $template->param( CAN_user_editcatalogue => 1 );
192         }
193
194         if ( $flags && $flags->{updatecharges} == 1 ) {
195             $template->param( CAN_user_updatecharge => 1 );
196         }
197
198         if ( $flags && $flags->{acquisition} == 1 ) {
199             $template->param( CAN_user_acquisition => 1 );
200         }
201
202         if ( $flags && $flags->{tools} == 1 ) {
203             $template->param( CAN_user_tools => 1 );
204         }
205         
206         if ( $flags && $flags->{editauthorities} == 1 ) {
207             $template->param( CAN_user_editauthorities => 1 );
208         }
209                 
210         if ( $flags && $flags->{serials} == 1 ) {
211             $template->param( CAN_user_serials => 1 );
212         }
213
214         if ( $flags && $flags->{reports} == 1 ) {
215             $template->param( CAN_user_reports => 1 );
216         }
217     }
218     if ( $in->{'type'} eq "intranet" ) {
219         $template->param(
220             intranetcolorstylesheet => 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 );
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                                 # if they specify at login, use that
549                                 if ($query->param('branch')) {
550                                 $branchcode  = $query->param('branch');
551                                 $branchname = GetBranchName($branchcode);
552                                 }
553                 my $branches = GetBranches();
554                 my @branchesloop;
555                 foreach my $br ( keys %$branches ) {
556                     #           now we work with the treatment of ip
557                     my $domain = $branches->{$br}->{'branchip'};
558                     if ( $domain && $ip =~ /^$domain/ ) {
559                         $branchcode = $branches->{$br}->{'branchcode'};
560
561                         # new op dev : add the branchprinter and branchname in the cookie
562                         $branchprinter = $branches->{$br}->{'branchprinter'};
563                         $branchname    = $branches->{$br}->{'branchname'};
564                     }
565                 }
566                                 
567                                 $session->param('number',$borrowernumber);
568                                 $session->param('id',$userid);
569                                 $session->param('cardnumber',$cardnumber);
570                                 $session->param('firstname',$firstname);
571                                 $session->param('surname',$surname);
572                                 $session->param('branch',$branchcode);
573                                 $session->param('branchname',$branchname);
574                                 $session->param('flags',$userflags);
575                                 $session->param('emailaddress',$emailaddress);
576                 $session->param('ip',$session->remote_addr());
577                                 $session->param('lasttime',time());
578             }
579             elsif ( $return == 2 ) {
580
581                 #We suppose the user is the superlibrarian
582                                 $session->param('number',0);
583                                 $session->param('id',C4::Context->config('user'));
584                                 $session->param('cardnumber',C4::Context->config('user'));
585                                 $session->param('firstname',C4::Context->config('user'));
586                                 $session->param('surname',C4::Context->config('user'),);
587                                 $session->param('branch','NO_LIBRARY_SET');
588                                 $session->param('branchname','NO_LIBRARY_SET');
589                                 $session->param('flags',1);
590                                 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
591                 $session->param('ip',$session->remote_addr());
592                                 $session->param('lasttime',time());
593                         }
594                         if ($session){
595                 C4::Context::set_userenv(
596                 $session->param('number'),       $session->param('id'),
597                 $session->param('cardnumber'),   $session->param('firstname'),
598                 $session->param('surname'),      $session->param('branch'),
599                 $session->param('branchname'),   $session->param('flags'),
600                 $session->param('emailaddress'), $session->param('branchprinter')
601                 );
602                 }               
603         }
604
605         else {
606             if ($userid) {
607                 $info{'invalid_username_or_password'} = 1;
608                 C4::Context->_unset_userenv($sessionID);
609             }
610         }
611     }
612     my $insecure = C4::Context->boolean_preference('insecure');
613
614     # finished authentification, now respond
615     if ( $loggedin || $authnotrequired || ( defined($insecure) && $insecure ) )
616     {
617         # successful login
618         unless ($cookie) {
619             $cookie = $query->cookie( CGISESSID => ''
620             );
621         }
622                 return ( $userid, $cookie, $sessionID, $flags );
623
624     }
625
626     # else we have a problem...
627     # get the inputs from the incoming query
628     my @inputs = ();
629     foreach my $name ( param $query) {
630         (next) if ( $name eq 'userid' || $name eq 'password' );
631         my $value = $query->param($name);
632         push @inputs, { name => $name, value => $value };
633     }
634     # get the branchloop, which we need for authetication
635         use C4::Branch;
636     my $branches = GetBranches();
637     my @branch_loop;
638     for my $branch_hash (keys %$branches) {
639                 push @branch_loop, {branchcode => "$branch_hash", branchname => $branches->{$branch_hash}->{'branchname'}, };
640     }
641
642     my $template = gettemplate( $template_name, $type, $query );
643     $template->param(branchloop => \@branch_loop,);
644     $template->param(
645         INPUTS               => \@inputs,
646         suggestion           => C4::Context->preference("suggestion"),
647         virtualshelves       => C4::Context->preference("virtualshelves"),
648         opaclargeimage       => C4::Context->preference("opaclargeimage"),
649         LibraryName          => C4::Context->preference("LibraryName"),
650         OpacNav              => C4::Context->preference("OpacNav"),
651         opaccredits          => C4::Context->preference("opaccredits"),
652         opacreadinghistory   => C4::Context->preference("opacreadinghistory"),
653         opacsmallimage       => C4::Context->preference("opacsmallimage"),
654         opaclayoutstylesheet => C4::Context->preference("opaclayoutstylesheet"),
655         opaccolorstylesheet  => C4::Context->preference("opaccolorstylesheet"),
656         opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
657         opacuserjs           => C4::Context->preference("opacuserjs"),
658
659         intranetcolorstylesheet =>
660           C4::Context->preference("intranetcolorstylesheet"),
661         intranetstylesheet => C4::Context->preference("intranetstylesheet"),
662         IntranetNav        => C4::Context->preference("IntranetNav"),
663         intranetuserjs     => C4::Context->preference("intranetuserjs"),
664         TemplateEncoding   => C4::Context->preference("TemplateEncoding"),
665
666     );
667     $template->param( loginprompt => 1 ) unless $info{'nopermission'};
668
669     my $self_url = $query->url( -absolute => 1 );
670     $template->param(
671         url         => $self_url,
672         LibraryName => => C4::Context->preference("LibraryName"),
673     );
674     $template->param( \%info );
675 #    $cookie = $query->cookie(CGISESSID => $session->id
676 #   );
677     print $query->header(
678         -type   => 'utf-8',
679         -cookie => $cookie
680       ),
681       $template->output;
682     exit;
683 }
684
685 sub checkpw {
686
687     my ( $dbh, $userid, $password ) = @_;
688
689     # INTERNAL AUTH
690     my $sth =
691       $dbh->prepare(
692 "select password,cardnumber,borrowernumber,userid,firstname,surname,branchcode,flags from borrowers where userid=?"
693       );
694     $sth->execute($userid);
695     if ( $sth->rows ) {
696         my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
697             $surname, $branchcode, $flags )
698           = $sth->fetchrow;
699         if ( md5_base64($password) eq $md5password ) {
700
701             C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
702                 $firstname, $surname, $branchcode, $flags );
703             return 1, $cardnumber;
704         }
705     }
706     $sth =
707       $dbh->prepare(
708 "select password,cardnumber,borrowernumber,userid, firstname,surname,branchcode,flags from borrowers where cardnumber=?"
709       );
710     $sth->execute($userid);
711     if ( $sth->rows ) {
712         my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
713             $surname, $branchcode, $flags )
714           = $sth->fetchrow;
715         if ( md5_base64($password) eq $md5password ) {
716
717             C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
718                 $firstname, $surname, $branchcode, $flags );
719             return 1, $userid;
720         }
721     }
722     if (   $userid && $userid eq C4::Context->config('user')
723         && "$password" eq C4::Context->config('pass') )
724     {
725
726 # Koha superuser account
727 #               C4::Context->set_userenv(0,0,C4::Context->config('user'),C4::Context->config('user'),C4::Context->config('user'),"",1);
728         return 2;
729     }
730     if (   $userid && $userid eq 'demo'
731         && "$password" eq 'demo'
732         && C4::Context->config('demo') )
733     {
734
735 # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
736 # some features won't be effective : modify systempref, modify MARC structure,
737         return 2;
738     }
739     return 0;
740 }
741
742 sub getuserflags {
743     my $cardnumber = shift;
744     my $dbh        = shift;
745     my $userflags;
746     my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE cardnumber=?");
747     $sth->execute($cardnumber);
748     my ($flags) = $sth->fetchrow;
749     $flags = 0 unless $flags;
750     $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
751     $sth->execute;
752
753     while ( my ( $bit, $flag, $defaulton ) = $sth->fetchrow ) {
754         if ( ( $flags & ( 2**$bit ) ) || $defaulton ) {
755             $userflags->{$flag} = 1;
756         }
757         else {
758             $userflags->{$flag} = 0;
759         }
760     }
761     return $userflags;
762 }
763
764 sub haspermission {
765     my ( $dbh, $userid, $flagsrequired ) = @_;
766     my $sth = $dbh->prepare("SELECT cardnumber FROM borrowers WHERE userid=?");
767     $sth->execute($userid);
768     my ($cardnumber) = $sth->fetchrow;
769     ($cardnumber) || ( $cardnumber = $userid );
770     my $flags = getuserflags( $cardnumber, $dbh );
771     my $configfile;
772     if ( $userid eq C4::Context->config('user') ) {
773
774         # Super User Account from /etc/koha.conf
775         $flags->{'superlibrarian'} = 1;
776     }
777     if ( $userid eq 'demo' && C4::Context->config('demo') ) {
778
779         # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
780         $flags->{'superlibrarian'} = 1;
781     }
782     return $flags if $flags->{superlibrarian};
783     foreach ( keys %$flagsrequired ) {
784         return $flags if $flags->{$_};
785     }
786     return 0;
787 }
788
789 sub getborrowernumber {
790     my ($userid) = @_;
791     my $dbh = C4::Context->dbh;
792     for my $field ( 'userid', 'cardnumber' ) {
793         my $sth =
794           $dbh->prepare("select borrowernumber from borrowers where $field=?");
795         $sth->execute($userid);
796         if ( $sth->rows ) {
797             my ($bnumber) = $sth->fetchrow;
798             return $bnumber;
799         }
800     }
801     return 0;
802 }
803
804 END { }    # module clean-up code here (global destructor)
805 1;
806 __END__
807
808 =back
809
810 =head1 SEE ALSO
811
812 CGI(3)
813
814 C4::Output(3)
815
816 Digest::MD5(3)
817
818 =cut