New sipb-xen-console. Now with more magic - and more working
authorEvan Broder <broder@mit.edu>
Sun, 30 Mar 2008 09:09:46 +0000 (05:09 -0400)
committerEvan Broder <broder@mit.edu>
Sun, 30 Mar 2008 09:09:46 +0000 (05:09 -0400)
This package installed onto a clean Debian system should do all of the setup
for a console server except for copying the ssh private keys, granting access
to the Postgres database, and Kerberos keytabs

svn path=/trunk/packages/sipb-xen-console/; revision=344

12 files changed:
debian/changelog
debian/control.in
debian/rules
debian/sipb-xen-console.init
files/etc/nscd.conf.sipb-xen [new file with mode: 0644]
files/etc/nss-pgsql.conf
files/etc/nsswitch.conf.sipb-xen
files/etc/pam.d/ssh.sipb-xen [new file with mode: 0644]
files/etc/ssh/ssh_config.sipb-xen
files/etc/ssh/ssh_known_hosts [moved from files/home/machines/.ssh/known_hosts with 66% similarity]
files/usr/bin/sipb-xen-consolefs
files/usr/bin/sipb-xen-consolesh [new file with mode: 0755]

index 92eff1e..606f7cc 100644 (file)
@@ -1,3 +1,9 @@
+sipb-xen-console (2) unstable; urgency=low
+
+  * Actually functional release.
+
+ -- SIPB Xen Project <sipb-xen@mit.edu>  Sun, 30 Mar 2008 05:07:43 -0400
+
 sipb-xen-console (1) unstable; urgency=low
 
   * Initial release.
index 8b594df..2737e46 100644 (file)
@@ -9,7 +9,7 @@ Package: sipb-xen-console
 Architecture: all
 Provides: ${diverted-files}
 Conflicts: ${diverted-files}
-Depends: ${shlibs:Depends}, ${misc:Depends}, fuse-utils, libnss-pgsql1, openssh-client, openssh-server, python-fuse, sipb-xen-database-common
+Depends: ${shlibs:Depends}, ${misc:Depends}, daemon, fuse-utils, libnss-pgsql1, nscd, openssh-client, openssh-server, python-fuse, sipb-xen-database-common
 Description: SIPB Xen serial console server
  This package  should be installed on sipb-xen-console
  It makes sure that necessary tools are available.
index 8dfab96..881fd0c 100755 (executable)
@@ -3,7 +3,9 @@
 DEB_AUTO_UPDATE_DEBIAN_CONTROL = 1
 DEB_DIVERT_EXTENSION = .sipb-xen
 DEB_DIVERT_FILES_sipb-xen-console += \
-       /etc/nsswitch.conf
+       /etc/nscd.conf \
+       /etc/nsswitch.conf \
+       /etc/pam.d/ssh \
        /etc/ssh/ssh_config
 
 include /usr/share/cdbs/1/rules/debhelper.mk
index 14ed7e8..6d2b7d4 100755 (executable)
@@ -63,6 +63,7 @@ do_stop()
        [ "$RETVAL" = 2 ] && return 2
        # Many daemons don't delete their pidfiles when they exit.
        rm -f $PIDFILE
+       umount "$DAEMON_ARGS"
        return "$RETVAL"
 }
 
diff --git a/files/etc/nscd.conf.sipb-xen b/files/etc/nscd.conf.sipb-xen
new file mode 100644 (file)
index 0000000..0ed898e
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# /etc/nscd.conf
+#
+# An example Name Service Cache config file.  This file is needed by nscd.
+#
+# Legal entries are:
+#
+#      logfile                 <file>
+#      debug-level             <level>
+#      threads                 <initial #threads to use>
+#      max-threads             <maximum #threads to use>
+#      server-user             <user to run server as instead of root>
+#              server-user is ignored if nscd is started with -S parameters
+#       stat-user               <user who is allowed to request statistics>
+#      reload-count            unlimited|<number>
+#      paranoia                <yes|no>
+#      restart-interval        <time in seconds>
+#
+#       enable-cache           <service> <yes|no>
+#      positive-time-to-live   <service> <time in seconds>
+#      negative-time-to-live   <service> <time in seconds>
+#       suggested-size         <service> <prime number>
+#      check-files             <service> <yes|no>
+#      persistent              <service> <yes|no>
+#      shared                  <service> <yes|no>
+#
+# Currently supported cache names (services): passwd, group, hosts
+#
+
+
+#      logfile                 /var/log/nscd.log
+#      threads                 6
+#      max-threads             128
+#      server-user             nobody
+#      stat-user               somebody
+       debug-level             0
+#      reload-count            5
+       paranoia                no
+#      restart-interval        3600
+
+       enable-cache            passwd          yes
+       positive-time-to-live   passwd          600
+#      negative-time-to-live   passwd          20
+       negative-time-to-live   passwd          3
+       suggested-size          passwd          211
+       check-files             passwd          yes
+#      persistent              passwd          yes
+       persistent              passwd          no
+       shared                  passwd          yes
+
+       enable-cache            group           yes
+       positive-time-to-live   group           3600
+#      negative-time-to-live   group           60
+       negative-time-to-live   group           3
+       suggested-size          group           211
+       check-files             group           yes
+#      persistent              group           yes
+       persistent              group           no
+       shared                  group           yes
+
+       enable-cache            hosts           yes
+       positive-time-to-live   hosts           3600
+       negative-time-to-live   hosts           20
+       suggested-size          hosts           211
+       check-files             hosts           yes
+       persistent              hosts           yes
+       shared                  hosts           yes
index d4ddcfe..e0ae1f2 100644 (file)
@@ -5,19 +5,14 @@ host          = sipb-xen-dev
 port           = 5432
 database       = sipb_xen
 login          = sipb-xen
-#passwd                = foo
-#passwdtable   = machines
-#grouptable    = machines
-# you can use anything postgres accepts as table expression
-#groupmembertable = accounts JOIN usergroups ON accounts.uid=usergroups.uid JOIN groups ON usergroups.gid=groups.gid
 
-querypasswd = SELECT name, 'moo', 1000 as uid, 1000, '', '/vmhome/'|| name, '/usr/local/bin/sipb-xen-consolesh' FROM machines
-querygroup = SELECT name, NULL, 1000 as gid FROM machines
-querymembers = SELECT name FROM machines WHERE 1000 = %d
-queryids = SELECT 1000 AS gid FROM machines LIMIT 0;
+querypasswd = SELECT name, NULL, machine_id + 1000 as uid, machine_id + 1000 as gid, '', '/consolefs/'|| name, '/usr/bin/sipb-xen-consolesh' FROM machines
+querygroup = SELECT name, NULL, machine_id + 1000 as gid FROM machines
+querymembers = SELECT name FROM machines WHERE 1000 + machine_id = %d
+queryids = SELECT 1000 + machine_id AS gid FROM machines LIMIT 0
 
 passwd_name = name
-passwd_uid = uid
+passwd_uid = 1000 + machine_id
 
 group_name = name
-group_gid = gid
+group_gid = 1000 + machine_id
index 4fcecf6..4a82f1e 100644 (file)
@@ -5,7 +5,7 @@
 # `info libc "Name Service Switch"' for information about this file.
 
 passwd:         compat pgsql
-group:          compat
+group:          compat pgsql
 shadow:         compat
 
 hosts:          files dns
diff --git a/files/etc/pam.d/ssh.sipb-xen b/files/etc/pam.d/ssh.sipb-xen
new file mode 100644 (file)
index 0000000..1259f21
--- /dev/null
@@ -0,0 +1,39 @@
+# PAM configuration for the Secure Shell service
+
+# Read environment variables from /etc/environment and
+# /etc/security/pam_env.conf.
+auth       required     pam_env.so # [1]
+# In Debian 4.0 (etch), locale-related environment variables were moved to
+# /etc/default/locale, so read that as well.
+auth       required     pam_env.so envfile=/etc/default/locale
+
+# Standard Un*x authentication.
+@include common-auth
+
+# Disallow non-root logins when /etc/nologin exists.
+account    required     pam_nologin.so
+
+# Uncomment and edit /etc/security/access.conf if you need to set complex
+# access limits that are hard to express in sshd_config.
+# account  required     pam_access.so
+
+# Standard Un*x authorization.
+@include common-account
+
+# Standard Un*x session setup and teardown.
+@include common-session
+
+# Print the message of the day upon successful login.
+#session    optional     pam_motd.so # [1]
+
+# Print the status of the user's mailbox upon successful login.
+session    optional     pam_mail.so standard noenv # [1]
+
+# Set up user limits from /etc/security/limits.conf.
+session    required     pam_limits.so
+
+# Set up SELinux capabilities (need modified pam)
+# session  required     pam_selinux.so multiple
+
+# Standard Un*x password updating.
+@include common-password
index 3630fc0..97ca8e8 100644 (file)
@@ -17,7 +17,7 @@
 # ssh_config(5) man page.
 
 Host *
-   SetEnv VM_NAME
+   SendEnv VM_NAME
 #   ForwardAgent no
 #   ForwardX11 no
 #   ForwardX11Trusted yes
similarity index 66%
rename from files/home/machines/.ssh/known_hosts
rename to files/etc/ssh/ssh_known_hosts
index 3056107..0aa35d1 100644 (file)
@@ -1,2 +1,3 @@
 |1|CoekhjakJDYiibQ38vZna+XKwCg=|Ts2GavZxl8KVEl++tnJnjqfn84s= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsoOOazVHn04z6s+kQnoFcw9fv7dGB9s/9H1QygYW9QAbvklWx0q4J8KGTATXCFwjooLNqjHYONOQ8x0h1fZPDmhdoHk24wH/EBUAAyhtrwTMpsgfqZwG7yuRpcbO382F3wRv6CIRYZ6hyIlm0Zt3680mO/u7l2wAFoMTyYwSdZ8Gl9p5Ay750TFCZoEI/Z4EQY5lGPHrHIXN+uo0Yus//AmWIzY9y3TSKabHz77rPGIzJc8Y4XjDqA7LzXCY+KGw2Of059AseVHNTCMo6KzVIKgdZoRBtiY7fD1l7ystgKL6lGJr4C1UyWoM41EVkDqsRJZ70C4Elcr1x/MrQFLEgQ==
 |1|SFl+Ci6EXZcVvxvxDm4Cf85nGho=|InwYz5wWUf/NRbBQRa/TO3Lm2uQ= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsoOOazVHn04z6s+kQnoFcw9fv7dGB9s/9H1QygYW9QAbvklWx0q4J8KGTATXCFwjooLNqjHYONOQ8x0h1fZPDmhdoHk24wH/EBUAAyhtrwTMpsgfqZwG7yuRpcbO382F3wRv6CIRYZ6hyIlm0Zt3680mO/u7l2wAFoMTyYwSdZ8Gl9p5Ay750TFCZoEI/Z4EQY5lGPHrHIXN+uo0Yus//AmWIzY9y3TSKabHz77rPGIzJc8Y4XjDqA7LzXCY+KGw2Of059AseVHNTCMo6KzVIKgdZoRBtiY7fD1l7ystgKL6lGJr4C1UyWoM41EVkDqsRJZ70C4Elcr1x/MrQFLEgQ==
+|1|52lp5FTRtu4Fyk8GvC3mH2idB+0=|fGJ+LwWltfUP9kC1fiMfJO5XrVk= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsoOOazVHn04z6s+kQnoFcw9fv7dGB9s/9H1QygYW9QAbvklWx0q4J8KGTATXCFwjooLNqjHYONOQ8x0h1fZPDmhdoHk24wH/EBUAAyhtrwTMpsgfqZwG7yuRpcbO382F3wRv6CIRYZ6hyIlm0Zt3680mO/u7l2wAFoMTyYwSdZ8Gl9p5Ay750TFCZoEI/Z4EQY5lGPHrHIXN+uo0Yus//AmWIzY9y3TSKabHz77rPGIzJc8Y4XjDqA7LzXCY+KGw2Of059AseVHNTCMo6KzVIKgdZoRBtiY7fD1l7ystgKL6lGJr4C1UyWoM41EVkDqsRJZ70C4Elcr1x/MrQFLEgQ==
index 7cd3766..380c94b 100755 (executable)
@@ -10,11 +10,11 @@ import os     # for filesystem modes (O_RDONLY, etc)
 import errno   # for error number codes (ENOENT, etc)
                           # - note: these must be returned as negatives
 
+import sipb_xen_database
+
 fuse.fuse_python_api = (0, 2)
 
-machines = ['moo17', 'remus']
 realpath = "/home/machines/"
-uid = 1000
 
 def dirFromList(list):
        """
@@ -47,7 +47,7 @@ class MyStat:
                self.st_ino = 0
                self.st_dev = 0
                self.st_nlink = 0
-               self.st_uid = uid
+               self.st_uid = 0
                self.st_gid = 0
                self.st_size = 0
                self.st_atime = 0
@@ -63,11 +63,36 @@ class ConsoleFS(Fuse):
        
        def __init__(self, *args, **kw):
                Fuse.__init__(self, *args, **kw)
+               self.lasttime = time()
+               self.allow_other = 1
                print 'Init complete.'
        
        def mirrorPath(self, path):
                return realpath + "/".join(getParts(path)[1:])
        
+       def getMachines(self):
+               if time() - self.lasttime > 15:
+                       self.lasttime = time()
+                       sipb_xen_database.clear_cache()
+               return [machine.name for machine in sipb_xen_database.Machine.select()]
+       
+       def getUid(self, machine_name):
+               return sipb_xen_database.Machine.get_by(name=machine_name).machine_id + 1000
+       
+       def getK5login(self, machine_name):
+               machine = sipb_xen_database.Machine.get_by(name=machine_name)
+               users = [acl.user for acl in machine.acl]
+               return "\n".join(map(self.userToPrinc, users) + [''])
+       
+       def userToPrinc(self, user):
+               if '@' in user:
+                       (princ, realm) = user.split('@')
+               else:
+                       princ = user
+                       realm = "ATHENA.MIT.EDU"
+               
+               return princ.replace('.', '/') + realm
+       
        def getattr(self, path):
                """
                - st_mode (protection bits)
@@ -93,38 +118,50 @@ class ConsoleFS(Fuse):
                        st.st_mode = stat.S_IFDIR | 0755
                        st.st_nlink = 2
                elif depth == 1:
-                       if parts[-1] in machines:
+                       if parts[-1] in self.getMachines():
                                st.st_mode = stat.S_IFDIR | 0755
                                st.st_nlink = 2
+                               st.st_uid = st.st_gid = self.getUid(parts[0])
                        else:
                                return -errno.ENOENT
                elif depth == 2 and parts[-1] == '.k5login':
                        st.st_mode = stat.S_IFREG | 0444
                        st.st_nlink = 1
-                       st.st_size = 17
+                       st.st_size = len(self.getK5login(parts[0]))
+                       st.st_uid = st.st_gid = self.getUid(parts[0])
                else:
-                       st = os.lstat(self.mirrorPath(path))
+                       stats = list(os.lstat(self.mirrorPath(path)))
+                       stats[4:6] = [self.getUid(parts[0])] * 2
+                       return tuple(stats)
                return st.toTuple()
        
        def readdir(self, path, offset):
                print '*** readdir', path, offset
+               for (value, zero) in self.getdir(path):
+                       yield fuse.Direntry(value)
+       
+       def getdir(self, path):
+               print '*** getdir', path
                if path == '/':
-                       for r in  ['.', '..']+machines:
-                               yield fuse.Direntry(r)
+                       contents = ['.', '..']+self.getMachines()
                elif getDepth(path) == 1:
-                       for r in set(os.listdir(self.mirrorPath(path)) + ['.k5login']):
-                               yield fuse.Direntry(r)
+                       contents = set(os.listdir(self.mirrorPath(path)) + ['.k5login', '.', '..'])
                else:
-                       for r in os.listdir(self.mirrorPath(path)):
-                               yield fuse.Direntry(r)
+                       contents = os.listdir(self.mirrorPath(path)) + ['.', '..']
+               return [(i, 0) for i in contents]
        
        def read ( self, path, length, offset ):
                print '*** read', path, length, offset
                
+               parts = getParts(path)
+               
                if getDepth(path) < 2:
                        return -errno.ENOENT
-               elif getParts(path)[1:] == ['.k5login']:
-                       pass
+               elif parts[1:] == ['.k5login']:
+                       if parts[0] not in self.getMachines():
+                               return -errno.ENOENT
+                       else:
+                               return self.getK5login(parts[0])[offset:length + offset]
                else:
                        fname = self.mirrorPath(path)
                        if not os.path.isfile(fname):
@@ -135,6 +172,7 @@ class ConsoleFS(Fuse):
                                return f.read(length)
 
 if __name__ == '__main__':
+       sipb_xen_database.connect('postgres://sipb-xen@sipb-xen-dev.mit.edu/sipb_xen')
        usage="""
 ConsoleFS [mount_path]
 """
diff --git a/files/usr/bin/sipb-xen-consolesh b/files/usr/bin/sipb-xen-consolesh
new file mode 100755 (executable)
index 0000000..ffaa191
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+export VM_NAME="d_$USER"
+ssh console@black-mesa