def might_work(sender, receiver): server = options.value("smtp_hostname", "localhost") port = options.value("smtp_port", 25) username = options.value("smtp_username", "") password = options.value("smtp_password", "") my_hostname = socket.getfqdn() test_commands = [('EHLO', my_hostname), ('MAIL FROM:', sender), ('RCPT TO:', receiver)] try: server = SMTP(server, int(port)) if username != "" and password != "": # The .login() function only accepts str, not unicode, so force it server.login(str(username), str(password)) for cmd, arg in test_commands: code, msg = server.docmd(cmd, arg) if code == 250: continue raise SendEmailError('SMTP: %s was not accepted: %s' % (cmd, msg)) # do not actually send something server.quit() except (SMTPException, socket.error) as e: raise SendEmailError('SMTP: %s' % (str(e), ))
def _getIsExternal(self): """Returns True if a user is configured with external authentication""" if options.value('enabled_external', 'no') != 'no': group = LDAPGroup(options.value('external_passwd'), options.value('external_user')) return self._name in group.members return False
def might_work(sender, receiver): server = options.value("smtp_hostname", "localhost") port = options.value("smtp_port", 25) username = options.value("smtp_username", "") password = options.value("smtp_password", "") my_hostname = socket.getfqdn() test_commands = [ ('EHLO', my_hostname), ('MAIL FROM:', sender), ('RCPT TO:', receiver) ] try: server = SMTP(server, int(port)) if username != "" and password != "": # The .login() function only accepts str, not unicode, so force it server.login(str(username), str(password)) for cmd, arg in test_commands: code, msg = server.docmd(cmd, arg) if code == 250: continue raise SendEmailError('SMTP: %s was not accepted: %s' % (cmd, msg)) # do not actually send something server.quit() except (SMTPException, socket.error) as e: raise SendEmailError('SMTP: %s' % (str(e), ))
def _connect(self, username, password): """Returns True if connection to the LDAP server using the given credentials is successful""" try: self._con = ldap.initialize(options.value('external_server', '')) self._con.simple_bind_s( '%s@%s' % (username, options.value('external_upn_suffix', '')), password) except ldap.INVALID_CREDENTIALS as e: self._con.unbind_s() self._con = None except ldap.LDAPError as e: self._con = None
def diagnostics(): results = {} results['enabled_git'] = 'git' in options.value('vcs_plugins', '') if not results['enabled_git']: results['enabled_git_label'] = 'disabled' results['git_all_label'] = 'disabled' return results try: git_dir = options.env_path('git_dir') except UnknownKeyError: results['git_dir_set'] = False results['git_hooks_all_new'] = True # because no repositories results['git_old_hook_repos'] = [] else: results['git_dir_set'] = True old_repos = list(old_hook_repos(git_dir)) results['git_hooks_all_new'] = len(old_repos) == 0 results['git_old_hook_repos'] = old_repos # check dirs for correct permissions bad_dirs = git_repos_wrong_perms(git_dir) results['git_repos_correct_perms'] = len(bad_dirs) == 0 results['git_repos_bad_dirs'] = bad_dirs try: git_ssh_host = options.value('git_ssh_host') except UnknownKeyError: results['git_hostname_ok'] = False else: results['git_hostname_ok'] = True if git_ssh_host in ('localhost', '127.0.0.1', '::1'): results['git_hostname_ok'] = False try: remote.execute("update-auth") except (remote.NonZeroExitStatus, UnknownKeyError) as e: results['git_admin_test'] = False results['git_admin_test_errmsg'] = str(e) results['git_ssh_host_internal'] = options.value( 'git_ssh_host_internal', 'git_ssh_host_internal') results['git_user'] = options.value('git_user', 'git_user') results['git_ssh_port'] = options.value('git_ssh_port', 'git_ssh_port') else: results['git_admin_test'] = True wrong_perms = git_dir_wrong_perms() results['git_dir_perms_wrong'] = wrong_perms results['git_dir_perms'] = len(wrong_perms) == 0 return add_labels(results, 'git_all', warnings, fails)
def diagnostics(): results = {} results["enabled_git"] = "git" in options.value("vcs_plugins", "") if not results["enabled_git"]: results["enabled_git_label"] = "disabled" results["git_all_label"] = "disabled" return results try: git_dir = options.env_path("git_dir") except UnknownKeyError: results["git_dir_set"] = False results["git_hooks_all_new"] = True # because no repositories results["git_old_hook_repos"] = [] else: results["git_dir_set"] = True old_repos = list(old_hook_repos(git_dir)) results["git_hooks_all_new"] = len(old_repos) == 0 results["git_old_hook_repos"] = old_repos # check dirs for correct permissions bad_dirs = git_repos_wrong_perms(git_dir) results["git_repos_correct_perms"] = len(bad_dirs) == 0 results["git_repos_bad_dirs"] = bad_dirs try: git_ssh_host = options.value("git_ssh_host") except UnknownKeyError: results["git_hostname_ok"] = False else: results["git_hostname_ok"] = True if git_ssh_host in ("localhost", "127.0.0.1", "::1"): results["git_hostname_ok"] = False try: remote.execute("update-auth") except (remote.NonZeroExitStatus, UnknownKeyError) as e: results["git_admin_test"] = False results["git_admin_test_errmsg"] = str(e) results["git_ssh_host_internal"] = options.value("git_ssh_host_internal", "git_ssh_host_internal") results["git_user"] = options.value("git_user", "git_user") results["git_ssh_port"] = options.value("git_ssh_port", "git_ssh_port") else: results["git_admin_test"] = True wrong_perms = git_dir_wrong_perms() results["git_dir_perms_wrong"] = wrong_perms results["git_dir_perms"] = len(wrong_perms) == 0 return add_labels(results, "git_all", warnings, fails)
def url(reposname): try: git_user = options.value("git_user") git_host = options.value("git_ssh_host") except UnknownKeyError as e: raise MissingConfig( 'Please make sure both git_user and git_ssh_host settings are set') git_port = options.value("git_ssh_port", "22") if git_port == "22": git_port = "" else: git_port = ":%s" % git_port return 'ssh://%s@%s%s/%s.git' % (git_user, git_host, git_port, reposname)
def execute(remote_command): ssh_key_path = options.env_path() + 'conf' + 'id_dsa' # The options provided with the -o flags are to prevent ssh trying to # create a '.ssh' directory in the homedir of the www user. cmd = 'ssh -i "%s" %s@%s -p %s -o "StrictHostKeyChecking=no"' cmd += ' -o "PreferredAuthentications=publickey"' cmd += ' -o "UserKnownHostsFile=/dev/null" %s' (exitstatus, outtext) = commands.getstatusoutput(cmd % (ssh_key_path, options.value("git_user"), options.value("git_ssh_host_internal"), options.value("git_ssh_port"), remote_command)) if exitstatus != 0: raise NonZeroExitStatus(outtext)
def execute(remote_command): ssh_key_path = options.env_path() + 'conf' + 'id_dsa' # The options provided with the -o flags are to prevent ssh trying to # create a '.ssh' directory in the homedir of the www user. cmd = 'ssh -i "%s" %s@%s -p %s -o "StrictHostKeyChecking=no"' cmd += ' -o "PreferredAuthentications=publickey"' cmd += ' -o "UserKnownHostsFile=/dev/null" %s' (exitstatus, outtext) = commands.getstatusoutput( cmd % (ssh_key_path, options.value("git_user"), options.value("git_ssh_host_internal"), options.value("git_ssh_port"), remote_command)) if exitstatus != 0: raise NonZeroExitStatus(outtext)
def external_sync(): """Synchronizes external users""" from submin.models import user errormsgs = [] if options.value('enabled_external', 'no') == 'no': errormsgs.append('external is not enabled') return {'errormsgs': errormsgs, 'success': False} group = LDAPGroup(options.value('external_passwd'), options.value('external_user')) if not group: errormsgs.append('cannot connect to LDAP server') return {'errormsgs': errormsgs, 'success': False} group_members = group.members if not group_members: errormsgs.append('cannot find LDAP group or its members') return {'errormsgs': errormsgs, 'success': False} user_list = user.list(user.FakeAdminUser()) for username in group_members: email = group_members[username]['email'] fullname = group_members[username]['fullname'] if not validate_username(username): errormsgs.append(InvalidUsername(username)) continue if not validate_email(email): errormsgs.append(InvalidEmail(email)) continue if not validate_fullname(fullname): errormsgs.append(InvalidFullname(fullname)) fullname = username if username not in user_list: # A new user user.add(username=username, email=email, send_mail=False) user.User(username).fullname = fullname else: u = user.User(username) # Update fullname and email if necessary if (u.email, u.fullname) != (email, fullname): u.email = email u.fullname = fullname return {'errormsgs': errormsgs, 'success': True}
def subcmd_fix(self, argv): from submin.models import options if os.getuid() != 0: print ''' To set permissions and ownerships properly, execute: sudo submin2-admin %s unixperms fix This should also remove possible following warnings. ''' % self.sa.env self.root = False vcs_plugins = options.value("vcs_plugins") # git should be owned by the git user, let 'git fix_perms' handle it if 'git' in vcs_plugins.split(','): git_dir = options.env_path('git_dir') self.ignore_dirs.append(git_dir) if len(argv) > 0: self._fix(argv[0]) else: self._fix('') if 'git' in vcs_plugins.split(','): self.sa.execute(['git', 'fix_perms'])
def diagnostics(): results = {} results['enabled_svn'] = 'svn' in options.value('vcs_plugins', '') if not results['enabled_svn']: results['enabled_svn_label'] = 'disabled' results['svn_all_label'] = 'disabled' return results try: svn_dir = options.env_path('svn_dir') except UnknownKeyError: results['svn_dir_set'] = False else: results['svn_dir_set'] = True found_mods = {} amods = [] required_mods = ['dav', 'dav_svn', 'authz_svn', 'authn_dbd', 'dbd'] try: amods = apache_modules() except ApacheCtlError as e: results['svn_apache_modules_ok'] = False results['svn_apache_modules_exec_ok'] = False results['svn_apache_modules_errmsg'] = str(e) else: results['svn_apache_modules_exec_ok'] = True for mod in required_mods: found_mods.update({mod: mod in amods}) results['svn_apache_modules'] = found_mods results['svn_apache_modules_ok'] = False not in found_mods.values() return add_labels(results, 'svn_all', warnings, fails)
def git_dir_wrong_perms(): submin_env = options.env_path() git_dir = options.env_path("git_dir") try: git_user = pwd.getpwnam(options.value("git_user")) except UnknownKeyError: return [] apache = www_user() wrong_permissions = [] checkdir = git_dir while checkdir != "/" and checkdir != submin_env: try: st = os.stat(checkdir) except OSError as e: if e.errno == errno.EACCES: wrong_permissions.append({"dir": checkdir, "reason": "unknown"}) else: if (st.st_uid != git_user.pw_uid or st.st_gid != apache.pw_gid or st.st_mode & 0o750 != 0o750) and ( st.st_mode & 0o005 != 0o005 ): wrong_permissions.append({"dir": checkdir, "reason": "incorrect"}) checkdir = os.path.dirname(checkdir) return wrong_permissions
def git_repos_wrong_perms(git_dir): bad_dirs = [] ssh_dir = git_dir + ".ssh" git_user = pwd.getpwnam(options.value("git_user")) apache = www_user() for root, dirs, files in os.walk(git_dir): for d in dirs: path = os.path.join(root, d) # skip .ssh dir if path == ssh_dir: continue st = os.stat(path) if stat.S_ISDIR(st.st_mode): user = pwd.getpwuid(st.st_uid) group = grp.getgrgid(st.st_gid) ingroup = group.gr_gid == apache.pw_gid or apache.pw_name in group.gr_mem if not ingroup or not st.st_mode & stat.S_ISGID or user.pw_name != git_user.pw_name: modestr = status.filemode(st.st_mode) relative = path[len(git_dir) + 1 :] bad_dirs.append({"name": relative, "mode": modestr, "user": user.pw_name, "group": group.gr_name}) return bad_dirs
def email_user(self, key=None, password=None, origin=None): """Email the user a key (to reset her password) OR a password (if the user followed a link with the key in it). The origin shows where the request came from (string)""" from submin.template.shortcuts import evaluate from submin.email import sendmail if key and password: raise ValueError('Ambiguous input: both key and password are set') templatevars = { 'from': options.value('smtp_from', 'root@localhost'), 'to': self.email, 'username': self.name, 'key': key, 'password': password, 'http_vhost': options.http_vhost(), 'base_url': options.url_path("base_url_submin"), 'origin': origin, } if key: template = 'email/prepare_reset.txt' else: template = 'email/reset_password.txt' message = evaluate(template, templatevars) sendmail(templatevars['from'], templatevars['to'], message)
def send(sender, receiver, message): server = options.value("smtp_hostname", "localhost") port = options.value("smtp_port", 25) username = options.value("smtp_username", "") password = options.value("smtp_password", "") try: server = SMTP(server, int(port)) if username != "" and password != "": # The .login() function only accepts str, not unicode, so force it server.login(str(username), str(password)) server.sendmail(sender, [receiver], message) server.quit() except (SMTPException, socket.error) as e: raise SendEmailError(str(e))
def generate_acl_list(): """A helper function for the decorator set a sane default, loopback IP's and the IP addresses that are used for the web server address. If this is not enough, the user should set the IP-address (see diagnostics). Since this might resolve, only use it when necessary. """ acls = ['127.0.0.1', '::1'] vhost = options.value('http_vhost', 'localhost') netloc = vhost.replace('https://', '').replace('http://', '').strip('/') m = re.search('\[([0-9a-fA-F:]+)\]', netloc) if not m: m = re.search('^([^:]+)', netloc) if not m: return set(acls) hostname = m.group(1) # get IPv4 and IPv6 addresses try: acls.extend([x[4][0] for x in socket.getaddrinfo(hostname, 0)]) except socket.gaierror as e: pass return set(acls)
def git_repos_wrong_perms(git_dir): bad_dirs = [] ssh_dir = git_dir + '.ssh' git_user = pwd.getpwnam(options.value('git_user')) apache = www_user() for root, dirs, files in os.walk(git_dir.encode('utf-8')): for d in dirs: path = os.path.join(root, d) # skip .ssh dir if path == ssh_dir: continue st = os.stat(path) if stat.S_ISDIR(st.st_mode): user = pwd.getpwuid(st.st_uid) group = grp.getgrgid(st.st_gid) ingroup = group.gr_gid == apache.pw_gid or \ apache.pw_name in group.gr_mem if not ingroup or not st.st_mode & stat.S_ISGID or \ user.pw_name != git_user.pw_name: modestr = status.filemode(st.st_mode) relative = path[len(git_dir) + 1:] bad_dirs.append({ 'name': relative, 'mode': modestr, 'user': user.pw_name, 'group': group.gr_name }) return bad_dirs
def git_dir_wrong_perms(): submin_env = options.env_path() git_dir = options.env_path("git_dir") try: git_user = pwd.getpwnam(options.value("git_user")) except UnknownKeyError: return [] apache = www_user() wrong_permissions = [] checkdir = git_dir while checkdir != '/' and checkdir != submin_env: try: st = os.stat(checkdir) except OSError as e: if e.errno == errno.EACCES: wrong_permissions.append({ 'dir': checkdir, 'reason': 'unknown' }) else: if (st.st_uid != git_user.pw_uid or st.st_gid != apache.pw_gid or st.st_mode & 0o750 != 0o750) and (st.st_mode & 0o005 != 0o005): wrong_permissions.append({ 'dir': checkdir, 'reason': 'incorrect' }) checkdir = os.path.dirname(checkdir) return wrong_permissions
def run(self): os.environ['SUBMIN_ENV'] = self.sa.env from submin.models import options if len(self.argv) < 1: self.sa.execute(['help', 'nginxconf']) return self.defaults = { 'output': options.env_path() + 'conf' + 'nginx.conf' } user = www_user() self.init_vars = { 'submin_env': self.canonicalize(str(self.sa.env)), 'www_dir': self.canonicalize(str(self.sa.basedir_www)), # Don't use options.url_path here, we need the url without # trailing slash. 'submin_base_url': self.urlpath(options.value('base_url_submin')), 'www_uid': user.pw_uid, 'www_gid': user.pw_gid, } self.init_vars['real_wsgi'] = os.path.realpath( os.path.join(self.init_vars['www_dir'], 'submin.wsgi')) try: subcmd = getattr(self, 'subcmd_%s' % self.argv[0]) except AttributeError: self.sa.execute(['help', 'nginxconf']) return subcmd(self.argv[1:])
def run(self): os.environ['SUBMIN_ENV'] = self.sa.env from submin.models import options if len(self.argv) < 1: self.sa.execute(['help', 'nginxconf']) return self.defaults = {'output': options.env_path() + 'conf' + 'nginx.conf'} user = www_user() self.init_vars = { 'submin_env': self.canonicalize(str(self.sa.env)), 'www_dir': self.canonicalize(str(self.sa.basedir_www)), # Don't use options.url_path here, we need the url without # trailing slash. 'submin_base_url': self.urlpath(options.value('base_url_submin')), 'www_uid': user.pw_uid, 'www_gid': user.pw_gid, } self.init_vars['real_wsgi'] = os.path.realpath( os.path.join(self.init_vars['www_dir'], 'submin.wsgi')) try: subcmd = getattr(self, 'subcmd_%s' % self.argv[0]) except AttributeError: self.sa.execute(['help', 'nginxconf']) return subcmd(self.argv[1:])
def subcmd_fix(self, argv): from submin.models import options if os.getuid() != 0: print(''' To set permissions and ownerships properly, execute: sudo submin2-admin %s unixperms fix This should also remove possible following warnings. ''' % self.sa.env) self.root = False vcs_plugins = options.value("vcs_plugins") # git should be owned by the git user, let 'git fix_perms' handle it if 'git' in vcs_plugins.split(','): git_dir = options.env_path('git_dir') self.ignore_dirs.append(git_dir) if len(argv) > 0: self._fix(argv[0]) else: self._fix('') if 'git' in vcs_plugins.split(','): self.sa.execute(['git', 'fix_perms'])
def run(): env_path = options.env_path() filename = os.path.expanduser("~/.ssh/authorized_keys") filename = options.value("git_dev_authorized_keysfile", filename) if not os.path.exists(os.path.dirname(filename)): try: # create dir and file if one of them doesn't exist os.mkdir(os.path.dirname(filename)) open(filename, 'a') except OSError as e: if e.errno != errno.EACCES: raise raise Exception( 'Could not write "%s", please check that git user can write it.' % filename) # Make the authorized_keys file only readable to the git-user gituser = options.value("git_user") owner = getpwnam(gituser) os.chown(os.path.dirname(filename), owner.pw_uid, owner.pw_gid) os.chmod(filename, 0o600) www_key_file = env_path + "conf" + "id_dsa.pub" if not www_key_file.exists(): raise Exception( "Could not find the submin ssh-key. Please run submin2-admin git init" ) key_fp = open(str(www_key_file)) www_key = key_fp.readline().strip() key_fp.close() # instead of writing ascii, write utf-8 encoding fp = codecs.open(str(filename), "a+", 'utf-8') env_vars = "PATH='%s' PYTHONPATH='%s'" % \ (options.value("env_path"), ':'.join(sys.path)) fp.write('command="%s submin2-admin \'%s\' git admin" %s\n' % \ (env_vars, env_path, www_key)) userlist = user.list(user.FakeAdminUser()) for x in userlist: u = user.User(x) ssh_keys = u.ssh_keys() if not ssh_keys: continue for ssh_key in ssh_keys: fp.write('command="%s submin2-admin \'%s\' git user %s" %s\n' % \ (env_vars, env_path, u, ssh_key["key"])) fp.close()
def check_password(self, password): """Return True if password is correct, can raise NoMD5PasswordError""" authenticated = False if options.value('enabled_external', 'no') != 'no': authenticated = check_membership(self._name, password) if not authenticated: authenticated = storage.check_password(self._id, password) return authenticated
def export_notifications(**kwargs): """Export a mailer.py config file For each user/repository pair, a config group is created. Only if a user has read or read/write permission to one or multiple paths in that repository, _and_ if the user has notifications enabled for that repository, _and_ if the user has a non-empty email-address. Multiple paths are grouped together by a regexp group (multiple|paths)""" bindir = options.static_path("hooks") + 'svn' # get a list of all users from submin.models import user users = [user.User(name) for name in user.list(user.FakeAdminUser())] groups = [] for u in users: if not u.email: continue u_notif = u.notifications() for repos in u_notif: repos_path = str(options.env_path("svn_dir") + repos) if not u_notif[repos]["enabled"]: continue # strip leading / paths = [ x[1:] for x in permissions.list_readable_user_paths(repos, "svn", u) ] if len(paths) == 0: continue elif len(paths) == 1: for_paths = paths[0] elif len(paths) > 0: for_paths = "(" + "|".join(paths) + ")" # Only match complete path, not partial paths (ticket #257) repos_path_re = '^' + repos_path + '$' g = { "repos_name": repos, "for_repos": repos_path_re, "email": u.email, "for_paths": for_paths, "username": u.name } groups.append(g) email = options.value( 'commit_email_from', 'Please configure commit_email_from <*****@*****.**>') templatevariables = {"groups": groups, 'from_addr': email} from submin.template.shortcuts import evaluate content = evaluate("plugins/vcs/svn/mailer.conf", templatevariables) filename = str((options.env_path() + 'conf') + 'mailer.py.conf') file(filename, 'w').writelines(content.encode('utf-8'))
def subcmd_fix_perms(self, args): from submin.models import options from pwd import getpwnam try: git_user = options.value("git_user") except UnknownKeyError as e: return False git_pw = getpwnam(git_user) self.chgrp_relevant_files(git_uid=git_pw.pw_uid, git_gid=git_pw.pw_gid)
def diagnostics(): results = {} results['enabled_external'] = options.value('enabled_external', 'no') != 'no' if not results['enabled_external']: results['enabled_external_label'] = 'disabled' results['external_all_label'] = 'disabled' return results found_mods = {} amods = [] required_mods = ['authnz_ldap', 'ldap'] try: amods = apache_modules() except ApacheCtlError as e: results['external_apache_modules_ok'] = False results['external_apache_modules_exec_ok'] = False results['external_apache_modules_errmsg'] = str(e) else: results['external_apache_modules_exec_ok'] = True for mod in required_mods: found_mods.update({mod: mod in amods}) results['external_apache_modules'] = found_mods results['external_apache_modules_ok'] = False not in found_mods.values() results['external_settings_ok'] = True results['external_settings'] = { 'external_server': [False, 'ldaps://example.net'], 'external_base_dn': [False, 'DC=example,DC=net'], 'external_group_dn': [False, 'CN=SVN,OU=SVN,DC=example,DC=net'], 'external_user': [False, 'user'], 'external_passwd': [False, 'secret'], 'external_upn_suffix': [False, 'example.net']} for setting in results['external_settings']: if not options.value(setting, ''): results['external_settings_ok'] = False else: results['external_settings'][setting][0] = True return add_labels(results, 'external_all', warnings, fails)
def add(name): reposdir = options.env_path('svn_dir') newrepos = reposdir + name path = options.value('env_path', "/bin:/usr/bin:/usr/local/bin:/opt/local/bin") cmd = "PATH='%s' svnadmin create '%s'" % (path, str(newrepos)) (exitstatus, outtext) = subprocess.getstatusoutput(cmd) if exitstatus != 0: raise PermissionError("External command 'svnadmin' failed: %s" % outtext) repos = Repository(name)
def run(): env_path = options.env_path() filename = os.path.expanduser("~/.ssh/authorized_keys") filename = options.value("git_dev_authorized_keysfile", filename) if not os.path.exists(os.path.dirname(filename)): try: # create dir and file if one of them doesn't exist os.mkdir(os.path.dirname(filename)) file(filename, 'a') except OSError as e: if e.errno != errno.EACCES: raise raise Exception('Could not write "%s", please check that git user can write it.' % filename) # Make the authorized_keys file only readable to the git-user gituser = options.value("git_user") owner = getpwnam(gituser) os.chown(os.path.dirname(filename), owner.pw_uid, owner.pw_gid) os.chmod(filename, 0o600) www_key_file = env_path + "conf" + "id_dsa.pub" if not www_key_file.exists(): raise Exception("Could not find the submin ssh-key. Please run submin2-admin git init") key_fp = open(str(www_key_file)) www_key = key_fp.readline().strip() key_fp.close() # instead of writing ascii, write utf-8 encoding fp = codecs.open(str(filename), "w+", 'utf-8') env_vars = "PATH='%s' PYTHONPATH='%s'" % \ (options.value("env_path"), ':'.join(sys.path)) fp.write('command="%s submin2-admin \'%s\' git admin" %s\n' % \ (env_vars, env_path, www_key)) userlist = user.list(user.FakeAdminUser()) for x in userlist: u = user.User(x) ssh_keys = u.ssh_keys() if not ssh_keys: continue for ssh_key in ssh_keys: fp.write('command="%s submin2-admin \'%s\' git user %s" %s\n' % \ (env_vars, env_path, u, ssh_key["key"])) fp.close()
def add(name): reposdir = options.env_path('svn_dir') newrepos = reposdir + name path = options.value('env_path', "/bin:/usr/bin:/usr/local/bin:/opt/local/bin") cmd = "PATH='%s' svnadmin create '%s'" % (path, str(newrepos)) (exitstatus, outtext) = commands.getstatusoutput(cmd) if exitstatus != 0: raise PermissionError("External command 'svnadmin' failed: %s" % outtext) repos = Repository(name)
def _get_members(self): """Returns members of the LDAP group""" if self._con: try: group = self._con.search_s( options.value('external_group_dn', ''), ldap.SCOPE_BASE)[0][1] self._find_member(group) except ldap.NO_SUCH_OBJECT as e: self._con.unbind_s() return self._members
def create(vcs_type, reposname, adminUser): from submin.models.repository import directory as repodir basedir = options.env_path('trac_dir') mkdirs(str(basedir)) tracenv = basedir + reposname projectname = reposname vcsdir = repodir(vcs_type, reposname) admin_command( tracenv, ['initenv', projectname, 'sqlite:db/trac.db', vcs_type, vcsdir]) admin_command(tracenv, ['permission', 'add', adminUser.name, "TRAC_ADMIN"]) components = [ 'tracopt.ticket.commit_updater.*', 'tracopt.versioncontrol.%s.*' % vcs_type ] for component in components: admin_command(tracenv, ['config', 'set', 'components', component, 'enabled']) admin_command(tracenv, ['config', 'set', 'header_logo', 'alt', 'Trac']) admin_command(tracenv, ['config', 'set', 'header_logo', 'height', '61']) admin_command(tracenv, [ 'config', 'set', 'header_logo', 'link', "%s/%s" % (options.value('base_url_trac'), reposname) ]) admin_command(tracenv, ['config', 'set', 'header_logo', 'src', 'trac_banner.png']) admin_command(tracenv, ['config', 'set', 'header_logo', 'width', '214']) admin_command( tracenv, ['config', 'set', 'project', 'descr', 'Repository %s' % reposname]) admin_command(tracenv, [ 'config', 'set', 'svn', 'authz_file', options.env_path('svn_authz_file') ]) admin_command(tracenv, ['config', 'set', 'svn', 'authz_module_name', reposname]) admin_command(tracenv, [ 'config', 'set', 'trac', 'authz_file', options.env_path('svn_authz_file') ]) permission_policies = admin_command( tracenv, ['config', 'get', 'trac', 'permission_policies']) admin_command(tracenv, [ 'config', 'set', 'trac', 'permission_policies', 'AuthzSourcePolicy,' + permission_policies ]) admin_command(tracenv, ['config', 'set', 'trac', 'repository_dir', vcsdir])
def admin_command(trac_dir, args): """trac_dir is the trac env dir, args is a list of arguments to trac-admin""" cmd = ['trac-admin', trac_dir] cmd.extend(args) path = options.value('env_path', "/bin:/usr/bin:/usr/local/bin:/opt/local/bin") env_copy = os.environ.copy() env_copy['PATH'] = path try: return check_output(cmd, stderr=subprocess.STDOUT, env=env_copy) except subprocess.CalledProcessError as e: raise TracAdminError(' '.join(cmd), e.returncode, e.output)
def run(reposname): reposdir = repository.directory('git', reposname) old_path = os.environ["PATH"] os.environ["PATH"] = options.value("env_path") cmd = 'rm -rf "%s"' % str(reposdir) (exitstatus, outtext) = commands.getstatusoutput(cmd) os.environ["PATH"] = old_path if exitstatus != 0: raise PermissionError( "External command '%s' failed: %s" % \ (cmd, outtext))
def which(program): from submin.models import options def is_exe(fpath): return os.path.exists(fpath) and os.access(fpath, os.X_OK) env_path = options.value("env_path") for path in env_path.split(os.pathsep): prog_path = os.path.join(path, program) if is_exe(prog_path) and os.path.isfile(prog_path): return prog_path raise ProgramNotFoundError(program, env_path)
def setCommitEmailHook(reponame, enable): prepare(reponame) reposdir = repository.directory('git', reponame) hook_dir = reposdir + 'hooks' + 'post-receive.d' mkdirs(hook_dir) hook_dest = hook_dir + '001-commit-email.hook' if enable: variables = { 'submin_lib_dir': options.lib_path(), 'base_url': options.url_path('base_url_submin'), 'http_vhost': options.http_vhost(), 'hook_version': HOOK_VERSIONS['commit-email'], } hook = evaluate('plugins/vcs/git/post-receive', variables) try: os.unlink(hook_dest) except OSError as e: if e.errno != errno.ENOENT: raise try: with file(hook_dest, 'w') as f: f.write(hook) os.chmod(hook_dest, 0o755) except OSError as e: raise repository.PermissionError("Enabling hook failed: %s" % (str(e), )) try: cfg = repository.directory('git', reponame) + 'config' email = options.value( 'commit_email_from', 'Please configure commit_email_from <*****@*****.**>') set_git_config(cfg, 'multimailhook.emailmaxlines', '2000') prefix = '[%s]' % reponame set_git_config(cfg, 'multimailhook.emailprefix', prefix) set_git_config(cfg, 'multimailhook.envelopesender', email) except SetGitConfigError as e: raise repository.PermissionError( "Enabling hook succeeded, but configuring it failed: %s" % (str(e))) else: try: os.unlink(hook_dest) except OSError as e: if e.errno != errno.ENOENT: raise repository.PermissionError("Removing hook failed: %s" % (str(e), ))
def diagnostics(): results = {} commit_email_from = options.value('commit_email_from', '') results['email_commit_set'] = commit_email_from != '' match = re.match('(.+) (<[^@>]+@[^@>]+\.[^@>]+>)', commit_email_from) results['email_commit_sane'] = match != None results['email_commit_current_value'] = commit_email_from smtp_from = options.value('smtp_from', '') results['email_from_set'] = smtp_from != '' match = re.match('(.+) (<[^@>]+@[^@>]+\.[^@>]+>)', smtp_from) results['email_from_sane'] = match != None results['email_from_current_value'] = smtp_from all_options = [x[0] for x in options.options()] sender = smtp_from if not results['email_from_set']: sender = 'root@localhost' sender = re.sub('.*<(.*)>.*', '\\1', sender) if 'smtp_hostname' in all_options: try: smtp.might_work(sender, '*****@*****.**') except SendEmailError as e: results['email_might_work_smtp_from'] = False results['email_might_work_smtp_from_msg'] = str(e) else: results['email_might_work_smtp_from'] = True else: try: local.might_work(sender, '*****@*****.**') except SendEmailError as e: results['email_might_work_smtp_from'] = False results['email_might_work_smtp_from_msg'] = str(e) else: results['email_might_work_smtp_from'] = True return add_labels(results, 'email_all', warnings, fails)
def enableTracCommitHook(self, enable): # only enable when trac env could be found, but always disable (whether trac # env could be found or not) (ticket #194, #269) if options.value('enabled_trac', 'no') == 'no': enable = False if enable: if not trac.exists(self.name): enable = False self.repository.enableTracCommitHook(enable) trigger_hook('repository-notifications-update', repositoryname=self.name, vcs_type=self.vcs_type)
def run(reponame): reposdir = repository.directory("git", reponame) old_path = os.environ["PATH"] os.environ["PATH"] = options.value("env_path") cmd = 'GIT_DIR="%s" git --bare init' % str(reposdir) (exitstatus, outtext) = commands.getstatusoutput(cmd) os.environ["PATH"] = old_path rewrite_hooks(reponame) post_receive_hook.rewrite_hooks(reponame) if exitstatus != 0: raise PermissionError("External command 'GIT_DIR=\"%s\" git --bare init' failed: %s" % (name, outtext))
def setCommitEmailHook(reponame, enable): prepare(reponame) reposdir = repository.directory('git', reponame) hook_dir = reposdir + 'hooks' + 'post-receive.d' mkdirs(hook_dir) hook_dest = hook_dir + '001-commit-email.hook' if enable: variables = { 'submin_lib_dir': options.lib_path(), 'base_url': options.url_path('base_url_submin'), 'http_vhost': options.http_vhost(), 'hook_version': HOOK_VERSIONS['commit-email'], } hook = evaluate('plugins/vcs/git/post-receive', variables) try: os.unlink(hook_dest) except OSError as e: if e.errno != errno.ENOENT: raise try: with file(hook_dest, 'w') as f: f.write(hook) os.chmod(hook_dest, 0o755) except OSError as e: raise repository.PermissionError( "Enabling hook failed: %s" % (str(e),)) try: cfg = repository.directory('git', reponame) + 'config' email = options.value('commit_email_from', 'Please configure commit_email_from <*****@*****.**>') set_git_config(cfg, 'multimailhook.emailmaxlines', '2000') prefix = '[%s]' % reponame set_git_config(cfg, 'multimailhook.emailprefix', prefix) set_git_config(cfg, 'multimailhook.envelopesender', email) except SetGitConfigError as e: raise repository.PermissionError( "Enabling hook succeeded, but configuring it failed: %s" % (str(e))) else: try: os.unlink(hook_dest) except OSError as e: if e.errno != errno.ENOENT: raise repository.PermissionError( "Removing hook failed: %s" % (str(e),))
def _decorator(fun): try: acls = options.value(acl_name) except UnknownKeyError as e: acls = generate_acl_list() else: acls = [x.strip() for x in acls.split(',')] def _wrapper(self, *args, **kwargs): address = self.request.remote_address if address not in acls: raise Unauthorized( "Your IP address [%s] does not have access" % address) return fun(self, *args, **kwargs) return _wrapper
def export_notifications(**kwargs): """Export a mailer.py config file For each user/repository pair, a config group is created. Only if a user has read or read/write permission to one or multiple paths in that repository, _and_ if the user has notifications enabled for that repository, _and_ if the user has a non-empty email-address. Multiple paths are grouped together by a regexp group (multiple|paths)""" bindir = options.static_path("hooks") + 'svn' # get a list of all users from submin.models import user users = [user.User(name) for name in user.list(user.FakeAdminUser())] groups = [] for u in users: if not u.email: continue u_notif = u.notifications() for repos in u_notif: repos_path = str(options.env_path("svn_dir") + repos) if not u_notif[repos]["enabled"]: continue # strip leading / paths = [x[1:] for x in permissions.list_readable_user_paths(repos, "svn", u)] if len(paths) == 0: continue elif len(paths) == 1: for_paths = paths[0] elif len(paths) > 0: for_paths = "(" + "|".join(paths) + ")" # Only match complete path, not partial paths (ticket #257) repos_path_re = '^' + repos_path + '$' g = {"repos_name": repos, "for_repos": repos_path_re, "email": u.email, "for_paths": for_paths, "username": u.name} groups.append(g) email = options.value('commit_email_from', 'Please configure commit_email_from <*****@*****.**>') templatevariables = {"groups": groups, 'from_addr': email} from submin.template.shortcuts import evaluate content = evaluate("plugins/vcs/svn/mailer.conf", templatevariables) filename = str((options.env_path() + 'conf') + 'mailer.py.conf') file(filename, 'w').writelines(content.encode('utf-8'))
def __init__(self, filename=None): if filename is None: filename = options.value("tests_scenarios_file") self.filename = filename # Don't randomly change this order! Code below uses indexes to refer # to these browsers and does not rebuild those indexes when getting # data from pickled-file. self.browsers = ["Safari 3", "Firefox 2", "Firefox 3", "IE 7", "Opera 9"] self.sections = [] # Should we get the sections from .txt file or pickled (".saved") file? if newer(self.filename, self.filename + ".saved"): self._parse() else: self.sections = self.load_state()
def run(reponame): reposdir = repository.directory('git', reponame) old_path = os.environ["PATH"] os.environ["PATH"] = options.value("env_path") cmd = 'GIT_DIR="%s" git --bare init' % str(reposdir) (exitstatus, outtext) = commands.getstatusoutput(cmd) os.environ["PATH"] = old_path rewrite_hooks(reponame) post_receive_hook.rewrite_hooks(reponame) if exitstatus != 0: raise PermissionError( "External command 'GIT_DIR=\"%s\" git --bare init' failed: %s" % \ (name, outtext))
def trigger_hook(event, **args): #log(event, **args) # call our own hooks # first compose a list of all hooks from submin.hooks import system_hooks hooks = system_hooks.hooks.copy() for vcs_plugin in options.value('vcs_plugins').split(','): plugin_hooks = _get_vcs_plugin_hooks(vcs_plugin) for key in plugin_hooks: hooks[key] = hooks.get(key, []) + plugin_hooks[key] # Then execute all hooks if event in hooks: for hook_fn in hooks[event]: hook_fn(**args) trigger_user_hook(event, **args)
def subcmd_get(self, argv): from submin.models import options self.sa.ensure_storage() if len(argv) == 1: try: value = options.value(argv[0]) except UnknownKeyError as e: print 'ERROR: %s does not exist' % argv[0] else: self._printkeyvalue(argv[0], value, len(argv[0])) else: all_options = sorted(options.options()) maxlen = 0 for arg in all_options: if len(arg[0]) > maxlen: maxlen = len(arg[0]) for arg in all_options: self._printkeyvalue(arg[0], arg[1], maxlen)
def __init__(self, url, request, store_url=True): Response.__init__(self, status_message="The princess is in another castle") if not request.is_ajax() and store_url: request.session["redirected_from"] = request.url if not store_url and "redirected_from" in request.session: del request.session["redirected_from"] url = unicode(url) self.status_code = 302 if "://" not in url: vhost = options.value("http_vhost") if "://" not in vhost: vhost = "http://" + vhost # to prevent accidental double slashes to be interpreted as netloc, # we strip all leading slashes from the url url = urlparse.urljoin(vhost, url.lstrip("/")) self.headers.update({"Location": url.encode("utf-8")})
def show(self, req, vcs_type, path, templatevars): import os.path u = user.User(req.session['user']['name']) try: repos = Repository(path[0], vcs_type) # Lie if user has no permission to read if not u.is_admin and not repository.userHasReadPermissions(u.name, path[0], vcs_type): raise DoesNotExistError except DoesNotExistError: return ErrorResponse('This repository does not exist.', request=req) trac_enabled = options.value('enabled_trac', 'no') != 'no' if trac_enabled: templatevars['trac_config_ok'] = True templatevars['trac_exists'] = False try: if trac.exists(path[0]): templatevars['trac_exists'] = True except MissingConfig as e: templatevars['trac_config_ok'] = False templatevars['trac_msg'] = \ 'There is something missing in your config: %s' % str(e) trac_base_url = options.url_path('base_url_trac') trac_http_url = str(trac_base_url + repos.name) templatevars['trac_http_url'] = trac_http_url try: vcs_url = repos.url() except MissingConfig as e: vcs_url = "" templatevars['vcs_url_error'] = str(e) templatevars['vcs_url'] = vcs_url templatevars['repository'] = repos templatevars['vcs_type'] = vcs_type formatted = evaluate_main('repositories.html', templatevars, request=req) return Response(formatted)
def show(self, req, path, localvars): if len(path) < 1: return ErrorResponse('Invalid path', request=req) is_admin = req.session['user']['is_admin'] if not is_admin and path[0] != req.session['user']['name']: raise Unauthorized('Permission denied to view this user') try: u = user.User(path[0]) except (IndexError, UnknownUserError): return ErrorResponse('This user does not exist.', request=req) localvars['user'] = u if 'change_password_hint' in req.session: localvars['change_password_hint'] = True localvars['enabled_git'] = 'git' in options.value('vcs_plugins', '') formatted = evaluate_main('users.html', localvars, request=req) return Response(formatted)