#!/usr/bin/perl
#
# Module: vyatta-snmp.pl
#
# **** License ****
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# 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.
#
# This code was originally developed by Vyatta, Inc.
# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
# All Rights Reserved.
#
# Author: Stig Thormodsrud
# Date: October 2007
# Description: Script to glue vyatta cli to snmp daemon
#
# **** End License ****
#

use lib "/opt/vyatta/share/perl5/";
use Vyatta::Config;
use Vyatta::Misc;
use Getopt::Long;
use File::Copy;

use strict;
use warnings;

my $mibdir    = '/opt/vyatta/share/snmp/mibs';
my $snmp_init = '/opt/vyatta/sbin/snmpd.init';
my $snmp_conf = '/etc/snmp/snmpd.conf';
my $snmp_tmp  = "/tmp/snmpd.conf.$$";
my $snmp_snmpv3_user_conf = '/usr/share/snmp/snmpd.conf';
my $snmp_snmpv3_createuser_conf = '/var/lib/snmp/snmpd.conf';
my $versionfile = '/opt/vyatta/etc/version';

sub snmp_restart {
    system("$snmp_init restart > /dev/null 2>&1 &");
}

sub snmp_stop {
    system("$snmp_init stop > /dev/null 2>&1");
}

sub snmp_start {
    open (my $fh, '>', $snmp_tmp)
	or die "Couldn't open $snmp_tmp - $!";

    select $fh;
    snmp_get_constants();
    snmp_get_values();
    close $fh;
    select STDOUT;
   
    move($snmp_tmp, $snmp_conf)
	or die "Couldn't move $snmp_tmp to $snmp_conf - $!";

    snmp_restart();
}

sub get_version {
    my $version = "unknown-version";

    if (open (my $f, '<', $versionfile)) {
	while (<$f>) {
	    chomp;
	    if (m/^Version\s*:\s*(.*)$/) {
		$version = $1;
		last;
	    }
	}
	close $f;
    }
    return $version;
}

sub snmp_get_constants {
    my $version = get_version();
    my $now = localtime;

    print "# autogenerated by vyatta-snmp.pl on $now\n";
    print "sysDescr Vyatta $version\n";
    print "sysObjectID 1.3.6.1.4.1.30803\n";
    print "sysServices 14\n";
    print "smuxpeer .1.3.6.1.4.1.3317.1.2.2\n"; 		# ospfd
    print "smuxpeer .1.3.6.1.4.1.3317.1.2.5\n";		# bgpd
    print "smuxpeer .1.3.6.1.4.1.3317.1.2.3\n";		# ripd
    print "smuxsocket localhost\n";
    print "perl do \"/opt/vyatta/sbin/enterprise-mib.pl\"\n";
}

# generate a random character hex string
sub randhex {
    my $length = shift;
    return join "", map { unpack "H*", chr(rand(256)) } 1..($length/2);
}

sub snmp_get_values {
    my $config = new Vyatta::Config;

    $config->setLevel("service snmp community");
    my @communities = $config->listNodes();
   
    foreach my $community (@communities) {
        my $authorization = $config->returnValue("$community authorization");
        my @clients = $config->returnValues("$community client");
        my @networks = $config->returnValues("$community network");

        if (scalar(@clients) == 0 and scalar(@networks) == 0){
           if (defined $authorization and $authorization eq "rw") {
               print "rwcommunity $community\n";
           } else {
                  print "rocommunity $community\n";
           }
        } else {
                if (scalar(@clients) != 0) {
                   foreach my $client (@clients){
                        if (defined $authorization and $authorization eq "rw") {
                            print "rwcommunity $community $client\n";
                        } else {
                                print "rocommunity $community $client\n";
                        }
                   }
                }
                if (scalar(@networks) != 0){
                   foreach my $network (@networks){
                        if (defined $authorization and $authorization eq "rw") {
                            print "rwcommunity $community $network\n";
                        } else {
                                print "rocommunity $community $network\n";
                        }

                   }
                }
        }
    }

    $config->setLevel("service snmp");
    my $contact = $config->returnValue("contact");
    if (defined $contact) {
	print "syscontact \"$contact\" \n";
    }

    my $description = $config->returnValue("description");
    if (defined $description) {
	print "sysdescr \"$description\" \n";
    }

    my $location = $config->returnValue("location");
    if (defined $location) {
	print "syslocation \"$location\" \n";
    }

    my @trap_targets = $config->returnValues("trap-target");
    if ($#trap_targets >= 0) {

	# linkUpDownNotifications configure the Event MIB tables to monitor
	# the ifTable for network interfaces being taken up or down
	# for making internal queries to retrieve any necessary information
	# a snmpv3 user needs to be created
	# we write appropriate values to /var/lib/snmp/snmpd.conf 
	# and /usr/share/snmp/snmpd.conf

	#create an internal snmpv3 user of the form 'vyattaxxxxxxxxxxxxxxxx'
	my $vyatta_user = "vyatta" . randhex(16);
	snmp_create_snmpv3_user($vyatta_user);
	snmp_write_snmpv3_user($vyatta_user);
	print "iquerySecName $vyatta_user\n";

	# code to activate link up down traps
	print "linkUpDownNotifications yes\n";
    }

    foreach my $trap_target (@trap_targets) {
        print "trap2sink $trap_target\n";
    }
}

sub snmp_create_snmpv3_user {

    my $vyatta_user = shift;
    my $passphrase = randhex(32);
    my $createuser = "createUser $vyatta_user MD5 \"$passphrase\" DES";
    open(my $fh, '>>', $snmp_snmpv3_createuser_conf) || die "Couldn't open $snmp_snmpv3_createuser_conf - $!";
    print $fh $createuser;
    close $fh;
}

sub snmp_write_snmpv3_user {

    my $vyatta_user = shift;
    my $user = "rouser $vyatta_user\n";
    system ("sed -i '/user[[:space:]]*vyatta[[:alnum:]]*/d' $snmp_snmpv3_user_conf 2>/dev/null;");
    open(my $fh, '>>', $snmp_snmpv3_user_conf) || die "Couldn't open $snmp_snmpv3_user_conf - $!";
    print $fh $user;
    close $fh;
}


#
# main
#
my $update_snmp;
my $stop_snmp;

GetOptions("update-snmp!" => \$update_snmp,
           "stop-snmp!"   => \$stop_snmp);

snmp_start() if ($update_snmp);
snmp_stop()  if ($stop_snmp);