Skip to content

Commit b06360d

Browse files
committed
Teach mbash to route SSH connections to the user's default pool
1 parent dd28bbf commit b06360d

File tree

1 file changed

+97
-2
lines changed

1 file changed

+97
-2
lines changed
Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,98 @@
1-
#!/bin/sh
1+
#!/usr/bin/env python
22

3-
exec @bash_path@ --rcfile /usr/local/etc/mbashrc "$@"
3+
from __future__ import (absolute_import, division, print_function)
4+
5+
import os
6+
import sys
7+
import getpass
8+
import subprocess
9+
import ldap
10+
import ldap.filter
11+
12+
def get_pool(username):
13+
ldap_uri = ldap.get_option(ldap.OPT_URI)
14+
15+
ll = ldap.initialize(ldap_uri)
16+
17+
users = ll.search_s(
18+
'dc=scripts,dc=mit,dc=edu',
19+
ldap.SCOPE_SUBTREE,
20+
ldap.filter.filter_format('(&(objectClass=posixAccount)(uid=%s))', [username]),
21+
[],
22+
)
23+
if not users:
24+
return None, None
25+
user_dn = users[0][0]
26+
27+
pool_ips = set()
28+
vhost_pools = {}
29+
for dn, attrs in ll.search_s(
30+
'dc=scripts,dc=mit,dc=edu',
31+
ldap.SCOPE_SUBTREE,
32+
ldap.filter.filter_format('(&(objectClass=scriptsVhost)(scriptsVhostAccount=%s))', [user_dn]),
33+
['scriptsVhostName', 'scriptsVhostPoolIPv4'],
34+
):
35+
vhost_pools[attrs['scriptsVhostName'][0]] = attrs['scriptsVhostPoolIPv4'][0]
36+
pool_ips.add(attrs['scriptsVhostPoolIPv4'][0])
37+
38+
pool_names = {}
39+
for dn, attrs in ll.search_s(
40+
'dc=scripts,dc=mit,dc=edu',
41+
ldap.SCOPE_SUBTREE,
42+
'(&(objectClass=scriptsVhostPool)(|'+''.join(ldap.filter.filter_format('(scriptsVhostPoolIPv4=%s)', [ip]) for ip in pool_ips)+'))',
43+
['cn', 'scriptsVhostPoolIPv4'],
44+
):
45+
pool_names[attrs['scriptsVhostPoolIPv4'][0]] = attrs['cn'][0]
46+
47+
main_pool = vhost_pools.get(username + '.scripts.mit.edu')
48+
other_pools = None
49+
if len(pool_ips) > 1:
50+
other_pools = sorted((pool_names.get(pool, pool), vhost) for vhost, pool in vhost_pools.items())
51+
return main_pool, other_pools
52+
53+
def should_forward():
54+
ssh_connection = os.environ.get('SSH_CONNECTION')
55+
if not ssh_connection:
56+
return False
57+
_, _, laddr, _ = ssh_connection.split(' ')
58+
try:
59+
with open('/etc/scripts/mbash-vips') as f:
60+
if laddr in [l.strip() for l in f]:
61+
return True
62+
except IOError:
63+
return False
64+
return False
65+
66+
def has_pool(ip):
67+
return len(subprocess.check_output(['/sbin/ip', 'addr', 'show', 'to', ip])) > 0
68+
69+
def maybe_forward():
70+
if not should_forward():
71+
return
72+
command = None
73+
if len(sys.argv) == 3 and sys.argv[1] == '-c':
74+
command = sys.argv[2]
75+
elif len(sys.argv) != 1:
76+
print("Unexpected shell invocation; not forwarding.", file=sys.stderr)
77+
return
78+
user = getpass.getuser()
79+
main_pool, other_pools = get_pool(user)
80+
forward = main_pool and not has_pool(main_pool)
81+
if forward:
82+
# TODO: Check if we're already on the right server.
83+
print("Forwarding to the server for %s.scripts.mit.edu." % (user,), file=sys.stderr)
84+
if other_pools:
85+
print("Your account has virtual hosts on multiple server pools; to connect to a server for a particular host, connect to a specific server:", file=sys.stderr)
86+
print(file=sys.stderr)
87+
for name, vhost in other_pools:
88+
print("%s - ssh %s" % (vhost, name), file=sys.stderr)
89+
print(file=sys.stderr)
90+
if forward:
91+
args = ['ssh', main_pool, '--']
92+
if command is not None:
93+
args.append(command)
94+
os.execv('/usr/bin/ssh', args)
95+
96+
maybe_forward()
97+
98+
os.execv("@bash_path@", ["bash", "--rcfile", "/usr/local/etc/mbashrc"] + sys.argv[1:])

0 commit comments

Comments
 (0)