# Authors: # Rob Crittenden # Pavel Zuna # # 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 """ Hosts/Machines (Identity) """ import platform import os import sys from ipalib import api, errors, util from ipalib import Str, Flag from ipalib.plugins.baseldap import * from ipalib.plugins.service import split_principal def validate_host(ugettext, fqdn): """ Require at least one dot in the hostname (to support localhost.localdomain) """ if fqdn.index('.') == -1: return 'Fully-qualified hostname required' return None class host(LDAPObject): """ Host object. """ container_dn = api.env.container_host object_name = 'host' object_name_plural = 'hosts' object_class = ['ipaobject', 'nshost', 'ipahost', 'pkiuser'] # object_class_config = 'ipahostobjectclasses' default_attributes = [ 'fqdn', 'description', 'localityname', 'nshostlocation', 'nshardwareplatform', 'nsosversion' ] uuid_attribute = 'ipauniqueid' attribute_names = { 'cn': 'name', 'fqdn': 'hostname', 'localityname': 'locality', 'nshostlocation': 'location', 'nshardwareplatform': 'platform', 'nsosversion': 'operating system', 'serverhostname': 'server hostname', 'enrolledby user': 'enrolled by', 'krbprincipalname': 'kerberos principal', } attribute_members = { 'enrolledby': ['user'], } takes_params = ( Str('fqdn', validate_host, cli_name='hostname', doc='Hostname', primary_key=True, normalizer=lambda value: value.lower(), ), Str('description?', cli_name='desc', doc='Description of the host', ), Str('localityname?', cli_name='locality', doc='Locality of the host (Baltimore, MD)', ), Str('nshostlocation?', cli_name='location', doc='Location of the host (e.g. Lab 2)', ), Str('nshardwareplatform?', cli_name='platform', doc='Hardware platform of the host (e.g. Lenovo T61)', ), Str('nsosversion?', cli_name='os', doc='Operating System and version of the host (e.g. Fedora 9)', ), Str('userpassword?', cli_name='password', doc='Password used in bulk enrollment', ), ) def get_dn(self, *keys, **options): if keys[-1].endswith('.'): keys[-1] = keys[-1][:-1] dn = super(host, self).get_dn(*keys, **options) try: self.backend.get_entry(dn, ['']) except errors.NotFound: try: (dn, entry_attrs) = self.backend.find_entry_by_attr( 'serverhostname', keys[-1], self.object_class, [''], self.container_dn ) except errors.NotFound: pass return dn api.register(host) class host_add(LDAPCreate): """ Create new host. """ def pre_callback(self, ldap, dn, entry_attrs, *keys, **options): entry_attrs['cn'] = keys[-1] entry_attrs['serverhostname'] = keys[-1].split('.', 1)[0] # FIXME: do DNS lookup to ensure host exists if 'userpassword' not in entry_attrs: entry_attrs['krbprincipalname'] = 'host/%s@%s' % ( keys[-1], self.api.env.realm ) if 'krbprincipalaux' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('krbprincipalaux') entry_attrs['objectclass'].append('krbprincipal') elif 'krbprincipalaux' in entry_attrs['objectclass']: entry_attrs['objectclass'].remove('krbprincipalaux') return dn api.register(host_add) class host_del(LDAPDelete): """ Delete host. """ def pre_callback(self, ldap, dn, *keys, **options): # Remove all service records for this host truncated = True while truncated: try: (services, truncated) = api.Command['service_find'](keys[-1]) except errors.NotFound: break else: for (dn_, entry_attrs) in services: principal = entry_attrs['krbprincipalname'][0] (service, hostname, realm) = split_principal(principal) if hostname.lower() == keys[-1]: api.Command['service_del'](principal) return dn api.register(host_del) class host_mod(LDAPUpdate): """ Modify host. """ takes_options = LDAPUpdate.takes_options + ( Str('krbprincipalname?', cli_name='principalname', doc='Kerberos principal name for this host', attribute=True, ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): # Once a principal name is set it cannot be changed if 'krbprincipalname' in entry_attrs: (dn, entry_attrs_old) = ldap.get_entry( dn, ['objectclass', 'krbprincipalname'] ) if 'krbprincipalname' in entry_attrs_old: msg = 'Principal name already set, it is unchangeable.' raise errors.ACIError(info=msg) obj_classes = entry_attrs_old['objectclass'] if 'krbprincipalaux' not in obj_classes: obj_classes.append('krbprincipalaux') entry_attrs['objectclass'] = obj_classes return dn api.register(host_mod) class host_find(LDAPSearch): """ Search for hosts. """ api.register(host_find) class host_show(LDAPRetrieve): """ Display host. """ api.register(host_show)