1
0

convertusers 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #!/usr/bin/env python
  2. import argparse
  3. import json
  4. import sys
  5. import time
  6. try:
  7. import pwd
  8. import spwd
  9. except ImportError:
  10. pwd = None
  11. class ConvertUsers:
  12. def __init__(self, input_file, users_format, output_file, min_uid, max_uid, usernames, force_uid, force_gid):
  13. self.input_file = input_file
  14. self.users_format = users_format
  15. self.output_file = output_file
  16. self.min_uid = min_uid
  17. self.max_uid = max_uid
  18. self.usernames = usernames
  19. self.force_uid = force_uid
  20. self.force_gid = force_gid
  21. self.SFTPGoUsers = []
  22. def buildUserObject(self, username, password, home_dir, uid, gid, max_sessions, quota_size, quota_files, upload_bandwidth,
  23. download_bandwidth, status, expiration_date, allowed_ip=[], denied_ip=[]):
  24. return {'id':0, 'username':username, 'password':password, 'home_dir':home_dir, 'uid':uid, 'gid':gid,
  25. 'max_sessions':max_sessions, 'quota_size':quota_size, 'quota_files':quota_files, 'permissions':{'/':["*"]},
  26. 'upload_bandwidth':upload_bandwidth, 'download_bandwidth':download_bandwidth,
  27. 'status':status, 'expiration_date':expiration_date,
  28. 'filters':{'allowed_ip':allowed_ip, 'denied_ip':denied_ip}}
  29. def addUser(self, user):
  30. user['id'] = len(self.SFTPGoUsers) + 1
  31. print('')
  32. print('New user imported: {}'.format(user))
  33. print('')
  34. self.SFTPGoUsers.append(user)
  35. def saveUsers(self):
  36. if self.SFTPGoUsers:
  37. data = {'users':self.SFTPGoUsers}
  38. jsonData = json.dumps(data)
  39. with open(self.output_file, 'w') as f:
  40. f.write(jsonData)
  41. print()
  42. print('Number of users saved to "{}": {}. You can import them using loaddata'.format(self.output_file,
  43. len(self.SFTPGoUsers)))
  44. print()
  45. sys.exit(0)
  46. else:
  47. print('No user imported')
  48. sys.exit(1)
  49. def convert(self):
  50. if self.users_format == 'unix-passwd':
  51. self.convertFromUnixPasswd()
  52. elif self.users_format == 'pure-ftpd':
  53. self.convertFromPureFTPD()
  54. else:
  55. self.convertFromProFTPD()
  56. self.saveUsers()
  57. def isUserValid(self, username, uid):
  58. if self.usernames and not username in self.usernames:
  59. return False
  60. if self.min_uid >= 0 and uid < self.min_uid:
  61. return False
  62. if self.max_uid >= 0 and uid > self.max_uid:
  63. return False
  64. return True
  65. def convertFromUnixPasswd(self):
  66. days_from_epoch_time = time.time() / 86400
  67. for user in pwd.getpwall():
  68. username = user.pw_name
  69. password = user.pw_passwd
  70. uid = user.pw_uid
  71. gid = user.pw_gid
  72. home_dir = user.pw_dir
  73. status = 1
  74. expiration_date = 0
  75. if not self.isUserValid(username, uid):
  76. continue
  77. if self.force_uid >= 0:
  78. uid = self.force_uid
  79. if self.force_gid >= 0:
  80. gid = self.force_gid
  81. # FIXME: if the passwords aren't in /etc/shadow they are probably DES encrypted and we don't support them
  82. if password == 'x' or password == '*':
  83. user_info = spwd.getspnam(username)
  84. password = user_info.sp_pwdp
  85. if not password or password == '!!' or password == '!*':
  86. print('cannot import user "{}" without a password'.format(username))
  87. continue
  88. if user_info.sp_inact > 0:
  89. last_pwd_change_diff = days_from_epoch_time - user_info.sp_lstchg
  90. if last_pwd_change_diff > user_info.sp_inact:
  91. status = 0
  92. if user_info.sp_expire > 0:
  93. expiration_date = user_info.sp_expire * 86400
  94. self.addUser(self.buildUserObject(username, password, home_dir, uid, gid, 0, 0, 0, 0, 0, status,
  95. expiration_date))
  96. def convertFromProFTPD(self):
  97. with open(self.input_file, 'r') as f:
  98. for line in f:
  99. fields = line.split(':')
  100. if len(fields) > 6:
  101. username = fields[0]
  102. password = fields[1]
  103. uid = int(fields[2])
  104. gid = int(fields[3])
  105. home_dir = fields[5]
  106. if not self.isUserValid(username, uid):
  107. continue
  108. if self.force_uid >= 0:
  109. uid = self.force_uid
  110. if self.force_gid >= 0:
  111. gid = self.force_gid
  112. self.addUser(self.buildUserObject(username, password, home_dir, uid, gid, 0, 0, 0, 0, 0, 1, 0))
  113. def convertPureFTPDIP(self, fields):
  114. result = []
  115. if not fields:
  116. return result
  117. for v in fields.split(','):
  118. ip_mask = v.strip()
  119. if not ip_mask:
  120. continue
  121. if ip_mask.count('.') < 3 and ip_mask.count(':') < 3:
  122. print('cannot import pure-ftpd IP: {}'.format(ip_mask))
  123. continue
  124. if '/' not in ip_mask:
  125. ip_mask += '/32'
  126. result.append(ip_mask)
  127. return result
  128. def convertFromPureFTPD(self):
  129. with open(self.input_file, 'r') as f:
  130. for line in f:
  131. fields = line.split(':')
  132. if len(fields) > 16:
  133. username = fields[0]
  134. password = fields[1]
  135. uid = int(fields[2])
  136. gid = int(fields[3])
  137. home_dir = fields[5]
  138. upload_bandwidth = 0
  139. if fields[6]:
  140. upload_bandwidth = int(int(fields[6]) / 1024)
  141. download_bandwidth = 0
  142. if fields[7]:
  143. download_bandwidth = int(int(fields[7]) / 1024)
  144. max_sessions = 0
  145. if fields[10]:
  146. max_sessions = int(fields[10])
  147. quota_files = 0
  148. if fields[11]:
  149. quota_files = int(fields[11])
  150. quota_size = 0
  151. if fields[12]:
  152. quota_size = int(fields[12])
  153. allowed_ip = self.convertPureFTPDIP(fields[15])
  154. denied_ip = self.convertPureFTPDIP(fields[16])
  155. if not self.isUserValid(username, uid):
  156. continue
  157. if self.force_uid >= 0:
  158. uid = self.force_uid
  159. if self.force_gid >= 0:
  160. gid = self.force_gid
  161. self.addUser(self.buildUserObject(username, password, home_dir, uid, gid, max_sessions, quota_size,
  162. quota_files, upload_bandwidth, download_bandwidth, 1, 0, allowed_ip,
  163. denied_ip))
  164. if __name__ == '__main__':
  165. parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, description=
  166. 'Convert users to a JSON format suitable to use with loadddata')
  167. supportedUsersFormats = []
  168. help_text = ''
  169. if pwd is not None:
  170. supportedUsersFormats.append('unix-passwd')
  171. help_text = 'To import from unix-passwd format you need the permission to read /etc/shadow that is typically granted to the root user only'
  172. supportedUsersFormats.append('pure-ftpd')
  173. supportedUsersFormats.append('proftpd')
  174. parser.add_argument('input_file', type=str)
  175. parser.add_argument('users_format', type=str, choices=supportedUsersFormats, help=help_text)
  176. parser.add_argument('output_file', type=str)
  177. parser.add_argument('--min-uid', type=int, default=-1, help='if >= 0 only import users with UID greater or equal ' +
  178. 'to this value. Default: %(default)s')
  179. parser.add_argument('--max-uid', type=int, default=-1, help='if >= 0 only import users with UID lesser or equal ' +
  180. 'to this value. Default: %(default)s')
  181. parser.add_argument('--usernames', type=str, nargs='+', default=[], help='Only import users with these usernames. ' +
  182. 'Default: %(default)s')
  183. parser.add_argument('--force-uid', type=int, default=-1, help='if >= 0 the imported users will have this UID in ' +
  184. 'SFTPGo. Default: %(default)s')
  185. parser.add_argument('--force-gid', type=int, default=-1, help='if >= 0 the imported users will have this GID in ' +
  186. 'SFTPGo. Default: %(default)s')
  187. args = parser.parse_args()
  188. convertUsers = ConvertUsers(args.input_file, args.users_format, args.output_file, args.min_uid, args.max_uid,
  189. args.usernames, args.force_uid, args.force_gid)
  190. convertUsers.convert()