#!/usr/bin/perl
#
# Copyright 1992, A. Brossard
#
#  Crypt_passwd converts the passwords of a given password file to the
# new encryption method
#  It also updates the libc.* so that it contains the new encryption routine
#  It also updates /sbin/init to use the new encryption routine
#  When used as a program ($src_files not defined), it may take a list
# of password files (in /etc/passwd format) to convert.  If no files are
# given, it converts /etc/passwd, /etc/security/passwd.adjunct and the NIS
# password file if there is one.
#
# upgrade the /etc/passwd file to deal with the new crypt routine
#
sub crypt_passwd {
    local( $root, $usr, $src_files, $arch, $passwd_file, $do_libc ) = @_;
    local( $username, $pwd, $end, $new_pwd, $maybe_done, $init_done, $did_init );
    local( $backup ) = "$passwd_file.bak";

    if( ! open( PASSWD, "$passwd_file" ) ) { 
	&print( "Failed to open $passwd_file for reading, not changed\n", "  Incapable de lire le fichier $passwd_file, aucun changement d'effectu.\n");
	return 0;
    }
#
#	Let's verify that this file hasn't been converted yet
#
    if( -e "$root$crypt_file_done" ) {
	if( ! open( CRYPT, "$root$crypt_file_done" ) ) {
	    &print( "There is a log of which password file has been converted, but I can't read
it ($root$crypt_file_done)!  So I'm not converting anything.\n", 
"Il existe une liste de fichiers convertis de mots de passe, mais je ne peux
pas la lire ($root$crypt_file_done)!  Alors je ne convertis rien.\n");
	    close PASSWD;
	    return 0;
	}
	while( $_ = <CRYPT> ) {
	    chop;
	    if( $_ eq '/sbin/init' ) { $init_done = 1; next; }
	    if( $_ eq $passwd_file || $_ eq "/a$passwd_file" ) {
		if( ! -e "$passwd_file.crypt" ) {
		    &print( "$passwd_file has already been converted on $host!
", " $passwd_file a dja t converti sur $host!\n");
		    close PASSWD; close CRYPT;
		    return 0;
		}
		$maybe_done = 1;
		if(  -e "$passwd_file.maybe.converted" ) {
		    $backup = '/dev/null';
		} else {
		    $backup = "$passwd_file.maybe.converted";
		}
		&print( "$passwd_file has MAYBE been already converted on $host!  The new version
will be installed anyway and the actual version will be kept under the name
$passwd_file.maybe.converted.  Please check against
$passwd_file.crypt.old (result from previous convertion?) to find out which
version is good, $passwd_file.bak is the original file before any
conversion ever happened.
", "$passwd_file a PEUT-TRE t dja converti sur $host!  Une nouvelle
version sera tout de mme installe et le fichier $passwd_file actuel sera
sauvegard sous le nom $passwd_file.maybe.converted.  Veuillez vrifier avec
$passwd_file.crypt.old (rsultat de la conversion prcdente?) pour voir
quelle version est bonne, $passwd_file.bak est l'ancien fichier avant
toute conversion.\n");
		last;
	    }
	}
	close CRYPT;
    }
    if( ! $init_done && $passwd_file =~ m#/etc.*passwd#) {
	chdir '/sbin';
	rename( 'init', 'init.FCS' );
	system( "cp -p $src_files/$arch/init.crypt init" );
	chmod 0755, 'init';
	$did_init = 1;
    }
    if( ! open( PASSWD_BCK, ">$backup" ) ) { 
	&print( "Failed to open $backup for writing, not changed\n", "Incapable d'crire dans le fichier $backup, aucun changement d'effectu.\n");
	close PASSWD;
	return 0;
    }

    if( $maybe_done && ! -e "$passwd_file.crypt.old" ) {
	rename( "$passwd_file.crypt", "$passwd_file.crypt.old" );
    }

    if( ! open( NEW, ">$passwd_file.crypt" ) ) { 
	&print( "Failed to open $passwd_file.crypt for writing, not changed\n", "Incapable d'crire dans le fichier $passwd_file.crypt, aucun changement d'effectu.\n");
	close PASSWD; close PASSWD_BCK;
	return 0;
    }
#
#	Make sure to use the new libraries, because they are needed by
#	the conversion program

    local( $keep_ld_path ) = $ENV{'LD_LIBRARY_PATH'};
    $ENV{'LD_LIBRARY_PATH'} = "$src_files/$arch";
    while( $_ = <PASSWD> ) {
	print PASSWD_BCK $_ unless $maybe_done;
	($username, $pwd, $end) = /^([^:]+:)([^:]*)(:.*\n)$/;
	if( ! $username ) {
	    if( /^\+/ ) { print NEW; next; }
	    &print( "Unable to parse $passwd_file: --$_--\n",
		"Incapable de comprendre $passwd_file: --$_--\n");
	    close PASSWD; close PASSWD_BCK; close NEW;
	    return 0;
	}
	if( $pwd && $pwd ne '*' && $pwd ne 'NOLOGIN' && $pwd !~ /^##/ ) {
	    chop($new_pwd = `$src_files/$arch/convert_passwords '$pwd'`);
	    if( ! $new_pwd ) {
		close PASSWD; close PASSWD_BCK; close NEW;
		&print( "The convertion of the password came back empty?\n", "La conversion du mot de passe n'a pas fonctionn??\n");
		return 0;
	    }
	} else { $new_pwd = $pwd; }
	print NEW "$username$new_pwd$end";
    }
    close PASSWD; close PASSWD_BCK; close NEW;
    chmod 0600, $backup if $backup =~ /.bak$/;
    $ENV{'LD_LIBRARY_PATH'} = $keep_ld_path;

    if( $do_libc ) {	# skip ONLY if already done
	require 'upgrade_libc';
	&print( "Do NOT interrupt NOW or you'll not be able to login again!\n", "Ne PAS interrompre maintenant car vous ne pourriez plus vous connecter
sur cette machine.\n");
	&upgrade_libc( $root, $usr, $src_files, $arch );
    }
    if( ! $maybe_done ) {	# Already present!
	local( $tmp ) = $passwd_file; $tmp =~ s#^/a/#/#; $tmp =~ s#//#/#g;
	open( CRYPT, ">>$root$crypt_file_done" ) ||
	    die $lang ? "Impossible de crer '$root$crypt_file_done'\n" :
			"Couldn't create '$root$crypt_file_done'\n";
	print CRYPT "$tmp\n";
	print CRYPT "/sbin/init\n" if $did_init;
	close CRYPT;
    }
    rename( "$passwd_file.crypt", "$passwd_file" );
    if( $do_libc ) {
	&print( "Ok, the machine is now using the new libc and the new password file
", "Ok, cette machine utilise maintenant la nouvelle libc et le nouveau fichier
de mots de passe.  L'ancien a t conserv avec le suffix .bak\n");
    }
    return 1;
}

sub crypt_NIS_passwd {
    local( $root, $usr, $src_files, $arch ) = @_;
    chdir $root . 'var/yp';
    require 'get_nis_passwd_file';
    local( $pwd, $pwd_adj ) = &get_nis_passwd_file;
    if( $pwd && $pwd ne 'NIS' ) {
	if( $pwd ne '/etc/passwd' ) {
	    &crypt_passwd( $root, $usr, $src_files, $arch, "$root$pwd", 0);
	}
	if( $pwd_adj ne '/etc/passwd/security/passwd.adjunct' ) {
	    &crypt_passwd( $root, $usr, $src_files, $arch, "$root$pwd_adj", 0);
	}
	&print( "You need to do a make in /var/yp.\n",
	     "Vous devrez faire un make dans /var/yp.\n");
    } elsif( $pwd eq 'NIS' ) {
	&print( "If this machine is the NIS master, then you have a problem because the NIS
password database was not converted to use the new encryption routines.\n",
	    "Si cette machine ($host) est le matre NIS, alors vous avez un problme
car la base de donne NIS pour les mots de passe n'a pas t convertie.\n");
    } # else, not the NIS master
}

sub crypt_all_passwd_file {
    local( $root, $usr, $src_files, $arch, $do_libc ) = @_;
    &print( "Re-encrypting password file(s), this takes 2 or 3 seconds per password.\n", "Re-encryption des fichiers de mots de passe, ceci prend quelques secondes par
mot de passe.\n" );
    &crypt_passwd( $root, $usr, $src_files, $arch,
		"${root}etc/passwd", $do_libc);
    &crypt_passwd( $root, $usr, $src_files, $arch,
		"${root}etc/security/passwd.adjunct", 0)
		if -e "${root}etc/security/passwd.adjunct";
    &crypt_NIS_passwd( $root, $usr, $src_files, $arch ) if $sunupgrade;
}

if( !$src_files ) {	# standalone
    local( $mount ) = 0;
    $src_files = "/tmp/4.1.2";
    chop( $arch=`arch` );
    chop( $host=`hostname` );
    $rhost='sasun1';
    $crypt = 1;	# Use special encryption library
    $crypt_file='/etc/install/crypt';
    $crypt_file_done='/etc/install/crypt.done';
    $sunupgrade = 1;	# We have a valid /etc and /var/yp
    $mount_prog = "/export/mnt/4.1.2";
    push( @INC, "$src_files/perl-lib");

    $ENV{PATH}="/usr/etc:$ENV{PATH}";

    if( ! -d "$src_files/$arch" ) {
	$mount = 1;
	mkdir( $src_files, 02755);
	system "mount $rhost:$mount_prog $src_files";
    }
    if( ! -d "$src_files/$arch" ) {
	die  $lang ? "mount de $rhost:$mount_prog sur $src_files a chou, aborting\n" : "mount of $rhost:$mount_prog on $src_files failed, aborting\n" if $?;
    }
    push( @INC, "$src_files/perl-lib");
    require 'print.pl';

    if( $#ARGV >= 0 ) {
	while( $#ARGV >= 0 ) {
	    shift @ARGV;
	    &crypt_passwd( '/', '/usr', $src_files, $arch, $_, 1 );
	}
    } else {
	&crypt_all_passwd_file( '/', '/usr', $src_files, $arch, 1 );
	&print( "All password files have been converted\n",
		"Ok, tous les fichiers passwd ont t converti\n");
    }
    system "umount $src_files" if $mount;
    rmdir $src_files if $mount;
}
1;
