parent
827c17b107
commit
2552bc2243
@ -1,3 +1,5 @@ |
||||
/build-stamp |
||||
/build |
||||
*.pyc |
||||
/build-ceo |
||||
/build-ceod |
||||
|
@ -0,0 +1,24 @@ |
||||
import os, re, subprocess, ldap, socket |
||||
from ceo import conf, ldapi, terms, remote, ceo_pb2 |
||||
from ceo.excep import InvalidArgument |
||||
|
||||
class MySQLException(Exception): |
||||
pass |
||||
|
||||
def create_mysql(username): |
||||
try: |
||||
request = ceo_pb2.AddMySQLUser() |
||||
request.username = username |
||||
|
||||
out = remote.run_remote('mysql', request.SerializeToString()) |
||||
|
||||
response = ceo_pb2.AddMySQLUserResponse() |
||||
response.ParseFromString(out) |
||||
|
||||
if any(message.status != 0 for message in response.messages): |
||||
raise MySQLException('\n'.join(message.message for message in response.messages)) |
||||
|
||||
return response.password |
||||
except remote.RemoteException, e: |
||||
raise MySQLException(e) |
||||
|
@ -1,15 +1,78 @@ |
||||
import urwid |
||||
from ceo import members |
||||
from ceo import members, mysql |
||||
from ceo.urwid import search |
||||
from ceo.urwid.widgets import * |
||||
from ceo.urwid.window import * |
||||
|
||||
def databases(menu): |
||||
menu = make_menu([ |
||||
("Create MySQL database", create_mysql_db, None), |
||||
("Back", raise_back, None), |
||||
]) |
||||
push_window(menu, "Databases") |
||||
class IntroPage(WizardPanel): |
||||
def init_widgets(self): |
||||
self.widgets = [ |
||||
urwid.Text("MySQL databases"), |
||||
urwid.Divider(), |
||||
urwid.Text("Members and hosted clubs may have one MySQL database each. You may " |
||||
"create a database for an account if: \n" |
||||
"\n" |
||||
"- It is your personal account,\n" |
||||
"- It is a club account, and you are in the club group, or\n" |
||||
"- You are on the CSC systems committee\n" |
||||
"\n" |
||||
"You may also use this to reset your database password." |
||||
) |
||||
] |
||||
def focusable(self): |
||||
return False |
||||
|
||||
def create_mysql_db(data): |
||||
pass |
||||
class UserPage(WizardPanel): |
||||
def init_widgets(self): |
||||
self.userid = LdapWordEdit(csclub_uri, csclub_base, 'uid', |
||||
"Username: ") |
||||
|
||||
self.widgets = [ |
||||
urwid.Text("Member Information"), |
||||
urwid.Divider(), |
||||
urwid.Text("Enter the user which will own the new database."), |
||||
urwid.Divider(), |
||||
self.userid, |
||||
] |
||||
def check(self): |
||||
self.state['userid'] = self.userid.get_edit_text() |
||||
self.state['member'] = None |
||||
if self.state['userid']: |
||||
self.state['member'] = members.get(self.userid.get_edit_text()) |
||||
if not self.state['member']: |
||||
set_status("Member not found") |
||||
self.focus_widget(self.userid) |
||||
return True |
||||
|
||||
class EndPage(WizardPanel): |
||||
def init_widgets(self): |
||||
self.headtext = urwid.Text("") |
||||
self.midtext = urwid.Text("") |
||||
|
||||
self.widgets = [ |
||||
self.headtext, |
||||
urwid.Divider(), |
||||
self.midtext, |
||||
] |
||||
def focusable(self): |
||||
return False |
||||
def activate(self): |
||||
problem = None |
||||
try: |
||||
password = mysql.create_mysql(self.state['userid']) |
||||
self.headtext.set_text("MySQL database created") |
||||
self.midtext.set_text("Connection Information: \n" |
||||
"\n" |
||||
"Database: %s\n" |
||||
"Username: %s\n" |
||||
"Hostname: localhost\n" |
||||
"Password: %s\n" |
||||
"\n" |
||||
"Note: Databases are only accessible from caffeine\n" |
||||
% (self.state['userid'], self.state['userid'], password)) |
||||
except mysql.MySQLException, e: |
||||
self.headtext.set_text("Failed to create MySQL database") |
||||
self.midtext.set_text("We failed to create the database. The error was:\n\n%s" % e) |
||||
|
||||
def check(self): |
||||
pop_window() |
||||
|
@ -1 +1 @@ |
||||
ginseng adduser 0x01 |
||||
ginseng adduser root 0x01 |
||||
|
@ -1 +1 @@ |
||||
ginseng mail 0x02 |
||||
ginseng mail root 0x02 |
||||
|
@ -0,0 +1 @@ |
||||
caffeine mysql mysql 0x03 |
@ -0,0 +1,113 @@ |
||||
#!/usr/bin/python |
||||
|
||||
import os, sys, string, random, syslog, grp, errno, re |
||||
from ceo import ceo_pb2, members, conf |
||||
import MySQLdb |
||||
|
||||
CONFIG_FILE = '/etc/csc/mysql.cf' |
||||
|
||||
cfg = {} |
||||
|
||||
def configure(): |
||||
string_fields = ['mysql_admin_username', 'mysql_admin_password'] |
||||
|
||||
# read configuration file |
||||
cfg_tmp = conf.read(CONFIG_FILE) |
||||
|
||||
# verify configuration |
||||
conf.check_string_fields(CONFIG_FILE, string_fields, cfg_tmp) |
||||
|
||||
# update the current configuration with the loaded values |
||||
cfg.update(cfg_tmp) |
||||
|
||||
def response_message(response, status, message): |
||||
priority = syslog.LOG_ERR if status else syslog.LOG_INFO |
||||
syslog.syslog(priority, message) |
||||
msg = response.messages.add() |
||||
msg.status = status |
||||
msg.message = message |
||||
return status |
||||
|
||||
def random_password(): |
||||
chars = string.letters + string.digits |
||||
return ''.join(random.choice(chars) for i in xrange(20)) |
||||
|
||||
def get_ceo_user(): |
||||
user = os.environ.get('CEO_USER') |
||||
if not user: |
||||
raise Exception("environment variable CEO_USER not set"); |
||||
return user |
||||
|
||||
def check_group(user, group): |
||||
try: |
||||
return user in grp.getgrnam(group).gr_mem |
||||
except KeyError: |
||||
return False |
||||
|
||||
def check_auth(remote_user, mysql_user, response): |
||||
if remote_user == mysql_user: |
||||
return response_message(response, 0, 'user %s creating database for self' % remote_user) |
||||
club = members.get(mysql_user) |
||||
if 'club' in club.get('objectClass', []): |
||||
if check_group(remote_user, mysql_user): |
||||
return response_message(response, 0, 'user %s is in club group %s' % (remote_user, mysql_user)) |
||||
else: |
||||
return response_message(response, errno.EPERM, 'denied, user %s is not in club group %s' % (remote_user, mysql_user)) |
||||
if check_group(remote_user, 'syscom'): |
||||
return response_message(response, 0, 'user %s is on systems committee' % remote_user) |
||||
else: |
||||
return response_message(response, errno.EPERM, 'denied, you may not create databases for other members') |
||||
|
||||
def mysql_createdb(remote_user, mysql_user, response): |
||||
if check_auth(remote_user, mysql_user, response): |
||||
return |
||||
|
||||
response.password = random_password() |
||||
|
||||
if not re.match('^[a-zA-Z0-9-]+$', mysql_user): |
||||
response_message(response, errno.EINVAL, 'invalid characters in username %s' % mysql_user) |
||||
return |
||||
|
||||
if not re.match('^[a-zA-Z0-9-]+$', response.password): |
||||
response_message(response, errno.EINVAL, 'invalid characters in password %s' % response.password) |
||||
return |
||||
|
||||
try: |
||||
connection = MySQLdb.Connect(user=cfg['mysql_admin_username'], passwd=cfg['mysql_admin_password']) |
||||
cursor = connection.cursor() |
||||
cursor.execute("GRANT ALL PRIVILEGES ON `%s`.* TO `%s`@`localhost` IDENTIFIED BY '%s'" |
||||
% (mysql_user, mysql_user, response.password)) |
||||
cursor.execute("CREATE DATABASE IF NOT EXISTS `%s`" % mysql_user) |
||||
cursor.close() |
||||
connection.close() |
||||
|
||||
response_message(response, 0, 'successfully created database %s' % mysql_user) |
||||
except MySQLdb.MySQLError, e: |
||||
response_message(response, 1, 'exception occured creating database: %s' % e) |
||||
|
||||
|
||||
def mysql_op(): |
||||
input = sys.stdin.read() |
||||
|
||||
request = ceo_pb2.AddMySQLUser() |
||||
request.ParseFromString(input) |
||||
|
||||
remote_user = get_ceo_user() |
||||
mysql_user = request.username |
||||
|
||||
response = ceo_pb2.AddMySQLUserResponse() |
||||
response_message(response, 0, 'mysql create db=%s by %s' % (mysql_user, remote_user)) |
||||
|
||||
mysql_createdb(remote_user, mysql_user, response) |
||||
|
||||
sys.stdout.write(response.SerializeToString()) |
||||
|
||||
def main(): |
||||
configure() |
||||
members.configure() |
||||
members.connect_anonymous() |
||||
syslog.openlog('op-mysql', syslog.LOG_PID, syslog.LOG_DAEMON) |
||||
mysql_op() |
||||
|
||||
if __name__ == '__main__': |
||||
main() |
Loading…
Reference in new issue