fedora-infrastructure/fas/client/fasClient.py

340 lines
13 KiB
Python
Raw Normal View History

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright © 2007-2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use, modify,
# copy, or redistribute it subject to the terms and conditions of the GNU
# General Public License v.2. This program is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details. You should have
# received a copy of the GNU General Public License along with this program;
# if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
# Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat trademarks that are
# incorporated in the source code or documentation are not subject to the GNU
# General Public License and may only be used or replicated with the express
# permission of Red Hat, Inc.
#
# Red Hat Author(s): Mike McGrath <mmcgrath@redhat.com>
#
# TODO: put tmp files in a 700 tmp dir
import sys
import logging
import syslog
2008-02-29 18:26:57 -06:00
import os
import tempfile
from fedora.tg.client import BaseClient, AuthError, ServerError
from optparse import OptionParser
2008-03-06 21:06:06 -06:00
from shutil import move, rmtree, copytree
from rhpl.translate import _
2008-03-03 12:40:06 -06:00
import ConfigParser
parser = OptionParser()
2008-02-29 18:26:57 -06:00
parser.add_option('-i', '--install',
dest = 'install',
default = False,
action = 'store_true',
help = _('Download and sync most recent content'))
2008-03-03 12:40:06 -06:00
parser.add_option('-c', '--config',
dest = 'CONFIG_FILE',
default = '/etc/fas.conf',
metavar = 'CONFIG_FILE',
help = _('Specify config file (default "%default")'))
parser.add_option('--nogroup',
dest = 'no_group',
default = False,
action = 'store_true',
help = _('Do not sync group information'))
parser.add_option('--nopasswd',
dest = 'no_passwd',
default = False,
action = 'store_true',
help = _('Do not sync passwd information'))
parser.add_option('--noshadow',
dest = 'no_shadow',
default = False,
action = 'store_true',
help = _('Do not sync shadow information'))
parser.add_option('--nohome',
dest = 'no_home_dirs',
default = False,
action = 'store_true',
help = _('Do not create home dirs'))
parser.add_option('-s', '--server',
dest = 'FAS_URL',
2008-03-03 12:40:06 -06:00
default = None,
metavar = 'FAS_URL',
2008-03-03 12:40:06 -06:00
help = _('Specify URL of fas server.'))
2008-02-29 18:26:57 -06:00
parser.add_option('-e', '--enable',
dest = 'enable',
default = False,
action = 'store_true',
help = _('Enable FAS synced shell accounts'))
parser.add_option('-d', '--disable',
dest = 'disable',
default = False,
action = 'store_true',
help = _('Disable FAS synced shell accounts'))
2008-02-29 18:26:57 -06:00
(opts, args) = parser.parse_args()
log = logging.getLogger('fas')
2008-03-03 12:40:06 -06:00
try:
config = ConfigParser.ConfigParser()
if os.path.exists(opts.CONFIG_FILE):
config.read(opts.CONFIG_FILE)
elif os.path.exists('fas.conf'):
config.read('fas.conf')
print >> sys.stderr, "Could not open %s, defaulting to ./fas.conf" % opts.CONFIG_FILE
else:
print >> sys.stderr, "Could not open %s." % opts.CONFIG_FILE
sys.exit(5)
except ConfigParser.MissingSectionHeaderError, e:
print >> sys.stderr, "Config file does not have proper formatting - %s" % e
sys.exit(6)
FAS_URL = config.get('global', 'url')
def _chown(arg, dir_name, files):
os.chown(dir_name, arg[0], arg[1])
for file in files:
os.chown(os.path.join(dir_name, file), arg[0], arg[1])
class MakeShellAccounts(BaseClient):
2008-02-29 18:26:57 -06:00
temp = None
groups = None
2008-03-04 11:34:28 -06:00
people = None
memberships = None
group_mapping = {}
2008-02-29 18:26:57 -06:00
def mk_tempdir(self):
2008-03-03 12:40:06 -06:00
self.temp = tempfile.mkdtemp('-tmp', 'fas-', config.get('global', 'temp'))
2008-02-29 18:26:57 -06:00
def rm_tempdir(self):
rmtree(self.temp)
def valid_user(self, username):
valid_groups = config.get('host', 'groups').split(',') + \
config.get('host', 'restricted_groups').split(',') + \
config.get('host', 'ssh_restricted_groups').split(',')
try:
for group in valid_groups:
if username in self.group_mapping[group]:
2008-03-04 11:34:28 -06:00
return True
except KeyError:
return False
2008-03-04 11:34:28 -06:00
return False
def shell(self, username):
''' Determine what shell username should have '''
for group in config.get('host', 'groups').split(','):
if username in self.group_mapping[group]:
return config.get('users', 'shell')
for group in config.get('host', 'restricted_groups'):
if username in self.group_mapping[group]:
return config.get('users', 'restricted_shell')
print >> sys.stderr, 'Could not determine shell for %s. Defaulting to /sbin/nologin' % username
return '/sbin/nologin'
2008-02-29 18:26:57 -06:00
def passwd_text(self, people=None):
i = 0
passwd_file = open(self.temp + '/passwd.txt', 'w')
shadow_file = open(self.temp + '/shadow.txt', 'w')
os.chmod(self.temp + '/shadow.txt', 00400)
if not self.people:
self.people = self.people_list()
for person in self.people:
username = person['username']
if self.valid_user(username):
uid = person['id']
2008-03-04 11:34:28 -06:00
human_name = person['human_name']
password = person['password']
2008-03-04 11:34:28 -06:00
home_dir = "%s/%s" % (config.get('users', 'home'), username)
shell = self.shell(username)
passwd_file.write("=%s %s:x:%i:%i:%s:%s:%s\n" % (uid, username, uid, uid, human_name, home_dir, shell))
passwd_file.write("0%i %s:x:%i:%i:%s:%s:%s\n" % (i, username, uid, uid, human_name, home_dir, shell))
passwd_file.write(".%s %s:x:%i:%i:%s:%s:%s\n" % (username, username, uid, uid, human_name, home_dir, shell))
shadow_file.write("=%i %s:%s:99999:0:99999:7:::\n" % (uid, username, password))
shadow_file.write("0%i %s:%s:99999:0:99999:7:::\n" % (i, username, password))
shadow_file.write(".%s %s:%s:99999:0:99999:7:::\n" % (username, username, password))
2008-03-04 11:34:28 -06:00
i = i + 1
passwd_file.close()
shadow_file.close()
def valid_user_group(self, person_id):
''' Determine if person is valid on this machine as defined in the
config file. I worry that this is going to be horribly inefficient
with large numbers of users and groups.'''
for member in self.memberships:
for group in self.memberships[member]:
if group['person_id'] == person_id:
return True
return False
def groups_text(self, groups=None, people=None):
i = 0
2008-02-29 18:26:57 -06:00
file = open(self.temp + '/group.txt', 'w')
if not groups:
groups = self.group_list()
if not people:
people = self.people_list()
''' First create all of our users/groups combo '''
usernames = {}
for person in people:
uid = person['id']
if self.valid_user_group(uid):
2008-03-04 11:58:59 -06:00
username = person['username']
usernames[uid] = username
file.write("=%i %s:x:%i:\n" % (uid, username, uid))
file.write("0%i %s:x:%i:\n" % (i, username, uid))
file.write(".%s %s:x:%i:\n" % (username, username, uid))
i = i + 1
2008-03-04 11:34:28 -06:00
for group in groups:
gid = group['id']
name = group['name']
try:
''' Shoot me now I know this isn't right '''
members = []
2008-03-04 11:34:28 -06:00
for member in self.memberships[name]:
members.append(usernames[member['person_id']])
memberships = ','.join(members)
self.group_mapping[name] = members
except KeyError:
''' No users exist in the group '''
pass
2008-03-04 11:58:59 -06:00
file.write("=%i %s:x:%i:%s\n" % (gid, name, gid, memberships))
file.write("0%i %s:x:%i:%s\n" % (i, name, gid, memberships))
file.write(".%s %s:x:%i:%s\n" % (name, name, gid, memberships))
i = i + 1
file.close()
def group_list(self, search='*'):
params = {'search' : search}
2008-03-04 11:34:28 -06:00
request = self.send_request('group/list', auth=True, input=params)
self.groups = request['groups']
self.memberships = request['memberships']
return self.groups
def people_list(self, search='*'):
params = {'search' : search}
self.people = self.send_request('user/list', auth=True, input=params)['people']
return self.people
def make_group_db(self):
self.groups_text()
2008-02-29 18:26:57 -06:00
os.system('makedb -o %s/group.db %s/group.txt' % (self.temp, self.temp))
def make_passwd_db(self):
self.passwd_text()
2008-02-29 18:26:57 -06:00
os.system('makedb -o %s/passwd.db %s/passwd.txt' % (self.temp, self.temp))
os.system('makedb -o %s/shadow.db %s/shadow.txt' % (self.temp, self.temp))
2008-02-29 18:34:28 -06:00
os.chmod(self.temp + '/shadow.db', 00400)
def install_passwd_db(self):
try:
2008-02-29 18:26:57 -06:00
move(self.temp + '/passwd.db', '/var/db/passwd.db')
except IOError, e:
print "ERROR: Could not write passwd db - %s" % e
def install_shadow_db(self):
try:
2008-02-29 18:26:57 -06:00
move(self.temp + '/shadow.db', '/var/db/shadow.db')
except IOError, e:
print "ERROR: Could not write shadow db - %s" % e
def install_group_db(self):
try:
2008-02-29 18:26:57 -06:00
move(self.temp + '/group.db', '/var/db/group.db')
except IOError, e:
print "ERROR: Could not write group db - %s" % e
def create_homedirs(self):
''' Create homedirs and home base dir if they do not exist '''
home_base = config.get('users', 'home')
if not os.path.exists(home_base):
os.makedirs(home_base, mode=0755)
for person in self.people:
home_dir = os.path.join(home_base, person['username'])
if not os.path.exists(home_dir) and self.valid_user(person['username']):
syslog.syslog('Creating homedir for %s' % person['username'])
2008-03-06 21:06:06 -06:00
copytree('/etc/skel/', home_dir)
os.path.walk(home_dir, _chown, [person['id'], person['id']])
2008-02-29 18:26:57 -06:00
def enable():
temp = tempfile.mkdtemp('-tmp', 'fas-', config.get('global', 'temp'))
old = open('/etc/sysconfig/authconfig', 'r')
new = open(temp + '/authconfig', 'w')
2008-02-29 18:26:57 -06:00
for line in old:
if line.startswith("USEDB"):
new.write("USEDB=yes\n")
else:
new.write(line)
2008-02-29 18:26:57 -06:00
new.close()
old.close()
try:
move(temp + '/authconfig', '/etc/sysconfig/authconfig')
2008-02-29 18:26:57 -06:00
except IOError, e:
print "ERROR: Could not write /etc/sysconfig/authconfig - %s" % e
sys.exit(5)
os.system('/usr/sbin/authconfig --updateall')
rmtree(temp)
2008-02-29 18:26:57 -06:00
def disable():
temp = tempfile.mkdtemp('-tmp', 'fas-', config.get('global', 'temp'))
old = open('/etc/sysconfig/authconfig', 'r')
new = open(temp + '/authconfig', 'w')
2008-02-29 18:26:57 -06:00
for line in old:
if line.startswith("USEDB"):
new.write("USEDB=no\n")
else:
new.write(line)
old.close()
2008-02-29 18:26:57 -06:00
new.close()
try:
move(temp + '/authconfig', '/etc/sysconfig/authconfig')
2008-02-29 18:26:57 -06:00
except IOError, e:
print "ERROR: Could not write /etc/sysconfig/authconfig - %s" % e
sys.exit(5)
os.system('/usr/sbin/authconfig --updateall')
rmtree(temp)
2008-02-29 18:26:57 -06:00
if __name__ == '__main__':
if opts.enable:
enable()
if opts.disable:
disable()
if opts.install:
2008-02-29 18:26:57 -06:00
try:
fas = MakeShellAccounts(FAS_URL, config.get('global', 'login'), config.get('global', 'password'), False)
2008-02-29 18:26:57 -06:00
except AuthError, e:
2008-03-03 12:40:06 -06:00
print >> sys.stderr, e
2008-02-29 18:26:57 -06:00
sys.exit(1)
fas.mk_tempdir()
fas.make_group_db()
fas.make_passwd_db()
if not opts.no_group:
fas.install_group_db()
if not opts.no_passwd:
fas.install_passwd_db()
if not opts.no_shadow:
fas.install_shadow_db()
if not opts.no_home_dirs:
fas.create_homedirs()
2008-02-29 18:26:57 -06:00
fas.rm_tempdir()
if not (opts.install or opts.enable or opts.disable):
2008-02-29 18:26:57 -06:00
parser.print_help()