summaryrefslogtreecommitdiffstats
path: root/ipalib/plugins/host.py
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2011-12-07 02:50:31 -0500
committerRob Crittenden <rcritten@redhat.com>2012-02-13 22:21:27 -0500
commit3c2b0fc28ae21c7e4b26961e28e2eb0ba0559d29 (patch)
tree856f8f2850043d1f3eb6f3df1c2d3287ae7fc969 /ipalib/plugins/host.py
parent9b6baf9beeb733d77883f4ed32e553265ee15543 (diff)
downloadfreeipa-3c2b0fc28ae21c7e4b26961e28e2eb0ba0559d29.tar.gz
freeipa-3c2b0fc28ae21c7e4b26961e28e2eb0ba0559d29.tar.xz
freeipa-3c2b0fc28ae21c7e4b26961e28e2eb0ba0559d29.zip
Add support for SSH public keys to user and host objects.
This patch adds a new multivalue param "sshpubkey" for specifying SSH public keys to both user and host objects. The accepted value is base64-encoded public key blob as specified in RFC4253, section 6.6. Additionaly, host commands automatically update DNS SSHFP records when requested by user. https://fedorahosted.org/freeipa/ticket/754
Diffstat (limited to 'ipalib/plugins/host.py')
-rw-r--r--ipalib/plugins/host.py116
1 files changed, 93 insertions, 23 deletions
diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index 0cae656b7..682b81420 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -22,6 +22,8 @@ import platform
import os
import sys
from nss.error import NSPRError
+import nss.nss as nss
+import netaddr
from ipalib import api, errors, util
from ipalib import Str, Flag, Bytes
@@ -34,11 +36,9 @@ from ipalib.plugins.dns import add_forward_record
from ipalib import _, ngettext
from ipalib import x509
from ipalib.dn import *
-from ipapython.ipautil import ipa_generate_password, CheckedIPAddress
from ipalib.request import context
-import base64
-import nss.nss as nss
-import netaddr
+from ipalib.util import validate_sshpubkey, output_sshpubkey
+from ipapython.ipautil import ipa_generate_password, CheckedIPAddress, make_sshfp
__doc__ = _("""
Hosts/Machines
@@ -87,6 +87,9 @@ EXAMPLES:
Modify information about a host:
ipa host-mod --os='Fedora 12' test.example.com
+ Remove SSH public keys of a host and update DNS to reflect this change:
+ ipa host-mod --sshpubkey= --updatedns test.example.com
+
Disable the host Kerberos key, SSL certificate and all of its services:
ipa host-disable test.example.com
@@ -162,6 +165,22 @@ def remove_fwd_ptr(ipaddr, host, domain, recordtype):
except errors.NotFound:
pass
+def update_sshfp_record(zone, record, entry_attrs):
+ if 'ipasshpubkey' not in entry_attrs:
+ return
+
+ pubkeys = entry_attrs['ipasshpubkey'] or ()
+ sshfps=[]
+ for pubkey in pubkeys:
+ sshfp = unicode(make_sshfp(pubkey))
+ if sshfp is not None:
+ sshfps.append(sshfp)
+
+ try:
+ api.Command['dnsrecord_mod'](zone, record, sshfprecord=sshfps)
+ except errors.EmptyModlist:
+ pass
+
host_output_params = (
Flag('has_keytab',
label=_('Keytab'),
@@ -226,6 +245,7 @@ class host(LDAPObject):
'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname',
'nshardwareplatform', 'nsosversion', 'usercertificate', 'memberof',
'managedby', 'memberindirect', 'memberofindirect', 'macaddress',
+ 'sshpubkeyfp',
]
uuid_attribute = 'ipauniqueid'
attribute_members = {
@@ -315,6 +335,15 @@ class host(LDAPObject):
label=_('MAC address'),
doc=_('Hardware MAC address(es) on this host'),
),
+ Bytes('ipasshpubkey*', validate_sshpubkey,
+ cli_name='sshpubkey',
+ label=_('Base-64 encoded SSH public key'),
+ flags=['no_search'],
+ ),
+ Str('sshpubkeyfp*',
+ label=_('SSH public key fingerprint'),
+ flags=['virtual_attribute', 'no_create', 'no_update', 'no_search'],
+ ),
)
def get_dn(self, *keys, **options):
@@ -452,33 +481,37 @@ class host_add(LDAPCreate):
entry_attrs['usercertificate'] = cert
entry_attrs['managedby'] = dn
entry_attrs['objectclass'].append('ieee802device')
+ entry_attrs['objectclass'].append('ipasshhost')
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
exc = None
- try:
- if 'ip_address' in options and dns_container_exists(ldap):
+ if dns_container_exists(ldap):
+ try:
parts = keys[-1].split('.')
domain = unicode('.'.join(parts[1:]))
- ip = CheckedIPAddress(options['ip_address'], match_local=False)
- add_forward_record(domain, parts[0], unicode(ip))
+ if 'ip_address' in options:
+ ip = CheckedIPAddress(options['ip_address'], match_local=False)
+ add_forward_record(domain, parts[0], unicode(ip))
- if not options.get('no_reverse', False):
- try:
- prefixlen = None
- if not ip.defaultnet:
- prefixlen = ip.prefixlen
- revzone, revname = get_reverse_zone(ip, prefixlen)
- addkw = { 'ptrrecord' : keys[-1]+'.' }
- api.Command['dnsrecord_add'](revzone, revname, **addkw)
- except errors.EmptyModlist:
- # the entry already exists and matches
- pass
+ if not options.get('no_reverse', False):
+ try:
+ prefixlen = None
+ if not ip.defaultnet:
+ prefixlen = ip.prefixlen
+ revzone, revname = get_reverse_zone(ip, prefixlen)
+ addkw = { 'ptrrecord' : keys[-1]+'.' }
+ api.Command['dnsrecord_add'](revzone, revname, **addkw)
+ except errors.EmptyModlist:
+ # the entry already exists and matches
+ pass
- del options['ip_address']
- except Exception, e:
- exc = e
+ del options['ip_address']
+
+ update_sshfp_record(domain, unicode(parts[0]), entry_attrs)
+ except Exception, e:
+ exc = e
if options.get('random', False):
try:
entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword'))
@@ -493,13 +526,15 @@ class host_add(LDAPCreate):
set_certificate_attrs(entry_attrs)
if options.get('all', False):
- entry_attrs['managing'] = self.obj.get_managed_hosts(dn)
+ entry_attrs['managing'] = self.obj.get_managed_hosts(dn)
self.obj.get_password_attributes(ldap, dn, entry_attrs)
if entry_attrs['has_password']:
# If an OTP is set there is no keytab, at least not one
# fetched anywhere.
entry_attrs['has_keytab'] = False
+ output_sshpubkey(ldap, dn, entry_attrs)
+
return dn
api.register(host_add)
@@ -632,6 +667,10 @@ class host_mod(LDAPUpdate):
doc=_('Kerberos principal name for this host'),
attribute=True,
),
+ Flag('updatedns?',
+ doc=_('Update DNS entries'),
+ default=False,
+ ),
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
@@ -688,6 +727,7 @@ class host_mod(LDAPUpdate):
raise nsprerr
entry_attrs['usercertificate'] = cert
+
if options.get('random'):
entry_attrs['userpassword'] = ipa_generate_password()
setattr(context, 'randompassword', entry_attrs['userpassword'])
@@ -703,6 +743,30 @@ class host_mod(LDAPUpdate):
obj_classes.append('ieee802device')
entry_attrs['objectclass'] = obj_classes
+ if options.get('updatedns', False) and dns_container_exists(ldap):
+ parts = keys[-1].split('.')
+ domain = unicode('.'.join(parts[1:]))
+ result = api.Command['dnszone_find']()['result']
+ match = False
+ for zone in result:
+ if domain == zone['idnsname'][0]:
+ match = True
+ break
+ if not match:
+ raise errors.NotFound(
+ reason=_('DNS zone %(zone)s not found') % dict(zone=domain)
+ )
+ update_sshfp_record(domain, unicode(parts[0]), entry_attrs)
+
+ if 'ipasshpubkey' in entry_attrs:
+ if 'objectclass' in entry_attrs:
+ obj_classes = entry_attrs['objectclass']
+ else:
+ (_dn, _entry_attrs) = ldap.get_entry(dn, ['objectclass'])
+ obj_classes = entry_attrs['objectclass'] = _entry_attrs['objectclass']
+ if 'ipasshhost' not in obj_classes:
+ obj_classes.append('ipasshhost')
+
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
@@ -720,6 +784,8 @@ class host_mod(LDAPUpdate):
self.obj.suppress_netgroup_memberof(entry_attrs)
+ output_sshpubkey(ldap, dn, entry_attrs)
+
return dn
api.register(host_mod)
@@ -802,6 +868,8 @@ class host_find(LDAPSearch):
if options.get('all', False):
entry_attrs['managing'] = self.obj.get_managed_hosts(entry[0])
+ output_sshpubkey(ldap, dn, entry_attrs)
+
api.register(host_find)
@@ -831,6 +899,8 @@ class host_show(LDAPRetrieve):
self.obj.suppress_netgroup_memberof(entry_attrs)
+ output_sshpubkey(ldap, dn, entry_attrs)
+
return dn
def forward(self, *keys, **options):