shell bypass 403
#!/usr/bin/perl
# Copyright (C) 2013-2018 X2Go Project - https://wiki.x2go.org
# Copyright (C) 2013-2015 Guangzhou Nianguan Electronics Technology Co.Ltd. <opensource@gznianguan.com>
# Copyright (C) 2013-2015 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
#
# 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 of the License, 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.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
package X2Go::SupeReNicer;
=head1 NAME
X2Go::SupeReNicer- X2Go SupeReNicer package for Perl
=head1 DESCRIPTION
X2Go::SupeReNicer Perl package.
=cut
use strict;
use Sys::Syslog qw( :standard :macros );
use X2Go::Utils qw( sanitizer clups system_capture_stdout_output );
use base 'Exporter';
our @EXPORT=('superenice');
sub checkPID {
my $pid = sanitizer("num",$_[0]);
if ( $pid )
{
open(PS,"/bin/ps --no-headers -o %u,%p,%n,%c -p $pid|");
my ($pidInf,undef) = <PS>;
close(PS);
my ($user,$pid,$nice,$cmd) = split(/\,/,clups($pidInf));
$pid =~ s/\D//g;
return ($pid,$user,$nice,$cmd);
} else {
return (-1, "failure", 0, "failed to sanitize PID");
}
}
sub sanitizeNL {
my $NL = shift;
my $fallbackNL = shift;
if ($NL =~ m/^(-|\+|)\d+$/) {
$NL = int $NL;
if ($NL > 19) { $NL = 19; }
elsif ($NL < -19) { $NL = -19; }
} else {
$NL = $fallbackNL;
}
return $NL;
}
sub superenice {
# Normal: Nice LEVEL?
my $normalNL = shift; $normalNL = 0 unless defined $normalNL;
$normalNL = sanitizeNL($normalNL, 0);
# Idle: Nice LEVEL?
my $idleNL = shift; $idleNL = 19 unless defined $idleNL;
$idleNL = sanitizeNL($idleNL, 19);
# Ignore these users (comma separated list as string)
my $ignore_users = shift; $ignore_users = "" unless defined $ignore_users;
# if set to "1" we will force renicing of entire user, even on systems with "/proc"
my $forceUSERrenice = shift; $forceUSERrenice = 0 unless defined $forceUSERrenice;
#Path to the "x2golistsessions_root" perl script...
my $x2golsrpath = system_capture_stdout_output("x2gopath", "base") . "/sbin/x2golistsessions_root";
###########################################################################################
# Load list of users to "ignore". These users will never be reniced...
my %ignore;
while (split(",", $ignore_users)) {my $iu = clups($_);if (length($iu) > 0) {$ignore{$iu} = 1;}}
# Load list of users to "ignore". These users will never be reniced...
###########################################################################################
if ((-f "/proc/$$/environ") and ($forceUSERrenice ne 1)) {
###########################################################################################
# Great! We're on a system with "/proc" so we're able to do this on individual sessions!
# Basicaly we're checking the users /proc/<$PID>/environ files for the "X2GO_SESSION" env...
my @x2goSessions;
# Read the current list of X2Go sessions and their running state
open(XGOLS,"$x2golsrpath|");
while (<XGOLS>) {
my $line = clups($_);
my ($agentPid,$x2gosid,undef,undef,$x2goState,undef,undef,undef,undef,undef,undef,$userID,undef,undef) = split(/\|/,$line);
#syslog('debug', "$agentPid,$x2gosid,$x2goState,$userID");
unless (($ignore{$userID} eq 1) || ($x2gosid =~ m/.*XSHAD.*XSHAD/)) {
push @x2goSessions, "$x2goState:$agentPid:$x2gosid:$userID";
}
}
close(XGOLS);
foreach my $x2goSInf (@x2goSessions) {
my ($x2goState,$agentPid,$x2gosid,$userID,undef) = split(/\:/,$x2goSInf);
$agentPid = sanitizer("num",$agentPid);
# We're only working with "portable" unix usernames.
$userID = sanitizer("pnixusername",$userID);
# So if the sanitizer returns something we'll do this....
if ($userID) {
# Using the NICE value of the agent to figgure out the current nice state...
my ($psP,$psU,$psN,$psC) = checkPID($agentPid);
if ($psP > -1) {
if ($x2goState eq "R") {
# State is R (Running?)...
if ($psN ne $normalNL) {
# If nice level is not normal, renice to normal...
syslog('notice', "ReNicing \"$userID\" to level $normalNL for session \"$x2gosid\"");
# For the sake of getting a user back to normal ASAP... We'll renice the entire user not just individual sessions...
system("renice", "-n", "$normalNL", "-u", "$userID");
}
} elsif ($x2goState eq "S") {
# State is S (suspended)
if ($psN ne $idleNL) {
# Did we renice this?
open(AUPS,"/bin/ps --no-headers -o %u,%p,%n,%c -u $userID|"); # use PS to fetch a list of the users current processes
while (<AUPS>) {
my ($user,$pid,$nice,$cmd) = split(/\,/,clups($_));
$pid = sanitizer("num",$pid);
if (-f "/proc/$pid/environ") {
open(ENVIRON,"/proc/$pid/environ");my ($Environ,undef) = <ENVIRON>;close(ENVIRON);
if ($Environ =~ m/X2GO_SESSION=$x2gosid/) { # If the x2go Session ID is in environ... renice the pid...
#syslog('debug', "$pid: X2GO_SESSION=$x2gosid");
system("renice", "-n", "$idleNL", "-p", "$pid");
}
}
}
close(AUPS);
# Renice the AGENT so that we'll know that this one is already reniced.
system("renice", "-n", "$idleNL", "-p", "$agentPid");
syslog('notice', "ReNicing \"$userID\" to level $idleNL for session \"$x2gosid\"");
}
}
}
}
}
# Great! We're on a system with "/proc" so we're able to do this on individual sessions!
############################################################################################
} else {
###########################################################################################
# Oh no.... No "/proc"? Lets do this on a per user basis instead then...
# If a user have more than one session, both need to be suspended before we renice....
# Resuming any of that users sessions would return them all to normal priority.
my %niceUsers;
# Read the current list of X2Go sessions and their running state
open(XGOLS,"$x2golsrpath|");
while (<XGOLS>) {
my $line = clups($_);
my ($agentPid,$x2gosid,undef,undef,$x2goState,undef,undef,undef,undef,undef,undef,$userID,undef,undef) = split(/\|/,$line);
syslog('debug', "$agentPid,$x2gosid,,$x2goState,$userID");
# If user is in ignore list... we're not going a damn thing..
unless (($ignore{$userID} eq 1) || ($x2gosid =~ m/.*XSHAD.*XSHAD/)) {
unless ($niceUsers{$userID} =~ /^R:/) { # Basically if we got an R we're sticking with it...
$niceUsers{$userID} = "$x2goState:$agentPid";
}
}
}
close(XGOLS);
foreach my $nUser (keys %niceUsers) {
$nUser = sanitizer("pnixusername",$nUser);
# We're only working with "portable" unix usernames..
if ($nUser) {
# So if the sanitizer return something we'll do this....
my ($x2goState,$agentPid) = split(/\:/, $niceUsers{$nUser});
# Using the NICE value of the agent to figgure out the current nice state...
my ($psP,$psU,$psN,$psC) = checkPID($agentPid);
syslog('debug', "$nUser:$x2goState,$agentPid:$psP,$psU,$psN,$psC");
if ($psP > -1) {
# State is R (Running?)...
if ($x2goState eq "R") {
# If nice level is not normal, renice to normal...
if ($psN ne $normalNL) {
syslog('debug', "ReNicing \"$nUser\" to level $normalNL");
system("renice", "-n", "$normalNL", "-u", "$nUser");
}
# State is S (suspended)
} elsif ($x2goState eq "S") {
# Did we renice this?
if ($psN ne $idleNL) {
syslog('debug', "ReNicing \"$nUser\" to level $idleNL");
system("renice", "-n", "$idleNL", "-u", "$nUser");
}
}
}
}
}
# Oh no.... No "/proc"? Lets do this on a per user basis instead then...
###########################################################################################
}
}
1;