line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Copyright (c) 2002 Graham Barr . All rights reserved. |
2
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or |
3
|
|
|
|
|
|
|
# modify it under the same terms as Perl itself. |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Authen::SASL::Perl; |
6
|
|
|
|
|
|
|
|
7
|
15
|
|
|
15
|
|
80
|
use strict; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
1045
|
|
8
|
15
|
|
|
15
|
|
79
|
use vars qw($VERSION); |
|
15
|
|
|
|
|
24
|
|
|
15
|
|
|
|
|
635
|
|
9
|
15
|
|
|
15
|
|
73
|
use Carp; |
|
15
|
|
|
|
|
28
|
|
|
15
|
|
|
|
|
18919
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
$VERSION = "2.14"; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
my %secflags = ( |
14
|
|
|
|
|
|
|
noplaintext => 1, |
15
|
|
|
|
|
|
|
noanonymous => 1, |
16
|
|
|
|
|
|
|
nodictionary => 1, |
17
|
|
|
|
|
|
|
); |
18
|
|
|
|
|
|
|
my %have; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub server_new { |
21
|
18
|
|
|
18
|
0
|
42
|
my ($pkg, $parent, $service, $host, $options) = @_; |
22
|
|
|
|
|
|
|
|
23
|
18
|
|
|
|
|
63
|
my $self = { |
24
|
18
|
|
50
|
|
|
28
|
callback => { %{$parent->callback} }, |
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
25
|
|
|
|
|
|
|
service => $service || '', |
26
|
|
|
|
|
|
|
host => $host || '', |
27
|
|
|
|
|
|
|
debug => $parent->{debug} || 0, |
28
|
|
|
|
|
|
|
need_step => 1, |
29
|
|
|
|
|
|
|
}; |
30
|
|
|
|
|
|
|
|
31
|
18
|
50
|
|
|
|
72
|
my $mechanism = $parent->mechanism |
32
|
|
|
|
|
|
|
or croak "No server mechanism specified"; |
33
|
18
|
|
|
|
|
113
|
$mechanism =~ s/^\s*\b(.*)\b\s*$/$1/g; |
34
|
18
|
|
|
|
|
55
|
$mechanism =~ s/-/_/g; |
35
|
18
|
|
|
|
|
43
|
$mechanism = uc $mechanism; |
36
|
18
|
|
|
|
|
45
|
my $mpkg = __PACKAGE__ . "::$mechanism"; |
37
|
18
|
50
|
|
|
|
899
|
eval "require $mpkg;" |
38
|
|
|
|
|
|
|
or croak "Cannot use $mpkg for " . $parent->mechanism; |
39
|
18
|
|
|
|
|
96
|
my $server = $mpkg->_init($self); |
40
|
18
|
|
|
|
|
68
|
$server->_init_server($options); |
41
|
18
|
|
|
|
|
105
|
return $server; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub client_new { |
45
|
33
|
|
|
33
|
0
|
86
|
my ($pkg, $parent, $service, $host, $secflags) = @_; |
46
|
|
|
|
|
|
|
|
47
|
33
|
|
100
|
|
|
231
|
my @sec = grep { $secflags{$_} } split /\W+/, lc($secflags || ''); |
|
11
|
|
|
|
|
44
|
|
48
|
|
|
|
|
|
|
|
49
|
33
|
|
|
|
|
103
|
my $self = { |
50
|
33
|
|
50
|
|
|
57
|
callback => { %{$parent->callback} }, |
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
51
|
|
|
|
|
|
|
service => $service || '', |
52
|
|
|
|
|
|
|
host => $host || '', |
53
|
|
|
|
|
|
|
debug => $parent->{debug} || 0, |
54
|
|
|
|
|
|
|
need_step => 1, |
55
|
|
|
|
|
|
|
}; |
56
|
|
|
|
|
|
|
|
57
|
106
|
|
|
|
|
302
|
my @mpkg = sort { |
58
|
89
|
50
|
33
|
|
|
1504
|
$b->_order <=> $a->_order |
|
|
|
66
|
|
|
|
|
59
|
|
|
|
|
|
|
} grep { |
60
|
89
|
|
|
|
|
269
|
my $have = $have{$_} ||= (eval "require $_;" and $_->can('_secflags')) ? 1 : -1; |
61
|
89
|
50
|
|
|
|
585
|
$have > 0 and $_->_secflags(@sec) == @sec |
62
|
|
|
|
|
|
|
} map { |
63
|
33
|
50
|
|
|
|
160
|
(my $mpkg = __PACKAGE__ . "::$_") =~ s/-/_/g; |
64
|
89
|
|
|
|
|
193
|
$mpkg; |
65
|
|
|
|
|
|
|
} split /[^-\w]+/, $parent->mechanism |
66
|
|
|
|
|
|
|
or croak "No SASL mechanism found\n"; |
67
|
|
|
|
|
|
|
|
68
|
33
|
|
|
|
|
238
|
$mpkg[0]->_init($self); |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
10
|
|
|
10
|
|
13
|
sub _init_server {} |
72
|
|
|
|
|
|
|
|
73
|
0
|
|
|
0
|
|
0
|
sub _order { 0 } |
74
|
58
|
100
|
|
58
|
0
|
779
|
sub code { defined(shift->{error}) || 0 } |
75
|
68
|
|
|
68
|
0
|
6686
|
sub error { shift->{error} } |
76
|
13
|
|
|
13
|
0
|
79
|
sub service { shift->{service} } |
77
|
21
|
|
|
21
|
0
|
147
|
sub host { shift->{host} } |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub need_step { |
80
|
87
|
|
|
87
|
0
|
274
|
my $self = shift; |
81
|
87
|
100
|
|
|
|
218
|
return 0 if $self->{error}; |
82
|
83
|
|
|
|
|
304
|
return $self->{need_step}; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
## I think I need to rename that to end()? |
86
|
|
|
|
|
|
|
## It doesn't mean that SASL is successful, but that |
87
|
|
|
|
|
|
|
## that the negotiation is over, no more step necessary |
88
|
|
|
|
|
|
|
## at least for the client |
89
|
|
|
|
|
|
|
sub set_success { |
90
|
15
|
|
|
15
|
0
|
28
|
my $self = shift; |
91
|
15
|
|
|
|
|
52
|
$self->{need_step} = 0; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub is_success { |
95
|
54
|
|
|
54
|
0
|
2274
|
my $self = shift; |
96
|
54
|
|
100
|
|
|
156
|
return !$self->code && !$self->need_step; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub set_error { |
100
|
30
|
|
|
30
|
0
|
49
|
my $self = shift; |
101
|
30
|
|
|
|
|
47
|
$self->{error} = shift; |
102
|
30
|
|
|
|
|
67
|
return; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# set/get property |
106
|
|
|
|
|
|
|
sub property { |
107
|
190
|
|
|
190
|
0
|
246
|
my $self = shift; |
108
|
190
|
|
100
|
|
|
543
|
my $prop = $self->{property} ||= {}; |
109
|
190
|
100
|
|
|
|
536
|
return $prop->{ $_[0] } if @_ == 1; |
110
|
131
|
|
|
|
|
288
|
my %new = @_; |
111
|
131
|
|
|
|
|
244
|
@{$prop}{keys %new} = values %new; |
|
131
|
|
|
|
|
254
|
|
112
|
131
|
|
|
|
|
366
|
1; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub callback { |
116
|
36
|
|
|
36
|
0
|
46
|
my $self = shift; |
117
|
|
|
|
|
|
|
|
118
|
36
|
50
|
|
|
|
198
|
return $self->{callback}{$_[0]} if @_ == 1; |
119
|
|
|
|
|
|
|
|
120
|
0
|
|
|
|
|
0
|
my %new = @_; |
121
|
0
|
|
|
|
|
0
|
@{$self->{callback}}{keys %new} = values %new; |
|
0
|
|
|
|
|
0
|
|
122
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
0
|
$self->{callback}; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Should be defined in the mechanism sub-class |
127
|
0
|
|
|
0
|
0
|
0
|
sub mechanism { undef } |
128
|
3
|
|
|
3
|
0
|
15
|
sub client_step { undef } |
129
|
0
|
|
|
0
|
0
|
0
|
sub client_start { undef } |
130
|
0
|
|
|
0
|
0
|
0
|
sub server_step { undef } |
131
|
0
|
|
|
0
|
0
|
0
|
sub server_start { undef } |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Private methods used by Authen::SASL::Perl that |
134
|
|
|
|
|
|
|
# may be overridden in mechanism sub-calsses |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub _init { |
137
|
31
|
|
|
31
|
|
65
|
my ($pkg, $href) = @_; |
138
|
|
|
|
|
|
|
|
139
|
31
|
|
|
|
|
288
|
bless $href, $pkg; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub _call { |
143
|
72
|
|
|
72
|
|
161
|
my ($self, $name) = splice(@_,0,2); |
144
|
|
|
|
|
|
|
|
145
|
72
|
|
|
|
|
157
|
my $cb = $self->{callback}{$name}; |
146
|
|
|
|
|
|
|
|
147
|
72
|
100
|
|
|
|
224
|
return undef unless defined $cb; |
148
|
|
|
|
|
|
|
|
149
|
43
|
|
|
|
|
48
|
my $value; |
150
|
|
|
|
|
|
|
|
151
|
43
|
100
|
|
|
|
154
|
if (ref($cb) eq 'ARRAY') { |
|
|
100
|
|
|
|
|
|
152
|
1
|
|
|
|
|
3
|
my @args = @$cb; |
153
|
1
|
|
|
|
|
2
|
$cb = shift @args; |
154
|
1
|
|
|
|
|
4
|
$value = $cb->($self, @args); |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
elsif (ref($cb) eq 'CODE') { |
157
|
4
|
|
|
|
|
18
|
$value = $cb->($self, @_); |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
else { |
160
|
38
|
|
|
|
|
54
|
$value = $cb; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
43
|
100
|
|
|
|
913
|
$self->{answer}{$name} = $value |
164
|
|
|
|
|
|
|
unless $name eq 'pass'; # Do not store password |
165
|
|
|
|
|
|
|
|
166
|
43
|
|
|
|
|
137
|
return $value; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# TODO: Need a better name than this |
170
|
|
|
|
|
|
|
sub answer { |
171
|
0
|
|
|
0
|
0
|
|
my ($self, $name) = @_; |
172
|
0
|
|
|
|
|
|
$self->{answer}{$name}; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
0
|
|
|
0
|
|
|
sub _secflags { 0 } |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub securesocket { |
178
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
179
|
0
|
0
|
0
|
|
|
|
return $_[0] unless (defined($self->property('ssf')) && $self->property('ssf') > 0); |
180
|
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
|
local *GLOB; # avoid used only once warning |
182
|
0
|
|
|
|
|
|
my $glob = \do { local *GLOB; }; |
|
0
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
|
tie(*$glob, 'Authen::SASL::Perl::Layer', $_[0], $self); |
184
|
0
|
|
|
|
|
|
$glob; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
{ |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# |
190
|
|
|
|
|
|
|
# Add SASL encoding/decoding to a filehandle |
191
|
|
|
|
|
|
|
# |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
package Authen::SASL::Perl::Layer; |
194
|
|
|
|
|
|
|
|
195
|
15
|
|
|
15
|
|
15158
|
use bytes; |
|
15
|
|
|
|
|
166
|
|
|
15
|
|
|
|
|
81
|
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
require Tie::Handle; |
198
|
|
|
|
|
|
|
our @ISA = qw(Tie::Handle); |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub TIEHANDLE { |
201
|
0
|
|
|
0
|
|
|
my ($class, $fh, $conn) = @_; |
202
|
0
|
|
|
|
|
|
my $self; |
203
|
|
|
|
|
|
|
|
204
|
0
|
0
|
0
|
|
|
|
warn __PACKAGE__ . ': non-blocking handle may not work' |
205
|
|
|
|
|
|
|
if ($fh->can('blocking') and not $fh->blocking()); |
206
|
|
|
|
|
|
|
|
207
|
0
|
|
|
|
|
|
$self->{fh} = $fh; |
208
|
0
|
|
|
|
|
|
$self->{conn} = $conn; |
209
|
0
|
|
|
|
|
|
$self->{readbuflen} = 0; |
210
|
0
|
|
|
|
|
|
$self->{sndbufsz} = $conn->property('maxout'); |
211
|
0
|
|
|
|
|
|
$self->{rcvbufsz} = $conn->property('maxbuf'); |
212
|
|
|
|
|
|
|
|
213
|
0
|
|
|
|
|
|
return bless($self, $class); |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub CLOSE { |
217
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# forward close to the inner handle |
220
|
0
|
|
|
|
|
|
close($self->{fh}); |
221
|
0
|
|
|
|
|
|
delete $self->{fh}; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub DESTROY { |
225
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
226
|
0
|
|
|
|
|
|
delete $self->{fh}; |
227
|
0
|
|
|
|
|
|
undef $self; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub FETCH { |
231
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
232
|
0
|
|
|
|
|
|
return $self->{fh}; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub FILENO { |
236
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
237
|
0
|
|
|
|
|
|
return fileno($self->{fh}); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
sub READ { |
242
|
0
|
|
|
0
|
|
|
my ($self, $buf, $len, $offset) = @_; |
243
|
0
|
|
|
|
|
|
my $debug = $self->{conn}->{debug}; |
244
|
|
|
|
|
|
|
|
245
|
0
|
|
|
|
|
|
$buf = \$_[1]; |
246
|
|
|
|
|
|
|
|
247
|
0
|
|
|
|
|
|
my $avail = $self->{readbuflen}; |
248
|
|
|
|
|
|
|
|
249
|
0
|
0
|
|
|
|
|
print STDERR " [READ(len=$len,offset=$offset)] avail=$avail;\n" |
250
|
|
|
|
|
|
|
if ($debug & 4); |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# Check if there's leftovers from a previous READ |
253
|
0
|
0
|
|
|
|
|
if ($avail <= 0) { |
254
|
0
|
|
|
|
|
|
$avail = $self->_getbuf(); |
255
|
0
|
0
|
|
|
|
|
return undef unless ($avail > 0); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# if there's more than we need right now, leave the rest for later |
259
|
0
|
0
|
|
|
|
|
if ($avail >= $len) { |
260
|
0
|
0
|
|
|
|
|
print STDERR " GOT ALL: avail=$avail; need=$len\n" |
261
|
|
|
|
|
|
|
if ($debug & 4); |
262
|
0
|
|
|
|
|
|
substr($$buf, $offset, $len) = substr($self->{readbuf}, 0, $len, ''); |
263
|
0
|
|
|
|
|
|
$self->{readbuflen} -= $len; |
264
|
0
|
|
|
|
|
|
return ($len); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# there's not enough; take all we have, read more on next call |
268
|
0
|
0
|
|
|
|
|
print STDERR " GOT PARTIAL: avail=$avail; need=$len\n" |
269
|
|
|
|
|
|
|
if ($debug & 4); |
270
|
0
|
|
0
|
|
|
|
substr($$buf, $offset || 0, $avail) = $self->{readbuf}; |
271
|
0
|
|
|
|
|
|
$self->{readbuf} = ''; |
272
|
0
|
|
|
|
|
|
$self->{readbuflen} = 0; |
273
|
|
|
|
|
|
|
|
274
|
0
|
|
|
|
|
|
return ($avail); |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# retrieve and decode a buffer of cipher text in SASL format |
278
|
|
|
|
|
|
|
sub _getbuf { |
279
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
280
|
0
|
|
|
|
|
|
my $debug = $self->{conn}->{debug}; |
281
|
0
|
|
|
|
|
|
my $fh = $self->{fh}; |
282
|
0
|
|
|
|
|
|
my $buf = ''; |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# first, read 4-octet buffer size |
285
|
0
|
|
|
|
|
|
my $n = 0; |
286
|
0
|
|
|
|
|
|
while ($n < 4) { |
287
|
0
|
|
|
|
|
|
my $rv = sysread($fh, $buf, 4 - $n, $n); |
288
|
0
|
0
|
|
|
|
|
print STDERR " [getbuf: sysread($fh,$buf,4-$n,$n)=$rv: $!\n" |
289
|
|
|
|
|
|
|
if ($debug & 4); |
290
|
0
|
0
|
|
|
|
|
return $rv unless $rv > 0; |
291
|
0
|
|
|
|
|
|
$n += $rv; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# size is encoded in network byte order |
295
|
0
|
|
|
|
|
|
my ($bsz) = unpack('N', $buf); |
296
|
0
|
0
|
|
|
|
|
print STDERR " [getbuf: cipher buffer sz=$bsz]\n" if ($debug & 4); |
297
|
0
|
0
|
|
|
|
|
return undef unless ($bsz <= $self->{rcvbufsz}); |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
# next, read actual cipher text |
300
|
0
|
|
|
|
|
|
$buf = ''; |
301
|
0
|
|
|
|
|
|
$n = 0; |
302
|
0
|
|
|
|
|
|
while ($n < $bsz) { |
303
|
0
|
|
|
|
|
|
my $rv = sysread($fh, $buf, $bsz - $n, $n); |
304
|
0
|
0
|
|
|
|
|
print STDERR " [getbuf: got o=$n,n=", $bsz - $n, ",rv=$rv,bl=" . length($buf) . "]\n" |
305
|
|
|
|
|
|
|
if ($debug & 4); |
306
|
0
|
0
|
|
|
|
|
return $rv unless $rv > 0; |
307
|
0
|
|
|
|
|
|
$n += $rv; |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# call mechanism specific decoding routine |
311
|
0
|
|
|
|
|
|
$self->{readbuf} = $self->{conn}->decode($buf, $bsz); |
312
|
0
|
|
|
|
|
|
$n = length($self->{readbuf}); |
313
|
0
|
0
|
|
|
|
|
print STDERR " [getbuf: clear text buffer sz=$n]\n" if ($debug & 4); |
314
|
0
|
|
|
|
|
|
$self->{readbuflen} = $n; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# Encrypting a write() to a filehandle is much easier than reading, because |
319
|
|
|
|
|
|
|
# all the data to be encrypted is immediately available |
320
|
|
|
|
|
|
|
sub WRITE { |
321
|
0
|
|
|
0
|
|
|
my ($self, undef, $len, $offset) = @_; |
322
|
0
|
|
|
|
|
|
my $debug = $self->{conn}->{debug}; |
323
|
|
|
|
|
|
|
|
324
|
0
|
|
|
|
|
|
my $fh = $self->{fh}; |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# put on wire in peer-sized chunks |
327
|
0
|
|
|
|
|
|
my $bsz = $self->{sndbufsz}; |
328
|
0
|
|
|
|
|
|
while ($len > 0) { |
329
|
0
|
0
|
|
|
|
|
print STDERR " [WRITE: chunk $bsz/$len]\n" |
330
|
|
|
|
|
|
|
if ($debug & 8); |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# call mechanism specific encoding routine |
333
|
0
|
|
0
|
|
|
|
my $x = $self->{conn}->encode(substr($_[1], $offset || 0, $bsz)); |
334
|
0
|
|
|
|
|
|
print $fh pack('N', length($x)), $x; |
335
|
0
|
|
|
|
|
|
$len -= $bsz; |
336
|
0
|
|
|
|
|
|
$offset += $bsz; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
0
|
|
|
|
|
|
return $_[2]; |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
1; |