summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2008-10-22 17:54:04 -0400
committerRob Crittenden <rcritten@redhat.com>2008-10-22 17:54:04 -0400
commit1daf319a19f902d7c7bef37af065cac81be9189e (patch)
tree5d840adb9273b7fa0569477fdf2be68d351d0d69
parentf189b02996668e5d600f1abed675cb20cd72290f (diff)
downloadfreeipa-1daf319a19f902d7c7bef37af065cac81be9189e.tar.gz
freeipa-1daf319a19f902d7c7bef37af065cac81be9189e.tar.xz
freeipa-1daf319a19f902d7c7bef37af065cac81be9189e.zip
Implement the host commands
In order for this to work against a v1 database the update host.update needs to be applied
-rw-r--r--ipa_server/plugins/b_ldap.py10
-rw-r--r--ipa_server/updates/host.update22
-rw-r--r--ipalib/config.py1
-rw-r--r--ipalib/plugins/b_xmlrpc.py2
-rw-r--r--ipalib/plugins/f_host.py271
-rw-r--r--ipalib/plugins/f_passwd.py12
-rw-r--r--ipalib/util.py9
7 files changed, 316 insertions, 11 deletions
diff --git a/ipa_server/plugins/b_ldap.py b/ipa_server/plugins/b_ldap.py
index a07e8e710..2e9c9e9fd 100644
--- a/ipa_server/plugins/b_ldap.py
+++ b/ipa_server/plugins/b_ldap.py
@@ -70,6 +70,16 @@ class ldap(CrudBackend):
self.api.env.basedn,
)
+ def make_host_dn(self, hostname):
+ """
+ Construct host dn from hostname
+ """
+ return 'cn=%s,%s,%s' % (
+ self.dn.escape_dn_chars(hostname),
+ self.api.env.container_host,
+ self.api.env.basedn,
+ )
+
def get_object_type(self, attribute):
"""
Based on attribute, make an educated guess as to the type of
diff --git a/ipa_server/updates/host.update b/ipa_server/updates/host.update
new file mode 100644
index 000000000..dfc9723cf
--- /dev/null
+++ b/ipa_server/updates/host.update
@@ -0,0 +1,22 @@
+#
+# Schema for IPA Hosts
+#
+dn: cn=schema
+add: attributeTypes:
+ ( 2.16.840.1.113730.3.8.3.10 NAME 'ipaClientVersion'
+ DESC 'Text string describing client version of the IPA software installed'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ X-ORIGIN 'IPA v2' )
+
+add: attributeTypes:
+ ( 2.16.840.1.113730.3.8.3.11 NAME 'enrolledBy'
+ DESC 'DN of administrator who performed manual enrollment of the host'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+ X-ORIGIN 'IPA v2' )
+add: objectClasses:
+ ( 2.16.840.1.113730.3.8.4.2 NAME 'ipaHost'
+ AUXILIARY
+ MAY ( userPassword $ ipaClientVersion $ enrolledBy)
+ X-ORIGIN 'IPA v2' )
+
+
diff --git a/ipalib/config.py b/ipalib/config.py
index e1b12f1ee..ebd602b91 100644
--- a/ipalib/config.py
+++ b/ipalib/config.py
@@ -138,6 +138,7 @@ def set_default_env(env):
container_user = EnvProp(basestring, 'cn=users,cn=accounts'),
container_group = EnvProp(basestring, 'cn=groups,cn=accounts'),
container_service = EnvProp(basestring, 'cn=services,cn=accounts'),
+ container_host = EnvProp(basestring, 'cn=computers,cn=accounts'),
domain = LazyProp(basestring, get_domain),
interactive = EnvProp(bool, True),
query_dns = EnvProp(bool, True),
diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py
index 9fe5b133a..572a75116 100644
--- a/ipalib/plugins/b_xmlrpc.py
+++ b/ipalib/plugins/b_xmlrpc.py
@@ -69,7 +69,7 @@ class xmlrpc(Backend):
print "%s: %s" % (code, faultString)
else:
print "%s: %s" % (code, getattr(err,'__doc__',''))
- return {}
+ return
api.register(xmlrpc)
diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py
new file mode 100644
index 000000000..da2815480
--- /dev/null
+++ b/ipalib/plugins/f_host.py
@@ -0,0 +1,271 @@
+# Authors:
+# Rob Crittenden <rcritten@redhat.com>
+#
+# Copyright (C) 2008 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
+
+"""
+Frontend plugins for host/machine Identity.
+"""
+
+from ipalib import frontend
+from ipalib import crud
+from ipalib import util
+from ipalib.frontend import Param
+from ipalib import api
+from ipalib import errors
+from ipalib import ipa_types
+
+
+def get_host(hostname):
+ """
+ Try to get the hostname as fully-qualified first, then fall back to
+ just a host name search.
+ """
+ ldap = api.Backend.ldap
+
+ # Strip off trailing dot
+ if hostname.endswith('.'):
+ hostname = hostname[:-1]
+ try:
+ dn = ldap.find_entry_dn("cn", hostname, "ipaHost")
+ except errors.NotFound:
+ dn = ldap.find_entry_dn("serverhostname", hostname, "ipaHost")
+ return dn
+
+def validate_host(cn):
+ """
+ Require at least one dot in the hostname (to support localhost.localdomain)
+ """
+ dots = len(cn.split('.'))
+ if dots < 2:
+ return 'Fully-qualified hostname required'
+ return None
+
+
+class host(frontend.Object):
+ """
+ Host object.
+ """
+ takes_params = (
+ Param('cn',
+ cli_name='hostname',
+ primary_key=True,
+ normalize=lambda value: value.lower(),
+ rules=(validate_host,)
+ ),
+ Param('description?',
+ doc='Description of the host',
+ ),
+ Param('localityname?',
+ cli_name='locality',
+ doc='Locality of this host (Baltimore, MD)',
+ ),
+ Param('nshostlocation?',
+ cli_name='location',
+ doc='Location of this host (e.g. Lab 2)',
+ ),
+ Param('nshardwareplatform?',
+ cli_name='platform',
+ doc='Hardware platform of this host (e.g. Lenovo T61)',
+ ),
+ Param('nsosversion?',
+ cli_name='os',
+ doc='Operating System and version on this host (e.g. Fedora 9)',
+ ),
+ Param('userpassword?',
+ cli_name='password',
+ doc='Set a password to be used in bulk enrollment',
+ ),
+ )
+api.register(host)
+
+
+class host_add(crud.Add):
+ 'Add a new host.'
+ def execute(self, hostname, **kw):
+ """
+ Execute the host-add operation.
+
+ The dn should not be passed as a keyword argument as it is constructed
+ by this method.
+
+ Returns the entry as it will be created in LDAP.
+
+ :param hostname: The name of the host being added.
+ :param kw: Keyword arguments for the other LDAP attributes.
+ """
+ assert 'cn' not in kw
+ assert 'dn' not in kw
+ ldap = self.api.Backend.ldap
+
+ kw['cn'] = hostname
+ kw['serverhostname'] = hostname.split('.',1)[0]
+ kw['dn'] = ldap.make_host_dn(hostname)
+ kw['krbPrincipalName'] = "host/%s@%s" % (hostname, self.api.env.realm)
+
+ # FIXME: do a DNS lookup to ensure host exists
+
+ current = util.get_current_principal()
+ if not current:
+ raise errors.NotFound('Unable to determine current user')
+ kw['enrolledBy'] = ldap.find_entry_dn("krbPrincipalName", current, "person")
+
+ # Get our configuration
+ config = ldap.get_ipa_config()
+
+ # some required objectclasses
+ # FIXME: add this attribute to cn=ipaconfig
+ #kw['objectClass'] = config.get('ipahostobjectclasses')
+ kw['objectClass'] = ['nsHost', 'krbPrincipalAux', 'ipaHost']
+
+ return ldap.create(**kw)
+ def output_for_cli(self, ret):
+ """
+ Output result of this command to command line interface.
+ """
+ if ret:
+ print "Host added"
+
+api.register(host_add)
+
+
+class host_del(crud.Del):
+ 'Delete an existing host.'
+ def execute(self, hostname, **kw):
+ """Delete a host.
+
+ hostname is the name of the host to delete
+
+ :param hostname: The name of the host being removed.
+ :param kw: Not used.
+ """
+ ldap = self.api.Backend.ldap
+ dn = get_host(hostname)
+ return ldap.delete(dn)
+ def output_for_cli(self, ret):
+ """
+ Output result of this command to command line interface.
+ """
+ if ret:
+ print "Host deleted"
+
+api.register(host_del)
+
+
+class host_mod(crud.Mod):
+ 'Edit an existing host.'
+ def execute(self, hostname, **kw):
+ """
+ Execute the host-mod operation.
+
+ The dn should not be passed as a keyword argument as it is constructed
+ by this method.
+
+ Returns the entry
+
+ :param hostname: The name of the host to retrieve.
+ :param kw: Keyword arguments for the other LDAP attributes.
+ """
+ assert 'cn' not in kw
+ assert 'dn' not in kw
+ ldap = self.api.Backend.ldap
+ dn = get_host(hostname)
+ return ldap.update(dn, **kw)
+
+ def output_for_cli(self, ret):
+ """
+ Output result of this command to command line interface.
+ """
+ if ret:
+ print "Host updated"
+
+api.register(host_mod)
+
+
+class host_find(crud.Find):
+ 'Search the hosts.'
+ def get_args(self):
+ """
+ Override Find.get_args() so we can exclude the validation rules
+ """
+ yield self.obj.primary_key.__clone__(rules=tuple())
+ def execute(self, term, **kw):
+ ldap = self.api.Backend.ldap
+
+ # Pull the list of searchable attributes out of the configuration.
+ #config = ldap.get_ipa_config()
+ # FIXME: add this attribute to cn=ipaconfig
+ #search_fields_conf_str = config.get('ipahostsearchfields')
+ #search_fields = search_fields_conf_str.split(",")
+ search_fields = ['cn','serverhostname','description','localityname','nshostlocation','nshardwareplatform','nsosversion']
+
+ for s in search_fields:
+ kw[s] = term
+
+ # Can't use ldap.get_object_type() since cn is also used for group dns
+ kw['objectclass'] = "ipaHost"
+ return ldap.search(**kw)
+ def output_for_cli(self, hosts):
+ if not hosts:
+ return
+ counter = hosts[0]
+ hosts = hosts[1:]
+ if counter == 0:
+ print "No entries found"
+ return
+ elif counter == -1:
+ print "These results are truncated."
+ print "Please refine your search and try again."
+
+ for h in hosts:
+ for a in h.keys():
+ print "%s: %s" % (a, h[a])
+api.register(host_find)
+
+
+class host_show(crud.Get):
+ 'Examine an existing host.'
+ takes_options = (
+ Param('all?', type=ipa_types.Bool(), doc='Display all host attributes'),
+ )
+ def execute(self, hostname, **kw):
+ """
+ Execute the host-show operation.
+
+ The dn should not be passed as a keyword argument as it is constructed
+ by this method.
+
+ Returns the entry
+
+ :param hostname: The login name of the host to retrieve.
+ :param kw: "all" set to True = return all attributes
+ """
+ ldap = self.api.Backend.ldap
+ dn = get_host(hostname)
+ # FIXME: should kw contain the list of attributes to display?
+ if kw.get('all', False):
+ return ldap.retrieve(dn)
+ else:
+ value = ldap.retrieve(dn, ['cn','description','localityname','nshostlocation','nshardwareplatform','nsosversion'])
+ del value['dn']
+ return value
+ def output_for_cli(self, host):
+ if host:
+ for a in host.keys():
+ print "%s: %s" % (a, host[a])
+
+api.register(host_show)
diff --git a/ipalib/plugins/f_passwd.py b/ipalib/plugins/f_passwd.py
index b1f907322..f70eacac8 100644
--- a/ipalib/plugins/f_passwd.py
+++ b/ipalib/plugins/f_passwd.py
@@ -26,15 +26,7 @@ from ipalib.frontend import Param
from ipalib import api
from ipalib import errors
from ipalib import ipa_types
-import krbV
-
-def get_current_principal():
- try:
- return krbV.default_context().default_ccache().principal().name
- except krbV.Krb5Error:
- #TODO: do a kinit
- print "Unable to get kerberos principal"
- return None
+from ipalib import util
class passwd(frontend.Command):
'Edit existing password policy.'
@@ -42,7 +34,7 @@ class passwd(frontend.Command):
Param('principal',
cli_name='user',
primary_key=True,
- default_from=get_current_principal,
+ default_from=util.get_current_principal,
),
)
def execute(self, principal, **kw):
diff --git a/ipalib/util.py b/ipalib/util.py
index b60bfc8aa..184c6d7c4 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -20,6 +20,7 @@
"""
Various utility functions.
"""
+import krbV
def xmlrpc_marshal(*args, **kw):
"""
@@ -39,3 +40,11 @@ def xmlrpc_unmarshal(*params):
else:
kw = {}
return (params[1:], kw)
+
+def get_current_principal():
+ try:
+ return krbV.default_context().default_ccache().principal().name
+ except krbV.Krb5Error:
+ #TODO: do a kinit
+ print "Unable to get kerberos principal"
+ return None