diff options
-rw-r--r-- | ipa-admintools/Makefile | 1 | ||||
-rw-r--r-- | ipa-admintools/ipa-addradiusclient | 248 | ||||
-rw-r--r-- | ipa-python/ipavalidate.py | 1 | ||||
-rw-r--r-- | ipa-python/radius_client.py | 7 | ||||
-rw-r--r-- | ipa-server/ipa-gui/ipagui/templates/welcome.kid | 2 | ||||
-rw-r--r-- | ipa-server/ipa-install/share/Makefile.am | 2 | ||||
-rw-r--r-- | ipa-server/ipa-install/share/bootstrap-template.ldif | 26 | ||||
-rw-r--r-- | ipa-server/ipa-install/share/dna-posix.ldif | 37 | ||||
-rw-r--r-- | ipa-server/ipa-install/share/encrypted_attribute.ldif | 6 | ||||
-rw-r--r-- | ipa-server/ipa-install/share/master-entry.ldif | 7 | ||||
-rw-r--r-- | ipa-server/ipa-install/share/radius.radiusd.conf.template | 2 | ||||
-rw-r--r-- | ipa-server/ipa-slapi-plugins/dna/dna-conf.ldif | 7 | ||||
-rw-r--r-- | ipa-server/ipa-slapi-plugins/dna/dna.c | 18 | ||||
-rw-r--r-- | ipa-server/ipaserver/dsinstance.py | 34 | ||||
-rw-r--r-- | ipa-server/ipaserver/radiusinstance.py | 15 | ||||
-rw-r--r-- | ipa-server/xmlrpc-server/funcs.py | 25 |
16 files changed, 424 insertions, 14 deletions
diff --git a/ipa-admintools/Makefile b/ipa-admintools/Makefile index 9d63db082..4c8d3f1f4 100644 --- a/ipa-admintools/Makefile +++ b/ipa-admintools/Makefile @@ -21,6 +21,7 @@ install: install -m 755 ipa-deldelegation $(SBINDIR) install -m 755 ipa-listdelegation $(SBINDIR) install -m 755 ipa-moddelegation $(SBINDIR) + install -m 755 ipa-addradiusclient $(SBINDIR) @for subdir in $(SUBDIRS); do \ (cd $$subdir && $(MAKE) $@) || exit 1; \ diff --git a/ipa-admintools/ipa-addradiusclient b/ipa-admintools/ipa-addradiusclient new file mode 100644 index 000000000..5772b4d8e --- /dev/null +++ b/ipa-admintools/ipa-addradiusclient @@ -0,0 +1,248 @@ +#! /usr/bin/python -E +# Authors: John Dennis <jdennis@redhat.com> +# +# Copyright (C) 2007 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import sys +from optparse import OptionParser +import ipa +import ipa.radius_client +import ipa.ipaclient as ipaclient +import ipa.ipavalidate as ipavalidate +import ipa.config +import ipa.ipaerror + +import xmlrpclib +import kerberos +import ldap +import getpass +import re + +#------------------------------------------------------------------------------ + +dotted_octet_RE = re.compile(r"^(\d+)\.(\d+)\.(\d+)\.(\d+)(/(\d+))?$") +dns_RE = re.compile(r"^[a-zA-Z.-]+$") +# secret, name, nastype all have 31 char max in freeRADIUS, max ip address len is 255 +valid_secret_len = (1,31) +valid_name_len = (1,31) +valid_nastype_len = (1,31) +valid_ip_addr_len = (1,255) + +valid_ip_addr_msg = "IP address is required and must be dotted octet with optional mask or a DNS name" +valid_desc_msg = "Description must text string" + +#------------------------------------------------------------------------------ + +def usage(): + print "ipa-addradiusclient" + sys.exit(1) + +def parse_options(): + parser = OptionParser() + parser.add_option("--usage", action="store_true", + help="Program usage") + parser.add_option("-a", "--address", dest="ip_addr", + help="RADIUS client IP address") + parser.add_option("-s", "--secret", dest="secret", + help="RADIUS client secret") + parser.add_option("-n", "--name", dest="name", + help="RADIUS client name") + parser.add_option("-t", "--type", dest="nastype", + help="RADIUS client name") + parser.add_option("-d", "--description", dest="desc", + help="description of the RADIUS client") + + args = ipa.config.init_config(sys.argv) + options, args = parser.parse_args(args) + + return options, args + +#------------------------------------------------------------------------------ + +def get_secret(): + valid = False + while (not valid): + secret = getpass.getpass("Enter Secret: ") + confirm = getpass.getpass("Confirm Secret: ") + if (secret != confirm): + print "Secrets do not match" + continue + valid = True + return secret + +#------------------------------------------------------------------------------ + +def valid_ip_addr(text): + + # is it a dotted octet? If so there should be 4 integers seperated + # by a dot and each integer should be between 0 and 255 + # there may be an optional mask preceded by a slash (e.g. 1.2.3.4/24) + match = dotted_octet_RE.search(text) + if match: + # dotted octet notation + i = 1 + while i <= 4: + octet = int(match.group(i)) + if octet > 255: return False + i += 1 + if match.group(5): + mask = int(match.group(6)) + if mask <= 32: + return True + else: + return False + return True + else: + # DNS name, can contain letters, dot and hypen + if dns_RE.search(text): return False + return True + +def validate_length(value, limits): + length = len(value) + if length < limits[0] or length > limits[1]: + return False + return True + +def valid_length_msg(name, limits): + return "%s length must be at least %d and not more than %d" % (name, limits[0], limits[1]) + +def validate_ip_addr(ip_addr): + if not validate_length(ip_addr, valid_ip_addr_len): + print valid_length_msg('ip address', valid_ip_addr_len) + return False + if not valid_ip_addr(ip_addr): + print valid_ip_addr_msg + return False + return True + +def validate_secret(secret): + if not validate_length(secret, valid_secret_len): + print valid_length_msg('secret', valid_secret_len) + return False + return True + +def validate_name(name): + if not validate_length(name, valid_name_len): + print valid_length_msg('name', valid_name_len) + return False + return True + +def validate_nastype(nastype): + if not validate_length(nastype, valid_nastype_len): + print valid_length_msg('NAS Type', valid_nastype_len) + return False + return True + +def validate_desc(desc): + if ipavalidate.plain(desc, notEmpty=True) != 0: + print valid_desc_msg + return False + return True + +#------------------------------------------------------------------------------ + +def main(): + ip_addr = None + secret = None + name = None + nastype = None + desc = None + + client=ipa.radius_client.RadiusClient() + options, args = parse_options() + + # client address is required + if options.ip_addr: + ip_addr = options.ip_addr + if not validate_ip_addr(ip_addr): return 1 + else: + valid = False + while not valid: + ip_addr = raw_input("Client IP: ") + if validate_ip_addr(ip_addr): valid = True + + # client secret is required + if options.secret: + secret = options.secret + if not validate_secret(secret): return 1 + else: + valid = False + while not valid: + secret = get_secret() + if validate_secret(secret): valid = True + + # client name is optional + if options.name: + name = options.name + if not validate_name(name): return 1 + + # client NAS Type is optional + if options.nastype: + nastype = options.nastype + if not validate_nastype(nastype): return 1 + + # client description is optional + if options.desc: + desc = options.desc + if not validate_desc(desc): return 1 + + + #print "ip_addr=%s secret=%s name=%s nastype=%s desc=%s" % (ip_addr, secret, name, nastype, desc) + + if ip_addr is not None: + client.setValue('radiusClientNASIpAddress', ip_addr) + else: + print "client IP Address is required" + return 1 + + if secret is not None: + client.setValue('radiusClientSecret', secret) + else: + print "client secret is required" + return 1 + + if name is not None: + client.setValue('radiusClientShortName', name) + + if nastype is not None: + client.setValue('radiusClientNASType', nastype) + + if desc is not None: + client.setValue('description', desc) + + try: + client = ipaclient.IPAClient() + client.add_radius_client(client) + print "successfully added" + except xmlrpclib.Fault, f: + print f.faultString + return 1 + except kerberos.GSSError, e: + print "Could not initialize GSSAPI: %s/%s" % (e[0][0][0], e[0][1][0]) + return 1 + except xmlrpclib.ProtocolError, e: + print "Unable to connect to IPA server: %s" % (e.errmsg) + return 1 + except ipa.ipaerror.IPAError, e: + print "%s" % (e.message) + return 1 + + return 0 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/ipa-python/ipavalidate.py b/ipa-python/ipavalidate.py index 918c34a62..3a6699e16 100644 --- a/ipa-python/ipavalidate.py +++ b/ipa-python/ipavalidate.py @@ -96,3 +96,4 @@ def path(text, notEmpty=False): return 1 return 0 + diff --git a/ipa-python/radius_client.py b/ipa-python/radius_client.py new file mode 100644 index 000000000..44deb7464 --- /dev/null +++ b/ipa-python/radius_client.py @@ -0,0 +1,7 @@ +from ipa.entity import Entity + +class RadiusClient(Entity): + + def __init2__(self): + pass + diff --git a/ipa-server/ipa-gui/ipagui/templates/welcome.kid b/ipa-server/ipa-gui/ipagui/templates/welcome.kid index 732b3d6d3..eb568851f 100644 --- a/ipa-server/ipa-gui/ipagui/templates/welcome.kid +++ b/ipa-server/ipa-gui/ipagui/templates/welcome.kid @@ -28,7 +28,7 @@ IPA is used to manage Identity, Policy, and Auditing for your organization. "joe finance" into the search box. </p> <p> - Alternatively, select a task from the left sidebar. + Alternatively, select a task from the right sidebar. </p> </div> diff --git a/ipa-server/ipa-install/share/Makefile.am b/ipa-server/ipa-install/share/Makefile.am index cbb2e149a..b103d5670 100644 --- a/ipa-server/ipa-install/share/Makefile.am +++ b/ipa-server/ipa-install/share/Makefile.am @@ -20,6 +20,8 @@ app_DATA = \ ntp.conf.server.template \ radius.radiusd.conf.template \ referint-conf.ldif \ + dna-posix.ldif \ + master-entry.ldif \ $(NULL) EXTRA_DIST = \ diff --git a/ipa-server/ipa-install/share/bootstrap-template.ldif b/ipa-server/ipa-install/share/bootstrap-template.ldif index 35d60a326..df59bc0ec 100644 --- a/ipa-server/ipa-install/share/bootstrap-template.ldif +++ b/ipa-server/ipa-install/share/bootstrap-template.ldif @@ -39,6 +39,18 @@ objectClass: nsContainer objectClass: top cn: sysaccounts +dn: cn=ipa,cn=etc,$SUFFIX +changetype: add +objectClass: nsContainer +objectClass: top +cn: ipa + +dn: cn=masters,cn=ipa,cn=etc,$SUFFIX +changetype: add +objectClass: nsContainer +objectClass: top +cn: masters + dn: uid=admin,cn=sysaccounts,cn=etc,$SUFFIX changetype: add objectClass: top @@ -50,7 +62,7 @@ uid: admin krbPrincipalName: admin@$REALM cn: Administrator sn: Administrator -uidNumber: 1000 +uidNumber: 999 gidNumber: 1001 homeDirectory: /home/admin loginShell: /bin/bash @@ -74,6 +86,18 @@ objectClass: nsContainer objectClass: top cn: clients +dn: cn=profiles,cn=radius,cn=services,cn=etc,$SUFFIX +changetype: add +objectClass: nsContainer +objectClass: top +cn: profiles + +dn: uid=ipa_default, cn=profiles,cn=radius,cn=services,cn=etc,$SUFFIX +changetype: add +objectClass: top +objectClass: radiusprofile +uid: ipa_default + dn: cn=admins,cn=groups,cn=accounts,$SUFFIX changetype: add objectClass: top diff --git a/ipa-server/ipa-install/share/dna-posix.ldif b/ipa-server/ipa-install/share/dna-posix.ldif new file mode 100644 index 000000000..e999b209b --- /dev/null +++ b/ipa-server/ipa-install/share/dna-posix.ldif @@ -0,0 +1,37 @@ +# add container for posix configuration + +dn: cn=Posix,cn=ipa-dna,cn=plugins,cn=config +changetype: add +objectclass: top +objectclass: nsContainer +objectclass: extensibleObject +cn: Posix + +# add plugin configuration for posix users + +dn: cn=Accounts,cn=Posix,cn=ipa-dna,cn=plugins,cn=config +changetype: add +objectclass: top +objectclass: extensibleObject +cn: Accounts +dnaType: uidNumber +dnaNextValue: 1100 +dnaInterval: 4 +dnaMagicRegen: 999 +dnaFilter: (objectclass=posixAccount) +dnaScope: $SUFFIX + +# add plugin configuration for posix groups + +dn: cn=Groups,cn=Posix,cn=ipa-dna,cn=plugins,cn=config +changetype: add +objectclass: top +objectclass: extensibleObject +cn: Groups +dnaType: gidNumber +dnaNextValue: 1100 +dnaInterval: 4 +dnaMagicRegen: 999 +dnaFilter: (objectclass=posixGroup) +dnaScope: $SUFFIX + diff --git a/ipa-server/ipa-install/share/encrypted_attribute.ldif b/ipa-server/ipa-install/share/encrypted_attribute.ldif new file mode 100644 index 000000000..3f5e1b43d --- /dev/null +++ b/ipa-server/ipa-install/share/encrypted_attribute.ldif @@ -0,0 +1,6 @@ +dn: cn=$ENCRYPTED_ATTRIBUTE, cn=encrypted attributes, cn=userRoot, cn=ldbm database, cn=plugins, cn=config +changetype: add +objectClass: top +objectClass: nsAttributeEncryption +cn: $ENCRYPTED_ATTRIBUTE +nsEncryptionAlgorithm: AES diff --git a/ipa-server/ipa-install/share/master-entry.ldif b/ipa-server/ipa-install/share/master-entry.ldif new file mode 100644 index 000000000..09c1d44fd --- /dev/null +++ b/ipa-server/ipa-install/share/master-entry.ldif @@ -0,0 +1,7 @@ +dn: cn=$FQHN,cn=masters,cn=ipa,cn=etc,$SUFFIX +changetype: add +objectclass: top +objectclass: extensibleObject +cn: $FQHN +dnabase: 1100 +dnainterval: 4 diff --git a/ipa-server/ipa-install/share/radius.radiusd.conf.template b/ipa-server/ipa-install/share/radius.radiusd.conf.template index 73d101c7e..3bc4927dd 100644 --- a/ipa-server/ipa-install/share/radius.radiusd.conf.template +++ b/ipa-server/ipa-install/share/radius.radiusd.conf.template @@ -82,6 +82,8 @@ $$INCLUDE $${confdir}/eap.conf 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" diff --git a/ipa-server/ipa-slapi-plugins/dna/dna-conf.ldif b/ipa-server/ipa-slapi-plugins/dna/dna-conf.ldif index a133fcf46..02532b4e4 100644 --- a/ipa-server/ipa-slapi-plugins/dna/dna-conf.ldif +++ b/ipa-server/ipa-slapi-plugins/dna/dna-conf.ldif @@ -1,13 +1,14 @@ dn: cn=ipa-dna,cn=plugins,cn=config +changetype: add objectclass: top objectclass: nsSlapdPlugin objectclass: extensibleObject cn: ipa-dna nsslapd-pluginpath: libipa-dna-plugin -nsslapd-plugininitfunc: dna_init -nsslapd-plugintype: postoperation +nsslapd-plugininitfunc: ipa_dna_init +nsslapd-plugintype: preoperation nsslapd-pluginenabled: on nsslapd-pluginid: ipa-dna nsslapd-pluginversion: 1.0 nsslapd-pluginvendor: Red Hat -nsslapd-plugindescription: Distributed numeric assignment plugin +nsslapd-plugindescription: IPA Distributed numeric assignment plugin diff --git a/ipa-server/ipa-slapi-plugins/dna/dna.c b/ipa-server/ipa-slapi-plugins/dna/dna.c index 7c8dad1aa..bafe44107 100644 --- a/ipa-server/ipa-slapi-plugins/dna/dna.c +++ b/ipa-server/ipa-slapi-plugins/dna/dna.c @@ -65,7 +65,7 @@ #include <sys/stat.h> #endif -#define DNA_PLUGIN_SUBSYSTEM "dna-plugin" +#define DNA_PLUGIN_SUBSYSTEM "ipa-dna-plugin" #define DNA_PLUGIN_VERSION 0x00010000 #define DNA_DN "cn=ipa-dna,cn=plugins,cn=config" /* temporary */ @@ -84,8 +84,8 @@ #define DNA_FILTER "dnaFilter" #define DNA_SCOPE "dnaScope" -#define FEATURE_DESC "Distributed Numeric Assignment" -#define PLUGIN_DESC "Distributed Numeric Assignment plugin" +#define FEATURE_DESC "IPA Distributed Numeric Assignment" +#define PLUGIN_DESC "IPA Distributed Numeric Assignment plugin" static Slapi_PluginDesc pdesc = { FEATURE_DESC, "FreeIPA project", "FreeIPA/1.0", @@ -125,7 +125,7 @@ static Slapi_Mutex *g_new_value_lock; * DNA plug-in management functions * */ -int dna_init(Slapi_PBlock *pb); +int ipa_dna_init(Slapi_PBlock *pb); static int dna_start(Slapi_PBlock *pb); static int dna_close(Slapi_PBlock *pb); static int dna_postop_init(Slapi_PBlock *pb); @@ -235,12 +235,12 @@ char * getPluginDN() ------------- adds our callbacks to the list */ -int dna_init( Slapi_PBlock *pb ) +int ipa_dna_init( Slapi_PBlock *pb ) { int status = DNA_SUCCESS; char * plugin_identity=NULL; - slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "--> dna_init\n"); + slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "--> ipa_dna_init\n"); /** * Store the plugin identity for later use. @@ -267,7 +267,7 @@ int dna_init( Slapi_PBlock *pb ) slapi_register_plugin( "postoperation", /* op type */ 1, /* Enabled */ - "dna_init", /* this function desc */ + "ipa_dna_init", /* this function desc */ dna_postop_init, /* init func for post op */ PLUGIN_DESC, /* plugin desc */ NULL, /* ? */ @@ -276,11 +276,11 @@ int dna_init( Slapi_PBlock *pb ) ) { slapi_log_error( SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, - "dna_init: failed to register plugin\n" ); + "ipa_dna_init: failed to register plugin\n" ); status = DNA_FAILURE; } - slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "<-- dna_init\n"); + slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "<-- ipa_dna_init\n"); return status; } diff --git a/ipa-server/ipaserver/dsinstance.py b/ipa-server/ipaserver/dsinstance.py index 284ad3a6d..9a539470e 100644 --- a/ipa-server/ipaserver/dsinstance.py +++ b/ipa-server/ipaserver/dsinstance.py @@ -84,6 +84,7 @@ class DsInstance(service.Service): self.__add_default_schemas() self.__add_memberof_module() self.__add_referint_module() + self.__add_dna_module() self.__create_indeces() self.__enable_ssl() self.__certmap_conf() @@ -93,7 +94,10 @@ class DsInstance(service.Service): except: # TODO: roll back here? logging.critical("Failed to restart the ds instance") + self.__config_uidgid_gen_first_master() self.__add_default_layout() + self.__add_master_entry_first_master() + self.step("configuring directoy to start on boot") self.chkconfig_on() @@ -183,6 +187,36 @@ class DsInstance(service.Service): print "Failed to load referint-conf.ldif", e referint_fd.close() + def __add_dna_module(self): + self.step("enabling distributed numeric assignment plugin") + dna_txt = template_file(SHARE_DIR + "dna-conf.ldif", self.sub_dict) + dna_fd = write_tmp_file(dna_txt) + try: + ldap_mod(dna_fd, "cn=Directory Manager", self.dm_password) + except subprocess.CalledProcessError, e: + print "Failed to load dna-conf.ldif", e + dna_fd.close() + + def __config_uidgid_gen_first_master(self): + self.step("configuring Posix uid/gid generation as first master") + dna_txt = template_file(SHARE_DIR + "dna-posix.ldif", self.sub_dict) + dna_fd = write_tmp_file(dna_txt) + try: + ldap_mod(dna_fd, "cn=Directory Manager", self.dm_password) + except subprocess.CalledProcessError, e: + print "Failed to configure Posix uid/gid generation with dna-posix.ldif", e + dna_fd.close() + + def __add_master_entry_first_master(self): + self.step("adding master entry as first master") + master_txt = template_file(SHARE_DIR + "master-entry.ldif", self.sub_dict) + master_fd = write_tmp_file(master_txt) + try: + ldap_mod(master_fd, "cn=Directory Manager", self.dm_password) + except subprocess.CalledProcessError, e: + print "Failed to add master-entry.ldif", e + master_fd.close() + def __enable_ssl(self): self.step("configuring ssl for ds instance") dirname = self.config_dirname() diff --git a/ipa-server/ipaserver/radiusinstance.py b/ipa-server/ipaserver/radiusinstance.py index 90727758f..38091d696 100644 --- a/ipa-server/ipaserver/radiusinstance.py +++ b/ipa-server/ipaserver/radiusinstance.py @@ -51,6 +51,10 @@ 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: @@ -160,6 +164,17 @@ class RadiusInstance(service.Service): except Exception, e: logging.error("could not chown on %s to %s: %s", IPA_KEYTAB_FILEPATH, RADIUS_USER, e) + 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() + #------------------------------------------------------------------------------- # FIXME: this should be in a common area so it can be shared diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py index 6fdaaca51..8169b4463 100644 --- a/ipa-server/xmlrpc-server/funcs.py +++ b/ipa-server/xmlrpc-server/funcs.py @@ -456,6 +456,31 @@ class IPAServer: self.releaseConnection(conn) return res + def add_radius_client (self, client, opts=None): + client_container = 'cn=clients,cn=radius,cn=services,cn=etc' # FIXME, should not be hardcoded + if self.__is_client_unique(client['radiusClientNASIpAddress'], opts) == 0: + raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE) + + dn="radiusClientNASIpAddress=%s,%s,%s" % (ldap.dn.escape_dn_chars(client['radiusClientNASIpAddress']), + client_container,self.basedn) + entry = ipaserver.ipaldap.Entry(dn) + + # FIXME: This should be dynamic and can include just about anything + + # some required objectclasses + entry.setValues('objectClass', 'top', 'radiusClientProfile') + + # fill in our new entry with everything sent by the client + for u in client: + entry.setValues(u, client[u]) + + conn = self.getConnection(opts) + try: + res = conn.addEntry(entry) + finally: + self.releaseConnection(conn) + return res + def get_add_schema (self): """Get the list of fields to be used when adding users in the GUI.""" |