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-client/ipaclient/Makefile.am | 1 - ipa-client/ipaclient/__init__.py | 2 +- ipa-client/ipaclient/dnsclient.py | 445 ----------------------------------- ipa-client/ipaclient/ipadiscovery.py | 14 +- ipa-python/MANIFEST.in | 2 +- ipa-python/dnsclient.py | 445 +++++++++++++++++++++++++++++++++++ 6 files changed, 454 insertions(+), 455 deletions(-) delete mode 100644 ipa-client/ipaclient/dnsclient.py create mode 100644 ipa-python/dnsclient.py diff --git a/ipa-client/ipaclient/Makefile.am b/ipa-client/ipaclient/Makefile.am index 038238926..290ffef8d 100644 --- a/ipa-client/ipaclient/Makefile.am +++ b/ipa-client/ipaclient/Makefile.am @@ -3,7 +3,6 @@ NULL = appdir = $(IPA_DATA_DIR)/ipaclient app_PYTHON = \ __init__.py \ - dnsclient.py \ ipachangeconf.py \ ipadiscovery.py \ ntpconf.py \ diff --git a/ipa-client/ipaclient/__init__.py b/ipa-client/ipaclient/__init__.py index c07a549a5..ba14d3c4c 100644 --- a/ipa-client/ipaclient/__init__.py +++ b/ipa-client/ipaclient/__init__.py @@ -18,5 +18,5 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -__all__ = ["ipadiscovery", "ipachangeconf", "dnsclient"] +__all__ = ["ipadiscovery", "ipachangeconf"] diff --git a/ipa-client/ipaclient/dnsclient.py b/ipa-client/ipaclient/dnsclient.py deleted file mode 100644 index bc8a229cd..000000000 --- a/ipa-client/ipaclient/dnsclient.py +++ /dev/null @@ -1,445 +0,0 @@ -# -# 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) diff --git a/ipa-client/ipaclient/ipadiscovery.py b/ipa-client/ipaclient/ipadiscovery.py index 6f44ffd1b..939d41056 100644 --- a/ipa-client/ipaclient/ipadiscovery.py +++ b/ipa-client/ipaclient/ipadiscovery.py @@ -20,7 +20,7 @@ import socket import logging -import dnsclient +import ipa.dnsclient import ldap from ldap import LDAPError @@ -191,10 +191,10 @@ class IPADiscovery: # terminate the name if not qname.endswith("."): qname += "." - results = dnsclient.query(qname, dnsclient.DNS_C_IN, dnsclient.DNS_T_SRV) + results = ipa.dnsclient.query(qname, ipa.dnsclient.DNS_C_IN, ipa.dnsclient.DNS_T_SRV) for result in results: - if result.dns_type == dnsclient.DNS_T_SRV: + if result.dns_type == ipa.dnsclient.DNS_T_SRV: rserver = result.rdata.server.rstrip(".") if result.rdata.port and result.rdata.port != 389: rserver += ":" + str(result.rdata.port) @@ -214,10 +214,10 @@ class IPADiscovery: # terminate the name if not qname.endswith("."): qname += "." - results = dnsclient.query(qname, dnsclient.DNS_C_IN, dnsclient.DNS_T_TXT) + results = ipa.dnsclient.query(qname, ipa.dnsclient.DNS_C_IN, ipa.dnsclient.DNS_T_TXT) for result in results: - if result.dns_type == dnsclient.DNS_T_TXT: + if result.dns_type == ipa.dnsclient.DNS_T_TXT: realm = result.rdata.data if realm: break @@ -228,9 +228,9 @@ class IPADiscovery: # terminate the name if not qname.endswith("."): qname += "." - results = dnsclient.query(qname, dnsclient.DNS_C_IN, dnsclient.DNS_T_SRV) + results = ipa.dnsclient.query(qname, ipa.dnsclient.DNS_C_IN, ipa.dnsclient.DNS_T_SRV) for result in results: - if result.dns_type == dnsclient.DNS_T_SRV: + if result.dns_type == ipa.dnsclient.DNS_T_SRV: qname = result.rdata.server.rstrip(".") if result.rdata.port and result.rdata.port != 88: qname += ":" + str(result.rdata.port) diff --git a/ipa-python/MANIFEST.in b/ipa-python/MANIFEST.in index 49f2126a6..e2cad6f22 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 000000000..bc8a229cd --- /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(-) diff --git a/ipa-python/config.py b/ipa-python/config.py index a17e585bc..c1a3915d0 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 06140245660d4d68a155796418e80867ce853be4 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 11 Dec 2007 10:59:07 -0500 Subject: Minor fix --- ipa-server/ipa-kpasswd/ipa_kpasswd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipa-server/ipa-kpasswd/ipa_kpasswd.c b/ipa-server/ipa-kpasswd/ipa_kpasswd.c index 99dfe678f..ccd17c1f0 100644 --- a/ipa-server/ipa-kpasswd/ipa_kpasswd.c +++ b/ipa-server/ipa-kpasswd/ipa_kpasswd.c @@ -306,7 +306,7 @@ int ldap_pwd_change(char *client_name, char *realm_name, krb5_data pwd, char **e LDAPControl **srvctrl = NULL; char *exterr1 = NULL; char *exterr2 = NULL; - char *err; + char *err = NULL; int msgid; int ret, rc; -- cgit From 4f0b2154146cc3ed3b32b34713089323d96c1c74 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 11 Dec 2007 12:25:58 -0500 Subject: Make sure we don't keep around old keys. Fixes problem changing passwords seen only on servers where re-installations where performed (and old secrets piled up) --- ipa-server/ipaserver/krbinstance.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ipa-server/ipaserver/krbinstance.py b/ipa-server/ipaserver/krbinstance.py index ede008a83..76818af7d 100644 --- a/ipa-server/ipaserver/krbinstance.py +++ b/ipa-server/ipaserver/krbinstance.py @@ -383,6 +383,11 @@ class KrbInstance(service.Service): def __export_kadmin_changepw_keytab(self): self.step("exporting the kadmin keytab") + try: + if file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"): + os.remove("/var/kerberos/krb5kdc/kpasswd.keytab") + except os.error: + logging.critical("Failed to remove /var/kerberos/krb5kdc/kpasswd.keytab.") (kwrite, kread, kerr) = os.popen3("/usr/kerberos/sbin/kadmin.local") kwrite.write("modprinc +requires_preauth kadmin/changepw\n") kwrite.flush() -- cgit From 10ac6c3c6107cd4deaae922bb681588a0ff410a2 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 11 Dec 2007 15:06:01 -0500 Subject: Enable searching for multiple things at once --- ipa-server/xmlrpc-server/funcs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py index 4943da24d..528b138ba 100644 --- a/ipa-server/xmlrpc-server/funcs.py +++ b/ipa-server/xmlrpc-server/funcs.py @@ -316,7 +316,7 @@ class IPAServer: # construct the giant match for all words exact_match_filter = "(&" - partial_match_filter = "(&" + partial_match_filter = "(|" for word in criteria_words: exact_match_filter += gen_search_pattern(word) partial_match_filter += gen_search_pattern("*%s*" % word) -- cgit From 5c217ce31a4b8c26941c86644b33b904734f61b8 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 11 Dec 2007 15:14:29 -0500 Subject: Change from "Common Name" to "Full Name" --- ipa-server/ipa-gui/ipagui/forms/user.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipa-server/ipa-gui/ipagui/forms/user.py b/ipa-server/ipa-gui/ipagui/forms/user.py index 74369a6ae..43a7a5477 100644 --- a/ipa-server/ipa-gui/ipagui/forms/user.py +++ b/ipa-server/ipa-gui/ipagui/forms/user.py @@ -5,8 +5,8 @@ from tg_expanding_form_widget.tg_expanding_form_widget import ExpandingForm class UserFields(object): givenname = widgets.TextField(name="givenname", label="First Name") sn = widgets.TextField(name="sn", label="Last Name") - cn = widgets.TextField(name="cn", label="Common Names") - cns = ExpandingForm(name="cns", label="Common Names", fields=[cn]) + cn = widgets.TextField(name="cn", label="Full Name") + cns = ExpandingForm(name="cns", label="Full Name", fields=[cn]) title = widgets.TextField(name="title", label="Title") displayname = widgets.TextField(name="displayname", label="Display Name") initials = widgets.TextField(name="initials", label="Initials") -- 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 ++--- ipa-server/xmlrpc-server/funcs.py | 280 ++++++++++++++++++++++++++++++-------- 4 files changed, 233 insertions(+), 92 deletions(-) diff --git a/ipa-python/ipaclient.py b/ipa-python/ipaclient.py index d815afa7b..bd1fb235a 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 e34963365..59e262018 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 5656b99d9..c993ac991 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.""" diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py index 528b138ba..2d2bddbb4 100644 --- a/ipa-server/xmlrpc-server/funcs.py +++ b/ipa-server/xmlrpc-server/funcs.py @@ -25,17 +25,15 @@ import ldap import ldap.dn import ipaserver.dsinstance import ipaserver.ipaldap -import ipa.ipautil -import xmlrpclib import copy import attrs from ipa import ipaerror +from ipa import ipautil from urllib import quote,unquote from ipa import radius_util import string from types import * -import os import re import logging import subprocess @@ -84,7 +82,7 @@ class IPAConnPool: # This will bind the connection try: conn.set_krbccache(krbccache, cprinc.name) - except ldap.UNWILLING_TO_PERFORM, e: + except ldap.UNWILLING_TO_PERFORM: raise ipaerror.gen_exception(ipaerror.CONNECTION_UNWILLING) return conn @@ -111,7 +109,7 @@ class IPAServer: if _LDAPPool is None: _LDAPPool = IPAConnPool(128) - self.basedn = ipa.ipautil.realm_to_suffix(self.realm) + self.basedn = ipautil.realm_to_suffix(self.realm) self.scope = ldap.SCOPE_SUBTREE self.princ = None self.krbccache = None @@ -127,11 +125,11 @@ class IPAServer: global _LDAPPool princ = self.__safe_filter(princ) - filter = "(krbPrincipalName=" + princ + ")" + searchfilter = "(krbPrincipalName=" + princ + ")" # The only anonymous search we should have conn = _LDAPPool.getConn(self.host,self.sslport,self.bindca,self.bindcert,self.bindkey,None,None,debug) try: - ent = conn.getEntry(self.basedn, self.scope, filter, ['dn']) + ent = conn.getEntry(self.basedn, self.scope, searchfilter, ['dn']) finally: _LDAPPool.releaseConn(conn) @@ -220,7 +218,7 @@ class IPAServer: # they currently restrict the data coming back without # restricting scope. For now adding a __get_base/sub_entry() # calls, but the API isn't great. - def __get_entry (self, base, scope, filter, sattrs=None, opts=None): + def __get_entry (self, base, scope, searchfilter, sattrs=None, opts=None): """Get a specific entry (with a parametized scope). Return as a dict of values. Multi-valued fields are represented as lists. @@ -229,28 +227,28 @@ class IPAServer: conn = self.getConnection(opts) try: - ent = conn.getEntry(base, scope, filter, sattrs) + ent = conn.getEntry(base, scope, searchfilter, sattrs) finally: self.releaseConnection(conn) return self.convert_entry(ent) - def __get_base_entry (self, base, filter, sattrs=None, opts=None): + def __get_base_entry (self, base, searchfilter, sattrs=None, opts=None): """Get a specific entry (with a scope of BASE). Return as a dict of values. Multi-valued fields are represented as lists. """ - return self.__get_entry(base, ldap.SCOPE_BASE, filter, sattrs, opts) + return self.__get_entry(base, ldap.SCOPE_BASE, searchfilter, sattrs, opts) - def __get_sub_entry (self, base, filter, sattrs=None, opts=None): + def __get_sub_entry (self, base, searchfilter, sattrs=None, opts=None): """Get a specific entry (with a scope of SUB). Return as a dict of values. Multi-valued fields are represented as lists. """ - return self.__get_entry(base, ldap.SCOPE_SUBTREE, filter, sattrs, opts) + return self.__get_entry(base, ldap.SCOPE_SUBTREE, searchfilter, sattrs, opts) - def __get_list (self, base, filter, sattrs=None, opts=None): + def __get_list (self, base, searchfilter, sattrs=None, opts=None): """Gets a list of entries. Each is converted to a dict of values. Multi-valued fields are represented as lists. """ @@ -258,7 +256,7 @@ class IPAServer: conn = self.getConnection(opts) try: - entries = conn.getList(base, self.scope, filter, sattrs) + entries = conn.getList(base, self.scope, searchfilter, sattrs) finally: self.releaseConnection(conn) @@ -278,7 +276,7 @@ class IPAServer: # original try: moddn = oldentry['dn'] - except KeyError, e: + except KeyError: raise ipaerror.gen_exception(ipaerror.LDAP_MISSING_DN) conn = self.getConnection(opts) @@ -366,43 +364,66 @@ class IPAServer: Multi-valued fields are represented as lists. """ - filter = "(objectClass=*)" - return self.__get_base_entry(dn, filter, sattrs, opts) + if not dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + searchfilter = "(objectClass=*)" + return self.__get_base_entry(dn, searchfilter, sattrs, opts) def get_entry_by_cn (self, cn, sattrs, opts=None): """Get a specific entry by cn. Return as a dict of values. Multi-valued fields are represented as lists. """ + if not cn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) cn = self.__safe_filter(cn) - filter = "(cn=" + cn + ")" - return self.__get_sub_entry(self.basedn, filter, sattrs, opts) + searchfilter = "(cn=" + cn + ")" + return self.__get_sub_entry(self.basedn, searchfilter, sattrs, opts) def update_entry (self, oldentry, newentry, opts=None): - """Update an entry in LDAP""" + """Update an entry in LDAP + + oldentry and newentry are XML-RPC structs. + + If oldentry is not empty then it is used when determine what + has changed. + + If oldentry is empty then the value of newentry is compared + to the current value of oldentry. + """ + if not newentry: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + + if not oldentry: + oldentry = self.get_entry_by_dn(newentry.get('dn'), None, opts) + if oldentry is None: + raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) + return self.__update_entry(oldentry, newentry, opts) # User support def __is_user_unique(self, uid, opts): - """Return 1 if the uid is unique in the tree, 0 otherwise.""" + """Return True if the uid is unique in the tree, False otherwise.""" uid = self.__safe_filter(uid) - filter = "(&(uid=%s)(objectclass=posixAccount))" % uid + searchfilter = "(&(uid=%s)(objectclass=posixAccount))" % uid try: - entry = self.__get_sub_entry(self.basedn, filter, ['dn','uid'], opts) - return 0 + entry = self.__get_sub_entry(self.basedn, searchfilter, ['dn','uid'], opts) + return False except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - return 1 + return True def get_user_by_uid (self, uid, sattrs, opts=None): """Get a specific user's entry. Return as a dict of values. Multi-valued fields are represented as lists. """ + if not uid: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) uid = self.__safe_filter(uid) - filter = "(uid=" + uid + ")" - return self.__get_sub_entry(self.basedn, filter, sattrs, opts) + searchfilter = "(uid=" + uid + ")" + return self.__get_sub_entry(self.basedn, searchfilter, sattrs, opts) def get_user_by_principal(self, principal, sattrs, opts=None): """Get a user entry searching by Kerberos Principal Name. @@ -410,27 +431,33 @@ class IPAServer: represented as lists. """ - filter = "(krbPrincipalName="+self.__safe_filter(principal)+")" - return self.__get_sub_entry(self.basedn, filter, sattrs, opts) + if not principal: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + searchfilter = "(krbPrincipalName="+self.__safe_filter(principal)+")" + return self.__get_sub_entry(self.basedn, searchfilter, sattrs, opts) def get_user_by_email (self, email, sattrs, opts=None): """Get a specific user's entry. Return as a dict of values. Multi-valued fields are represented as lists. """ + if not email: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) email = self.__safe_filter(email) - filter = "(mail=" + email + ")" - return self.__get_sub_entry(self.basedn, filter, sattrs, opts) + searchfilter = "(mail=" + email + ")" + return self.__get_sub_entry(self.basedn, searchfilter, sattrs, opts) def get_users_by_manager (self, manager_dn, sattrs, opts=None): """Gets the users that report to a particular manager. """ + if not manager_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) manager_dn = self.__safe_filter(manager_dn) - filter = "(&(objectClass=person)(manager=%s))" % manager_dn + searchfilter = "(&(objectClass=person)(manager=%s))" % manager_dn try: - return self.__get_list(self.basedn, filter, sattrs, opts) + return self.__get_list(self.basedn, searchfilter, sattrs, opts) except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): return [] @@ -438,11 +465,16 @@ class IPAServer: """Add a user in LDAP. Takes as input a dict where the key is the attribute name and the value is either a string or in the case of a multi-valued field a list of values. user_container sets - where in the tree the user is placed.""" + where in the tree the user is placed. + """ + + if not user: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + if not user_container: user_container = DefaultUserContainer - if self.__is_user_unique(user['uid'], opts) == 0: + if not self.__is_user_unique(user['uid'], opts): raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE) # dn is set here, not by the user @@ -758,6 +790,8 @@ class IPAServer: It is displayed to the user in the order of the list. """ + if not schema: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) config = self.get_ipa_config(opts) # The schema is stored as: @@ -783,11 +817,11 @@ class IPAServer: """Return a list containing a User object for each existing user. """ - filter = "(objectclass=posixAccount)" + searchfilter = "(objectclass=posixAccount)" conn = self.getConnection(opts) try: - all_users = conn.getList(self.basedn, self.scope, filter, None) + all_users = conn.getList(self.basedn, self.scope, searchfilter, None) finally: self.releaseConnection(conn) @@ -803,6 +837,8 @@ class IPAServer: If the results are truncated, counter will be set to -1.""" logging.debug("IPA: find users %s" % criteria) + if not criteria: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) config = self.get_ipa_config(opts) if timelimit < 0: timelimit = float(config.get('ipasearchtimelimit')) @@ -875,6 +911,8 @@ class IPAServer: def convert_scalar_values(self, orig_dict): """LDAP update dicts expect all values to be a list (except for dn). This method converts single entries to a list.""" + if not orig_dict or not isinstance(orig_dict, dict): + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) new_dict={} for (k,v) in orig_dict.iteritems(): if not isinstance(v, list) and k != 'dn': @@ -886,9 +924,23 @@ class IPAServer: def update_user (self, oldentry, newentry, opts=None): """Wrapper around update_entry with user-specific handling. + oldentry and newentry are XML-RPC structs. + + If oldentry is not empty then it is used when determine what + has changed. + + If oldentry is empty then the value of newentry is compared + to the current value of oldentry. + If you want to change the RDN of a user you must use this function. update_entry will fail. """ + if not newentry: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + if not oldentry: + oldentry = self.get_entry_by_dn(newentry.get('dn'), None, opts) + if oldentry is None: + raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) newrdn = 0 @@ -938,6 +990,9 @@ class IPAServer: logging.debug("IPA: activating entry %s" % dn) + if not dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + res = "" # First, check the entry status entry = self.get_entry_by_dn(dn, ['dn', 'nsAccountlock'], opts) @@ -970,6 +1025,9 @@ class IPAServer: logging.debug("IPA: inactivating entry %s" % dn) + if not dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + entry = self.get_entry_by_dn(dn, ['dn', 'nsAccountlock', 'memberOf'], opts) if entry.get('nsaccountlock', 'false') == "true": @@ -990,12 +1048,16 @@ class IPAServer: def mark_user_active(self, uid, opts=None): """Mark a user as active""" + if not uid: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) user = self.get_user_by_uid(uid, ['dn', 'uid'], opts) return self.mark_entry_active(user.get('dn')) def mark_user_inactive(self, uid, opts=None): """Mark a user as inactive""" + if not uid: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) user = self.get_user_by_uid(uid, ['dn', 'uid'], opts) return self.mark_entry_inactive(user.get('dn')) @@ -1008,6 +1070,8 @@ class IPAServer: The memberOf plugin handles removing the user from any other groups. """ + if not uid: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) user = self.get_user_by_uid(uid, ['dn', 'uid', 'objectclass'], opts) if user is None: raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) @@ -1026,6 +1090,8 @@ class IPAServer: oldpass is the old password (if available) newpass is the new password """ + if not principal or not newpass: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) user = self.get_user_by_principal(principal, ['krbprincipalname'], opts) if user is None or user['krbprincipalname'] != principal: raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) @@ -1040,26 +1106,28 @@ class IPAServer: # Group support def __is_group_unique(self, cn, opts): - """Return 1 if the cn is unique in the tree, 0 otherwise.""" + """Return True if the cn is unique in the tree, False otherwise.""" cn = self.__safe_filter(cn) - filter = "(&(cn=%s)(objectclass=posixGroup))" % cn + searchfilter = "(&(cn=%s)(objectclass=posixGroup))" % cn try: - entry = self.__get_sub_entry(self.basedn, filter, ['dn','cn'], opts) - return 0 + entry = self.__get_sub_entry(self.basedn, searchfilter, ['dn','cn'], opts) + return False except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - return 1 + return True def get_groups_by_member (self, member_dn, sattrs, opts=None): """Get a specific group's entry. Return as a dict of values. Multi-valued fields are represented as lists. """ + if not member_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) member_dn = self.__safe_filter(member_dn) - filter = "(&(objectClass=posixGroup)(member=%s))" % member_dn + searchfilter = "(&(objectClass=posixGroup)(member=%s))" % member_dn try: - return self.__get_list(self.basedn, filter, sattrs, opts) + return self.__get_list(self.basedn, searchfilter, sattrs, opts) except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): return [] @@ -1068,10 +1136,13 @@ class IPAServer: attribute name and the value is either a string or in the case of a multi-valued field a list of values. group_container sets where in the tree the group is placed.""" + if not group: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + if not group_container: group_container = DefaultGroupContainer - if self.__is_group_unique(group['cn'], opts) == 0: + if not self.__is_group_unique(group['cn'], opts): raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE) # Get our configuration @@ -1102,6 +1173,8 @@ class IPAServer: """Return a list containing a User object for each existing group that matches the criteria. """ + if not criteria: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) config = self.get_ipa_config(opts) if timelimit < 0: @@ -1178,6 +1251,8 @@ class IPAServer: def add_member_to_group(self, member_dn, group_dn, opts=None): """Add a member to an existing group. """ + if not member_dn or not group_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) old_group = self.get_entry_by_dn(group_dn, None, opts) if old_group is None: @@ -1186,6 +1261,8 @@ class IPAServer: # check to make sure member_dn exists member_entry = self.__get_base_entry(member_dn, "(objectClass=*)", ['dn','uid'], opts) + if not member_entry: + raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) if new_group.get('member') is not None: if ((isinstance(new_group.get('member'), str)) or (isinstance(new_group.get('member'), unicode))): @@ -1205,6 +1282,9 @@ class IPAServer: Returns a list of the member_dns that were not added to the group. """ + if not member_dns or not group_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + failed = [] if (isinstance(member_dns, str)): @@ -1225,6 +1305,8 @@ class IPAServer: def remove_member_from_group(self, member_dn, group_dn, opts=None): """Remove a member_dn from an existing group. """ + if not member_dn or not group_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) old_group = self.get_entry_by_dn(group_dn, None, opts) if old_group is None: @@ -1255,6 +1337,8 @@ class IPAServer: """Given a list of member dn's remove them from the group. Returns a list of the members not removed from the group. """ + if not member_dns or not group_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) failed = [] @@ -1277,6 +1361,8 @@ class IPAServer: """Add a user to an existing group. """ + if not user_uid or not group_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) user = self.get_user_by_uid(user_uid, ['dn', 'uid', 'objectclass'], opts) if user is None: raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) @@ -1287,6 +1373,8 @@ class IPAServer: """Given a list of user uid's add them to the group cn denoted by group Returns a list of the users were not added to the group. """ + if not user_uids or not group_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) failed = [] @@ -1309,6 +1397,9 @@ class IPAServer: """Remove a user from an existing group. """ + if not user_uid or not group_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + user = self.get_user_by_uid(user_uid, ['dn', 'uid', 'objectclass'], opts) if user is None: raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) @@ -1319,6 +1410,8 @@ class IPAServer: """Given a list of user uid's remove them from the group Returns a list of the user uids not removed from the group. """ + if not user_uids or not group_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) failed = [] @@ -1342,6 +1435,8 @@ class IPAServer: Returns a list of the group dns that were not added. """ + if not group_dns or not user_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) failed = [] @@ -1365,6 +1460,8 @@ class IPAServer: Returns a list of the group dns that were not removed. """ + if not group_dns or not user_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) failed = [] @@ -1386,9 +1483,23 @@ class IPAServer: def update_group (self, oldentry, newentry, opts=None): """Wrapper around update_entry with group-specific handling. + oldentry and newentry are XML-RPC structs. + + If oldentry is not empty then it is used when determine what + has changed. + + If oldentry is empty then the value of newentry is compared + to the current value of oldentry. + If you want to change the RDN of a group you must use this function. update_entry will fail. """ + if not newentry: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + if not oldentry: + oldentry = self.get_entry_by_dn(newentry.get('dn'), None, opts) + if oldentry is None: + raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) newrdn = 0 @@ -1451,6 +1562,8 @@ class IPAServer: The memberOf plugin handles removing the group from any other groups. """ + if not group_dn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) group = self.get_entry_by_dn(group_dn, ['dn', 'cn'], opts) if group is None: raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) @@ -1478,6 +1591,8 @@ class IPAServer: tgroup is the DN of the target group to be added to """ + if not group or not tgroup: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) old_group = self.get_entry_by_dn(tgroup, None, opts) if old_group is None: raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) @@ -1514,19 +1629,21 @@ class IPAServer: """Do a memberOf search of groupdn and return the attributes in attr_list (an empty list returns everything).""" + if not groupdn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) config = self.get_ipa_config(opts) timelimit = float(config.get('ipasearchtimelimit')) searchlimit = float(config.get('ipasearchrecordslimit')) groupdn = self.__safe_filter(groupdn) - filter = "(memberOf=%s)" % groupdn + searchfilter = "(memberOf=%s)" % groupdn conn = self.getConnection(opts) try: try: results = conn.getListAsync(self.basedn, self.scope, - filter, attr_list, 0, None, None, timelimit, + searchfilter, attr_list, 0, None, None, timelimit, searchlimit) except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): results = [0] @@ -1545,33 +1662,42 @@ class IPAServer: def mark_group_active(self, cn, opts=None): """Mark a group as active""" + if not cn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) group = self.get_entry_by_cn(cn, ['dn', 'cn'], opts) return self.mark_entry_active(group.get('dn')) def mark_group_inactive(self, cn, opts=None): """Mark a group as inactive""" + if not cn: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) group = self.get_entry_by_cn(cn, ['dn', 'uid'], opts) return self.mark_entry_inactive(group.get('dn')) def __is_service_unique(self, name, opts): - """Return 1 if the uid is unique in the tree, 0 otherwise.""" + """Return True if the uid is unique in the tree, False otherwise.""" name = self.__safe_filter(name) - filter = "(&(krbprincipalname=%s)(objectclass=krbPrincipal))" % name + searchfilter = "(&(krbprincipalname=%s)(objectclass=krbPrincipal))" % name try: - entry = self.__get_sub_entry(self.basedn, filter, ['dn','krbprincipalname'], opts) - return 0 + entry = self.__get_sub_entry(self.basedn, searchfilter, ['dn','krbprincipalname'], opts) + return False except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - return 1 + return True def add_service_principal(self, name, opts=None): + """Given a name of the form: service/FQDN create a service + principal for it in the default realm.""" + if not name: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + service_container = DefaultServiceContainer princ_name = name + "@" + self.realm conn = self.getConnection(opts) - if self.__is_service_unique(name, opts) == 0: + if not self.__is_service_unique(name, opts): raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE) dn = "krbprincipalname=%s,%s,%s" % (ldap.dn.escape_dn_chars(princ_name), @@ -1591,6 +1717,8 @@ class IPAServer: timelimit=-1, opts=None): """Returns a list: counter followed by the results. If the results are truncated, counter will be set to -1.""" + if not criteria: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) config = self.get_ipa_config(opts) if timelimit < 0: @@ -1658,7 +1786,10 @@ class IPAServer: return entries def get_keytab(self, name, opts=None): - """get a keytab""" + """Return a keytab for an existing service principal. Note that + this increments the secret thus invalidating any older keys.""" + if not name: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) princ_name = name + "@" + self.realm @@ -1699,8 +1830,24 @@ class IPAServer: return config def update_ipa_config(self, oldconfig, newconfig, opts=None): - """Update the IPA configuration""" - + """Update the IPA configuration. + + oldconfig and newconfig are XML-RPC structs. + + If oldconfig is not empty then it is used when determine what + has changed. + + If oldconfig is empty then the value of newconfig is compared + to the current value of oldconfig. + + """ + if not newconfig: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + if not oldconfig: + oldconfig = self.get_entry_by_dn(newconfig.get('dn'), None, opts) + if oldconfig is None: + raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) + # The LDAP routines want strings, not ints, so convert a few # things. Otherwise it sees a string -> int conversion as a change. try: @@ -1749,7 +1896,24 @@ class IPAServer: return policy def update_password_policy(self, oldpolicy, newpolicy, opts=None): - """Update the IPA configuration""" + """Update the IPA configuration + + oldpolicy and newpolicy are XML-RPC structs. + + If oldpolicy is not empty then it is used when determine what + has changed. + + If oldpolicy is empty then the value of newpolicy is compared + to the current value of oldpolicy. + + """ + if not newpolicy: + raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER) + if not oldpolicy: + oldpolicy = self.get_entry_by_dn(newpolicy.get('dn'), None, opts) + if oldpolicy is None: + raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) + # The LDAP routines want strings, not ints, so convert a few # things. Otherwise it sees a string -> int conversion as a change. -- cgit From 148a55811d0e9814bc2943f3600acf17be1b844e Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 10:10:06 -0500 Subject: Return a proper error code from ipa-webgui so that the init script can indicate when the service fails to start. --- ipa-server/ipa-gui/ipa-webgui | 69 ++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/ipa-server/ipa-gui/ipa-webgui b/ipa-server/ipa-gui/ipa-webgui index c8e3d0589..a18c2db81 100644 --- a/ipa-server/ipa-gui/ipa-webgui +++ b/ipa-server/ipa-gui/ipa-webgui @@ -63,41 +63,48 @@ def daemonize(): # stderr os.open("/dev/null", os.O_RDWR) -# To make development easier, we detect if we are in the development -# environment to load a different configuration and avoid becoming -# a daemon -devel = False -if os.path.exists(os.path.join(os.path.dirname(__file__), "Makefile.am")): - devel = True - -if not devel: - try: - daemonize() - except Exception, e: - sys.stderr.write("error becoming daemon: " + str(e)) - sys.exit(1) +def main(): + # To make development easier, we detect if we are in the development + # environment to load a different configuration and avoid becoming + # a daemon + devel = False + if os.path.exists(os.path.join(os.path.dirname(__file__), "Makefile.am")): + devel = True + + if not devel: + try: + daemonize() + except Exception, e: + sys.stderr.write("error becoming daemon: " + str(e)) + sys.exit(1) + + sys.path.append("/usr/share/ipa/") -sys.path.append("/usr/share/ipa/") + # this must be after sys.path is changed to work correctly + import pkg_resources + pkg_resources.require("TurboGears") + pkg_resources.require("ipa_gui") -# this must be after sys.path is changed to work correctly -import pkg_resources -pkg_resources.require("TurboGears") -pkg_resources.require("ipa_gui") + from turbogears import update_config, start_server + import cherrypy + cherrypy.lowercase_api = True -from turbogears import update_config, start_server -import cherrypy -cherrypy.lowercase_api = True + # Load the config - look for a local file first for development + # and then the system config file + if devel: + update_config(configfile="dev.cfg", + modulename="ipagui.config") + else: + update_config(configfile="/usr/share/ipa/ipa-webgui.cfg", + modulename="ipagui.config.app") -# Load the config - look for a local file first for development -# and then the system config file -if devel: - update_config(configfile="dev.cfg", - modulename="ipagui.config") -else: - update_config(configfile="/usr/share/ipa/ipa-webgui.cfg", - modulename="ipagui.config.app") + from ipagui.controllers import Root -from ipagui.controllers import Root + start_server(Root()) -start_server(Root()) +try: + main() +except Exception, e: + print "failed to start web gui: %s" % str(e) + sys.exit(1) -- cgit From 380756ace9f1f6f4ce1e203d53f64ac503bb6652 Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 10:16:22 -0500 Subject: Confirm before configuring the client. --- ipa-client/ipa-install/ipa-client-install | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install index bc8e7c9c3..dfaabca3e 100644 --- a/ipa-client/ipa-install/ipa-client-install +++ b/ipa-client/ipa-install/ipa-client-install @@ -124,6 +124,12 @@ def main(): print "IPA Server: "+ds.getServerName() print "BaseDN: "+ds.getBaseDN() + print "\n" + yesno = raw_input("Continue to configure the system with these values? [y/N] ") + if yesno.lower() != "y": + return 1 + print "\n" + # Configure ipa.conf ipaconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer") ipaconf.setOptionAssignment(" = ") @@ -225,4 +231,4 @@ def main(): return 0 -main() +sys.exit(main()) -- cgit From 7561d7c42d8d62d42cb6a50dac368c786cf75b38 Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 10:36:46 -0500 Subject: Remove radius from main install script and add ipa-radius-install. --- ipa-server/ipa-install/Makefile.am | 1 + ipa-server/ipa-install/ipa-radius-install | 72 +++++++++++++++++++++++++++++++ ipa-server/ipa-install/ipa-server-install | 5 --- ipa-server/ipaserver/radiusinstance.py | 2 +- 4 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 ipa-server/ipa-install/ipa-radius-install diff --git a/ipa-server/ipa-install/Makefile.am b/ipa-server/ipa-install/Makefile.am index 1b46d354b..b9ce69156 100644 --- a/ipa-server/ipa-install/Makefile.am +++ b/ipa-server/ipa-install/Makefile.am @@ -8,6 +8,7 @@ sbin_SCRIPTS = \ ipa-server-install \ ipa-replica-install \ ipa-replica-prepare \ + ipa-radius-install \ $(NULL) EXTRA_DIST = \ diff --git a/ipa-server/ipa-install/ipa-radius-install b/ipa-server/ipa-install/ipa-radius-install new file mode 100644 index 000000000..84e10e426 --- /dev/null +++ b/ipa-server/ipa-install/ipa-radius-install @@ -0,0 +1,72 @@ +#! /usr/bin/python -E +# Authors: Karl MacMillan +# +# 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 traceback, logging, krbV + +from ipaserver import radiusinstance, installutils + +from ipa import ipautil + +def get_host_name(): + hostname = installutils.get_fqdn() + try: + installutils.verify_fqdn(hostname) + except RuntimeError, e: + logging.error(str(e)) + sys.exit(1) + + return hostname + +def get_realm_name(): + c = krbV.default_context() + return c.default_realm + +def main(): + if not ipautil.file_exists("/etc/ipa/ipa.conf"): + print "This system does not appear to have IPA configured." + print "Has ipa-server-install been run?" + yesno = raw_input("Continue with radius install [y/N]? ") + if yesno.lower() != "y": + sys.exit(1) + + installutils.standard_logging_setup("iparadius-install.log", False) + + host_name = get_host_name() + + realm_name = get_realm_name() + + # Create a radius instance + radius = radiusinstance.RadiusInstance() + # FIXME: ldap_server should be derived, not hardcoded to localhost, also should it be a URL? + radius.create_instance(realm_name, host_name, 'localhost') + + +try: + main() +except Exception, e: + message = "Unexpected error - see iparadius-install.log for details:\n %s" % str(e) + print message + message = str(e) + for str in traceback.format_tb(sys.exc_info()[2]): + message = message + "\n" + str + logging.debug(message) diff --git a/ipa-server/ipa-install/ipa-server-install b/ipa-server/ipa-install/ipa-server-install index 646512d51..05bece9e2 100644 --- a/ipa-server/ipa-install/ipa-server-install +++ b/ipa-server/ipa-install/ipa-server-install @@ -400,11 +400,6 @@ def main(): webgui = ipaserver.webguiinstance.WebGuiInstance() webgui.create_instance() - # Create a radius instance - radius = ipaserver.radiusinstance.RadiusInstance() - # FIXME: ldap_server should be derived, not hardcoded to localhost, also should it be a URL? - radius.create_instance(realm_name, host_name, 'localhost') - bind.setup(host_name, ip_address, realm_name) if options.setup_bind: skipbind = False diff --git a/ipa-server/ipaserver/radiusinstance.py b/ipa-server/ipaserver/radiusinstance.py index 3b89018f0..4250b4bd1 100644 --- a/ipa-server/ipaserver/radiusinstance.py +++ b/ipa-server/ipaserver/radiusinstance.py @@ -125,7 +125,7 @@ class RadiusInstance(service.Service): logging.error("could not create %s: %s", radius_util.RADIUSD_CONF_FILEPATH, e) def __create_radius_keytab(self): - self.step("creating a keytab for httpd") + self.step("creating a keytab for radiusd") try: if file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): os.remove(radius_util.RADIUS_IPA_KEYTAB_FILEPATH) -- cgit From 2892c28f56b855bc07a1c2cdb765bd0e5d2e5f8b Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 11:05:47 -0500 Subject: Improve confirmation. --- ipa-client/ipa-install/ipa-client-install | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install index dfaabca3e..9cc6f6f6b 100644 --- a/ipa-client/ipa-install/ipa-client-install +++ b/ipa-client/ipa-install/ipa-client-install @@ -51,6 +51,13 @@ def parse_options(): return options +def ask_for_confirmation(message): + yesno = raw_input(message + " [y/N]: ") + if not yesno or yesno.lower()[0] != "y": + return False + print "\n" + return True + def logging_setup(options): # Always log everything (i.e., DEBUG) to the log # file. @@ -114,10 +121,8 @@ def main(): print "\nThe failure to use DNS to find your IPA server indicates that your resolv.conf file is not properly configured\n." print "Autodiscovery of servers for failover cannot work with this configuration.\n" print "If you proceed with the installation, services will be configured to always access the discovered server for all operation and will not fail over to other servers in case of failure\n" - yesno = raw_input("Do you want to proceed and configure the system with fixed values with no DNS discovery? [y/N] ") - if yesno.lower() != "y": + if not ask_for_confirmation("Do you want to proceed and configure the system with fixed values with no DNS discovery?"): return ret - print "\n" print "Realm: "+ds.getRealmName() print "DNS Domain: "+ds.getDomainName() @@ -125,10 +130,8 @@ def main(): print "BaseDN: "+ds.getBaseDN() print "\n" - yesno = raw_input("Continue to configure the system with these values? [y/N] ") - if yesno.lower() != "y": + if not ask_for_confirmation("Continue to configure the system with these values?"): return 1 - print "\n" # Configure ipa.conf ipaconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer") -- cgit From 8792559f7440cac54072395a7677f31e9b029dc7 Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 11:16:20 -0500 Subject: Remove radiusinstance from ipa-server-install. --- ipa-server/ipa-install/ipa-server-install | 1 - 1 file changed, 1 deletion(-) diff --git a/ipa-server/ipa-install/ipa-server-install b/ipa-server/ipa-install/ipa-server-install index 05bece9e2..ee5e929d1 100644 --- a/ipa-server/ipa-install/ipa-server-install +++ b/ipa-server/ipa-install/ipa-server-install @@ -46,7 +46,6 @@ import ipaserver.krbinstance import ipaserver.bindinstance import ipaserver.httpinstance import ipaserver.ntpinstance -import ipaserver.radiusinstance import ipaserver.webguiinstance from ipaserver import service -- cgit From 1c3849eb576dc9d4cd3d4a39aff9da78be0ddcba Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 11:19:42 -0500 Subject: User provided certs. --- ipa-server/ipa-install/Makefile.am | 1 + ipa-server/ipa-install/ipa-server-certinstall | 156 ++++++++++++++++++++++++++ ipa-server/ipaserver/certs.py | 49 +++++++- ipa-server/ipaserver/dsinstance.py | 2 +- ipa-server/ipaserver/httpinstance.py | 18 +-- ipa-server/ipaserver/installutils.py | 19 ++++ 6 files changed, 224 insertions(+), 21 deletions(-) create mode 100644 ipa-server/ipa-install/ipa-server-certinstall diff --git a/ipa-server/ipa-install/Makefile.am b/ipa-server/ipa-install/Makefile.am index b9ce69156..37dd325e8 100644 --- a/ipa-server/ipa-install/Makefile.am +++ b/ipa-server/ipa-install/Makefile.am @@ -8,6 +8,7 @@ sbin_SCRIPTS = \ ipa-server-install \ ipa-replica-install \ ipa-replica-prepare \ + ipa-server-certinstall \ ipa-radius-install \ $(NULL) diff --git a/ipa-server/ipa-install/ipa-server-certinstall b/ipa-server/ipa-install/ipa-server-certinstall new file mode 100644 index 000000000..932a6be18 --- /dev/null +++ b/ipa-server/ipa-install/ipa-server-certinstall @@ -0,0 +1,156 @@ +#! /usr/bin/python -E +# Authors: Karl MacMillan +# +# 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 +sys.path.append("/usr/share/ipa") + +import traceback + +import krbV, ldap, getpass + +from ipaserver import certs, dsinstance, httpinstance, ipaldap, installutils + +def get_realm_name(): + c = krbV.default_context() + return c.default_realm + +def parse_options(): + from optparse import OptionParser + parser = OptionParser() + + parser.add_option("-d", "--dirsrv", dest="dirsrv", action="store_true", + default=False, help="install certificate for the directory server") + parser.add_option("-w", "--http", dest="http", action="store_true", + default=False, help="install certificate for the http server") + + + options, args = parser.parse_args() + + if not options.dirsrv and not options.http: + parser.error("you must specify dirsrv and/or http") + + if len(args) != 1: + parser.error("you must provide a pkcs12 filename") + + return options, args[0] + +def set_ds_cert_name(cert_name, dm_password): + conn = ipaldap.IPAdmin("127.0.0.1") + conn.simple_bind_s("cn=directory manager", dm_password) + + mod = [(ldap.MOD_REPLACE, "nsSSLPersonalitySSL", cert_name)] + + conn.modify_s("cn=RSA,cn=encryption,cn=config", mod) + + conn.unbind() + +def set_http_cert_name(cert_name): + # find the existing cert name + fd = open(httpinstance.NSS_CONF) + nick_name = None + file = [] + for line in fd: + if "NSSNickname" in line: + file.append('NSSNickname "%s"\n' % cert_name) + else: + file.append(line) + fd.close() + + fd = open(httpinstance.NSS_CONF, "w") + fd.write("".join(file)) + fd.close() + + +def choose_server_cert(server_certs): + print "Please select the certificate to use:" + num = 1 + for cert in server_certs: + print "%d. %s" % (num, cert[0]) + num += 1 + + cert_num = 0 + while 1: + cert_input = raw_input("Certificate number [1]: ") + print "" + if cert_input == "": + break + else: + try: + num = int(cert_input) + except ValueError: + print "invalid number" + continue + if num > len(server_certs): + print "number out of range" + continue + cert_num = num - 1 + break + return server_certs[cert_num] + + +def import_cert(dirname, pkcs12_fname): + cdb = certs.CertDB(dirname) + cdb.create_passwd_file(False) + cdb.create_certdbs() + try: + cdb.import_pkcs12(pkcs12_fname) + except RuntimeError, e: + print str(e) + sys.exit(1) + + server_certs = cdb.find_server_certs() + if len(server_certs) == 0: + print "could not find a suitable server cert in import" + sys.exit(1) + elif len(server_certs) == 1: + server_cert = server_certs[0] + else: + server_cert = choose_server_cert(server_certs) + + cdb.trust_root_cert(server_cert[0]) + + return server_cert + +def main(): + options, pkcs12_fname = parse_options() + + try: + if options.dirsrv: + dm_password = getpass.getpass("Directory Manager password: ") + realm = get_realm_name() + dirname = dsinstance.config_dirname(realm) + server_cert = import_cert(dirname, pkcs12_fname) + set_ds_cert_name(server_cert[0], dm_password) + + if options.http: + dirname = httpinstance.NSS_DIR + server_cert = import_cert(dirname, pkcs12_fname) + print server_cert + set_http_cert_name(server_cert[0]) + + except Exception, e: + print "an unexpected error occurred: %s" % str(e) + traceback.print_exc() + return 1 + + return 0 + + +sys.exit(main()) diff --git a/ipa-server/ipaserver/certs.py b/ipa-server/ipaserver/certs.py index fb6b01d0e..77052c13e 100644 --- a/ipa-server/ipaserver/certs.py +++ b/ipa-server/ipaserver/certs.py @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -import os, stat, subprocess +import os, stat, subprocess, re import sha from ipa import ipautil @@ -196,6 +196,50 @@ class CertDB(object): f.close() self.set_perms(self.pin_fname) + def trust_root_cert(self, nickname): + p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, + "-O", "-n", nickname], stdout=subprocess.PIPE) + + chain = p.stdout.read() + chain = chain.split("\n") + + root_nickname = re.match('\ *"(.*)".*', chain[0]).groups()[0] + + self.run_certutil(["-M", "-n", root_nickname, + "-t", "CT,CT,"]) + + def find_server_certs(self): + p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, + "-L"], stdout=subprocess.PIPE) + + certs = p.stdout.read() + + certs = certs.split("\n") + + server_certs = [] + + for cert in certs: + fields = cert.split() + if not len(fields): + continue + flags = fields[-1] + if 'u' in flags: + name = " ".join(fields[0:-1]) + server_certs.append((name, flags)) + + return server_certs + + + def import_pkcs12(self, pkcs12_fname): + try: + ipautil.run(["/usr/bin/pk12util", "-d", self.secdir, + "-i", pkcs12_fname]) + except ipautil.CalledProcessError, e: + if e.returncode == 17: + raise RuntimeError("incorrect password") + else: + raise RuntimeError("unknown error import pkcs#12 file") + def create_self_signed(self, passwd=True): self.create_noise_file() self.create_passwd_file(passwd) @@ -208,6 +252,3 @@ class CertDB(object): self.create_passwd_file(passwd) self.create_certdbs() self.load_cacert(cacert_fname) - - - diff --git a/ipa-server/ipaserver/dsinstance.py b/ipa-server/ipaserver/dsinstance.py index 5edc3879e..818710fb6 100644 --- a/ipa-server/ipaserver/dsinstance.py +++ b/ipa-server/ipaserver/dsinstance.py @@ -322,7 +322,7 @@ class DsInstance(service.Service): conn.addEntry(entry) conn.unbind() - + def __add_default_layout(self): self.step("adding default layout") txt = ipautil.template_file(ipautil.SHARE_DIR + "bootstrap-template.ldif", self.sub_dict) diff --git a/ipa-server/ipaserver/httpinstance.py b/ipa-server/ipaserver/httpinstance.py index 1799cca07..de0b3af82 100644 --- a/ipa-server/ipaserver/httpinstance.py +++ b/ipa-server/ipaserver/httpinstance.py @@ -29,6 +29,7 @@ import time import service import certs import dsinstance +import installutils from ipa.ipautil import * HTTPD_DIR = "/etc/httpd" @@ -43,21 +44,6 @@ successfully change with the command: Try updating the policycoreutils and selinux-policy packages. """ -def update_file(filename, orig, subst): - if os.path.exists(filename): - pattern = "%s" % re.escape(orig) - p = re.compile(pattern) - for line in fileinput.input(filename, inplace=1): - if not p.search(line): - sys.stdout.write(line) - else: - sys.stdout.write(p.sub(subst, line)) - fileinput.close() - return 0 - else: - print "File %s doesn't exist." % filename - return 1 - class HTTPInstance(service.Service): def __init__(self): service.Service.__init__(self, "httpd") @@ -145,7 +131,7 @@ class HTTPInstance(service.Service): def __set_mod_nss_port(self): self.step("Setting mod_nss port to 443") - if update_file(NSS_CONF, '8443', '443') != 0: + if installutils.update_file(NSS_CONF, '8443', '443') != 0: print "Updating %s failed." % NSS_CONF def __setup_ssl(self): diff --git a/ipa-server/ipaserver/installutils.py b/ipa-server/ipaserver/installutils.py index a403e8154..25cd1555c 100644 --- a/ipa-server/ipaserver/installutils.py +++ b/ipa-server/ipaserver/installutils.py @@ -21,6 +21,10 @@ import logging import socket import errno import getpass +import os +import re +import fileinput +import sys def get_fqdn(): fqdn = "" @@ -105,4 +109,19 @@ def read_password(user): print "" return pwd +def update_file(filename, orig, subst): + if os.path.exists(filename): + pattern = "%s" % re.escape(orig) + p = re.compile(pattern) + for line in fileinput.input(filename, inplace=1): + if not p.search(line): + sys.stdout.write(line) + else: + sys.stdout.write(p.sub(subst, line)) + fileinput.close() + return 0 + else: + print "File %s doesn't exist." % filename + return 1 + -- cgit From 6390db3502eaee385cb990eef723bc4f27a633c0 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 12 Dec 2007 09:36:32 -0500 Subject: Add automatic browser configuration for kerberos SSO using javascript. This uses the UniversalPreferencesWrite function to set the browser preferences to allow negotiation and ticket forwarding in the IPA domain. A self-signed certificate is generated to sign the javascript. --- ipa-server/ipa-install/share/Makefile.am | 1 + .../ipa-install/share/preferences.html.template | 33 +++++++++++++ ipa-server/ipaserver/certs.py | 56 +++++++++++++++++++--- ipa-server/ipaserver/httpinstance.py | 34 ++++++++++++- ipa-server/xmlrpc-server/ipa.conf | 5 +- ipa-server/xmlrpc-server/unauthorized.html | 14 ++++++ 6 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 ipa-server/ipa-install/share/preferences.html.template diff --git a/ipa-server/ipa-install/share/Makefile.am b/ipa-server/ipa-install/share/Makefile.am index 36bb54e83..36837356d 100644 --- a/ipa-server/ipa-install/share/Makefile.am +++ b/ipa-server/ipa-install/share/Makefile.am @@ -19,6 +19,7 @@ app_DATA = \ krb.con.template \ krbrealm.con.template \ ntp.conf.server.template \ + preferences.html.template \ radius.radiusd.conf.template \ referint-conf.ldif \ dna-posix.ldif \ diff --git a/ipa-server/ipa-install/share/preferences.html.template b/ipa-server/ipa-install/share/preferences.html.template new file mode 100644 index 000000000..2d3684dcd --- /dev/null +++ b/ipa-server/ipa-install/share/preferences.html.template @@ -0,0 +1,33 @@ + + + + Automatically set browser preferences + + +
+ +
+ + + + + diff --git a/ipa-server/ipaserver/certs.py b/ipa-server/ipaserver/certs.py index 77052c13e..eecfdf21c 100644 --- a/ipa-server/ipaserver/certs.py +++ b/ipa-server/ipaserver/certs.py @@ -77,6 +77,11 @@ class CertDB(object): new_args = new_args + args ipautil.run(new_args, stdin) + def run_signtool(self, args, stdin=None): + new_args = ["/usr/bin/signtool", "-d", self.secdir] + new_args = new_args + args + ipautil.run(new_args, stdin) + def create_noise_file(self): ipautil.backup_file(self.noise_fname) f = open(self.noise_fname, "w") @@ -108,7 +113,7 @@ class CertDB(object): self.run_certutil(["-S", "-n", self.cacert_name, "-s", "cn=CAcert", "-x", - "-t", "CT,,", + "-t", "CT,,C", "-m", self.next_serial(), "-v", self.valid_months, "-z", self.noise_fname, @@ -130,7 +135,7 @@ class CertDB(object): def load_cacert(self, cacert_fname): self.run_certutil(["-A", "-n", self.cacert_name, - "-t", "CT,CT,", + "-t", "CT,,C", "-a", "-i", cacert_fname]) @@ -139,7 +144,17 @@ class CertDB(object): if not cdb: cdb = self self.request_cert(name) - cdb.issue_cert(self.certreq_fname, self.certder_fname) + cdb.issue_server_cert(self.certreq_fname, self.certder_fname) + self.add_cert(self.certder_fname, nickname) + os.unlink(self.certreq_fname) + os.unlink(self.certder_fname) + + def create_signing_cert(self, nickname, name, other_certdb=None): + cdb = other_certdb + if not cdb: + cdb = self + self.request_cert(name) + cdb.issue_signing_cert(self.certreq_fname, self.certder_fname) self.add_cert(self.certder_fname, nickname) os.unlink(self.certreq_fname) os.unlink(self.certder_fname) @@ -151,7 +166,7 @@ class CertDB(object): "-z", self.noise_fname, "-f", self.passwd_fname]) - def issue_cert(self, certreq_fname, cert_fname): + def issue_server_cert(self, certreq_fname, cert_fname): p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, "-C", "-c", self.cacert_name, @@ -179,8 +194,37 @@ class CertDB(object): # n - not critical p.stdin.write("2\n9\nn\n1\n9\nn\n") p.wait() - - + + def issue_signing_cert(self, certreq_fname, cert_fname): + p = subprocess.Popen(["/usr/bin/certutil", + "-d", self.secdir, + "-C", "-c", self.cacert_name, + "-i", certreq_fname, + "-o", cert_fname, + "-m", self.next_serial(), + "-v", self.valid_months, + "-f", self.passwd_fname, + "-1", "-5"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + + # Bah - this sucks, but I guess it isn't possible to fully + # control this with command line arguments. + # + # What this is requesting is: + # -1 (Create key usage extension) + # 0 - Digital Signature + # 5 - Cert signing key + # 9 - done + # n - not critical + # + # -5 (Create netscape cert type extension) + # 3 - Object Signing + # 9 - done + # n - not critical + p.stdin.write("0\n5\n9\nn\n3\n9\nn\n") + p.wait() + def add_cert(self, cert_fname, nickname): self.run_certutil(["-A", "-n", nickname, "-t", "u,u,u", diff --git a/ipa-server/ipaserver/httpinstance.py b/ipa-server/ipaserver/httpinstance.py index de0b3af82..a131faedc 100644 --- a/ipa-server/ipaserver/httpinstance.py +++ b/ipa-server/ipaserver/httpinstance.py @@ -25,6 +25,7 @@ import pwd import fileinput import sys import time +import shutil import service import certs @@ -49,9 +50,10 @@ class HTTPInstance(service.Service): service.Service.__init__(self, "httpd") def create_instance(self, realm, fqdn): - self.sub_dict = { "REALM" : realm, "FQDN": fqdn } self.fqdn = fqdn self.realm = realm + self.domain = fqdn[fqdn.find(".")+1:] + self.sub_dict = { "REALM" : realm, "FQDN": fqdn, "DOMAIN" : self.domain } self.start_creation(7, "Configuring the web interface") @@ -60,6 +62,7 @@ class HTTPInstance(service.Service): self.__configure_http() self.__create_http_keytab() self.__setup_ssl() + self.__setup_autoconfig() self.step("restarting httpd") self.restart() @@ -141,4 +144,31 @@ class HTTPInstance(service.Service): ds_ca.cur_serial = 2000 ca.create_from_cacert(ds_ca.cacert_fname) ca.create_server_cert("Server-Cert", "cn=%s,ou=Apache Web Server" % self.fqdn, ds_ca) - + ca.create_signing_cert("Signing-Cert", "cn=%s,ou=Signing Certificate,o=Identity Policy Audit" % self.fqdn, ds_ca) + + def __setup_autoconfig(self): + prefs_txt = template_file(SHARE_DIR + "preferences.html.template", self.sub_dict) + prefs_fd = open("/usr/share/ipa/html/preferences.html", "w") + prefs_fd.write(prefs_txt) + prefs_fd.close() + + # The signing cert is generated in __setup_ssl + ds_ca = certs.CertDB(dsinstance.config_dirname(self.realm)) + ca = certs.CertDB(NSS_DIR) + + # Publish the CA certificate + shutil.copy(ds_ca.cacert_fname, "/usr/share/ipa/html/ca.crt") + os.chmod("/usr/share/ipa/html/ca.crt", 0444) + + try: + shutil.rmtree("/tmp/ipa") + except: + pass + os.mkdir("/tmp/ipa") + shutil.copy("/usr/share/ipa/html/preferences.html", "/tmp/ipa") + + ca.run_signtool(["-k", "Signing-Cert", + "-Z", "/usr/share/ipa/html/configure.jar", + "-e", ".html", + "/tmp/ipa"]) + shutil.rmtree("/tmp/ipa") diff --git a/ipa-server/xmlrpc-server/ipa.conf b/ipa-server/xmlrpc-server/ipa.conf index fbf26b67c..4e8bf528f 100644 --- a/ipa-server/xmlrpc-server/ipa.conf +++ b/ipa-server/xmlrpc-server/ipa.conf @@ -12,9 +12,12 @@ RewriteRule ^/(.*) http://$FQDN/$$1 [L,R=301] # Redirect to the secure port if not displaying an error or retrieving # configuration. RewriteCond %{SERVER_PORT} !^443$$ -RewriteCond %{REQUEST_URI} !^/(errors|config)/ +RewriteCond %{REQUEST_URI} !^/(errors|config|favicon.ico) RewriteRule ^/(.*) https://$FQDN/$$1 [L,R=301,NC] +# This is required so the auto-configuration works with Firefox 2+ +AddType application/java-archive jar + AuthType Kerberos AuthName "Kerberos Login" diff --git a/ipa-server/xmlrpc-server/unauthorized.html b/ipa-server/xmlrpc-server/unauthorized.html index 23a8d5c7d..e46ca538f 100644 --- a/ipa-server/xmlrpc-server/unauthorized.html +++ b/ipa-server/xmlrpc-server/unauthorized.html @@ -9,6 +9,20 @@ have configured your browser correctly. If you are still unable to access the IPA Web interface, please contact the helpdesk on for additional assistance.

+

+Import the IPA Certificate Authority. +

+

+ +

-- cgit From c9160e02331dfd57b3f6a4b1c00d614a129c126d Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 11:32:56 -0500 Subject: Fix minor typo in unauthorized page. --- ipa-server/xmlrpc-server/unauthorized.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipa-server/xmlrpc-server/unauthorized.html b/ipa-server/xmlrpc-server/unauthorized.html index e46ca538f..eba1266ad 100644 --- a/ipa-server/xmlrpc-server/unauthorized.html +++ b/ipa-server/xmlrpc-server/unauthorized.html @@ -19,7 +19,7 @@ Import the IPA Certificate Authority. { document.write("

You can automatically configure your browser to work with Kerberos by importing the Certificate Authority below and clicking on the Configure Browser button.

"); document.write("

You must reload this page after importing the Certificate Authority for the automatic settings to work

"); - document.write("<\/object"); + document.write("<\/object"); }

-- cgit From 5cdff99bdfef7f43fb48814720d4e942f197d9c1 Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 12:01:03 -0500 Subject: Add a man page for ipa-getkeytab. --- ipa-admintools/man/Makefile | 3 +- ipa-admintools/man/ipa-getkeytab.1 | 64 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 ipa-admintools/man/ipa-getkeytab.1 diff --git a/ipa-admintools/man/Makefile b/ipa-admintools/man/Makefile index 19648f539..154124753 100644 --- a/ipa-admintools/man/Makefile +++ b/ipa-admintools/man/Makefile @@ -14,7 +14,8 @@ MANFILES=\ ipa-lockuser.1 \ ipa-moddelegation.1 \ ipa-passwd.1 \ - ipa-usermod.1 + ipa-usermod.1 \ + ipa-getkeytab.1 all: ; diff --git a/ipa-admintools/man/ipa-getkeytab.1 b/ipa-admintools/man/ipa-getkeytab.1 new file mode 100644 index 000000000..da511171a --- /dev/null +++ b/ipa-admintools/man/ipa-getkeytab.1 @@ -0,0 +1,64 @@ +.\" A man page for ipa-getkeytab +.\" Copyright (C) 2007 Red Hat, Inc. +.\" +.\" This is free software; you can redistribute it and/or modify it under +.\" the terms of the GNU Library 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 Library General Public +.\" License along with this program; if not, write to the Free Software +.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +.\" +.\" Author: Karl MacMillan +.\" +.TH "ipa-getkeytab" "1" "Oct 10 2007" "freeipa" "" +.SH "NAME" +ipa\-getkeytab \- Get a keytab for a kerberos principal +.SH "SYNOPSIS" +ipa\-getkeytab [\fI-a\fR] \fIprincipal-name\fR \fIfile-name\fR + +.SH "DESCRIPTION" +Retrieves a kerberos \fIkeytab\fR and optionally adds a +service \fIprincipal\fR. + +Kerberos keytabs are used for services (like sshd) to +perform kerberos authentication. A keytab is a file +with one or more secrets (or keys) for a kerberos +principal. + +A kerberos service principal is a kerberos identity +that can be used for authentication. Service principals +contain the name of the service, the hostname of the +server, and the realm name. For example, the following +is an example principal for an ldap server: + + ldap/foo.example.com@EXAMPLE.COM + +When using ipa-getkeytab the realm name is already +provided, so the principal name is just the service +name and hostname (ldap/foo.example.com from the +example above). + +\fBWARNING:\fR retrieving the keytab resets the secret +rendering all other keytabs for that principal invalid. + +.SH "OPTIONS" +.TP +\fB\-a\fR +Add the service principal in addition to getting the keytab + +.SH "EXAMPLES" + +Add and retrieve a keytab for the ldap service principal on +the host foo.example.com and save it in the file ldap.keytab. + + # ipa-getkeytab -a ldap/foo.example.com ldap.keytab + +.SH "EXIT STATUS" +The exit status is 0 on success, nonzero on error. -- 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. --- Makefile | 28 +- ipa-python/ipautil.py | 1 + ipa-python/radius_util.py | 2 +- ipa-radius-server/Makefile | 20 ++ ipa-radius-server/ipa-radius-install | 73 ++++++ ipa-radius-server/ipa-radius-server.spec | 50 ++++ ipa-radius-server/ipa-radius-server.spec.in | 50 ++++ ipa-radius-server/plugins/__init__.py | 1 + ipa-radius-server/plugins/radiusinstance.py | 173 +++++++++++++ .../share/radius.radiusd.conf.template | 285 +++++++++++++++++++++ ipa-server/ipa-install/Makefile.am | 1 - ipa-server/ipa-install/ipa-radius-install | 72 ------ ipa-server/ipa-install/share/Makefile.am | 1 - .../ipa-install/share/radius.radiusd.conf.template | 285 --------------------- ipa-server/ipa-server.spec | 1 - ipa-server/ipa-server.spec.in | 1 - ipa-server/ipaserver/Makefile.am | 1 - ipa-server/ipaserver/radiusinstance.py | 171 ------------- 18 files changed, 680 insertions(+), 536 deletions(-) create mode 100644 ipa-radius-server/Makefile create mode 100644 ipa-radius-server/ipa-radius-install create mode 100755 ipa-radius-server/ipa-radius-server.spec create mode 100755 ipa-radius-server/ipa-radius-server.spec.in create mode 100644 ipa-radius-server/plugins/__init__.py create mode 100644 ipa-radius-server/plugins/radiusinstance.py create mode 100644 ipa-radius-server/share/radius.radiusd.conf.template delete mode 100644 ipa-server/ipa-install/ipa-radius-install delete mode 100644 ipa-server/ipa-install/share/radius.radiusd.conf.template delete mode 100644 ipa-server/ipaserver/radiusinstance.py diff --git a/Makefile b/Makefile index 0461144ac..25af85334 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SUBDIRS=ipa-server ipa-admintools ipa-python ipa-client +SUBDIRS=ipa-server ipa-admintools ipa-python ipa-client ipa-radius-server PRJ_PREFIX=ipa @@ -35,6 +35,13 @@ CLI_VERSION=$(CLI_MAJOR).$(CLI_MINOR).$(CLI_RELEASE) CLI_TARBALL_PREFIX=$(PRJ_PREFIX)-client-$(CLI_VERSION) CLI_TARBALL=$(CLI_TARBALL_PREFIX).tgz +RADIUS_SERVER_MAJOR=0 +RADIUS_SERVER_MINOR=5 +RADIUS_SERVER_RELEASE=0 +RADIUS_SERVER_VERSION=$(RADIUS_SERVER_MAJOR).$(RADIUS_SERVER_MINOR).$(RADIUS_SERVER_RELEASE) +RADIUS_SERVER_TARBALL_PREFIX=$(PRJ_PREFIX)-radius-server-$(RADIUS_SERVER_VERSION) +RADIUS_SERVER_TARBALL=$(RADIUS_SERVER_TARBALL_PREFIX).tgz + LIBDIR ?= /usr/lib all: bootstrap-autogen @@ -77,6 +84,9 @@ version-update: sed s/VERSION/$(CLI_VERSION)/ ipa-client/ipa-client.spec.in \ > ipa-client/ipa-client.spec + sed s/VERSION/$(RADIUS_SERVER_VERSION)/ ipa-radius-server/ipa-radius-server.spec.in \ + > ipa-radius-server/ipa-radius-server.spec + archive: -mkdir -p dist @@ -120,6 +130,13 @@ tarballs: cd dist; tar cfz sources/$(CLI_TARBALL) $(CLI_TARBALL_PREFIX) rm -fr dist/$(CLI_TARBALL_PREFIX) + # ipa-radius-server + mv dist/ipa/ipa-radius-server dist/$(RADIUS_SERVER_TARBALL_PREFIX) + rm -f dist/sources/$(RADIUS_SERVER_TARBALL) + cd dist; tar cfz sources/$(RADIUS_SERVER_TARBALL) $(RADIUS_SERVER_TARBALL_PREFIX) + rm -fr dist/$(RADIUS_SERVER_TARBALL_PREFIX) + + rpmroot: mkdir -p $(RPMBUILD)/BUILD mkdir -p $(RPMBUILD)/RPMS @@ -155,7 +172,14 @@ rpm-ipa-client: cp rpmbuild/RPMS/*/$(PRJ_PREFIX)-client-$(CLI_VERSION)-*.rpm dist/rpms/ cp rpmbuild/SRPMS/$(PRJ_PREFIX)-client-$(CLI_VERSION)-*.src.rpm dist/srpms/ -rpms: rpmroot rpmdistdir rpm-ipa-server rpm-ipa-admin rpm-ipa-python rpm-ipa-client +rpm-ipa-radius-server: + cp dist/sources/$(RADIUS_SERVER_TARBALL) $(RPMBUILD)/SOURCES/. + rpmbuild --define "_topdir $(RPMBUILD)" -ba ipa-radius-server/ipa-radius-server.spec + cp rpmbuild/RPMS/noarch/$(PRJ_PREFIX)-radius-server-$(RADIUS_SERVER_VERSION)-*.rpm dist/rpms/ + cp rpmbuild/SRPMS/$(PRJ_PREFIX)-radius-server-$(RADIUS_SERVER_VERSION)-*.src.rpm dist/srpms/ + + +rpms: rpmroot rpmdistdir rpm-ipa-server rpm-ipa-admin rpm-ipa-python rpm-ipa-client rpm-ipa-radius-server repodata: -createrepo -p dist diff --git a/ipa-python/ipautil.py b/ipa-python/ipautil.py index 3c2b37f73..c617854e5 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 1f6e7902b..40b0bd253 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' diff --git a/ipa-radius-server/Makefile b/ipa-radius-server/Makefile new file mode 100644 index 000000000..7de51b469 --- /dev/null +++ b/ipa-radius-server/Makefile @@ -0,0 +1,20 @@ +PLUGINS_SHARE = $(DESTDIR)/usr/share/ipa/plugins +PLUGINS_PYTHON = $(DESTDIR)/usr/share/ipa/ipaserver/plugins +SBINDIR = $(DESTDIR)/usr/sbin + +all: + +install: + -mkdir -p $(PLUGINS_SHARE) + -mkdir -p $(PLUGINS_PYTHON) + -mkdir -p $(PLUGINS_SBINDIR) + install -m 644 plugins/*.py $(PLUGINS_PYTHON) + install -m 644 share/*.template $(PLUGINS_SHARE) + install -m 755 ipa-radius-install $(SBINDIR) + +clean: + rm -fr *.pyc *~ + +distclean: clean + +test: \ No newline at end of file diff --git a/ipa-radius-server/ipa-radius-install b/ipa-radius-server/ipa-radius-install new file mode 100644 index 000000000..3e759d8d2 --- /dev/null +++ b/ipa-radius-server/ipa-radius-install @@ -0,0 +1,73 @@ +#! /usr/bin/python -E +# Authors: Karl MacMillan +# +# 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 traceback, logging, krbV + +from ipaserver import installutils +from ipaserver.plugins import radiusinstance + +from ipa import ipautil + +def get_host_name(): + hostname = installutils.get_fqdn() + try: + installutils.verify_fqdn(hostname) + except RuntimeError, e: + logging.error(str(e)) + sys.exit(1) + + return hostname + +def get_realm_name(): + c = krbV.default_context() + return c.default_realm + +def main(): + if not ipautil.file_exists("/etc/ipa/ipa.conf"): + print "This system does not appear to have IPA configured." + print "Has ipa-server-install been run?" + yesno = raw_input("Continue with radius install [y/N]? ") + if yesno.lower() != "y": + sys.exit(1) + + installutils.standard_logging_setup("iparadius-install.log", False) + + host_name = get_host_name() + + realm_name = get_realm_name() + + # Create a radius instance + radius = radiusinstance.RadiusInstance() + # FIXME: ldap_server should be derived, not hardcoded to localhost, also should it be a URL? + radius.create_instance(realm_name, host_name, 'localhost') + + +try: + main() +except Exception, e: + message = "Unexpected error - see iparadius-install.log for details:\n %s" % str(e) + print message + message = str(e) + for str in traceback.format_tb(sys.exc_info()[2]): + message = message + "\n" + str + logging.debug(message) diff --git a/ipa-radius-server/ipa-radius-server.spec b/ipa-radius-server/ipa-radius-server.spec new file mode 100755 index 000000000..2b8b61624 --- /dev/null +++ b/ipa-radius-server/ipa-radius-server.spec @@ -0,0 +1,50 @@ +Name: ipa-radius-server +Version: 0.5.0 +Release: 1%{?dist} +Summary: IPA authentication server - radius plugin + +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 +Requires: ipa-server +Requires: freeradius + +%description +Radius plugin for an IPA server + +%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* + +%dir %{_usr}/share/ipa/plugins +%{_usr}/share/ipa/plugins/* + +%dir %{_usr}/share/ipa/ipaserver/plugins +%{_usr}/share/ipa/ipaserver/plugins/* + +%changelog +* Wed Dec 12 2007 Karl MacMillan - 0.5.0-1 +- Initial version + + + + diff --git a/ipa-radius-server/ipa-radius-server.spec.in b/ipa-radius-server/ipa-radius-server.spec.in new file mode 100755 index 000000000..5937d3b19 --- /dev/null +++ b/ipa-radius-server/ipa-radius-server.spec.in @@ -0,0 +1,50 @@ +Name: ipa-radius-server +Version: VERSION +Release: 1%{?dist} +Summary: IPA authentication server - radius plugin + +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 +Requires: ipa-server +Requires: freeradius + +%description +Radius plugin for an IPA server + +%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* + +%dir %{_usr}/share/ipa/plugins +%{_usr}/share/ipa/plugins/* + +%dir %{_usr}/share/ipa/ipaserver/plugins +%{_usr}/share/ipa/ipaserver/plugins/* + +%changelog +* Wed Dec 12 2007 Karl MacMillan - 0.5.0-1 +- Initial version + + + + diff --git a/ipa-radius-server/plugins/__init__.py b/ipa-radius-server/plugins/__init__.py new file mode 100644 index 000000000..636bc1a8a --- /dev/null +++ b/ipa-radius-server/plugins/__init__.py @@ -0,0 +1 @@ +# intentionally empty diff --git a/ipa-radius-server/plugins/radiusinstance.py b/ipa-radius-server/plugins/radiusinstance.py new file mode 100644 index 000000000..743a1d8a2 --- /dev/null +++ b/ipa-radius-server/plugins/radiusinstance.py @@ -0,0 +1,173 @@ +#! /usr/bin/python -E +# Authors: John Dennis +# +# 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 +sys.path.append("/usr/share/ipa") + +import subprocess +import string +import tempfile +import shutil +import logging +import pwd +import time +import sys +from ipa.ipautil import * +from ipa import radius_util + +from ipaserver import service + +import os +import re + +IPA_RADIUS_VERSION = '0.0.0' + +# FIXME there should a utility to get the user base dn +from ipaserver.funcs import DefaultUserContainer, DefaultGroupContainer + +#------------------------------------------------------------------------------- + +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 get_radius_version(): + version = None + try: + p = subprocess.Popen([radius_util.RADIUSD, '-v'], stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + status = p.returncode + + if status == 0: + match = re.search("radiusd: FreeRADIUS Version (.+), for host", stdout) + if match: + version = match.group(1) + except Exception, e: + pass + return version + + +#------------------------------------------------------------------------------- + +class RadiusInstance(service.Service): + def __init__(self): + service.Service.__init__(self, "radiusd") + self.fqdn = None + self.realm = None + self.principal = None + + def create_instance(self, realm_name, host_name, ldap_server): + self.realm = realm_name.upper() + self.suffix = realm_to_suffix(self.realm) + self.fqdn = host_name + self.ldap_server = ldap_server + self.principal = "%s/%s@%s" % (radius_util.RADIUS_SERVICE_NAME, self.fqdn, self.realm) + self.basedn = self.suffix + self.user_basedn = "%s,%s" % (DefaultUserContainer, self.basedn) # FIXME, should be utility to get this + self.radius_version = get_radius_version() + self.start_creation(4, "Configuring radiusd") + + try: + self.stop() + except: + # It could have been not running + pass + + self.__create_radius_keytab() + self.__radiusd_conf() + + try: + self.step("starting radiusd") + self.start() + except: + logging.error("radiusd service failed to start") + + self.step("configuring radiusd to start on boot") + self.chkconfig_on() + + + def __radiusd_conf(self): + self.step('configuring radiusd.conf for radius instance') + + version = 'IPA_RADIUS_VERSION=%s FREE_RADIUS_VERSION=%s' % (IPA_RADIUS_VERSION, self.radius_version) + sub_dict = {'CONFIG_FILE_VERSION_INFO' : version, + 'LDAP_SERVER' : self.ldap_server, + 'RADIUS_KEYTAB' : radius_util.RADIUS_IPA_KEYTAB_FILEPATH, + 'RADIUS_PRINCIPAL' : self.principal, + 'RADIUS_USER_BASE_DN' : self.user_basedn, + 'ACCESS_ATTRIBUTE' : '', + 'ACCESS_ATTRIBUTE_DEFAULT' : 'TRUE', + 'CLIENTS_BASEDN' : radius_util.radius_clients_basedn(None, self.suffix), + 'SUFFIX' : self.suffix, + } + try: + radiusd_conf = template_file(radius_util.RADIUSD_CONF_TEMPLATE_FILEPATH, sub_dict) + radiusd_fd = open(radius_util.RADIUSD_CONF_FILEPATH, 'w+') + radiusd_fd.write(radiusd_conf) + radiusd_fd.close() + except Exception, e: + logging.error("could not create %s: %s", radius_util.RADIUSD_CONF_FILEPATH, e) + + def __create_radius_keytab(self): + self.step("creating a keytab for radiusd") + try: + if file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): + os.remove(radius_util.RADIUS_IPA_KEYTAB_FILEPATH) + except os.error: + logging.error("Failed to remove %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH) + + (kwrite, kread, kerr) = os.popen3("/usr/kerberos/sbin/kadmin.local") + kwrite.write("addprinc -randkey %s\n" % (self.principal)) + kwrite.flush() + kwrite.write("ktadd -k %s %s\n" % (radius_util.RADIUS_IPA_KEYTAB_FILEPATH, self.principal)) + kwrite.flush() + kwrite.close() + kread.close() + kerr.close() + + # give kadmin time to actually write the file before we go on + retry = 0 + while not file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): + time.sleep(1) + retry += 1 + if retry > 15: + print "Error timed out waiting for kadmin to finish operations\n" + sys.exit(1) + try: + pent = pwd.getpwnam(radius_util.RADIUS_USER) + os.chown(radius_util.RADIUS_IPA_KEYTAB_FILEPATH, pent.pw_uid, pent.pw_gid) + except Exception, e: + logging.error("could not chown on %s to %s: %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH, radius_util.RADIUS_USER, e) + + #FIXME, should use IPAdmin method + def __set_ldap_encrypted_attributes(self): + ldif_file = 'encrypted_attribute.ldif' + self.step("setting ldap encrypted attributes") + ldif_txt = template_file(SHARE_DIR + ldif_file, {'ENCRYPTED_ATTRIBUTE':'radiusClientSecret'}) + ldif_fd = write_tmp_file(ldif_txt) + try: + ldap_mod(ldif_fd, "cn=Directory Manager", self.dm_password) + except subprocess.CalledProcessError, e: + logging.critical("Failed to load %s: %s" % (ldif_file, str(e))) + ldif_fd.close() + +#------------------------------------------------------------------------------- + diff --git a/ipa-radius-server/share/radius.radiusd.conf.template b/ipa-radius-server/share/radius.radiusd.conf.template new file mode 100644 index 000000000..3bc4927dd --- /dev/null +++ b/ipa-radius-server/share/radius.radiusd.conf.template @@ -0,0 +1,285 @@ +# +# WARNING: This file is automatically generated, do not edit +# +# $CONFIG_FILE_VERSION_INFO +# +prefix = /usr +exec_prefix = /usr +sysconfdir = /etc +localstatedir = /var +sbindir = /usr/sbin +logdir = $${localstatedir}/log/radius +raddbdir = $${sysconfdir}/raddb +radacctdir = $${logdir}/radacct +confdir = $${raddbdir} +run_dir = $${localstatedir}/run/radiusd +db_dir = $${localstatedir}/lib/radiusd +log_file = $${logdir}/radius.log +libdir = /usr/lib +pidfile = $${run_dir}/radiusd.pid +user = radiusd +group = radiusd +max_request_time = 30 +delete_blocked_requests = no +cleanup_delay = 5 +max_requests = 1024 +bind_address = * +port = 0 +hostname_lookups = no +allow_core_dumps = no +regular_expressions = yes +extended_expressions = yes +log_stripped_names = no +log_auth = no +log_auth_badpass = no +log_auth_goodpass = no +usercollide = no +lower_user = no +lower_pass = no +nospace_user = no +nospace_pass = no +checkrad = $${sbindir}/checkrad +security { + max_attributes = 200 + reject_delay = 1 + status_server = no +} +proxy_requests = yes +$$INCLUDE $${confdir}/proxy.conf +$$INCLUDE $${confdir}/clients.conf +snmp = no +$$INCLUDE $${confdir}/snmp.conf +thread pool { + start_servers = 5 + max_servers = 32 + min_spare_servers = 3 + max_spare_servers = 10 + max_requests_per_server = 0 +} +modules { + chap { + authtype = CHAP + } + pam { + pam_auth = radiusd + } + unix { + cache = no + cache_reload = 600 + shadow = /etc/shadow + radwtmp = $${logdir}/radwtmp + } +$$INCLUDE $${confdir}/eap.conf + mschap { + } + ldap { + server = "$LDAP_SERVER" + use_sasl = yes + sasl_mech = "GSSAPI" + krb_keytab = "$RADIUS_KEYTAB" + krb_principal = "$RADIUS_PRINCIPAL" + basedn = "$RADIUS_USER_BASE_DN" + filter = "(uid=%{Stripped-User-Name:-%{User-Name}})" + base_filter = "(objectclass=radiusprofile)" + start_tls = no + profile_attribute = "radiusProfileDn" + default_profile = "uid=ipa_default,cn=profiles,cn=radius,cn=services,cn=etc,$SUFFIX + # FIXME: we'll want to toggle the access_attr feature on/off, + # but it needs a control, so disable it for now. + #access_attr = "$ACCESS_ATTRIBUTE" + #access_attr_used_for_allow = "$ACCESS_ATTRIBUTE_DEFAULT" + dictionary_mapping = $${raddbdir}/ldap.attrmap + ldap_connections_number = 5 + edir_account_policy_check=no + timeout = 4 + timelimit = 3 + net_timeout = 1 + clients_basedn = "$CLIENTS_BASEDN" + } + realm IPASS { + format = prefix + delimiter = "/" + ignore_default = no + ignore_null = no + } + realm suffix { + format = suffix + delimiter = "@" + ignore_default = no + ignore_null = no + } + realm realmpercent { + format = suffix + delimiter = "%" + ignore_default = no + ignore_null = no + } + realm ntdomain { + format = prefix + delimiter = "\\" + ignore_default = no + ignore_null = no + } + checkval { + item-name = Calling-Station-Id + check-name = Calling-Station-Id + data-type = string + } + preprocess { + huntgroups = $${confdir}/huntgroups + hints = $${confdir}/hints + with_ascend_hack = no + ascend_channels_per_line = 23 + with_ntdomain_hack = no + with_specialix_jetstream_hack = no + with_cisco_vsa_hack = no + } + files { + usersfile = $${confdir}/users + acctusersfile = $${confdir}/acct_users + preproxy_usersfile = $${confdir}/preproxy_users + compat = no + } + detail { + detailfile = $${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d + detailperm = 0600 + } + acct_unique { + key = "User-Name, Acct-Session-Id, NAS-IP-Address, Client-IP-Address, NAS-Port" + } + radutmp { + filename = $${logdir}/radutmp + username = %{User-Name} + case_sensitive = yes + check_with_nas = yes + perm = 0600 + callerid = "yes" + } + radutmp sradutmp { + filename = $${logdir}/sradutmp + perm = 0644 + callerid = "no" + } + attr_filter { + attrsfile = $${confdir}/attrs + } + counter daily { + filename = $${db_dir}/db.daily + key = User-Name + count-attribute = Acct-Session-Time + reset = daily + counter-name = Daily-Session-Time + check-name = Max-Daily-Session + allowed-servicetype = Framed-User + cache-size = 5000 + } + sqlcounter dailycounter { + counter-name = Daily-Session-Time + check-name = Max-Daily-Session + reply-name = Session-Timeout + sqlmod-inst = sql + key = User-Name + reset = daily + query = "SELECT SUM(AcctSessionTime - \ + GREATEST((%b - UNIX_TIMESTAMP(AcctStartTime)), 0)) \ + FROM radacct WHERE UserName='%{%k}' AND \ + UNIX_TIMESTAMP(AcctStartTime) + AcctSessionTime > '%b'" + } + sqlcounter monthlycounter { + counter-name = Monthly-Session-Time + check-name = Max-Monthly-Session + reply-name = Session-Timeout + sqlmod-inst = sql + key = User-Name + reset = monthly + query = "SELECT SUM(AcctSessionTime - \ + GREATEST((%b - UNIX_TIMESTAMP(AcctStartTime)), 0)) \ + FROM radacct WHERE UserName='%{%k}' AND \ + UNIX_TIMESTAMP(AcctStartTime) + AcctSessionTime > '%b'" + } + always fail { + rcode = fail + } + always reject { + rcode = reject + } + always ok { + rcode = ok + simulcount = 0 + mpp = no + } + expr { + } + digest { + } + exec { + wait = yes + input_pairs = request + } + exec echo { + wait = yes + program = "/bin/echo %{User-Name}" + input_pairs = request + output_pairs = reply + } + ippool main_pool { + range-start = 192.168.1.1 + range-stop = 192.168.3.254 + netmask = 255.255.255.0 + cache-size = 800 + session-db = $${db_dir}/db.ippool + ip-index = $${db_dir}/db.ipindex + override = no + maximum-timeout = 0 + } + krb5 { + keytab = "$RADIUS_KEYTAB" + service_principal = "$RADIUS_PRINCIPAL" + } +} +instantiate { + exec + expr +} +authorize { + preprocess + chap + mschap + suffix + eap + #files + ldap +} +authenticate { + Auth-Type CHAP { + chap + } + Auth-Type MS-CHAP { + mschap + } + eap + Auth-Type Kerberos { + krb5 + } +} +preacct { + preprocess + acct_unique + suffix + files +} +accounting { + detail + unix + radutmp +} +session { + radutmp +} +post-auth { +} +pre-proxy { +} +post-proxy { + eap +} diff --git a/ipa-server/ipa-install/Makefile.am b/ipa-server/ipa-install/Makefile.am index 37dd325e8..8a3e4a975 100644 --- a/ipa-server/ipa-install/Makefile.am +++ b/ipa-server/ipa-install/Makefile.am @@ -9,7 +9,6 @@ sbin_SCRIPTS = \ ipa-replica-install \ ipa-replica-prepare \ ipa-server-certinstall \ - ipa-radius-install \ $(NULL) EXTRA_DIST = \ diff --git a/ipa-server/ipa-install/ipa-radius-install b/ipa-server/ipa-install/ipa-radius-install deleted file mode 100644 index 84e10e426..000000000 --- a/ipa-server/ipa-install/ipa-radius-install +++ /dev/null @@ -1,72 +0,0 @@ -#! /usr/bin/python -E -# Authors: Karl MacMillan -# -# 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 traceback, logging, krbV - -from ipaserver import radiusinstance, installutils - -from ipa import ipautil - -def get_host_name(): - hostname = installutils.get_fqdn() - try: - installutils.verify_fqdn(hostname) - except RuntimeError, e: - logging.error(str(e)) - sys.exit(1) - - return hostname - -def get_realm_name(): - c = krbV.default_context() - return c.default_realm - -def main(): - if not ipautil.file_exists("/etc/ipa/ipa.conf"): - print "This system does not appear to have IPA configured." - print "Has ipa-server-install been run?" - yesno = raw_input("Continue with radius install [y/N]? ") - if yesno.lower() != "y": - sys.exit(1) - - installutils.standard_logging_setup("iparadius-install.log", False) - - host_name = get_host_name() - - realm_name = get_realm_name() - - # Create a radius instance - radius = radiusinstance.RadiusInstance() - # FIXME: ldap_server should be derived, not hardcoded to localhost, also should it be a URL? - radius.create_instance(realm_name, host_name, 'localhost') - - -try: - main() -except Exception, e: - message = "Unexpected error - see iparadius-install.log for details:\n %s" % str(e) - print message - message = str(e) - for str in traceback.format_tb(sys.exc_info()[2]): - message = message + "\n" + str - logging.debug(message) diff --git a/ipa-server/ipa-install/share/Makefile.am b/ipa-server/ipa-install/share/Makefile.am index 36837356d..5d117dec5 100644 --- a/ipa-server/ipa-install/share/Makefile.am +++ b/ipa-server/ipa-install/share/Makefile.am @@ -20,7 +20,6 @@ app_DATA = \ krbrealm.con.template \ ntp.conf.server.template \ preferences.html.template \ - radius.radiusd.conf.template \ referint-conf.ldif \ dna-posix.ldif \ master-entry.ldif \ diff --git a/ipa-server/ipa-install/share/radius.radiusd.conf.template b/ipa-server/ipa-install/share/radius.radiusd.conf.template deleted file mode 100644 index 3bc4927dd..000000000 --- a/ipa-server/ipa-install/share/radius.radiusd.conf.template +++ /dev/null @@ -1,285 +0,0 @@ -# -# WARNING: This file is automatically generated, do not edit -# -# $CONFIG_FILE_VERSION_INFO -# -prefix = /usr -exec_prefix = /usr -sysconfdir = /etc -localstatedir = /var -sbindir = /usr/sbin -logdir = $${localstatedir}/log/radius -raddbdir = $${sysconfdir}/raddb -radacctdir = $${logdir}/radacct -confdir = $${raddbdir} -run_dir = $${localstatedir}/run/radiusd -db_dir = $${localstatedir}/lib/radiusd -log_file = $${logdir}/radius.log -libdir = /usr/lib -pidfile = $${run_dir}/radiusd.pid -user = radiusd -group = radiusd -max_request_time = 30 -delete_blocked_requests = no -cleanup_delay = 5 -max_requests = 1024 -bind_address = * -port = 0 -hostname_lookups = no -allow_core_dumps = no -regular_expressions = yes -extended_expressions = yes -log_stripped_names = no -log_auth = no -log_auth_badpass = no -log_auth_goodpass = no -usercollide = no -lower_user = no -lower_pass = no -nospace_user = no -nospace_pass = no -checkrad = $${sbindir}/checkrad -security { - max_attributes = 200 - reject_delay = 1 - status_server = no -} -proxy_requests = yes -$$INCLUDE $${confdir}/proxy.conf -$$INCLUDE $${confdir}/clients.conf -snmp = no -$$INCLUDE $${confdir}/snmp.conf -thread pool { - start_servers = 5 - max_servers = 32 - min_spare_servers = 3 - max_spare_servers = 10 - max_requests_per_server = 0 -} -modules { - chap { - authtype = CHAP - } - pam { - pam_auth = radiusd - } - unix { - cache = no - cache_reload = 600 - shadow = /etc/shadow - radwtmp = $${logdir}/radwtmp - } -$$INCLUDE $${confdir}/eap.conf - mschap { - } - ldap { - server = "$LDAP_SERVER" - use_sasl = yes - sasl_mech = "GSSAPI" - krb_keytab = "$RADIUS_KEYTAB" - krb_principal = "$RADIUS_PRINCIPAL" - basedn = "$RADIUS_USER_BASE_DN" - filter = "(uid=%{Stripped-User-Name:-%{User-Name}})" - base_filter = "(objectclass=radiusprofile)" - start_tls = no - profile_attribute = "radiusProfileDn" - default_profile = "uid=ipa_default,cn=profiles,cn=radius,cn=services,cn=etc,$SUFFIX - # FIXME: we'll want to toggle the access_attr feature on/off, - # but it needs a control, so disable it for now. - #access_attr = "$ACCESS_ATTRIBUTE" - #access_attr_used_for_allow = "$ACCESS_ATTRIBUTE_DEFAULT" - dictionary_mapping = $${raddbdir}/ldap.attrmap - ldap_connections_number = 5 - edir_account_policy_check=no - timeout = 4 - timelimit = 3 - net_timeout = 1 - clients_basedn = "$CLIENTS_BASEDN" - } - realm IPASS { - format = prefix - delimiter = "/" - ignore_default = no - ignore_null = no - } - realm suffix { - format = suffix - delimiter = "@" - ignore_default = no - ignore_null = no - } - realm realmpercent { - format = suffix - delimiter = "%" - ignore_default = no - ignore_null = no - } - realm ntdomain { - format = prefix - delimiter = "\\" - ignore_default = no - ignore_null = no - } - checkval { - item-name = Calling-Station-Id - check-name = Calling-Station-Id - data-type = string - } - preprocess { - huntgroups = $${confdir}/huntgroups - hints = $${confdir}/hints - with_ascend_hack = no - ascend_channels_per_line = 23 - with_ntdomain_hack = no - with_specialix_jetstream_hack = no - with_cisco_vsa_hack = no - } - files { - usersfile = $${confdir}/users - acctusersfile = $${confdir}/acct_users - preproxy_usersfile = $${confdir}/preproxy_users - compat = no - } - detail { - detailfile = $${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d - detailperm = 0600 - } - acct_unique { - key = "User-Name, Acct-Session-Id, NAS-IP-Address, Client-IP-Address, NAS-Port" - } - radutmp { - filename = $${logdir}/radutmp - username = %{User-Name} - case_sensitive = yes - check_with_nas = yes - perm = 0600 - callerid = "yes" - } - radutmp sradutmp { - filename = $${logdir}/sradutmp - perm = 0644 - callerid = "no" - } - attr_filter { - attrsfile = $${confdir}/attrs - } - counter daily { - filename = $${db_dir}/db.daily - key = User-Name - count-attribute = Acct-Session-Time - reset = daily - counter-name = Daily-Session-Time - check-name = Max-Daily-Session - allowed-servicetype = Framed-User - cache-size = 5000 - } - sqlcounter dailycounter { - counter-name = Daily-Session-Time - check-name = Max-Daily-Session - reply-name = Session-Timeout - sqlmod-inst = sql - key = User-Name - reset = daily - query = "SELECT SUM(AcctSessionTime - \ - GREATEST((%b - UNIX_TIMESTAMP(AcctStartTime)), 0)) \ - FROM radacct WHERE UserName='%{%k}' AND \ - UNIX_TIMESTAMP(AcctStartTime) + AcctSessionTime > '%b'" - } - sqlcounter monthlycounter { - counter-name = Monthly-Session-Time - check-name = Max-Monthly-Session - reply-name = Session-Timeout - sqlmod-inst = sql - key = User-Name - reset = monthly - query = "SELECT SUM(AcctSessionTime - \ - GREATEST((%b - UNIX_TIMESTAMP(AcctStartTime)), 0)) \ - FROM radacct WHERE UserName='%{%k}' AND \ - UNIX_TIMESTAMP(AcctStartTime) + AcctSessionTime > '%b'" - } - always fail { - rcode = fail - } - always reject { - rcode = reject - } - always ok { - rcode = ok - simulcount = 0 - mpp = no - } - expr { - } - digest { - } - exec { - wait = yes - input_pairs = request - } - exec echo { - wait = yes - program = "/bin/echo %{User-Name}" - input_pairs = request - output_pairs = reply - } - ippool main_pool { - range-start = 192.168.1.1 - range-stop = 192.168.3.254 - netmask = 255.255.255.0 - cache-size = 800 - session-db = $${db_dir}/db.ippool - ip-index = $${db_dir}/db.ipindex - override = no - maximum-timeout = 0 - } - krb5 { - keytab = "$RADIUS_KEYTAB" - service_principal = "$RADIUS_PRINCIPAL" - } -} -instantiate { - exec - expr -} -authorize { - preprocess - chap - mschap - suffix - eap - #files - ldap -} -authenticate { - Auth-Type CHAP { - chap - } - Auth-Type MS-CHAP { - mschap - } - eap - Auth-Type Kerberos { - krb5 - } -} -preacct { - preprocess - acct_unique - suffix - files -} -accounting { - detail - unix - radutmp -} -session { - radutmp -} -post-auth { -} -pre-proxy { -} -post-proxy { - eap -} diff --git a/ipa-server/ipa-server.spec b/ipa-server/ipa-server.spec index 8c8df82e8..910f4627b 100755 --- a/ipa-server/ipa-server.spec +++ b/ipa-server/ipa-server.spec @@ -37,7 +37,6 @@ Requires: python-krbV Requires: TurboGears Requires: python-tgexpandingformwidget Requires: acl -Requires: freeradius Requires: pyasn1 Requires: libcap diff --git a/ipa-server/ipa-server.spec.in b/ipa-server/ipa-server.spec.in index 21f46556a..b0c13c06a 100644 --- a/ipa-server/ipa-server.spec.in +++ b/ipa-server/ipa-server.spec.in @@ -37,7 +37,6 @@ Requires: python-krbV Requires: TurboGears Requires: python-tgexpandingformwidget Requires: acl -Requires: freeradius Requires: pyasn1 Requires: libcap diff --git a/ipa-server/ipaserver/Makefile.am b/ipa-server/ipaserver/Makefile.am index f1c094b36..b1d00a80a 100644 --- a/ipa-server/ipaserver/Makefile.am +++ b/ipa-server/ipaserver/Makefile.am @@ -9,7 +9,6 @@ app_PYTHON = \ krbinstance.py \ httpinstance.py \ ntpinstance.py \ - radiusinstance.py \ webguiinstance.py \ service.py \ installutils.py \ diff --git a/ipa-server/ipaserver/radiusinstance.py b/ipa-server/ipaserver/radiusinstance.py deleted file mode 100644 index 4250b4bd1..000000000 --- a/ipa-server/ipaserver/radiusinstance.py +++ /dev/null @@ -1,171 +0,0 @@ -#! /usr/bin/python -E -# Authors: John Dennis -# -# 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 subprocess -import string -import tempfile -import shutil -import logging -import pwd -import time -import sys -from ipa.ipautil import * -from ipa import radius_util - -import service - -import os -import re - -IPA_RADIUS_VERSION = '0.0.0' - -# FIXME there should a utility to get the user base dn -from ipaserver.funcs import DefaultUserContainer, DefaultGroupContainer - -#------------------------------------------------------------------------------- - -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 get_radius_version(): - version = None - try: - p = subprocess.Popen([radius_util.RADIUSD, '-v'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = p.communicate() - status = p.returncode - - if status == 0: - match = re.search("radiusd: FreeRADIUS Version (.+), for host", stdout) - if match: - version = match.group(1) - except Exception, e: - pass - return version - - -#------------------------------------------------------------------------------- - -class RadiusInstance(service.Service): - def __init__(self): - service.Service.__init__(self, "radiusd") - self.fqdn = None - self.realm = None - self.principal = None - - def create_instance(self, realm_name, host_name, ldap_server): - self.realm = realm_name.upper() - self.suffix = realm_to_suffix(self.realm) - self.fqdn = host_name - self.ldap_server = ldap_server - self.principal = "%s/%s@%s" % (radius_util.RADIUS_SERVICE_NAME, self.fqdn, self.realm) - self.basedn = self.suffix - self.user_basedn = "%s,%s" % (DefaultUserContainer, self.basedn) # FIXME, should be utility to get this - self.radius_version = get_radius_version() - self.start_creation(4, "Configuring radiusd") - - try: - self.stop() - except: - # It could have been not running - pass - - self.__create_radius_keytab() - self.__radiusd_conf() - - try: - self.step("starting radiusd") - self.start() - except: - logging.error("radiusd service failed to start") - - self.step("configuring radiusd to start on boot") - self.chkconfig_on() - - - def __radiusd_conf(self): - self.step('configuring radiusd.conf for radius instance') - - version = 'IPA_RADIUS_VERSION=%s FREE_RADIUS_VERSION=%s' % (IPA_RADIUS_VERSION, self.radius_version) - sub_dict = {'CONFIG_FILE_VERSION_INFO' : version, - 'LDAP_SERVER' : self.ldap_server, - 'RADIUS_KEYTAB' : radius_util.RADIUS_IPA_KEYTAB_FILEPATH, - 'RADIUS_PRINCIPAL' : self.principal, - 'RADIUS_USER_BASE_DN' : self.user_basedn, - 'ACCESS_ATTRIBUTE' : '', - 'ACCESS_ATTRIBUTE_DEFAULT' : 'TRUE', - 'CLIENTS_BASEDN' : radius_util.radius_clients_basedn(None, self.suffix), - 'SUFFIX' : self.suffix, - } - try: - radiusd_conf = template_file(radius_util.RADIUSD_CONF_TEMPLATE_FILEPATH, sub_dict) - radiusd_fd = open(radius_util.RADIUSD_CONF_FILEPATH, 'w+') - radiusd_fd.write(radiusd_conf) - radiusd_fd.close() - except Exception, e: - logging.error("could not create %s: %s", radius_util.RADIUSD_CONF_FILEPATH, e) - - def __create_radius_keytab(self): - self.step("creating a keytab for radiusd") - try: - if file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): - os.remove(radius_util.RADIUS_IPA_KEYTAB_FILEPATH) - except os.error: - logging.error("Failed to remove %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH) - - (kwrite, kread, kerr) = os.popen3("/usr/kerberos/sbin/kadmin.local") - kwrite.write("addprinc -randkey %s\n" % (self.principal)) - kwrite.flush() - kwrite.write("ktadd -k %s %s\n" % (radius_util.RADIUS_IPA_KEYTAB_FILEPATH, self.principal)) - kwrite.flush() - kwrite.close() - kread.close() - kerr.close() - - # give kadmin time to actually write the file before we go on - retry = 0 - while not file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): - time.sleep(1) - retry += 1 - if retry > 15: - print "Error timed out waiting for kadmin to finish operations\n" - sys.exit(1) - try: - pent = pwd.getpwnam(radius_util.RADIUS_USER) - os.chown(radius_util.RADIUS_IPA_KEYTAB_FILEPATH, pent.pw_uid, pent.pw_gid) - except Exception, e: - logging.error("could not chown on %s to %s: %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH, radius_util.RADIUS_USER, e) - - #FIXME, should use IPAdmin method - def __set_ldap_encrypted_attributes(self): - ldif_file = 'encrypted_attribute.ldif' - self.step("setting ldap encrypted attributes") - ldif_txt = template_file(SHARE_DIR + ldif_file, {'ENCRYPTED_ATTRIBUTE':'radiusClientSecret'}) - ldif_fd = write_tmp_file(ldif_txt) - try: - ldap_mod(ldif_fd, "cn=Directory Manager", self.dm_password) - except subprocess.CalledProcessError, e: - logging.critical("Failed to load %s: %s" % (ldif_file, str(e))) - ldif_fd.close() - -#------------------------------------------------------------------------------- - -- cgit From d76886ff4f481370b6e5f2a5c337992078f872b1 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 11 Dec 2007 21:56:36 -0500 Subject: - Better access control, make sure not even admins can read out passwords - Insure admins can't locked out by mistake by inclusion in disabled groups - Fix also minor error in krbinstance.py --- .../ipa-install/share/bootstrap-template.ldif | 2 ++ ipa-server/ipa-install/share/default-aci.ldif | 23 +++++++++++++--------- ipa-server/ipaserver/krbinstance.py | 8 ++++---- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/ipa-server/ipa-install/share/bootstrap-template.ldif b/ipa-server/ipa-install/share/bootstrap-template.ldif index 9642070c7..d29b5d1b3 100644 --- a/ipa-server/ipa-install/share/bootstrap-template.ldif +++ b/ipa-server/ipa-install/share/bootstrap-template.ldif @@ -80,6 +80,7 @@ gidNumber: 1001 homeDirectory: /home/admin loginShell: /bin/bash gecos: Administrator +nsAccountLock: False dn: cn=radius,$SUFFIX changetype: add @@ -114,6 +115,7 @@ cn: admins description: Account administrators group gidNumber: 1001 member: uid=admin,cn=sysaccounts,cn=etc,$SUFFIX +nsAccountLock: False dn: cn=ipausers,cn=groups,cn=accounts,$SUFFIX changetype: add diff --git a/ipa-server/ipa-install/share/default-aci.ldif b/ipa-server/ipa-install/share/default-aci.ldif index 95743eebb..422fe16e9 100644 --- a/ipa-server/ipa-install/share/default-aci.ldif +++ b/ipa-server/ipa-install/share/default-aci.ldif @@ -1,18 +1,18 @@ # $SUFFIX (base entry) -# FIXME: We need to allow truly anonymous access only to NIS data for older clients. We need to allow broad access to most attributes only to authewnticated users +# FIXME: We need to allow truly anonymous access only to NIS data for older clients. We need to allow broad access to most attributes only to authenticated users dn: $SUFFIX changetype: modify replace: aci -aci: (targetattr != "userPassword || krbPrincipalKey || krbMKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Enable anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";) -aci: (targetattr != "userPassword || krbPrincipalKey || krbMKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Admin can manage any entry except for passwords"; allow (all) userdn = "ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX";) -aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Admin can write passwords"; allow (write) userdn="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX";) -aci: (targetattr = "krbPrincipalName || krbUPEnabled || krbPrincipalKey || krbMKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData")(version 3.0; acl "KDC System Account has access to kerberos material"; allow (read, search, compare) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) -aci: (targetattr = "krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "KDC System Account can update some fields"; allow (read, search, compare, write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) -aci: (targetattr = "userPassword || krbPrincipalKey ||sambaLMPassword || sambaNTPassword || krbPasswordExpiration || krbPwdHistory || krbLastPwdChange")(version 3.0; acl "Kpasswd access to passowrd hashes for passowrd changes"; allow (read, write) userdn = "ldap:///krbprincipalname=kadmin/changepw@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";) -aci: (targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup)(objectClass=radiusprofile))")(targetattr != "aci")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) +aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMkey")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";) +aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMkey")(version 3.0; acl "Admin can manage any entry"; allow (all) userdn = "ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX";) +aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Admins can write passwords"; allow (write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) +aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Password change service can read/write passwords"; allow (read, write) userdn="ldap:///krbprincipalname=kadmin/changepw@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";) +aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "KDC System Account can access passwords"; allow (all) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) +aci: (targetattr = "krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "KDC System Account can update some fields"; allow (write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) +aci: (targetattr = "krbPrincipalName || krbUPEnabled || krbMKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "Only the KDC System Account has access to kerberos material"; allow (read, search, compare) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) +aci: (targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup)(objectClass=radiusprofile))")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) aci: (targetfilter = "(objectClass=krbPwdPolicy)")(targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policies"; allow (read, search, compare, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) aci: (targetattr = "givenName || sn || cn || displayName || initials || loginShell || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";) -aci: (target="ldap:///cn=radius,$SUFFIX")(version 3.0; acl "Only radius and admin can access radius service data"; deny (all) userdn!="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX || ldap:///krbprincipalname=radius/$FQDN@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";) dn: cn=ipaConfig,cn=etc,$SUFFIX changetype: modify @@ -25,6 +25,11 @@ add: aci aci: (targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policy"; allow (write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) aci: (targetattr = "aci")(version 3.0;acl "Admins can manage delegations"; allow (write, delete) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) +dn: cn=radius,$SUFFIX +changetype: modify +add: aci +aci: (targetattr = "*")(version 3.0; acl "Only radius and admin can access radius service data"; deny (all) userdn!="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX || ldap:///krbprincipalname=radius/$FQDN@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";) + dn: cn=services,cn=accounts,$SUFFIX changetype: modify add: aci diff --git a/ipa-server/ipaserver/krbinstance.py b/ipa-server/ipaserver/krbinstance.py index 76818af7d..1376cb0c3 100644 --- a/ipa-server/ipaserver/krbinstance.py +++ b/ipa-server/ipaserver/krbinstance.py @@ -245,7 +245,7 @@ class KrbInstance(service.Service): kerberos_fd = write_tmp_file(kerberos_txt) try: ldap_mod(kerberos_fd, "cn=Directory Manager", self.admin_password) - except ipautil.CalledProcessError, e: + except CalledProcessError, e: logging.critical("Failed to load kerberos.ldif: %s" % str(e)) kerberos_fd.close() @@ -254,7 +254,7 @@ class KrbInstance(service.Service): aci_fd = write_tmp_file(aci_txt) try: ldap_mod(aci_fd, "cn=Directory Manager", self.admin_password) - except ipautil.CalledProcessError, e: + except CalledProcessError, e: logging.critical("Failed to load default-aci.ldif: %s" % str(e)) aci_fd.close() @@ -291,7 +291,7 @@ class KrbInstance(service.Service): args = ["/usr/kerberos/sbin/kdb5_ldap_util", "-D", "uid=kdc,cn=sysaccounts,cn=etc,"+self.suffix, "-w", self.kdc_password, "create", "-s", "-P", self.master_password, "-r", self.realm, "-subtrees", self.suffix, "-sscope", "sub"] try: run(args) - except ipautil.CalledProcessError, e: + except CalledProcessError, e: print "Failed to populate the realm structure in kerberos", e def __write_stash_from_ds(self): @@ -322,7 +322,7 @@ class KrbInstance(service.Service): extop_fd = write_tmp_file(extop_txt) try: ldap_mod(extop_fd, "cn=Directory Manager", self.admin_password) - except ipautil.CalledProcessError, e: + except CalledProcessError, e: logging.critical("Failed to load pwd-extop-conf.ldif: %s" % str(e)) extop_fd.close() -- cgit From 88c0c7f321fc1861f8c0cfb54a15eb6c51445a25 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 12 Dec 2007 13:15:56 -0500 Subject: from ipa.ipautil import * --> from ipa import ipautil --- ipa-server/ipaserver/krbinstance.py | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/ipa-server/ipaserver/krbinstance.py b/ipa-server/ipaserver/krbinstance.py index 1376cb0c3..c5ecbb892 100644 --- a/ipa-server/ipaserver/krbinstance.py +++ b/ipa-server/ipaserver/krbinstance.py @@ -33,6 +33,7 @@ import time import shutil import service +from ipa import ipautil from ipa import ipaerror import ipaldap @@ -46,7 +47,6 @@ import pyasn1.codec.ber.encoder import pyasn1.codec.ber.decoder import struct import base64 -from ipa.ipautil import * def host_to_domain(fqdn): s = fqdn.split(".") @@ -54,7 +54,7 @@ def host_to_domain(fqdn): 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) + ipautil.run(args) def update_key_val_in_file(filename, key, val): if os.path.exists(filename): @@ -89,8 +89,8 @@ class KrbInstance(service.Service): self.host = host_name.split(".")[0] self.ip = socket.gethostbyname(host_name) self.domain = host_to_domain(host_name) - self.suffix = realm_to_suffix(self.realm) - self.kdc_password = ipa_generate_password() + self.suffix = ipautil.realm_to_suffix(self.realm) + self.kdc_password = ipautil.ipa_generate_password() self.admin_password = admin_password self.__setup_sub_dict() @@ -241,47 +241,47 @@ class KrbInstance(service.Service): self.step("adding kerberos entries to the DS") #TODO: test that the ldif is ok with any random charcter we may use in the password - kerberos_txt = template_file(SHARE_DIR + "kerberos.ldif", self.sub_dict) - kerberos_fd = write_tmp_file(kerberos_txt) + kerberos_txt = ipautil.template_file(ipautil.SHARE_DIR + "kerberos.ldif", self.sub_dict) + kerberos_fd = ipautil.write_tmp_file(kerberos_txt) try: ldap_mod(kerberos_fd, "cn=Directory Manager", self.admin_password) - except CalledProcessError, e: + except ipautil.CalledProcessError, e: logging.critical("Failed to load kerberos.ldif: %s" % str(e)) kerberos_fd.close() #Change the default ACL to avoid anonimous access to kerberos keys and othe hashes - aci_txt = template_file(SHARE_DIR + "default-aci.ldif", self.sub_dict) - aci_fd = write_tmp_file(aci_txt) + aci_txt = ipautil.template_file(ipautil.SHARE_DIR + "default-aci.ldif", self.sub_dict) + aci_fd = ipautil.write_tmp_file(aci_txt) try: ldap_mod(aci_fd, "cn=Directory Manager", self.admin_password) - except CalledProcessError, e: + except ipautil.CalledProcessError, e: logging.critical("Failed to load default-aci.ldif: %s" % str(e)) aci_fd.close() def __create_instance(self, replica=False): self.step("configuring KDC") - kdc_conf = template_file(SHARE_DIR+"kdc.conf.template", self.sub_dict) + kdc_conf = ipautil.template_file(ipautil.SHARE_DIR+"kdc.conf.template", self.sub_dict) kdc_fd = open("/var/kerberos/krb5kdc/kdc.conf", "w+") kdc_fd.write(kdc_conf) kdc_fd.close() - krb5_conf = template_file(SHARE_DIR+"krb5.conf.template", self.sub_dict) + krb5_conf = ipautil.template_file(ipautil.SHARE_DIR+"krb5.conf.template", self.sub_dict) krb5_fd = open("/etc/krb5.conf", "w+") krb5_fd.write(krb5_conf) krb5_fd.close() # Windows configuration files - krb5_ini = template_file(SHARE_DIR+"krb5.ini.template", self.sub_dict) + krb5_ini = ipautil.template_file(ipautil.SHARE_DIR+"krb5.ini.template", self.sub_dict) krb5_fd = open("/usr/share/ipa/html/krb5.ini", "w+") krb5_fd.write(krb5_ini) krb5_fd.close() - krb_con = template_file(SHARE_DIR+"krb.con.template", self.sub_dict) + krb_con = ipautil.template_file(ipautil.SHARE_DIR+"krb.con.template", self.sub_dict) krb_fd = open("/usr/share/ipa/html/krb.con", "w+") krb_fd.write(krb_con) krb_fd.close() - krb_realm = template_file(SHARE_DIR+"krbrealm.con.template", self.sub_dict) + krb_realm = ipautil.template_file(ipautil.SHARE_DIR+"krbrealm.con.template", self.sub_dict) krb_fd = open("/usr/share/ipa/html/krbrealm.con", "w+") krb_fd.write(krb_realm) krb_fd.close() @@ -290,8 +290,8 @@ class KrbInstance(service.Service): #populate the directory with the realm structure args = ["/usr/kerberos/sbin/kdb5_ldap_util", "-D", "uid=kdc,cn=sysaccounts,cn=etc,"+self.suffix, "-w", self.kdc_password, "create", "-s", "-P", self.master_password, "-r", self.realm, "-subtrees", self.suffix, "-sscope", "sub"] try: - run(args) - except CalledProcessError, e: + ipautil.run(args) + except ipautil.CalledProcessError, e: print "Failed to populate the realm structure in kerberos", e def __write_stash_from_ds(self): @@ -318,11 +318,11 @@ class KrbInstance(service.Service): #add the password extop module def __add_pwd_extop_module(self): self.step("adding the password extenstion to the directory") - extop_txt = template_file(SHARE_DIR + "pwd-extop-conf.ldif", self.sub_dict) - extop_fd = write_tmp_file(extop_txt) + extop_txt = ipautil.template_file(ipautil.SHARE_DIR + "pwd-extop-conf.ldif", self.sub_dict) + extop_fd = ipautil.write_tmp_file(extop_txt) try: ldap_mod(extop_fd, "cn=Directory Manager", self.admin_password) - except CalledProcessError, e: + except ipautil.CalledProcessError, e: logging.critical("Failed to load pwd-extop-conf.ldif: %s" % str(e)) extop_fd.close() @@ -355,7 +355,7 @@ class KrbInstance(service.Service): def __create_ds_keytab(self): self.step("creating a keytab for the directory") try: - if file_exists("/etc/dirsrv/ds.keytab"): + if ipautil.file_exists("/etc/dirsrv/ds.keytab"): os.remove("/etc/dirsrv/ds.keytab") except os.error: logging.critical("Failed to remove /etc/dirsrv/ds.keytab.") @@ -370,7 +370,7 @@ class KrbInstance(service.Service): # give kadmin time to actually write the file before we go on retry = 0 - while not file_exists("/etc/dirsrv/ds.keytab"): + while not ipautil.file_exists("/etc/dirsrv/ds.keytab"): time.sleep(1) retry += 1 if retry > 15: @@ -384,7 +384,7 @@ class KrbInstance(service.Service): def __export_kadmin_changepw_keytab(self): self.step("exporting the kadmin keytab") try: - if file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"): + if ipautil.file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"): os.remove("/var/kerberos/krb5kdc/kpasswd.keytab") except os.error: logging.critical("Failed to remove /var/kerberos/krb5kdc/kpasswd.keytab.") @@ -404,7 +404,7 @@ class KrbInstance(service.Service): # give kadmin time to actually write the file before we go on retry = 0 - while not file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"): + while not ipautil.file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"): time.sleep(1) retry += 1 if retry > 15: -- cgit From 913201a9192c106829df55d89c29df03e68f07ec Mon Sep 17 00:00:00 2001 From: Karl MacMillan Date: Wed, 12 Dec 2007 18:18:26 -0500 Subject: Fix spec file to grab certinstall. --- ipa-server/ipa-server.spec | 1 + ipa-server/ipa-server.spec.in | 1 + 2 files changed, 2 insertions(+) diff --git a/ipa-server/ipa-server.spec b/ipa-server/ipa-server.spec index 910f4627b..38725cf34 100755 --- a/ipa-server/ipa-server.spec +++ b/ipa-server/ipa-server.spec @@ -93,6 +93,7 @@ fi %{_sbindir}/ipa-server-install %{_sbindir}/ipa-replica-install %{_sbindir}/ipa-replica-prepare +%{_sbindir}/ipa-server-certinstall %{_sbindir}/ipa_kpasswd %{_sbindir}/ipa-webgui %attr(4750,root,apache) %{_sbindir}/ipa-keytab-util diff --git a/ipa-server/ipa-server.spec.in b/ipa-server/ipa-server.spec.in index b0c13c06a..e43f07aa2 100644 --- a/ipa-server/ipa-server.spec.in +++ b/ipa-server/ipa-server.spec.in @@ -93,6 +93,7 @@ fi %{_sbindir}/ipa-server-install %{_sbindir}/ipa-replica-install %{_sbindir}/ipa-replica-prepare +%{_sbindir}/ipa-server-certinstall %{_sbindir}/ipa_kpasswd %{_sbindir}/ipa-webgui %attr(4750,root,apache) %{_sbindir}/ipa-keytab-util -- cgit From 87bc5c4d6394ce2b0f0a5e18bcff5721b34ebdc1 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 12 Dec 2007 13:58:55 -0500 Subject: Handle add/removing and stopping restarting daemons in update/remove --- ipa-server/ipa-server.spec | 19 +++++++++++++++++++ ipa-server/ipa-server.spec.in | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/ipa-server/ipa-server.spec b/ipa-server/ipa-server.spec index f84affe86..8c8df82e8 100755 --- a/ipa-server/ipa-server.spec +++ b/ipa-server/ipa-server.spec @@ -69,6 +69,25 @@ rm %{buildroot}/%{plugin_dir}/libipa-dna-plugin.la %clean rm -rf %{buildroot} +%post +if [ $1 = 1 ]; then + /sbin/chkconfig --add ipa-kpasswd + /sbin/chkconfig --add ipa-webgui +fi + +%preun +if [ $1 = 0 ]; then + /sbin/chkconfig --del ipa-kpasswd + /sbin/chkconfig --del ipa-webgui + /sbin/service ipa-kpasswd stop >/dev/null 2>&1 || : + /sbin/service ipa-webgui stop >/dev/null 2>&1 || : +fi + +%postun +if [ "$1" -ge "1" ]; then + /sbin/service ipa-kpasswd condrestart >/dev/null 2>&1 || : + /sbin/service ipa-webgui condrestart >/dev/null 2>&1 || : +fi %files %defattr(-,root,root,-) diff --git a/ipa-server/ipa-server.spec.in b/ipa-server/ipa-server.spec.in index 874d82cfd..21f46556a 100644 --- a/ipa-server/ipa-server.spec.in +++ b/ipa-server/ipa-server.spec.in @@ -69,6 +69,25 @@ rm %{buildroot}/%{plugin_dir}/libipa-dna-plugin.la %clean rm -rf %{buildroot} +%post +if [ $1 = 1 ]; then + /sbin/chkconfig --add ipa-kpasswd + /sbin/chkconfig --add ipa-webgui +fi + +%preun +if [ $1 = 0 ]; then + /sbin/chkconfig --del ipa-kpasswd + /sbin/chkconfig --del ipa-webgui + /sbin/service ipa-kpasswd stop >/dev/null 2>&1 || : + /sbin/service ipa-webgui stop >/dev/null 2>&1 || : +fi + +%postun +if [ "$1" -ge "1" ]; then + /sbin/service ipa-kpasswd condrestart >/dev/null 2>&1 || : + /sbin/service ipa-webgui condrestart >/dev/null 2>&1 || : +fi %files %defattr(-,root,root,-) -- cgit From cecbca1a84579c6aaf20ab7979aee1ae483f32c6 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 12 Dec 2007 14:16:52 -0500 Subject: Separate out ACIs that affect radius --- ipa-server/ipa-install/share/default-aci.ldif | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ipa-server/ipa-install/share/default-aci.ldif b/ipa-server/ipa-install/share/default-aci.ldif index 422fe16e9..ae8801ac5 100644 --- a/ipa-server/ipa-install/share/default-aci.ldif +++ b/ipa-server/ipa-install/share/default-aci.ldif @@ -10,7 +10,7 @@ aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaN aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "KDC System Account can access passwords"; allow (all) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) aci: (targetattr = "krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "KDC System Account can update some fields"; allow (write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) aci: (targetattr = "krbPrincipalName || krbUPEnabled || krbMKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "Only the KDC System Account has access to kerberos material"; allow (read, search, compare) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) -aci: (targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup)(objectClass=radiusprofile))")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) +aci: (targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup))")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) aci: (targetfilter = "(objectClass=krbPwdPolicy)")(targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policies"; allow (read, search, compare, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) aci: (targetattr = "givenName || sn || cn || displayName || initials || loginShell || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";) @@ -29,6 +29,7 @@ dn: cn=radius,$SUFFIX changetype: modify add: aci aci: (targetattr = "*")(version 3.0; acl "Only radius and admin can access radius service data"; deny (all) userdn!="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX || ldap:///krbprincipalname=radius/$FQDN@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";) +aci: (targetfilter = "(objectClass=radiusprofile)")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) dn: cn=services,cn=accounts,$SUFFIX changetype: modify -- cgit From c39d6d3be878e82fdb4bb4bd6a09aaed1d5fad12 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 12 Dec 2007 16:42:19 -0500 Subject: Merge in Rob aci patch (resolve conflict) --- ipa-server/ipa-install/share/default-aci.ldif | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipa-server/ipa-install/share/default-aci.ldif b/ipa-server/ipa-install/share/default-aci.ldif index ae8801ac5..5715259a1 100644 --- a/ipa-server/ipa-install/share/default-aci.ldif +++ b/ipa-server/ipa-install/share/default-aci.ldif @@ -12,7 +12,7 @@ aci: (targetattr = "krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailed aci: (targetattr = "krbPrincipalName || krbUPEnabled || krbMKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "Only the KDC System Account has access to kerberos material"; allow (read, search, compare) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) aci: (targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup))")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) aci: (targetfilter = "(objectClass=krbPwdPolicy)")(targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policies"; allow (read, search, compare, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) -aci: (targetattr = "givenName || sn || cn || displayName || initials || loginShell || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";) +aci: (targetattr = "givenName || sn || cn || displayName || title || initials || loginShell || gecos || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || secretary || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso || employeeType || businessCategory || ou")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";) dn: cn=ipaConfig,cn=etc,$SUFFIX changetype: modify -- 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(-) diff --git a/ipa-python/ipa-python.spec b/ipa-python/ipa-python.spec index 2837a2832..1c838821b 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 bd8ac0da6..9eb2e11c2 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 3a5a6f4eb..deb84f293 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 From a39f1cb2cba6eb934ba0601471d55ca180415402 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 13 Dec 2007 09:31:28 +0000 Subject: Fix ldif to work with ldapmodify in openldap-2.4.x It seems that in openldap-2.4.x ldapmodify has gotten somewhat more picky about the ldif it accepts. See here for more details: https://bugzilla.redhat.com/422251 Not sure whether ldapmodify will be fixed, but for now just fix the ldif. Signed-off-by: Mark McLoughlin --- ipa-server/ipa-install/share/bootstrap-template.ldif | 2 ++ ipa-server/ipa-install/share/referint-conf.ldif | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/ipa-server/ipa-install/share/bootstrap-template.ldif b/ipa-server/ipa-install/share/bootstrap-template.ldif index d29b5d1b3..0a969de38 100644 --- a/ipa-server/ipa-install/share/bootstrap-template.ldif +++ b/ipa-server/ipa-install/share/bootstrap-template.ldif @@ -2,6 +2,8 @@ dn: $SUFFIX changetype: modify add: objectClass objectClass: pilotObject +- +add: info info: IPA V1.0 dn: cn=accounts,$SUFFIX diff --git a/ipa-server/ipa-install/share/referint-conf.ldif b/ipa-server/ipa-install/share/referint-conf.ldif index 7a547ba50..533b97ded 100644 --- a/ipa-server/ipa-install/share/referint-conf.ldif +++ b/ipa-server/ipa-install/share/referint-conf.ldif @@ -2,6 +2,10 @@ dn: cn=referential integrity postoperation,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginenabled nsslapd-pluginenabled: on +- +add: nsslapd-pluginArg7 nsslapd-pluginArg7: manager +- +add: nsslapd-pluginArg8 nsslapd-pluginArg8: secretary -- cgit From 2a036abe7a601bbc8e65bbe4ab7c489b81db0eb5 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 13 Dec 2007 09:31:28 +0000 Subject: More ipautil fixing Recently, dsinstance and krbinstance was fixed to not import * from ipautil; do the same for the rest of ipaserver. Signed-off-by: Mark McLoughlin --- ipa-radius-server/plugins/radiusinstance.py | 18 +++++++++--------- ipa-server/ipaserver/bindinstance.py | 22 ++++++++-------------- ipa-server/ipaserver/httpinstance.py | 16 +++++++++------- ipa-server/ipaserver/ntpinstance.py | 8 ++++---- ipa-server/ipaserver/service.py | 12 ++++++------ ipa-server/ipaserver/webguiinstance.py | 3 --- 6 files changed, 36 insertions(+), 43 deletions(-) diff --git a/ipa-radius-server/plugins/radiusinstance.py b/ipa-radius-server/plugins/radiusinstance.py index 743a1d8a2..a330621d1 100644 --- a/ipa-radius-server/plugins/radiusinstance.py +++ b/ipa-radius-server/plugins/radiusinstance.py @@ -29,7 +29,7 @@ import logging import pwd import time import sys -from ipa.ipautil import * +from ipa import ipautil from ipa import radius_util from ipaserver import service @@ -46,7 +46,7 @@ from ipaserver.funcs import DefaultUserContainer, DefaultGroupContainer 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) + ipautil.run(args) def get_radius_version(): version = None @@ -76,7 +76,7 @@ class RadiusInstance(service.Service): def create_instance(self, realm_name, host_name, ldap_server): self.realm = realm_name.upper() - self.suffix = realm_to_suffix(self.realm) + self.suffix = ipautil.realm_to_suffix(self.realm) self.fqdn = host_name self.ldap_server = ldap_server self.principal = "%s/%s@%s" % (radius_util.RADIUS_SERVICE_NAME, self.fqdn, self.realm) @@ -119,7 +119,7 @@ class RadiusInstance(service.Service): 'SUFFIX' : self.suffix, } try: - radiusd_conf = template_file(radius_util.RADIUSD_CONF_TEMPLATE_FILEPATH, sub_dict) + radiusd_conf = ipautil.template_file(radius_util.RADIUSD_CONF_TEMPLATE_FILEPATH, sub_dict) radiusd_fd = open(radius_util.RADIUSD_CONF_FILEPATH, 'w+') radiusd_fd.write(radiusd_conf) radiusd_fd.close() @@ -129,7 +129,7 @@ class RadiusInstance(service.Service): def __create_radius_keytab(self): self.step("creating a keytab for radiusd") try: - if file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): + if ipautil.file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): os.remove(radius_util.RADIUS_IPA_KEYTAB_FILEPATH) except os.error: logging.error("Failed to remove %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH) @@ -145,7 +145,7 @@ class RadiusInstance(service.Service): # give kadmin time to actually write the file before we go on retry = 0 - while not file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): + while not ipautil.file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): time.sleep(1) retry += 1 if retry > 15: @@ -161,11 +161,11 @@ class RadiusInstance(service.Service): def __set_ldap_encrypted_attributes(self): ldif_file = 'encrypted_attribute.ldif' self.step("setting ldap encrypted attributes") - ldif_txt = template_file(SHARE_DIR + ldif_file, {'ENCRYPTED_ATTRIBUTE':'radiusClientSecret'}) - ldif_fd = write_tmp_file(ldif_txt) + ldif_txt = ipautil.template_file(ipautil.SHARE_DIR + ldif_file, {'ENCRYPTED_ATTRIBUTE':'radiusClientSecret'}) + ldif_fd = ipautil.write_tmp_file(ldif_txt) try: ldap_mod(ldif_fd, "cn=Directory Manager", self.dm_password) - except subprocess.CalledProcessError, e: + except ipautil.CalledProcessError, e: logging.critical("Failed to load %s: %s" % (ldif_file, str(e))) ldif_fd.close() diff --git a/ipa-server/ipaserver/bindinstance.py b/ipa-server/ipaserver/bindinstance.py index 8a131fe79..cc99eacfa 100644 --- a/ipa-server/ipaserver/bindinstance.py +++ b/ipa-server/ipaserver/bindinstance.py @@ -23,10 +23,13 @@ import tempfile import shutil import os import socket -from ipa.ipautil import * -class BindInstance: +import service +from ipa import ipautil + +class BindInstance(service.Service): def __init__(self): + service.Service.__init__(self, "named") self.fqdn = None self.domain = None self.host = None @@ -52,7 +55,7 @@ class BindInstance: return True def create_sample_bind_zone(self): - bind_txt = template_file(SHARE_DIR + "bind.zone.db.template", self.sub_dict) + bind_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.zone.db.template", self.sub_dict) [bind_fd, bind_name] = tempfile.mkstemp(".db","sample.zone.") os.write(bind_fd, bind_txt) os.close(bind_fd) @@ -73,15 +76,6 @@ class BindInstance: except: print "named service failed to start" - def stop(self): - run(["/sbin/service", "named", "stop"]) - - def start(self): - run(["/sbin/service", "named", "start"]) - - def restart(self): - run(["/sbin/service", "named", "restart"]) - def __setup_sub_dict(self): self.sub_dict = dict(FQDN=self.fqdn, IP=self.ip_address, @@ -90,7 +84,7 @@ class BindInstance: REALM=self.realm) def __setup_zone(self): - zone_txt = template_file(SHARE_DIR + "bind.zone.db.template", self.sub_dict) + zone_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.zone.db.template", self.sub_dict) zone_fd = open('/var/named/'+self.domain+'.zone.db', 'w') zone_fd.write(zone_txt) zone_fd.close() @@ -98,7 +92,7 @@ class BindInstance: def __setup_named_conf(self): if os.path.exists('/etc/named.conf'): shutil.copy2('/etc/named.conf', '/etc/named.conf.ipabkp') - named_txt = template_file(SHARE_DIR + "bind.named.conf.template", self.sub_dict) + named_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.named.conf.template", self.sub_dict) named_fd = open('/etc/named.conf', 'w') named_fd.seek(0) named_fd.truncate(0) diff --git a/ipa-server/ipaserver/httpinstance.py b/ipa-server/ipaserver/httpinstance.py index a131faedc..8a7c527af 100644 --- a/ipa-server/ipaserver/httpinstance.py +++ b/ipa-server/ipaserver/httpinstance.py @@ -17,6 +17,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # +import os +import os.path import subprocess import string import tempfile @@ -31,7 +33,7 @@ import service import certs import dsinstance import installutils -from ipa.ipautil import * +from ipa import ipautil HTTPD_DIR = "/etc/httpd" SSL_CONF = HTTPD_DIR + "/conf.d/ssl.conf" @@ -77,7 +79,7 @@ class HTTPInstance(service.Service): selinux=0 try: if (os.path.exists('/usr/sbin/selinuxenabled')): - run(["/usr/sbin/selinuxenabled"]) + ipautil.run(["/usr/sbin/selinuxenabled"]) selinux=1 except ipautil.CalledProcessError: # selinuxenabled returns 1 if not enabled @@ -87,14 +89,14 @@ class HTTPInstance(service.Service): # Allow apache to connect to the turbogears web gui # This can still fail even if selinux is enabled try: - run(["/usr/sbin/setsebool", "-P", "httpd_can_network_connect", "true"]) + ipautil.run(["/usr/sbin/setsebool", "-P", "httpd_can_network_connect", "true"]) except: self.print_msg(selinux_warning) def __create_http_keytab(self): self.step("creating a keytab for httpd") try: - if file_exists("/etc/httpd/conf/ipa.keytab"): + if ipautil.file_exists("/etc/httpd/conf/ipa.keytab"): os.remove("/etc/httpd/conf/ipa.keytab") except os.error: print "Failed to remove /etc/httpd/conf/ipa.keytab." @@ -109,7 +111,7 @@ class HTTPInstance(service.Service): # give kadmin time to actually write the file before we go on retry = 0 - while not file_exists("/etc/httpd/conf/ipa.keytab"): + while not ipautil.file_exists("/etc/httpd/conf/ipa.keytab"): time.sleep(1) retry += 1 if retry > 15: @@ -121,7 +123,7 @@ class HTTPInstance(service.Service): def __configure_http(self): self.step("configuring httpd") - http_txt = template_file(SHARE_DIR + "ipa.conf", self.sub_dict) + http_txt = ipautil.template_file(ipautil.SHARE_DIR + "ipa.conf", self.sub_dict) http_fd = open("/etc/httpd/conf.d/ipa.conf", "w") http_fd.write(http_txt) http_fd.close() @@ -147,7 +149,7 @@ class HTTPInstance(service.Service): ca.create_signing_cert("Signing-Cert", "cn=%s,ou=Signing Certificate,o=Identity Policy Audit" % self.fqdn, ds_ca) def __setup_autoconfig(self): - prefs_txt = template_file(SHARE_DIR + "preferences.html.template", self.sub_dict) + prefs_txt = ipautil.template_file(ipautil.SHARE_DIR + "preferences.html.template", self.sub_dict) prefs_fd = open("/usr/share/ipa/html/preferences.html", "w") prefs_fd.write(prefs_txt) prefs_fd.close() diff --git a/ipa-server/ipaserver/ntpinstance.py b/ipa-server/ipaserver/ntpinstance.py index 46841b0b2..3872d93c6 100644 --- a/ipa-server/ipaserver/ntpinstance.py +++ b/ipa-server/ipaserver/ntpinstance.py @@ -17,10 +17,10 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -from ipa.ipautil import * import shutil import service +from ipa import ipautil class NTPInstance(service.Service): def __init__(self): @@ -36,9 +36,9 @@ class NTPInstance(service.Service): # or fedora pools. Other distros should be added in the future # or we can get our own pool. os = "" - if file_exists("/etc/fedora-release"): + if ipautil.file_exists("/etc/fedora-release"): os = "fedora." - elif file_exists("/etc/redhat-release"): + elif ipautil.file_exists("/etc/redhat-release"): os = "rhel." sub_dict = { } @@ -46,7 +46,7 @@ class NTPInstance(service.Service): sub_dict["SERVERB"] = "1.%spool.ntp.org" % os sub_dict["SERVERC"] = "2.%spool.ntp.org" % os - ntp_conf = template_file(SHARE_DIR + "ntp.conf.server.template", sub_dict) + ntp_conf = ipautil.template_file(ipautil.SHARE_DIR + "ntp.conf.server.template", sub_dict) shutil.copy("/etc/ntp.conf", "/etc/ntp.conf.ipasave") diff --git a/ipa-server/ipaserver/service.py b/ipa-server/ipaserver/service.py index f0109488d..4b2799702 100644 --- a/ipa-server/ipaserver/service.py +++ b/ipa-server/ipaserver/service.py @@ -17,24 +17,24 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -from ipa.ipautil import * import logging, sys +from ipa import ipautil def stop(service_name): - run(["/sbin/service", service_name, "stop"]) + ipautil.run(["/sbin/service", service_name, "stop"]) def start(service_name): - run(["/sbin/service", service_name, "start"]) + ipautil.run(["/sbin/service", service_name, "start"]) def restart(service_name): - run(["/sbin/service", service_name, "restart"]) + ipautil.run(["/sbin/service", service_name, "restart"]) def chkconfig_on(service_name): - run(["/sbin/chkconfig", service_name, "on"]) + ipautil.run(["/sbin/chkconfig", service_name, "on"]) def chkconfig_off(service_name): - run(["/sbin/chkconfig", service_name, "off"]) + ipautil.run(["/sbin/chkconfig", service_name, "off"]) def print_msg(message, output_fd=sys.stdout): logging.debug(message) diff --git a/ipa-server/ipaserver/webguiinstance.py b/ipa-server/ipaserver/webguiinstance.py index 757b50c5d..2d41f30fb 100644 --- a/ipa-server/ipaserver/webguiinstance.py +++ b/ipa-server/ipaserver/webguiinstance.py @@ -17,9 +17,6 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -import logging - -from ipa.ipautil import * import service class WebGuiInstance(service.Service): -- cgit From 7ba901d7774d914e1fc4aa06855f3f9f7ae6a7c4 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 13 Dec 2007 09:31:28 +0000 Subject: Only update key/value files if necessary update_key_val_in_file() shouldn't try and write to a file if the key is already set to the given value in the file Rationale here is that if we write these files out while building a system image, ipa-server-install shouldn't need to re-write them and, therefore, they don't need to be writable. Signed-off-by: Mark McLoughlin --- ipa-server/ipaserver/krbinstance.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ipa-server/ipaserver/krbinstance.py b/ipa-server/ipaserver/krbinstance.py index c5ecbb892..5705a1ef3 100644 --- a/ipa-server/ipaserver/krbinstance.py +++ b/ipa-server/ipaserver/krbinstance.py @@ -58,6 +58,14 @@ def ldap_mod(fd, dn, pwd): def update_key_val_in_file(filename, key, val): if os.path.exists(filename): + pattern = "^[\s#]*%s\s*=\s*%s\s*" % (re.escape(key), re.escape(val)) + p = re.compile(pattern) + for line in fileinput.input(filename): + if p.search(line): + fileinput.close() + return + fileinput.close() + pattern = "^[\s#]*%s\s*=" % re.escape(key) p = re.compile(pattern) for line in fileinput.input(filename, inplace=1): -- cgit From 065827d6e135686c81194280cba442ca696cba9d Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 13 Dec 2007 09:31:28 +0000 Subject: Refactor dsinstance ldap modify code Just a patch to refactor lots of similar code in dsinstance and krbinstance using a simple helper method. Note, there are some differences: - Some code used to call ldapmodify without -h 127.0.0.1 - Some of the code used to just print an error rather than using logging.critical() - Some code used to log some extra debug Signed-off-by: Mark McLoughlin --- ipa-radius-server/plugins/radiusinstance.py | 31 +++++---- ipa-server/ipaserver/dsinstance.py | 97 +++++++---------------------- ipa-server/ipaserver/krbinstance.py | 50 ++++++--------- 3 files changed, 61 insertions(+), 117 deletions(-) diff --git a/ipa-radius-server/plugins/radiusinstance.py b/ipa-radius-server/plugins/radiusinstance.py index a330621d1..2d68adf7e 100644 --- a/ipa-radius-server/plugins/radiusinstance.py +++ b/ipa-radius-server/plugins/radiusinstance.py @@ -44,10 +44,6 @@ from ipaserver.funcs import DefaultUserContainer, DefaultGroupContainer #------------------------------------------------------------------------------- -def ldap_mod(fd, dn, pwd): - args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", "-D", dn, "-w", pwd, "-f", fd.name] - ipautil.run(args) - def get_radius_version(): version = None try: @@ -157,17 +153,26 @@ class RadiusInstance(service.Service): except Exception, e: logging.error("could not chown on %s to %s: %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH, radius_util.RADIUS_USER, e) - #FIXME, should use IPAdmin method - def __set_ldap_encrypted_attributes(self): - ldif_file = 'encrypted_attribute.ldif' - self.step("setting ldap encrypted attributes") - ldif_txt = ipautil.template_file(ipautil.SHARE_DIR + ldif_file, {'ENCRYPTED_ATTRIBUTE':'radiusClientSecret'}) - ldif_fd = ipautil.write_tmp_file(ldif_txt) + def __ldap_mod(self, step, ldif): + self.step(step) + + txt = iputil.template_file(ipautil.SHARE_DIR + ldif, self.sub_dict) + fd = ipautil.write_tmp_file(txt) + + args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", + "-D", "cn=Directory Manager", "-w", self.dm_password, "-f", fd.name] + try: - ldap_mod(ldif_fd, "cn=Directory Manager", self.dm_password) + ipautil.run(args) except ipautil.CalledProcessError, e: - logging.critical("Failed to load %s: %s" % (ldif_file, str(e))) - ldif_fd.close() + logging.critical("Failed to load %s: %s" % (ldif, str(e))) + + fd.close() + + #FIXME, should use IPAdmin method + def __set_ldap_encrypted_attributes(self): + self.__ldap_mod("setting ldap encrypted attributes", + "encrypted_attribute.ldif", {"ENCRYPTED_ATTRIBUTE" : "radiusClientSecret"}) #------------------------------------------------------------------------------- diff --git a/ipa-server/ipaserver/dsinstance.py b/ipa-server/ipaserver/dsinstance.py index 818710fb6..8a4a00314 100644 --- a/ipa-server/ipaserver/dsinstance.py +++ b/ipa-server/ipaserver/dsinstance.py @@ -35,10 +35,6 @@ import ipaldap, ldap SERVER_ROOT_64 = "/usr/lib64/dirsrv" SERVER_ROOT_32 = "/usr/lib/dirsrv" -def ldap_mod(fd, dn, pwd): - args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", "-D", dn, "-w", pwd, "-f", fd.name] - ipautil.run(args) - def realm_to_suffix(realm_name): s = realm_name.split(".") terms = ["dc=" + x.lower() for x in s] @@ -229,65 +225,39 @@ class DsInstance(service.Service): shutil.copyfile(ipautil.SHARE_DIR + "60ipaconfig.ldif", schema_dirname(self.realm_name) + "60ipaconfig.ldif") - def __add_memberof_module(self): - self.step("enabling memboerof plugin") - memberof_txt = ipautil.template_file(ipautil.SHARE_DIR + "memberof-conf.ldif", self.sub_dict) - memberof_fd = ipautil.write_tmp_file(memberof_txt) + def __ldap_mod(self, step, ldif): + self.step(step) + + txt = ipautil.template_file(ipautil.SHARE_DIR + ldif, self.sub_dict) + fd = ipautil.write_tmp_file(txt) + + args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", + "-D", "cn=Directory Manager", "-w", self.dm_password, "-f", fd.name] + try: - ldap_mod(memberof_fd, "cn=Directory Manager", self.dm_password) + ipautil.run(args) except ipautil.CalledProcessError, e: - logging.critical("Failed to load memberof-conf.ldif: %s" % str(e)) - memberof_fd.close() + logging.critical("Failed to load %s: %s" % (ldif, str(e))) + + fd.close() + + def __add_memberof_module(self): + self.__ldap_mod("enabling memberof plugin", "memberof-conf.ldif") def __init_memberof(self): - self.step("initializing group membership") - memberof_txt = ipautil.template_file(ipautil.SHARE_DIR + "memberof-task.ldif", self.sub_dict) - memberof_fd = ipautil.write_tmp_file(memberof_txt) - try: - ldap_mod(memberof_fd, "cn=Directory Manager", self.dm_password) - except ipautil.CalledProcessError, e: - logging.critical("Failed to load memberof-conf.ldif: %s" % str(e)) - memberof_fd.close() + self.__ldap_mod("initializing group membership", "memberof-task.ldif") def __add_referint_module(self): - self.step("enabling referential integrity plugin") - referint_txt = ipautil.template_file(ipautil.SHARE_DIR + "referint-conf.ldif", self.sub_dict) - referint_fd = ipautil.write_tmp_file(referint_txt) - try: - ldap_mod(referint_fd, "cn=Directory Manager", self.dm_password) - except ipautil.CalledProcessError, e: - print "Failed to load referint-conf.ldif", e - referint_fd.close() + self.__ldap_mod("enabling referential integrity plugin", "referint-conf.ldif") def __add_dna_module(self): - self.step("enabling distributed numeric assignment plugin") - dna_txt = ipautil.template_file(ipautil.SHARE_DIR + "dna-conf.ldif", self.sub_dict) - dna_fd = ipautil.write_tmp_file(dna_txt) - try: - ldap_mod(dna_fd, "cn=Directory Manager", self.dm_password) - except ipautil.CalledProcessError, e: - print "Failed to load dna-conf.ldif", e - dna_fd.close() + self.__ldap_mod("enabling distributed numeric assignment plugin", "dna-conf.ldif") def __config_uidgid_gen_first_master(self): - self.step("configuring Posix uid/gid generation as first master") - dna_txt = ipautil.template_file(ipautil.SHARE_DIR + "dna-posix.ldif", self.sub_dict) - dna_fd = ipautil.write_tmp_file(dna_txt) - try: - ldap_mod(dna_fd, "cn=Directory Manager", self.dm_password) - except ipautil.CalledProcessError, e: - print "Failed to configure Posix uid/gid generation with dna-posix.ldif", e - dna_fd.close() + self.__ldap_mod("configuring Posix uid/gid generation as first master", "dna-posix.ldif") def __add_master_entry_first_master(self): - self.step("adding master entry as first master") - master_txt = ipautil.template_file(ipautil.SHARE_DIR + "master-entry.ldif", self.sub_dict) - master_fd = ipautil.write_tmp_file(master_txt) - try: - ldap_mod(master_fd, "cn=Directory Manager", self.dm_password) - except ipautil.CalledProcessError, e: - print "Failed to add master-entry.ldif", e - master_fd.close() + self.__ldap_mod("adding master entry as first master", "master-entry.ldif") def __enable_ssl(self): self.step("configuring ssl for ds instance") @@ -324,31 +294,10 @@ class DsInstance(service.Service): conn.unbind() def __add_default_layout(self): - self.step("adding default layout") - txt = ipautil.template_file(ipautil.SHARE_DIR + "bootstrap-template.ldif", self.sub_dict) - inf_fd = ipautil.write_tmp_file(txt) - logging.debug("adding default dfrom ipa.ipautil import *s layout") - args = ["/usr/bin/ldapmodify", "-xv", "-D", "cn=Directory Manager", - "-w", self.dm_password, "-f", inf_fd.name] - try: - ipautil.run(args) - logging.debug("done adding default ds layout") - except ipautil.CalledProcessError, e: - print "Failed to add default ds layout", e - logging.critical("Failed to add default ds layout %s" % e) + self.__ldap_mod("adding default layout", "bootstrap-template.ldif") def __create_indeces(self): - self.step("creating indeces") - txt = ipautil.template_file(ipautil.SHARE_DIR + "indeces.ldif", self.sub_dict) - inf_fd = ipautil.write_tmp_file(txt) - logging.debug("adding/updating indeces") - args = ["/usr/bin/ldapmodify", "-xv", "-D", "cn=Directory Manager", - "-w", self.dm_password, "-f", inf_fd.name] - try: - ipautil.run(args) - logging.debug("done adding/updating indeces") - except ipautil.CalledProcessError, e: - logging.critical("Failed to add/update indeces %s" % str(e)) + self.__ldap_mod("creating indeces", "indeces.ldif") def __certmap_conf(self): self.step("configuring certmap.conf") diff --git a/ipa-server/ipaserver/krbinstance.py b/ipa-server/ipaserver/krbinstance.py index 5705a1ef3..67d3019e0 100644 --- a/ipa-server/ipaserver/krbinstance.py +++ b/ipa-server/ipaserver/krbinstance.py @@ -52,10 +52,6 @@ def host_to_domain(fqdn): s = fqdn.split(".") return ".".join(s[1:]) -def ldap_mod(fd, dn, pwd): - args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", "-D", dn, "-w", pwd, "-f", fd.name] - ipautil.run(args) - def update_key_val_in_file(filename, key, val): if os.path.exists(filename): pattern = "^[\s#]*%s\s*=\s*%s\s*" % (re.escape(key), re.escape(val)) @@ -139,7 +135,7 @@ class KrbInstance(service.Service): self.__common_setup(ds_user, realm_name, host_name, admin_password) - self.start_creation(11, "Configuring Kerberos KDC") + self.start_creation(12, "Configuring Kerberos KDC") self.__configure_kdc_account_password() self.__configure_sasl_mappings() @@ -195,6 +191,22 @@ class KrbInstance(service.Service): HOST=self.host, REALM=self.realm) + def __ldap_mod(self, step, ldif): + self.step(step) + + txt = ipautil.template_file(ipautil.SHARE_DIR + ldif, self.sub_dict) + fd = ipautil.write_tmp_file(txt) + + args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", + "-D", "cn=Directory Manager", "-w", self.admin_password, "-f", fd.name] + + try: + ipautil.run(args) + except ipautil.CalledProcessError, e: + logging.critical("Failed to load %s: %s" % (ldif, str(e))) + + fd.close() + def __configure_sasl_mappings(self): self.step("adding sasl mappings to the directory") # we need to remove any existing SASL mappings in the directory as otherwise they @@ -246,25 +258,10 @@ class KrbInstance(service.Service): raise e def __add_krb_entries(self): - self.step("adding kerberos entries to the DS") - - #TODO: test that the ldif is ok with any random charcter we may use in the password - kerberos_txt = ipautil.template_file(ipautil.SHARE_DIR + "kerberos.ldif", self.sub_dict) - kerberos_fd = ipautil.write_tmp_file(kerberos_txt) - try: - ldap_mod(kerberos_fd, "cn=Directory Manager", self.admin_password) - except ipautil.CalledProcessError, e: - logging.critical("Failed to load kerberos.ldif: %s" % str(e)) - kerberos_fd.close() + self.__ldap_mod("adding kerberos entries to the DS", "kerberos.ldif") #Change the default ACL to avoid anonimous access to kerberos keys and othe hashes - aci_txt = ipautil.template_file(ipautil.SHARE_DIR + "default-aci.ldif", self.sub_dict) - aci_fd = ipautil.write_tmp_file(aci_txt) - try: - ldap_mod(aci_fd, "cn=Directory Manager", self.admin_password) - except ipautil.CalledProcessError, e: - logging.critical("Failed to load default-aci.ldif: %s" % str(e)) - aci_fd.close() + self.__ldap_mod("adding defalt ACIs", "default-aci.ldif") def __create_instance(self, replica=False): self.step("configuring KDC") @@ -325,14 +322,7 @@ class KrbInstance(service.Service): #add the password extop module def __add_pwd_extop_module(self): - self.step("adding the password extenstion to the directory") - extop_txt = ipautil.template_file(ipautil.SHARE_DIR + "pwd-extop-conf.ldif", self.sub_dict) - extop_fd = ipautil.write_tmp_file(extop_txt) - try: - ldap_mod(extop_fd, "cn=Directory Manager", self.admin_password) - except ipautil.CalledProcessError, e: - logging.critical("Failed to load pwd-extop-conf.ldif: %s" % str(e)) - extop_fd.close() + self.__ldap_mod("adding the password extenstion to the directory", "pwd-extop-conf.ldif") #get the Master Key from the stash file try: -- cgit From c049d2d8218dc5c560f9692397af91cac2559edd Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 13 Dec 2007 09:31:28 +0000 Subject: Don't template files which don't contain variables The following files hav no template variables, so don't bother templating them: - memberof-conf.ldif - referint-conf.ldif - dna-conf.ldif - certmap.conf.template Signed-off-by: Mark McLoughlin --- ipa-server/ipaserver/dsinstance.py | 41 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/ipa-server/ipaserver/dsinstance.py b/ipa-server/ipaserver/dsinstance.py index 8a4a00314..b57ac1db3 100644 --- a/ipa-server/ipaserver/dsinstance.py +++ b/ipa-server/ipaserver/dsinstance.py @@ -225,39 +225,50 @@ class DsInstance(service.Service): shutil.copyfile(ipautil.SHARE_DIR + "60ipaconfig.ldif", schema_dirname(self.realm_name) + "60ipaconfig.ldif") - def __ldap_mod(self, step, ldif): + def __ldap_mod(self, step, ldif, sub_dict = None): self.step(step) - txt = ipautil.template_file(ipautil.SHARE_DIR + ldif, self.sub_dict) - fd = ipautil.write_tmp_file(txt) + fd = None + path = ipautil.SHARE_DIR + ldif + + if not sub_dict is None: + txt = ipautil.template_file(path, sub_dict) + fd = ipautil.write_tmp_file(txt) + path = fd.name args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", - "-D", "cn=Directory Manager", "-w", self.dm_password, "-f", fd.name] + "-D", "cn=Directory Manager", "-w", self.dm_password, "-f", path] try: ipautil.run(args) except ipautil.CalledProcessError, e: logging.critical("Failed to load %s: %s" % (ldif, str(e))) - fd.close() + if not fd is None: + fd.close() def __add_memberof_module(self): self.__ldap_mod("enabling memberof plugin", "memberof-conf.ldif") def __init_memberof(self): - self.__ldap_mod("initializing group membership", "memberof-task.ldif") + self.__ldap_mod("initializing group membership", + "memberof-task.ldif", self.sub_dict) def __add_referint_module(self): - self.__ldap_mod("enabling referential integrity plugin", "referint-conf.ldif") + self.__ldap_mod("enabling referential integrity plugin", + "referint-conf.ldif") def __add_dna_module(self): - self.__ldap_mod("enabling distributed numeric assignment plugin", "dna-conf.ldif") + self.__ldap_mod("enabling distributed numeric assignment plugin", + "dna-conf.ldif") def __config_uidgid_gen_first_master(self): - self.__ldap_mod("configuring Posix uid/gid generation as first master", "dna-posix.ldif") + self.__ldap_mod("configuring Posix uid/gid generation as first master", + "dna-posix.ldif", self.sub_dict) def __add_master_entry_first_master(self): - self.__ldap_mod("adding master entry as first master", "master-entry.ldif") + self.__ldap_mod("adding master entry as first master", + "master-entry.ldif", self.sub_dict) def __enable_ssl(self): self.step("configuring ssl for ds instance") @@ -294,18 +305,16 @@ class DsInstance(service.Service): conn.unbind() def __add_default_layout(self): - self.__ldap_mod("adding default layout", "bootstrap-template.ldif") + self.__ldap_mod("adding default layout", + "bootstrap-template.ldif", self.sub_dict) def __create_indeces(self): self.__ldap_mod("creating indeces", "indeces.ldif") def __certmap_conf(self): self.step("configuring certmap.conf") - dirname = config_dirname(self.realm_name) - certmap_conf = ipautil.template_file(ipautil.SHARE_DIR + "certmap.conf.template", self.sub_dict) - certmap_fd = open(dirname+"certmap.conf", "w+") - certmap_fd.write(certmap_conf) - certmap_fd.close() + shutil.copyfile(ipautil.SHARE_DIR + "certmap.conf.template", + config_dirname(self.realm_name) + "certmap.conf") def change_admin_password(self, password): logging.debug("Changing admin password") -- cgit From 6976f92862c1dba3f7a25baa1893c41a67590b23 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 13 Dec 2007 09:31:28 +0000 Subject: Refactor krbinstance and dsinstance creation steps Creation steps are currently done with: self.start_creation(2, "Create foo") self.step("do foo") self.foo() self.step("do bar") self.bar() self.done_creation() This patch refactors that into the much more straightforward: self.step("do foo", self.foo) self.step("do bar", self.bar) self.start_creation("Create foo") Signed-off-by: Mark McLoughlin --- ipa-radius-server/plugins/radiusinstance.py | 28 ++++------ ipa-server/ipaserver/dsinstance.py | 83 ++++++++++++---------------- ipa-server/ipaserver/httpinstance.py | 33 ++++------- ipa-server/ipaserver/krbinstance.py | 86 +++++++++++++---------------- ipa-server/ipaserver/ntpinstance.py | 17 +++--- ipa-server/ipaserver/service.py | 26 ++++----- ipa-server/ipaserver/webguiinstance.py | 14 +---- 7 files changed, 119 insertions(+), 168 deletions(-) diff --git a/ipa-radius-server/plugins/radiusinstance.py b/ipa-radius-server/plugins/radiusinstance.py index 2d68adf7e..731cd65a1 100644 --- a/ipa-radius-server/plugins/radiusinstance.py +++ b/ipa-radius-server/plugins/radiusinstance.py @@ -79,7 +79,6 @@ class RadiusInstance(service.Service): self.basedn = self.suffix self.user_basedn = "%s,%s" % (DefaultUserContainer, self.basedn) # FIXME, should be utility to get this self.radius_version = get_radius_version() - self.start_creation(4, "Configuring radiusd") try: self.stop() @@ -87,22 +86,23 @@ class RadiusInstance(service.Service): # It could have been not running pass - self.__create_radius_keytab() - self.__radiusd_conf() + self.step("create radiusd keytab", self.__create_radius_keytab) + self.step("configuring radiusd.conf for radius instance", self.__radiusd_conf) + self.step("starting radiusd", self.__start_instance) + self.step("configuring radiusd to start on boot", self.chkconfig_on) + # FIXME: + # self.step("setting ldap encrypted attributes", self.__set_ldap_encrypted_attributes) + + self.start_creation("Configuring radiusd") + + def __start_instance(self): try: - self.step("starting radiusd") self.start() except: logging.error("radiusd service failed to start") - self.step("configuring radiusd to start on boot") - self.chkconfig_on() - - def __radiusd_conf(self): - self.step('configuring radiusd.conf for radius instance') - version = 'IPA_RADIUS_VERSION=%s FREE_RADIUS_VERSION=%s' % (IPA_RADIUS_VERSION, self.radius_version) sub_dict = {'CONFIG_FILE_VERSION_INFO' : version, 'LDAP_SERVER' : self.ldap_server, @@ -123,7 +123,6 @@ class RadiusInstance(service.Service): logging.error("could not create %s: %s", radius_util.RADIUSD_CONF_FILEPATH, e) def __create_radius_keytab(self): - self.step("creating a keytab for radiusd") try: if ipautil.file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH): os.remove(radius_util.RADIUS_IPA_KEYTAB_FILEPATH) @@ -153,9 +152,7 @@ class RadiusInstance(service.Service): except Exception, e: logging.error("could not chown on %s to %s: %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH, radius_util.RADIUS_USER, e) - def __ldap_mod(self, step, ldif): - self.step(step) - + def __ldap_mod(self, ldif): txt = iputil.template_file(ipautil.SHARE_DIR + ldif, self.sub_dict) fd = ipautil.write_tmp_file(txt) @@ -171,8 +168,7 @@ class RadiusInstance(service.Service): #FIXME, should use IPAdmin method def __set_ldap_encrypted_attributes(self): - self.__ldap_mod("setting ldap encrypted attributes", - "encrypted_attribute.ldif", {"ENCRYPTED_ATTRIBUTE" : "radiusClientSecret"}) + self.__ldap_mod("encrypted_attribute.ldif", {"ENCRYPTED_ATTRIBUTE" : "radiusClientSecret"}) #------------------------------------------------------------------------------- diff --git a/ipa-server/ipaserver/dsinstance.py b/ipa-server/ipaserver/dsinstance.py index b57ac1db3..6cbffcb84 100644 --- a/ipa-server/ipaserver/dsinstance.py +++ b/ipa-server/ipaserver/dsinstance.py @@ -135,38 +135,29 @@ class DsInstance(service.Service): self.domain = host_name[host_name.find(".")+1:] self.__setup_sub_dict() - if ro_replica: - self.start_creation(15, "Configuring directory server:") - else: - self.start_creation(15, "Configuring directory server:") - - self.__create_ds_user() - self.__create_instance() - self.__add_default_schemas() + self.step("creating directory server user", self.__create_ds_user) + self.step("creating directory server instance", self.__create_instance) + self.step("adding default schema", self.__add_default_schemas) if not ro_replica: - self.__add_memberof_module() - self.__add_referint_module() - self.__add_dna_module() - self.__create_indeces() - self.__enable_ssl() - self.__certmap_conf() - try: - self.step("restarting directory server") - self.restart() - except: - # TODO: roll back here? - logging.critical("Failed to restart the ds instance") - self.__add_default_layout() + self.step("enabling memberof plugin", self.__add_memberof_module) + self.step("enabling referential integrity plugin", self.__add_referint_module) + self.step("enabling distributed numeric assignment plugin", self.__add_dna_module) + self.step("creating indeces", self.__create_indeces) + self.step("configuring ssl for ds instance", self.__enable_ssl) + self.step("configuring certmap.conf", self.__certmap_conf) + self.step("restarting directory server", self.__restart_instance) + self.step("adding default layout", self.__add_default_layout) if not ro_replica: - self.__config_uidgid_gen_first_master() - self.__add_master_entry_first_master() - self.__init_memberof() + self.step("configuring Posix uid/gid generation as first master", + self.__config_uidgid_gen_first_master) + self.step("adding master entry as first master", + self.__add_master_entry_first_master) + self.step("initializing group membership", + self.__init_memberof) + self.step("configuring directory to start on boot", self.chkconfig_on) - self.step("configuring directoy to start on boot") - self.chkconfig_on() - - self.done_creation() + self.start_creation("Configuring directory server:") def __setup_sub_dict(self): server_root = find_server_root() @@ -176,7 +167,6 @@ class DsInstance(service.Service): SERVER_ROOT=server_root, DOMAIN=self.domain) def __create_ds_user(self): - self.step("creating directory server user") try: pwd.getpwnam(self.ds_user) logging.debug("ds user %s exists" % self.ds_user) @@ -190,7 +180,6 @@ class DsInstance(service.Service): logging.critical("failed to add user %s" % e) def __create_instance(self): - self.step("creating directory server instance") inf_txt = ipautil.template_str(INF_TEMPLATE, self.sub_dict) logging.debug(inf_txt) inf_fd = ipautil.write_tmp_file(inf_txt) @@ -215,7 +204,6 @@ class DsInstance(service.Service): logging.debug("failed to restart ds instance %s" % e) def __add_default_schemas(self): - self.step("adding default schema") shutil.copyfile(ipautil.SHARE_DIR + "60kerberos.ldif", schema_dirname(self.realm_name) + "60kerberos.ldif") shutil.copyfile(ipautil.SHARE_DIR + "60samba.ldif", @@ -225,9 +213,14 @@ class DsInstance(service.Service): shutil.copyfile(ipautil.SHARE_DIR + "60ipaconfig.ldif", schema_dirname(self.realm_name) + "60ipaconfig.ldif") - def __ldap_mod(self, step, ldif, sub_dict = None): - self.step(step) + def __restart_instance(self): + try: + self.restart() + except: + # TODO: roll back here? + logging.critical("Failed to restart the ds instance") + def __ldap_mod(self, ldif, sub_dict = None): fd = None path = ipautil.SHARE_DIR + ldif @@ -248,30 +241,24 @@ class DsInstance(service.Service): fd.close() def __add_memberof_module(self): - self.__ldap_mod("enabling memberof plugin", "memberof-conf.ldif") + self.__ldap_mod("memberof-conf.ldif") def __init_memberof(self): - self.__ldap_mod("initializing group membership", - "memberof-task.ldif", self.sub_dict) + self.__ldap_mod("memberof-task.ldif", self.sub_dict) def __add_referint_module(self): - self.__ldap_mod("enabling referential integrity plugin", - "referint-conf.ldif") + self.__ldap_mod("referint-conf.ldif") def __add_dna_module(self): - self.__ldap_mod("enabling distributed numeric assignment plugin", - "dna-conf.ldif") + self.__ldap_mod("dna-conf.ldif") def __config_uidgid_gen_first_master(self): - self.__ldap_mod("configuring Posix uid/gid generation as first master", - "dna-posix.ldif", self.sub_dict) + self.__ldap_mod("dna-posix.ldif", self.sub_dict) def __add_master_entry_first_master(self): - self.__ldap_mod("adding master entry as first master", - "master-entry.ldif", self.sub_dict) + self.__ldap_mod("master-entry.ldif", self.sub_dict) def __enable_ssl(self): - self.step("configuring ssl for ds instance") dirname = config_dirname(self.realm_name) ca = certs.CertDB(dirname) ca.create_self_signed() @@ -305,14 +292,12 @@ class DsInstance(service.Service): conn.unbind() def __add_default_layout(self): - self.__ldap_mod("adding default layout", - "bootstrap-template.ldif", self.sub_dict) + self.__ldap_mod("bootstrap-template.ldif", self.sub_dict) def __create_indeces(self): - self.__ldap_mod("creating indeces", "indeces.ldif") + self.__ldap_mod("indeces.ldif") def __certmap_conf(self): - self.step("configuring certmap.conf") shutil.copyfile(ipautil.SHARE_DIR + "certmap.conf.template", config_dirname(self.realm_name) + "certmap.conf") diff --git a/ipa-server/ipaserver/httpinstance.py b/ipa-server/ipaserver/httpinstance.py index 8a7c527af..d0329ccad 100644 --- a/ipa-server/ipaserver/httpinstance.py +++ b/ipa-server/ipaserver/httpinstance.py @@ -57,25 +57,19 @@ class HTTPInstance(service.Service): self.domain = fqdn[fqdn.find(".")+1:] self.sub_dict = { "REALM" : realm, "FQDN": fqdn, "DOMAIN" : self.domain } - self.start_creation(7, "Configuring the web interface") - - self.__disable_mod_ssl() - self.__set_mod_nss_port() - self.__configure_http() - self.__create_http_keytab() - self.__setup_ssl() - self.__setup_autoconfig() - - self.step("restarting httpd") - self.restart() - - self.step("configuring httpd to start on boot") - self.chkconfig_on() - - self.done_creation() + self.step("disabling mod_ssl in httpd", self.__disable_mod_ssl) + self.step("Setting mod_nss port to 443", self.__set_mod_nss_port) + self.step("configuring httpd", self.__configure_http) + self.step("creating a keytab for httpd", self.__create_http_keytab) + self.step("Setting up ssl", self.__setup_ssl) + self.step("Setting up browser autoconfig", self.__setup_autoconfig) + self.step("configuring SELinux for httpd", self.__selinux_config) + self.step("restarting httpd", self.restart) + self.step("configuring httpd to start on boot", self.chkconfig_on) + + self.start_creation("Configuring the web interface") def __selinux_config(self): - self.step("configuring SELinux for httpd") selinux=0 try: if (os.path.exists('/usr/sbin/selinuxenabled')): @@ -94,7 +88,6 @@ class HTTPInstance(service.Service): self.print_msg(selinux_warning) def __create_http_keytab(self): - self.step("creating a keytab for httpd") try: if ipautil.file_exists("/etc/httpd/conf/ipa.keytab"): os.remove("/etc/httpd/conf/ipa.keytab") @@ -122,7 +115,6 @@ class HTTPInstance(service.Service): os.chown("/etc/httpd/conf/ipa.keytab", pent.pw_uid, pent.pw_gid) def __configure_http(self): - self.step("configuring httpd") http_txt = ipautil.template_file(ipautil.SHARE_DIR + "ipa.conf", self.sub_dict) http_fd = open("/etc/httpd/conf.d/ipa.conf", "w") http_fd.write(http_txt) @@ -130,17 +122,14 @@ class HTTPInstance(service.Service): def __disable_mod_ssl(self): - self.step("disabling mod_ssl in httpd") if os.path.exists(SSL_CONF): os.rename(SSL_CONF, "%s.moved_by_ipa" % SSL_CONF) def __set_mod_nss_port(self): - self.step("Setting mod_nss port to 443") if installutils.update_file(NSS_CONF, '8443', '443') != 0: print "Updating %s failed." % NSS_CONF def __setup_ssl(self): - self.step("Setting up ssl") ds_ca = certs.CertDB(dsinstance.config_dirname(self.realm)) ca = certs.CertDB(NSS_DIR) ds_ca.cur_serial = 2000 diff --git a/ipa-server/ipaserver/krbinstance.py b/ipa-server/ipaserver/krbinstance.py index 67d3019e0..5036aa53b 100644 --- a/ipa-server/ipaserver/krbinstance.py +++ b/ipa-server/ipaserver/krbinstance.py @@ -114,58 +114,42 @@ class KrbInstance(service.Service): pass def __common_post_setup(self): - try: - self.step("starting the KDC") - self.start() - except: - logging.critical("krb5kdc service failed to start") - - self.step("configuring KDC to start on boot") - self.chkconfig_on() - - self.step("configuring ipa-kpasswd to start on boot") - service.chkconfig_on("ipa-kpasswd") - - self.step("starting ipa-kpasswd") - service.start("ipa-kpasswd") - + self.step("starting the KDC", self.__start_instance) + self.step("configuring KDC to start on boot", self.chkconfig_on) + self.step("enabling and starting ipa-kpasswd", self.__enable_kpasswd) def create_instance(self, ds_user, realm_name, host_name, admin_password, master_password): self.master_password = master_password self.__common_setup(ds_user, realm_name, host_name, admin_password) - self.start_creation(12, "Configuring Kerberos KDC") - - self.__configure_kdc_account_password() - self.__configure_sasl_mappings() - self.__add_krb_entries() - self.__create_instance() - self.__create_ds_keytab() - self.__export_kadmin_changepw_keytab() - self.__add_pwd_extop_module() + self.step("setting KDC account password", self.__configure_kdc_account_password) + self.step("adding sasl mappings to the directory", self.__configure_sasl_mappings) + self.step("adding kerberos entries to the DS", self.__add_krb_entries) + self.step("adding defalt ACIs", self.__add_default_acis) + self.step("configuring KDC", self.__create_instance) + self.step("creating a keytab for the directory", self.__create_ds_keytab) + self.step("exporting the kadmin keytab", self.__export_kadmin_changepw_keytab) + self.step("adding the password extenstion to the directory", self.__add_pwd_extop_module) self.__common_post_setup() - self.done_creation() - + self.start_creation("Configuring Kerberos KDC") def create_replica(self, ds_user, realm_name, host_name, admin_password, ldap_passwd_filename): - + self.__copy_ldap_passwd(ldap_passwd_filename) + self.__common_setup(ds_user, realm_name, host_name, admin_password) - self.start_creation(9, "Configuring Kerberos KDC") - self.__copy_ldap_passwd(ldap_passwd_filename) - self.__configure_sasl_mappings() - self.__write_stash_from_ds() - self.__create_instance(replica=True) - self.__create_ds_keytab() - self.__export_kadmin_changepw_keytab() + self.step("adding sasl mappings to the directory", self.__configure_sasl_mappings) + self.step("writing stash file from DS", self.__write_stash_from_ds) + self.step("configuring KDC", self.__create_replica_instance) + self.step("creating a keytab for the directory", self.__create_ds_keytab) + self.step("exporting the kadmin keytab", self.__export_kadmin_changepw_keytab) self.__common_post_setup() - self.done_creation() - + self.start_creation("Configuring Kerberos KDC") def __copy_ldap_passwd(self, filename): shutil.copy(filename, "/var/kerberos/krb5kdc/ldappwd") @@ -173,7 +157,6 @@ class KrbInstance(service.Service): def __configure_kdc_account_password(self): - self.step("setting KDC account password") hexpwd = '' for x in self.kdc_password: hexpwd += (hex(ord(x))[2:]) @@ -182,6 +165,16 @@ class KrbInstance(service.Service): pwd_fd.close() os.chmod("/var/kerberos/krb5kdc/ldappwd", 0600) + def __start_instance(self): + try: + self.start() + except: + logging.critical("krb5kdc service failed to start") + + def __enable_kpasswd(self): + service.chkconfig_on("ipa-kpasswd") + service.start("ipa-kpasswd") + def __setup_sub_dict(self): self.sub_dict = dict(FQDN=self.fqdn, IP=self.ip, @@ -191,9 +184,7 @@ class KrbInstance(service.Service): HOST=self.host, REALM=self.realm) - def __ldap_mod(self, step, ldif): - self.step(step) - + def __ldap_mod(self, ldif): txt = ipautil.template_file(ipautil.SHARE_DIR + ldif, self.sub_dict) fd = ipautil.write_tmp_file(txt) @@ -208,7 +199,6 @@ class KrbInstance(service.Service): fd.close() def __configure_sasl_mappings(self): - self.step("adding sasl mappings to the directory") # we need to remove any existing SASL mappings in the directory as otherwise they # they may conflict. There is no way to define the order they are used in atm. @@ -258,13 +248,16 @@ class KrbInstance(service.Service): raise e def __add_krb_entries(self): - self.__ldap_mod("adding kerberos entries to the DS", "kerberos.ldif") + self.__ldap_mod("kerberos.ldif") + def __add_default_acis(self): #Change the default ACL to avoid anonimous access to kerberos keys and othe hashes - self.__ldap_mod("adding defalt ACIs", "default-aci.ldif") + self.__ldap_mod("default-aci.ldif") + + def __create_replica_instance(self): + self.__create_instance(replace=True) def __create_instance(self, replica=False): - self.step("configuring KDC") kdc_conf = ipautil.template_file(ipautil.SHARE_DIR+"kdc.conf.template", self.sub_dict) kdc_fd = open("/var/kerberos/krb5kdc/kdc.conf", "w+") kdc_fd.write(kdc_conf) @@ -300,7 +293,6 @@ class KrbInstance(service.Service): print "Failed to populate the realm structure in kerberos", e def __write_stash_from_ds(self): - self.step("writing stash file from DS") try: entry = self.conn.getEntry("cn=%s, cn=kerberos, %s" % (self.realm, self.suffix), ldap.SCOPE_SUBTREE) except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND), e: @@ -322,7 +314,7 @@ class KrbInstance(service.Service): #add the password extop module def __add_pwd_extop_module(self): - self.__ldap_mod("adding the password extenstion to the directory", "pwd-extop-conf.ldif") + self.__ldap_mod("pwd-extop-conf.ldif") #get the Master Key from the stash file try: @@ -351,7 +343,6 @@ class KrbInstance(service.Service): raise e def __create_ds_keytab(self): - self.step("creating a keytab for the directory") try: if ipautil.file_exists("/etc/dirsrv/ds.keytab"): os.remove("/etc/dirsrv/ds.keytab") @@ -380,7 +371,6 @@ class KrbInstance(service.Service): os.chown("/etc/dirsrv/ds.keytab", pent.pw_uid, pent.pw_gid) def __export_kadmin_changepw_keytab(self): - self.step("exporting the kadmin keytab") try: if ipautil.file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"): os.remove("/var/kerberos/krb5kdc/kpasswd.keytab") diff --git a/ipa-server/ipaserver/ntpinstance.py b/ipa-server/ipaserver/ntpinstance.py index 3872d93c6..b321ec075 100644 --- a/ipa-server/ipaserver/ntpinstance.py +++ b/ipa-server/ipaserver/ntpinstance.py @@ -25,11 +25,8 @@ from ipa import ipautil class NTPInstance(service.Service): def __init__(self): service.Service.__init__(self, "ntpd") - - def create_instance(self): - self.start_creation(3, "Configuring ntpd") - self.step("writing configuration") + def __write_config(self): # The template sets the config to point towards ntp.pool.org, but # they request that software not point towards the default pool. # We use the OS variable to point it towards either the rhel @@ -54,11 +51,13 @@ class NTPInstance(service.Service): fd.write(ntp_conf) fd.close() + def create_instance(self): + self.step("writing configuration", self.__write_config) + # we might consider setting the date manually using ntpd -qg in case # the current time is very far off. - self.step("starting ntpd") - self.start() - - self.step("configuring ntpd to start on boot") - self.chkconfig_on() + self.step("starting ntpd", self.start) + self.step("configuring ntpd to start on boot", self.chkconfig_on) + + self.start_creation("Configuring ntpd") diff --git a/ipa-server/ipaserver/service.py b/ipa-server/ipaserver/service.py index 4b2799702..90d0e606a 100644 --- a/ipa-server/ipaserver/service.py +++ b/ipa-server/ipaserver/service.py @@ -45,8 +45,7 @@ def print_msg(message, output_fd=sys.stdout): class Service: def __init__(self, service_name): self.service_name = service_name - self.num_steps = -1 - self.current_step = -1 + self.steps = [] self.output_fd = sys.stdout def set_output(self, fd): @@ -69,18 +68,19 @@ class Service: def print_msg(self, message): print_msg(message, self.output_fd) - - def start_creation(self, num_steps, message): - self.num_steps = num_steps - self.cur_step = 0 - self.print_msg(message) - def step(self, message): - self.cur_step += 1 - self.print_msg(" [%d/%d]: %s" % (self.cur_step, self.num_steps, message)) + def step(self, message, method): + self.steps.append((message, method)) - def done_creation(self): - self.cur_step = -1 - self.num_steps = -1 + def start_creation(self, message): + self.print_msg(message) + + step = 0 + for (message, method) in self.steps: + self.print_msg(" [%d/%d]: %s" % (step, len(self.steps), message)) + method() + step += 1 + self.print_msg("done configuring %s." % self.service_name) + self.steps = [] diff --git a/ipa-server/ipaserver/webguiinstance.py b/ipa-server/ipaserver/webguiinstance.py index 2d41f30fb..11727e113 100644 --- a/ipa-server/ipaserver/webguiinstance.py +++ b/ipa-server/ipaserver/webguiinstance.py @@ -24,14 +24,6 @@ class WebGuiInstance(service.Service): service.Service.__init__(self, "ipa-webgui") def create_instance(self): - self.start_creation(2, "Configuring ipa-webgui") - - self.step("starting ipa-webgui") - service.start("ipa-webgui") - - self.step("configuring ipa-webgui to start on boot") - service.chkconfig_on("ipa-webgui") - - self.done_creation() - - + self.step("starting ipa-webgui", self.start) + self.step("configuring ipa-webgui to start on boot", self.chkconfig_on) + self.start_creation("Configuring ipa-webgui") -- cgit From b5af99c51d1ea8d4e6593a634d347b38a5d97271 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 12 Dec 2007 15:18:28 -0500 Subject: Fix the UI indicators for mandatory fields. The source and target groups weren't highlighted but the entire block of checkboxes was and it looked absolutely horrible. --- ipa-server/ipa-gui/ipagui/forms/delegate.py | 5 +++-- ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py | 7 +++++++ ipa-server/ipa-gui/ipagui/templates/delegateform.kid | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ipa-server/ipa-gui/ipagui/forms/delegate.py b/ipa-server/ipa-gui/ipagui/forms/delegate.py index d9d5d727c..7eadfe23e 100644 --- a/ipa-server/ipa-gui/ipagui/forms/delegate.py +++ b/ipa-server/ipa-gui/ipagui/forms/delegate.py @@ -65,8 +65,9 @@ class DelegateValidator(validators.Schema): messages = { 'empty': _("Please choose a group"), }) dest_group_dn = validators.String(not_empty=True, messages = { 'empty': _("Please choose a group"), }) - attrs = validators.NotEmpty( - messages = { 'empty': _("Please select at least one value"), }) + # There is no attrs validator here because then it shows as one + # huge block of color in the form. The validation is done in + # the subcontroller. class DelegateForm(widgets.Form): params = ['delegate_fields', 'attr_list'] diff --git a/ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py b/ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py index cee239e72..9f4ec6c43 100644 --- a/ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py +++ b/ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py @@ -292,4 +292,11 @@ class DelegationController(IPAController): @validate(form=delegate_form) @identity.require(identity.not_anonymous()) def delegatevalidate(self, tg_errors=None, **kw): + # We are faking this because otherwise it shows up as one huge + # block of color in the UI when it has a not empty validator. + if not kw.get('attrs'): + if not tg_errors: + tg_errors = {} + tg_errors['attrs'] = _("Please select at least one value") + cherrypy.request.validation_errors = tg_errors return tg_errors, kw diff --git a/ipa-server/ipa-gui/ipagui/templates/delegateform.kid b/ipa-server/ipa-gui/ipagui/templates/delegateform.kid index 4eb846d53..d2be336c8 100644 --- a/ipa-server/ipa-gui/ipagui/templates/delegateform.kid +++ b/ipa-server/ipa-gui/ipagui/templates/delegateform.kid @@ -104,7 +104,7 @@ py:content="tg.errors.get('source_group_dn')" />