1#!/usr/local/bin/perl 2 3 4# Perl c_rehash script, scan all files in a directory 5# and add symbolic links to their hash values. 6 7my $openssl; 8 9my $dir; 10 11if(defined $ENV{OPENSSL}) { 12 $openssl = $ENV{OPENSSL}; 13} else { 14 $openssl = "openssl"; 15 $ENV{OPENSSL} = $openssl; 16} 17 18my $pwd; 19eval "require Cwd"; 20if (defined(&Cwd::getcwd)) { 21 $pwd=Cwd::getcwd(); 22} else { 23 $pwd=`pwd`; chomp($pwd); 24} 25my $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':'; # DOS/Win32 or Unix delimiter? 26 27$ENV{PATH} .= "$path_delim$dir/bin"; 28 29if(! -x $openssl) { 30 my $found = 0; 31 foreach (split /$path_delim/, $ENV{PATH}) { 32 if(-x "$_/$openssl") { 33 $found = 1; 34 $openssl = "$_/$openssl"; 35 last; 36 } 37 } 38 if($found == 0) { 39 print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n"; 40 exit 0; 41 } 42} 43 44if(@ARGV) { 45 @dirlist = @ARGV; 46} elsif($ENV{SSL_CERT_DIR}) { 47 @dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR}; 48} else { 49 $dirlist[0] = "$dir/certs"; 50} 51 52if (-d $dirlist[0]) { 53 chdir $dirlist[0]; 54 $openssl="$pwd/$openssl" if (!-x $openssl); 55 chdir $pwd; 56} 57 58foreach (@dirlist) { 59 if(-d $_ and -w $_) { 60 hash_dir($_); 61 } 62} 63 64sub hash_dir { 65 my %hashlist; 66 print "Doing $_[0]\n"; 67 chdir $_[0]; 68 opendir(DIR, "."); 69 my @flist = readdir(DIR); 70 # Delete any existing symbolic links 71 foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) { 72 if(-l $_) { 73 unlink $_; 74 } 75 } 76 closedir DIR; 77 FILE: foreach $fname (grep {/\.pem$/} @flist) { 78 # Check to see if certificates and/or CRLs present. 79 my ($cert, $crl) = check_file($fname); 80 if(!$cert && !$crl) { 81 print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n"; 82 next; 83 } 84 link_hash_cert($fname) if($cert); 85 link_hash_crl($fname) if($crl); 86 } 87} 88 89sub check_file { 90 my ($is_cert, $is_crl) = (0,0); 91 my $fname = $_[0]; 92 open IN, $fname; 93 while(<IN>) { 94 if(/^-----BEGIN (.*)-----/) { 95 my $hdr = $1; 96 if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) { 97 $is_cert = 1; 98 last if($is_crl); 99 } elsif($hdr eq "X509 CRL") { 100 $is_crl = 1; 101 last if($is_cert); 102 } 103 } 104 } 105 close IN; 106 return ($is_cert, $is_crl); 107} 108 109 110# Link a certificate to its subject name hash value, each hash is of 111# the form <hash>.<n> where n is an integer. If the hash value already exists 112# then we need to up the value of n, unless its a duplicate in which 113# case we skip the link. We check for duplicates by comparing the 114# certificate fingerprints 115 116sub link_hash_cert { 117 my $fname = $_[0]; 118 $fname =~ s/'/'\\''/g; 119 my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in "$fname"`; 120 chomp $hash; 121 chomp $fprint; 122 $fprint =~ s/^.*=//; 123 $fprint =~ tr/://d; 124 my $suffix = 0; 125 # Search for an unused hash filename 126 while(exists $hashlist{"$hash.$suffix"}) { 127 # Hash matches: if fingerprint matches its a duplicate cert 128 if($hashlist{"$hash.$suffix"} eq $fprint) { 129 print STDERR "WARNING: Skipping duplicate certificate $fname\n"; 130 return; 131 } 132 $suffix++; 133 } 134 $hash .= ".$suffix"; 135 print "$fname => $hash\n"; 136 $symlink_exists=eval {symlink("",""); 1}; 137 if ($symlink_exists) { 138 symlink $fname, $hash; 139 } else { 140 open IN,"<$fname" or die "can't open $fname for read"; 141 open OUT,">$hash" or die "can't open $hash for write"; 142 print OUT <IN>; # does the job for small text files 143 close OUT; 144 close IN; 145 } 146 $hashlist{$hash} = $fprint; 147} 148 149# Same as above except for a CRL. CRL links are of the form <hash>.r<n> 150 151sub link_hash_crl { 152 my $fname = $_[0]; 153 $fname =~ s/'/'\\''/g; 154 my ($hash, $fprint) = `"$openssl" crl -hash -fingerprint -noout -in '$fname'`; 155 chomp $hash; 156 chomp $fprint; 157 $fprint =~ s/^.*=//; 158 $fprint =~ tr/://d; 159 my $suffix = 0; 160 # Search for an unused hash filename 161 while(exists $hashlist{"$hash.r$suffix"}) { 162 # Hash matches: if fingerprint matches its a duplicate cert 163 if($hashlist{"$hash.r$suffix"} eq $fprint) { 164 print STDERR "WARNING: Skipping duplicate CRL $fname\n"; 165 return; 166 } 167 $suffix++; 168 } 169 $hash .= ".r$suffix"; 170 print "$fname => $hash\n"; 171 $symlink_exists=eval {symlink("",""); 1}; 172 if ($symlink_exists) { 173 symlink $fname, $hash; 174 } else { 175 system ("cp", $fname, $hash); 176 } 177 $hashlist{$hash} = $fprint; 178} 179 180