package Net::Radius::Dictionary; use strict; use warnings; use vars qw($VERSION); # $Id: Dictionary.pm,v 1.1 2006/02/27 19:25:04 toni Exp $ $VERSION = '1.43'; sub new { my $class = shift; my $self = { }; bless $self, $class; $self->readfile($_[0]) if defined($_[0]); return $self; } sub readfile { my ($self, $filename) = @_; my (%vsattr, %rvsattr, %vsaval, %rvsaval, %attr, %rattr, %val, %rval); open DICT, "<$filename"; while (defined(my $l = )) { next if $l =~ /^\#/; next unless my @l = split /\s+/, $l; if (uc($l[0]) eq "ATTRIBUTE") { if (not defined $attr{$l[1]}) { $attr{$l[1]} = [@l[2,3]]; } if (not defined $rattr{$l[2]}) { $rattr{$l[2]} = [@l[1,3]]; } } elsif (uc($l[0]) eq "VALUE") { if (defined $attr{$l[1]}) { if (not defined $val{$attr{$l[1]}->[0]}->{$l[2]}) { $val{$attr{$l[1]}->[0]}->{$l[2]} = $l[3]; } if (not defined $rval{$attr{$l[1]}->[0]}->{$l[3]}) { $rval{$attr{$l[1]}->[0]}->{$l[3]} = $l[2]; } } else { warn "Warning: $filename contains value for unknown attribute ", "\"$l[1]\"\n"; } } elsif (uc($l[0]) eq "VENDORATTR") { if (substr($l[3],0,1) eq "0") { #allow hex or octal my $num = lc($l[3]); $num =~ s/^0b//; $l[3] = oct($num); } if (not defined $vsattr{$l[1]}->{$l[2]}) { $vsattr{$l[1]}->{$l[2]} = [@l[3, 4]]; } if (not defined $rvsattr{$l[1]}->{$l[3]}) { $rvsattr{$l[1]}->{$l[3]} = [@l[2, 4]]; } } elsif (uc($l[0]) eq "VENDORVALUE") { if (substr($l[4],0,1) eq "0") { #allow hex or octal my $num = lc($l[4]); $num =~ s/^0b//; $l[4] = oct($num); } if (defined $vsattr{$l[1]}->{$l[2]}) { if (not defined $vsaval{$l[1]}->{$vsattr{$l[1]}->{$l[2]}->[0]}->{$l[3]}) { $vsaval{$l[1]}->{$vsattr{$l[1]}->{$l[2]}->[0]}->{$l[3]} = $l[4]; } if (not defined $rvsaval{$l[1]}->{$vsattr{$l[1]}->{$l[2]}->[0]}->{$l[4]}) { $rvsaval{$l[1]}->{$vsattr{$l[1]}->{$l[2]}->[0]}->{$l[4]} = $l[3]; } } else { warn "Warning: $filename contains vendor value for ", "unknown vendor attribute - ignored", "\"$l[1]\"\n $l"; } } else { warn "Warning: Weird dictionary line: $l\n"; } } close DICT; $self->{attr} = \%attr; $self->{rattr} = \%rattr; $self->{val} = \%val; $self->{rval} = \%rval; $self->{vsattr} = \%vsattr; $self->{rvsattr} = \%rvsattr; $self->{vsaval} = \%vsaval; $self->{rvsaval} = \%rvsaval; } # Accessors for standard attributes sub attr_num { $_[0]->{attr}->{$_[1]}->[0]; } sub attr_type { $_[0]->{attr}->{$_[1]}->[1]; } sub attr_name { $_[0]->{rattr}->{$_[1]}->[0]; } sub attr_numtype { $_[0]->{rattr}->{$_[1]}->[1]; } sub attr_has_val { $_[0]->{val}->{$_[1]}; } sub val_has_name { $_[0]->{rval}->{$_[1]}; } sub val_num { $_[0]->{val}->{$_[1]}->{$_[2]}; } sub val_name { $_[0]->{rval}->{$_[1]}->{$_[2]}; } # Accessors for Vendor-Specific Attributes sub vsattr_num { $_[0]->{vsattr}->{$_[1]}->{$_[2]}->[0]; } sub vsattr_type { $_[0]->{vsattr}->{$_[1]}->{$_[2]}->[1]; } sub vsattr_name { $_[0]->{rvsattr}->{$_[1]}->{$_[2]}->[0]; } sub vsattr_numtype { $_[0]->{rvsattr}->{$_[1]}->{$_[2]}->[1]; } sub vsattr_has_val { $_[0]->{vsaval}->{$_[1]}->{$_[2]}; } sub vsaval_has_name { $_[0]->{rvsaval}->{$_[1]}->{$_[2]}; } sub vsaval_num { $_[0]->{vsaval}->{$_[1]}->{$_[2]}->{$_[3]}; } sub vsaval_name { $_[0]->{rvsaval}->{$_[1]}->{$_[2]}->{$_[3]};} 1; __END__ =head1 NAME Net::Radius::Dictionary - RADIUS dictionary parser =head1 SYNOPSIS use Net::Radius::Dictionary; my $dict = new Net::Radius::Dictionary "/etc/radius/dictionary"; $dict->readdict("/some/other/file"); my $num = $dict->attr_num('User-Name'); my $name = $dict->attr_name(1); my $vsa_num = $dict->vsattr_num(9, 'cisco-avpair'); my $vsa_name = $dict->vsattr_name(9, 1); =head1 DESCRIPTION This is a simple module that reads a RADIUS dictionary file and parses it, allowing conversion between dictionary names and numbers. Vendor-Specific attributes are supported in a way consistent to the standards. =head2 METHODS I Returns a new instance of a Net::Radius::Dictionary object. If given an (optional) filename, it calls I for you. -EI Parses a dictionary file and learns the name<->number mappings. -EI($attrname) Returns the number of the named attribute. -EI($attrname) Returns the type (I, I, I, or I