From a5617680bac3b34dbd5b4654b11f35cec180e72d Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 10 Dec 2007 16:31:21 -0500 Subject: Move dnsclient into ipa-python so that I will be able to use it in ipaconfig --- ipa-python/MANIFEST.in | 2 +- ipa-python/dnsclient.py | 445 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 446 insertions(+), 1 deletion(-) create mode 100644 ipa-python/dnsclient.py (limited to 'ipa-python') diff --git a/ipa-python/MANIFEST.in b/ipa-python/MANIFEST.in index 49f2126a..e2cad6f2 100644 --- a/ipa-python/MANIFEST.in +++ b/ipa-python/MANIFEST.in @@ -1,3 +1,3 @@ include *.conf -include freeipa-python.spec* +include ipa-python.spec* diff --git a/ipa-python/dnsclient.py b/ipa-python/dnsclient.py new file mode 100644 index 00000000..bc8a229c --- /dev/null +++ b/ipa-python/dnsclient.py @@ -0,0 +1,445 @@ +# +# Copyright 2001, 2005 Red Hat, Inc. +# +# This 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; either version 2 of the License, or +# (at your option) any later version. +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +import struct +import socket +import sys + +import acutil + +DNS_C_IN = 1 +DNS_C_CS = 2 +DNS_C_CHAOS = 3 +DNS_C_HS = 4 +DNS_C_ANY = 255 + +DNS_T_A = 1 +DNS_T_NS = 2 +DNS_T_CNAME = 5 +DNS_T_SOA = 6 +DNS_T_NULL = 10 +DNS_T_WKS = 11 +DNS_T_PTR = 12 +DNS_T_HINFO = 13 +DNS_T_MX = 15 +DNS_T_TXT = 16 +DNS_T_SRV = 33 +DNS_T_ANY = 255 + +DEBUG_DNSCLIENT = False + +class DNSQueryHeader: + FORMAT = "!HBBHHHH" + def __init__(self): + self.dns_id = 0 + self.dns_rd = 0 + self.dns_tc = 0 + self.dns_aa = 0 + self.dns_opcode = 0 + self.dns_qr = 0 + self.dns_rcode = 0 + self.dns_z = 0 + self.dns_ra = 0 + self.dns_qdcount = 0 + self.dns_ancount = 0 + self.dns_nscount = 0 + self.dns_arcount = 0 + + def pack(self): + return struct.pack(DNSQueryHeader.FORMAT, + self.dns_id, + (self.dns_rd & 1) | + (self.dns_tc & 1) << 1 | + (self.dns_aa & 1) << 2 | + (self.dns_opcode & 15) << 3 | + (self.dns_qr & 1) << 7, + (self.dns_rcode & 15) | + (self.dns_z & 7) << 4 | + (self.dns_ra & 1) << 7, + self.dns_qdcount, + self.dns_ancount, + self.dns_nscount, + self.dns_arcount) + + def unpack(self, data): + (self.dns_id, byte1, byte2, self.dns_qdcount, self.dns_ancount, + self.dns_nscount, self.dns_arcount) = struct.unpack(DNSQueryHeader.FORMAT, data[0:self.size()]) + self.dns_rd = byte1 & 1 + self.dns_tc = (byte1 >> 1) & 1 + self.dns_aa = (byte1 >> 2) & 1 + self.dns_opcode = (byte1 >> 3) & 15 + self.dns_qr = (byte1 >> 7) & 1 + self.dns_rcode = byte2 & 15 + self.dns_z = (byte2 >> 4) & 7 + self.dns_ra = (byte1 >> 7) & 1 + + def size(self): + return struct.calcsize(DNSQueryHeader.FORMAT) + +def unpackQueryHeader(data): + header = DNSQueryHeader() + header.unpack(data) + return header + +class DNSResult: + FORMAT = "!HHIH" + QFORMAT = "!HH" + def __init__(self): + self.dns_name = "" + self.dns_type = 0 + self.dns_class = 0 + self.dns_ttl = 0 + self.dns_rlength = 0 + self.rdata = None + + def unpack(self, data): + (self.dns_type, self.dns_class, self.dns_ttl, + self.dns_rlength) = struct.unpack(DNSResult.FORMAT, data[0:self.size()]) + + def qunpack(self, data): + (self.dns_type, self.dns_class) = struct.unpack(DNSResult.QFORMAT, data[0:self.qsize()]) + + def size(self): + return struct.calcsize(DNSResult.FORMAT) + + def qsize(self): + return struct.calcsize(DNSResult.QFORMAT) + +class DNSRData: + def __init__(self): + pass + +#typedef struct dns_rr_a { +# u_int32_t address; +#} dns_rr_a_t; +# +#typedef struct dns_rr_cname { +# const char *cname; +#} dns_rr_cname_t; +# +#typedef struct dns_rr_hinfo { +# const char *cpu, *os; +#} dns_rr_hinfo_t; +# +#typedef struct dns_rr_mx { +# u_int16_t preference; +# const char *exchange; +#} dns_rr_mx_t; +# +#typedef struct dns_rr_null { +# unsigned const char *data; +#} dns_rr_null_t; +# +#typedef struct dns_rr_ns { +# const char *nsdname; +#} dns_rr_ns_t; +# +#typedef struct dns_rr_ptr { +# const char *ptrdname; +#} dns_rr_ptr_t; +# +#typedef struct dns_rr_soa { +# const char *mname; +# const char *rname; +# u_int32_t serial; +# int32_t refresh; +# int32_t retry; +# int32_t expire; +# int32_t minimum; +#} dns_rr_soa_t; +# +#typedef struct dns_rr_txt { +# const char *data; +#} dns_rr_txt_t; +# +#typedef struct dns_rr_srv { +# const char *server; +# u_int16_t priority; +# u_int16_t weight; +# u_int16_t port; +#} dns_rr_srv_t; + +def dnsNameToLabel(name): + out = "" + name = name.split(".") + for part in name: + out += chr(len(part)) + part + return out + +def dnsFormatQuery(query, qclass, qtype): + header = DNSQueryHeader() + + header.dns_id = 0 # FIXME: id = 0 + header.dns_rd = 1 # don't know why the original code didn't request recursion for non SOA requests + header.dns_qr = 0 # query + header.dns_opcode = 0 # standard query + header.dns_qdcount = 1 # single query + + qlabel = dnsNameToLabel(query) + if not qlabel: + return "" + + out = header.pack() + qlabel + out += chr(qtype >> 8) + out += chr(qtype & 0xff) + out += chr(qclass >> 8) + out += chr(qclass & 0xff) + + return out + +def dnsParseLabel(label, base): + # returns (output, rest) + if not label: + return ("", None) + + update = 1 + rest = label + output = "" + skip = 0 + + try: + while ord(rest[0]): + if ord(rest[0]) & 0xc0: + rest = base[((ord(rest[0]) & 0x3f) << 8) + ord(rest[1]):] + if update: + skip += 2 + update = 0 + continue + output += rest[1:ord(rest[0]) + 1] + "." + if update: + skip += ord(rest[0]) + 1 + rest = rest[ord(rest[0]) + 1:] + except IndexError: + return ("", None) + return (label[skip+update:], output) + +def dnsParseA(data, base): + rdata = DNSRData() + if len(data) < 4: + rdata.address = 0 + return None + + rdata.address = (ord(data[0])<<24) | (ord(data[1])<<16) | (ord(data[2])<<8) | (ord(data[3])<<0) + + if DEBUG_DNSCLIENT: + print "A = %d.%d.%d.%d." % (ord(data[0]), ord(data[1]), ord(data[2]), ord(data[3])) + return rdata + +def dnsParseText(data): + if len(data) < 1: + return ("", None) + tlen = ord(data[0]) + if len(data) < tlen + 1: + return ("", None) + return (data[tlen+1:], data[1:tlen+1]) + +def dnsParseNS(data, base): + rdata = DNSRData() + (rest, rdata.nsdname) = dnsParseLabel(data, base) + if DEBUG_DNSCLIENT: + print "NS DNAME = \"%s\"." % (rdata.nsdname) + return rdata + +def dnsParseCNAME(data, base): + rdata = DNSRData() + (rest, rdata.cname) = dnsParseLabel(data, base) + if DEBUG_DNSCLIENT: + print "CNAME = \"%s\"." % (rdata.cname) + return rdata + +def dnsParseSOA(data, base): + rdata = DNSRData() + format = "!IIIII" + + (rest, rdata.mname) = dnsParseLabel(data, base) + if rdata.mname is None: + return None + (rest, rdata.rname) = dnsParseLabel(rest, base) + if rdata.rname is None: + return None + if len(rest) < struct.calcsize(format): + return None + + (rdata.serial, rdata.refresh, rdata.retry, rdata.expire, + rdata.minimum) = struct.unpack(format, rest[:struct.calcsize(format)]) + + if DEBUG_DNSCLIENT: + print "SOA(mname) = \"%s\"." % rdata.mname + print "SOA(rname) = \"%s\"." % rdata.rname + print "SOA(serial) = %d." % rdata.serial + print "SOA(refresh) = %d." % rdata.refresh + print "SOA(retry) = %d." % rdata.retry + print "SOA(expire) = %d." % rdata.expire + print "SOA(minimum) = %d." % rdata.minimum + return rdata + +def dnsParseNULL(data, base): + # um, yeah + return None + +def dnsParseWKS(data, base): + return None + +def dnsParseHINFO(data, base): + rdata = DNSRData() + (rest, rdata.cpu) = dnsParseText(data) + if rest: + (rest, rdata.os) = dnsParseText(rest) + if DEBUG_DNSCLIENT: + print "HINFO(cpu) = \"%s\"." % rdata.cpu + print "HINFO(os) = \"%s\"." % rdata.os + return rdata + +def dnsParseMX(data, base): + rdata = DNSRData() + if len(data) < 2: + return None + rdata.preference = (ord(data[0]) << 8) | ord(data[1]) + (rest, rdata.exchange) = dnsParseLabel(data[2:], base) + if DEBUG_DNSCLIENT: + print "MX(exchanger) = \"%s\"." % rdata.exchange + print "MX(preference) = %d." % rdata.preference + return rdata + +def dnsParseTXT(data, base): + rdata = DNSRData() + (rest, rdata.data) = dnsParseText(data) + if DEBUG_DNSCLIENT: + print "TXT = \"%s\"." % rdata.data + return rdata + +def dnsParsePTR(data, base): + rdata = DNSRData() + (rest, rdata.ptrdname) = dnsParseLabel(data, base) + if DEBUG_DNSCLIENT: + print "PTR = \"%s\"." % rdata.ptrdname + +def dnsParseSRV(data, base): + rdata = DNSRData() + format = "!HHH" + flen = struct.calcsize(format) + if len(data) < flen: + return None + + (rdata.priority, rdata.weight, rdata.port) = struct.unpack(format, data[:flen]) + (rest, rdata.server) = dnsParseLabel(data[flen:], base) + if DEBUG_DNSCLIENT: + print "SRV(server) = \"%s\"." % rdata.server + print "SRV(weight) = %d." % rdata.weight + print "SRV(priority) = %d." % rdata.priority + print "SRV(port) = %d." % rdata.port + return rdata + +def dnsParseResults(results): + try: + header = unpackQueryHeader(results) + except struct.error: + return [] + + if header.dns_qr != 1: # should be a response + return [] + + if header.dns_rcode != 0: # should be no error + return [] + + rest = results[header.size():] + + rrlist = [] + + for i in xrange(header.dns_qdcount): + if not rest: + return [] + + rr = DNSResult() + + (rest, label) = dnsParseLabel(rest, results) + if label is None: + return [] + + if len(rest) < rr.qsize(): + return [] + + rr.qunpack(rest) + + rest = rest[rr.qsize():] + + if DEBUG_DNSCLIENT: + print "Queried for '%s', class = %d, type = %d." % (label, + rr.dns_class, rr.dns_type) + + for i in xrange(header.dns_ancount + header.dns_nscount + header.dns_arcount): + (rest, label) = dnsParseLabel(rest, results) + if label is None: + return [] + + rr = DNSResult() + + rr.dns_name = label + + if len(rest) < rr.size(): + return [] + + rr.unpack(rest) + + rest = rest[rr.size():] + + if DEBUG_DNSCLIENT: + print "Answer %d for '%s', class = %d, type = %d, ttl = %d." % (i, + rr.dns_name, rr.dns_class, rr.dns_type, + rr.dns_ttl) + + if len(rest) < rr.dns_rlength: + if DEBUG_DNSCLIENT: + print "Answer too short." + return [] + + fmap = { DNS_T_A: dnsParseA, DNS_T_NS: dnsParseNS, + DNS_T_CNAME: dnsParseCNAME, DNS_T_SOA: dnsParseSOA, + DNS_T_NULL: dnsParseNULL, DNS_T_WKS: dnsParseWKS, + DNS_T_PTR: dnsParsePTR, DNS_T_HINFO: dnsParseHINFO, + DNS_T_MX: dnsParseMX, DNS_T_TXT: dnsParseTXT, + DNS_T_SRV: dnsParseSRV} + + if not rr.dns_type in fmap: + if DEBUG_DNSCLIENT: + print "Don't know how to parse RR type %d!" % rr.dns_type + else: + rr.rdata = fmap[rr.dns_type](rest[:rr.dns_rlength], results) + + rest = rest[rr.dns_rlength:] + rrlist += [rr] + + if not rrlist: + rrlist = [rr] + return rrlist + +def query(query, qclass, qtype): + qdata = dnsFormatQuery(query, qclass, qtype) + if not qdata: + return [] + answer = acutil.res_send(qdata) + if not answer: + return [] + return dnsParseResults(answer) + +if __name__ == '__main__': + DEBUG_DNSCLIENT = True + print "Sending query." + rr = query(len(sys.argv) > 1 and sys.argv[1] or "devserv.devel.redhat.com.", + DNS_C_IN, DNS_T_ANY) + sys.exit(0) -- cgit From 463a0462d3bbd5491ab70befdb0e559f8dd7872a Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 11 Dec 2007 10:58:39 -0500 Subject: Make admintools discover the domain using DNS calls to find the LDAP server. --- ipa-python/config.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) (limited to 'ipa-python') diff --git a/ipa-python/config.py b/ipa-python/config.py index a17e585b..c1a3915d 100644 --- a/ipa-python/config.py +++ b/ipa-python/config.py @@ -20,6 +20,10 @@ import ConfigParser from optparse import OptionParser +import krbV +import socket +import ipa.dnsclient + class IPAConfigError(Exception): def __init__(self, msg=''): self.msg = msg @@ -55,11 +59,51 @@ def __parse_config(): p.read("/etc/ipa/ipa.conf") try: - config.default_realm = p.get("defaults", "realm") - config.default_server = p.get("defaults", "server") + if not config.default_realm: + config.default_realm = p.get("defaults", "realm") + if not config.default_server: + config.default_server = p.get("defaults", "server") except: pass +def __discover_config(): + try: + if not config.default_realm: + krbctx = krbV.default_context() + config.default_realm = krbctx.default_realm + if not config.default_realm: + return False + + if not config.default_server: + #try once with REALM -> domain + name = "_ldap._tcp."+config.default_realm+"." + rs = ipa.dnsclient.query(name, ipa.dnsclient.DNS_C_IN, ipa.dnsclient.DNS_T_SRV) + rl = len(rs) + + #try cycling on domain components of FQDN + if rl == 0: + name = socket.getfqdn() + while rl == 0: + tok = name.find(".") + if tok == -1: + return False + name = name[tok+1:] + q = "_ldap._tcp." + name + "." + rs = ipa.dnsclient.query(q, ipa.dnsclient.DNS_C_IN, ipa.dnsclient.DNS_T_SRV) + rl = len(rs) + + for r in rs: + if r.dns_type == ipa.dnsclient.DNS_T_SRV: + rsrv = r.rdata.server.rstrip(".") + # we take only the first one returned for now + config.default_server = rsrv + return True + + #if none found + return False + except: + return False + def usage(): return """ --realm\tset the IPA realm --server\tset the IPA server @@ -92,15 +136,17 @@ def __parse_args(args): def init_config(args=None): - __parse_config() out_args = None if args: out_args = __parse_args(args) + __discover_config() + __parse_config() + if not config.default_realm: - raise IPAConfigError("realm not specified in config file or on command line") + raise IPAConfigError("realm not found, nor specified in config file or on command line") if not config.default_server: - raise IPAConfigError("server not specified in config file or on command line") + raise IPAConfigError("server not found, nor specified in config file or on command line") if out_args: return out_args -- cgit From 23ffab533fde03171b023d50ba72b53d0ab8f1d7 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 11 Dec 2007 17:34:15 -0500 Subject: Make the old entry option in update_*, check for empty parameters and fix some problems reported by pychecker. --- ipa-python/ipaclient.py | 4 ---- ipa-python/ipaerror.py | 6 +++--- ipa-python/rpcclient.py | 35 ++++++++--------------------------- 3 files changed, 11 insertions(+), 34 deletions(-) (limited to 'ipa-python') diff --git a/ipa-python/ipaclient.py b/ipa-python/ipaclient.py index d815afa7..bd1fb235 100644 --- a/ipa-python/ipaclient.py +++ b/ipa-python/ipaclient.py @@ -19,14 +19,10 @@ #!/usr/bin/python -import sys - import ipa.rpcclient as rpcclient import entity import user import group -import ipa -import config import radius_util class IPAClient: diff --git a/ipa-python/ipaerror.py b/ipa-python/ipaerror.py index e3496336..59e26201 100644 --- a/ipa-python/ipaerror.py +++ b/ipa-python/ipaerror.py @@ -129,14 +129,14 @@ LDAP_NO_CONFIG = gen_error_code( "IPA configuration not found") # -# Input errors (sample - replace me) +# Function input errors # INPUT_CATEGORY = 0x0002 -INPUT_INVALID_ERROR = gen_error_code( +INPUT_INVALID_PARAMETER = gen_error_code( INPUT_CATEGORY, 0x0001, - "Illegal input") + "Invalid parameter(s)") # # Connection errors diff --git a/ipa-python/rpcclient.py b/ipa-python/rpcclient.py index 5656b99d..c993ac99 100644 --- a/ipa-python/rpcclient.py +++ b/ipa-python/rpcclient.py @@ -24,11 +24,8 @@ import socket import config from krbtransport import KerbTransport from kerberos import GSSError -import os -import base64 -import user -import ipa from ipa import ipaerror, ipautil +from ipa import config # Some errors to catch # http://cvs.fedora.redhat.com/viewcvs/ldapserver/ldap/servers/plugins/pam_passthru/README?root=dirsec&rev=1.6&view=auto @@ -36,7 +33,7 @@ from ipa import ipaerror, ipautil class RPCClient: def __init__(self): - ipa.config.init_config() + config.init_config() def server_url(self): """Build the XML-RPC server URL from our configuration""" @@ -47,25 +44,6 @@ class RPCClient: authentication""" return xmlrpclib.ServerProxy(self.server_url(), KerbTransport()) - def convert_entry(self,ent): - # Convert into a dict. We need to handle multi-valued attributes as well - # so we'll convert those into lists. - obj={} - for (k) in ent: - k = k.lower() - if obj.get(k) is not None: - if isinstance(obj[k],list): - obj[k].append(ent[k].strip()) - else: - first = obj[k] - obj[k] = () - obj[k].append(first) - obj[k].append(ent[k].strip()) - else: - obj[k] = ent[k] - - return obj - # Higher-level API def get_aci_entry(self, sattrs=None): @@ -168,7 +146,8 @@ class RPCClient: def get_user_by_email(self,email,sattrs=None): """Get a specific user's entry. Return as a dict of values. - Multi-valued fields are represented as lists. + Multi-valued fields are represented as lists. The result is a + dict. """ server = self.setup_server() if sattrs is None: @@ -245,7 +224,7 @@ class RPCClient: return ipautil.unwrap_binary_data(result) def get_all_users (self): - """Return a list containing a User object for each existing user.""" + """Return a list containing a dict for each existing user.""" server = self.setup_server() try: @@ -258,7 +237,7 @@ class RPCClient: return ipautil.unwrap_binary_data(result) def find_users (self, criteria, sattrs=None, searchlimit=0, timelimit=-1): - """Return a list: counter followed by a User object for each user that + """Return a list: counter followed by a dict for each user that matches the criteria. If the results are truncated, counter will be set to -1""" @@ -381,6 +360,8 @@ class RPCClient: except socket.error, (value, msg): raise xmlrpclib.Fault(value, msg) + return ipautil.unwrap_binary_data(result) + def find_groups (self, criteria, sattrs=None, searchlimit=0, timelimit=-1): """Return a list containing a Group object for each group that matches the criteria.""" -- cgit From cf595511ff9e55b5f10a3273575980d6bb39d67a Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 18:06:39 -0500 Subject: Move radius server components into a separate package. --- ipa-python/ipautil.py | 1 + ipa-python/radius_util.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'ipa-python') diff --git a/ipa-python/ipautil.py b/ipa-python/ipautil.py index 3c2b37f7..c617854e 100644 --- a/ipa-python/ipautil.py +++ b/ipa-python/ipautil.py @@ -18,6 +18,7 @@ # SHARE_DIR = "/usr/share/ipa/" +PLUGINS_SHARE_DIR = "/usr/share/ipa/plugins" import string import tempfile diff --git a/ipa-python/radius_util.py b/ipa-python/radius_util.py index 1f6e7902..40b0bd25 100644 --- a/ipa-python/radius_util.py +++ b/ipa-python/radius_util.py @@ -79,7 +79,7 @@ RADIUS_USER = 'radiusd' RADIUS_IPA_KEYTAB_FILEPATH = os.path.join(RADIUS_PKG_CONFIG_DIR, 'ipa.keytab') RADIUS_LDAP_ATTR_MAP_FILEPATH = os.path.join(RADIUS_PKG_CONFIG_DIR, 'ldap.attrmap') RADIUSD_CONF_FILEPATH = os.path.join(RADIUS_PKG_CONFIG_DIR, 'radiusd.conf') -RADIUSD_CONF_TEMPLATE_FILEPATH = os.path.join(ipautil.SHARE_DIR, 'radius.radiusd.conf.template') +RADIUSD_CONF_TEMPLATE_FILEPATH = os.path.join(ipautil.PLUGINS_SHARE_DIR, 'radius.radiusd.conf.template') RADIUSD = '/usr/sbin/radiusd' -- cgit From 2dd8c346f34f361c19166c5033a2af8c1367159b Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 13 Dec 2007 09:31:28 +0000 Subject: Fix ipa-python packaging Latest Fedora 9 python distutils generates .egg-info files; follow the recommendation at: http://fedoraproject.org/wiki/Packaging/Python/Eggs and just package everything under %{python_sitelib}/ Signed-off-by: Mark McLoughlin --- ipa-python/ipa-python.spec | 5 +---- ipa-python/ipa-python.spec.in | 5 +---- ipa-python/setup.py | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) (limited to 'ipa-python') diff --git a/ipa-python/ipa-python.spec b/ipa-python/ipa-python.spec index 2837a283..1c838821 100755 --- a/ipa-python/ipa-python.spec +++ b/ipa-python/ipa-python.spec @@ -14,8 +14,6 @@ Requires: PyKerberos %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%define pkgpythondir %{python_sitelib}/ipa - %description Ipa is a server for identity, policy, and audit. @@ -33,8 +31,7 @@ rm -rf %{buildroot} %files %defattr(-,root,root,-) -%dir %{pkgpythondir} -%{pkgpythondir}/* +%{python_sitelib}/* %config(noreplace) %{_sysconfdir}/ipa/ipa.conf %changelog diff --git a/ipa-python/ipa-python.spec.in b/ipa-python/ipa-python.spec.in index bd8ac0da..9eb2e11c 100755 --- a/ipa-python/ipa-python.spec.in +++ b/ipa-python/ipa-python.spec.in @@ -14,8 +14,6 @@ Requires: PyKerberos %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%define pkgpythondir %{python_sitelib}/ipa - %description Ipa is a server for identity, policy, and audit. @@ -33,8 +31,7 @@ rm -rf %{buildroot} %files %defattr(-,root,root,-) -%dir %{pkgpythondir} -%{pkgpythondir}/* +%{python_sitelib}/* %config(noreplace) %{_sysconfdir}/ipa/ipa.conf %changelog diff --git a/ipa-python/setup.py b/ipa-python/setup.py index 3a5a6f4e..deb84f29 100644 --- a/ipa-python/setup.py +++ b/ipa-python/setup.py @@ -34,7 +34,7 @@ def setup_package(): try: setup( - name = "freeipa-python", + name = "ipa", version = "0.5.0", license = "GPL", author = "Karl MacMillan, et.al.", -- cgit