ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/ccs/admin/admin.py
Revision: 687
Committed: 2010-07-18T03:39:30-07:00 (14 years, 11 months ago) by douglas
Content type: text/x-python
File size: 6690 byte(s)
Log Message:
Use optparse instead of argparse. Man pages!

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

Properties

Name Value
svn:executable *
svn:keywords Id