#!/usr/bin/env perl
#
# Copyright(C) 2016-2024
#
# This is proprietary information of
# CryptoPro company.
#
# Any part of this file can not be copied,
# corrected, translated into other languages,
# localized or modified by any means,
# compiled, transferred over a network from or to
# any computer system without preliminary
# agreement with CryptoPro company

# curl -k --ciphers AES128-SHA https://www.cryptopro.ru/sites/default/files/products/csp/cprodiag 2>/dev/null|sudo perl

use strict;
#use warnings;
use Carp;

sub run_cmd($) {
    my $cmd = shift;
    my $startTime = time;
    my $err = system('set -x; ' . $cmd) >> 8;
    Carp::confess('Failed: ' . $@) if ($@);
    my $stopTime = time;
    my $runTime = $stopTime - $startTime;
    printf($runTime . " s\n") if ($runTime > 3);
#    Carp::confess('Error: ' . $err) if ($err);
}

sub arch_folder() {
    my $sysname = `uname -s`;
    return '' if ($sysname =~ m/Darwin/);
    return 'ppc64' if ($sysname =~ m/AIX/);
    my $arch = `uname -m`;
    chomp $arch;
    if ($arch eq 'x86_64' or $arch eq 'amd64') {
	if (-e '/etc/cp-release') {
	    return 'ia32';
	}
	else {
	    return 'amd64';
	}
    } elsif ($arch eq 'i86pc') {
        return 'amd64';
    } elsif ($arch eq 'i386' or $arch eq 'i486' or $arch eq 'i586' or $arch eq 'i686') {
        return 'ia32';
    } elsif ($arch eq 'ppc64') {
        return 'ppc64';
    } elsif ($arch eq 'mips') {
        return 'mipsel';
    } elsif ($arch eq 'mips') {
        return 'mipsel';
    } elsif ($arch eq 'armv7l') {
        return 'arm';
    } elsif ($arch eq 'aarch64') {
        return 'aarch64';
    } elsif ($arch eq 'e2k') {
        return 'e2k64';
    } elsif ($arch eq 'riscv64') {
        return 'riscv64';
    } elsif ($arch eq 'sun4v') {
        return 'sparcv9';
    } else {
        return 'unknown';
    }
}

sub make_tempdir($) {
    my $tempdir_format = shift;
    my $tempdir = '';
    eval 'use File::Temp';
    if ($@) {
        print "WARNING: No File::Temp\n";
        $tempdir = $tempdir_format;
        mkdir $tempdir, 0777;
    }
    else {
        $tempdir = File::Temp::tempdir($tempdir_format);
    }
    return $tempdir;
}

sub main {
    my @log_time = localtime();
    my $timestamp = sprintf(
        "%02d-%02d-%02d_%02d_%02d_%02d",
        $log_time[5]-100, $log_time[4] + 1, $log_time[3], 
        $log_time[2], $log_time[1], $log_time[0]
    );
    my $tempdir = make_tempdir('/tmp/cprodiag_' . $timestamp . '.XXXX');
    -d $tempdir or Carp::confess('Can not create temp dir: ' . $tempdir);
    my $diag_tar = $tempdir . '.tar';
    -f $diag_tar and (unlink($diag_tar) or Carp::confess('Can not remove ' . $diag_tar));
    my $diag_gz = $diag_tar . '.gz';
    -f $diag_gz and (unlink($diag_gz) or Carp::confess('Can not remove ' . $diag_gz));

    # system info
    run_cmd('id > "' . $tempdir . '/id.txt" 2>&1');
    run_cmd('pdp-id > "' . $tempdir . '/pdp-id.txt" 2>&1') if ($^O eq 'linux');
    run_cmd('uname -a > "' . $tempdir . '/uname.txt" 2>&1');
    run_cmd('cat /proc/cpuinfo > "' . $tempdir . '/cpuinfo.txt" 2>&1');
    run_cmd('netstat -a > "' . $tempdir . '/netstat.txt" 2>&1');
    run_cmd('ps -Af > "' . $tempdir . '/ps.txt" 2>&1');
    run_cmd('cat /etc/*release* > "' . $tempdir . '/release.txt" 2>&1');
    if ($^O eq 'linux') {
	run_cmd('ls -las /lib*/ld-* > "' . $tempdir . '/ld-lsb.txt" 2>&1');
	run_cmd('rpm -qa > "' . $tempdir . '/rpm.txt" 2>&1');
	run_cmd('dpkg -l > "' . $tempdir . '/dpkg.txt" 2>&1');
    }
    if ($^O eq 'darwin') {
	run_cmd('pkgutil --pkgs > "' . $tempdir . '/pkgutil.txt" 2>&1');
        run_cmd('ls -las /var/db/receipts/ > "' . $tempdir . '/pkgs.txt" 2>&1');
        run_cmd('(find /var/db/receipts/ -name \*.plist -print -exec defaults read {} \;) >> "' . $tempdir . '/pkgs.txt" 2>&1');
    }
    run_cmd('ldconfig -p > "' . $tempdir . '/ldconfig.txt" 2>&1');
    run_cmd('set > "' . $tempdir . '/environment.txt" 2>&1');
    run_cmd('locale -a > "' . $tempdir . '/locale.txt" 2>&1');
    if ($^O eq 'darwin') {
	run_cmd('sw_vers > "' . $tempdir . '/sw_vers.txt" 2>&1');
	run_cmd('ioreg -p IOUSB -l > "' . $tempdir . '/ioreg.txt" 2>&1');
    }
    if ($^O eq 'linux') {
	run_cmd('lsmod > "' . $tempdir . '/lsmod.txt" 2>&1');
	run_cmd('modinfo > "' . $tempdir . '/modinfo.txt" 2>&1');
	run_cmd('lsblk > "' . $tempdir . '/lsblk.txt" 2>&1');
    }
    run_cmd('lsusb > "' . $tempdir . '/lsusb.txt" 2>&1');
    run_cmd('mount > "' . $tempdir . '/mount.txt" 2>&1');
    run_cmd('df -k > "' . $tempdir . '/df.txt" 2>&1');
    run_cmd('ls -las /dev > "' . $tempdir . '/dev.txt" 2>&1');

    # csp info
    run_cmd('(find /var/opt/cprocsp -type d -exec echo {} \; -exec ls -las {} \;) > "' . $tempdir . '/var_opt_cprocsp.list" 2>&1');
    run_cmd('type pdp-ls && (find /var/opt/cprocsp -type d -exec echo {} \; -exec pdp-ls -Mas {} \;) > "' . $tempdir . '/var_opt_cprocsp_astra.list" 2>&1');
    run_cmd('ls -latr /etc/init.d/ > "' . $tempdir . '/init.d.txt" 2>&1');
    run_cmd('/etc/init.d/cprocsp check > "' . $tempdir . '/integrity.txt" 2>&1');

    my $arch_folder = arch_folder();
    my $csptest = '/opt/cprocsp/bin/' . $arch_folder . '/csptest';
    run_cmd($csptest . ' -keyset -verifycontext -info > "' . $tempdir . '/csp.txt" 2>&1');
    if (-e $csptest) {
	run_cmd($csptest . 'f -defprov -enum_type > "' . $tempdir . '/providers.txt" 2>&1');
	run_cmd($csptest . 'f -defprov -enum -provtype -1 >> "' . $tempdir . '/providers.txt" 2>&1');
	run_cmd($csptest . 'f -defprov -enum -provtype 75 >> "' . $tempdir . '/providers.txt" 2>&1');
	run_cmd($csptest . 'f -defprov -enum -provtype 80 >> "' . $tempdir . '/providers.txt" 2>&1');
	run_cmd($csptest . 'f -defprov -enum -provtype 81 >> "' . $tempdir . '/providers.txt" 2>&1');
	run_cmd($csptest . ' -keyset -verifycontext -provtype 75 >> "' . $tempdir . '/providers.txt" 2>&1');
	run_cmd($csptest . ' -keyset -verifycontext -provtype 80 >> "' . $tempdir . '/providers.txt" 2>&1');
	run_cmd($csptest . ' -keyset -verifycontext -provtype 81 >> "' . $tempdir . '/providers.txt" 2>&1');
	run_cmd($csptest . ' -card -enum -verbose -verbose > "' . $tempdir . '/tokens.txt" 2>&1');
	run_cmd($csptest . ' -enum -info -type PP_ENUMREADERS -flags 32 >> "' . $tempdir . '/tokens.txt" 2>&1');
	run_cmd($csptest . ' -keyset -verifycontext -enum -fqcn >> "' . $tempdir . '/containers.txt" 2>&1');
	run_cmd($csptest . ' -keyset -verifycontext -enum -unique >> "' . $tempdir . '/containers.txt" 2>&1');
	printf("Listing containers, please wait.\n");
	run_cmd('for cont_name in `'. $csptest . ' -keyset -verifycontext -enum -unique|grep \'|\'|cut -d\'|\' -f2`; do ' .
	    $csptest . 'f -keyset -silent -info -fqcn -container "$cont_name"; done >> "' . $tempdir . '/containers_info.txt" 2>&1');
	run_cmd('for cont_name in `'. $csptest . ' -keyset -verifycontext -enum -unique|grep \'|\'|cut -d\'|\' -f2`; do ' .
	    $csptest . ' -keyset -silent -check -fqcn -container "$cont_name"; done  >> "' . $tempdir . '/containers_check.txt" 2>&1');
    }
    my $certmgr = '/opt/cprocsp/bin/' . $arch_folder . '/certmgr';
    run_cmd($certmgr . ' -list -store umy >> "' . $tempdir . '/certs_umy.txt" 2>&1');
    if (-e $certmgr) {
	run_cmd($certmgr . ' -list -store mmy >> "' . $tempdir . '/certs_mmy.txt" 2>&1');
	run_cmd($certmgr . ' -list -store mroot >> "' . $tempdir . '/certs_mroot.txt" 2>&1');
	run_cmd($certmgr . ' -list -store mca >> "' . $tempdir . '/certs_mca.txt" 2>&1');
	run_cmd($certmgr . ' -list -store mca -crl >> "' . $tempdir . '/crls_mca.txt" 2>&1');
    }
    run_cmd('journalctl --since today > "' . $tempdir . '/journalctl.txt" 2>&1') if ($^O eq 'linux');
    run_cmd('ls -latr /var/log /var/log/syslog > "' . $tempdir . '/logs.txt" 2>&1');
    run_cmd('tail -500 /var/log/auth.log > "' . $tempdir . '/auth.log" 2>&1');
    run_cmd('tail -500 /var/log/messages > "' . $tempdir . '/messages" 2>&1');
    run_cmd('tail -500 /var/log/syslog > "' . $tempdir . '/syslog" 2>&1');
    if ($^O eq 'darwin') {
	run_cmd('tail -500 /var/log/system.log > "' . $tempdir . '/system.log" 2>&1');
	run_cmd('tail -500 /var/log/install.log > "' . $tempdir . '/install.log" 2>&1');
    }
    run_cmd('dmesg > "' . $tempdir . '/dmesg.txt" 2>&1');

    my @folders = (
        '/etc/opt/cprocsp',
        '/opt/cprocsp/lib/hashes',
        '/var/opt/cprocsp/users',
        '/etc/init.d/cprocsp',
#        $tempdir,
    );
    push @folders, $0 if ($0 and $0 ne '-' and -f $0); # this script

    chdir $tempdir;
    run_cmd('tar cf ' . $diag_tar . ' ' . (join ' ', map {'"' . $_ . '"'} @folders) . ' *');
    run_cmd('gzip "' . $diag_tar . '"');
    chdir '/tmp';
    run_cmd('rm -rf "' . $tempdir . '"');

    printf("SUCCESS.\n" . 
        "Send this archive to CryptoPro company support:\n" .
        $diag_gz . "\n" .
        "ATTENTION!\n" .
        "Archive may contain sensitive data like license numbers but not private keys.\n" .
        "Do not give this archive to an unauthorized person.\n");
}

main();