To: sdorner@qualcomm.com Subject: Password daemon for MH/Eudora Organisation: BNR Europe, HARLOW, Essex CM17 9NA, GB Phone: +44 279 402423 From: Andrew Macpherson (Postmaster) Steve, Thanks for helping John Bingham out so much. Since you've added a password changer, here is a daemon for those sites which use MH bpop (ie pop support for non unix users from a unix host). If it doesn't work the way you want I'll happily make changes. #!/usr/bin/perl # # Author Andrew Macpherson # # /DD.ID=1248566/G=Andrew/S=Macpherson/PRMD=BNR/ADMD= /C=GB/ # to support the eudora password change protocol # # Entry for /etc/services: # epass 106/tcp # And for /etc/inetd.conf: # epass stream tcp nowait pop /path/to/in.poppass # # $Header: /tmp_mnt/u/andrew/andrew/src/poppass/RCS/in.poppass,v 1.4 14/11/92 16:29:12 andrew Exp $ # # $Log: in.poppass,v $ # Revision 1.4 14/11/92 16:29:12 andrew # Inetd looping with wait, admin features not so usefull # # Revision 1.3 14/11/92 15:32:42 andrew # Add admin password reset capability # # Revision 1.2 14/11/92 15:05:21 andrew # Off by 1 report of existing accounts. # # Make use of the locking given by only allowing 1 daemon to # add users without losing password changes. # # Revision 1.1 14/11/92 14:10:23 andrew # Initial revision # $| = 1; $Id = '$Id: in.poppass,v 1.4 14/11/92 16:29:12 andrew Exp $'; $perl = '/usr/bin/perl' ; # Used in system() later $MyName="POPpass" ; require "syslog.pl"; &openlog($MyName,"pid,cons,nowait", "auth"); $\ = "\r\n" ; # Set output seperator for chitchat over tcp chop( $host=`hostname` ); ( $me, $pop_pass, $b, $c, $d, $e, $f, $dir, $g ) = getpwnam("pop") ; if ( ! $dir || ! -w $dir . '/POP' || ! chdir($dir) ) { print "420 Configuration error, please tell postmaster@$host" ; &syslog("notice", "Cannot access ${dir}/POP"); &closelog(); die; } print "200 hello $host POP password service" ; $user = ''; $curcrypt = '' ; $newcrypt = '' ; while(<>) { chop; ( $action, $arg, $extra ) = split(/\s+/, $_); if ( $action =~ m/^user$/i ) { $user = $arg ; $curcrypt = '' ; print "300 Hello $arg, please prove it with your password" ; } elsif ( $action =~ m/^pass$/i ) { $curcrypt = '' ; if ( $user eq '' ) { print "400 I need to know who you claim to be first" ; next ; } &ValidUser($user, $arg) ; # Sets $curcrypt if true if ($curcrypt eq '') { &syslog('notice', "invalid POP password offered for $user"); sleep(20); # Slow him down print "500 Imposter! I have issued a security alert" ; last; } if ( $user eq 'pop' ) { print "200 Hail Oh great and glorious leader" ; } else { print "200 Ok, Now I believe you are $user" ; } &syslog('info', "POP user $user validated"); } elsif ( $action =~ m/^newpass$/i ) { if ( $user eq '' ) { print "400 Who are you? Logon with USER and PASS first" ; next ; } if ( $curcrypt eq '' ) { print "401 Until you give me your old password," . " I have to believe you are an Imposter"; next ; } if (crypt($arg, $curcrypt) eq $curcrypt) { print "402 No it isn't, it's the same" ; next; } $newcrypt = crypt($arg, substr($curcrypt,1,2)); $ok = system("$perl -pi.bak " . "-e 's:$curcrypt:$newcrypt: if m/^$user:/ ;' POP" ) ; if ( $ok / 256 ) { print "500 Sorry, update failed" ; } else { print "200 OK"; $curcrypt = $newcrypt ; } } elsif ( $action =~ m/^quit$/i ) { print "200 $host, Glad to help" ; last ; } elsif ( $action =~ m/^status$/i ) { print "200 " . ($user eq '' ? "no user" : "user $user") . ($curcrypt eq '' ? ' not' : '') . ' authenticated' ; } elsif ( $action =~ m/^version$/i ) { print "200 $MyName $Id" ; } elsif ( $action =~ m/^help$/i ) { print "200 Supported actions:" . " USER PASS NEWPASS HELP QUIT STATUS VERSION" . (( $user eq 'pop' && $curcrypt ne '') ? " NEWUSER SETPASS" : ""); } elsif ( $user eq 'pop' && $curcrypt ne '' && $action =~ m/^newuser$/i ) { if ( $arg ne '' && $extra ne '' ) { &NewUser($arg, $extra) ; } else { print "400 Newuser user pass" ; } } elsif ( $user eq 'pop' && $curcrypt ne '' && $action =~ m/^setpass$/i && $arg ne '' && $extra ne '' ) { $newcrypt = crypt($extra, substr($curcrypt,1,2)); $ok = system("$perl -pi.bak " . "-e 's|$arg::$arg.*|$arg::$arg:$newcrypt::::::0| ;' POP" ) ; if ( $ok / 256 ) { print "500 Sorry, update failed" ; } else { print "200 OK"; $curcrypt = $newcrypt ; } } else { print "400 I don't understand '$action' try help" ; } } &closelog(); exit 0; sub ValidUser { local($user, $pass) = @_ ; if ( $user eq 'pop' ) { $curcrypt = $pop_pass if (crypt($pass, $pop_pass) eq $pop_pass); return ; } $curcrypt = ''; # Just in case open(POP, '<' . "POP") ; @entry = grep(/^$user:/, ); close POP; if ($#entry == -1) { &syslog('notice', "POP user $user does not exist"); return; } if ($#entry != 0) { $accts = $#entry + 1; print "520 there are $accts POP accounts for $user" ; &syslog('notice', "POP user $user has $accts accounts"); &closelog(); exit 1; } $entry = shift(@entry); ( $a, $b, $c, $ppass, @rest) = split(/:/, $entry) ; $curcrypt = $ppass if (crypt($pass, $ppass) eq $ppass); } sub NewUser { local($user, $pass) = @_ ; open(POP, '<' . "POP") ; @entry = grep(/^$user:/, ); close POP; if ($#entry != -1) { &syslog('notice', "POP user $user already exists"); print "500 $user exists" ; return ; } open(POP, '>>' . 'POP') ; printf POP "$user::$user:" . crypt($pass, '//') . "::::::0\n" ; close POP ; print "200 $user added" ; } __END__ This program was written to support Steve Dorner's Eudora program password changing routine for systems using the MH/pop. It is released for general use. Andrew Macpherson reserves and asserts the right to be known as the author of this work. .