Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

#! /usr/bin/env python 

""" 

rca-sh - Remote Control Access Shell. 

 

Copyright (C) 2017-2018 Mathias Stelzer 

 

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 3 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, see <http://www.gnu.org/licenses/>. 

""" 

from __future__ import absolute_import, print_function, unicode_literals 

import argparse 

import getpass 

import re 

import subprocess 

import sys 

import syslog 

 

try: 

import configparser 

except ImportError: 

import ConfigParser as configparser # py2 

 

CONFIG_PATH = '/etc/rca-sh.ini' 

 

 

def check(users, command, user=None): 

""" 

Check whether the user is allowed to run the command. 

 

:param users: User configuration 

:param command: The command the user is trying to run. 

:param user: The user who is trying to run the command. If not given, 

the current user will be used. 

""" 

if user is None: 

user = getpass.getuser() 

 

syslog.syslog(syslog.LOG_INFO, 'Checking whether "{}" is allowed to run: {}'.format(user, command)) 

 

try: 

allowed_commands = users[user] 

except KeyError: 

syslog.syslog(syslog.LOG_INFO, 'User "{}" is not configured.'.format(user)) 

return False 

 

for allowed_command in allowed_commands: 

 

if allowed_command.startswith('/') and allowed_command.endswith('/'): 

pattern = allowed_command[1:-1] # remove slashes 

 

if re.match(pattern, command) is not None: 

syslog.syslog(syslog.LOG_DEBUG, 'regex match: ' + pattern) 

return True 

syslog.syslog(syslog.LOG_DEBUG, 'regex ignore: ' + pattern) 

continue 

 

if allowed_command == command: 

syslog.syslog(syslog.LOG_DEBUG, 'match: ' + allowed_command) 

return True 

 

syslog.syslog(syslog.LOG_DEBUG, 'ignore: ' + allowed_command) 

 

syslog.syslog(syslog.LOG_ERR, '"{}" is not allowed to run: {}'.format(user, command)) 

return False 

 

 

def configure(): 

"""Configure the app and return the config.""" 

config = configparser.ConfigParser() 

config.read(CONFIG_PATH) 

 

_facility = config.get('config', 'log facility') 

facility = getattr(syslog, 'LOG_{}'.format(_facility.upper())) 

 

debug = config.getboolean('config', 'debug') 

 

if debug: 

syslog.setlogmask(syslog.LOG_UPTO(syslog.LOG_DEBUG)) 

else: 

syslog.setlogmask(syslog.LOG_UPTO(syslog.LOG_ERR)) 

 

syslog.closelog() 

syslog.openlog('rca-sh', syslog.LOG_PID, facility) 

 

user_commands = {} 

for user in config.options('commands'): 

value = config.get('commands', user) 

lines = value.splitlines() 

user_commands[user] = [l for l in lines if l] 

return user_commands 

 

 

def get_argument_parser(): 

"""Build and return the commandline parser.""" 

parser = argparse.ArgumentParser() 

parser.add_argument('-c', '--command') 

parser.add_argument('-u', '--user', help="Test this user") 

return parser 

 

 

def main(args=None): 

""" 

Main entry point. 

 

Parse arguments, read the config, run the given command if allowed and exit. 

""" 

if args is None: # nocov 

args = sys.argv[1:] 

 

args = get_argument_parser().parse_args(args) 

 

users = configure() 

 

if not users: 

syslog.syslog(syslog.LOG_ERR, 'No users configured.') 

sys.exit(1) 

 

if args.command is None: 

syslog.syslog(syslog.LOG_ERR, 'No command to execute.') 

sys.exit(1) 

 

if not check(users, args.command, user=args.user): 

sys.exit(1) 

 

if args.user: 

# test, don't run the command 

sys.exit(0) 

 

subprocess.call(args.command, shell=True) 

sys.exit(0) 

 

 

if __name__ == '__main__': 

main()