%PDF- %PDF-
Direktori : /etc/ |
Current File : //etc/exim.pl.rpmsave |
BEGIN { unshift @INC, '/etc/exim/perl'; } my $hasmd5; sub loadmd5 { if ( defined $hasmd5 ) { return; } eval { #require Digest::Perl::MD5; $hasmd5 = 1; }; } sub checkrelayhost { my ($hostaddress) = @_; if ( $hostaddress eq "127.0.0.1" ) { return 1; } open( RELAYHOSTS, "/etc/relayhosts" ); while (<RELAYHOSTS>) { s/\n//g; next if ( $_ eq "" ); if ( $hostaddress eq $_ ) { close(RELAYHOSTS); return 1; } } close(RELAYHOSTS); return (0); } sub getfilterfile { my ($user) = @_; my ($domain) = getusersdomain($user); return ("/etc/vfilters/${domain}"); } sub hasfilterfile { my ($user) = @_; my ($domain) = getusersdomain($user); if ( ${domain} eq "" ) { return (0); } if ( !-d "/etc/vfilters/${domain}" && -e "/etc/vfilters/${domain}" ) { return (1); } return (0); } sub checkvalias { my ( $domain, $local_part ) = @_; my ($hasval) = 0; my ($autoresponder) = 0; open( VAL, "/etc/valiases/$domain" ); while (<VAL>) { if ( $autoresponder && beginmatch( $_, "*:" ) ) { if (/:fail:/) { #stop processing the message as we already have #given an autoresponse and we do not want to send #a failure message $hasval = 1; last(); } } elsif ( beginmatch( $_, "${local_part}\@${domain}:" ) ) { my $defi; ( undef, $defi ) = split( /: /, $_ ); my (@DESTS) = split( /\,/, $defi ); foreach my $dest (@DESTS) { if ( $dest =~ /\/autorespond/ ) { $autoresponder = 1; } else { $hasval = 1; } } if ( !$autoresponder ) { last; } } } close(VAL); return ($hasval); } sub gensaheader_virtual { my ($domain) = @_; my ($owner) = getdomainowner($domain); my ($spamkey) = getspamkey($owner); return "X-Spam-Exim: $spamkey\n"; } sub gensaheader { my ($owner) = @_; my ($spamkey) = getspamkey($owner); return "X-Spam-Exim: $spamkey\n"; } sub getspamkey { my ($user) = @_; my ($homedir) = gethomedir($user); my ($spamkey); if ( -e "${homedir}/.spamkey" ) { open( SPAMKEY, "${homedir}/.spamkey" ); $spamkey = <SPAMKEY>; close(SPAMKEY); return ($spamkey); } else { if ( $> == 0 ) { my $pid; if ( !( $pid = fork() ) ) { &setuids($user); open( RANDOM, "/dev/urandom" ); read RANDOM, $spamkey, 4096; close(RANDOM); $spamkey =~ s/\W//g; $spamkey = substr( $spamkey, 0, 24 ); open( SPAMKEY, ">${homedir}/.spamkey" ); chmod( 0600, "${homedir}/.spamkey" ); print SPAMKEY $spamkey; close(SPAMKEY); exit(); } waitpid( $pid, 0 ); open( SPAMKEY, "${homedir}/.spamkey" ); $spamkey = <SPAMKEY>; close(SPAMKEY); return ($spamkey); } else { open( RANDOM, "/dev/urandom" ); read RANDOM, $spamkey, 4096; close(RANDOM); $spamkey =~ s/\W//g; $spamkey = substr( $spamkey, 0, 24 ); open( SPAMKEY, ">${homedir}/.spamkey" ); chmod( 0600, "${homedir}/.spamkey" ); print SPAMKEY $spamkey; close(SPAMKEY); return ($spamkey); } } } sub checksa_deliver { my ( $domain, $localpart, $received_protocol ) = @_; my ($owner) = getdomainowner($domain); my ($homedir) = gethomedir($owner); my ($passwd) = "${homedir}/etc/${domain}/passwd"; my ($addressexists) = 0; my ($spamkey) = getspamkey($owner); my $headers = Exim::expand_string('$message_headers'); if ( $headers =~ /^X-Spam-Exim: ${spamkey}$/m ) { return "no"; } if ( $received_protocol eq "local-bsmtp" ) { return "no"; } if ( -e $passwd ) { open( PASSWD, ${passwd} ); while (<PASSWD>) { if ( beginmatch( $_, "${localpart}:" ) ) { $addressexists = 1; } } close(PASSWD); } else { return "no"; } if ( $> == 0 ) { my $waittime = 1; while ( -e "${homedir}/.spamassassinquotatest" ) { if ( $waittime == 60 ) { last; } $waittime++; sleep(1); } my $pid; if ( !( $pid = fork() ) ) { umask(0002); &setuids($owner); open( QUOTATEST, ">${homedir}/.spamassassinquotatest" ); print QUOTATEST " " x 4096; close(QUOTATEST); exit(); } waitpid( $pid, 0 ); if ( !( ( stat("${homedir}/.spamassassinquotatest") )[7] == 4096 ) ) { unlink("${homedir}/.spamassassinquotatest"); return "no"; } unlink("${homedir}/.spamassassinquotatest"); } if ( -e $homedir . "/.spamassassinenable" && $addressexists ) { return "yes"; } else { return "no"; } } sub check_deliver { my ( $domain, $localpart ) = @_; my ($owner) = getdomainowner($domain); my ($homedir) = gethomedir($owner); my ($passwd) = "${homedir}/etc/${domain}/passwd"; my ($addressexists) = 0; if ( -e $passwd ) { open( PASSWD, ${passwd} ); while (<PASSWD>) { if ( beginmatch( $_, "${localpart}:" ) ) { $addressexists = 1; } } close(PASSWD); } else { return "no"; } if ($addressexists) { return "yes"; } else { return "no"; } } sub check_deliver_spam { my ( $domain, $localpart ) = @_; my ($owner) = getdomainowner($domain); if ( $owner eq "root" ) { return "no"; } my ($homedir) = gethomedir($owner); my ($passwd) = "${homedir}/etc/${domain}/passwd"; my ($addressexists) = 0; my ($isspam) = 0; if ( !-e $homedir . "/.spamassassinboxenable" ) { return "no"; } if ( -e $passwd ) { open( PASSWD, ${passwd} ); while (<PASSWD>) { if ( beginmatch( $_, "${localpart}:" ) ) { $addressexists = 1; } } close(PASSWD); } else { return "no"; } my $headers = Exim::expand_string('$message_headers'); if ( $headers =~ /^X-Spam-Status: Yes/m ) { $isspam = 1; } if ( $addressexists && $isspam ) { return "yes"; } else { return "no"; } } sub checkusersa { my ( $owner, $received_protocol ) = @_; if ( $owner eq "root" ) { return "no"; } my ($homedir) = gethomedir($owner); my ($spamkey) = getspamkey($owner); my $headers = Exim::expand_string('$message_headers'); if ( $headers =~ /^X-Spam-Exim: ${spamkey}$/m ) { return "no"; } if ( $received_protocol eq "local-bsmtp" ) { return "no"; } if ( $> == 0 ) { my $waittime = 1; while ( -e "${homedir}/.spamassassinquotatest" ) { if ( $waittime == 60 ) { last; } $waittime++; sleep(1); } my $pid; if ( !( $pid = fork() ) ) { umask(0002); &setuids($owner); open( QUOTATEST, ">${homedir}/.spamassassinquotatest" ); print QUOTATEST " " x 4096; close(QUOTATEST); exit(); } waitpid( $pid, 0 ); if ( !( ( stat("${homedir}/.spamassassinquotatest") )[7] == 4096 ) ) { unlink("${homedir}/.spamassassinquotatest"); return "no"; } unlink("${homedir}/.spamassassinquotatest"); } if ( -e $homedir . "/.spamassassinenable" ) { return "yes"; } else { return "no"; } } sub checkuserspambox { my ($owner) = @_; if ( $owner eq "root" ) { return "no"; } my ($homedir) = gethomedir($owner); my ($isspam) = 0; my $headers = Exim::expand_string('$message_headers'); if ( $headers =~ /^X-Spam-Status: Yes/m ) { $isspam = 1; } if ( -e $homedir . "/.spamassassinboxenable" && $isspam ) { return "yes"; } else { return "no"; } } sub checkspam { my $uid = Exim::expand_string('$originator_uid'); my $gid = Exim::expand_string('$originator_gid'); my $primary_hostname = Exim::expand_string('$primary_hostname'); my $sender = Exim::expand_string('$sender_address'); my $domain; my $islocald = 0; my @LD; open( LD, "/etc/localdomains" ); @LD = <LD>; close(LD); #MAILTRAP my $safegid = ( getgrnam("mailtrap") )[2]; if ( $uid >= 99 && $gid >= 99 && $safegid ne $gid && -e "/etc/eximmailtrap" ) { die "Gid $gid is not permitted to relay mail"; } #MAILTRAP if ( $sender =~ /\@${primary_hostname}/ ) { my $tuid = Exim::expand_string('${extract{2}{:}{${lookup passwd{$sender_address}{$value}}}}'); if ( $uid eq "0" and $tuid ne "0" ) { $uid = $tuid; } $domain = getusersdomain( ( getpwuid($uid) )[0] ); $islocald = 1; } else { my $sender_domain; ( undef, $sender_domain ) = split( /\@/, $sender ); $domain = $sender_domain; foreach my $ldomain (@LD) { $ldomain =~ s/\n//g; if ( $domain eq $ldomain ) { $islocald = 1; } } my $tuser = getdomainowner($sender_domain); $tuser =~ s/\\//g; my $tuid = Exim::expand_string( '${extract{2}{:}{${lookup passwd{\N' . $tuser . '\N}{$value}}}}' ); if ( $uid eq "0" and $tuid ne "0" ) { $uid = $tuid; } } if ( int($uid) == 99 && -e '/etc/webspam' ) { die "Mail sent by user nobody, UID 99, being discarded due to sender restrictions in WHM->Tweak Settings"; } if ( isdemo($uid) ) { die "Demo Accounts are not permitted to relay mail."; } my $headers = Exim::expand_string('$message_headers'); my $original_domain = Exim::expand_string('$original_domain'); my $sender_address_domain = Exim::expand_string('$sender_address_domain'); if ( !$islocald ) { return "yes"; } #logsmtpbw here my $now = time(); $domain =~ s/[^\w\.\-]//g; #we just can't trust user input my $message_size = Exim::expand_string('$message_size'); if ( $domain ne "" ) { my $maxmails = 0; open( CF, "/var/cpanel/cpanel.config" ); while (<CF>) { next if (/^#/); s/\n//g; my ( $var, $value ) = split( /=/, $_ ); if ( $var eq "maxemailsperhour" ) { $maxmails = int($value); } } close(CF); open( CPM, "/var/cpanel/maxemails" ); while (<CPM>) { s/\n//g; my ( $mdomain, $mmax ) = split(/=/); if ( $mdomain eq $domain ) { $maxmails = int($mmax); } } close(CPM); if ( $maxmails > 0 ) { my $nummailsinhour = readbacktodate("/usr/local/apache/domlogs/$domain-smtpbytes_log"); if ( $nummailsinhour > $maxmails ) { die "Domain $domain has exceeded the max emails per hour. Message discarded.\n"; } } open( DLOG, ">>/usr/local/apache/domlogs/$domain-smtpbytes_log" ); print DLOG "$now $message_size .\n"; close(DLOG); chmod( 0640, "/usr/local/apache/domlogs/$domain-smtpbytes_log" ); } #end logsmtpbw if ( !( $uid == 99 ) ) { #If it isn't the nobody user its ok return "yes"; } my ($receivedfor); my @RECPS; my @HEADERS = split( /\n/, $headers ); my ( $header, $email ); foreach $header (@HEADERS) { if ( $header =~ /^to:/i ) { my $line = $header; $line =~ s/^to: //ig; my @TRECPS = split( /[\,\;]/, $line ); foreach (@TRECPS) { push( @RECPS, $_ ); } } if ( $header =~ /^bcc:/i ) { my $line = $header; $line =~ s/^to: //ig; my @TRECPS = split( /[\,\;]/, $line ); foreach (@TRECPS) { push( @RECPS, $_ ); } } if ( $header =~ /^cc:/i ) { my $line = $header; $line =~ s/^to: //ig; my @TRECPS = split( /[\,\;]/, $line ); foreach (@TRECPS) { push( @RECPS, $_ ); } } if ( $header =~ /\tfor\s([^\;]+)/i ) { $receivedfor = $1; } } for ( my $i = 0; $i <= $#RECPS; $i++ ) { if ( $RECPS[$i] =~ /\<(\S+)\>/ ) { $RECPS[$i] = $1; } elsif ( $RECPS[$i] =~ /\((\S+)\)/ ) { $RECPS[$i] = $1; } } my $matchdomain = 0; my $matchrecv = 0; foreach my $ldomain (@LD) { $ldomain =~ s/\n//g; next if ( $ldomain !~ /\./ ); foreach my $recp (@RECPS) { if ( $recp =~ /\@${ldomain}$/ ) { $matchdomain = 1; } } if ( $receivedfor =~ /\@${ldomain}$/ ) { $matchrecv = 1; } } if ( $receivedfor ne "" && $matchrecv == 0 && -e "/etc/webspam" ) { die "you are not permitted to relay mail"; } if ($matchdomain) { return "yes"; } if ( -e "/etc/webspam" ) { die "you are not permitted to relay mail"; } return "yes"; } sub checkuserpass { my ( $user, $pass, $shift ) = @_; my ($domain); my ( $owner, $homedir, $uid, $gid ); if ( $user eq "" || ( $user eq $pass && length($shift) > 0 ) ) { #netscape sucks! $user = $pass; $pass = $shift; } $user =~ s/[\+\%\/\:]/\@/g; my $trueowner; if ( $user =~ /\@/ ) { ( $user, $domain ) = split( /\@/, $user ); if ( $domain eq "" ) { return "no"; } $owner = getdomainowner($domain); if ( $owner eq "" ) { return "no"; } $homedir = gethomedir($owner); if ( $homedir eq "" || $homedir eq "/" ) { return "no"; } $owner =~ s/\\//g; ( undef, $uid, $gid ) = split( /:/, Exim::expand_string( '${lookup passwd{\N' . $owner . '\N}{$value}}' ) ); $trueowner = $owner; } else { $user =~ s/\\//g; ( undef, $uid, $gid ) = split( /:/, Exim::expand_string( '${lookup passwd{\N' . $user . '\N}{$value}}' ) ); $trueowner = $user; } $trueowner =~ s/\///g; $trueowner =~ s/\.\.//g; if ( isdemo( ${trueowner} ) ) { return ('no'); } if ( checkpass( $user, $pass, $homedir, $domain ) ) { return "yes"; } else { return "no"; } } sub checkpass { my ( $user, $pass, $homedir, $domain ) = @_; my ($cpass); my ($retval) = 0; if ( $pass eq "" ) { return (0); } if ( -e "$homedir/etc/exim/authtab" ) { open( SHADOW, "$homedir/etc/exim/authtab" ); } else { open( SHADOW, "$homedir/etc/${domain}/shadow" ); } while (<SHADOW>) { if ( beginmatch( $_, "$user:" ) ) { ( $user, $cpass, undef ) = split( /:/, $_, 3 ); if ( crypt( $pass, $cpass ) eq $cpass ) { close(SHADOW); return (1); } else { close(SHADOW); return (0); } } } close(SHADOW); return (0); } sub getdomainowner { my ($domain) = @_; my ($user) = ''; open( USERDOMS, "/etc/userdomains" ); seek( USERDOMS, 0, 0 ); while (<USERDOMS>) { s/\n//g; if ( beginmatch( $_, "$domain: " ) ) { /\S+:\s(\S+)/; $user = $1; last; } } close(USERDOMS); return $user; } sub gethomedir { my ($user) = @_; $user =~ s/\\//g; return ( Exim::expand_string( '${extract{5}{:}{${lookup passwd{\N' . $user . '\N}{$value}}}}' ) ); } sub isdemo { my ($user) = @_; if ( $user =~ /^\d+$/ ) { $user = getpwuid($uid); } open( DEMOUSERS, "<", "/etc/demousers" ); my @DEMOUSERS = <DEMOUSERS>; close(DEMOUSERS); if ( grep( /^\Q${user}\E$/, @DEMOUSERS ) ) { return (1); } return (0); } sub readbacktodate { my ($filename) = @_; my ($buf); my ($filepos) = 0; my $now = time(); my $onehourago = ( $now - ( 60 * 60 ) ); my ($hitcount) = 0; my ( $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks ) = stat($filename); $filepos = ( $size - 4096 ); open( RF, "$filename" ); seek( RF, $filepos, 0 ); my $reachedend = 0; while ( $filepos >= -4096 ) { if ( $filepos < 0 ) { read( RF, $buf, ( $filepos + 4096 ) ); } else { read( RF, $buf, 4096 ); } if ( $filepos > 0 ) { $buf =~ /([^\n]+\n)/; $filepos += length($1); $buf = substr( $buf, length($1) ); } my @BUF = split( /\n/, $buf ); foreach ( reverse @BUF ) { my ( $ttime, $tbytes ) = split(/ /); if ( $ttime > $onehourago ) { $hitcount++; } else { $reachedend = 1; last(); } } last if ($reachedend); $filepos -= 4096; if ( $filepos < 0 ) { seek( RF, 0, 0 ); } else { seek( RF, $filepos, 0 ); } } close(RF); return ($hitcount); } sub beginmatch { my ( $haystack, $needle ) = @_; $haystack =~ tr/[A-Z]/[a-z]/; $needle =~ tr/[A-Z]/[a-z]/; if ( substr( $haystack, 0, length($needle) ) eq $needle ) { return (1); } return (0); } sub setuids { my ($user) = $_[0]; my ( $uid, $gid ); $user =~ s/\\//g; ( undef, $uid, $gid ) = split( /:/, Exim::expand_string( '${lookup passwd{\N' . $user . '\N}{$value}}' ) ); if ( !( $( = int($gid) ) ) { print "error setting gid\n"; exit; } if ( !( $) = "$gid $gid" ) ) { print "error setting gid\n"; exit; } if ( !( ( $< = $uid ) && ( $> = $uid ) ) ) { die "error setting uid ($uid) [$user]\n"; } return $uid; } sub popbeforesmtpwarn { my ($hostaddress) = @_; if ( !-e "/etc/eximpopbeforesmtpwarning" ) { return (); } my (@SENDERS); open( RELAYHOSTS, "/etc/relayhostsusers" ); while (<RELAYHOSTS>) { chomp(); my ( $rhost, $user ) = split( / /, $_ ); next if ( $rhost eq "" ); if ( $hostaddress eq $rhost ) { push( @SENDERS, $user ); } } close(RELAYHOSTS); if ( $#SENDERS > -1 ) { return ( "X-PopBeforeSMTPSenders: " . join( ",", @SENDERS ) ); } return (""); } sub mailtrapheaders { my $primary_hostname = Exim::expand_string('$primary_hostname'); my $original_domain = Exim::expand_string('$original_domain'); my $sender_address_domain = Exim::expand_string('$sender_address_domain'); my $originator_uid = Exim::expand_string('$originator_uid'); my $originator_gid = Exim::expand_string('$originator_gid'); my $caller_uid = Exim::expand_string('$caller_uid'); my $caller_gid = Exim::expand_string('$caller_gid'); my $xsource = $ENV{'X-SOURCE'}; my $xsourceargs = $ENV{'X-SOURCE-ARGS'}; my $xsourcedir = maskdir( $ENV{'X-SOURCE-DIR'} ); my $headers = "X-AntiAbuse: This header was added to track abuse, please include it with any abuse report\n" . "X-AntiAbuse: Primary Hostname - $primary_hostname\n" . "X-AntiAbuse: Original Domain - $original_domain\n" . "X-AntiAbuse: Originator/Caller UID/GID - [$originator_uid $originator_gid] / [$caller_uid $caller_gid]\n" . "X-AntiAbuse: Sender Address Domain - $sender_address_domain\n" . "X-Source: ${xsource}\n" . "X-Source-Args: ${xsourceargs}\n" . "X-Source-Dir: ${xsourcedir}"; return ($headers); } sub maskdir { my ($dir) = @_; open( PASSWD, "/etc/passwd" ); while (<PASSWD>) { my ( $homedir, $uid, $user ); ( $user, undef, $uid, undef, undef, $homedir, undef ) = split( /:/, $_ ); next if ( $uid < 100 ); next if ( length($homedir) < 3 ); if ( substr( $homedir, -1, 1 ) ne "/" ) { $homedir .= "/"; } if ( beginmatch( ${dir}, ${homedir} ) ) { my $maskeddir = $dir; $maskeddir =~ s/^${homedir}//g; $maskeddir = getusersdomain($user) . ":" . "/" . $maskeddir; close(PASSWD); return ($maskeddir); } } close(PASSWD); return ($dir); } sub getusersdomain { my ($user) = @_; open( USERDOMS, "/etc/trueuserdomains" ); seek( USERDOMS, 0, 0 ); while (<USERDOMS>) { s/\n//g; if ( endmatch( $_, " ${user}" ) ) { /(\S+):/; $domain = $1; last; } } close(USERDOMS); return $domain; } sub endmatch { my ( $haystack, $needle ) = @_; $haystack =~ tr/[A-Z]/[a-z]/; $needle =~ tr/[A-Z]/[a-z]/; if ( substr( $haystack, -1 * length($needle) ) eq $needle ) { return (1); } return (0); } if ( -e "/usr/share/amavis/amavis-filter" && !-e "/etc/noamavis" ) { do '/usr/share/amavis/amavis-filter'; } if ( -e "/etc/exim.pl.local" ) { do '/etc/exim.pl.local'; } 1; # The following notice referes to code below this line: # # "THE BEER-WARE LICENSE" (Revision 42): # <phk@login.dknet.dk> wrote this file. As long as you retain this notice you # can do whatever you want with this stuff. If we meet some day, and you think # this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp # # based on Crypt::PasswdMD5 # # bdraco@darkorb.net http://cpanel.net sub checkpassword { my ( $password, $cryptedpassword ) = @_; if ( $cryptedpassword eq "" || $cryptedpassword =~ /^\!/ || $cryptedpassword =~ /^\*/ ) { return (0); } loadmd5(); if ( $cryptedpassword =~ /^\$1\$(.+)\$.*/ && $hasmd5 ) { my $salt = getsalt($cryptedpassword); if ( unix_md5_crypt( $password, $salt ) eq $cryptedpassword ) { return (1); } } else { if ( crypt( $password, $cryptedpassword ) eq $cryptedpassword ) { return (1); } } return (0); } sub unix_md5_crypt { my $Magic = '$1$'; # Magic string my ( $pw, $salt ) = @_; my $passwd; $salt =~ s/^\Q$Magic//; # Take care of the magic string if # if present. $salt =~ s/^(.*)\$.*$/$1/; # Salt can have up to 8 chars... $salt = substr( $salt, 0, 8 ); my $ctx = new Digest::Perl::MD5; # Here we start the calculation $ctx->add($pw); # Original password... $ctx->add($Magic); # ...our magic string... $ctx->add($salt); # ...the salt... my ($final) = new Digest::Perl::MD5; $final->add($pw); $final->add($salt); $final->add($pw); $final = $final->digest; for ( my $pl = length($pw); $pl > 0; $pl -= 16 ) { $ctx->add( substr( $final, 0, $pl > 16 ? 16 : $pl ) ); } # Now the 'weird' xform for ( my $i = length($pw); $i; $i >>= 1 ) { if ( $i & 1 ) { $ctx->add( pack( "C", 0 ) ); } # This comes from the original version, # where a memset() is done to $final # before this loop. else { $ctx->add( substr( $pw, 0, 1 ) ); } } $final = $ctx->digest; # The following is supposed to make # things run slower. In perl, perhaps # it'll be *really* slow! for ( my $i = 0; $i < 1000; $i++ ) { my $ctx1 = new Digest::Perl::MD5; if ( $i & 1 ) { $ctx1->add($pw); } else { $ctx1->add( substr( $final, 0, 16 ) ); } if ( $i % 3 ) { $ctx1->add($salt); } if ( $i % 7 ) { $ctx1->add($pw); } if ( $i & 1 ) { $ctx1->add( substr( $final, 0, 16 ) ); } else { $ctx1->add($pw); } $final = $ctx1->digest; } # Final xform $passwd = ''; $passwd .= to64( int( unpack( "C", ( substr( $final, 0, 1 ) ) ) << 16 ) | int( unpack( "C", ( substr( $final, 6, 1 ) ) ) << 8 ) | int( unpack( "C", ( substr( $final, 12, 1 ) ) ) ), 4 ); $passwd .= to64( int( unpack( "C", ( substr( $final, 1, 1 ) ) ) << 16 ) | int( unpack( "C", ( substr( $final, 7, 1 ) ) ) << 8 ) | int( unpack( "C", ( substr( $final, 13, 1 ) ) ) ), 4 ); $passwd .= to64( int( unpack( "C", ( substr( $inal, 2, 1 ) ) ) << 16 ) | int( unpack( "C", ( substr( $final, 8, 1 ) ) ) << 8 ) | int( unpack( "C", ( substr( $final, 14, 1 ) ) ) ), 4 ); $passwd .= to64( int( unpack( "C", ( substr( $final, 3, 1 ) ) ) << 16 ) | int( unpack( "C", ( substr( $final, 9, 1 ) ) ) << 8 ) | int( unpack( "C", ( substr( $final, 15, 1 ) ) ) ), 4 ); $passwd .= to64( int( unpack( "C", ( substr( $final, 4, 1 ) ) ) << 16 ) | int( unpack( "C", ( substr( $final, 10, 1 ) ) ) << 8 ) | int( unpack( "C", ( substr( $final, 5, 1 ) ) ) ), 4 ); $passwd .= to64( int( unpack( "C", substr( $final, 11, 1 ) ) ), 2 ); $final = ''; return ( $Magic . $salt . '$' . $passwd ); } sub to64 { my $itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; my ( $v, $n ) = @_; my $ret = ''; while ( --$n >= 0 ) { $ret .= substr( $itoa64, $v & 0x3f, 1 ); $v >>= 6; } $ret; } sub getsalt { my ($cpass) = @_; ( $cpass =~ /^\$1\$(.+)\$.*/ ) and return $1; ( $cpass =~ /^(..)*/ ) and return $1; } sub democheck { my $uid = Exim::expand_string('$originator_uid'); if ( isdemo($uid) ) { return 'yes'; } return 'no'; } 1;