client.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. ###############################################################################
  2. # #
  3. # L3q - Light, light, lightweight queue #
  4. # Copyright (C) 2023 Marcus Pedersén marcus.pedersen@slu.se #
  5. # #
  6. # This program is free software: you can redistribute it and/or modify #
  7. # it under the terms of the GNU General Public License as published by #
  8. # the Free Software Foundation, either version 3 of the License, or #
  9. # (at your option) any later version. #
  10. # #
  11. # This program is distributed in the hope that it will be useful, #
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of #
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  14. # GNU General Public License for more details. #
  15. # #
  16. # You should have received a copy of the GNU General Public License #
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>. #
  18. # #
  19. ###############################################################################
  20. import sys
  21. import os
  22. import grp
  23. import configparser
  24. '''
  25. This module contains common classes
  26. and functions for all L3q client programs.
  27. '''
  28. CONF_FILE = '/etc/l3q/l3q.conf'
  29. class L3QConfig:
  30. '''
  31. Contains the needed configuration
  32. for the L3Queue clients.
  33. On failure program will terminate.
  34. Variables:
  35. validate_mode
  36. validate_uid
  37. are required permission and owner
  38. for validate file.
  39. '''
  40. validate_mode = 0o100440
  41. validate_uid = 0
  42. def __init__(self, parse_validate:bool=True) -> None:
  43. '''
  44. Init will read config file:
  45. /etc/l3q/l3q.conf
  46. If values are missing default
  47. values will be used.
  48. Validate file will also be checked
  49. and read.
  50. If any error occures error will be
  51. printed and program will terminate
  52. with non zero exit code.
  53. '''
  54. self.set_defaults()
  55. self.get_config()
  56. # After config is parsed and before
  57. # validation file is read,
  58. # check if user is part of group self.group
  59. # or is root
  60. member_of_group = False
  61. for gid in os.getgroups():
  62. gname = grp.getgrgid(gid)
  63. if(gname.gr_name == self.group or gid == 0):
  64. member_of_group = True
  65. if(not member_of_group):
  66. print('Permission denied.', file=sys.stderr)
  67. exit(1)
  68. if(parse_validate):
  69. self.get_validate()
  70. def set_defaults(self) -> None:
  71. '''
  72. Sets the default config values
  73. '''
  74. self.l3qd_host:str = ''
  75. self.l3qd_port:int = 39911
  76. self.group:str = 'l3q'
  77. self.validate_file:str = '/etc/l3q/network.l3q'
  78. self.log_file:str = '/var/log/l3q/l3q-client.log'
  79. self.validate_key:str = ''
  80. def get_config(self) -> None:
  81. '''
  82. Reads config file and populates
  83. object with values read from file.
  84. '''
  85. conf = configparser.ConfigParser()
  86. conf.read(CONF_FILE)
  87. if(not conf.has_section('l3q_daemon')):
  88. print('Error reading config file:', file=sys.stderr)
  89. print(CONF_FILE, file=sys.stderr)
  90. print('Check configuration of client tools', file=sys.stderr)
  91. sys.exit(1)
  92. if(not conf.has_option('l3q_daemon', 'l3qd_host')):
  93. print('Required parameter \'l3qd_host\' is missing in config file:', file=sys.stderr)
  94. print(CONF_FILE, file=sys.stderr)
  95. print('Check configuration of client tools', file=sys.stderr)
  96. sys.exit(2)
  97. self.l3qd_host = conf['l3q_daemon']['l3qd_host']
  98. if(conf.has_option('l3q_daemon', 'l3qd_port')):
  99. if(not conf['l3q_daemon']['l3qd_port'].isdigit()):
  100. print('Parse error in config file:', file=sys.stderr)
  101. print(CONF_FILE, file=sys.stderr)
  102. print('Parameter l3qd_port must be an integer', file=sys.stderr)
  103. sys.exit(3)
  104. else:
  105. self.l3qd_port = int(conf['l3q_daemon']['l3qd_port'])
  106. if(conf.has_option('l3q_client', 'validate_file')):
  107. self.validate_file = conf['l3q_client']['validate_file']
  108. if(conf.has_option('l3q_client', 'log_file')):
  109. self.log_file = conf['l3q_client']['log_file']
  110. if(conf.has_option('l3q_client', 'group')):
  111. self.group = conf['l3q_client']['group']
  112. def get_validate(self) -> None:
  113. '''
  114. Checks permissions and owner of
  115. the validation file, terminates
  116. program on failure.
  117. Puts validation sting in this object.
  118. First line of validation file is read
  119. so first line must contain validation key.
  120. File must only contain validate key.
  121. '''
  122. if(not os.path.exists(self.validate_file)):
  123. print('Validate file: {}'.format(self.validate_file), file=sys.stderr)
  124. print('Does not exist', file=sys.stderr)
  125. print('Configure verification with L3q daemon', file=sys.stderr)
  126. sys.exit(4)
  127. stat = os.stat(self.validate_file)
  128. if(int(stat.st_size) == 0):
  129. print('Validate file: {}'.format(self.validate_file), file=sys.stderr)
  130. print('Have zero size', file=sys.stderr)
  131. print('Configure verification with L3q daemon', file=sys.stderr)
  132. sys.exit(5)
  133. if(int(stat.st_mode) != L3QConfig.validate_mode):
  134. print('Validate file: {}'.format(self.validate_file), file=sys.stderr)
  135. print('has wrong file permissions', file=sys.stderr)
  136. print('Required mode is: {}'.format(oct(L3QConfig.validate_mode - 0o100000)[2:]), file=sys.stderr)
  137. sys.exit(6)
  138. if(int(stat.st_uid) != L3QConfig.validate_uid):
  139. print('Validate file: {}'.format(self.validate_file), file=sys.stderr)
  140. print('has wrong file owner', file=sys.stderr)
  141. print('Required owner is: root', file=sys.stderr)
  142. sys.exit(7)
  143. if(grp.getgrgid(stat.st_gid)[0] != self.group):
  144. print('Validate file: {}'.format(self.validate_file), file=sys.stderr)
  145. print('has wrong file group', file=sys.stderr)
  146. print('Required group is: {}'.format(self.group), file=sys.stderr)
  147. sys.exit(8)
  148. try:
  149. with open(self.validate_file) as f:
  150. self.validate_key = f.readline().strip()
  151. except Exception as e:
  152. print('Validate file: {}'.format(self.validate_file), file=sys.stderr)
  153. print('Error reading file', file=sys.stderr)
  154. print('{}'.format(e), file=sys.stderr)
  155. sys.exit(9)