summaryrefslogtreecommitdiff
blob: 27a5aa7988e4cb7ca772a0294b33a3457358bad5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package Scire::Job;

use POSIX qw/WEXITSTATUS WIFEXITED waitpid setuid setgid/;

sub new {
	my $proto = shift;
	my $class = ref($proto) || $proto;
	my $filename = shift;
	my $self  = {};
	bless ($self, $class);
	if(defined $filename) {
		$self->load_jobfile($filename);
	}
	return $self;
}

sub load_jobfile {
	my $self = shift;
	my $filename = shift;
	$self->{filename} = $filename;
	my $jobcontents;
	my $jobdata;
	open JOB, "< ${filename}" or die "Can't open file ${filename}";
	$jobcontents = join("", <JOB>);
	close JOB;
	$jobdata = eval($jobcontents);
	($@) and print "ERROR: Could not parse job file ${filename}!\n";
	if(defined $jobdata->{script}) {
		for(keys %{$jobdata->{script}}) {
			$self->{$_} = $jobdata->{script}->{$_};
		}
	}
	for(keys %{$jobdata}) {
		$self->{$_} = $jobdata->{$_} unless($_ eq "script");
	}
}

sub set_script_file {
	my ($self, $scriptfile) = @_;
	if(defined $scriptfile and $scriptfile) {
		$self->{script_filename} = $scriptfile;
	}
}

sub set_stdout_file {
	my ($self, $outfile) = @_;
	if(defined $outfile && $outfile) {
		$self->{stdout_filename} = $outfile;
	}
}

sub set_stderr_file {
	my ($self, $errfile) = @_;
	if(defined $errfile && $errfile) {
		$self->{stderr_filename} = $errfile;
	}
}

sub run {
	my $self = shift;

	# XXX: we might want to check capabilities here instead of UID, but I
	# have no idea how to do that
	my ($run_as_uid, $run_as_gid) = (0, 0);
	if($< == 0) {
		# XXX: we'll use setuid to drop privileges here
		my @user = getpwnam($self->{run_as});
		if(defined @user) {
			$run_as_uid = $user[2];
			$run_as_gid = $user[3];
		} else {
			return -2;
		}
	}

	open SCRIPT, ">", $self->{script_filename};
	print SCRIPT $self->{script_data};
	close SCRIPT;
	if($run_as_uid) {
		chown $run_as_uid, $run_as_gid, $self->{script_filename};
	}
	chmod 0500, $self->{script_filename};

	my $pid = fork();
	if($pid) {
		# XXX: eventually, we'll move the waitpid() call to another function
		# called something like is_running() and use WNOHANG instead of blocking
		waitpid($pid, 0);
		my $status = $?;
#		my $exitcode = -1;
#		if(WIFEXITED($status)) {
			my $exitcode = WEXITSTATUS($status);
#		}
		return $exitcode;
	} else {
		# We redirect STDOUT and STDERR first since the new user may not have
		# write access to the file locations
		if(defined $self->{stdout_filename}) {
			open STDOUT, '>', $self->{stdout_filename};
		}
		if(defined $self->{stderr_filename}) {
			open STDERR, '>', $self->{stderr_filename};
		}
		if($run_as_uid) {
			setuid($run_as_uid);
			setgid($run_as_gid);
		}
		# XXX: exec() to run our command. our STDOUT and STDERR have been
		# redirected to the files specified, and the exit code is returned
		# to the main process when we're done executing. This will be changed
		# to the path of the script we've written to disk once that code is in
		exec '/bin/sh', '-c', $self->{script_filename};
	}
}

1;