mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 14:25:52 +00:00
Changes to add support for the AppArmor profile repository to the
console UI tools. (jmichael)
This commit is contained in:
@@ -21,19 +21,22 @@
|
||||
string status = "";
|
||||
|
||||
map CMDS = $[ ];
|
||||
CMDS["CMD_ALLOW"] = _("&Allow");
|
||||
CMDS["CMD_DENY"] = _("&Deny");
|
||||
CMDS["CMD_ABORT"] = _("Abo(r)t");
|
||||
CMDS["CMD_FINISHED"] = _("&Finish");
|
||||
CMDS["CMD_INHERIT"] = _("&Inherit");
|
||||
CMDS["CMD_PROFILE"] = _("&Profile");
|
||||
CMDS["CMD_UNCONFINED"] = _("&Unconfined");
|
||||
CMDS["CMD_NEW"] = _("&Edit");
|
||||
CMDS["CMD_GLOB"] = _("&Glob");
|
||||
CMDS["CMD_GLOBEXT"] = _("Glob w/E&xt");
|
||||
CMDS["CMD_ADDHAT"] = _("&Add Requested Hat");
|
||||
CMDS["CMD_USEDEFAULT"] = _("&Use Default Hat");
|
||||
CMDS["CMD_SCAN"] = _("&Scan system log for AppArmor events");
|
||||
CMDS["CMD_ALLOW"] = _("&Allow");
|
||||
CMDS["CMD_DENY"] = _("&Deny");
|
||||
CMDS["CMD_ABORT"] = _("Abo(r)t");
|
||||
CMDS["CMD_FINISHED"] = _("&Finish");
|
||||
CMDS["CMD_INHERIT"] = _("&Inherit");
|
||||
CMDS["CMD_PROFILE"] = _("&Profile");
|
||||
CMDS["CMD_UNCONFINED"] = _("&Unconfined");
|
||||
CMDS["CMD_NEW"] = _("&Edit");
|
||||
CMDS["CMD_GLOB"] = _("&Glob");
|
||||
CMDS["CMD_GLOBEXT"] = _("Glob w/E&xt");
|
||||
CMDS["CMD_ADDHAT"] = _("&Add Requested Hat");
|
||||
CMDS["CMD_USEDEFAULT"] = _("&Use Default Hat");
|
||||
CMDS["CMD_SCAN"] = _("&Scan system log for AppArmor events");
|
||||
CMDS["CMD_VIEW_REPO"] = _("&View Profile");
|
||||
CMDS["CMD_USE_REPO"] = _("&Use Profile");
|
||||
CMDS["CMD_CREATE_PROFILE"] = _("&Create New Profile");
|
||||
|
||||
if (!installAppArmorPackages()) {
|
||||
return;
|
||||
@@ -312,6 +315,26 @@
|
||||
// tell the backend what they did
|
||||
SCR::Write(.genprof, answers);
|
||||
|
||||
} else if (type == "dialog-view-profile") {
|
||||
|
||||
string user = agent_data["user"]:"MISSING USER";
|
||||
string profile = agent_data["profile"]:"MISSING PROFILE";
|
||||
string default_ans = agent_data["default"]:"b";
|
||||
|
||||
symbol focus = `focus_yes;
|
||||
if (default_ans == "b") {
|
||||
focus = `focus_no;
|
||||
}
|
||||
map answers = $[ ];
|
||||
if (Popup::AnyQuestion(_("Profile created by user ") + user,
|
||||
profile, _("&Use Profile"), _("&Back"), focus)) {
|
||||
answers["answer"] = "u";
|
||||
} else {
|
||||
answers["answer"] = "b";
|
||||
}
|
||||
// write the answers for the last dialog
|
||||
boolean written = SCR::Write(.genprof, answers);
|
||||
|
||||
} else if (type == "dialog-yesno") {
|
||||
|
||||
string question = agent_data["question"]:"MISSING QUESTION";
|
||||
|
@@ -21,19 +21,22 @@
|
||||
string status = "";
|
||||
|
||||
map CMDS = $[ ];
|
||||
CMDS["CMD_ALLOW"] = _("&Allow");
|
||||
CMDS["CMD_DENY"] = _("&Deny");
|
||||
CMDS["CMD_ABORT"] = _("Abo(r)t");
|
||||
CMDS["CMD_FINISHED"] = _("&Finish");
|
||||
CMDS["CMD_INHERIT"] = _("&Inherit");
|
||||
CMDS["CMD_PROFILE"] = _("&Profile");
|
||||
CMDS["CMD_UNCONFINED"] = _("&Unconfined");
|
||||
CMDS["CMD_NEW"] = _("&Edit");
|
||||
CMDS["CMD_GLOB"] = _("&Glob");
|
||||
CMDS["CMD_GLOBEXT"] = _("Glob w/E&xt");
|
||||
CMDS["CMD_ADDHAT"] = _("&Add Requested Hat");
|
||||
CMDS["CMD_USEDEFAULT"] = _("&Use Default Hat");
|
||||
CMDS["CMD_SCAN"] = _("&Scan system log for AppArmor events");
|
||||
CMDS["CMD_ALLOW"] = _("&Allow");
|
||||
CMDS["CMD_DENY"] = _("&Deny");
|
||||
CMDS["CMD_ABORT"] = _("Abo&rt");
|
||||
CMDS["CMD_FINISHED"] = _("&Finish");
|
||||
CMDS["CMD_INHERIT"] = _("&Inherit");
|
||||
CMDS["CMD_PROFILE"] = _("&Profile");
|
||||
CMDS["CMD_UNCONFINED"] = _("&Unconfined");
|
||||
CMDS["CMD_NEW"] = _("&Edit");
|
||||
CMDS["CMD_GLOB"] = _("&Glob");
|
||||
CMDS["CMD_GLOBEXT"] = _("Glob w/E&xt");
|
||||
CMDS["CMD_ADDHAT"] = _("&Add Requested Hat");
|
||||
CMDS["CMD_USEDEFAULT"] = _("&Use Default Hat");
|
||||
CMDS["CMD_SCAN"] = _("&Scan system log for AppArmor events");
|
||||
CMDS["CMD_VIEW_REPO"] = _("&View Profile");
|
||||
CMDS["CMD_USE_REPO"] = _("&Use Profile");
|
||||
CMDS["CMD_CREATE_PROFILE"] = _("&Create New Profile");
|
||||
|
||||
if (!installAppArmorPackages()) {
|
||||
return;
|
||||
@@ -311,6 +314,27 @@
|
||||
// tell the backend what they did
|
||||
SCR::Write(.logprof, answers);
|
||||
|
||||
} else if (type == "dialog-view-profile") {
|
||||
|
||||
string user = agent_data["user"]:"MISSING USER";
|
||||
string profile = agent_data["profile"]:"MISSING PROFILE";
|
||||
string default_ans = agent_data["default"]:"b";
|
||||
|
||||
symbol focus = `focus_yes;
|
||||
if (default_ans == "b") {
|
||||
focus = `focus_no;
|
||||
}
|
||||
map answers = $[ ];
|
||||
if (Popup::AnyQuestion(_("Profile created by user ") + user,
|
||||
profile, _("&Use Profile"), _("&Back"), focus)) {
|
||||
answers["answer"] = "u";
|
||||
} else {
|
||||
answers["answer"] = "b";
|
||||
}
|
||||
// write the answers for the last dialog
|
||||
boolean written = SCR::Write(.logprof, answers);
|
||||
|
||||
|
||||
} else if (type == "dialog-yesno") {
|
||||
|
||||
string question = agent_data["question"]:"MISSING QUESTION";
|
||||
|
@@ -27,10 +27,15 @@ use warnings;
|
||||
use Carp;
|
||||
use Cwd qw(cwd realpath);
|
||||
use File::Basename;
|
||||
use File::Temp qw/ tempfile tempdir /;
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
use RPC::XML;
|
||||
use RPC::XML::Client;
|
||||
use Storable qw(dclone);
|
||||
|
||||
use Term::ReadKey;
|
||||
|
||||
use Immunix::Severity;
|
||||
@@ -94,6 +99,8 @@ our @EXPORT = qw(
|
||||
|
||||
our $confdir = "/etc/apparmor";
|
||||
|
||||
our $repo_client;
|
||||
|
||||
our $running_under_genprof = 0;
|
||||
|
||||
our $DEBUGGING;
|
||||
@@ -105,6 +112,8 @@ our $UI_Mode = "text";
|
||||
|
||||
our $sevdb;
|
||||
|
||||
our %uid2login;
|
||||
|
||||
# initialize Term::ReadLine if it's available
|
||||
our $term;
|
||||
eval {
|
||||
@@ -133,6 +142,7 @@ our $seenevents = 0;
|
||||
|
||||
# behaviour tweaking
|
||||
our $cfg;
|
||||
our $repo_cfg;
|
||||
|
||||
# these are globs that the user specifically entered. we'll keep track of
|
||||
# them so that if one later matches, we'll suggest it again.
|
||||
@@ -142,6 +152,7 @@ our @userglobs;
|
||||
our %t;
|
||||
our %transitions;
|
||||
our %sd; # we keep track of the original profiles in %sd
|
||||
our %original_sd;
|
||||
|
||||
my @log;
|
||||
my %pid;
|
||||
@@ -290,6 +301,7 @@ sub setup_yast {
|
||||
# something's broken, die a horrible, painful death
|
||||
fatal_error "Yast frontend is out of sync from backend agent.";
|
||||
}
|
||||
$DEBUGGING && debug "Initial handshake ok";
|
||||
|
||||
# the yast connection seems to be working okay
|
||||
return 1;
|
||||
@@ -578,6 +590,140 @@ sub handle_binfmt ($$) {
|
||||
}
|
||||
}
|
||||
|
||||
sub get_profile_from_repo {
|
||||
my $fqdbin = shift;
|
||||
|
||||
my $profile_data;
|
||||
|
||||
my $distro = $cfg->{settings}{distro};
|
||||
my $repository = $cfg->{settings}{repository};
|
||||
|
||||
if ($repo_client) {
|
||||
my $res = $repo_client->send_request('FindProfiles', $distro, $fqdbin, "");
|
||||
if (did_result_succeed($res)) {
|
||||
my @profiles;
|
||||
my @profile_list = @{$res->value};
|
||||
|
||||
if (@profile_list) {
|
||||
my @uids;
|
||||
for my $p (@profile_list) {
|
||||
my $uid = $p->{user_id};
|
||||
my $username = $uid2login{$uid};
|
||||
if ($username) {
|
||||
$p->{username} = $username;
|
||||
} else {
|
||||
push @uids, $uid;
|
||||
}
|
||||
}
|
||||
|
||||
if (@uids) {
|
||||
# LoginNamesFromUserIds currently returns the list of uids in sorted
|
||||
# order no matter how you pass them to it - that's a bug, but let's
|
||||
# explictly sort the list to work around that.
|
||||
@uids = sort @uids;
|
||||
|
||||
my $res = $repo_client->send_request('LoginNamesFromUserIds', [ @uids ]);
|
||||
if (did_result_succeed($res)) {
|
||||
my @usernames = @{$res->value};
|
||||
for my $uid (@uids) {
|
||||
my $username = shift @usernames;
|
||||
$uid2login{$uid} = $username;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for my $p (@profile_list) {
|
||||
next if $p->{username};
|
||||
my $uid = $p->{user_id};
|
||||
my $username = $uid2login{$uid};
|
||||
if ($username) {
|
||||
$p->{username} = $username;
|
||||
} else {
|
||||
$p->{username} = "unknown-$uid";
|
||||
}
|
||||
}
|
||||
|
||||
my @options = map { $_->{username} } @profile_list;
|
||||
|
||||
my $q = { };
|
||||
$q->{headers} = [ ];
|
||||
push @{$q->{headers}}, gettext("Profile"), $fqdbin;
|
||||
|
||||
$q->{functions} = [
|
||||
"CMD_VIEW_REPO", "CMD_USE_REPO", "CMD_CREATE_PROFILE",
|
||||
"CMD_ABORT", "CMD_FINISHED"
|
||||
];
|
||||
|
||||
$q->{default} = "CMD_VIEW_REPO";
|
||||
|
||||
$q->{options} = [ @options ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($p, $ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
for (my $i = 0; $i < scalar(@profile_list); $i++) {
|
||||
if ($profile_list[$i]->{username} eq $options[$arg]) {
|
||||
$p = $profile_list[$i];
|
||||
$q->{selected} = $i;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ans eq "CMD_VIEW_REPO") {
|
||||
if ($UI_Mode eq "yast") {
|
||||
SendDataToYast( { type => "dialog-view-profile", user => $arg,
|
||||
profile => $p->{profile} } );
|
||||
my ($ypath, $yarg) = GetDataFromYast();
|
||||
$ans = $yarg->{answer} || "b";
|
||||
if ( $ans eq "u" ) {
|
||||
$profile_data = use_repo_profile($fqdbin, $repository, $p);
|
||||
$ans = "CMD_USE_REPO";
|
||||
}
|
||||
} else {
|
||||
open(PAGER, "| less");
|
||||
print PAGER gettext("Profile submitted by") . " $options[$arg]:\n\n$p->{profile}\n\n";;
|
||||
close(PAGER);
|
||||
}
|
||||
} elsif ($ans eq "CMD_USE_REPO") {
|
||||
$profile_data = use_repo_profile($fqdbin, $repository, $p );
|
||||
}
|
||||
} until ($ans =~ /^CMD_(USE_REPO|CREATE_PROFILE)$/);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $profile_data;
|
||||
}
|
||||
|
||||
sub set_repo_info {
|
||||
my ($profile_data, $repo_url, $username, $id) = @_;
|
||||
|
||||
# save repository metadata
|
||||
$profile_data->{repo}{url} = $repo_url;
|
||||
$profile_data->{repo}{user} = $username;
|
||||
$profile_data->{repo}{id} = $id;
|
||||
}
|
||||
|
||||
sub use_repo_profile {
|
||||
my ($fqdbin, $repo_url, $profile) = @_;
|
||||
|
||||
my $profile_data = eval {
|
||||
parse_profile_data($profile->{profile}, "repository profile");
|
||||
};
|
||||
if ($@) {
|
||||
$profile_data = undef;
|
||||
}
|
||||
|
||||
if ($profile_data) {
|
||||
set_repo_info($profile_data->{$fqdbin}{$fqdbin}, $repo_url,
|
||||
$profile->{username}, $profile->{id});
|
||||
}
|
||||
|
||||
return $profile_data;
|
||||
}
|
||||
|
||||
|
||||
sub create_new_profile {
|
||||
my $fqdbin = shift;
|
||||
|
||||
@@ -585,7 +731,7 @@ sub create_new_profile {
|
||||
$fqdbin => {
|
||||
flags => "complain",
|
||||
include => { "abstractions/base" => 1 },
|
||||
path => { $fqdbin => "mr" }
|
||||
path => { $fqdbin => "mr" },
|
||||
}
|
||||
};
|
||||
|
||||
@@ -621,6 +767,17 @@ sub create_new_profile {
|
||||
sub autodep ($) {
|
||||
my $bin = shift;
|
||||
|
||||
unless ($repo_cfg) {
|
||||
$repo_cfg = read_config("repository.conf");
|
||||
unless ($repo_cfg->{repository}{enabled}) {
|
||||
ask_to_enable_repo();
|
||||
}
|
||||
}
|
||||
|
||||
if (repo_is_enabled()) {
|
||||
setup_repo_client();
|
||||
}
|
||||
|
||||
# findexecutable() might fail if we're running on a different system
|
||||
# than the logs were collected on. ugly. we'll just hope for the best.
|
||||
my $fqdbin = findexecutable($bin) || $bin;
|
||||
@@ -631,10 +788,19 @@ sub autodep ($) {
|
||||
# ignore directories
|
||||
return if -d $fqdbin;
|
||||
|
||||
my $profile_data = create_new_profile($fqdbin);
|
||||
my $profile_data;
|
||||
if (repo_is_enabled()) {
|
||||
$profile_data = eval { get_profile_from_repo($fqdbin) };
|
||||
}
|
||||
unless ($profile_data) {
|
||||
$profile_data = create_new_profile($fqdbin);
|
||||
}
|
||||
|
||||
# stick the profile into our data structure.
|
||||
attach_profile_data(\%sd, $profile_data);
|
||||
# and store a "clean" version also so we can display the changes we've
|
||||
# made during this run
|
||||
attach_profile_data(\%original_sd, $profile_data);
|
||||
|
||||
if (-f "$profiledir/tunables/global") {
|
||||
my $file = getprofilefilename($fqdbin);
|
||||
@@ -913,6 +1079,18 @@ my %CMDS = (
|
||||
CMD_USEDEFAULT => "(U)se Default Hat",
|
||||
CMD_SCAN => "(S)can system log for SubDomain events",
|
||||
CMD_HELP => "(H)elp",
|
||||
CMD_VIEW_REPO => "(V)iew Profile",
|
||||
CMD_USE_REPO => "(U)se Profile",
|
||||
CMD_CREATE_PROFILE => "(C)reate New Profile",
|
||||
CMD_UPDATE_PROFILE => "(U)pdate Profile",
|
||||
CMD_IGNORE_UPDATE => "(I)gnore Update",
|
||||
CMD_SAVE_CHANGES => "(S)ave Changes",
|
||||
CMD_UPLOAD_CHANGES => "(U)pload Changes",
|
||||
CMD_VIEW_CHANGES => "(V)iew Changes",
|
||||
CMD_ENABLE_REPO => "(E)nable Repository",
|
||||
CMD_DISABLE_REPO => "(D)isable Repository",
|
||||
CMD_ASK_NEVER => "(N)ever Ask Again",
|
||||
CMD_ASK_LATER => "Ask Me (L)ater",
|
||||
);
|
||||
|
||||
sub UI_PromptUser ($) {
|
||||
@@ -1647,6 +1825,77 @@ sub read_log {
|
||||
close(LOG);
|
||||
}
|
||||
|
||||
sub check_repo_for_newer {
|
||||
my $profile = shift;
|
||||
|
||||
my $distro = $cfg->{settings}{distro};
|
||||
my $url = $sd{$profile}{$profile}{repo}{url};
|
||||
my $user = $sd{$profile}{$profile}{repo}{user};
|
||||
my $id = $sd{$profile}{$profile}{repo}{id};
|
||||
|
||||
return unless ($distro && $url && $user && $id);
|
||||
|
||||
my $p;
|
||||
if ($repo_client) {
|
||||
my $res = $repo_client->send_request('FindProfiles', $distro, $profile, $user);
|
||||
if (did_result_succeed($res)) {
|
||||
my @profiles;
|
||||
my @profile_list = @{$res->value};
|
||||
|
||||
if (@profile_list) {
|
||||
if ($profile_list[0]->{id} > $id) {
|
||||
$p = $profile_list[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($p) {
|
||||
my $q = { };
|
||||
$q->{headers} = [
|
||||
"Profile", $profile,
|
||||
"User", $user,
|
||||
"Old Revision", $id,
|
||||
"New Revision", $p->{id},
|
||||
];
|
||||
$q->{explanation} = "An updated version of this profile has been found in the profile repository. Would you like to use it?";
|
||||
$q->{functions} = [
|
||||
"CMD_VIEW_CHANGES", "CMD_UPDATE_PROFILE", "CMD_IGNORE_UPDATE",
|
||||
"CMD_ABORT", "CMD_FINISHED"
|
||||
];
|
||||
|
||||
my $ans;
|
||||
do {
|
||||
$ans = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW_CHANGES") {
|
||||
my $oldprofile = serialize_profile($sd{$profile}, $profile);
|
||||
my $newprofile = $p->{profile};
|
||||
display_changes($oldprofile, $newprofile);
|
||||
}
|
||||
} until $ans =~ /^CMD_(UPDATE_PROFILE|IGNORE_UPDATE)/;
|
||||
|
||||
if ($ans eq "CMD_UPDATE_PROFILE") {
|
||||
eval {
|
||||
my $profile_data = parse_profile_data($p->{profile}, "repository profile");
|
||||
if ($profile_data) {
|
||||
attach_profile_data(\%sd, $profile_data);
|
||||
attach_profile_data(\%original_sd, $profile_data);
|
||||
$changed{$profile} = 1;
|
||||
}
|
||||
|
||||
set_repo_info($sd{$profile}{$profile}, $url, $user, $p->{id});
|
||||
|
||||
UI_Info("Updated profile $profile to revision $p->{id}.");
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
UI_Info("Error parsing repository profile.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub ask_the_questions {
|
||||
my $found;
|
||||
|
||||
@@ -1668,6 +1917,8 @@ sub ask_the_questions {
|
||||
|
||||
for my $profile (sort keys %{ $log{$sdmode} }) {
|
||||
|
||||
check_repo_for_newer($profile);
|
||||
|
||||
$found++;
|
||||
|
||||
# this sorts the list of hats, but makes sure that the containing
|
||||
@@ -2047,6 +2298,122 @@ sub ask_the_questions {
|
||||
}
|
||||
}
|
||||
|
||||
sub repo_is_enabled {
|
||||
my $enabled;
|
||||
|
||||
if ($repo_cfg &&
|
||||
$repo_cfg->{repository}{enabled} &&
|
||||
$repo_cfg->{repository}{enabled} eq "yes") {
|
||||
$enabled = 1;
|
||||
}
|
||||
|
||||
return $enabled;
|
||||
}
|
||||
|
||||
sub ask_to_enable_repo {
|
||||
|
||||
my $q = { };
|
||||
$q->{headers} = [
|
||||
"Repository", $cfg->{settings}{repository},
|
||||
];
|
||||
$q->{explanation} = "Would you like to enable access to the profile repository?";
|
||||
$q->{functions} = [
|
||||
"CMD_ENABLE_REPO", "CMD_DISABLE_REPO", "CMD_ASK_LATER",
|
||||
"CMD_ABORT", "CMD_FINISHED",
|
||||
];
|
||||
|
||||
my $cmd;
|
||||
do {
|
||||
$cmd = UI_PromptUser($q);
|
||||
} until $cmd =~ /^CMD_(ENABLE_REPO|DISABLE_REPO|LATER_REPO)/;
|
||||
|
||||
if ($cmd eq "CMD_ENABLE_REPO") {
|
||||
$repo_cfg->{repository}{enabled} = "yes";
|
||||
} elsif ($cmd eq "CMD_DISABLE_REPO") {
|
||||
$repo_cfg->{repository}{enabled} = "no";
|
||||
} elsif ($cmd eq "CMD_LATER_REPO") {
|
||||
$repo_cfg->{repository}{enabled} = "later";
|
||||
}
|
||||
|
||||
write_config("repository.conf", $repo_cfg);
|
||||
}
|
||||
|
||||
sub get_repo_user_pass {
|
||||
my ($user, $pass);
|
||||
|
||||
if ($repo_cfg) {
|
||||
$user = $repo_cfg->{repository}{user};
|
||||
$pass = $repo_cfg->{repository}{pass};
|
||||
}
|
||||
|
||||
unless ($user && $pass) {
|
||||
($user, $pass) = ask_signup_info();
|
||||
}
|
||||
|
||||
return ($user, $pass);
|
||||
}
|
||||
|
||||
sub setup_repo_client {
|
||||
unless ($repo_client) {
|
||||
$repo_client = new RPC::XML::Client $cfg->{settings}{repository};
|
||||
}
|
||||
}
|
||||
|
||||
sub did_result_succeed {
|
||||
my $result = shift;
|
||||
|
||||
my $ref = ref $result;
|
||||
return ($ref && $ref ne "RPC::XML::fault") ? 1 : 0;
|
||||
}
|
||||
|
||||
sub get_result_error {
|
||||
my $result = shift;
|
||||
|
||||
if (ref $result) {
|
||||
if (ref $result eq "RPC::XML::fault") {
|
||||
$result = $result->string;
|
||||
} else {
|
||||
$result = $$result;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub ask_signup_info {
|
||||
|
||||
my ($user, $pass, $email, $signup_okay);
|
||||
|
||||
if ($repo_client) {
|
||||
do {
|
||||
$user = UI_GetString("Username: ", $user);
|
||||
$pass = UI_GetString("Password: ", $pass);
|
||||
$email = UI_GetString("Email Addr: ", $email);
|
||||
|
||||
my $res = $repo_client->send_request('LoginConfirm', $user, $pass);
|
||||
if (did_result_succeed($res)) {
|
||||
$signup_okay = 1;
|
||||
} else {
|
||||
$res = $repo_client->send_request('Signup', $user, $pass, $email);
|
||||
if (did_result_succeed($res)) {
|
||||
$signup_okay = 1;
|
||||
} else {
|
||||
my $error = get_result_error($res);
|
||||
print STDERR "$error\n";
|
||||
}
|
||||
}
|
||||
} until $signup_okay;
|
||||
}
|
||||
|
||||
$repo_cfg->{repository}{user} = $user;
|
||||
$repo_cfg->{repository}{pass} = $pass;
|
||||
$repo_cfg->{repository}{email} = $email;
|
||||
|
||||
write_config("repository.conf", $repo_cfg);
|
||||
|
||||
return ($user, $pass);
|
||||
}
|
||||
|
||||
sub do_logprof_pass {
|
||||
my $logmark = shift || "";
|
||||
|
||||
@@ -2075,6 +2442,17 @@ sub do_logprof_pass {
|
||||
# we need to be able to break all the way out of deep into subroutine calls
|
||||
# if they select "Finish" so we can take them back out to the genprof prompt
|
||||
eval {
|
||||
unless ($repo_cfg) {
|
||||
$repo_cfg = read_config("repository.conf");
|
||||
unless ($repo_cfg->{repository}{enabled}) {
|
||||
ask_to_enable_repo();
|
||||
}
|
||||
}
|
||||
|
||||
if (repo_is_enabled()) {
|
||||
setup_repo_client();
|
||||
}
|
||||
|
||||
read_log($logmark);
|
||||
|
||||
for my $root (@log) {
|
||||
@@ -2119,6 +2497,13 @@ sub do_logprof_pass {
|
||||
|
||||
save_profiles();
|
||||
|
||||
if (repo_is_enabled()) {
|
||||
unless ($repo_cfg->{repository}{neversubmit}) {
|
||||
submit_created_profiles();
|
||||
submit_changed_profiles();
|
||||
}
|
||||
}
|
||||
|
||||
# if they hit "Finish" we need to tell the caller that so we can exit
|
||||
# all the way instead of just going back to the genprof prompt
|
||||
return $finishing ? "FINISHED" : "NORMAL";
|
||||
@@ -2126,12 +2511,251 @@ sub do_logprof_pass {
|
||||
|
||||
sub save_profiles {
|
||||
# make sure the profile changes we've made are saved to disk...
|
||||
for my $profile (sort keys %changed) {
|
||||
writeprofile($profile);
|
||||
reload($profile);
|
||||
my @changed = sort keys %changed;
|
||||
|
||||
if (@changed) {
|
||||
my $q = { };
|
||||
$q->{title} = "Changed Profiles";
|
||||
$q->{headers} = [ ];
|
||||
|
||||
$q->{explanation} = "The following profiles were changed. Would you like to save them?";
|
||||
|
||||
$q->{functions} = [
|
||||
"CMD_SAVE_CHANGES", "CMD_VIEW_CHANGES",
|
||||
"CMD_ABORT",
|
||||
];
|
||||
|
||||
$q->{default} = "CMD_VIEW_CHANGES";
|
||||
|
||||
$q->{options} = [ @changed ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($p, $ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW_CHANGES") {
|
||||
my $which = $changed[$arg];
|
||||
my $oldprofile = serialize_profile($original_sd{$which},
|
||||
$which);
|
||||
my $newprofile = serialize_profile($sd{$which}, $which);
|
||||
display_changes($oldprofile, $newprofile);
|
||||
}
|
||||
|
||||
} until $ans =~ /^CMD_SAVE_CHANGES/;
|
||||
|
||||
for my $profile (sort keys %changed) {
|
||||
writeprofile($profile);
|
||||
reload($profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub is_repo_profile {
|
||||
my $profile_data = shift;
|
||||
|
||||
return $profile_data->{repo}{url} &&
|
||||
$profile_data->{repo}{user} &&
|
||||
$profile_data->{repo}{id};
|
||||
}
|
||||
|
||||
sub submit_created_profiles {
|
||||
my $url = $cfg->{settings}{repository};
|
||||
|
||||
my @new_profiles;
|
||||
for my $profile (sort keys %sd) {
|
||||
unless (is_repo_profile($sd{$profile}{$profile})) {
|
||||
push @new_profiles, $profile;
|
||||
}
|
||||
}
|
||||
|
||||
if ($repo_client && @new_profiles) {
|
||||
my $q = { };
|
||||
$q->{title} = "Submit New Profiles";
|
||||
$q->{headers} = [
|
||||
"Repository", $url,
|
||||
];
|
||||
|
||||
$q->{explanation} = "Would you like to upload the following newly created profiles?";
|
||||
|
||||
$q->{functions} = [
|
||||
"CMD_UPLOAD_CHANGES", "CMD_VIEW_CHANGES", "CMD_ASK_NEVER",
|
||||
"CMD_ABORT",
|
||||
];
|
||||
|
||||
$q->{default} = "CMD_VIEW_CHANGES";
|
||||
|
||||
$q->{options} = [ @new_profiles ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW_CHANGES") {
|
||||
my $which = $new_profiles[$arg];
|
||||
my $newprofile = serialize_profile($sd{$which}, $which);
|
||||
display_text($which, $newprofile);
|
||||
}
|
||||
|
||||
} until $ans =~ /^CMD_UPLOAD_CHANGES/;
|
||||
|
||||
if ($ans eq "CMD_UPLOAD_CHANGES") {
|
||||
my $changelog = UI_GetString("Changelog Entry: ", "");
|
||||
|
||||
my ($user, $pass) = get_repo_user_pass();
|
||||
|
||||
if ($user && $pass) {
|
||||
for my $profile (@new_profiles) {
|
||||
my $profile_string = serialize_profile($sd{$profile},
|
||||
$profile);
|
||||
|
||||
my @args = (
|
||||
'Create', $user, $pass, $cfg->{settings}{distro},
|
||||
$profile, $profile_string, $changelog
|
||||
);
|
||||
my $res = $repo_client->send_request(@args);
|
||||
if (ref $res) {
|
||||
my $newprofile = $res->{value};
|
||||
my $newid = $newprofile->{id};
|
||||
|
||||
set_repo_info($sd{$profile}{$profile},
|
||||
$url,
|
||||
$user,
|
||||
$newid);
|
||||
writeprofile($profile);
|
||||
UI_Info("Uploaded $profile to repository.");
|
||||
} else {
|
||||
print "Error: $res\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub submit_changed_profiles {
|
||||
|
||||
my $url = $cfg->{settings}{repository};
|
||||
|
||||
my @repo_profiles;
|
||||
for my $profile (sort keys %sd) {
|
||||
if (is_repo_profile($sd{$profile}{$profile})) {
|
||||
push @repo_profiles, $profile;
|
||||
}
|
||||
}
|
||||
|
||||
if (@repo_profiles) {
|
||||
if ($repo_client) {
|
||||
my @changed_profiles;
|
||||
for my $profile (@repo_profiles) {
|
||||
my $id = $sd{$profile}{$profile}{repo}{id};
|
||||
my $res = $repo_client->send_request('Show', $id);
|
||||
if (did_result_succeed($res)) {
|
||||
my $p = $res->value;
|
||||
my $profile_string = serialize_profile($sd{$profile},
|
||||
$profile);
|
||||
if ($p->{profile} ne $profile_string) {
|
||||
push @changed_profiles, [ $profile, $p ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (@changed_profiles) {
|
||||
my $q = { };
|
||||
$q->{title} = "Submit Profiles";
|
||||
$q->{headers} = [
|
||||
"Repository", $url,
|
||||
];
|
||||
|
||||
$q->{explanation} = "The following profiles from the repository were changed. Would you like to upload your changes?";
|
||||
|
||||
$q->{functions} = [
|
||||
"CMD_UPLOAD_CHANGES", "CMD_VIEW_CHANGES", "CMD_ASK_NEVER",
|
||||
"CMD_ABORT",
|
||||
];
|
||||
|
||||
$q->{default} = "CMD_VIEW_CHANGES";
|
||||
|
||||
$q->{options} = [ map { $_->[0] } @changed_profiles ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW_CHANGES") {
|
||||
my $which = $changed_profiles[$arg]->[0];
|
||||
my $repo_profile = $changed_profiles[$arg]->[1]->{profile};
|
||||
my $newprofile = serialize_profile($sd{$which}, $which);
|
||||
display_changes($repo_profile, $newprofile);
|
||||
}
|
||||
|
||||
} until $ans =~ /^CMD_UPLOAD_CHANGES/;
|
||||
|
||||
print "UPLOAD CHANGES\n";
|
||||
|
||||
if ($ans eq "CMD_UPLOAD_CHANGES") {
|
||||
my $changelog = UI_GetString("Changelog Entry: ", "");
|
||||
|
||||
my ($user, $pass) = get_repo_user_pass();
|
||||
|
||||
if ($user && $pass) {
|
||||
for my $profile (map { $_->[0] } @changed_profiles) {
|
||||
my $profile_string =
|
||||
serialize_profile($sd{$profile}, $profile);
|
||||
|
||||
my @args = (
|
||||
'Create', $user, $pass, $cfg->{settings}{distro},
|
||||
$profile, $profile_string, $changelog
|
||||
);
|
||||
my $res = $repo_client->send_request(@args);
|
||||
if (ref $res) {
|
||||
my $newprofile = $res->{value};
|
||||
my $newid = $newprofile->{id};
|
||||
|
||||
set_repo_info($sd{$profile}{$profile},
|
||||
$url,
|
||||
$user,
|
||||
$newid);
|
||||
writeprofile($profile);
|
||||
UI_Info("Uploaded $profile to repository.");
|
||||
} else {
|
||||
print "Error: $res\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub display_text {
|
||||
my ($header, $body) = @_;
|
||||
|
||||
if (open(PAGER, "| less")) {
|
||||
print PAGER "$header\n\n$body";
|
||||
close(PAGER);
|
||||
}
|
||||
}
|
||||
|
||||
sub display_changes {
|
||||
my ($oldprofile, $newprofile) = @_;
|
||||
|
||||
my $oldtmp = new File::Temp( UNLINK => 0 );
|
||||
print $oldtmp $oldprofile;
|
||||
close($oldtmp);
|
||||
|
||||
my $newtmp = new File::Temp( UNLINK => 0 );
|
||||
print $newtmp $newprofile;
|
||||
close($newtmp);
|
||||
|
||||
system("diff -uw $oldtmp $newtmp | less");
|
||||
|
||||
unlink($oldtmp);
|
||||
unlink($newtmp);
|
||||
}
|
||||
|
||||
sub setprocess ($$) {
|
||||
my ($pid, $profile) = @_;
|
||||
@@ -2340,6 +2964,7 @@ sub readprofile ($$) {
|
||||
my $profile_data = parse_profile_data($data, $file);
|
||||
if ($profile_data) {
|
||||
attach_profile_data(\%sd, $profile_data);
|
||||
attach_profile_data(\%original_sd, $profile_data);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2356,15 +2981,17 @@ sub readprofile ($$) {
|
||||
sub attach_profile_data {
|
||||
my ($profiles, $profile_data) = @_;
|
||||
|
||||
# make deep copies of the profile data so that if we change one set of
|
||||
# profile data, we're not changing others because of sharing references
|
||||
for my $p ( keys %$profile_data) {
|
||||
$profiles->{$p} = $profile_data->{$p};
|
||||
$profiles->{$p} = dclone($profile_data->{$p});
|
||||
}
|
||||
}
|
||||
|
||||
sub parse_profile_data {
|
||||
my ($data, $file) = @_;
|
||||
|
||||
my ($profile_data, $profile, $hat, $in_contained_hat);
|
||||
my ($profile_data, $profile, $hat, $in_contained_hat, $repo_data);
|
||||
my $initial_comment = "";
|
||||
for (split(/\n/, $data)) {
|
||||
chomp;
|
||||
@@ -2413,6 +3040,13 @@ sub parse_profile_data {
|
||||
$profile_data->{$profile}{$hat}{initial_comment} = $initial_comment if $initial_comment;
|
||||
$initial_comment = "";
|
||||
|
||||
if ($repo_data) {
|
||||
$profile_data->{$profile}{$profile}{repo}{url} = $repo_data->{url};
|
||||
$profile_data->{$profile}{$profile}{repo}{user} = $repo_data->{user};
|
||||
$profile_data->{$profile}{$profile}{repo}{id} = $repo_data->{id};
|
||||
$repo_data = undef;
|
||||
}
|
||||
|
||||
} elsif (m/^\s*\}\s*$/) { # end of a profile...
|
||||
|
||||
# if we hit the end of a profile when we're not in one, something's
|
||||
@@ -2554,7 +3188,11 @@ sub parse_profile_data {
|
||||
next if /^\s*\# vim:syntax/;
|
||||
# ignore Last Modified: lines
|
||||
next if /^\s*\# Last Modified:/;
|
||||
$initial_comment .= "$_\n";
|
||||
if (/^\s*\# REPOSITORY: (\S+) (\S+) (\S+)$/) {
|
||||
$repo_data = { url => $1, user => $2, id => $3 };
|
||||
} else {
|
||||
$initial_comment .= "$_\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2702,6 +3340,15 @@ sub serialize_profile {
|
||||
if ($include_metadata) {
|
||||
# keep track of when the file was last updated
|
||||
$string .= "# Last Modified: " . localtime(time) . "\n";
|
||||
|
||||
# print out repository metadata
|
||||
if ($profile_data->{$name}{repo} &&
|
||||
$profile_data->{$name}{repo}{url} &&
|
||||
$profile_data->{$name}{repo}{user} &&
|
||||
$profile_data->{$name}{repo}{id}) {
|
||||
my $repo = $profile_data->{$name}{repo};
|
||||
$string .= "# REPOSITORY: $repo->{url} $repo->{user} $repo->{id}\n";
|
||||
}
|
||||
}
|
||||
|
||||
# print out initial comment
|
||||
@@ -2753,6 +3400,7 @@ sub writeprofile ($) {
|
||||
|
||||
# mark the profile as up-to-date
|
||||
delete $changed{$profile};
|
||||
$original_sd{$profile} = dclone($sd{$profile});
|
||||
}
|
||||
|
||||
sub getprofileflags {
|
||||
|
@@ -42,7 +42,7 @@ Requires: perl-DateManip
|
||||
%else
|
||||
Requires: perl-TimeDate
|
||||
%endif
|
||||
Requires: perl-DBI perl-DBD-SQLite perl-File-Tail perl-gettext
|
||||
Requires: perl-DBI perl-DBD-SQLite perl-File-Tail perl-gettext perl-RPC-XML
|
||||
Obsoletes: subdomain-utils
|
||||
Provides: subdomain-utils
|
||||
|
||||
|
@@ -16,6 +16,9 @@
|
||||
parser = /sbin/apparmor_parser /sbin/subdomain_parser
|
||||
ldd = /usr/bin/ldd
|
||||
|
||||
distro = opensuse
|
||||
repository = http://localhost:3000/backend/api
|
||||
|
||||
# custom directory locations to look for #includes
|
||||
#
|
||||
# each name should be a valid directory containing possible #include
|
||||
|
Reference in New Issue
Block a user