mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2026-10-13 17:02:02 -05:00
Merge from upstream
This commit is contained in:
commit
96d292b735
49 files changed
+2110
-79
No files matched your search
@@ -0,0 +1,104 @@
|
||||
SUBDIRS=ipa-server ipa-admintools ipa-python
|
||||
|
||||
PRJ_PREFIX=freeipa
|
||||
|
||||
# Version numbers - this is for the entire server. After
|
||||
# updating this you should run the version-update
|
||||
# target.
|
||||
SERV_MAJOR=0
|
||||
SERV_MINOR=1
|
||||
SERV_RELEASE=0
|
||||
SERV_VERSION=$(SERV_MAJOR).$(SERV_MINOR).$(SERV_RELEASE)
|
||||
SERV_TARBALL_PREFIX=$(PRJ_PREFIX)-server-$(SERV_VERSION)
|
||||
SERV_TARBALL=$(SERV_TARBALL_PREFIX).tgz
|
||||
|
||||
ADMIN_MAJOR=0
|
||||
ADMIN_MINOR=1
|
||||
ADMIN_RELEASE=0
|
||||
ADMIN_VERSION=$(ADMIN_MAJOR).$(ADMIN_MINOR).$(ADMIN_RELEASE)
|
||||
ADMIN_TARBALL_PREFIX=$(PRJ_PREFIX)-admintools-$(ADMIN_VERSION)
|
||||
ADMIN_TARBALL=$(ADMIN_TARBALL_PREFIX).tgz
|
||||
|
||||
PYTHON_MAJOR=0
|
||||
PYTHON_MINOR=1
|
||||
PYTHON_RELEASE=0
|
||||
PYTHON_VERSION=$(PYTHON_MAJOR).$(PYTHON_MINOR).$(PYTHON_RELEASE)
|
||||
PYTHON_TARBALL_PREFIX=$(PRJ_PREFIX)-python-$(PYTHON_VERSION)
|
||||
PYTHON_TARBALL=$(PYTHON_TARBALL_PREFIX).tgz
|
||||
|
||||
all:
|
||||
@for subdir in $(SUBDIRS); do \
|
||||
(cd $$subdir && $(MAKE) $@) || exit 1; \
|
||||
done
|
||||
|
||||
install:
|
||||
@for subdir in $(SUBDIRS); do \
|
||||
(cd $$subdir && $(MAKE) $@) || exit 1; \
|
||||
done
|
||||
|
||||
clean:
|
||||
@for subdir in $(SUBDIRS); do \
|
||||
(cd $$subdir && $(MAKE) $@) || exit 1; \
|
||||
done
|
||||
rm -f *~
|
||||
|
||||
version-update:
|
||||
sed s/VERSION/$(SERV_VERSION)/ ipa-server/freeipa-server.spec.in \
|
||||
> ipa-server/freeipa-server.spec
|
||||
|
||||
sed s/VERSION/$(ADMIN_VERSION)/ ipa-admintools/freeipa-admintools.spec.in \
|
||||
> ipa-admintools/freeipa-admintools.spec
|
||||
|
||||
sed s/VERSION/$(PYTHON_VERSION)/ ipa-python/freeipa-python.spec.in \
|
||||
> ipa-python/freeipa-python.spec
|
||||
|
||||
|
||||
tarballs:
|
||||
-mkdir -p dist
|
||||
hg archive -t files dist/freeipa
|
||||
|
||||
# ipa-server
|
||||
mv dist/freeipa/ipa-server dist/$(SERV_TARBALL_PREFIX)
|
||||
rm -f dist/$(SERV_TARBALL)
|
||||
cd dist; tar cfz $(SERV_TARBALL) $(SERV_TARBALL_PREFIX)
|
||||
rm -fr dist/$(SERV_TARBALL_PREFIX)
|
||||
|
||||
# ipa-admintools
|
||||
mv dist/freeipa/ipa-admintools dist/$(ADMIN_TARBALL_PREFIX)
|
||||
rm -f dist/$(ADMIN_TARBALL)
|
||||
cd dist; tar cfz $(ADMIN_TARBALL) $(ADMIN_TARBALL_PREFIX)
|
||||
rm -fr dist/$(ADMIN_TARBALL_PREFIX)
|
||||
|
||||
# ipa-python
|
||||
mv dist/freeipa/ipa-python dist/$(PYTHON_TARBALL_PREFIX)
|
||||
rm -f dist/$(PYTHON_TARBALL)
|
||||
cd dist; tar cfz $(PYTHON_TARBALL) $(PYTHON_TARBALL_PREFIX)
|
||||
rm -fr dist/$(PYTHON_TARBALL_PREFIX)
|
||||
|
||||
# cleanup
|
||||
rm -fr dist/freeipa
|
||||
|
||||
rpm-ipa-server:
|
||||
cp dist/$(SERV_TARBALL) ~/rpmbuild/SOURCES/.
|
||||
rpmbuild -ba ipa-server/freeipa-server.spec
|
||||
cp ~/rpmbuild/RPMS/noarch/$(PRJ_PREFIX)-server-$(SERV_VERSION)-*.rpm dist/.
|
||||
cp ~/rpmbuild/SRPMS/$(PRJ_PREFIX)-server-$(SERV_VERSION)-*.src.rpm dist/.
|
||||
|
||||
rpm-ipa-admin:
|
||||
cp dist/$(ADMIN_TARBALL) ~/rpmbuild/SOURCES/.
|
||||
rpmbuild -ba ipa-admintools/freeipa-admintools.spec
|
||||
cp ~/rpmbuild/RPMS/noarch/$(PRJ_PREFIX)-admintools-$(ADMIN_VERSION)-*.rpm dist/.
|
||||
cp ~/rpmbuild/SRPMS/$(PRJ_PREFIX)-admintools-$(ADMIN_VERSION)-*.src.rpm dist/.
|
||||
|
||||
rpm-ipa-python:
|
||||
cp dist/$(PYTHON_TARBALL) ~/rpmbuild/SOURCES/.
|
||||
rpmbuild -ba ipa-python/freeipa-python.spec
|
||||
cp ~/rpmbuild/RPMS/noarch/$(PRJ_PREFIX)-python-$(PYTHON_VERSION)-*.rpm dist/.
|
||||
cp ~/rpmbuild/SRPMS/$(PRJ_PREFIX)-python-$(PYTHON_VERSION)-*.src.rpm dist/.
|
||||
|
||||
rpms: rpm-ipa-server rpm-ipa-admin rpm-ipa-python
|
||||
|
||||
dist: version-update tarballs rpms
|
||||
|
||||
dist-clean: clean
|
||||
rm -fr dist
|
||||
@@ -0,0 +1,10 @@
|
||||
SBINDIR = $(DESTDIR)/usr/sbin
|
||||
|
||||
all: ;
|
||||
|
||||
install:
|
||||
install -m 755 ipa-adduser $(SBINDIR)
|
||||
install -m 755 ipa-finduser $(SBINDIR)
|
||||
|
||||
clean:
|
||||
rm -f *~ *.pyc
|
||||
File renamed without changes.
Executable
+42
@@ -0,0 +1,42 @@
|
||||
Name: freeipa-admintools
|
||||
Version: 0.1.0
|
||||
Release: 1%{?dist}
|
||||
Summary: FreeIPA authentication server
|
||||
|
||||
Group: System Environment/Base
|
||||
License: GPL
|
||||
URL: http://www.freeipa.org
|
||||
Source0: %{name}-%{version}.tgz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: python freeipa-python
|
||||
|
||||
%description
|
||||
FreeIPA is a server for identity, policy, and audit.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}%{_sbindir}
|
||||
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_sbindir}/ipa-adduser
|
||||
%{_sbindir}/ipa-finduser
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Jul 27 2007 Karl MacMillan <kmacmill@localhost.localdomain> - 0.1.0-1
|
||||
- Initial rpm version
|
||||
|
||||
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
Name: freeipa-admintools
|
||||
Version: 0.1.0
|
||||
Release: 1%{?dist}
|
||||
Summary: FreeIPA authentication server
|
||||
|
||||
Group: System Environment/Base
|
||||
License: GPL
|
||||
URL: http://www.freeipa.org
|
||||
Source0: %{name}-%{version}.tgz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: python freeipa-python
|
||||
|
||||
%description
|
||||
FreeIPA is a server for identity, policy, and audit.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}%{_sbindir}
|
||||
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_sbindir}/ipa-adduser
|
||||
%{_sbindir}/ipa-finduser
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Jul 27 2007 Karl MacMillan <kmacmill@localhost.localdomain> - 0.1.0-1
|
||||
- Initial rpm version
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#! /usr/bin/python -E
|
||||
# Authors: Rob Crittenden <rcritten@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 only
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
import ipa
|
||||
import ipa.rpcclient
|
||||
import xmlrpclib
|
||||
|
||||
def usage():
|
||||
print "ipa-adduser [-c|--gecos STRING] [-d|--directory STRING] [-f|--firstname STRING] [-l|--lastname STRING] user"
|
||||
sys.exit(1)
|
||||
|
||||
def parse_options():
|
||||
parser = OptionParser()
|
||||
parser.add_option("-c", "--gecos", dest="gecos",
|
||||
help="Set the GECOS field")
|
||||
parser.add_option("-d", "--directory", dest="directory",
|
||||
help="Set the User's home directory")
|
||||
parser.add_option("-f", "--firstname", dest="gn",
|
||||
help="User's first name")
|
||||
parser.add_option("-l", "--lastname", dest="sn",
|
||||
help="User's last name")
|
||||
parser.add_option("-s", "--shell", dest="shell",
|
||||
help="Set user's login shell to shell")
|
||||
parser.add_option("--usage", action="store_true",
|
||||
help="Program usage")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if not options.gn or not options.sn:
|
||||
usage()
|
||||
|
||||
return options, args
|
||||
|
||||
def main():
|
||||
user={}
|
||||
(options, args) = parse_options()
|
||||
|
||||
if len(args) != 1:
|
||||
usage()
|
||||
|
||||
user['gn'] = options.gn
|
||||
user['sn'] = options.sn
|
||||
user['uid'] = args[0]
|
||||
if options.gecos:
|
||||
user['gecos'] = options.gecos
|
||||
if options.directory:
|
||||
user['homedirectory'] = options.directory
|
||||
if options.shell:
|
||||
user['loginshell'] = options.shell
|
||||
else:
|
||||
user['loginshell'] = "/bin/bash"
|
||||
|
||||
try:
|
||||
ipa.rpcclient.add_user(user)
|
||||
print args[0] + " successfully added"
|
||||
except xmlrpclib.Fault, f:
|
||||
print f.faultString
|
||||
|
||||
return 0
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,60 @@
|
||||
#! /usr/bin/python -E
|
||||
# Authors: Rob Crittenden <rcritten@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 only
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
from optparse import OptionParser
|
||||
import ipa
|
||||
import ipa.rpcclient
|
||||
import base64
|
||||
import sys
|
||||
import xmlrpclib
|
||||
|
||||
def usage():
|
||||
print "ipa-finduser <uid>"
|
||||
sys.exit()
|
||||
|
||||
def parse_options():
|
||||
parser = OptionParser()
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
return options, args
|
||||
|
||||
def main():
|
||||
user={}
|
||||
(options, args) = parse_options()
|
||||
|
||||
if len(args) != 1:
|
||||
usage()
|
||||
|
||||
try:
|
||||
ent = ipa.rpcclient.get_user(args[0])
|
||||
for name, value in ent.items():
|
||||
if isinstance(value, str):
|
||||
print name + ": " + value
|
||||
else:
|
||||
print name + ": "
|
||||
for x in value:
|
||||
print "\t" + x
|
||||
except xmlrpclib.Fault, fault:
|
||||
print fault.faultString
|
||||
|
||||
return 0
|
||||
|
||||
main()
|
||||
@@ -1,10 +0,0 @@
|
||||
all: ;
|
||||
|
||||
install:
|
||||
$(MAKE) -C src $@
|
||||
$(MAKE) -C share $@
|
||||
|
||||
clean:
|
||||
$(MAKE) -C src $@
|
||||
$(MAKE) -C share $@
|
||||
rm -f *~
|
||||
@@ -1 +0,0 @@
|
||||
__all__ = ["dsinstance", "krbinstance"]
|
||||
@@ -1,14 +1,11 @@
|
||||
PYTHONLIBDIR ?= $(shell python -c "from distutils.sysconfig import *; print get_python_lib(1)")
|
||||
PACKAGEDIR ?= $(DESTDIR)/$(PYTHONLIBDIR)/ipa
|
||||
SBINDIR = $(DESTDIR)/usr/sbin
|
||||
|
||||
all: ;
|
||||
|
||||
install:
|
||||
-mkdir -p $(PACKAGEDIR)
|
||||
install -m 644 ipa/*.py $(PACKAGEDIR)
|
||||
install -m 755 ipa-server-install $(SBINDIR)
|
||||
install -m 755 ipa-server-setupssl $(SBINDIR)
|
||||
install -m 644 *.py $(PACKAGEDIR)
|
||||
|
||||
clean:
|
||||
rm -f *~ *.pyc
|
||||
File renamed without changes.
File renamed without changes.
Executable
+45
@@ -0,0 +1,45 @@
|
||||
Name: freeipa-python
|
||||
Version: 0.1.0
|
||||
Release: 1%{?dist}
|
||||
Summary: FreeIPA authentication server
|
||||
|
||||
Group: System Environment/Base
|
||||
License: GPL
|
||||
URL: http://www.freeipa.org
|
||||
Source0: %{name}-%{version}.tgz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: python
|
||||
|
||||
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
|
||||
|
||||
%define pkgpythondir %{python_sitelib}/ipa
|
||||
|
||||
%description
|
||||
FreeIPA is a server for identity, policy, and audit.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}%{pkgpythondir}
|
||||
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{pkgpythondir}/*
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Jul 27 2007 Karl MacMillan <kmacmill@localhost.localdomain> - 0.1.0-1
|
||||
- Initial rpm version
|
||||
|
||||
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
Name: freeipa-python
|
||||
Version: VERSION
|
||||
Release: 1%{?dist}
|
||||
Summary: FreeIPA authentication server
|
||||
|
||||
Group: System Environment/Base
|
||||
License: GPL
|
||||
URL: http://www.freeipa.org
|
||||
Source0: %{name}-%{version}.tgz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: python
|
||||
|
||||
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
|
||||
|
||||
%define pkgpythondir %{python_sitelib}/ipa
|
||||
|
||||
%description
|
||||
FreeIPA is a server for identity, policy, and audit.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}%{pkgpythondir}
|
||||
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{pkgpythondir}/*
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Jul 27 2007 Karl MacMillan <kmacmill@localhost.localdomain> - 0.1.0-1
|
||||
- Initial rpm version
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#! /usr/bin/python -E
|
||||
# Authors: Rob Crittenden <rcritten@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 or later
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
#!/usr/bin/python
|
||||
|
||||
try:
|
||||
import krbV
|
||||
except ImportError:
|
||||
pass
|
||||
import xmlrpclib
|
||||
import socket
|
||||
import os
|
||||
import base64
|
||||
|
||||
# Some errors to catch
|
||||
# http://cvs.fedora.redhat.com/viewcvs/ldapserver/ldap/servers/plugins/pam_passthru/README?root=dirsec&rev=1.6&view=auto
|
||||
|
||||
# FIXME: do we want this set somewhere else?
|
||||
server = xmlrpclib.ServerProxy("http://localhost:80/ipa")
|
||||
|
||||
def get_user(username):
|
||||
"""Get a specific user"""
|
||||
|
||||
try:
|
||||
result = server.get_user(username)
|
||||
myuser = result
|
||||
except xmlrpclib.Fault, fault:
|
||||
raise xmlrpclib.Fault(fault.faultCode, fault.faultString)
|
||||
return None
|
||||
except socket.error, (value, msg):
|
||||
raise xmlrpclib.Fault(value, msg)
|
||||
return None
|
||||
|
||||
return myuser
|
||||
|
||||
def add_user(user):
|
||||
"""Add a new user"""
|
||||
|
||||
# FIXME: Get the realm from somewhere
|
||||
realm="GREYOAK.COM"
|
||||
|
||||
# FIXME: This should be dynamic and can include just about anything
|
||||
# Let us add in some missing attributes
|
||||
if user.get('homeDirectory') is None:
|
||||
user['homeDirectory'] ='/home/%s' % user['uid']
|
||||
if user.get('gecos') is None:
|
||||
user['gecos'] = user['uid']
|
||||
|
||||
# FIXME: This can be removed once the DS plugin is installed
|
||||
user['uidNumber'] ='501'
|
||||
|
||||
# FIXME: What is the default group for users?
|
||||
user['gidNumber'] ='501'
|
||||
user['krbPrincipalName'] = "%s@%s" % (user['uid'], realm)
|
||||
user['cn'] = "%s %s" % (user['gn'], user['sn'])
|
||||
if user.get('gn'):
|
||||
del user['gn']
|
||||
|
||||
try:
|
||||
result = server.add_user(user)
|
||||
return result
|
||||
except xmlrpclib.Fault, fault:
|
||||
raise xmlrpclib.Fault(fault.faultCode, fault.faultString)
|
||||
return None
|
||||
except socket.error, (value, msg):
|
||||
raise xmlrpclib.Fault(value, msg)
|
||||
return None
|
||||
|
||||
def get_add_schema():
|
||||
"""Get the list of attributes we need to ask when adding a new
|
||||
user.
|
||||
"""
|
||||
|
||||
# FIXME: Hardcoded and designed for the TurboGears GUI. Do we want
|
||||
# this for the CLI as well?
|
||||
try:
|
||||
result = server.get_add_schema()
|
||||
except xmlrpclib.Fault, fault:
|
||||
raise xmlrpclib.Fault(fault,faultCode, fault.faultString)
|
||||
return None
|
||||
except socket.error, (value, msg):
|
||||
raise xmlrpclib.Fault(value, msg)
|
||||
return None
|
||||
|
||||
return result
|
||||
@@ -0,0 +1,23 @@
|
||||
SUBDIRS=ipa-install xmlrpc-server
|
||||
PYTHONDIR=$(DESTDIR)/usr/share/ipa/ipaserver
|
||||
|
||||
all:
|
||||
@for subdir in $(SUBDIRS); do \
|
||||
(cd $$subdir && $(MAKE) $@) || exit 1; \
|
||||
done
|
||||
|
||||
install-ipaserver:
|
||||
-mkdir -p $(PYTHONDIR)
|
||||
install -m 644 ipaserver/*.py $(PYTHONDIR)
|
||||
|
||||
install: install-ipaserver
|
||||
@for subdir in $(SUBDIRS); do \
|
||||
(cd $$subdir && $(MAKE) $@) || exit 1; \
|
||||
done
|
||||
|
||||
clean:
|
||||
@for subdir in $(SUBDIRS); do \
|
||||
(cd $$subdir && $(MAKE) $@) || exit 1; \
|
||||
done
|
||||
rm -f *~
|
||||
rm -f ipaserver/*~
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
Name: freeipa-server
|
||||
Version: 0.1.0
|
||||
Release: 1%{?dist}
|
||||
Summary: FreeIPA authentication server
|
||||
|
||||
Group: System Environment/Base
|
||||
License: GPL
|
||||
URL: http://www.freeipa.org
|
||||
Source0: %{name}-%{version}.tgz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: python fedora-ds-base krb5-server krb5-server-ldap nss-tools openldap-clients httpd mod_python python-ldap freeipa-python
|
||||
|
||||
%define httpd_conf /etc/httpd/conf.d
|
||||
|
||||
%description
|
||||
FreeIPA is a server for identity, policy, and audit.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}%{_sbindir}
|
||||
mkdir -p %{buildroot}%{httpd_conf}
|
||||
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_sbindir}/ipa-server-install
|
||||
%{_sbindir}/ipa-server-setupssl
|
||||
|
||||
%dir %{_usr}/share/ipa
|
||||
%{_usr}/share/ipa/*
|
||||
|
||||
%{httpd_conf}/ipa.conf
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Jul 27 2007 Karl MacMillan <kmacmill@localhost.localdomain> - 0.1.0-1
|
||||
- Initial rpm version
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
Name: freeipa-server
|
||||
Version: VERSION
|
||||
Release: 1%{?dist}
|
||||
Summary: FreeIPA authentication server
|
||||
|
||||
Group: System Environment/Base
|
||||
License: GPL
|
||||
URL: http://www.freeipa.org
|
||||
Source0: %{name}-%{version}.tgz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: python fedora-ds-base krb5-server krb5-server-ldap nss-tools openldap-clients httpd mod_python python-ldap freeipa-python
|
||||
|
||||
%define httpd_conf /etc/httpd/conf.d
|
||||
|
||||
%description
|
||||
FreeIPA is a server for identity, policy, and audit.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}%{_sbindir}
|
||||
mkdir -p %{buildroot}%{httpd_conf}
|
||||
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_sbindir}/ipa-server-install
|
||||
%{_sbindir}/ipa-server-setupssl
|
||||
|
||||
%dir %{_usr}/share/ipa
|
||||
%{_usr}/share/ipa/*
|
||||
|
||||
%{httpd_conf}/ipa.conf
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Jul 27 2007 Karl MacMillan <kmacmill@localhost.localdomain> - 0.1.0-1
|
||||
- Initial rpm version
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
SBINDIR=$(DESTDIR)/usr/sbin
|
||||
|
||||
all: ;
|
||||
|
||||
install:
|
||||
install -m 755 ipa-server-install $(SBINDIR)
|
||||
install -m 755 ipa-server-setupssl $(SBINDIR)
|
||||
$(MAKE) -C share $@
|
||||
|
||||
clean:
|
||||
$(MAKE) -C share $@
|
||||
rm -f *~ *.pyc
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
Required packages:
|
||||
|
||||
krb5-server
|
||||
fedora-ds-base
|
||||
openldap-clients
|
||||
krb5-server-ldap
|
||||
cyrus-sasl-gssapi
|
||||
httpd
|
||||
mod_auth_kerb
|
||||
|
||||
|
||||
Installation example:
|
||||
|
||||
TEMPORARY: (until fedora ds scripts are fixed)
|
||||
please use the fedora-ds.init.patch under share/ to patch your init scripts before
|
||||
running ipa-server-install
|
||||
|
||||
cd ipa-install
|
||||
make install
|
||||
cd ..
|
||||
/usr/sbin/ipa-server-install -u fds -r FREEIPA.ORG -p freeipa -m ipafree
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
diff -r 5ebd8adc48b8 ipa-install/README
|
||||
--- a/ipa-install/README Mon Jul 02 15:51:04 2007 -0400
|
||||
+++ b/ipa-install/README Fri Jul 13 16:25:05 2007 -0400
|
||||
@@ -5,12 +5,17 @@ fedora-ds-base
|
||||
fedora-ds-base
|
||||
openldap-clients
|
||||
krb5-server-ldap
|
||||
+cyrus-sasl-gssapi
|
||||
|
||||
|
||||
Installation example:
|
||||
+
|
||||
+TEMPORARY: (until fedora ds scripts are fixed)
|
||||
+please use the fedora-ds.init.patch under share/ to patch your init scripts before
|
||||
+running ipa-server-install
|
||||
|
||||
cd ipa-install
|
||||
make install
|
||||
cd ..
|
||||
-/usr/sbin/ipa-server-install -r FREEIPA.ORG -a rc1.freeipa.org -p freeipa -m ipafree
|
||||
+/usr/sbin/ipa-server-install -u fds -r FREEIPA.ORG -p freeipa -m ipafree
|
||||
|
||||
diff -r 5ebd8adc48b8 ipa-install/share/bind.zone.db.template
|
||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
|
||||
+++ b/ipa-install/share/bind.zone.db.template Fri Jul 13 16:22:12 2007 -0400
|
||||
@@ -0,0 +1,26 @@
|
||||
+$$ORIGIN $DOMAIN.
|
||||
+$$TTL 86400
|
||||
+@ IN SOA $DOMAIN. root.$DOMAIN. (
|
||||
+ 01 ; serial (d. adams)
|
||||
+ 3H ; refresh
|
||||
+ 15M ; retry
|
||||
+ 1W ; expiry
|
||||
+ 1D ) ; minimum
|
||||
+
|
||||
+ IN NS $HOST
|
||||
+$HOST IN A $IP
|
||||
+;
|
||||
+; ldap servers
|
||||
+_ldap._tcp IN SRV 0 100 389 $HOST
|
||||
+
|
||||
+;kerberos realm
|
||||
+_kerberos IN TXT $REALM
|
||||
+
|
||||
+; kerberos servers
|
||||
+_kerberos._tcp IN SRV 0 100 88 $HOST
|
||||
+_kerberos._udp IN SRV 0 100 88 $HOST
|
||||
+_kerberos-master._tcp IN SRV 0 100 88 $HOST
|
||||
+_kerberos-master._udp IN SRV 0 100 88 $HOST
|
||||
+_kpasswd._tcp IN SRV 0 100 88 $HOST
|
||||
+_kpasswd._udp IN SRV 0 100 88 $HOST
|
||||
+
|
||||
diff -r 5ebd8adc48b8 ipa-install/share/fedora-ds.init.patch
|
||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
|
||||
+++ b/ipa-install/share/fedora-ds.init.patch Fri Jul 13 14:45:53 2007 -0400
|
||||
@@ -0,0 +1,12 @@
|
||||
+--- /etc/init.d/fedora-ds.orig 2007-07-06 18:21:30.000000000 -0400
|
||||
++++ /etc/init.d/fedora-ds 2007-05-18 19:36:24.000000000 -0400
|
||||
+@@ -10,6 +10,9 @@
|
||||
+ # datadir: /var/lib/fedora-ds/slapd-<instance name>
|
||||
+ #
|
||||
+
|
||||
++# Get config.
|
||||
++[ -r /etc/sysconfig/fedora-ds ] && . /etc/sysconfig/fedora-ds
|
||||
++
|
||||
+ # Source function library.
|
||||
+ if [ -f /etc/rc.d/init.d/functions ] ; then
|
||||
+ . /etc/rc.d/init.d/functions
|
||||
diff -r 5ebd8adc48b8 ipa-install/share/krb5.conf.template
|
||||
--- a/ipa-install/share/krb5.conf.template Mon Jul 02 15:51:04 2007 -0400
|
||||
+++ b/ipa-install/share/krb5.conf.template Fri Jul 13 11:01:36 2007 -0400
|
||||
@@ -9,6 +9,13 @@
|
||||
dns_lookup_kdc = true
|
||||
ticket_lifetime = 24h
|
||||
forwardable = yes
|
||||
+
|
||||
+[realms]
|
||||
+ $REALM = {
|
||||
+ kdc = $FQDN:88
|
||||
+ admin_server = $FQDN:749
|
||||
+ default_domain = $DOMAIN
|
||||
+}
|
||||
|
||||
[domain_realm]
|
||||
.$DOMAIN = $REALM
|
||||
@@ -29,7 +36,7 @@
|
||||
ldap_servers = ldap://127.0.0.1/
|
||||
ldap_kerberos_container_dn = cn=kerberos,$SUFFIX
|
||||
ldap_kdc_dn = uid=kdc,cn=kerberos,$SUFFIX
|
||||
-; ldap_kadmind_dn = cn=Directory Manager
|
||||
+ ldap_kadmind_dn = uid=kdc,cn=kerberos,$SUFFIX
|
||||
ldap_service_password_file = /var/kerberos/krb5kdc/ldappwd
|
||||
}
|
||||
|
||||
diff -r 5ebd8adc48b8 ipa-install/src/ipa-server-install
|
||||
--- a/ipa-install/src/ipa-server-install Mon Jul 02 15:51:04 2007 -0400
|
||||
+++ b/ipa-install/src/ipa-server-install Fri Jul 13 19:43:13 2007 -0400
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
VERSION = "%prog .1"
|
||||
|
||||
+import socket
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
import ipa.dsinstance
|
||||
@@ -37,8 +38,6 @@ def parse_options():
|
||||
help="ds user")
|
||||
parser.add_option("-r", "--realm", dest="realm_name",
|
||||
help="realm name")
|
||||
- parser.add_option("-a", "--host-address", dest="host_name",
|
||||
- help="host address (name or IP address)")
|
||||
parser.add_option("-p", "--password", dest="password",
|
||||
help="admin password")
|
||||
parser.add_option("-m", "--master-password", dest="master_password",
|
||||
@@ -46,8 +45,8 @@ def parse_options():
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
- if not options.realm_name or not options.host_name or not options.password:
|
||||
- parser.error("error: password, realm, and host name required")
|
||||
+ if not options.ds_user or not options.realm_name or not options.password or not options.master_password:
|
||||
+ parser.error("error: all options are required")
|
||||
|
||||
return options
|
||||
|
||||
@@ -56,13 +55,35 @@ def main():
|
||||
format='%(asctime)s %(levelname)s %(message)s',
|
||||
filename='ipa-install.log',
|
||||
filemode='w')
|
||||
+
|
||||
options = parse_options()
|
||||
+
|
||||
+ # check the hostname is correctly configured, it must be as the kldap
|
||||
+ # utilities just use the hostname as returned by gethostbyname to set
|
||||
+ # up some of the standard entries
|
||||
+
|
||||
+ host_name = socket.gethostname()
|
||||
+ if len(host_name.split(".")) < 2:
|
||||
+ print "Invalid hostname <"+host_name+">"
|
||||
+ print "Check the /etc/hosts file and make sure to have a valid FQDN"
|
||||
+ return "-Fatal Error-"
|
||||
+
|
||||
+ if socket.gethostbyname(host_name) == "127.0.0.1":
|
||||
+ print "The hostname resolves to the localhost address (127.0.0.1)"
|
||||
+ print "Please change your /etc/hosts file or your DNS so that the"
|
||||
+ print "hostname resolves to the ip address of your network interface."
|
||||
+ print "The KDC service does not listen on 127.0.0.1"
|
||||
+ return "-Fatal Error-"
|
||||
+
|
||||
+ print "The Final KDC Host Name will be: " + host_name
|
||||
+
|
||||
ds = ipa.dsinstance.DsInstance()
|
||||
- ds.create_instance(options.ds_user, options.realm_name, options.host_name, options.password)
|
||||
+ ds.create_instance(options.ds_user, options.realm_name, host_name, options.password)
|
||||
|
||||
krb = ipa.krbinstance.KrbInstance()
|
||||
- krb.create_instance(options.ds_user, options.realm_name, options.host_name, options.password, options.master_password)
|
||||
- #restart ds after the krb instance have add the sasl map
|
||||
+ krb.create_instance(options.ds_user, options.realm_name, host_name, options.password, options.master_password)
|
||||
+
|
||||
+ #restart ds after the krb instance have add the sasl map and the ldap keytab
|
||||
ds.restart()
|
||||
|
||||
return 0
|
||||
diff -r 5ebd8adc48b8 ipa-install/src/ipa/krbinstance.py
|
||||
--- a/ipa-install/src/ipa/krbinstance.py Mon Jul 02 15:51:04 2007 -0400
|
||||
+++ b/ipa-install/src/ipa/krbinstance.py Fri Jul 13 19:20:41 2007 -0400
|
||||
@@ -25,6 +25,9 @@ import logging
|
||||
import logging
|
||||
from random import Random
|
||||
from time import gmtime
|
||||
+import os
|
||||
+import pwd
|
||||
+import socket
|
||||
|
||||
SHARE_DIR = "/usr/share/ipa/"
|
||||
|
||||
@@ -32,6 +35,10 @@ def realm_to_suffix(realm_name):
|
||||
s = realm_name.split(".")
|
||||
terms = ["dc=" + x.lower() for x in s]
|
||||
return ",".join(terms)
|
||||
+
|
||||
+def host_to_domain(fqdn):
|
||||
+ s = fqdn.split(".")
|
||||
+ return ".".join(s[1:])
|
||||
|
||||
def generate_kdc_password():
|
||||
rndpwd = ''
|
||||
@@ -75,8 +82,10 @@ class KrbInstance:
|
||||
class KrbInstance:
|
||||
def __init__(self):
|
||||
self.ds_user = None
|
||||
- self.realm_name = None
|
||||
- self.host_name = None
|
||||
+ self.fqdn = None
|
||||
+ self.realm = None
|
||||
+ self.domain = None
|
||||
+ self.host = None
|
||||
self.admin_password = None
|
||||
self.master_password = None
|
||||
self.suffix = None
|
||||
@@ -85,12 +94,15 @@ class KrbInstance:
|
||||
|
||||
def create_instance(self, ds_user, realm_name, host_name, admin_password, master_password):
|
||||
self.ds_user = ds_user
|
||||
- self.realm_name = realm_name.upper()
|
||||
- self.host_name = host_name
|
||||
+ self.fqdn = host_name
|
||||
+ self.ip = socket.gethostbyname(host_name)
|
||||
+ self.realm = realm_name.upper()
|
||||
+ self.host = host_name.split(".")[0]
|
||||
+ self.domain = host_to_domain(host_name)
|
||||
self.admin_password = admin_password
|
||||
self.master_password = master_password
|
||||
|
||||
- self.suffix = realm_to_suffix(self.realm_name)
|
||||
+ self.suffix = realm_to_suffix(self.realm)
|
||||
self.kdc_password = generate_kdc_password()
|
||||
self.__configure_kdc_account_password()
|
||||
|
||||
@@ -99,6 +111,10 @@ class KrbInstance:
|
||||
self.__configure_ldap()
|
||||
|
||||
self.__create_instance()
|
||||
+
|
||||
+ self.__create_ds_keytab()
|
||||
+
|
||||
+ self.__create_sample_bind_zone()
|
||||
|
||||
self.start()
|
||||
|
||||
@@ -120,12 +136,13 @@ class KrbInstance:
|
||||
pwd_fd.close()
|
||||
|
||||
def __setup_sub_dict(self):
|
||||
- #FIXME: can DOMAIN be different than REALM ?
|
||||
- self.sub_dict = dict(FQHN=self.host_name,
|
||||
+ self.sub_dict = dict(FQDN=self.fqdn,
|
||||
+ IP=self.ip,
|
||||
PASSWORD=self.kdc_password,
|
||||
SUFFIX=self.suffix,
|
||||
- DOMAIN= self.realm_name.lower(),
|
||||
- REALM=self.realm_name)
|
||||
+ DOMAIN=self.domain,
|
||||
+ HOST=self.host,
|
||||
+ REALM=self.realm)
|
||||
|
||||
def __configure_ldap(self):
|
||||
|
||||
@@ -153,7 +170,7 @@ class KrbInstance:
|
||||
krb5_fd.close()
|
||||
|
||||
#populate the directory with the realm structure
|
||||
- args = ["/usr/kerberos/sbin/kdb5_ldap_util", "-D", "uid=kdc,cn=kerberos,"+self.suffix, "-w", self.kdc_password, "create", "-s", "-r", self.realm_name, "-subtrees", self.suffix, "-sscope", "sub"]
|
||||
+ args = ["/usr/kerberos/sbin/kdb5_ldap_util", "-D", "uid=kdc,cn=kerberos,"+self.suffix, "-w", self.kdc_password, "create", "-s", "-P", self.master_password, "-r", self.realm, "-subtrees", self.suffix, "-sscope", "sub"]
|
||||
run(args)
|
||||
|
||||
# TODO: NOT called yet, need to find out how to make sure the plugin is available first
|
||||
@@ -165,5 +182,28 @@ class KrbInstance:
|
||||
extop_fd.close()
|
||||
|
||||
#add an ACL to let the DS user read the master key
|
||||
- args = ["/usr/bin/setfacl", "-m", "u:"+self.ds_user+":r", "/var/kerberos/krb5kdc/.k5."+self.realm_name]
|
||||
+ args = ["/usr/bin/setfacl", "-m", "u:"+self.ds_user+":r", "/var/kerberos/krb5kdc/.k5."+self.realm]
|
||||
run(args)
|
||||
+
|
||||
+ def __create_sample_bind_zone(self):
|
||||
+ bind_txt = template_file(SHARE_DIR + "bind.zone.db.template", self.sub_dict)
|
||||
+ [bind_fd, bind_name] = tempfile.mkstemp(".db","sammple.zone.")
|
||||
+ os.write(bind_fd, bind_txt)
|
||||
+ os.close(bind_fd)
|
||||
+ print "Sample zone file for bind has been created in "+bind_name
|
||||
+
|
||||
+ def __create_ds_keytab(self):
|
||||
+ (kwrite, kread, kerr) = os.popen3("/usr/kerberos/sbin/kadmin.local")
|
||||
+ kwrite.write("addprinc -randkey ldap/"+self.fqdn+"@"+self.realm+"\n")
|
||||
+ kwrite.flush()
|
||||
+ kwrite.write("ktadd -k /etc/fedora-ds/ds.keytab ldap/"+self.fqdn+"@"+self.realm+"\n")
|
||||
+ kwrite.flush()
|
||||
+ kwrite.close()
|
||||
+ kread.close()
|
||||
+ kerr.close()
|
||||
+
|
||||
+ cfg_fd = open("/etc/sysconfig/fedora-ds", "a")
|
||||
+ cfg_fd.write("export KRB5_KTNAME=/etc/fedora-ds/ds.keytab\n")
|
||||
+ cfg_fd.close()
|
||||
+ pent = pwd.getpwnam(self.ds_user)
|
||||
+ os.chown("/etc/sysconfig/fedora-ds", pent.pw_uid, pent.pw_gid)
|
||||
@@ -26,11 +26,15 @@
|
||||
|
||||
VERSION = "%prog .1"
|
||||
|
||||
import sys
|
||||
sys.path.append("/usr/share/ipa")
|
||||
|
||||
import socket
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
import ipa.dsinstance
|
||||
import ipa.krbinstance
|
||||
import ipaserver.dsinstance
|
||||
import ipaserver.krbinstance
|
||||
from ipaserver.util import run
|
||||
|
||||
def parse_options():
|
||||
parser = OptionParser(version=VERSION)
|
||||
@@ -42,6 +46,9 @@ def parse_options():
|
||||
help="admin password")
|
||||
parser.add_option("-m", "--master-password", dest="master_password",
|
||||
help="kerberos master password")
|
||||
parser.add_option("-d", "--debug", dest="debug", action="store_true",
|
||||
dest="debug", default=False, help="print debugging information")
|
||||
parser.add_option("--hostname", dest="host_name", help="fully qualified name of server")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
@@ -50,19 +57,37 @@ def parse_options():
|
||||
|
||||
return options
|
||||
|
||||
def main():
|
||||
def logging_setup(options):
|
||||
# Always log everything (i.e., DEBUG) to the log
|
||||
# file.
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
format='%(asctime)s %(levelname)s %(message)s',
|
||||
filename='ipa-install.log',
|
||||
filename='ipaserver-install.log',
|
||||
filemode='w')
|
||||
|
||||
console = logging.StreamHandler()
|
||||
# If the debug option is set, also log debug messages to the console
|
||||
if options.debug:
|
||||
console.setLevel(logging.DEBUG)
|
||||
else:
|
||||
# Otherwise, log critical and error messages
|
||||
console.setLevel(logging.ERROR)
|
||||
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
|
||||
console.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(console)
|
||||
|
||||
def main():
|
||||
options = parse_options()
|
||||
logging_setup(options)
|
||||
|
||||
# check the hostname is correctly configured, it must be as the kldap
|
||||
# utilities just use the hostname as returned by gethostbyname to set
|
||||
# up some of the standard entries
|
||||
|
||||
host_name = socket.gethostname()
|
||||
if options.host_name:
|
||||
host_name = options.host_name
|
||||
else:
|
||||
host_name = socket.gethostname()
|
||||
if len(host_name.split(".")) < 2:
|
||||
print "Invalid hostname <"+host_name+">"
|
||||
print "Check the /etc/hosts file and make sure to have a valid FQDN"
|
||||
@@ -77,15 +102,23 @@ def main():
|
||||
|
||||
print "The Final KDC Host Name will be: " + host_name
|
||||
|
||||
ds = ipa.dsinstance.DsInstance()
|
||||
ds.create_instance(options.ds_user, options.realm_name, host_name, options.password)
|
||||
|
||||
krb = ipa.krbinstance.KrbInstance()
|
||||
krb.create_instance(options.ds_user, options.realm_name, host_name, options.password, options.master_password)
|
||||
# Create a directory server instance
|
||||
ds = ipaserver.dsinstance.DsInstance()
|
||||
ds.create_instance(options.ds_user, options.realm_name, host_name,
|
||||
options.password)
|
||||
|
||||
#restart ds after the krb instance have add the sasl map and the ldap keytab
|
||||
# Create a kerberos instance
|
||||
krb = ipaserver.krbinstance.KrbInstance()
|
||||
krb.create_instance(options.ds_user, options.realm_name, host_name,
|
||||
options.password, options.master_password)
|
||||
|
||||
# Restart ds after the krb instance have add the sasl map
|
||||
ds.restart()
|
||||
|
||||
# Restart apache
|
||||
run(["/sbin/service", "httpd", "restart"])
|
||||
|
||||
return 0
|
||||
|
||||
main()
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,42 @@
|
||||
[logging]
|
||||
default = FILE:/var/log/krb5libs.log
|
||||
kdc = FILE:/var/log/krb5kdc.log
|
||||
admin_server = FILE:/var/log/kadmind.log
|
||||
|
||||
[libdefaults]
|
||||
default_realm = $REALM
|
||||
dns_lookup_realm = true
|
||||
dns_lookup_kdc = true
|
||||
ticket_lifetime = 24h
|
||||
forwardable = yes
|
||||
|
||||
[realms]
|
||||
$REALM = {
|
||||
kdc = $FQDN:88
|
||||
admin_server = $FQDN:749
|
||||
default_domain = $DOMAIN
|
||||
}
|
||||
|
||||
[domain_realm]
|
||||
.$DOMAIN = $REALM
|
||||
$DOMAIN = $REALM
|
||||
|
||||
[appdefaults]
|
||||
pam = {
|
||||
debug = false
|
||||
ticket_lifetime = 36000
|
||||
renew_lifetime = 36000
|
||||
forwardable = true
|
||||
krb4_convert = false
|
||||
}
|
||||
|
||||
[dbmodules]
|
||||
$REALM = {
|
||||
db_library = kldap
|
||||
ldap_servers = ldap://127.0.0.1/
|
||||
ldap_kerberos_container_dn = cn=kerberos,$SUFFIX
|
||||
ldap_kdc_dn = uid=kdc,cn=kerberos,$SUFFIX
|
||||
ldap_kadmind_dn = uid=kdc,cn=kerberos,$SUFFIX
|
||||
ldap_service_password_file = /var/kerberos/krb5kdc/ldappwd
|
||||
}
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,57 @@
|
||||
#! /usr/bin/python -E
|
||||
# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
|
||||
# see inline
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 or later
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
__all__ = ["dsinstance", "krbinstance"]
|
||||
|
||||
#
|
||||
# Functions common for the XML RPC client and server
|
||||
#
|
||||
# Authors:
|
||||
# Mike McLean <mikem@redhat.com> (from koji)
|
||||
|
||||
# functions for encoding/decoding optional arguments
|
||||
|
||||
def encode_args(*args,**opts):
|
||||
"""The function encodes optional arguments as regular arguments.
|
||||
|
||||
This is used to allow optional arguments in xmlrpc calls
|
||||
Returns a tuple of args
|
||||
"""
|
||||
if opts:
|
||||
opts['__starstar'] = True
|
||||
args = args + (opts,)
|
||||
return args
|
||||
|
||||
def decode_args(*args):
|
||||
"""Decodes optional arguments from a flat argument list
|
||||
|
||||
Complementary to encode_args
|
||||
Returns a tuple (args,opts) where args is a tuple and opts is a dict
|
||||
"""
|
||||
opts = {}
|
||||
if len(args) > 0:
|
||||
last = args[-1]
|
||||
if type(last) == dict and last.get('__starstar',False):
|
||||
del last['__starstar']
|
||||
opts = last
|
||||
args = args[:-1]
|
||||
return args,opts
|
||||
|
||||
@@ -24,8 +24,13 @@ import tempfile
|
||||
import shutil
|
||||
import logging
|
||||
import pwd
|
||||
from util import *
|
||||
|
||||
|
||||
SHARE_DIR = "/usr/share/ipa/"
|
||||
SERVER_ROOT_64 = "/usr/lib64/fedora-ds-base"
|
||||
SERVER_ROOT_32 = "/usr/lib/fedora-ds-base"
|
||||
|
||||
|
||||
def generate_serverid():
|
||||
"""Generate a UUID (universally unique identifier) suitable
|
||||
@@ -44,38 +49,17 @@ def realm_to_suffix(realm_name):
|
||||
terms = ["dc=" + x.lower() for x in s]
|
||||
return ",".join(terms)
|
||||
|
||||
def template_str(txt, vars):
|
||||
return string.Template(txt).substitute(vars)
|
||||
|
||||
def template_file(infilename, vars):
|
||||
txt = open(infilename).read()
|
||||
return template_str(txt, vars)
|
||||
|
||||
def write_tmp_file(txt):
|
||||
fd = tempfile.NamedTemporaryFile()
|
||||
fd.write(txt)
|
||||
fd.flush()
|
||||
|
||||
return fd
|
||||
|
||||
def run(args, stdin=None):
|
||||
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if stdin:
|
||||
stdout,stderr = p.communicate(stdin)
|
||||
def find_server_root():
|
||||
if dir_exists(SERVER_ROOT_64):
|
||||
return SERVER_ROOT_64
|
||||
else:
|
||||
stdout,stderr = p.communicate()
|
||||
logging.info(stdout)
|
||||
logging.info(stderr)
|
||||
|
||||
if p.returncode != 0:
|
||||
raise subprocess.CalledProcessError(p.returncode, args[0])
|
||||
|
||||
return SERVER_ROOT_32
|
||||
|
||||
INF_TEMPLATE = """
|
||||
[General]
|
||||
FullMachineName= $FQHN
|
||||
SuiteSpotUserID= $USER
|
||||
ServerRoot= /usr/lib/fedora-ds-base
|
||||
ServerRoot= $SERVER_ROOT
|
||||
[slapd]
|
||||
ServerPort= 389
|
||||
ServerIdentifier= $SERVERID
|
||||
@@ -126,22 +110,39 @@ class DsInstance:
|
||||
|
||||
def __setup_sub_dict(self):
|
||||
suffix = realm_to_suffix(self.realm_name)
|
||||
server_root = find_server_root()
|
||||
self.sub_dict = dict(FQHN=self.host_name, SERVERID=self.serverid,
|
||||
PASSWORD=self.admin_password, SUFFIX=suffix,
|
||||
REALM=self.realm_name, USER=self.ds_user)
|
||||
REALM=self.realm_name, USER=self.ds_user,
|
||||
SERVER_ROOT=server_root)
|
||||
|
||||
def __create_ds_user(self):
|
||||
try:
|
||||
pwd.getpwnam(self.ds_user)
|
||||
logging.debug("ds user %s exists" % self.ds_user)
|
||||
except KeyError:
|
||||
logging.debug("adding ds user %s" % self.ds_user)
|
||||
args = ["/usr/sbin/useradd", "-c", "DS System User", "-d", "/var/lib/fedora-ds", "-M", "-r", "-s", "/sbin/nologin", self.ds_user]
|
||||
run(args)
|
||||
logging.debug("done adding user")
|
||||
|
||||
def __create_instance(self):
|
||||
logging.debug("creating ds instance . . . ")
|
||||
inf_txt = template_str(INF_TEMPLATE, self.sub_dict)
|
||||
logging.debug(inf_txt)
|
||||
inf_fd = write_tmp_file(inf_txt)
|
||||
args = ["/usr/bin/ds_newinst.pl", inf_fd.name]
|
||||
logging.debug("writing inf template")
|
||||
if file_exists("/usr/sbin/setup-ds.pl"):
|
||||
args = ["/usr/sbin/setup-ds.pl", "--silent", "--logfile", "-", "-f", inf_fd.name]
|
||||
logging.debug("calling setup-ds.pl")
|
||||
else:
|
||||
args = ["/usr/sbin/ds_newinst.pl", inf_fd.name]
|
||||
logging.debug("calling ds_newinst.pl")
|
||||
run(args)
|
||||
logging.debug("completed creating ds instance")
|
||||
logging.debug("restarting ds instance")
|
||||
self.restart()
|
||||
logging.debug("done restarting ds instance")
|
||||
|
||||
def __add_default_schemas(self):
|
||||
shutil.copyfile(SHARE_DIR + "60kerberos.ldif",
|
||||
@@ -150,14 +151,18 @@ class DsInstance:
|
||||
self.schema_dirname() + "60samba.ldif")
|
||||
|
||||
def __enable_ssl(self):
|
||||
logging.debug("configuring ssl for ds instance")
|
||||
dirname = self.config_dirname()
|
||||
args = ["/usr/sbin/ipa-server-setupssl", self.admin_password,
|
||||
dirname, self.host_name]
|
||||
run(args)
|
||||
logging.debug("done configuring ssl for ds instance")
|
||||
|
||||
def __add_default_layout(self):
|
||||
txt = template_file(SHARE_DIR + "bootstrap-template.ldif", self.sub_dict)
|
||||
inf_fd = write_tmp_file(txt)
|
||||
logging.debug("adding default ds layout")
|
||||
args = ["/usr/bin/ldapmodify", "-xv", "-D", "cn=Directory Manager",
|
||||
"-w", self.admin_password, "-f", inf_fd.name]
|
||||
run(args)
|
||||
logging.debug("done adding default ds layout")
|
||||
@@ -0,0 +1,395 @@
|
||||
#! /usr/bin/python -E
|
||||
# Authors: Rich Megginson <richm@redhat.com>
|
||||
# Rob Crittenden <rcritten2redhat.com
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 or later
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
import sys
|
||||
import os
|
||||
import os.path
|
||||
import popen2
|
||||
import base64
|
||||
import urllib
|
||||
import urllib2
|
||||
import socket
|
||||
import ldif
|
||||
import re
|
||||
import ldap
|
||||
import cStringIO
|
||||
import time
|
||||
import operator
|
||||
|
||||
from ldap.ldapobject import SimpleLDAPObject
|
||||
|
||||
class Error(Exception): pass
|
||||
class InvalidArgumentError(Error):
|
||||
def __init__(self,message): self.message = message
|
||||
def __repr__(self): return message
|
||||
class NoSuchEntryError(Error):
|
||||
def __init__(self,message): self.message = message
|
||||
def __repr__(self): return message
|
||||
|
||||
class Entry:
|
||||
"""This class represents an LDAP Entry object. An LDAP entry consists of a DN
|
||||
and a list of attributes. Each attribute consists of a name and a list of
|
||||
values. In python-ldap, entries are returned as a list of 2-tuples.
|
||||
Instance variables:
|
||||
dn - string - the string DN of the entry
|
||||
data - cidict - case insensitive dict of the attributes and values"""
|
||||
|
||||
def __init__(self,entrydata):
|
||||
"""data is the raw data returned from the python-ldap result method, which is
|
||||
a search result entry or a reference or None.
|
||||
If creating a new empty entry, data is the string DN."""
|
||||
if entrydata:
|
||||
if isinstance(entrydata,tuple):
|
||||
self.dn = entrydata[0]
|
||||
self.data = ldap.cidict.cidict(entrydata[1])
|
||||
elif isinstance(entrydata,str):
|
||||
self.dn = entrydata
|
||||
self.data = ldap.cidict.cidict()
|
||||
else:
|
||||
self.dn = ''
|
||||
self.data = ldap.cidict.cidict()
|
||||
|
||||
def __nonzero__(self):
|
||||
"""This allows us to do tests like if entry: returns false if there is no data,
|
||||
true otherwise"""
|
||||
return self.data != None and len(self.data) > 0
|
||||
|
||||
def hasAttr(self,name):
|
||||
"""Return True if this entry has an attribute named name, False otherwise"""
|
||||
return self.data and self.data.has_key(name)
|
||||
|
||||
def __getattr__(self,name):
|
||||
"""If name is the name of an LDAP attribute, return the first value for that
|
||||
attribute - equivalent to getValue - this allows the use of
|
||||
entry.cn
|
||||
instead of
|
||||
entry.getValue('cn')
|
||||
This also allows us to return None if an attribute is not found rather than
|
||||
throwing an exception"""
|
||||
return self.getValue(name)
|
||||
|
||||
def getValues(self,name):
|
||||
"""Get the list (array) of values for the attribute named name"""
|
||||
return self.data.get(name)
|
||||
|
||||
def getValue(self,name):
|
||||
"""Get the first value for the attribute named name"""
|
||||
return self.data.get(name,[None])[0]
|
||||
|
||||
def setValue(self,name,*value):
|
||||
"""Value passed in may be a single value, several values, or a single sequence.
|
||||
For example:
|
||||
ent.setValue('name', 'value')
|
||||
ent.setValue('name', 'value1', 'value2', ..., 'valueN')
|
||||
ent.setValue('name', ['value1', 'value2', ..., 'valueN'])
|
||||
ent.setValue('name', ('value1', 'value2', ..., 'valueN'))
|
||||
Since *value is a tuple, we may have to extract a list or tuple from that
|
||||
tuple as in the last two examples above"""
|
||||
if isinstance(value[0],list) or isinstance(value[0],tuple):
|
||||
self.data[name] = value[0]
|
||||
else:
|
||||
self.data[name] = value
|
||||
|
||||
setValues = setValue
|
||||
|
||||
def toTupleList(self):
|
||||
"""Convert the attrs and values to a list of 2-tuples. The first element
|
||||
of the tuple is the attribute name. The second element is either a
|
||||
single value or a list of values."""
|
||||
return self.data.items()
|
||||
|
||||
def __str__(self):
|
||||
"""Convert the Entry to its LDIF representation"""
|
||||
return self.__repr__()
|
||||
|
||||
# the ldif class base64 encodes some attrs which I would rather see in raw form - to
|
||||
# encode specific attrs as base64, add them to the list below
|
||||
ldif.safe_string_re = re.compile('^$')
|
||||
base64_attrs = ['nsstate', 'krbprincipalkey', 'krbExtraData']
|
||||
|
||||
def __repr__(self):
|
||||
"""Convert the Entry to its LDIF representation"""
|
||||
sio = cStringIO.StringIO()
|
||||
# what's all this then? the unparse method will currently only accept
|
||||
# a list or a dict, not a class derived from them. self.data is a
|
||||
# cidict, so unparse barfs on it. I've filed a bug against python-ldap,
|
||||
# but in the meantime, we have to convert to a plain old dict for printing
|
||||
# I also don't want to see wrapping, so set the line width really high (1000)
|
||||
newdata = {}
|
||||
newdata.update(self.data)
|
||||
ldif.LDIFWriter(sio,Entry.base64_attrs,1000).unparse(self.dn,newdata)
|
||||
return sio.getvalue()
|
||||
|
||||
def wrapper(f,name):
|
||||
"""This is the method that wraps all of the methods of the superclass. This seems
|
||||
to need to be an unbound method, that's why it's outside of IPAdmin. Perhaps there
|
||||
is some way to do this with the new classmethod or staticmethod of 2.4.
|
||||
Basically, we replace every call to a method in SimpleLDAPObject (the superclass
|
||||
of IPAdmin) with a call to inner. The f argument to wrapper is the bound method
|
||||
of IPAdmin (which is inherited from the superclass). Bound means that it will implicitly
|
||||
be called with the self argument, it is not in the args list. name is the name of
|
||||
the method to call. If name is a method that returns entry objects (e.g. result),
|
||||
we wrap the data returned by an Entry class. If name is a method that takes an entry
|
||||
argument, we extract the raw data from the entry object to pass in."""
|
||||
def inner(*args, **kargs):
|
||||
if name == 'result':
|
||||
type, data = f(*args, **kargs)
|
||||
# data is either a 2-tuple or a list of 2-tuples
|
||||
# print data
|
||||
if data:
|
||||
if isinstance(data,tuple):
|
||||
return type, Entry(data)
|
||||
elif isinstance(data,list):
|
||||
return type, [Entry(x) for x in data]
|
||||
else:
|
||||
raise TypeError, "unknown data type %s returned by result" % type(data)
|
||||
else:
|
||||
return type, data
|
||||
elif name.startswith('add'):
|
||||
# the first arg is self
|
||||
# the second and third arg are the dn and the data to send
|
||||
# We need to convert the Entry into the format used by
|
||||
# python-ldap
|
||||
ent = args[0]
|
||||
if isinstance(ent,Entry):
|
||||
return f(ent.dn, ent.toTupleList(), *args[2:])
|
||||
else:
|
||||
return f(*args, **kargs)
|
||||
else:
|
||||
return f(*args, **kargs)
|
||||
return inner
|
||||
|
||||
class IPAdmin(SimpleLDAPObject):
|
||||
CFGSUFFIX = "o=NetscapeRoot"
|
||||
DEFAULT_USER_ID = "nobody"
|
||||
|
||||
def __initPart2(self):
|
||||
if self.binddn and len(self.binddn) and not hasattr(self,'sroot'):
|
||||
try:
|
||||
ent = self.getEntry('cn=config', ldap.SCOPE_BASE, '(objectclass=*)',
|
||||
[ 'nsslapd-instancedir', 'nsslapd-errorlog' ])
|
||||
instdir = ent.getValue('nsslapd-instancedir')
|
||||
self.sroot, self.inst = re.match(r'(.*)[\/]slapd-(\w+)$', instdir).groups()
|
||||
self.errlog = ent.getValue('nsslapd-errorlog')
|
||||
except (ldap.INSUFFICIENT_ACCESS, ldap.CONNECT_ERROR, NoSuchEntryError):
|
||||
pass # usually means
|
||||
# print "ignored exception"
|
||||
except ldap.LDAPError, e:
|
||||
print "caught exception ", e
|
||||
raise
|
||||
|
||||
def __localinit__(self):
|
||||
SimpleLDAPObject.__init__(self,'ldap://%s:%d' % (self.host,self.port))
|
||||
# see if binddn is a dn or a uid that we need to lookup
|
||||
if self.binddn and not IPAdmin.is_a_dn(self.binddn):
|
||||
self.simple_bind("","") # anon
|
||||
ent = self.getEntry(IPAdmin.CFGSUFFIX, ldap.SCOPE_SUBTREE,
|
||||
"(uid=%s)" % self.binddn,
|
||||
['uid'])
|
||||
if ent:
|
||||
self.binddn = ent.dn
|
||||
else:
|
||||
print "Error: could not find %s under %s" % (self.binddn, IPAdmin.CFGSUFFIX)
|
||||
self.simple_bind(self.binddn,self.bindpw)
|
||||
# self.__initPart2()
|
||||
|
||||
def __init__(self,host,port,binddn,bindpw):
|
||||
"""We just set our instance variables and wrap the methods - the real work is
|
||||
done in __localinit__ and __initPart2 - these are separated out this way so
|
||||
that we can call them from places other than instance creation e.g. when
|
||||
using the start command, we just need to reconnect, not create a new instance"""
|
||||
self.__wrapmethods()
|
||||
self.port = port or 389
|
||||
self.sslport = 0
|
||||
self.host = host
|
||||
self.binddn = binddn
|
||||
self.bindpw = bindpw
|
||||
# see if is local or not
|
||||
host1 = IPAdmin.getfqdn(host)
|
||||
host2 = IPAdmin.getfqdn()
|
||||
self.isLocal = (host1 == host2)
|
||||
self.suffixes = {}
|
||||
self.__localinit__()
|
||||
|
||||
def __str__(self):
|
||||
return self.host + ":" + str(self.port)
|
||||
|
||||
def toLDAPURL(self):
|
||||
return "ldap://%s:%d/" % (self.host,self.port)
|
||||
|
||||
def getEntry(self,*args):
|
||||
"""This wraps the search function. It is common to just get one entry"""
|
||||
res = self.search(*args)
|
||||
type, obj = self.result(res)
|
||||
if not obj:
|
||||
raise NoSuchEntryError("no such entry for " + str(args))
|
||||
elif isinstance(obj,Entry):
|
||||
return obj
|
||||
else: # assume list/tuple
|
||||
return obj[0]
|
||||
|
||||
def addEntry(self,*args):
|
||||
"""This wraps the add function. It assumes that the entry is already
|
||||
populated with all of the desired objectclasses and attributes"""
|
||||
try:
|
||||
self.add_s(*args)
|
||||
except ldap.ALREADY_EXISTS:
|
||||
raise ldap.ALREADY_EXISTS
|
||||
except ldap.LDAPError, e:
|
||||
raise e
|
||||
return "Success"
|
||||
|
||||
def __wrapmethods(self):
|
||||
"""This wraps all methods of SimpleLDAPObject, so that we can intercept
|
||||
the methods that deal with entries. Instead of using a raw list of tuples
|
||||
of lists of hashes of arrays as the entry object, we want to wrap entries
|
||||
in an Entry class that provides some useful methods"""
|
||||
for name in dir(self.__class__.__bases__[0]):
|
||||
attr = getattr(self, name)
|
||||
if callable(attr):
|
||||
setattr(self, name, wrapper(attr, name))
|
||||
|
||||
def exportLDIF(self, file, suffix, forrepl=False, verbose=False):
|
||||
cn = "export" + str(int(time.time()))
|
||||
dn = "cn=%s, cn=export, cn=tasks, cn=config" % cn
|
||||
entry = Entry(dn)
|
||||
entry.setValues('objectclass', 'top', 'extensibleObject')
|
||||
entry.setValues('cn', cn)
|
||||
entry.setValues('nsFilename', file)
|
||||
entry.setValues('nsIncludeSuffix', suffix)
|
||||
if forrepl:
|
||||
entry.setValues('nsExportReplica', 'true')
|
||||
|
||||
rc = self.startTaskAndWait(entry, verbose)
|
||||
|
||||
if rc:
|
||||
if verbose:
|
||||
print "Error: export task %s for file %s exited with %d" % (cn,file,rc)
|
||||
else:
|
||||
if verbose:
|
||||
print "Export task %s for file %s completed successfully" % (cn,file)
|
||||
return rc
|
||||
|
||||
def waitForEntry(self, dn, timeout=7200, attr='', quiet=False):
|
||||
scope = ldap.SCOPE_BASE
|
||||
filter = "(objectclass=*)"
|
||||
attrlist = []
|
||||
if attr:
|
||||
filter = "(%s=*)" % attr
|
||||
attrlist.append(attr)
|
||||
timeout += int(time.time())
|
||||
|
||||
if isinstance(dn,Entry):
|
||||
dn = dn.dn
|
||||
|
||||
# wait for entry and/or attr to show up
|
||||
if not quiet:
|
||||
sys.stdout.write("Waiting for %s %s:%s " % (self,dn,attr))
|
||||
sys.stdout.flush()
|
||||
entry = None
|
||||
while not entry and int(time.time()) < timeout:
|
||||
try:
|
||||
entry = self.getEntry(dn, scope, filter, attrlist)
|
||||
except NoSuchEntryError: pass # found entry, but no attr
|
||||
except ldap.NO_SUCH_OBJECT: pass # no entry yet
|
||||
except ldap.LDAPError, e: # badness
|
||||
print "\nError reading entry", dn, e
|
||||
break
|
||||
if not entry:
|
||||
if not quiet:
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
time.sleep(1)
|
||||
|
||||
if not entry and int(time.time()) > timeout:
|
||||
print "\nwaitForEntry timeout for %s for %s" % (self,dn)
|
||||
elif entry and not quiet:
|
||||
print "\nThe waited for entry is:", entry
|
||||
else:
|
||||
print "\nError: could not read entry %s from %s" % (dn,self)
|
||||
|
||||
return entry
|
||||
|
||||
def addSchema(self, attr, val):
|
||||
dn = "cn=schema"
|
||||
self.modify_s(dn, [(ldap.MOD_ADD, attr, val)])
|
||||
|
||||
def addAttr(self, *args):
|
||||
return self.addSchema('attributeTypes', args)
|
||||
|
||||
def addObjClass(self, *args):
|
||||
return self.addSchema('objectClasses', args)
|
||||
|
||||
###########################
|
||||
# Static methods start here
|
||||
###########################
|
||||
def normalizeDN(dn):
|
||||
# not great, but will do until we use a newer version of python-ldap
|
||||
# that has DN utilities
|
||||
ary = ldap.explode_dn(dn.lower())
|
||||
return ",".join(ary)
|
||||
normalizeDN = staticmethod(normalizeDN)
|
||||
|
||||
def getfqdn(name=''):
|
||||
return socket.getfqdn(name)
|
||||
getfqdn = staticmethod(getfqdn)
|
||||
|
||||
def getdomainname(name=''):
|
||||
fqdn = IPAdmin.getfqdn(name)
|
||||
index = fqdn.find('.')
|
||||
if index >= 0:
|
||||
return fqdn[index+1:]
|
||||
else:
|
||||
return fqdn
|
||||
getdomainname = staticmethod(getdomainname)
|
||||
|
||||
def getdefaultsuffix(name=''):
|
||||
dm = IPAdmin.getdomainname(name)
|
||||
if dm:
|
||||
return "dc=" + dm.replace('.', ', dc=')
|
||||
else:
|
||||
return 'dc=localdomain'
|
||||
getdefaultsuffix = staticmethod(getdefaultsuffix)
|
||||
|
||||
def getnewhost(args):
|
||||
"""One of the arguments to createInstance is newhost. If this is specified, we need
|
||||
to convert it to the fqdn. If not given, we need to figure out what the fqdn of the
|
||||
local host is. This method sets newhost in args to the appropriate value and
|
||||
returns True if newhost is the localhost, False otherwise"""
|
||||
isLocal = False
|
||||
if args.has_key('newhost'):
|
||||
args['newhost'] = IPAdmin.getfqdn(args['newhost'])
|
||||
myhost = IPAdmin.getfqdn()
|
||||
if myhost == args['newhost']:
|
||||
isLocal = True
|
||||
elif args['newhost'] == 'localhost' or \
|
||||
args['newhost'] == 'localhost.localdomain':
|
||||
isLocal = True
|
||||
else:
|
||||
isLocal = True
|
||||
args['newhost'] = IPAdmin.getfqdn()
|
||||
return isLocal
|
||||
getnewhost = staticmethod(getnewhost)
|
||||
|
||||
def is_a_dn(dn):
|
||||
"""Returns True if the given string is a DN, False otherwise."""
|
||||
return (dn.find("=") > 0)
|
||||
is_a_dn = staticmethod(is_a_dn)
|
||||
@@ -49,36 +49,10 @@ def generate_kdc_password():
|
||||
rndpwd += chr(r.randint(65,90)) #stricter set for testing
|
||||
return rndpwd
|
||||
|
||||
def template_str(txt, vars):
|
||||
return string.Template(txt).substitute(vars)
|
||||
|
||||
def template_file(infilename, vars):
|
||||
txt = open(infilename).read()
|
||||
return template_str(txt, vars)
|
||||
|
||||
def write_tmp_file(txt):
|
||||
fd = tempfile.NamedTemporaryFile()
|
||||
fd.write(txt)
|
||||
fd.flush()
|
||||
|
||||
return fd
|
||||
|
||||
def ldap_mod(fd, dn, pwd):
|
||||
args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", "-D", dn, "-w", pwd, "-f", fd.name]
|
||||
run(args)
|
||||
|
||||
def run(args, stdin=None):
|
||||
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if stdin:
|
||||
stdout,stderr = p.communicate(stdin)
|
||||
else:
|
||||
stdout,stderr = p.communicate()
|
||||
logging.info(stdout)
|
||||
logging.info(stderr)
|
||||
|
||||
if p.returncode != 0:
|
||||
raise subprocess.CalledProcessError(p.returncode, args[0])
|
||||
|
||||
class KrbInstance:
|
||||
def __init__(self):
|
||||
self.ds_user = None
|
||||
@@ -0,0 +1,80 @@
|
||||
#! /usr/bin/python -E
|
||||
# Authors: Simo Sorce <ssorce@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 or later
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
SHARE_DIR = "/usr/share/ipa/"
|
||||
|
||||
import string
|
||||
import tempfile
|
||||
import logging
|
||||
import subprocess
|
||||
import os
|
||||
import stat
|
||||
|
||||
def realm_to_suffix(realm_name):
|
||||
s = realm_name.split(".")
|
||||
terms = ["dc=" + x.lower() for x in s]
|
||||
return ",".join(terms)
|
||||
|
||||
|
||||
def template_str(txt, vars):
|
||||
return string.Template(txt).substitute(vars)
|
||||
|
||||
def template_file(infilename, vars):
|
||||
txt = open(infilename).read()
|
||||
return template_str(txt, vars)
|
||||
|
||||
def write_tmp_file(txt):
|
||||
fd = tempfile.NamedTemporaryFile()
|
||||
fd.write(txt)
|
||||
fd.flush()
|
||||
|
||||
return fd
|
||||
|
||||
def run(args, stdin=None):
|
||||
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if stdin:
|
||||
stdout,stderr = p.communicate(stdin)
|
||||
else:
|
||||
stdout,stderr = p.communicate()
|
||||
logging.info(stdout)
|
||||
logging.info(stderr)
|
||||
|
||||
if p.returncode != 0:
|
||||
raise subprocess.CalledProcessError(p.returncode, args[0])
|
||||
|
||||
def file_exists(filename):
|
||||
try:
|
||||
mode = os.stat(filename)[stat.ST_MODE]
|
||||
if stat.S_ISREG(mode):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def dir_exists(filename):
|
||||
try:
|
||||
mode = os.stat(filename)[stat.ST_MODE]
|
||||
if stat.S_ISDIR(mode):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
@@ -0,0 +1,12 @@
|
||||
SHAREDIR = $(DESTDIR)/usr/share/ipa/ipaserver
|
||||
HTTPDIR = $(DESTDIR)/etc/httpd/conf.d/
|
||||
|
||||
all: ;
|
||||
|
||||
install:
|
||||
-mkdir -p $(SHAREDIR)
|
||||
install -m 644 *.py $(SHAREDIR)
|
||||
install -m 644 ipa.conf $(HTTPDIR)
|
||||
|
||||
clean:
|
||||
rm -f *~ *.pyc
|
||||
File renamed without changes.
@@ -0,0 +1,170 @@
|
||||
# Authors: Rob Crittenden <rcritten@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 only
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("/usr/share/ipa")
|
||||
|
||||
import ldap
|
||||
import ipaserver.dsinstance
|
||||
import ipaserver.ipaldap
|
||||
import pdb
|
||||
import string
|
||||
from types import *
|
||||
import xmlrpclib
|
||||
|
||||
# FIXME, this needs to be auto-discovered
|
||||
host = 'localhost'
|
||||
port = 389
|
||||
binddn = "cn=directory manager"
|
||||
bindpw = "freeipa"
|
||||
|
||||
basedn = "dc=greyoak,dc=com"
|
||||
scope = ldap.SCOPE_SUBTREE
|
||||
|
||||
def get_user (username):
|
||||
"""Get a specific user's entry. Return as a dict of values.
|
||||
Multi-valued fields are represented as lists.
|
||||
"""
|
||||
ent=""
|
||||
|
||||
# FIXME: Is this the filter we want or should it be more specific?
|
||||
filter = "(uid=" + username + ")"
|
||||
try:
|
||||
m1 = ipaserver.ipaldap.IPAdmin(host,port,binddn,bindpw)
|
||||
ent = m1.getEntry(basedn, scope, filter, None)
|
||||
except ldap.LDAPError, e:
|
||||
raise xmlrpclib.Fault(1, e)
|
||||
except ipaserver.ipaldap.NoSuchEntryError:
|
||||
raise xmlrpclib.Fault(2, "No such user")
|
||||
|
||||
# Convert to LDIF
|
||||
entry = str(ent)
|
||||
|
||||
# Strip off any junk
|
||||
entry = entry.strip()
|
||||
|
||||
# Don't need to identify binary fields and this breaks the parser so
|
||||
# remove double colons
|
||||
entry = entry.replace('::', ':')
|
||||
specs = [spec.split(':') for spec in entry.split('\n')]
|
||||
|
||||
# Convert into a dict. We need to handle multi-valued attributes as well
|
||||
# so we'll convert those into lists.
|
||||
user={}
|
||||
for (k,v) in specs:
|
||||
k = k.lower()
|
||||
if user.get(k) is not None:
|
||||
if isinstance(user[k],list):
|
||||
user[k].append(v.strip())
|
||||
else:
|
||||
first = user[k]
|
||||
user[k] = []
|
||||
user[k].append(first)
|
||||
user[k].append(v.strip())
|
||||
else:
|
||||
user[k] = v.strip()
|
||||
|
||||
return user
|
||||
# return str(ent) # return as LDIF
|
||||
|
||||
def add_user (user):
|
||||
"""Add a user in LDAP"""
|
||||
dn="uid=%s,ou=users,ou=default,dc=greyoak,dc=com" % user['uid']
|
||||
entry = ipaserver.ipaldap.Entry(dn)
|
||||
|
||||
# some required objectclasses
|
||||
entry.setValues('objectClass', 'top', 'posixAccount', 'shadowAccount', 'account', 'person', 'inetOrgPerson', 'organizationalPerson', 'krbPrincipalAux', 'krbTicketPolicyAux')
|
||||
|
||||
# Fill in shadow fields
|
||||
entry.setValue('shadowMin', '0')
|
||||
entry.setValue('shadowMax', '99999')
|
||||
entry.setValue('shadowWarning', '7')
|
||||
entry.setValue('shadowExpire', '-1')
|
||||
entry.setValue('shadowInactive', '-1')
|
||||
entry.setValue('shadowFlag', '-1')
|
||||
|
||||
# FIXME: calculate shadowLastChange
|
||||
|
||||
# fill in our new entry with everything sent by the user
|
||||
for u in user:
|
||||
entry.setValues(u, user[u])
|
||||
|
||||
try:
|
||||
m1 = ipaserver.ipaldap.IPAdmin(host,port,binddn,bindpw)
|
||||
res = m1.addEntry(entry)
|
||||
return res
|
||||
except ldap.ALREADY_EXISTS:
|
||||
raise xmlrpclib.Fault(3, "User already exists")
|
||||
return None
|
||||
except ldap.LDAPError, e:
|
||||
raise xmlrpclib.Fault(1, str(e))
|
||||
return None
|
||||
|
||||
def get_add_schema ():
|
||||
"""Get the list of fields to be used when adding users in the GUI."""
|
||||
|
||||
# FIXME: this needs to be pulled from LDAP
|
||||
fields = []
|
||||
|
||||
field1 = {
|
||||
"name": "uid" ,
|
||||
"label": "Login:",
|
||||
"type": "text",
|
||||
"validator": "text",
|
||||
"required": "true"
|
||||
}
|
||||
fields.append(field1)
|
||||
|
||||
field1 = {
|
||||
"name": "userPassword" ,
|
||||
"label": "Password:",
|
||||
"type": "password",
|
||||
"validator": "String",
|
||||
"required": "true"
|
||||
}
|
||||
fields.append(field1)
|
||||
|
||||
field1 = {
|
||||
"name": "gn" ,
|
||||
"label": "First name:",
|
||||
"type": "text",
|
||||
"validator": "string",
|
||||
"required": "true"
|
||||
}
|
||||
fields.append(field1)
|
||||
|
||||
field1 = {
|
||||
"name": "sn" ,
|
||||
"label": "Last name:",
|
||||
"type": "text",
|
||||
"validator": "string",
|
||||
"required": "true"
|
||||
}
|
||||
fields.append(field1)
|
||||
|
||||
field1 = {
|
||||
"name": "mail" ,
|
||||
"label": "E-mail address:",
|
||||
"type": "text",
|
||||
"validator": "email",
|
||||
"required": "true"
|
||||
}
|
||||
fields.append(field1)
|
||||
|
||||
return fields
|
||||
@@ -0,0 +1,24 @@
|
||||
# LoadModule auth_kerb_module modules/mod_auth_kerb.so
|
||||
|
||||
Alias /ipa "/usr/share/ipa/ipaserver/XMLRPC"
|
||||
|
||||
<Directory "/usr/share/ipa/ipaserver">
|
||||
# AuthType Kerberos
|
||||
# AuthName "Kerberos Login"
|
||||
# KrbMethodNegotiate on
|
||||
# KrbMethodK5Passwd off
|
||||
# KrbServiceName HTTP
|
||||
# KrbAuthRealms GREYOAK.COM
|
||||
# Krb5KeyTab /etc/httpd/conf/ipa.keytab
|
||||
# KrbSaveCredentials on
|
||||
# Require valid-user
|
||||
ErrorDocument 401 /errors/unauthorized.html
|
||||
|
||||
SetHandler mod_python
|
||||
PythonHandler ipaxmlrpc
|
||||
|
||||
PythonDebug Off
|
||||
|
||||
# this is pointless to use since it would just reload ipaxmlrpc.py
|
||||
PythonAutoReload Off
|
||||
</Directory>
|
||||
@@ -0,0 +1,277 @@
|
||||
# mod_python script
|
||||
|
||||
# ipaxmlrpc - an XMLRPC interface for ipa.
|
||||
# Copyright (c) 2007 Red Hat
|
||||
#
|
||||
# IPA is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation;
|
||||
# version 2.1 of the License.
|
||||
#
|
||||
# This software is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this software; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Based on kojixmlrpc - an XMLRPC interface for koji by
|
||||
# Mike McLean <mikem@redhat.com>
|
||||
#
|
||||
# Authors:
|
||||
# Rob Crittenden <rcritten@redhat.com>
|
||||
|
||||
import sys
|
||||
sys.path.append("/usr/share/ipa")
|
||||
|
||||
|
||||
import time
|
||||
import traceback
|
||||
import pprint
|
||||
from xmlrpclib import Marshaller,loads,dumps,Fault
|
||||
from mod_python import apache
|
||||
|
||||
import ipaserver
|
||||
import funcs
|
||||
import string
|
||||
import base64
|
||||
|
||||
#
|
||||
# An override so we can base64 encode all outgoing values.
|
||||
# This is set by calling: Marshaller._Marshaller__dump = xmlrpclib_dump
|
||||
#
|
||||
# Not currently used.
|
||||
#
|
||||
def xmlrpclib_escape(s, replace = string.replace):
|
||||
"""
|
||||
xmlrpclib only handles certain characters. Lets encode the whole
|
||||
blob
|
||||
"""
|
||||
|
||||
return base64.encodestring(s)
|
||||
|
||||
def xmlrpclib_dump(self, value, write):
|
||||
"""
|
||||
xmlrpclib cannot marshal instances of subclasses of built-in
|
||||
types. This function overrides xmlrpclib.Marshaller.__dump so that
|
||||
any value that is an instance of one of its acceptable types is
|
||||
marshalled as that type.
|
||||
|
||||
xmlrpclib also cannot handle invalid 7-bit control characters. See
|
||||
above.
|
||||
"""
|
||||
|
||||
# Use our escape function
|
||||
args = [self, value, write]
|
||||
if isinstance(value, (str, unicode)):
|
||||
args.append(xmlrpclib_escape)
|
||||
|
||||
try:
|
||||
# Try for an exact match first
|
||||
f = self.dispatch[type(value)]
|
||||
except KeyError:
|
||||
# Try for an isinstance() match
|
||||
for Type, f in self.dispatch.iteritems():
|
||||
if isinstance(value, Type):
|
||||
f(*args)
|
||||
return
|
||||
raise TypeError, "cannot marshal %s objects" % type(value)
|
||||
else:
|
||||
f(*args)
|
||||
|
||||
|
||||
class ModXMLRPCRequestHandler(object):
|
||||
"""Simple XML-RPC handler for mod_python environment"""
|
||||
|
||||
def __init__(self):
|
||||
self.funcs = {}
|
||||
self.traceback = False
|
||||
#introspection functions
|
||||
self.register_function(self.list_api, name="_listapi")
|
||||
self.register_function(self.system_listMethods, name="system.listMethods")
|
||||
self.register_function(self.system_methodSignature, name="system.methodSignature")
|
||||
self.register_function(self.system_methodHelp, name="system.methodHelp")
|
||||
self.register_function(self.multiCall)
|
||||
|
||||
def register_function(self, function, name = None):
|
||||
if name is None:
|
||||
name = function.__name__
|
||||
self.funcs[name] = function
|
||||
|
||||
def register_module(self, instance, prefix=None):
|
||||
"""Register all the public functions in an instance with prefix prepended
|
||||
|
||||
For example
|
||||
h.register_module(exports,"pub.sys")
|
||||
will register the methods of exports with names like
|
||||
pub.sys.method1
|
||||
pub.sys.method2
|
||||
...etc
|
||||
"""
|
||||
for name in dir(instance):
|
||||
if name.startswith('_'):
|
||||
continue
|
||||
function = getattr(instance, name)
|
||||
if not callable(function):
|
||||
continue
|
||||
if prefix is not None:
|
||||
name = "%s.%s" %(prefix,name)
|
||||
self.register_function(function, name=name)
|
||||
|
||||
def register_instance(self,instance):
|
||||
self.register_module(instance)
|
||||
|
||||
def _marshaled_dispatch(self, data):
|
||||
"""Dispatches an XML-RPC method from marshalled (XML) data."""
|
||||
|
||||
params, method = loads(data)
|
||||
|
||||
# special case
|
||||
# if method == "get_user":
|
||||
# Marshaller._Marshaller__dump = xmlrpclib_dump
|
||||
|
||||
start = time.time()
|
||||
# generate response
|
||||
try:
|
||||
response = self._dispatch(method, params)
|
||||
# wrap response in a singleton tuple
|
||||
response = (response,)
|
||||
response = dumps(response, methodresponse=1, allow_none=1)
|
||||
except Fault, fault:
|
||||
self.traceback = True
|
||||
response = dumps(fault)
|
||||
except:
|
||||
self.traceback = True
|
||||
# report exception back to server
|
||||
e_class, e = sys.exc_info()[:2]
|
||||
faultCode = getattr(e_class,'faultCode',1)
|
||||
tb_str = ''.join(traceback.format_exception(*sys.exc_info()))
|
||||
faultString = tb_str
|
||||
response = dumps(Fault(faultCode, faultString))
|
||||
|
||||
return response
|
||||
|
||||
def _dispatch(self,method,params):
|
||||
func = self.funcs.get(method,None)
|
||||
if func is None:
|
||||
raise Fault(1, "Invalid method: %s" % method)
|
||||
params,opts = ipaserver.decode_args(*params)
|
||||
|
||||
ret = func(*params,**opts)
|
||||
|
||||
return ret
|
||||
|
||||
def multiCall(self, calls):
|
||||
"""Execute a multicall. Execute each method call in the calls list, collecting
|
||||
results and errors, and return those as a list."""
|
||||
results = []
|
||||
for call in calls:
|
||||
try:
|
||||
result = self._dispatch(call['methodName'], call['params'])
|
||||
except Fault, fault:
|
||||
results.append({'faultCode': fault.faultCode, 'faultString': fault.faultString})
|
||||
except:
|
||||
# transform unknown exceptions into XML-RPC Faults
|
||||
# don't create a reference to full traceback since this creates
|
||||
# a circular reference.
|
||||
exc_type, exc_value = sys.exc_info()[:2]
|
||||
faultCode = getattr(exc_type, 'faultCode', 1)
|
||||
faultString = ', '.join(exc_value.args)
|
||||
trace = traceback.format_exception(*sys.exc_info())
|
||||
# traceback is not part of the multicall spec, but we include it for debugging purposes
|
||||
results.append({'faultCode': faultCode, 'faultString': faultString, 'traceback': trace})
|
||||
else:
|
||||
results.append([result])
|
||||
|
||||
return results
|
||||
|
||||
def list_api(self):
|
||||
funcs = []
|
||||
for name,func in self.funcs.items():
|
||||
#the keys in self.funcs determine the name of the method as seen over xmlrpc
|
||||
#func.__name__ might differ (e.g. for dotted method names)
|
||||
args = self._getFuncArgs(func)
|
||||
funcs.append({'name': name,
|
||||
'doc': func.__doc__,
|
||||
'args': args})
|
||||
return funcs
|
||||
|
||||
def _getFuncArgs(self, func):
|
||||
args = []
|
||||
for x in range(0, func.func_code.co_argcount):
|
||||
if x == 0 and func.func_code.co_varnames[x] == "self":
|
||||
continue
|
||||
if func.func_defaults and func.func_code.co_argcount - x <= len(func.func_defaults):
|
||||
args.append((func.func_code.co_varnames[x], func.func_defaults[x - func.func_code.co_argcount + len(func.func_defaults)]))
|
||||
else:
|
||||
args.append(func.func_code.co_varnames[x])
|
||||
return args
|
||||
|
||||
def system_listMethods(self):
|
||||
return self.funcs.keys()
|
||||
|
||||
def system_methodSignature(self, method):
|
||||
#it is not possible to autogenerate this data
|
||||
return 'signatures not supported'
|
||||
|
||||
def system_methodHelp(self, method):
|
||||
func = self.funcs.get(method)
|
||||
if func is None:
|
||||
return ""
|
||||
arglist = []
|
||||
for arg in self._getFuncArgs(func):
|
||||
if isinstance(arg,str):
|
||||
arglist.append(arg)
|
||||
else:
|
||||
arglist.append('%s=%s' % (arg[0], arg[1]))
|
||||
ret = '%s(%s)' % (method, ", ".join(arglist))
|
||||
if func.__doc__:
|
||||
ret += "\ndescription: %s" % func.__doc__
|
||||
return ret
|
||||
|
||||
def handle_request(self,req):
|
||||
"""Handle a single XML-RPC request"""
|
||||
|
||||
# XMLRPC uses POST only. Reject anything else
|
||||
if req.method != 'POST':
|
||||
req.allow_methods(['POST'],1)
|
||||
raise apache.SERVER_RETURN, apache.HTTP_METHOD_NOT_ALLOWED
|
||||
|
||||
response = self._marshaled_dispatch(req.read())
|
||||
|
||||
req.content_type = "text/xml"
|
||||
req.set_content_length(len(response))
|
||||
req.write(response)
|
||||
|
||||
|
||||
#
|
||||
# mod_python handler
|
||||
#
|
||||
|
||||
def handler(req, profiling=False):
|
||||
if profiling:
|
||||
import profile, pstats, StringIO, tempfile
|
||||
global _profiling_req
|
||||
_profiling_req = req
|
||||
temp = tempfile.NamedTemporaryFile()
|
||||
profile.run("import ipxmlrpc; ipaxmlrpc.handler(ipaxmlrpc._profiling_req, False)", temp.name)
|
||||
stats = pstats.Stats(temp.name)
|
||||
strstream = StringIO.StringIO()
|
||||
sys.stdout = strstream
|
||||
stats.sort_stats("time")
|
||||
stats.print_stats()
|
||||
req.write("<pre>" + strstream.getvalue() + "</pre>")
|
||||
_profiling_req = None
|
||||
else:
|
||||
opts = req.get_options()
|
||||
try:
|
||||
h = ModXMLRPCRequestHandler()
|
||||
h.register_function(funcs.get_user)
|
||||
h.register_function(funcs.add_user)
|
||||
h.register_function(funcs.get_add_schema)
|
||||
h.handle_request(req)
|
||||
finally:
|
||||
pass
|
||||
return apache.OK
|
||||
Whitespace-only changes.
Whitespace-only changes.
Reference in new issue
Block a user