#!/usr/bin/perl
#
# $Id: genprof 5579 2005-11-02 18:21:35Z jesse $
#
# ----------------------------------------------------------------------
#    PROPRIETARY DATA of IMMUNIX INC.
#    Copyright (c) 2004, IMMUNIX (All rights reserved)
#
#    This document contains trade secret data which is the property
#    of IMMUNIX Inc.  This document is submitted to recipient in
#    confidence. Information contained herein may not be used, copied
#    or disclosed in whole or in part except as permitted by written
#    agreement signed by an officer of IMMUNIX, Inc.
# ----------------------------------------------------------------------

use strict;
use Getopt::Long;

use Immunix::SubDomain;

use Data::Dumper;

use Locale::gettext;
use POSIX;

# force $PATH to be sane
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";

# initialize the local poo
setlocale(LC_MESSAGES, "");
textdomain("subdomain-utils");

# options variables
my $help           = '';
  
GetOptions(
  'file|f=s'    => \$filename,
  'dir|d=s'     => \$profiledir,
  'help|h'      => \$help,
);
  
# tell 'em how to use it...
&usage && exit if $help;

my $sd_mountpoint = check_for_subdomain();
unless($sd_mountpoint) {
  fatal_error(gettext("SubDomain does not appear to be started.  Please enable SubDomain and try again."));
}

# let's convert it to full path...
$profiledir = get_full_path($profiledir);
  
unless(-d $profiledir) {
  fatal_error "Can't find subdomain profiles in $profiledir.";
}

# what are we profiling?
my $profiling = shift;

unless($profiling) {
  $profiling = UI_GetString(gettext("Please enter the program to profile: "), "") || exit 0;
}

my $fqdbin;
if(-e $profiling) {
  $fqdbin = get_full_path($profiling);
  chomp($fqdbin);
} else {
  if($profiling !~ /\//) {
    my $which = which($profiling);
    if($which) {
      $fqdbin = get_full_path($which);
    }
  }
}

unless($fqdbin && -e $fqdbin) {
  if($profiling =~ /^[^\/]+$/) {
    fatal_error(sprintf(gettext('Can\'t find %s in the system path list.  If the name of the application is correct, please run \'which %s\' in the other window in order to find the fully-qualified path.'), $profiling, $profiling));
  } else {
    fatal_error(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
  }
}

# read the settings in /etc/logprof.conf
readconfig();

# make sure that the app they're requesting to profile is not marked as
# not allowed to have it's own profile
if($qualifiers{$fqdbin}) {
  unless($qualifiers{$fqdbin} =~ /p/) {
    fatal_error(sprintf(gettext("\%s is currently marked as a program that should not have it's own profile.  Usually, programs are marked this way if creating a profile for them is likely to break the rest of the system.  If you know what you're doing and are certain you want to create a profile for this program, edit the corresponding entry in the [qualifiers] section in /etc/apparmor/logprof.conf."), $fqdbin));
  }
}

unless(profile_is_authorized($fqdbin)) {
    fatal_error(gettext("The version of AppArmor that you are running does not allow the\ncreation of this profile.  Please contact Novell sales for\nupgrade options for AppArmor."));
}

# load all the include files
loadincludes();

my $profilefilename = getprofilefilename($fqdbin);
if(-e $profilefilename) {
  $helpers{$fqdbin}  = getprofileflags($profilefilename) || "enforce";
} else {
  autodep($fqdbin);
  $helpers{$fqdbin} = "enforce";
}

if($helpers{$fqdbin} eq "enforce") {
  complain($fqdbin);
  reload($fqdbin);
}

UI_Important(gettext("Please start the application to be profiled in \nanother window and exercise its functionality now.\n\nOnce completed, select the \"Scan\" button below in \norder to scan the system logs for AppArmor events.  \n\nFor each AppArmor event, you will be given the  \nopportunity to choose whether the access should be  \nallowed or denied."));

my $done_profiling = 0;
while(not $done_profiling) {
  
  my $logmark = `date | md5sum`;
  chomp $logmark;
  $logmark = $1 if $logmark =~ /^([0-9a-f]+)/;
  system("/bin/logger -p kern.warn 'GenProf: $logmark'");

  my $q = { };
  $q->{headers}   = [ gettext("Profiling"), $fqdbin ];
  $q->{functions} = [ "CMD_SCAN", "CMD_FINISHED" ];
  $q->{default}   = "CMD_SCAN";

  my ($ans, $arg) = UI_PromptUser($q);

  if($ans eq "CMD_SCAN") {

    my $lp_ret = do_logprof_pass($logmark);

    $done_profiling = 1 if $lp_ret eq "FINISHED";

  } else {

    $done_profiling = 1;

  }

}
  
for my $p (sort keys %helpers) {
  if($helpers{$p} eq "enforce") {
    enforce($p);
    reload($p);
  }
}

UI_Info(gettext("Reloaded SubDomain profiles in enforce mode."));
UI_Info(sprintf(gettext('Finished generating profile for %s.'), $fqdbin));
exit 0;

sub usage {
  UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ program to profile ]"), $0));
  exit 0;
}

