#!/usr/bin/perl -W

#   Copyright (C) 2000 Vince (Vincent Saugey), MandrakeSoft <vince@mandrakesoft.com>

#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2, or (at your option)
#   any later version.

#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.

#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


my $PACKAGE_CHECK=1;
my $BINARIES_CHECK=1;
my $dont_apply="false";

sub check_package ($)
{
    my $package;
    ($package) = @_;
    return system ("rpm -q $package > /dev/null");
}

sub set_nsswitch_priority($)
{
    my $type;
    ($type) = @_;
    print ("Change nsswitch order\n");
    open (NSSWITCH, "</etc/nsswitch.conf");
    open (NEWNSSWITCH, ">/etc/nsswitch.conf.new");
    while (<NSSWITCH>) {
	if (my ($cat, $options) = /^(\s*(?:passwd|shadow|group|automount):\s*)(.*)/) {
	    my @other = 
	      grep { $_ ne $type && $_ ne 'files' } # remove it and 'files'
	      split(' ', $options);
	    print NEWNSSWITCH $cat, join(' ', 'files', $type ? $type : (), @other), "\n";
	}
	else {
	    print NEWNSSWITCH $_;
	    
	}
    }
    close(NEWNSSWITCH);
    close(NSSWITCH);
    rename "/etc/nsswitch.conf.new", "/etc/nsswitch.conf";
}

sub pam_change ($) {
    my $type;
    print "Change pam conf\n";
    ($type) = @_;
    open (PAMFILE, ">/etc/pam.d/system-auth");
    if ($type eq "noldap") {	
	print PAMFILE <<EOF
#%PAM-1.0
 
auth       required       pam_nologin.so
auth       required       pam_env.so
auth       sufficient     pam_unix.so likeauth nullok try_first_pass
auth       required       pam_deny.so
 
account    sufficient     pam_unix.so
account    required       pam_deny.so
 
password   required       pam_cracklib.so retry=3
password   sufficient     pam_unix.so nullok use_authtok md5 shadow use_first_pass
password   required       pam_deny.so
 
session    required       pam_limits.so
session    sufficient     pam_unix.so
session    required       pam_deny.so
EOF
    ;
    }
    else {
	print PAMFILE <<EOF
#%PAM-1.0
 
auth       required       pam_nologin.so
auth       required       pam_env.so
auth       sufficient     pam_pwdb.so likeauth nullok
auth       sufficient     pam_ldap.so use_first_pass
auth       required       pam_deny.so
 
account    sufficient     pam_unix.so
account    sufficient     pam_ldap.so
account    required       pam_deny.so
 
password   required       pam_cracklib.so retry=3
password   sufficient     pam_pwdb.so nullok use_authtok md5 shadow use_first_pass
password   sufficient     pam_ldap.so use_authtok
password   required       pam_deny.so

session    required       pam_limits.so
session    sufficient     pam_unix.so
session    sufficient     pam_ldap.so
session    required       pam_deny.so
EOF
    ;
    }
    close (PAMFILE);
}


sub pam_conf_setup {
    my $sslmode;
    my $basedn;
    my @servers;
    
    ($sslmode, $basedn, @servers) = @_;
    
    print ("Change ldap configuration\n");
    open (LDAPCONF, "</etc/ldap.conf");
    open (NEWLDAPCONF, ">/etc/ldap.conf.new");
    while (<LDAPCONF>) {
	if (/^\s*host\s+/) {
	    print NEWLDAPCONF "host " . "@servers" . "\n";
	    next;
	}
	if (/^\s*base\s+/) {
	    print NEWLDAPCONF "base $basedn\n";
	    next;		
	}
	if (/^\s*port\s+/) {
	    if ($sslmode eq "on") {
		print NEWLDAPCONF "port 636\n";
	    }
	    else {
		print NEWLDAPCONF "port 389\n";
	    }
	    next;		
	}
	if (/^\s*ssl\s+/) {
	    print NEWLDAPCONF "ssl on\n" if ($sslmode eq "on");
	    print NEWLDAPCONF "ssl off\n" if ($sslmode eq "off");
	    print NEWLDAPCONF "ssl start_tls\n" if ($sslmode eq "off");
	}
	if (/^\s*nss_base_(passwd|shadow)\s+/) {
	    print NEWLDAPCONF "nss_base_$1" . "\t ou=People,$basedn\n";
	    next; 
	}
	if (/^\s*nss_base_group\s+/) {
	    print NEWLDAPCONF "nss_base_group\t ou=Group,$basedn\n";
	    next;
	}
	print NEWLDAPCONF $_;
    }
    rename "/etc/ldap.conf.new", "/etc/ldap.conf";
}

sub yp_conf_setup ($$) {
    my ($ypdomain, $server);
    ($ypdomain, $server) = @_;

    print ("Set yp configuration\n");
    open (YPCONF, "</etc/sysconfig/network");
    open (NEWYPCONF, ">/etc/sysconfig/network.new");
    while (<YPCONF>) {
	print NEWYPCONF $_ if (!/^\s*NISDOMAIN=/);
    }
    print NEWYPCONF "NISDOMAIN=$ypdomain\n";
    close (YPCONF);
    close (NEWYPCONF);
    rename "/etc/sysconfig/network.new", "/etc/sysconfig/network";
    open (YPCONF, "</etc/yp.conf");
    open (NEWYPCONF, ">/etc/yp.conf.new");
    while (<YPCONF>) {
	print NEWYPCONF $_ if (!/^\s*(domain|ypserver)\s+.+$/);
    }
    if (!($server eq "") and ($ypdomain eq "")) {
	print NEWYPCONF "ypserver $server\n";				
    }
    else
    {
	if (($server eq "")) {
	    print NEWYPCONF "domain $ypdomain broadcast\n";				
	}
	else {
	    print NEWYPCONF "domain $ypdomain server $server\n";		
	}
    }
    close (YPCONF);
    close (NEWYPCONF);
    rename "/etc/yp.conf.new", "/etc/yp.conf";
}

sub exit_with_usage() {
    print "Usage drakeauth [file|yp|ldap] ...\n";
    print "file : [noshadow|shadow] [-m md5|crypt] (default shadow, md5)\n";
    print "yp : domainname [-s server]\n";
    print "ldap : [tls|nossl|ssl] [-s server]* [-D base dn]\n";
    exit 1;
}

sub set_file_auth {
    my $SHADOW="TRUE";
    my $CRYPT_METHOD="md5";
    foreach $i (@_) {
	if ($i eq "noshadow") {
	    $SHADOW="FALSE";
	    next;
	}
	if ($i eq "crypt") {
	    $CRYPT_METHOD="crypt";
	    next;
	}
	exit_with_usage() if (!($i eq "shadow" or $i eq "md5"));
    }

#    print "FILE: SHADOW=$SHADOW, CRYPT_METHOD=$CRYPT_METHOD\n";
    set_nsswitch_priority("");
    pam_change ("noldap");
    system ("chkconfig --del ypbind") if (-e "/etc/init.d/ypbind");
    if (-e "/var/lock/subsys/portmap") {
	system ("service portmap stop") ;
    }
    if (-e "/var/lock/subsys/ypbind" || -e "/var/run/ypbind.pid") {
	system ("service ypbind stop") ;
    }
    system ("service nscd restart") if -e "/var/lock/subsys/nscd";
    exit(0);
}

sub set_ldap_auth {
    my @packages=("openldap-clients", "nss_ldap", "pam_ldap");
    my @binaries=();
    
#default conf
    my @serveurs=();
    my $basedn="";
    my $sslmode="tls";

# parse arg
    while (@ARGV) {
	$_ = shift @ARGV;
	if ($_ eq "-s") {
	    $_ = shift @ARGV;	    
	    push @serveurs, ($_);
	    next;
	}
	if (/nossl/) {
	    $sslmode="off";
	    next;
	}
	if (/ssl/) {
	    $sslmode="on";
	    next;
	}
	if ($_ eq "-D") {
	    $_ = shift @ARGV;	    
	    $basedn = $_;
	    next;	    
	}
	next if (/ssl|tls/);
	print STDERR "token doesn't known \"$_\"\n";
	exit_with_usage();
    }

#check dependencies
    if ($PACKAGE_CHECK) {	
	for $i (@packages) {
	    if (check_package($i)) {
		print STDERR ("You have to install $i package for do this\n");
		exit (2);
	    }
	}
    }
    
    if ($BINARIES_CHECK) {
	for $i (@binaries) {
	    if (! -x $i ) {				
		print STDERR ("You have to have install $i for do this\n"); 	
		exit (2);
	    }	    
	}
    }

    if ($basedn eq "") {
	while (@serveurs) {
	    print "search base dn of server $_\n";
	    my $root = `ldapsearch -x -h $_ -b "" -s base + | grep namingContexts`;
	    if ($root =~ /namingContexts: (.+)/) {
		print "Find root = $1\n";
		$basedn = $1;
		last;
	    }
	}
    }

    exit_with_usage() if (($basedn eq "") || (scalar(@serveurs) < 1));

    print "LDAP: serveur=@serveurs: basedn=$basedn serveur number ". scalar(@serveurs) . "\n";
    set_nsswitch_priority("ldap");
    pam_change ("ldap");
    pam_conf_setup (($sslmode, $basedn, @serveurs));
    system ("service nscd restart") if -e "/var/lock/subsys/nscd";
    exit (0);
}

sub set_yp_auth
{

    my @packages=("net-tools", "yp-tools", "ypbind");
    my @binaries=("/bin/ypdomainname");

    my ($ypdomain, $server) = ("","");

    while (@ARGV) {
	$_ = shift @ARGV;
	if ($_ eq "-s") {
	    $server = shift @ARGV;
	    next;
	}
	if ($ypdomain eq "") {	    
	    $ypdomain = $_;
	    next;
	}
	exit_with_usage();
    }

#check dependencies
    if ($PACKAGE_CHECK) {	
	for $i (@packages) {
	    if (check_package($i)) {
		print STDERR ("You have to install $i package for do this\n");
		exit (2);
	    }
	}
    }
    
    if ($BINARIES_CHECK) {
	for $i (@binaries) {
	    if (! -x $i ) {				
		print STDERR ("You have to have $i install for do this\n"); 	
		exit (2);
	    }	    
	}
    }
    
    exit_with_usage() if (($ypdomain eq "") and ($server eq ""));
	

    print "YP: domain: $ypdomain server: $server\n";
    yp_conf_setup ($ypdomain, $server);
    `chkconfig --add ypbind`;
    `chkconfig --add portmap`;
    set_nsswitch_priority("nis");
    `ypdomainname $ypdomain`  if ($dont_apply eq "false");
    system ("service nscd restart") if -e "/var/lock/subsys/nscd";
    if (-e "/var/lock/subsys/portmap") {
	system ("service portmap restart");
    }
    else { 
	system ("service portmap start") if ($dont_apply eq "false");
    }
    if (-e "/var/lock/subsys/ypbind" || -e "/var/run/ypbind.pid") {
	system ("service ypbind restart") ;
    }
    else { 
	system ("service ypbind start") if ($dont_apply eq "false");
    }
    exit (0);
}

if ($< != 0) {
    print "You must be root to do that\n";
    exit (1);
}
exit_with_usage() if (@ARGV == 0);
$_ = shift @ARGV;
if ($_ eq "--pixel") {
    $_ = shift @ARGV;
    $dont_apply = "true";    
}

set_file_auth(@ARGV) if ($_ eq "file");
set_ldap_auth(@ARGV) if ($_ eq "ldap");
set_yp_auth(@ARGV) if ($_ eq "yp");
exit_with_usage();
