b6001cdb0b
* Use Privs module functions for Bongo user.
261 lines
6.4 KiB
Python
261 lines
6.4 KiB
Python
###
|
|
# Configure slapd for embedded use
|
|
#
|
|
|
|
import base64
|
|
import logging
|
|
import os
|
|
import pwd
|
|
import random
|
|
import sha
|
|
import signal
|
|
import socket
|
|
import string
|
|
import sys
|
|
import time
|
|
|
|
from bongo import Xpl, Privs
|
|
from bongo.Console import wrap
|
|
|
|
log = logging.getLogger("managed-slapd")
|
|
|
|
class NullStream:
|
|
"""A substitute for stdout and stderr that writes to nowhere"""
|
|
def write(self, s):
|
|
pass
|
|
|
|
class ConfigSlapd:
|
|
def __init__(self, schemaFile, slapdPath, slapdPort, adminRootpw):
|
|
self.schemaFile = schemaFile
|
|
self.binary = slapdPath
|
|
self.port = slapdPort
|
|
|
|
self.sysschemadir = Xpl.DEFAULT_SLAPD_SCHEMA_DIR
|
|
|
|
self.suffix = "dc=example,dc=com"
|
|
self.rootdn = "cn=admin," + self.suffix
|
|
self.root = "\\com\\example\\admin"
|
|
self.password = adminRootpw
|
|
self.slapdPid = None
|
|
self.slapdPidFile = Xpl.DEFAULT_WORK_DIR + "/bongo-slapd.pid"
|
|
|
|
if not os.path.exists(Xpl.DEFAULT_WORK_DIR):
|
|
os.makedirs(Xpl.DEFAULT_WORK_DIR)
|
|
Privs.Chown(Xpl.DEFAULT_WORK_DIR)
|
|
|
|
def slapdRunning(self, port):
|
|
s = socket.socket()
|
|
if s.connect_ex(("127.0.0.1", port)) != 0:
|
|
return False
|
|
s.close()
|
|
|
|
if not os.path.exists(self.slapdPidFile):
|
|
print wrap("Slapd is running, but its pid file doesn't exist. You may need to kill slapd manually.")
|
|
return None
|
|
|
|
return True
|
|
|
|
def readPidFile(self, pidFile):
|
|
f = open(pidFile, 'r')
|
|
line = f.readline()
|
|
f.close()
|
|
|
|
return int(line)
|
|
|
|
def preDaemonize(self):
|
|
os.chdir("/")
|
|
os.setsid()
|
|
os.umask(0)
|
|
|
|
sys.stdin.close()
|
|
sys.stdout = NullStream()
|
|
sys.stderr = NullStream()
|
|
|
|
for fd in range(3, 256):
|
|
try:
|
|
os.close(fd)
|
|
except:
|
|
pass
|
|
|
|
def encodePassword(self, password):
|
|
salt = ""
|
|
for i in range(1, 10):
|
|
salt = salt + random.choice(string.ascii_letters + string.digits)
|
|
|
|
ctx = sha.new(password)
|
|
ctx.update(salt)
|
|
|
|
enc = base64.encodestring(ctx.digest() + salt)
|
|
return "{SSHA}" + enc.strip()
|
|
|
|
def startSlapd(self, confFile):
|
|
if not os.path.exists(self.binary):
|
|
print "Slapd path doesn't exist: %s" % self.binary
|
|
return None
|
|
|
|
tmp = self.slapdRunning(self.port)
|
|
if tmp is None:
|
|
return None
|
|
|
|
if tmp:
|
|
print "Found an existing slapd on port %d, using that" % self.port
|
|
return 0
|
|
|
|
print "Starting temporary slapd process"
|
|
|
|
pid = os.fork()
|
|
|
|
if not pid:
|
|
args = [self.binary,
|
|
"-f", confFile,
|
|
"-h", "ldap://127.0.0.1:%d" % self.port,
|
|
"-n", "bongo-slapd"]
|
|
if Privs.HaveBongoUser():
|
|
args.extend(("-u", Xpl.BONGO_USER))
|
|
|
|
self.preDaemonize()
|
|
|
|
log.debug("starting managed slapd: %s", " ".join(args))
|
|
|
|
os.execv(self.binary, args)
|
|
sys.exit(1)
|
|
|
|
pid, status = os.waitpid(pid, 0)
|
|
|
|
if (status >> 8) != 0:
|
|
return None
|
|
|
|
while True:
|
|
running = self.slapdRunning(self.port)
|
|
if running is None:
|
|
# slapd started, but is unusable
|
|
return None
|
|
if running is True:
|
|
break
|
|
time.sleep(1)
|
|
|
|
pid = self.slapdPid = self.readPidFile(self.slapdPidFile)
|
|
return pid
|
|
|
|
def killSlapd(self):
|
|
if self.slapdPid:
|
|
print "Shutting down temporary slapd process"
|
|
os.kill(self.slapdPid, signal.SIGTERM)
|
|
|
|
# wait until it has exited before continuing
|
|
while True:
|
|
try:
|
|
os.kill(self.slapdPid, 0)
|
|
time.sleep(1)
|
|
except OSError:
|
|
break
|
|
|
|
self.slapdPid = None
|
|
|
|
def initSlapd(self, confFile):
|
|
if not os.path.exists(self.binary):
|
|
print "Slapd path doesn't exist: %s" % self.binary
|
|
return None
|
|
|
|
readfd, writefd = os.pipe()
|
|
|
|
pid = os.fork()
|
|
|
|
if not pid:
|
|
Privs.DropPrivs()
|
|
os.close(writefd)
|
|
os.dup2(readfd, sys.stdin.fileno())
|
|
sys.stdin.close()
|
|
|
|
args = ["slapadd",
|
|
"-f", confFile]
|
|
|
|
os.execv(self.binary, args)
|
|
sys.exit(1)
|
|
|
|
os.close(readfd)
|
|
|
|
os.write(writefd, """\
|
|
dn: %(suffix)s
|
|
objectClass: dcObject
|
|
objectClass: organization
|
|
o: Example, Inc.
|
|
dc: example
|
|
|
|
dn: %(rootdn)s
|
|
cn: admin
|
|
objectClass: inetOrgPerson
|
|
sn: Admin
|
|
userPassword: %(userpw)s
|
|
""" % {"suffix" : self.suffix, "rootdn" : self.rootdn,
|
|
"userpw" : self.encodePassword("bongo")})
|
|
|
|
os.close(writefd)
|
|
|
|
pid, status = os.waitpid(pid, 0)
|
|
|
|
if (status >> 8) != 0:
|
|
return None
|
|
|
|
return pid
|
|
|
|
def writeSlapdConf(self, file, writeRootpw=True):
|
|
ldapdir = "%s/ldap" % Xpl.DEFAULT_STATE_DIR
|
|
|
|
if not os.path.exists(ldapdir):
|
|
os.makedirs(ldapdir)
|
|
|
|
Privs.Chown(ldapdir)
|
|
|
|
for file in os.listdir(ldapdir):
|
|
Privs.Chown(os.path.join(ldapdir, file))
|
|
|
|
config = """\
|
|
include %(sysschemadir)s/core.schema
|
|
include %(sysschemadir)s/cosine.schema
|
|
include %(sysschemadir)s/inetorgperson.schema
|
|
include %(schema)s
|
|
|
|
%(moduleload)s
|
|
database bdb
|
|
directory %(ldapdir)s
|
|
suffix %(suffix)s
|
|
rootdn %(rootdn)s
|
|
%(rootpw)s
|
|
|
|
pidfile %(pidfile)s
|
|
|
|
index objectClass eq
|
|
lastmod on
|
|
|
|
access to attrs=userPassword
|
|
by dn="%(rootdn)s" write
|
|
by anonymous auth
|
|
by self write
|
|
by * none
|
|
access to dn.base="" by * read
|
|
access to *
|
|
by dn="%(rootdn)s" write
|
|
by dn="ou=Bongo Messaging Server,o=Bongo Services,%(suffix)s" write
|
|
by * read
|
|
"""
|
|
opts = {"schema" : self.schemaFile,
|
|
"sysschemadir" : self.sysschemadir,
|
|
"ldapdir" : ldapdir,
|
|
"pidfile" : self.slapdPidFile,
|
|
"suffix" : self.suffix,
|
|
"rootdn" : self.rootdn,
|
|
"moduleload" : "",
|
|
"rootpw" : ""}
|
|
|
|
if writeRootpw:
|
|
opts["rootpw"] = "rootpw " + self.encodePassword(self.password)
|
|
|
|
# quick fix for ubuntu
|
|
if os.path.exists("/usr/lib/ldap/back_bdb.so"):
|
|
opts["moduleload"] = "moduleload /usr/lib/ldap/back_bdb.so"
|
|
|
|
fd = open(file, "w")
|
|
fd.write(config % opts)
|
|
fd.close()
|