This file is indexed.

/var/lib/gnumed/server/pycommon/gmHooks.py is in gnumed-server 16.17-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
"""GNUmed hooks framework.

This module provides convenience functions and definitions
for accessing the GNUmed hooks framework.

This framework calls the script

	~/.gnumed/scripts/hook_script.py

at various times during client execution. The script must
contain a function

def run_script(hook=None):
	pass

which accepts a single argument <hook>. That argument will
contain the hook that is being activated.
"""
# ========================================================================
__version__ = "$Revision: 1.18 $"
__author__  = "K. Hilbert <Karsten.Hilbert@gmx.net>"
__license__ = "GPL v2 or later (details at http://www.gnu.org)"


# stdlib
import os, sys, stat, logging

_log = logging.getLogger('gm.hook')
_log.info(__version__)


# GNUmed libs
if __name__ == '__main__':
	sys.path.insert(0, '../../')
from Gnumed.pycommon import gmDispatcher, gmTools

# ========================================================================
known_hooks = [
	u'post_patient_activation',
	u'post_person_creation',

	u'shutdown-post-GUI',
	u'startup-after-GUI-init',
	u'startup-before-GUI',

	u'request_user_attention',
	u'app_activated_startup',
	u'app_activated',
	u'app_deactivated',

	u'after_substance_intake_modified',
	u'after_test_result_modified',
	u'after_soap_modified',
	u'after_code_link_modified',

	u'after_new_doc_created',
	u'before_print_doc',
	u'before_fax_doc',
	u'before_mail_doc',
	u'before_print_doc_part',
	u'before_fax_doc_part',
	u'before_mail_doc_part',
	u'before_external_doc_access',

	u'db_maintenance_warning'
]

_log.debug('known hooks:')
for hook in known_hooks:
	_log.debug(hook)

# ========================================================================
hook_module = None

def import_hook_module(reimport=False):

	global hook_module
	if not reimport:
		if hook_module is not None:
			return True

	# hardcoding path and script name allows us to
	# not need configuration for it, the environment
	# can always be detected at runtime (workplace etc)
	script_name = 'hook_script.py'
	script_path = os.path.expanduser(os.path.join('~', '.gnumed', 'scripts'))
	full_script = os.path.join(script_path, script_name)

	if not os.access(full_script, os.F_OK):
		_log.warning('creating default hook script')
		f = open(full_script, 'w')
		f.write("""
# known hooks:
#  %s

def run_script(hook=None):
	pass
""" % '#  '.join(known_hooks))
		f.close()
		os.chmod(full_script, 384)

	if os.path.islink(full_script):
		gmDispatcher.send (
			signal = 'statustext',
			msg = _('Script must not be a link: [%s].') % full_script
		)
		return False

	if not os.access(full_script, os.R_OK):
		gmDispatcher.send (
			signal = 'statustext',
			msg = _('Script must be readable by the calling user: [%s].') % full_script
		)
		return False

	script_stat_val = os.stat(full_script)
	_log.debug('hook script stat(): %s', script_stat_val)
	script_perms = stat.S_IMODE(script_stat_val.st_mode)
	_log.debug('hook script mode: %s (oktal: %s)', script_perms, oct(script_perms))
	if script_perms != 384:				# octal 0600
		if os.name in ['nt']:
			_log.warning('this platform does not support os.stat() file permission checking')
		else:
			gmDispatcher.send (
				signal = 'statustext',
				msg = _('Script must be readable by the calling user only (permissions "0600"): [%s].') % full_script
			)
			return False

	try:
		tmp = gmTools.import_module_from_directory(script_path, script_name)
	except StandardError:
		_log.exception('cannot import hook script')
		return False

	hook_module = tmp
#	if reimport:
#		reload(tmp)			# this has well-known shortcomings !

	_log.info('hook script: %s', full_script)
	return True
# ========================================================================
def run_hook_script(hook=None):
	# NOTE: this just *might* be a huge security hole

	if hook not in known_hooks:
		raise ValueError('run_hook_script(): unknown hook [%s]' % hook)

	if not import_hook_module(reimport = False):
		return False

	try:
		hook_module.run_script(hook = hook)
	except StandardError:
		_log.exception('error running hook script for [%s]', hook)
		gmDispatcher.send (
			signal = u'statustext',
			msg = _('Error running hook [%s] script.') % hook,
			beep = True
		)
		return False

	return True
# ========================================================================
if __name__ == '__main__':

	run_hook_script(hook = 'shutdown-post-GUI')
	run_hook_script(hook = 'invalid hook')

# ========================================================================