ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/ccs/admin/admin.py
Revision: 692
Committed: 2010-07-18T04:33:45-07:00 (14 years, 11 months ago) by douglas
Content type: text/x-python
File size: 6798 byte(s)
Log Message:
Don't use TLS on non CCS systems when testing.

File Contents

# User Rev Content
1 douglas 600 #!/usr/bin/env python
2 douglas 585 # CCS Computer Science
3 douglas 590 # Admin
4 douglas 585 #
5     # Douglas Thrift
6     #
7     # $Id$
8    
9 douglas 591 import common
10 douglas 692 import fnmatch
11 douglas 585 import ldap
12 douglas 687 import optparse
13 douglas 598 import os
14     import psycopg2
15 douglas 681 import re
16 douglas 598 import shutil
17 douglas 681 import subprocess
18 douglas 592 import sys
19 douglas 680 import warnings
20 douglas 585
21 douglas 680 with warnings.catch_warnings():
22     warnings.filterwarnings('ignore', 'the sets module is deprecated', DeprecationWarning)
23 douglas 598
24     import MySQLdb
25    
26 douglas 585 MASTER = 'zweihander.ccs.ucsb.edu'
27 douglas 600 SLAVE = 'wireless.ccs.ucsb.edu'
28     MASTER_URI = 'ldaps://' + MASTER
29     SLAVE_URI = 'ldaps://' + SLAVE
30 douglas 585 BASE = 'dc=ccs,dc=ucsb,dc=edu'
31 douglas 598 PEOPLE = 'ou=People,' + BASE
32     GROUP = 'ou=Group,' + BASE
33 douglas 606 SECRET = '/ccs/etc/secret'
34 douglas 592 SHELLS = map(lambda system: 'ucsbCcs' + system.capitalize(), common.SYSTEMS)
35 douglas 598 SAMBA_SID = 'S-1-5-21-3739982181-3886045993-82308153-%u'
36 douglas 681 USER = re.compile('^[a-z0-9]{1,16}$')
37     NAME = re.compile('^[^:]+$')
38     INVALID_USER = 'Invalid user name: "%s"'
39     INVALID_NAME = 'Invalid full name: "%s"'
40 douglas 585
41     ldap.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
42     ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, '/ccs/ssl/ccscert.pem')
43     ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND)
44    
45     def _user(user):
46 douglas 598 return 'uid=%s,%s' % (user, PEOPLE)
47 douglas 585
48 douglas 598 def _group(group):
49     return 'cn=%s,%s' % (group, GROUP)
50    
51 douglas 681 def _program():
52     return os.path.splitext(os.path.basename(sys.argv[0]))[0]
53    
54     def ldap_connection(root = True):
55 douglas 692 connection = ldap.initialize(MASTER_URI if fnmatch.fnmatch(common.HOST, '*.ccs.ucsb.edu') else MASTER_URI.replace('ldaps:', 'ldap:'))
56 douglas 585
57 douglas 681 if root:
58     with open(SECRET, 'rb') as secret:
59     connection.simple_bind_s(_user('root'), secret.read())
60     else:
61     connection.simple_bind_s()
62 douglas 585
63     return connection
64    
65 douglas 591 def master():
66 douglas 592 return common.HOST == MASTER
67 douglas 591
68 douglas 593 def run(errors):
69     if errors:
70     for host, error in errors.iteritems():
71     sys.stderr.write('%s: %s\n' % (host, error))
72 douglas 592
73     sys.exit(1)
74    
75 douglas 593 def error(error):
76 douglas 681 sys.exit('%s: %s' % (_program(), error))
77 douglas 593
78 douglas 592 def eof():
79     print
80    
81     sys.exit(130)
82    
83 douglas 681 def parser(**kwargs):
84     kwargs['prog'] = _program()
85 douglas 687 parser = optparse.OptionParser(**kwargs)
86 douglas 681
87 douglas 687 def version(option, opt_str, value, parser, *args, **kwargs):
88     parser.version = '%%prog %s (CCS CS Lab)' % subprocess.Popen('svnversion', stdout = subprocess.PIPE, cwd = os.path.dirname(__file__)).communicate()[0].strip()
89 douglas 681
90 douglas 687 if opt_str != '--version-short':
91     name = os.uname()
92     parser.version += ' - %s %s %s' % (name[0], name[2], name[4])
93    
94     parser.print_version()
95     parser.exit()
96    
97     parser.add_option('-V', '--version', action = 'callback', callback = version, help = 'show version information and exit')
98     parser.add_option('--version-short', action = 'callback', callback = version, help = optparse.SUPPRESS_HELP)
99    
100     return parser
101    
102     def user(options):
103 douglas 681 user = os.environ['USER']
104    
105     if user == 'root':
106 douglas 687 user = options.user
107 douglas 681
108     while USER.match(user) is None:
109 douglas 687 if options.user:
110 douglas 681 error(INVALID_USER % user)
111     elif user:
112     warn(INVALID_USER % user)
113    
114     user = raw_input('User: ')
115    
116     return user
117    
118     def warn(error):
119     sys.stderr.write('%s: %s\n' % (_program(), error))
120    
121 douglas 598 def adduser(user, name, password):
122     connection = ldap_connection()
123     uid = max(map(lambda user: int(user[1]['uidNumber'][0]), connection.search_s(PEOPLE, ldap.SCOPE_ONELEVEL, '(&(uid=*)(!(uid=root)))', ('uidNumber',)))) + 1
124     gid = uid
125     samba_gid = gid + 1000
126     home = os.path.join('/home', user)
127    
128     connection.add_s(_user(user), [
129     ('objectclass', ['top', 'account', 'posixAccount', 'shadowAccount', 'ucsbCcsLoginShells', 'sambaSamAccount']),
130     ('cn', name),
131     ('uid', user),
132     ('uidNumber', str(uid)),
133     ('gidNumber', str(gid)),
134     ('homeDirectory', home),
135     ('loginShell', 'bash'),
136     ] + zip(SHELLS, dict(common.SHELLS)['bash']) + [
137     ('sambaAcctFlags', '[U ]'),
138     ('sambaSID', SAMBA_SID % uid),
139     ('sambaPrimaryGroupSID', SAMBA_SID % samba_gid),
140     ])
141     connection.add_s(_group(user), [
142     ('objectclass', ['top', 'posixGroup', 'sambaGroupMapping']),
143     ('cn', user),
144     ('gidNumber', str(gid)),
145     ('sambaSID', SAMBA_SID % samba_gid),
146     ('sambaGroupType', '4'),
147     ])
148    
149     for group in ('wheel', 'fuse', 'operator'):
150     connection.modify_s(_group(group), [(ldap.MOD_ADD, 'memberUid', user)])
151    
152     connection.unbind_s()
153     os.umask(0022)
154     os.mkdir(home)
155     os.chown(home, uid, gid)
156    
157     for skel in ('/usr/share/skel', '/ccs/skel'):
158     for source, directories, files in os.walk(skel):
159     destination = os.path.join(home, source[len(skel):])
160    
161     for directory in directories:
162     target = os.path.join(destination, directory[3:] if directory.startswith('dot') else directory)
163    
164     os.mkdir(target)
165     shutil.copymode(os.path.join(source, directory), target)
166     os.chown(target, uid, gid)
167    
168     for file in files:
169     target = os.path.join(destination, file[3:] if file.startswith('dot') else file)
170    
171     shutil.copy(os.path.join(source, file), target)
172     os.chown(target, uid, gid)
173    
174     db = psycopg2.connect(database = 'postgres')
175     cursor = db.cursor()
176    
177     cursor.execute('create user %s with createdb' % user)
178     db.commit()
179    
180     passwd(user, None, password)
181    
182 douglas 592 def chfn(user, name):
183     connection = ldap_connection()
184    
185     connection.modify_s(_user(user), [(ldap.MOD_REPLACE, 'cn', name)])
186     connection.unbind_s()
187    
188 douglas 591 def chsh(user, shell, shells):
189     if shell != 'custom':
190     shells = dict(common.SHELLS)[shell]
191     else:
192     for _shell, _shells in common.SHELLS[:-1]:
193     if shells == _shells:
194     shell = _shell
195    
196     connection = ldap_connection()
197    
198     connection.modify_s(_user(user), map(lambda (key, value): (ldap.MOD_REPLACE, key, value), [('loginShell', shell)] + zip(SHELLS, shells)))
199     connection.unbind_s()
200    
201 douglas 585 def passwd(user, old_password, new_password):
202     connection = ldap_connection()
203    
204     connection.passwd_s(_user(user), old_password, new_password)
205     connection.unbind_s()
206    
207 douglas 606 with open(SECRET, 'rb') as secret:
208 douglas 585 db = MySQLdb.connect(passwd = secret.read(), db = 'mysql')
209    
210     cursor = db.cursor()
211    
212     cursor.execute('select count(User) from user where User = %s', (user,))
213    
214     if cursor.fetchone()[0]:
215     cursor.execute('update user set Password = PASSWORD(%s) where User = %s', (new_password, user))
216     cursor.execute('flush privileges');
217     else:
218     cursor.executemany('grant all on `' + db.escape_string(user) + r'\_%%`.* to %s@%s identified by %s', map(lambda host: (user, host, new_password), ('localhost', '%')))
219 douglas 600
220     if __name__ == '__main__':
221 douglas 687 parser = parser(usage = '%prog [options] [VARIABLE...]')
222    
223     parser.add_option('-l', '--list', action = 'store_true', default = False, help = 'list the available variables and their values')
224    
225     options, args = parser.parse_args()
226 douglas 681 variables = ('MASTER', 'SLAVE', 'MASTER_URI', 'SLAVE_URI', 'BASE', 'PEOPLE', 'GROUP')
227 douglas 600
228 douglas 687 if options.list:
229     for variable in variables:
230     exec "print '%%10s: %%s' %% (variable, %s)" % variable
231 douglas 681
232 douglas 687 parser.exit()
233    
234     if not args:
235     parser.error('no variable specified')
236    
237    
238     for variable in args:
239     if variable not in variables:
240     parser.error('unknown variable: "%s"' % variable)
241    
242     for variable in args:
243 douglas 681 exec 'print %s' % variable

Properties

Name Value
svn:executable *
svn:keywords Id