RT# 80555 Sanitize leading 0's from ip addr input
[freeside.git] / FS / FS / Record.pm
index 21fef73..cf8ec4d 100644 (file)
@@ -18,6 +18,7 @@ use DBIx::DBSchema 0.43; #0.43 for foreign keys
 use Locale::Country;
 use Locale::Currency;
 use NetAddr::IP; # for validation
+use Crypt::OpenSSL::RSA;
 use FS::UID qw(dbh datasrc driver_name);
 use FS::CurrentUser;
 use FS::Schema qw(dbdef);
@@ -53,8 +54,6 @@ our $qsearch_qualify_columns = 1;
 
 our $no_check_foreign = 1; #well, not inefficiently in perl by default anymore
 
-my $rsa_module;
-my $rsa_loaded;
 my $rsa_encrypt;
 my $rsa_decrypt;
 
@@ -2882,11 +2881,9 @@ to 127.0.0.1.
 sub ut_ip {
   my( $self, $field ) = @_;
   $self->setfield($field, '127.0.0.1') if $self->getfield($field) eq '::1';
-  $self->getfield($field) =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
-    or return "Illegal (IP address) $field: ". $self->getfield($field);
-  for ( $1, $2, $3, $4 ) { return "Illegal (IP address) $field" if $_ > 255; }
-  $self->setfield($field, "$1.$2.$3.$4");
-  '';
+  return "Illegal (IP address) $field: ".$self->getfield($field)
+    unless $self->getfield($field) =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
+  $self->ut_ip46($field);
 }
 
 =item ut_ipn COLUMN
@@ -2914,7 +2911,17 @@ Check/untaint IPv4 or IPv6 address.
 
 sub ut_ip46 {
   my( $self, $field ) = @_;
-  my $ip = NetAddr::IP->new($self->getfield($field))
+  my $ip_addr = $self->getfield( $field );
+
+  # strip user-entered leading 0's from IPv4 addresses
+  # Parsers like NetAddr::IP interpret them as octal instead of decimal
+  $ip_addr = join( '.', (
+        map{ int($_) }
+        split( /\./, $ip_addr )
+    )
+  ) if $ip_addr =~ /\./ && $ip_addr =~ /[\.^]0/;
+
+  my $ip = NetAddr::IP->new( $ip_addr )
     or return "Illegal (IP address) $field: ".$self->getfield($field);
   $self->setfield($field, lc($ip->addr));
   return '';
@@ -3397,27 +3404,19 @@ sub decrypt {
 }
 
 sub loadRSA {
-    my $self = shift;
-    #Initialize the Module
-    $rsa_module = 'Crypt::OpenSSL::RSA'; # The Default
-
-    if ($conf_encryptionmodule && $conf_encryptionmodule ne '') {
-      $rsa_module = $conf_encryptionmodule;
-    }
+  my $self = shift;
 
-    if (!$rsa_loaded) {
-       eval ("require $rsa_module"); # No need to import the namespace
-       $rsa_loaded++;
-    }
-    # Initialize Encryption
-    if ($conf_encryptionpublickey && $conf_encryptionpublickey ne '') {
-      $rsa_encrypt = $rsa_module->new_public_key($conf_encryptionpublickey);
-    }
+  my $rsa_module = $conf_encryptionmodule || 'Crypt::OpenSSL::RSA';
 
-    # Intitalize Decryption
-    if ($conf_encryptionprivatekey && $conf_encryptionprivatekey ne '') {
-      $rsa_decrypt = $rsa_module->new_private_key($conf_encryptionprivatekey);
-    }
+  # Initialize Encryption
+  if ($conf_encryptionpublickey && $conf_encryptionpublickey ne '') {
+    $rsa_encrypt = $rsa_module->new_public_key($conf_encryptionpublickey);
+  }
+    
+  # Intitalize Decryption
+  if ($conf_encryptionprivatekey && $conf_encryptionprivatekey ne '') {
+    $rsa_decrypt = $rsa_module->new_private_key($conf_encryptionprivatekey);
+  }
 }
 
 =item h_search ACTION