summaryrefslogtreecommitdiffstats
path: root/pym/portage/_selinux.py
blob: e4621b1d9d9070d2600f7a172728b0a883cfa71e (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

# Don't use the unicode-wrapped os and shutil modules here since
# the whole _selinux module itself will be wrapped.
import os
import shutil

import portage
from portage import _encodings
from portage import _native_string, _unicode_decode
from portage.localization import _
portage.proxy.lazyimport.lazyimport(globals(),
	'selinux')

def copyfile(src, dest):
	src = _native_string(src, encoding=_encodings['fs'], errors='strict')
	dest = _native_string(dest, encoding=_encodings['fs'], errors='strict')
	(rc, ctx) = selinux.lgetfilecon(src)
	if rc < 0:
		if sys.hexversion < 0x3000000:
			src = _unicode_decode(src, encoding=_encodings['fs'], errors='replace')
		raise OSError(_("copyfile: Failed getting context of \"%s\".") % src)

	setfscreate(ctx)
	try:
		shutil.copyfile(src, dest)
	finally:
		setfscreate()

def getcontext():
	(rc, ctx) = selinux.getcon()
	if rc < 0:
		raise OSError(_("getcontext: Failed getting current process context."))

	return ctx

def is_selinux_enabled():
	return selinux.is_selinux_enabled()

def mkdir(target, refdir):
	target = _native_string(target, encoding=_encodings['fs'], errors='strict')
	refdir = _native_string(refdir, encoding=_encodings['fs'], errors='strict')
	(rc, ctx) = selinux.getfilecon(refdir)
	if rc < 0:
		if sys.hexversion < 0x3000000:
			refdir = _unicode_decode(refdir, encoding=_encodings['fs'], errors='replace')
		raise OSError(
			_("mkdir: Failed getting context of reference directory \"%s\".") \
			% refdir)

	setfscreate(ctx)
	try:
		os.mkdir(target)
	finally:
		setfscreate()

def rename(src, dest):
	src = _native_string(src, encoding=_encodings['fs'], errors='strict')
	dest = _native_string(dest, encoding=_encodings['fs'], errors='strict')
	(rc, ctx) = selinux.lgetfilecon(src)
	if rc < 0:
		if sys.hexversion < 0x3000000:
			src = _unicode_decode(src, encoding=_encodings['fs'], errors='replace')
		raise OSError(_("rename: Failed getting context of \"%s\".") % src)

	setfscreate(ctx)
	try:
		os.rename(src,dest)
	finally:
		setfscreate()

def settype(newtype):
	ret = getcontext().split(":")
	ret[2] = newtype
	return ":".join(ret)

def setexec(ctx="\n"):
	ctx = _native_string(ctx, encoding=_encodings['content'], errors='strict')
	if selinux.setexeccon(ctx) < 0:
		if sys.hexversion < 0x3000000:
			ctx = _unicode_decode(ctx, encoding=_encodings['content'], errors='replace')
		if selinux.security_getenforce() == 1:
			raise OSError(_("Failed setting exec() context \"%s\".") % ctx)
		else:
			portage.writemsg("!!! " + \
				_("Failed setting exec() context \"%s\".") % ctx, \
				noiselevel=-1)

def setfscreate(ctx="\n"):
	ctx = _native_string(ctx, encoding=_encodings['content'], errors='strict')
	if selinux.setfscreatecon(ctx) < 0:
		if sys.hexversion < 0x3000000:
			ctx = _unicode_decode(ctx, encoding=_encodings['content'], errors='replace')
		raise OSError(
			_("setfscreate: Failed setting fs create context \"%s\".") % ctx)

class spawn_wrapper(object):
	"""
	Create a wrapper function for the given spawn function. When the wrapper
	is called, it will adjust the arguments such that setexec() to be called
	*after* the fork (thereby avoiding any interference with concurrent
	threads in the calling process).
	"""
	__slots__ = ("_con", "_spawn_func")

	def __init__(self, spawn_func, selinux_type):
		self._spawn_func = spawn_func
		selinux_type = _native_string(selinux_type, encoding=_encodings['content'], errors='strict')
		self._con = settype(selinux_type)

	def __call__(self, *args, **kwargs):

		pre_exec = kwargs.get("pre_exec")

		def _pre_exec():
			if pre_exec is not None:
				pre_exec()
			setexec(self._con)

		kwargs["pre_exec"] = _pre_exec
		return self._spawn_func(*args, **kwargs)

def symlink(target, link, reflnk):
	target = _native_string(target, encoding=_encodings['fs'], errors='strict')
	link = _native_string(link, encoding=_encodings['fs'], errors='strict')
	reflnk = _native_string(reflnk, encoding=_encodings['fs'], errors='strict')
	(rc, ctx) = selinux.lgetfilecon(reflnk)
	if rc < 0:
		if sys.hexversion < 0x3000000:
			reflnk = _unicode_decode(reflnk, encoding=_encodings['fs'], errors='replace')
		raise OSError(
			_("symlink: Failed getting context of reference symlink \"%s\".") \
			% reflnk)

	setfscreate(ctx)
	try:
		os.symlink(target, link)
	finally:
		setfscreate()