From c88bc35f1c88d9fbbba6706a4abaad24a1868c98 Mon Sep 17 00:00:00 2001 From: Peter Palfrader Date: Wed, 18 Oct 2006 11:33:32 +0000 Subject: Add hosting ldap git-svn-id: svn+ssh://asteria.noreply.org/svn/weaselutils/trunk@190 bc3d92e2-beff-0310-a7cd-cc87d7ac0ede --- bin/ldap2chroot-accounts | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100755 bin/ldap2chroot-accounts (limited to 'bin/ldap2chroot-accounts') diff --git a/bin/ldap2chroot-accounts b/bin/ldap2chroot-accounts new file mode 100755 index 0000000..2cdadab --- /dev/null +++ b/bin/ldap2chroot-accounts @@ -0,0 +1,139 @@ +#!/usr/bin/ruby + +# +# Copyright (c) 2004 Peter Palfrader +# +# All rights reserved. +# + +require "ldap" +require "getoptlong" +require "myldap" +require "yaml" + + + +def fatal(reason) + STDERR.puts reason + exit 1; +end + +# read mtab +# +# /dev/sda11 /aux xfs rw 0 0 +# /chroot-accounts/MasterChroot/bin /chroot-accounts/weasel.weasel/bin none rw,bind 0 0 +# +def getmounts() + mounts = Hash.new + + IO.foreach('/etc/mtab') { |line| + (device, mountpoint, fstype, option, dummy1, dummy2) = line.split + next unless mountpoint.index(@spool) + + fatal("Unexpected option or fstype in "+line) if (!(option =~ /bind/) || (fstype != 'none')) + + # check mountpoint in detail + components = mountpoint.gsub(/^\//, '').split('/'); + fatal("Weird mountpoint (not 3 components) in "+line) unless (components.size == 3) + fatal("1st componend of mountpoint is not sane in "+line) unless ('/' + components[0] == @spool) + fatal("2nd componend of mountpoint is not sane in "+line) unless (components[1] =~ /^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$/) + fatal("3rd componend of mountpoint is not sane in "+line) unless (["bin", "usr", "lib", components[1]].include?(components[2])) + + mounts[components[1]] = Hash.new unless mounts[components[1]] + mounts[components[1]][components[2]] = device + } + mounts +end + +@config = YAML::load( File.open( '/etc/noreply/config' ) ) + +masterName = @config['module']['ftp']['masterName'] +@spool = (@config['module']['ftp']['chrootBaseDir']).gsub('//', '/') +@spool.chop! if @spool =~ /\/$/ +@master = @spool + '/' + masterName + '/' + +ldap = MyLDAP.new(@config, "ldap2chroot-accounts") +accounts = Hash.new +ldap.conn.search2(@config['basedn'], LDAP::LDAP_SCOPE_SUBTREE, + '(&(objectclass=tnFTPuser)(tnHost='+@config['thishost']+'))').each{ |e| + accounts[ e['uid'][0] ] = e +} + +mounts = getmounts + +# create all account directories +accounts.each_key{ |homedir| + dir = @spool + '/' + homedir + Dir.mkdir(dir) unless File.exists?(dir) +} + +existingdirs = Dir.entries( @spool ).delete_if { |e| ((e =~ /^\./) != nil) } +existingdirs.delete( masterName ) +# Iterate over all existing directories +# checking up on mounts, and update them if necessary +existingdirs.each { |homedir| + basedir = @spool + '/' + homedir + if accounts[homedir] + # Check bin, usr, and lib mounts + # also, the user's datadir is in a directory with the same name as her account + subdirs = %w(bin usr lib) + subdirs << homedir + subdirs.each { |subdir| + supposedLocation = subdir == homedir ? accounts[homedir]['tnFTPDataDirectory'][0] : @master + subdir + mountpoint = basedir + '/' + subdir + + # umount if it's mounted in the wrong place + if mounts[homedir] && mounts[homedir][subdir] + if mounts[homedir][subdir] != supposedLocation + STDERR.puts("warn: Directory "+mountpoint+" is bind mounted to the wrong place: "+mounts[homedir][subdir]+". Should be "+supposedLocation+" remounting.") + system("umount " + mountpoint) or fatal("umount for "+mountpoint+" failed"); + mounts[homedir].delete(subdir) + end + end + + # mount if it's not mounted + if !(mounts[homedir] && mounts[homedir][subdir]) + Dir.mkdir(mountpoint) unless File.exists?(mountpoint) + system("mount -o bind "+ supposedLocation + " " + mountpoint) or fatal("mount for "+mountpoint+" failed"); + end + } + # create etc + etcdir = basedir + '/etc' + Dir.mkdir(etcdir, 0111) unless File.exists?(etcdir) + uid = accounts[homedir]['uid'][0] + uidNumber = accounts[homedir]['uidNumber'][0] + gidNumber = accounts[homedir]['gidNumber'][0] + passwd = "root:x:0:0:root::\n" + "%s:x:%d:%d:::\n"%[uid, uidNumber, gidNumber] + group = "root:x:0:\n" + "%s:x:%s:\n"%[uid, gidNumber] + File.open(etcdir+'/passwd', File::CREAT|File::TRUNC|File::RDWR, 0444).write(passwd) + File.open(etcdir+'/group', File::CREAT|File::TRUNC|File::RDWR, 0444).write(group) + + # create .ssh + sshdir = basedir + '/.ssh' + Dir.mkdir(sshdir, 0111) unless File.exists?(sshdir) + authkeys = ''; + accounts[homedir]['tnSSHKey'] and accounts[homedir]['tnSSHKey'].each{ |key| + key.gsub!('\n', '') + authkeys << "no-port-forwarding,no-X11-forwarding,no-agent-forwarding "+key+"\n" + } + File.open(sshdir+'/authorized_keys', File::CREAT|File::TRUNC|File::RDWR, 0444).write(authkeys) + else + # clean up old stuff + mounts[homedir] and mounts[homedir].each_key{ |subdir| + mountpoint = basedir + '/' + subdir + system("umount " + mountpoint) or fatal("umount for "+mountpoint+" failed"); + Dir.rmdir(mountpoint) + } + { 'etc' => ['passwd', 'group'], '.ssh' => ['authorized_keys'], homedir => [] }.each{ |dir, files| + dir = basedir + '/' + dir + if File.exists?(dir) + files.each { |f| + file = dir + '/' + f + File.unlink(file) if File.exists?(file) + } + Dir.rmdir(dir) + end + } + Dir.rmdir(basedir) + end +} -- cgit v1.2.3