bugfixing request.pl
[koha.git] / C4 / Auth.pm
1
2 # -*- tab-width: 8 -*-
3 # NOTE: This file uses 8-character tabs; do not change the tab size!
4
5 package C4::Auth;
6
7 # Copyright 2000-2002 Katipo Communications
8 #
9 # This file is part of Koha.
10 #
11 # Koha is free software; you can redistribute it and/or modify it under the
12 # terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
14 # version.
15 #
16 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
17 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License along with
21 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
22 # Suite 330, Boston, MA  02111-1307 USA
23
24 use strict;
25 use Digest::MD5 qw(md5_base64);
26 use CGI::Session;
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 vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap);
37
38 BEGIN {
39         $VERSION = 3.01;        # set version for version checking
40         $debug = $ENV{DEBUG} || 0 ;
41         @ISA   = qw(Exporter);
42         @EXPORT    = qw(&checkauth &get_template_and_user);
43         @EXPORT_OK = qw(&check_api_auth &get_session &check_cookie_auth &checkpw);
44         $ldap = C4::Context->config('useldapserver') || 0;
45         if ($ldap) {
46                 require C4::Auth_with_ldap;             # no import
47                 import  C4::Auth_with_ldap qw(checkpw_ldap);
48         }
49 }
50
51 =head1 NAME
52
53 C4::Auth - Authenticates Koha users
54
55 =head1 SYNOPSIS
56
57   use CGI;
58   use C4::Auth;
59
60   my $query = new CGI;
61
62   my ($template, $borrowernumber, $cookie) 
63     = get_template_and_user(
64         {
65             template_name   => "opac-main.tmpl",
66             query           => $query,
67       type            => "opac",
68       authnotrequired => 1,
69       flagsrequired   => {borrow => 1},
70   }
71     );
72
73   print $query->header(
74     -type => 'utf-8',
75     -cookie => $cookie
76   ), $template->output;
77
78
79 =head1 DESCRIPTION
80
81     The main function of this module is to provide
82     authentification. However the get_template_and_user function has
83     been provided so that a users login information is passed along
84     automatically. This gets loaded into the template.
85
86 =head1 FUNCTIONS
87
88 =over 2
89
90 =item get_template_and_user
91
92         my ($template, $borrowernumber, $cookie)
93                 = get_template_and_user(
94                   {
95                         template_name   => "opac-main.tmpl",
96                         query           => $query,
97                         type            => "opac",
98                         authnotrequired => 1,
99                         flagsrequired   => {borrow => 1},
100                   }
101                 );
102
103     This call passes the C<query>, C<flagsrequired> and C<authnotrequired>
104     to C<&checkauth> (in this module) to perform authentification.
105     See C<&checkauth> for an explanation of these parameters.
106
107     The C<template_name> is then used to find the correct template for
108     the page. The authenticated users details are loaded onto the
109     template in the HTML::Template LOOP variable C<USER_INFO>. Also the
110     C<sessionID> is passed to the template. This can be used in templates
111     if cookies are disabled. It needs to be put as and input to every
112     authenticated page.
113
114     More information on the C<gettemplate> sub can be found in the
115     Output.pm module.
116
117 =cut
118
119 sub get_template_and_user {
120     my $in       = shift;
121     my $template =
122       gettemplate( $in->{'template_name'}, $in->{'type'}, $in->{'query'} );
123     my ( $user, $cookie, $sessionID, $flags ) = checkauth(
124         $in->{'query'},
125         $in->{'authnotrequired'},
126         $in->{'flagsrequired'},
127         $in->{'type'}
128     ) unless ($in->{'template_name'}=~/maintenance/);
129
130     my $borrowernumber;
131     my $insecure = C4::Context->preference('insecure');
132     if ($user or $insecure) {
133
134                 # load the template variables for stylesheets and JavaScript
135                 $template->param( css_libs => $in->{'css_libs'} );
136                 $template->param( css_module => $in->{'css_module'} );
137                 $template->param( css_page => $in->{'css_page'} );
138                 $template->param( css_widgets => $in->{'css_widgets'} );
139
140         $template->param( js_libs => $in->{'js_libs'} );
141         $template->param( js_module => $in->{'js_module'} );
142         $template->param( js_page => $in->{'js_page'} );
143         $template->param( js_widgets => $in->{'js_widgets'} );
144
145                 # user info
146         $template->param( loggedinusername => $user );
147         $template->param( sessionID        => $sessionID );
148
149         $borrowernumber = getborrowernumber($user);
150         my ( $borr, $alternativeflags ) =
151           GetMemberDetails( $borrowernumber );
152         my @bordat;
153         $bordat[0] = $borr;
154         $template->param( "USER_INFO" => \@bordat );
155
156                 my @flagroots = qw(circulate catalogue parameters borrowers permissions reserveforothers borrow
157                                                         editcatalogue updatecharge management tools editauthorities serials reports);
158         # We are going to use the $flags returned by checkauth
159         # to create the template's parameters that will indicate
160         # which menus the user can access.
161         if (( $flags && $flags->{superlibrarian}==1) or $insecure==1) {
162             $template->param( CAN_user_circulate        => 1 );
163             $template->param( CAN_user_catalogue        => 1 );
164             $template->param( CAN_user_parameters       => 1 );
165             $template->param( CAN_user_borrowers        => 1 );
166             $template->param( CAN_user_permission       => 1 );
167             $template->param( CAN_user_reserveforothers => 1 );
168             $template->param( CAN_user_borrow           => 1 );
169             $template->param( CAN_user_editcatalogue    => 1 );
170             $template->param( CAN_user_updatecharge     => 1 );
171             $template->param( CAN_user_acquisition      => 1 );
172             $template->param( CAN_user_management       => 1 );
173             $template->param( CAN_user_tools            => 1 ); 
174             $template->param( CAN_user_editauthorities  => 1 );
175             $template->param( CAN_user_serials          => 1 );
176             $template->param( CAN_user_reports          => 1 );
177             $template->param( CAN_user_staffaccess              => 1 );
178         }
179
180         if ( $flags && $flags->{circulate} == 1 ) {
181             $template->param( CAN_user_circulate => 1 );
182         }
183
184         if ( $flags && $flags->{catalogue} == 1 ) {
185             $template->param( CAN_user_catalogue => 1 );
186         }
187
188         if ( $flags && $flags->{parameters} == 1 ) {
189             $template->param( CAN_user_parameters => 1 );
190             $template->param( CAN_user_management => 1 );
191         }
192
193         if ( $flags && $flags->{borrowers} == 1 ) {
194             $template->param( CAN_user_borrowers => 1 );
195         }
196
197         if ( $flags && $flags->{permissions} == 1 ) {
198             $template->param( CAN_user_permission => 1 );
199         }
200
201         if ( $flags && $flags->{reserveforothers} == 1 ) {
202             $template->param( CAN_user_reserveforothers => 1 );
203         }
204
205         if ( $flags && $flags->{borrow} == 1 ) {
206             $template->param( CAN_user_borrow => 1 );
207         }
208
209         if ( $flags && $flags->{editcatalogue} == 1 ) {
210             $template->param( CAN_user_editcatalogue => 1 );
211         }
212
213         if ( $flags && $flags->{updatecharges} == 1 ) {
214             $template->param( CAN_user_updatecharge => 1 );
215         }
216
217         if ( $flags && $flags->{acquisition} == 1 ) {
218             $template->param( CAN_user_acquisition => 1 );
219         }
220
221         if ( $flags && $flags->{tools} == 1 ) {
222             $template->param( CAN_user_tools => 1 );
223         }
224   
225         if ( $flags && $flags->{editauthorities} == 1 ) {
226             $template->param( CAN_user_editauthorities => 1 );
227         }
228     
229         if ( $flags && $flags->{serials} == 1 ) {
230             $template->param( CAN_user_serials => 1 );
231         }
232
233         if ( $flags && $flags->{reports} == 1 ) {
234             $template->param( CAN_user_reports => 1 );
235         }
236         if ( $flags && $flags->{staffaccess} == 1 ) {
237             $template->param( CAN_user_staffaccess => 1 );
238         }
239     }
240     if ( $in->{'type'} eq "intranet" ) {
241         $template->param(
242             intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
243             intranetstylesheet => C4::Context->preference("intranetstylesheet"),
244             IntranetNav        => C4::Context->preference("IntranetNav"),
245             intranetuserjs     => C4::Context->preference("intranetuserjs"),
246             TemplateEncoding   => C4::Context->preference("TemplateEncoding"),
247             AmazonContent      => C4::Context->preference("AmazonContent"),
248             LibraryName        => C4::Context->preference("LibraryName"),
249             LoginBranchcode    => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
250             LoginBranchname    => (C4::Context->userenv?C4::Context->userenv->{"branchname"}:"insecure"),
251             LoginFirstname     => (C4::Context->userenv?C4::Context->userenv->{"firstname"}:"Bel"),
252             LoginSurname       => C4::Context->userenv?C4::Context->userenv->{"surname"}:"Inconnu", 
253             AutoLocation       => C4::Context->preference("AutoLocation"),
254             hide_marc          => C4::Context->preference("hide_marc"),
255             patronimages       => C4::Context->preference("patronimages"),
256             "BiblioDefaultView".C4::Context->preference("IntranetBiblioDefaultView") => 1,
257             advancedMARCEditor      => C4::Context->preference("advancedMARCEditor"),
258             suggestion              => C4::Context->preference("suggestion"),
259             virtualshelves          => C4::Context->preference("virtualshelves"),
260             LibraryName             => C4::Context->preference("LibraryName"),
261             KohaAdminEmailAddress   => "" . C4::Context->preference("KohaAdminEmailAddress"),
262             IntranetmainUserblock       => C4::Context->preference("IntranetmainUserblock"),
263             IndependantBranches     => C4::Context->preference("IndependantBranches"),
264                         CircAutocompl => C4::Context->preference("CircAutocompl"),
265                         yuipath => C4::Context->preference("yuipath"),
266                         FRBRizeEditions => C4::Context->preference("FRBRizeEditions"),
267                         AmazonSimilarItems => C4::Context->preference("AmazonSimilarItems"),
268                         'item-level_itypes' => C4::Context->preference('item-level_itypes'),
269                         canreservefromotherbranches => C4::Context->preference('canreservefromotherbranches'),
270         );
271     }
272     else {
273         warn "template type should be OPAC, here it is=[" . $in->{'type'} . "]" unless ( $in->{'type'} eq 'opac' );
274         my $LibraryNameTitle = C4::Context->preference("LibraryName");
275         $LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi;
276         $LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg;
277   $template->param(
278             KohaAdminEmailAddress  => "" . C4::Context->preference("KohaAdminEmailAddress"),
279                         AnonSuggestions =>  "" . C4::Context->preference("AnonSuggestions"),
280             suggestion             => "" . C4::Context->preference("suggestion"),
281             virtualshelves         => "" . C4::Context->preference("virtualshelves"),
282             OpacNav                => "" . C4::Context->preference("OpacNav"),
283             opacheader             => "" . C4::Context->preference("opacheader"),
284             opaccredits            => "" . C4::Context->preference("opaccredits"),
285             opacsmallimage         => "" . C4::Context->preference("opacsmallimage"),
286             opaclargeimage         => "" . C4::Context->preference("opaclargeimage"),
287             opaclayoutstylesheet   => "". C4::Context->preference("opaclayoutstylesheet"),
288             opaccolorstylesheet    => "". C4::Context->preference("opaccolorstylesheet"),
289             opaclanguagesdisplay   => "". C4::Context->preference("opaclanguagesdisplay"),
290             opacuserlogin          => "" . C4::Context->preference("opacuserlogin"),
291             opacbookbag            => "" . C4::Context->preference("opacbookbag"),
292             TemplateEncoding       => "". C4::Context->preference("TemplateEncoding"),
293             AmazonContent          => "" . C4::Context->preference("AmazonContent"),
294             LibraryName            => "" . C4::Context->preference("LibraryName"),
295             LibraryNameTitle       => "" . $LibraryNameTitle,
296             LoginBranchcode        => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
297             LoginBranchname        => C4::Context->userenv?C4::Context->userenv->{"branchname"}:"", 
298             LoginFirstname        => (C4::Context->userenv?C4::Context->userenv->{"firstname"}:"Bel"),
299             LoginSurname        => C4::Context->userenv?C4::Context->userenv->{"surname"}:"Inconnu", 
300             OpacPasswordChange     => C4::Context->preference("OpacPasswordChange"),
301             opacreadinghistory     => C4::Context->preference("opacreadinghistory"),
302             opacuserjs             => C4::Context->preference("opacuserjs"),
303             OpacCloud              => C4::Context->preference("OpacCloud"),
304             OpacTopissue           => C4::Context->preference("OpacTopissue"),
305             OpacAuthorities        => C4::Context->preference("OpacAuthorities"),
306             OpacBrowser            => C4::Context->preference("OpacBrowser"),
307             RequestOnOpac          => C4::Context->preference("RequestOnOpac"),
308             reviewson              => C4::Context->preference("reviewson"),
309             hide_marc              => C4::Context->preference("hide_marc"),
310             patronimages           => C4::Context->preference("patronimages"),
311             mylibraryfirst   => C4::Context->preference("SearchMyLibraryFirst"),
312             "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
313                         OPACFRBRizeEditions => C4::Context->preference("OPACFRBRizeEditions"),
314                         'item-level_itypes' => C4::Context->preference('item-level_itypes'),
315         );
316     }
317     return ( $template, $borrowernumber, $cookie, $flags);
318 }
319
320 =item checkauth
321
322   ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
323
324 Verifies that the user is authorized to run this script.  If
325 the user is authorized, a (userid, cookie, session-id, flags)
326 quadruple is returned.  If the user is not authorized but does
327 not have the required privilege (see $flagsrequired below), it
328 displays an error page and exits.  Otherwise, it displays the
329 login page and exits.
330
331 Note that C<&checkauth> will return if and only if the user
332 is authorized, so it should be called early on, before any
333 unfinished operations (e.g., if you've opened a file, then
334 C<&checkauth> won't close it for you).
335
336 C<$query> is the CGI object for the script calling C<&checkauth>.
337
338 The C<$noauth> argument is optional. If it is set, then no
339 authorization is required for the script.
340
341 C<&checkauth> fetches user and session information from C<$query> and
342 ensures that the user is authorized to run scripts that require
343 authorization.
344
345 The C<$flagsrequired> argument specifies the required privileges
346 the user must have if the username and password are correct.
347 It should be specified as a reference-to-hash; keys in the hash
348 should be the "flags" for the user, as specified in the Members
349 intranet module. Any key specified must correspond to a "flag"
350 in the userflags table. E.g., { circulate => 1 } would specify
351 that the user must have the "circulate" privilege in order to
352 proceed. To make sure that access control is correct, the
353 C<$flagsrequired> parameter must be specified correctly.
354
355 The C<$type> argument specifies whether the template should be
356 retrieved from the opac or intranet directory tree.  "opac" is
357 assumed if it is not specified; however, if C<$type> is specified,
358 "intranet" is assumed if it is not "opac".
359
360 If C<$query> does not have a valid session ID associated with it
361 (i.e., the user has not logged in) or if the session has expired,
362 C<&checkauth> presents the user with a login page (from the point of
363 view of the original script, C<&checkauth> does not return). Once the
364 user has authenticated, C<&checkauth> restarts the original script
365 (this time, C<&checkauth> returns).
366
367 The login page is provided using a HTML::Template, which is set in the
368 systempreferences table or at the top of this file. The variable C<$type>
369 selects which template to use, either the opac or the intranet 
370 authentification template.
371
372 C<&checkauth> returns a user ID, a cookie, and a session ID. The
373 cookie should be sent back to the browser; it verifies that the user
374 has authenticated.
375
376 =cut
377
378 sub _version_check ($$) {
379     my $type = shift;
380     my $query = shift;
381         my $version;
382     # If Version syspref is unavailable, it means Koha is beeing installed,
383     # and so we must redirect to OPAC maintenance page or to the WebInstaller
384     #warn "about to check version";
385     unless ($version = C4::Context->preference('Version')) {    # assignment, not comparison
386       if ($type ne 'opac') {
387         warn "Install required, redirecting to Installer";
388         print $query->redirect("/cgi-bin/koha/installer/install.pl");
389       } 
390       else {
391         warn "OPAC Install required, redirecting to maintenance";
392         print $query->redirect("/cgi-bin/koha/maintenance.pl");
393       }
394       exit;
395     }
396
397         # check that database and koha version are the same
398         # there is no DB version, it's a fresh install,
399         # go to web installer
400         # there is a DB version, compare it to the code version
401         my $kohaversion=C4::Context::KOHAVERSION;
402         # remove the 3 last . to have a Perl number
403         $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
404         $debug and print STDERR "kohaversion : $kohaversion\n";
405         if ($version < $kohaversion){
406                 my $warning = "Database update needed, redirecting to %s. Database is $version and Koha is "
407                         . C4::Context->config("kohaversion");
408                 if ($type ne 'opac'){
409                         warn sprintf($warning, 'Installer');
410                         print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3");
411                 } else {
412                         warn sprintf("OPAC: " . $warning, 'maintenance');
413                         print $query->redirect("/cgi-bin/koha/maintenance.pl");
414                 }       
415                 exit;
416         }
417 }
418
419 sub _session_log {
420         (@_) or return 0;
421         open L, ">>/tmp/sessionlog";
422         printf L join("\n",@_);
423         close L;
424 }
425
426 sub checkauth {
427     my $query = shift;
428   # warn "Checking Auth";
429     # $authnotrequired will be set for scripts which will run without authentication
430     my $authnotrequired = shift;
431     my $flagsrequired   = shift;
432     my $type            = shift;
433     $type = 'opac' unless $type;
434
435     my $dbh     = C4::Context->dbh;
436     my $timeout = C4::Context->preference('timeout');
437         # days
438         if ($timeout =~ /(\d+)[dD]/) {
439                 $timeout = $1 * 86400;
440     };
441         $timeout = 600 unless $timeout;
442
443         _version_check($type,$query);
444     # state variables
445     my $loggedin = 0;
446     my %info;
447     my ( $userid, $cookie, $sessionID, $flags );
448     my $logout = $query->param('logout.x');
449     if ( $userid = $ENV{'REMOTE_USER'} ) {
450         # Using Basic Authentication, no cookies required
451         $cookie = $query->cookie(
452             -name    => 'CGISESSID',
453             -value   => '',
454             -expires => ''
455         );
456         $loggedin = 1;
457     }
458     elsif ( $sessionID = $query->cookie("CGISESSID")) {         # assignment, not comparison (?)
459         my $session = get_session($sessionID);
460         C4::Context->_new_userenv($sessionID);
461         if ($session){
462             C4::Context::set_userenv(
463                 $session->param('number'),       $session->param('id'),
464                 $session->param('cardnumber'),   $session->param('firstname'),
465                 $session->param('surname'),      $session->param('branch'),
466                 $session->param('branchname'),   $session->param('flags'),
467                 $session->param('emailaddress'), $session->param('branchprinter')
468             );
469                         $debug and printf STDERR "AUTH_SESSION: (%s)\t%s %s - %s\n", map {$session->param($_)} qw(cardnumber firstname surname branch) ;
470         }
471         my $ip;
472         my $lasttime;
473         if ($session) {
474                         $ip = $session->param('ip');
475                         $lasttime = $session->param('lasttime');
476                         $userid = $session->param('id');
477         }
478     
479         if ($logout) {
480             # voluntary logout the user
481             $session->flush;      
482                         $session->delete();
483             C4::Context->_unset_userenv($sessionID);
484             $sessionID = undef;
485             $userid    = undef;
486             _session_log(sprintf "%20s from %16s logged out at %30s (manually).\n", $userid,$ip,localtime);
487         }
488         if ($userid) {
489             if ( $lasttime < time() - $timeout ) {
490                 # timed logout
491                 $info{'timed_out'} = 1;
492                 $session->delete();
493                 C4::Context->_unset_userenv($sessionID);
494                 $userid    = undef;
495                 $sessionID = undef;
496                 _session_log(sprintf "%20s from %16s logged out at %30s (inactivity).\n", $userid,$ip,localtime);
497             }
498             elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
499                 # Different ip than originally logged in from
500                 $info{'oldip'}        = $ip;
501                 $info{'newip'}        = $ENV{'REMOTE_ADDR'};
502                 $info{'different_ip'} = 1;
503                                 $session->delete();
504                 C4::Context->_unset_userenv($sessionID);
505                 $sessionID = undef;
506                 $userid    = undef;
507                 _session_log(sprintf "%20s from %16s logged out at %30s (ip changed to %16s).\n", $userid,$ip,localtime, $info{'newip'});
508             }
509             else {
510                 $cookie = $query->cookie( CGISESSID => $session->id );
511                 $session->param('lasttime',time());
512                 $flags = haspermission( $dbh, $userid, $flagsrequired );
513                 if ($flags) {
514                     $loggedin = 1;
515                 }
516                 else {
517                     $info{'nopermission'} = 1;
518                 }
519             }
520         }
521     }
522     unless ($userid) {
523                 my $session = get_session("");
524         my $sessionID;
525                 if ($session) {
526                         $sessionID = $session->id;
527                 }
528         $userid    = $query->param('userid');
529         C4::Context->_new_userenv($sessionID);
530         my $password = $query->param('password');
531         C4::Context->_new_userenv($sessionID);
532         my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
533         if ($return) {
534             _session_log(sprintf "%20s from %16s logged in  at %30s.\n", $userid,$ENV{'REMOTE_ADDR'},localtime);
535             $cookie = $query->cookie(CGISESSID => $sessionID);
536             if ( $flags = haspermission( $dbh, $userid, $flagsrequired ) ) {
537                 $loggedin = 1;
538             }
539             else {
540                 $info{'nopermission'} = 1;
541                 C4::Context->_unset_userenv($sessionID);
542             }
543             if ( $return == 1 ) {
544                 my (
545                    $borrowernumber, $firstname, $surname, $userflags,
546                    $branchcode, $branchname, $branchprinter, $emailaddress
547                 );
548                                 my $select = "
549                                 SELECT borrowernumber, firstname, surname, flags, borrowers.branchcode, 
550                                                 branches.branchname    as branchname, 
551                                                 branches.branchprinter as branchprinter, 
552                                                 email 
553                                 FROM borrowers 
554                                 LEFT JOIN branches on borrowers.branchcode=branches.branchcode
555                                 ";
556                 my $sth = $dbh->prepare("$select where userid=?");
557                 $sth->execute($userid);
558                                 ($sth->rows) and (
559                                         $borrowernumber, $firstname, $surname, $userflags,
560                                         $branchcode, $branchname, $branchprinter, $emailaddress
561                                 ) = $sth->fetchrow;
562
563                                 $debug and print STDERR "AUTH_1: $cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress\n";
564                 unless ( $sth->rows ) {
565                     my $sth = $dbh->prepare("$select where cardnumber=?");
566                                         $sth->execute($cardnumber);
567                                         ($sth->rows) and (
568                                                 $borrowernumber, $firstname, $surname, $userflags,
569                                                 $branchcode, $branchname, $branchprinter, $emailaddress
570                                         ) = $sth->fetchrow;
571
572                                         $debug and print STDERR "AUTH_2: $cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress\n";
573                     unless ( $sth->rows ) {
574                         $sth->execute($userid);
575                                                 ($sth->rows) and (
576                                                         $borrowernumber, $firstname, $surname, $userflags,
577                                                         $branchcode, $branchname, $branchprinter, $emailaddress
578                                                 ) = $sth->fetchrow;
579                     }
580                 }
581
582 # launch a sequence to check if we have a ip for the branch, i
583 # if we have one we replace the branchcode of the userenv by the branch bound in the ip.
584
585                 my $ip       = $ENV{'REMOTE_ADDR'};
586                 # if they specify at login, use that
587                 if ($query->param('branch')) {
588                     $branchcode  = $query->param('branch');
589                     $branchname = GetBranchName($branchcode);
590                 }
591                 my $branches = GetBranches();
592                 my @branchesloop;
593                 foreach my $br ( keys %$branches ) {
594                     #     now we work with the treatment of ip
595                     my $domain = $branches->{$br}->{'branchip'};
596                     if ( $domain && $ip =~ /^$domain/ ) {
597                         $branchcode = $branches->{$br}->{'branchcode'};
598
599                         # new op dev : add the branchprinter and branchname in the cookie
600                         $branchprinter = $branches->{$br}->{'branchprinter'};
601                         $branchname    = $branches->{$br}->{'branchname'};
602                     }
603                 }
604                 $session->param('number',$borrowernumber);
605                 $session->param('id',$userid);
606                 $session->param('cardnumber',$cardnumber);
607                 $session->param('firstname',$firstname);
608                 $session->param('surname',$surname);
609                 $session->param('branch',$branchcode);
610                 $session->param('branchname',$branchname);
611                 $session->param('flags',$userflags);
612                 $session->param('emailaddress',$emailaddress);
613                 $session->param('ip',$session->remote_addr());
614                 $session->param('lasttime',time());
615                                 $debug and printf STDERR "AUTH_3: (%s)\t%s %s - %s\n", map {$session->param($_)} qw(cardnumber firstname surname branch) ;
616             }
617             elsif ( $return == 2 ) {
618                 #We suppose the user is the superlibrarian
619                                 $session->param('number',0);
620                                 $session->param('id',C4::Context->config('user'));
621                                 $session->param('cardnumber',C4::Context->config('user'));
622                                 $session->param('firstname',C4::Context->config('user'));
623                                 $session->param('surname',C4::Context->config('user'));
624                                 $session->param('branch','NO_LIBRARY_SET');
625                                 $session->param('branchname','NO_LIBRARY_SET');
626                                 $session->param('flags',1);
627                                 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
628                                 $session->param('ip',$session->remote_addr());
629                                 $session->param('lasttime',time());
630                         }
631                         if ($session) {
632                                 C4::Context::set_userenv(
633                                 $session->param('number'),       $session->param('id'),
634                                 $session->param('cardnumber'),   $session->param('firstname'),
635                                 $session->param('surname'),      $session->param('branch'),
636                                 $session->param('branchname'),   $session->param('flags'),
637                                 $session->param('emailaddress'), $session->param('branchprinter')
638                                 );
639                         }
640         }
641         else {
642             if ($userid) {
643                 $info{'invalid_username_or_password'} = 1;
644                 C4::Context->_unset_userenv($sessionID);
645             }
646         }
647     }
648     my $insecure = C4::Context->boolean_preference('insecure');
649
650     # finished authentification, now respond
651     if ( $loggedin || $authnotrequired || ( defined($insecure) && $insecure ) )
652     {
653         # successful login
654         unless ($cookie) {
655             $cookie = $query->cookie( CGISESSID => '' );
656         }
657         return ( $userid, $cookie, $sessionID, $flags );
658     }
659
660 #
661 #
662 # AUTH rejected, show the login/password template, after checking the DB.
663 #
664 #
665     
666     # get the inputs from the incoming query
667     my @inputs = ();
668     foreach my $name ( param $query) {
669         (next) if ( $name eq 'userid' || $name eq 'password' );
670         my $value = $query->param($name);
671         push @inputs, { name => $name, value => $value };
672     }
673     # get the branchloop, which we need for authentication
674     my $branches = GetBranches();
675     my @branch_loop;
676     for my $branch_hash (keys %$branches) {
677                 push @branch_loop, {branchcode => "$branch_hash", branchname => $branches->{$branch_hash}->{'branchname'}, };
678     }
679
680     my $template_name = ( $type eq 'opac' ) ? 'opac-auth.tmpl' : 'auth.tmpl';
681     my $template = gettemplate( $template_name, $type, $query );
682     $template->param(branchloop => \@branch_loop,);
683     $template->param(
684     login        => 1,
685         INPUTS               => \@inputs,
686         suggestion           => C4::Context->preference("suggestion"),
687         virtualshelves       => C4::Context->preference("virtualshelves"),
688         opaclargeimage       => C4::Context->preference("opaclargeimage"),
689         LibraryName          => C4::Context->preference("LibraryName"),
690         OpacNav              => C4::Context->preference("OpacNav"),
691         opaccredits          => C4::Context->preference("opaccredits"),
692         opacreadinghistory   => C4::Context->preference("opacreadinghistory"),
693         opacsmallimage       => C4::Context->preference("opacsmallimage"),
694         opaclayoutstylesheet => C4::Context->preference("opaclayoutstylesheet"),
695         opaccolorstylesheet  => C4::Context->preference("opaccolorstylesheet"),
696         opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
697         opacuserjs           => C4::Context->preference("opacuserjs"),
698
699         intranetcolorstylesheet =>
700           C4::Context->preference("intranetcolorstylesheet"),
701         intranetstylesheet => C4::Context->preference("intranetstylesheet"),
702         IntranetNav        => C4::Context->preference("IntranetNav"),
703         intranetuserjs     => C4::Context->preference("intranetuserjs"),
704         TemplateEncoding   => C4::Context->preference("TemplateEncoding"),
705         IndependantBranches     => C4::Context->preference("IndependantBranches"),
706                 AutoLocation       => C4::Context->preference("AutoLocation"),
707                 yuipath            => C4::Context->preference("yuipath"),
708     );
709     $template->param( loginprompt => 1 ) unless $info{'nopermission'};
710
711     my $self_url = $query->url( -absolute => 1 );
712     $template->param(
713         url         => $self_url,
714         LibraryName => => C4::Context->preference("LibraryName"),
715     );
716     $template->param( \%info );
717 #    $cookie = $query->cookie(CGISESSID => $session->id
718 #   );
719     print $query->header(
720                 -type   => 'text/html',
721         -charset => 'utf-8',
722         -cookie => $cookie
723       ),
724       $template->output;
725     exit;
726 }
727
728 =item check_api_auth
729
730   ($status, $cookie, $sessionId) = check_api_auth($query, $userflags);
731
732 Given a CGI query containing the parameters 'userid' and 'password' and/or a session
733 cookie, determine if the user has the privileges specified by C<$userflags>.
734
735 C<check_api_auth> is is meant for authenticating users of web services, and
736 consequently will always return and will not attempt to redirect the user
737 agent.
738
739 If a valid session cookie is already present, check_api_auth will return a status
740 of "ok", the cookie, and the Koha session ID.
741
742 If no session cookie is present, check_api_auth will check the 'userid' and 'password
743 parameters and create a session cookie and Koha session if the supplied credentials
744 are OK.
745
746 Possible return values in C<$status> are:
747
748 =over 4
749
750 =item "ok" -- user authenticated; C<$cookie> and C<$sessionid> have valid values.
751
752 =item "failed" -- credentials are not correct; C<$cookie> and C<$sessionid> are undef
753
754 =item "maintenance" -- DB is in maintenance mode; no login possible at the moment
755
756 =item "expired -- session cookie has expired; API user should resubmit userid and password
757
758 =back
759
760 =cut
761
762 sub check_api_auth {
763     my $query = shift;
764     my $flagsrequired = shift;
765
766     my $dbh     = C4::Context->dbh;
767     my $timeout = C4::Context->preference('timeout');
768     $timeout = 600 unless $timeout;
769
770     unless (C4::Context->preference('Version')) {
771         # database has not been installed yet
772         return ("maintenance", undef, undef);
773     }
774     my $kohaversion=C4::Context::KOHAVERSION;
775     $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
776     if (C4::Context->preference('Version') < $kohaversion) {
777         # database in need of version update; assume that
778         # no API should be called while databsae is in
779         # this condition.
780         return ("maintenance", undef, undef);
781     }
782
783     # FIXME -- most of what follows is a copy-and-paste
784     # of code from checkauth.  There is an obvious need
785     # for refactoring to separate the various parts of
786     # the authentication code, but as of 2007-11-19 this
787     # is deferred so as to not introduce bugs into the
788     # regular authentication code for Koha 3.0.
789
790     # see if we have a valid session cookie already
791     # however, if a userid parameter is present (i.e., from
792     # a form submission, assume that any current cookie
793     # is to be ignored
794     my $sessionID = undef;
795     unless ($query->param('userid')) {
796         $sessionID = $query->cookie("CGISESSID");
797     }
798     if ($sessionID) {
799         my $session = get_session($sessionID);
800         C4::Context->_new_userenv($sessionID);
801         if ($session) {
802             C4::Context::set_userenv(
803                 $session->param('number'),       $session->param('id'),
804                 $session->param('cardnumber'),   $session->param('firstname'),
805                 $session->param('surname'),      $session->param('branch'),
806                 $session->param('branchname'),   $session->param('flags'),
807                 $session->param('emailaddress'), $session->param('branchprinter')
808             );
809
810             my $ip = $session->param('ip');
811             my $lasttime = $session->param('lasttime');
812             my $userid = $session->param('id');
813             if ( $lasttime < time() - $timeout ) {
814                 # time out
815                 $session->delete();
816                 C4::Context->_unset_userenv($sessionID);
817                 $userid    = undef;
818                 $sessionID = undef;
819                 return ("expired", undef, undef);
820             } elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
821                 # IP address changed
822                 $session->delete();
823                 C4::Context->_unset_userenv($sessionID);
824                 $userid    = undef;
825                 $sessionID = undef;
826                 return ("expired", undef, undef);
827             } else {
828                 my $cookie = $query->cookie( CGISESSID => $session->id );
829                 $session->param('lasttime',time());
830                 my $flags = haspermission( $dbh, $userid, $flagsrequired );
831                 if ($flags) {
832                     return ("ok", $cookie, $sessionID);
833                 } else {
834                     $session->delete();
835                     C4::Context->_unset_userenv($sessionID);
836                     $userid    = undef;
837                     $sessionID = undef;
838                     return ("failed", undef, undef);
839                 }
840             }
841         } else {
842             return ("expired", undef, undef);
843         }
844     } else {
845         # new login
846         my $userid = $query->param('userid');   
847         my $password = $query->param('password');   
848         unless ($userid and $password) {
849             # caller did something wrong, fail the authenticateion
850             return ("failed", undef, undef);
851         }
852         my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
853         if ($return and haspermission( $dbh, $userid, $flagsrequired)) {
854             my $session = get_session("");
855             return ("failed", undef, undef) unless $session;
856
857             my $sessionID = $session->id;
858             C4::Context->_new_userenv($sessionID);
859             my $cookie = $query->cookie(CGISESSID => $sessionID);
860             if ( $return == 1 ) {
861                 my (
862                     $borrowernumber, $firstname,  $surname,
863                     $userflags,      $branchcode, $branchname,
864                     $branchprinter,  $emailaddress
865                 );
866                 my $sth =
867                   $dbh->prepare(
868 "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=?"
869                   );
870                 $sth->execute($userid);
871                 (
872                     $borrowernumber, $firstname,  $surname,
873                     $userflags,      $branchcode, $branchname,
874                     $branchprinter,  $emailaddress
875                 ) = $sth->fetchrow if ( $sth->rows );
876
877                 unless ($sth->rows ) {
878                     my $sth = $dbh->prepare(
879 "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=?"
880                       );
881                     $sth->execute($cardnumber);
882                     (
883                         $borrowernumber, $firstname,  $surname,
884                         $userflags,      $branchcode, $branchname,
885                         $branchprinter,  $emailaddress
886                     ) = $sth->fetchrow if ( $sth->rows );
887
888                     unless ( $sth->rows ) {
889                         $sth->execute($userid);
890                         (
891                             $borrowernumber, $firstname, $surname, $userflags,
892                             $branchcode, $branchname, $branchprinter, $emailaddress
893                         ) = $sth->fetchrow if ( $sth->rows );
894                     }
895                 }
896
897                 my $ip       = $ENV{'REMOTE_ADDR'};
898                 # if they specify at login, use that
899                 if ($query->param('branch')) {
900                     $branchcode  = $query->param('branch');
901                     $branchname = GetBranchName($branchcode);
902                 }
903                 my $branches = GetBranches();
904                 my @branchesloop;
905                 foreach my $br ( keys %$branches ) {
906                     #     now we work with the treatment of ip
907                     my $domain = $branches->{$br}->{'branchip'};
908                     if ( $domain && $ip =~ /^$domain/ ) {
909                         $branchcode = $branches->{$br}->{'branchcode'};
910
911                         # new op dev : add the branchprinter and branchname in the cookie
912                         $branchprinter = $branches->{$br}->{'branchprinter'};
913                         $branchname    = $branches->{$br}->{'branchname'};
914                     }
915                 }
916                 $session->param('number',$borrowernumber);
917                 $session->param('id',$userid);
918                 $session->param('cardnumber',$cardnumber);
919                 $session->param('firstname',$firstname);
920                 $session->param('surname',$surname);
921                 $session->param('branch',$branchcode);
922                 $session->param('branchname',$branchname);
923                 $session->param('flags',$userflags);
924                 $session->param('emailaddress',$emailaddress);
925                 $session->param('ip',$session->remote_addr());
926                 $session->param('lasttime',time());
927             } elsif ( $return == 2 ) {
928                 #We suppose the user is the superlibrarian
929                 $session->param('number',0);
930                 $session->param('id',C4::Context->config('user'));
931                 $session->param('cardnumber',C4::Context->config('user'));
932                 $session->param('firstname',C4::Context->config('user'));
933                 $session->param('surname',C4::Context->config('user'));
934                 $session->param('branch','NO_LIBRARY_SET');
935                 $session->param('branchname','NO_LIBRARY_SET');
936                 $session->param('flags',1);
937                 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
938                 $session->param('ip',$session->remote_addr());
939                 $session->param('lasttime',time());
940             } 
941             C4::Context::set_userenv(
942                 $session->param('number'),       $session->param('id'),
943                 $session->param('cardnumber'),   $session->param('firstname'),
944                 $session->param('surname'),      $session->param('branch'),
945                 $session->param('branchname'),   $session->param('flags'),
946                 $session->param('emailaddress'), $session->param('branchprinter')
947             );
948             return ("ok", $cookie, $sessionID);
949         } else {
950             return ("failed", undef, undef);
951         }
952     } 
953 }
954
955 =item check_cookie_auth
956
957   ($status, $sessionId) = check_api_auth($cookie, $userflags);
958
959 Given a CGISESSID cookie set during a previous login to Koha, determine
960 if the user has the privileges specified by C<$userflags>.
961
962 C<check_cookie_auth> is meant for authenticating special services
963 such as tools/upload-file.pl that are invoked by other pages that
964 have been authenticated in the usual way.
965
966 Possible return values in C<$status> are:
967
968 =over 4
969
970 =item "ok" -- user authenticated; C<$sessionID> have valid values.
971
972 =item "failed" -- credentials are not correct; C<$sessionid> are undef
973
974 =item "maintenance" -- DB is in maintenance mode; no login possible at the moment
975
976 =item "expired -- session cookie has expired; API user should resubmit userid and password
977
978 =back
979
980 =cut
981
982 sub check_cookie_auth {
983     my $cookie = shift;
984     my $flagsrequired = shift;
985
986     my $dbh     = C4::Context->dbh;
987     my $timeout = C4::Context->preference('timeout');
988     $timeout = 600 unless $timeout;
989
990     unless (C4::Context->preference('Version')) {
991         # database has not been installed yet
992         return ("maintenance", undef);
993     }
994     my $kohaversion=C4::Context::KOHAVERSION;
995     $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
996     if (C4::Context->preference('Version') < $kohaversion) {
997         # database in need of version update; assume that
998         # no API should be called while databsae is in
999         # this condition.
1000         return ("maintenance", undef);
1001     }
1002
1003     # FIXME -- most of what follows is a copy-and-paste
1004     # of code from checkauth.  There is an obvious need
1005     # for refactoring to separate the various parts of
1006     # the authentication code, but as of 2007-11-23 this
1007     # is deferred so as to not introduce bugs into the
1008     # regular authentication code for Koha 3.0.
1009
1010     # see if we have a valid session cookie already
1011     # however, if a userid parameter is present (i.e., from
1012     # a form submission, assume that any current cookie
1013     # is to be ignored
1014     unless (defined $cookie and $cookie) {
1015         return ("failed", undef);
1016     }
1017     my $sessionID = $cookie;
1018     my $session = get_session($sessionID);
1019     C4::Context->_new_userenv($sessionID);
1020     if ($session) {
1021         C4::Context::set_userenv(
1022             $session->param('number'),       $session->param('id'),
1023             $session->param('cardnumber'),   $session->param('firstname'),
1024             $session->param('surname'),      $session->param('branch'),
1025             $session->param('branchname'),   $session->param('flags'),
1026             $session->param('emailaddress'), $session->param('branchprinter')
1027         );
1028
1029         my $ip = $session->param('ip');
1030         my $lasttime = $session->param('lasttime');
1031         my $userid = $session->param('id');
1032         if ( $lasttime < time() - $timeout ) {
1033             # time out
1034             $session->delete();
1035             C4::Context->_unset_userenv($sessionID);
1036             $userid    = undef;
1037             $sessionID = undef;
1038             return ("expired", undef);
1039         } elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
1040             # IP address changed
1041             $session->delete();
1042             C4::Context->_unset_userenv($sessionID);
1043             $userid    = undef;
1044             $sessionID = undef;
1045             return ("expired", undef);
1046         } else {
1047             $session->param('lasttime',time());
1048             my $flags = haspermission( $dbh, $userid, $flagsrequired );
1049             if ($flags) {
1050                 return ("ok", $sessionID);
1051             } else {
1052                 $session->delete();
1053                 C4::Context->_unset_userenv($sessionID);
1054                 $userid    = undef;
1055                 $sessionID = undef;
1056                 return ("failed", undef);
1057             }
1058         }
1059     } else {
1060         return ("expired", undef);
1061     }
1062 }
1063
1064 =item get_session
1065
1066   use CGI::Session;
1067   my $session = get_session($sessionID);
1068
1069 Given a session ID, retrieve the CGI::Session object used to store
1070 the session's state.  The session object can be used to store 
1071 data that needs to be accessed by different scripts during a
1072 user's session.
1073
1074 If the C<$sessionID> parameter is an empty string, a new session
1075 will be created.
1076
1077 =cut
1078
1079 sub get_session {
1080     my $sessionID = shift;
1081     my $storage_method = C4::Context->preference('SessionStorage');
1082     my $dbh = C4::Context->dbh;
1083     my $session;
1084     if ($storage_method eq 'mysql'){
1085         $session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
1086     }
1087     elsif ($storage_method eq 'Pg') {
1088         $session = new CGI::Session("driver:PostgreSQL", $sessionID, {Handle=>$dbh});
1089     }
1090     else {
1091         # catch all defaults to tmp should work on all systems
1092         $session = new CGI::Session("driver:File", $sessionID, {Directory=>'/tmp'});
1093     }
1094     return $session;
1095 }
1096
1097 sub checkpw {
1098
1099     my ( $dbh, $userid, $password ) = @_;
1100         if ($ldap) {
1101                 $debug and print "## checkpw - checking LDAP\n";
1102                 my ($retval,$retcard) = checkpw_ldap(@_);    # EXTERNAL AUTH
1103                 ($retval) and return ($retval,$retcard);
1104         }
1105
1106     # INTERNAL AUTH
1107     my $sth =
1108       $dbh->prepare(
1109 "select password,cardnumber,borrowernumber,userid,firstname,surname,branchcode,flags from borrowers where userid=?"
1110       );
1111     $sth->execute($userid);
1112     if ( $sth->rows ) {
1113         my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
1114             $surname, $branchcode, $flags )
1115           = $sth->fetchrow;
1116         if ( md5_base64($password) eq $md5password ) {
1117
1118             C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
1119                 $firstname, $surname, $branchcode, $flags );
1120             return 1, $cardnumber;
1121         }
1122     }
1123     $sth =
1124       $dbh->prepare(
1125 "select password,cardnumber,borrowernumber,userid, firstname,surname,branchcode,flags from borrowers where cardnumber=?"
1126       );
1127     $sth->execute($userid);
1128     if ( $sth->rows ) {
1129         my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
1130             $surname, $branchcode, $flags )
1131           = $sth->fetchrow;
1132         if ( md5_base64($password) eq $md5password ) {
1133
1134             C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
1135                 $firstname, $surname, $branchcode, $flags );
1136             return 1, $userid;
1137         }
1138     }
1139     if (   $userid && $userid eq C4::Context->config('user')
1140         && "$password" eq C4::Context->config('pass') )
1141     {
1142
1143 # Koha superuser account
1144 #     C4::Context->set_userenv(0,0,C4::Context->config('user'),C4::Context->config('user'),C4::Context->config('user'),"",1);
1145         return 2;
1146     }
1147     if (   $userid && $userid eq 'demo'
1148         && "$password" eq 'demo'
1149         && C4::Context->config('demo') )
1150     {
1151
1152 # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
1153 # some features won't be effective : modify systempref, modify MARC structure,
1154         return 2;
1155     }
1156     return 0;
1157 }
1158
1159 =item getuserflags
1160
1161  $authflags = getuserflags($flags,$dbh);
1162 Translates integer flags into permissions strings hash.
1163
1164 C<$flags> is the integer userflags value ( borrowers.userflags )
1165 C<$authflags> is a hashref of permissions
1166
1167 =cut
1168
1169 sub getuserflags {
1170     my $flags   = shift;
1171     my $dbh     = shift;
1172     my $userflags;
1173         $flags = 0 unless $flags;
1174     my $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
1175     $sth->execute;
1176
1177     while ( my ( $bit, $flag, $defaulton ) = $sth->fetchrow ) {
1178         if ( ( $flags & ( 2**$bit ) ) || $defaulton ) {
1179             $userflags->{$flag} = 1;
1180         }
1181         else {
1182             $userflags->{$flag} = 0;
1183         }
1184     }
1185     return $userflags;
1186 }
1187
1188 =item haspermission 
1189
1190   $flags = ($dbh,$member,$flagsrequired);
1191
1192 C<$member> may be either userid or overloaded with $borrower hashref from GetMemberDetails.
1193 C<$flags> is a hashref of required flags lik C<$borrower-&lt;{authflags}> 
1194
1195 Returns member's flags or 0 if a permission is not met.
1196
1197 =cut
1198
1199 sub haspermission {
1200     my ( $dbh, $userid, $flagsrequired ) = @_;
1201         my ($flags,$intflags);
1202         $dbh=C4::Context->dbh unless($dbh);
1203         if(ref($userid)) {
1204                 $intflags = $userid->{'flags'};  
1205         } else {
1206             my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE userid=?");
1207             $sth->execute($userid);
1208             my ($intflags) = $sth->fetchrow;
1209             $flags = getuserflags( $intflags, $dbh );
1210         }
1211         if ( $userid eq C4::Context->config('user') ) {
1212         # Super User Account from /etc/koha.conf
1213         $flags->{'superlibrarian'} = 1;
1214     }
1215     if ( $userid eq 'demo' && C4::Context->config('demo') ) {
1216         # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
1217         $flags->{'superlibrarian'} = 1;
1218     }
1219     return $flags if $flags->{superlibrarian};
1220     foreach ( keys %$flagsrequired ) {
1221         return 0 unless( $flags->{$_} );
1222     }
1223     return $flags;
1224         #FIXME - This fcn should return the failed permission so a suitable error msg can be delivered.
1225 }
1226
1227
1228 sub getborrowernumber {
1229     my ($userid) = @_;
1230     my $dbh = C4::Context->dbh;
1231     for my $field ( 'userid', 'cardnumber' ) {
1232         my $sth =
1233           $dbh->prepare("select borrowernumber from borrowers where $field=?");
1234         $sth->execute($userid);
1235         if ( $sth->rows ) {
1236             my ($bnumber) = $sth->fetchrow;
1237             return $bnumber;
1238         }
1239     }
1240     return 0;
1241 }
1242
1243 END { }    # module clean-up code here (global destructor)
1244 1;
1245 __END__
1246
1247 =back
1248
1249 =head1 SEE ALSO
1250
1251 CGI(3)
1252
1253 C4::Output(3)
1254
1255 Digest::MD5(3)
1256
1257 =cut