forked from public/pyceo
Add mysql database stuff
This commit is contained in:
parent
827c17b107
commit
2552bc2243
|
@ -1,3 +1,5 @@
|
||||||
/build-stamp
|
/build-stamp
|
||||||
/build
|
/build
|
||||||
*.pyc
|
*.pyc
|
||||||
|
/build-ceo
|
||||||
|
/build-ceod
|
||||||
|
|
|
@ -91,6 +91,11 @@ def connect(auth_callback):
|
||||||
if password == None:
|
if password == None:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
def connect_anonymous():
|
||||||
|
"""Connect to LDAP."""
|
||||||
|
|
||||||
|
global ld
|
||||||
|
ld = ldap.initialize(cfg['ldap_server_url'])
|
||||||
|
|
||||||
def disconnect():
|
def disconnect():
|
||||||
"""Disconnect from LDAP."""
|
"""Disconnect from LDAP."""
|
||||||
|
|
|
@ -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
|
import urwid
|
||||||
from ceo import members
|
from ceo import members, mysql
|
||||||
from ceo.urwid import search
|
from ceo.urwid import search
|
||||||
from ceo.urwid.widgets import *
|
from ceo.urwid.widgets import *
|
||||||
from ceo.urwid.window import *
|
from ceo.urwid.window import *
|
||||||
|
|
||||||
def databases(menu):
|
class IntroPage(WizardPanel):
|
||||||
menu = make_menu([
|
def init_widgets(self):
|
||||||
("Create MySQL database", create_mysql_db, None),
|
self.widgets = [
|
||||||
("Back", raise_back, None),
|
urwid.Text("MySQL databases"),
|
||||||
])
|
urwid.Divider(),
|
||||||
push_window(menu, "Databases")
|
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):
|
class UserPage(WizardPanel):
|
||||||
pass
|
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()
|
||||||
|
|
|
@ -143,6 +143,13 @@ def change_shell(data):
|
||||||
shell.EndPage
|
shell.EndPage
|
||||||
], (50, 20))
|
], (50, 20))
|
||||||
|
|
||||||
|
def create_mysql_db(data):
|
||||||
|
push_wizard("Create MySQL database", [
|
||||||
|
databases.IntroPage,
|
||||||
|
databases.UserPage,
|
||||||
|
databases.EndPage,
|
||||||
|
], (60, 15))
|
||||||
|
|
||||||
def check_group(group):
|
def check_group(group):
|
||||||
try:
|
try:
|
||||||
me = pwd.getpwuid(os.getuid()).pw_name
|
me = pwd.getpwuid(os.getuid()).pw_name
|
||||||
|
@ -158,7 +165,6 @@ def top_menu():
|
||||||
("Renew Club Rep", renew_club_user, None),
|
("Renew Club Rep", renew_club_user, None),
|
||||||
("New Club", new_club, None),
|
("New Club", new_club, None),
|
||||||
("Library", library.library, None),
|
("Library", library.library, None),
|
||||||
("Databases", databases.databases, None),
|
|
||||||
]
|
]
|
||||||
syscom_only = [
|
syscom_only = [
|
||||||
("Manage Club or Group Members", manage_group, None),
|
("Manage Club or Group Members", manage_group, None),
|
||||||
|
@ -168,8 +174,9 @@ def top_menu():
|
||||||
]
|
]
|
||||||
unrestricted = [
|
unrestricted = [
|
||||||
("Display Member", display_member, None),
|
("Display Member", display_member, None),
|
||||||
("Change Shell", change_shell, None),
|
|
||||||
("Search", search_members, None),
|
("Search", search_members, None),
|
||||||
|
("Change Shell", change_shell, None),
|
||||||
|
("Create MySQL database", create_mysql_db, None),
|
||||||
]
|
]
|
||||||
footer = [
|
footer = [
|
||||||
("Exit", raise_abort, None),
|
("Exit", raise_abort, None),
|
||||||
|
|
|
@ -29,7 +29,7 @@ Description: Computer Science Club Administrative Clients
|
||||||
|
|
||||||
Package: ceo-daemon
|
Package: ceo-daemon
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ceo-python, ${shlibs:Depends}
|
Depends: ceo-python, ${python:Depends}, ${shlibs:Depends}
|
||||||
Description: Computer Science Club Administrative Daemon
|
Description: Computer Science Club Administrative Daemon
|
||||||
This package contains the CSC Electronic Office
|
This package contains the CSC Electronic Office
|
||||||
daemon.
|
daemon.
|
||||||
|
|
|
@ -4,7 +4,6 @@ CFLAGS := -g -O2 -fstack-protector-all -fPIE
|
||||||
LDFLAGS := -pie -Wl,--as-needed
|
LDFLAGS := -pie -Wl,--as-needed
|
||||||
|
|
||||||
build:
|
build:
|
||||||
python setup.py -q build
|
|
||||||
cd src && make CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)"
|
cd src && make CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
@ -12,13 +11,17 @@ clean:
|
||||||
dh_testroot
|
dh_testroot
|
||||||
dh_clean
|
dh_clean
|
||||||
$(MAKE) -C src clean
|
$(MAKE) -C src clean
|
||||||
python setup.py -q clean -a
|
python setup.py -q clean -a --build-base=build-ceo
|
||||||
|
python setupd.py -q clean -a --build-base=build-ceod
|
||||||
|
rm -rf build-ceo build-ceod
|
||||||
|
|
||||||
install: build
|
install: build
|
||||||
dh_testdir
|
dh_testdir
|
||||||
dh_testroot
|
dh_testroot
|
||||||
dh_installdirs
|
dh_installdirs
|
||||||
python setup.py -q install --no-compile -O0 --prefix=/usr --root=debian/ceo-python
|
python setup.py -q build --build-base=build-ceo install --no-compile -O0 --prefix=/usr --root=debian/ceo-python
|
||||||
|
python setupd.py -q build --build-base=build-ceod install --no-compile -O0 --prefix=/usr --root=debian/ceo-daemon \
|
||||||
|
--install-scripts=/usr/lib/ceod
|
||||||
$(MAKE) -C src DESTDIR=$(CURDIR)/debian/ceo-clients PREFIX=/usr install_clients
|
$(MAKE) -C src DESTDIR=$(CURDIR)/debian/ceo-clients PREFIX=/usr install_clients
|
||||||
$(MAKE) -C src DESTDIR=$(CURDIR)/debian/ceo-daemon PREFIX=/usr install_daemon
|
$(MAKE) -C src DESTDIR=$(CURDIR)/debian/ceo-daemon PREFIX=/usr install_daemon
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -35,6 +35,7 @@ all: $(BIN_PROGS) $(LIB_PROGS) $(EXT_PROGS) ../ceo/ceo_pb2.py
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(BIN_PROGS) $(LIB_PROGS) $(EXT_PROGS) *.o ceo.pb-c.c ceo.pb-c.h
|
rm -f $(BIN_PROGS) $(LIB_PROGS) $(EXT_PROGS) *.o ceo.pb-c.c ceo.pb-c.h
|
||||||
|
rm -f ceo_pb2.py ../ceo/ceo_pb2.py
|
||||||
|
|
||||||
op-adduser.o addmember.o addclub.o: ceo.pb-c.h
|
op-adduser.o addmember.o addclub.o: ceo.pb-c.h
|
||||||
|
|
||||||
|
|
|
@ -31,3 +31,12 @@ message UpdateMail {
|
||||||
message UpdateMailResponse {
|
message UpdateMailResponse {
|
||||||
repeated StatusMessage messages = 1;
|
repeated StatusMessage messages = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message AddMySQLUser {
|
||||||
|
required string username = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddMySQLUserResponse {
|
||||||
|
repeated StatusMessage messages = 1;
|
||||||
|
optional string password = 2;
|
||||||
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ static void handle_op_message(uint32_t in_type, struct strbuf *in, struct strbuf
|
||||||
"CEO_CONFIG_DIR", config_dir, NULL);
|
"CEO_CONFIG_DIR", config_dir, NULL);
|
||||||
char *argv[] = { op->path, NULL, };
|
char *argv[] = { op->path, NULL, };
|
||||||
|
|
||||||
if (spawnvem(op->path, argv, envp, in, out, 0))
|
if (spawnvemu(op->path, argv, envp, in, out, 0, op->user))
|
||||||
fatal("child %s failed", op->path);
|
fatal("child %s failed", op->path);
|
||||||
|
|
||||||
if (!out->len)
|
if (!out->len)
|
||||||
|
|
|
@ -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()
|
21
src/ops.c
21
src/ops.c
|
@ -3,6 +3,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
#include "ops.h"
|
#include "ops.h"
|
||||||
|
@ -15,13 +16,14 @@ static struct op *ops;
|
||||||
static const char *default_op_dir = "/usr/lib/ceod";
|
static const char *default_op_dir = "/usr/lib/ceod";
|
||||||
static const char *op_dir;
|
static const char *op_dir;
|
||||||
|
|
||||||
static void add_op(char *host, char *name, uint32_t id) {
|
static void add_op(char *host, char *name, char *user, uint32_t id) {
|
||||||
struct op *new = xmalloc(sizeof(struct op));
|
struct op *new = xmalloc(sizeof(struct op));
|
||||||
errno = 0;
|
errno = 0;
|
||||||
new->next = ops;
|
new->next = ops;
|
||||||
new->name = xstrdup(name);
|
new->name = xstrdup(name);
|
||||||
new->id = id;
|
new->id = id;
|
||||||
new->path = NULL;
|
new->path = NULL;
|
||||||
|
new->user = xstrdup(user);
|
||||||
|
|
||||||
struct hostent *hostent = gethostbyname(host);
|
struct hostent *hostent = gethostbyname(host);
|
||||||
if (!hostent)
|
if (!hostent)
|
||||||
|
@ -35,11 +37,15 @@ static void add_op(char *host, char *name, uint32_t id) {
|
||||||
sprintf(new->path, "%s/op-%s", op_dir, name);
|
sprintf(new->path, "%s/op-%s", op_dir, name);
|
||||||
if (access(new->path, X_OK))
|
if (access(new->path, X_OK))
|
||||||
fatalpe("cannot add op: %s: %s", name, new->path);
|
fatalpe("cannot add op: %s: %s", name, new->path);
|
||||||
|
|
||||||
|
struct passwd *pw = getpwnam(user);
|
||||||
|
if (!pw)
|
||||||
|
fatalpe("cannot add op %s: getpwnam: %s", name, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
ops = new;
|
ops = new;
|
||||||
debug("added op %s (%s%s)", new->name, new->local ? "" : "on ",
|
debug("added op %s (%s%s) [%s]", new->name, new->local ? "" : "on ",
|
||||||
new->local ? "local" : host);
|
new->local ? "local" : host, new->user);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct op *get_local_op(uint32_t id) {
|
struct op *get_local_op(uint32_t id) {
|
||||||
|
@ -88,16 +94,16 @@ void setup_ops(void) {
|
||||||
|
|
||||||
struct strbuf **words = strbuf_splitws(&line);
|
struct strbuf **words = strbuf_splitws(&line);
|
||||||
|
|
||||||
if (strbuf_list_len(words) != 3)
|
if (strbuf_list_len(words) != 4)
|
||||||
badconf("%s/%s: expected three words on line %d", op_config_dir, de->d_name, lineno);
|
badconf("%s/%s: expected four words on line %d", op_config_dir, de->d_name, lineno);
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
char *end;
|
char *end;
|
||||||
int id = strtol(words[2]->buf, &end, 0);
|
int id = strtol(words[3]->buf, &end, 0);
|
||||||
if (errno || *end)
|
if (errno || *end)
|
||||||
badconf("%s/%s: invalid id '%s' on line %d", op_config_dir, de->d_name, words[2]->buf, lineno);
|
badconf("%s/%s: invalid id '%s' on line %d", op_config_dir, de->d_name, words[2]->buf, lineno);
|
||||||
|
|
||||||
add_op(words[0]->buf, words[1]->buf, id);
|
add_op(words[0]->buf, words[1]->buf, words[2]->buf, id);
|
||||||
op_count++;
|
op_count++;
|
||||||
|
|
||||||
strbuf_list_free(words);
|
strbuf_list_free(words);
|
||||||
|
@ -115,6 +121,7 @@ void free_ops(void) {
|
||||||
free(ops->name);
|
free(ops->name);
|
||||||
free(ops->hostname);
|
free(ops->hostname);
|
||||||
free(ops->path);
|
free(ops->path);
|
||||||
|
free(ops->user);
|
||||||
free(ops);
|
free(ops);
|
||||||
ops = next;
|
ops = next;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ struct op {
|
||||||
char *path;
|
char *path;
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
struct op *next;
|
struct op *next;
|
||||||
|
char *user;
|
||||||
};
|
};
|
||||||
|
|
||||||
void setup_ops(void);
|
void setup_ops(void);
|
||||||
|
|
17
src/util.c
17
src/util.c
|
@ -8,6 +8,7 @@
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
|
@ -173,6 +174,10 @@ void full_write(int fd, const void *buf, size_t count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int spawnvem(const char *path, char *const *argv, char *const *envp, const struct strbuf *output, struct strbuf *input, int cap_stderr) {
|
int spawnvem(const char *path, char *const *argv, char *const *envp, const struct strbuf *output, struct strbuf *input, int cap_stderr) {
|
||||||
|
return spawnvemu(path, argv, envp, output, input, cap_stderr, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawnvemu(const char *path, char *const *argv, char *const *envp, const struct strbuf *output, struct strbuf *input, int cap_stderr, char *user) {
|
||||||
int pid, wpid, status;
|
int pid, wpid, status;
|
||||||
int tochild[2];
|
int tochild[2];
|
||||||
int fmchild[2];
|
int fmchild[2];
|
||||||
|
@ -197,6 +202,18 @@ int spawnvem(const char *path, char *const *argv, char *const *envp, const struc
|
||||||
close(tochild[1]);
|
close(tochild[1]);
|
||||||
close(fmchild[0]);
|
close(fmchild[0]);
|
||||||
close(fmchild[1]);
|
close(fmchild[1]);
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
struct passwd *pw = getpwnam(user);
|
||||||
|
if (!pw)
|
||||||
|
fatalpe("getpwnam: %s", user);
|
||||||
|
if (initgroups(user, pw->pw_gid))
|
||||||
|
fatalpe("initgroups: %s", user);
|
||||||
|
if (setregid(pw->pw_gid, pw->pw_gid))
|
||||||
|
fatalpe("setregid: %s", user);
|
||||||
|
if (setreuid(pw->pw_uid, pw->pw_uid))
|
||||||
|
fatalpe("setreuid");
|
||||||
|
}
|
||||||
execve(path, argv, envp);
|
execve(path, argv, envp);
|
||||||
fatalpe("execve");
|
fatalpe("execve");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,6 +28,7 @@ extern char **environ;
|
||||||
int spawnv(const char *path, char *const *argv);
|
int spawnv(const char *path, char *const *argv);
|
||||||
int spawnv_msg(const char *path, char *const *argv, const struct strbuf *output);
|
int spawnv_msg(const char *path, char *const *argv, const struct strbuf *output);
|
||||||
int spawnvem(const char *path, char *const *argv, char *const *envp, const struct strbuf *output, struct strbuf *input, int cap_stderr);
|
int spawnvem(const char *path, char *const *argv, char *const *envp, const struct strbuf *output, struct strbuf *input, int cap_stderr);
|
||||||
|
int spawnvemu(const char *path, char *const *argv, char *const *envp, const struct strbuf *output, struct strbuf *input, int cap_stderr, char *user);
|
||||||
void full_write(int fd, const void *buf, size_t count);
|
void full_write(int fd, const void *buf, size_t count);
|
||||||
ssize_t full_read(int fd, void *buf, size_t len);
|
ssize_t full_read(int fd, void *buf, size_t len);
|
||||||
FILE *fopenat(DIR *d, const char *path, int flags);
|
FILE *fopenat(DIR *d, const char *path, int flags);
|
||||||
|
|
Loading…
Reference in New Issue