Add mysql database stuff
[public/pyceo-broken.git] / src / op-mysql
1 #!/usr/bin/python
2
3 import os, sys, string, random, syslog, grp, errno, re
4 from ceo import ceo_pb2, members, conf
5 import MySQLdb
6
7 CONFIG_FILE = '/etc/csc/mysql.cf'
8
9 cfg = {}
10
11 def configure():
12     string_fields = ['mysql_admin_username', 'mysql_admin_password']
13
14     # read configuration file
15     cfg_tmp = conf.read(CONFIG_FILE)
16
17     # verify configuration
18     conf.check_string_fields(CONFIG_FILE, string_fields, cfg_tmp)
19
20     # update the current configuration with the loaded values
21     cfg.update(cfg_tmp)
22
23 def response_message(response, status, message):
24     priority = syslog.LOG_ERR if status else syslog.LOG_INFO
25     syslog.syslog(priority, message)
26     msg = response.messages.add()
27     msg.status = status
28     msg.message = message
29     return status
30
31 def random_password():
32     chars = string.letters + string.digits
33     return ''.join(random.choice(chars) for i in xrange(20))
34
35 def get_ceo_user():
36     user = os.environ.get('CEO_USER')
37     if not user:
38         raise Exception("environment variable CEO_USER not set");
39     return user
40
41 def check_group(user, group):
42     try:
43         return user in grp.getgrnam(group).gr_mem
44     except KeyError:
45         return False
46
47 def check_auth(remote_user, mysql_user, response):
48     if remote_user == mysql_user:
49         return response_message(response, 0, 'user %s creating database for self' % remote_user)
50     club = members.get(mysql_user)
51     if 'club' in club.get('objectClass', []):
52         if check_group(remote_user, mysql_user):
53             return response_message(response, 0, 'user %s is in club group %s' % (remote_user, mysql_user))
54         else:
55             return response_message(response, errno.EPERM, 'denied, user %s is not in club group %s' % (remote_user, mysql_user))
56     if check_group(remote_user, 'syscom'):
57         return response_message(response, 0, 'user %s is on systems committee' % remote_user)
58     else:
59         return response_message(response, errno.EPERM, 'denied, you may not create databases for other members')
60
61 def mysql_createdb(remote_user, mysql_user, response):
62     if check_auth(remote_user, mysql_user, response):
63         return
64
65     response.password = random_password()
66
67     if not re.match('^[a-zA-Z0-9-]+$', mysql_user):
68         response_message(response, errno.EINVAL, 'invalid characters in username %s' % mysql_user)
69         return
70
71     if not re.match('^[a-zA-Z0-9-]+$', response.password):
72         response_message(response, errno.EINVAL, 'invalid characters in password %s' % response.password)
73         return
74
75     try:
76         connection = MySQLdb.Connect(user=cfg['mysql_admin_username'], passwd=cfg['mysql_admin_password'])
77         cursor = connection.cursor()
78         cursor.execute("GRANT ALL PRIVILEGES ON `%s`.* TO `%s`@`localhost` IDENTIFIED BY '%s'"
79                        % (mysql_user, mysql_user, response.password))
80         cursor.execute("CREATE DATABASE IF NOT EXISTS `%s`" % mysql_user)
81         cursor.close()
82         connection.close()
83
84         response_message(response, 0, 'successfully created database %s' % mysql_user)
85     except MySQLdb.MySQLError, e:
86         response_message(response, 1, 'exception occured creating database: %s' % e)
87
88
89 def mysql_op():
90     input = sys.stdin.read()
91
92     request = ceo_pb2.AddMySQLUser()
93     request.ParseFromString(input)
94
95     remote_user = get_ceo_user()
96     mysql_user = request.username
97
98     response = ceo_pb2.AddMySQLUserResponse()
99     response_message(response, 0, 'mysql create db=%s by %s' % (mysql_user, remote_user))
100
101     mysql_createdb(remote_user, mysql_user, response)
102
103     sys.stdout.write(response.SerializeToString())
104
105 def main():
106     configure()
107     members.configure()
108     members.connect_anonymous()
109     syslog.openlog('op-mysql', syslog.LOG_PID, syslog.LOG_DAEMON)
110     mysql_op()
111
112 if __name__ == '__main__':
113     main()