File Coverage

lib/HTTPD/Realm.pm
Criterion Covered Total %
statement 123 139 88.4
branch 30 48 62.5
condition 24 59 40.6
subroutine 28 35 80.0
pod 5 6 83.3
total 210 287 73.1


line stmt bran cond sub pod time code
1             package HTTPD::RealmDef;
2 4     4   3595 use Carp;
  4         9  
  4         406  
3              
4 4     4   23 use strict;
  4         8  
  4         152  
5 4     4   789 use HTTPD::RealmManager;
  4         8  
  4         247  
6 4     4   21 use vars qw($VERSION);
  4         9  
  4         342  
7              
8             $VERSION = $HTTPD::Realm::VERSION = 1.52;
9              
10 4     4   7584 use overload '""'=>\&name;
  4         5384  
  4         40  
11              
12             sub new {
13 12     12   21 my ($class,$name) = @_;
14 12         57 return bless { 'name' => $name },$class;
15             }
16              
17             sub userdb {
18 18     18   21 my $self = shift;
19 18   33     150 return $self->{users} || $self->{userfile};
20             }
21              
22             sub groupdb {
23 10     10   15 my $self = shift;
24 10   33     55 return $self->{groups} || $self->{groupfile};
25             }
26              
27             # backwards compatability only
28 0     0   0 sub userfile { return &userdb; }
29 0     0   0 sub groupfile { return &groupdb; }
30              
31             sub mode {
32 3   50 3   35 return shift->{mode} || 0644;
33             }
34              
35             sub database {
36 1   50 1   20 return shift->{database} || "www\@localhost";
37             }
38              
39             #
40             # added by John Porter:
41             #
42             sub dblogin {
43 1     1   3 return shift->{dblogin};
44             }
45             sub dbpassword {
46 1     1   4 return shift->{dbpassword};
47             }
48              
49             sub fields {
50 1     1   6 return shift->{fields};
51             }
52              
53             sub usertype {
54 18     18   23 my $self = shift;
55 18   33     124 return $self->{usertype} || $self->{type};
56             }
57              
58             sub grouptype {
59 5     5   10 my $self = shift;
60 5   33     35 return $self->{grouptype} || $self->{type};
61             }
62              
63             sub authentication {
64 10   100 10   84 return shift->{'authentication'} || 'Basic';
65             }
66              
67             sub driver {
68 0   0 0   0 return shift->{'driver'} || 'mSQL';
69             }
70              
71             sub server {
72 4   50 4   43 return shift->{'server'} || 'apache';
73             }
74              
75             sub crypt {
76 9     9   11 my $self = shift;
77 9 50       647 return $self->{'crypt'} if $self->{'crypt'};
78 9 50       22 return 'crypt' if lc($self->authentication) eq 'basic';
79 0 0       0 return 'MD5' if lc($self->authentication) eq 'digest';
80 0         0 return 'crypt'; # default currently
81             }
82              
83             sub name {
84 185     185   699 return shift->{'name'};
85             }
86              
87             # return a pointer to an associative array with mSQL info.
88             # it will contain the keys:
89             # host name of the database host
90             # database name of the database
91             # dblogin
92             # dbpassword
93             # usertable name of the table that user/passwd/other info is in
94             # grouptable name of the table containing user/group pairs
95             # userfield name of the user field (both tables)
96             # groupuserfield
97             # groupfield name of the group field (group table only)
98             # passwdfield name of the password field (user table only)
99             # userfield_len length of the user field
100             # groupfield_len length of the group field
101             # passwdfield_len length of the password field
102             sub SQLdata {
103 1     1   3 my $self = shift;
104 1 50       5 return undef unless $self->usertype=~/sql/i;
105 1         89 my ($u,$g) = ($self->split_parms($self->userdb),$self->split_parms($self->groupdb));
106 1         2 my %result;
107 1         4 @result{qw(database host)} = split('@',$self->database);
108 1   50     5 $result{host} ||= 'localhost';
109             #
110             # Do what Lincoln didn't:
111 1         5 $result{dblogin} = $self->dblogin;
112 1         5 $result{dbpassword} = $self->dbpassword;
113             #
114 1   50     6 $result{usertable} = $u->{table} || 'users';
115 1         3 $result{grouptable} = $g->{table}; # no default
116 1   50     7 $result{userfield} = $u->{uid} || $g->{uid} || 'users';
117 1   50     8 $result{groupuserfield} = $g->{uid} || $u->{uid} || 'users';
118 1         3 $result{groupfield} = $g->{group};
119 1   50     8 $result{passwdfield} = $u->{password} || 'password';
120 1   50     7 $result{userfield_len} = $u->{uid_len} || $u->{user_len} || 12;
121 1   50     5 $result{groupfield_len} = $g->{group_len} || 20;
122 1   33     11 $result{passwdfield_len}= $u->{password_len} ||
123             (lc($self->authentication) eq 'digest' ? 32 + 3 + length($self->name) + $result{userfield_len} : 13);
124 1         9 return \%result;
125             }
126              
127             sub connect {
128 3     3   6 my $self = shift;
129 3         22 my ($writable,$mode,$server) = rearrange([[qw(WRITABLE WRITE MODIFY)],qw(MODE SERVER)],@_);
130 3   33     27 return new HTTPD::RealmManager(-realm => $self,
      50        
131             -writable => $writable,
132             '-mode' => $mode || $self->mode,
133             '-server' => $server || $self->server || 'apache');
134             }
135              
136             # A utility routine
137             sub split_parms {
138 2     2   4 my($self,$j) = @_;
139 2         33 my($junk,%p) = split(/\s*(\w+)=/,$j);
140 2         9 foreach (keys %p) {
141 6         20 $p{$_}=~s/^"//;
142 6         17 $p{$_}=~s/"$//;
143 6 100       26 if ($p{$_}=~/:[a-zA-Z]?(\d+)$/) {
144 4         10 $p{$_}=$`;
145 4         14 $p{"${_}_len"}=$1;
146             }
147             }
148 2         9 \%p;
149             }
150              
151             # ----------------------------------------------------------------------------------------
152             package HTTPD::Realm;
153              
154 4     4   4628 use strict;
  4         8  
  4         192  
155 4     4   22 use HTTPD::RealmManager;
  4         8  
  4         274  
156 4     4   24 use Carp;
  4         8  
  4         4775  
157              
158             *dbm = \&connect;
159              
160             my %CACHE;
161              
162             my %VALID_DIRECTIVES = (
163             'dblogin' =>1,
164             'dbpassword' =>1,
165             'users' =>1, # file or table of user/passwd info
166             'groups' =>1, # file or table of user/group info
167             'database' =>1, # database name (SQL only)
168             'fields' =>1, # other fields (SQL only)
169             'type' =>1, # db type (text|NDBM|DB|mSQL|SQL)
170             'driver' =>1, # SQL db driver type [mSQL]
171             'usertype' =>1, # override db type for users only
172             'grouptype' =>1, # override db type for groups only
173             'default' =>1, # set default realm
174             'authentication' =>1, # authentication scheme (Basic|Digest)
175             'server' =>1, # server type (Apache|NCSA|Netscape)
176             'mode' =>1, # mode for newly-created text & DBM files
177             'crypt' =>1, # override encryption, backward compatability only
178             'userfile' =>1, # synonyms for backward compatability only
179             'groupfile' =>1, # synonyms for backward compatability only
180             );
181              
182             # Security realm parsing utility -- high level interface to Doug MacEachern's
183             # HTTPD utilities.
184              
185             # Pass the location of the configuration file.
186             sub new {
187 3     3 1 29 my $class = shift;
188 3         24 my ($config_file) = rearrange([[qw(CONFIG CONFIG_FILE)]],@_);
189              
190 3 100 66     40 if ($CACHE{$config_file} && -C $config_file == $CACHE{$config_file}{ctime}) {
191 1         5 return $CACHE{$config_file}{obj};
192             }
193              
194 2         32 my $self = { config_file => $config_file, };
195              
196 2         6 my($realm,$realm_name,$directive,$value,$default_realm,$first_realm);
197 2 50       112 open(CONF,$config_file) || croak "Couldn't open $config_file: $!";
198 2         81 while () {
199 94         111 chomp;
200 94         120 s/\#.*$//; # get rid of all comments
201              
202 94 100       1687 if (//i) {
203 12 50       29 croak "Syntax error in $config_file, line $.: Missing directive.\n"
204             if $realm;
205 12 50       34 croak "Syntax error in $config_file, line $.: directive without realm name.\n"
206             unless $1;
207 12         51 $realm = new HTTPD::RealmDef($realm_name = $1);
208 12 100       30 $first_realm = $realm unless $first_realm;
209 12         42 next;
210             }
211              
212 82 100       666 if (/<\/Realm\s*>/i) {
213 12 50       23 croak "Syntax error in $config_file, line $.: seen without preceding directive.\n"
214             unless $realm;
215 12 50 33     32 croak "Incomplete definition for realm $realm. Need Users and Type directives at line $.\n"
216             unless $realm->userdb && $realm->usertype;
217 12         38 $self->{realms}->{$realm_name}=$realm;
218 12         18 undef $realm;
219 12         16 undef $realm_name;
220 12         61 next;
221             }
222              
223 70 100       525 next unless ($directive,$value) = /(\w+)\s*(.*)/;
224 60 50       2922 croak "Syntax error in $config_file, line $.: $directive directive without preceding tag.\n"
225             unless $realm;
226            
227 60         587 $directive=~tr/A-Z/a-z/;
228 60 50       291 croak "Unknown directive \"$directive\" at line $.\n"
229             unless $VALID_DIRECTIVES{$directive};
230              
231 60 50       373 $realm->{$directive} = $directive =~ /file/ ? untaint($value) : $value;
232 60 100       2006 if ($directive eq 'default') {
233 2 50       7 croak "More than one Default directive defined at $config_file, line $.\n"
234             if $default_realm;
235 2         13 $default_realm = $realm_name;
236             }
237              
238             }
239 2         670 close CONF;
240              
241 2   33     11 $self->{default_realm}=$default_realm || $first_realm;
242 2         8 bless $self,$class;
243 2         48 $CACHE{$config_file}{ctime} = -C $config_file;
244 2         12 return $CACHE{$config_file}{obj} = $self;
245             }
246              
247             sub connect {
248 2     2 1 4 my $self = shift;
249 2         12 my ($writable,$realm,$mode) = rearrange([[qw(WRITABLE WRITE MODIFY)],qw(REALM MODE)],@_);
250 2         14 my $r = $self->realm($realm);
251 2 50       7 die "Unknown realm $realm" unless ref($r);
252 2         4 my(@p);
253 2 100       8 push(@p,'-writable'=>$writable) if $writable;
254 2 50       6 push(@p,'-mode'=>$mode) if $mode;
255 2         9 return $r->connect(@p);
256             }
257              
258             sub exists {
259 0     0 1 0 my $self = shift;
260 0         0 my ($realm) = rearrange(['REALM'],@_);
261 0         0 return defined($self->{realms}->{$realm});
262             }
263              
264             sub list {
265 0     0 1 0 my $self = shift;
266 0         0 return sort keys %{$self->{realms}};
  0         0  
267             }
268              
269             sub realm {
270 6     6 1 23 my $self = shift;
271 6         28 my ($realm) = rearrange(['REALM'],@_);
272 6   33     21 $realm ||= $self->{default_realm};
273 6         26 return $self->{realms}->{$realm};
274             }
275              
276             sub untaint {
277 0     0 0   my $taint = shift;
278 0 0 0       croak('Relative paths are not allowed in password and/or group file definitions')
279             if $taint =~ /\.\./ or $taint !~ m|^/|;
280 0           $taint =~ m!(/[a-zA-Z/0-9._-]+)!;
281 0           return $1;
282             }
283              
284             sub DESTROY {
285 0     0     my $self = shift;
286             }
287              
288              
289             1;
290              
291             __END__