-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathhooks.py
More file actions
219 lines (175 loc) · 6.33 KB
/
hooks.py
File metadata and controls
219 lines (175 loc) · 6.33 KB
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#
# This is used to run hooks
#
from enum import Enum
import os, subprocess
from linuxmusterLinuxclient7 import logging, constants, user, config, computer, environment, setup, shares
class Type(Enum):
"""
Enum containing all hook types
"""
Boot = 0
"""The onBoot hook
"""
Shutdown = 1
"""The on Shutdown hook
"""
LoginAsRoot = 2
"""The onLoginAsRoot hook
"""
Login = 3
"""The onLogin hook
"""
SessionStarted = 4
"""The onSession started hook
"""
LogoutAsRoot = 5
LoginLogoutAsRoot = 6
remoteScriptNames = {
Type.Boot: "sysstart.sh",
Type.Login: "logon.sh",
Type.SessionStarted: "sessionstart.sh",
Type.Shutdown: "sysstop.sh"
}
_remoteScriptInUserContext = {
Type.Boot: False,
Type.Login: True,
Type.SessionStarted: True,
Type.Shutdown: False
}
def runLocalHook(hookType):
"""
Run all scripts in a local hookdir
:param hookType: The type of hook to run
:type hookType: hooks.Type
"""
hookDir = _getLocalHookDir(hookType)
logging.info(f"=== Running local hook on{hookType.name} in {hookDir} ===")
if os.path.exists(hookDir):
_prepareEnvironment()
for fileName in sorted(os.listdir(hookDir)):
filePath = hookDir + "/" + fileName
_runHookScript(filePath)
logging.info(f"===> Finished running local hook on{hookType.name} ===")
def runRemoteHook(hookType):
"""
Run hookscript from sysvol
:param hookType: The type of hook to run
:type hookType: hooks.Type
"""
logging.info(f"=== Running remote hook on{hookType.name} ===")
rc, hookScripts = _getRemoteHookScripts(hookType)
if rc:
_prepareEnvironment()
_runHookScript(hookScripts[0])
_runHookScript(hookScripts[1])
logging.info(f"===> Finished running remote hook on{hookType.name} ===")
def runHook(hookType):
"""
Executes hooks.runLocalHook() and hooks.runRemoteHook()
:param hookType: The type of hook to run
:type hookType: hooks.Type
"""
runLocalHook(hookType)
runRemoteHook(hookType)
def getLocalHookScript(hookType):
"""Get the path of a local hookscript
:param hookType: The type of hook script to get the path for
:type hookType: hooks.Type
:return: The path
:rtype: str
"""
return f"{constants.scriptDir}/on{hookType.name}"
def shouldHooksBeExecuted(overrideUsername=None):
"""Check if hooks should be executed
:param overrideUsername: Override the username to check, defaults to None
:type overrideUsername: str, optional
:return: True if hooks should be executed, fale otherwise
:rtype: bool
"""
# check if linuxmuster-linuxclient7 is setup
if not setup.isSetup():
logging.info("==== Linuxmuster-linuxclient7 is not setup, exiting ====")
return False
# check if the computer is joined
if not computer.isInAD():
logging.info("==== This Client is not joined to any domain, exiting ====")
return False
# Check if the user is an AD user
if overrideUsername == None:
overrideUsername = user.username()
if not user.isUserInAD(overrideUsername):
logging.info(f"==== {overrideUsername} is not an AD user, exiting ====")
return False
return True
# --------------------
# - Helper functions -
# --------------------
def _prepareEnvironment():
dictsAndPrefixes = {}
rc, networkConfig = config.network()
if rc:
dictsAndPrefixes["Network"] = networkConfig
rc, userConfig = user.readAttributes()
if rc:
dictsAndPrefixes["User"] = userConfig
rc, computerConfig = computer.readAttributes()
if rc:
dictsAndPrefixes["Computer"] = computerConfig
environment = _dictsToEnv(dictsAndPrefixes)
_writeEnvironment(environment)
def _getLocalHookDir(hookType):
return f"{constants.etcBaseDir}/on{hookType.name}.d"
def _getRemoteHookScripts(hookType):
if not hookType in remoteScriptNames:
return False, None
rc, networkConfig = config.network()
if not rc:
logging.error("Could not execute server hooks because the network config could not be read")
return False, None
if _remoteScriptInUserContext[hookType]:
rc, attributes = user.readAttributes()
if not rc:
logging.error("Could not execute server hooks because the user config could not be read")
return False, None
else:
rc, attributes = computer.readAttributes()
if not rc:
logging.error("Could not execute server hooks because the computer config could not be read")
return False, None
try:
domain = networkConfig["domain"]
school = attributes["sophomorixSchoolname"]
scriptName = remoteScriptNames[hookType]
except:
logging.error("Could not execute server hooks because the computer/user config is missing attributes")
return False, None
rc, sysvolPath = shares.getLocalSysvolPath()
if not rc:
logging.error("Could not execute server hook {} because the sysvol could not be mounted!\n")
return False, None
hookScriptPathTemplate = f"{sysvolPath}/{domain}/scripts/{school}/{{}}/linux/{scriptName}"
return True, [hookScriptPathTemplate.format("lmn"), hookScriptPathTemplate.format("custom")]
# parameter must be a dict of {"prefix": dict}
def _dictsToEnv(dictsAndPrefixes):
environmentDict = {}
for prefix in dictsAndPrefixes:
for key in dictsAndPrefixes[prefix]:
if type(dictsAndPrefixes[prefix][key]) is list:
environmentDict[prefix + "_" + key] = "\n".join(dictsAndPrefixes[prefix][key])
else:
environmentDict[prefix + "_" + key] = dictsAndPrefixes[prefix][key]
return environmentDict
def _runHookScript(filePath):
if not os.path.isfile(filePath):
logging.warning(f"* File {filePath} should be executed as hook but does not exist!")
return
if not os.access(filePath, os.X_OK):
logging.warning(f"* File {filePath} is in hook dir but not executable!")
return
logging.info(f"== Executing script {filePath} ==")
result = subprocess.call([filePath])
logging.info(f"==> Script {filePath} finished with exit code {result} ==")
def _writeEnvironment(environment):
for key in environment:
os.putenv(key, environment[key])