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__ |