From a6294ba041aa4568b414b5f25a345c00a031667e Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 31 Mar 2009 09:24:26 -0600 Subject: Renamed remaining plugins still using f_* b_* convention --- ipalib/plugins/application.py | 255 ++++++++++++++ ipalib/plugins/automount.py | 691 +++++++++++++++++++++++++++++++++++++ ipalib/plugins/b_kerberos.py | 34 -- ipalib/plugins/defaultoptions.py | 137 ++++++++ ipalib/plugins/delegation.py | 64 ++++ ipalib/plugins/f_application.py | 255 -------------- ipalib/plugins/f_automount.py | 691 ------------------------------------- ipalib/plugins/f_defaultoptions.py | 137 -------- ipalib/plugins/f_delegation.py | 64 ---- ipalib/plugins/f_host.py | 287 --------------- ipalib/plugins/f_passwd.py | 71 ---- ipalib/plugins/f_pwpolicy.py | 127 ------- ipalib/plugins/f_service.py | 220 ------------ ipalib/plugins/f_user.py | 383 -------------------- ipalib/plugins/host.py | 287 +++++++++++++++ ipalib/plugins/kerberos.py | 34 ++ ipalib/plugins/passwd.py | 71 ++++ ipalib/plugins/pwpolicy.py | 127 +++++++ ipalib/plugins/service.py | 220 ++++++++++++ ipalib/plugins/user.py | 383 ++++++++++++++++++++ 20 files changed, 2269 insertions(+), 2269 deletions(-) create mode 100644 ipalib/plugins/application.py create mode 100644 ipalib/plugins/automount.py delete mode 100644 ipalib/plugins/b_kerberos.py create mode 100644 ipalib/plugins/defaultoptions.py create mode 100644 ipalib/plugins/delegation.py delete mode 100644 ipalib/plugins/f_application.py delete mode 100644 ipalib/plugins/f_automount.py delete mode 100644 ipalib/plugins/f_defaultoptions.py delete mode 100644 ipalib/plugins/f_delegation.py delete mode 100644 ipalib/plugins/f_host.py delete mode 100644 ipalib/plugins/f_passwd.py delete mode 100644 ipalib/plugins/f_pwpolicy.py delete mode 100644 ipalib/plugins/f_service.py delete mode 100644 ipalib/plugins/f_user.py create mode 100644 ipalib/plugins/host.py create mode 100644 ipalib/plugins/kerberos.py create mode 100644 ipalib/plugins/passwd.py create mode 100644 ipalib/plugins/pwpolicy.py create mode 100644 ipalib/plugins/service.py create mode 100644 ipalib/plugins/user.py (limited to 'ipalib') diff --git a/ipalib/plugins/application.py b/ipalib/plugins/application.py new file mode 100644 index 000000000..150dbe8e1 --- /dev/null +++ b/ipalib/plugins/application.py @@ -0,0 +1,255 @@ +# Authors: +# Jakub Hrozek +# +# 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 application policy containers. +""" + +from ipalib import api, crud +from ipalib import Object, Command # Plugin base classes +from ipalib import Str, StrEnum, Flag # Parameter types + +def get_base_by_type(type): + if type == 'config': + return api.env.container_applications + if type == 'role': + return api.env.container_roles + +class application(Object): + 'Application object' + takes_params = ( + Str('cn', + cli_name='appname', + primary_key=True, + doc='Application name', + ), + Str('description?', + doc='Application description', + ), + ) +api.register(application) + +# The default attributes to query +default_attributes = ['cn','description'] + +class application_create(crud.Create): + 'Add a new application' + takes_options = ( + StrEnum('type', + values=(u'config', u'role'), + doc='The type of the application', + ), + ) + + def execute(self, cn, **kw): + """ + Execute the application-create operation + + The dn should not be passed as a keyword argument, it + should be constructed by this method. + + :param cn: The name of the application being added. + :param kw: Keyword arguments for the other LDAP attributes. + """ + self.log.info("IPA: application-create '%s'" % cn) + + assert 'dn' not in kw + assert 'cn' not in kw + ldap = self.api.Backend.ldap + + kw['objectClass'] = ['nsContainer', 'ipaContainer'] + if kw['type'] == 'config': + kw['dn'] = ldap.make_application_dn(cn) + if kw['type'] == 'role': + kw['dn'] = ldap.make_role_application_dn(cn) + kw['cn'] = cn + + del kw['type'] + return ldap.create(**kw) + + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + textui.print_name(self.name) + textui.print_entry(result) + textui.print_dashed('Added application "%s"' % result['cn']) + +api.register(application_create) + +class application_find(crud.Search): + 'Search for applications' + takes_options = ( + StrEnum('type', + values=(u'config', u'role'), + doc='The type of the application', + ), + Flag('all', + doc='Retrieve all application attributes' + ), + ) + + def execute(self, term, **kw): + """ + Execute the application-find operation + """ + ldap = self.api.Backend.ldap + + search_kw = dict() + search_kw['cn'] = term + search_kw['objectclass'] = 'ipaContainer' + search_kw['base'] = get_base_by_type(kw['type']) + search_kw['scope'] = 'one' + if kw.get('all', False): + search_kw['attributes'] = ['*'] + else: + search_kw['attributes'] = default_attributes + + return ldap.search(**search_kw) + + def output_for_cli(self, textui, result, cn, **options): + """ + Output result of this command to command line interface. + """ + counter = result[0] + apps = result[1:] + if counter == 0 or len(apps) == 0: + textui.print_plain("No applications found") + return + if len(apps) == 1: + textui.print_entry(apps[0]) + return + textui.print_name(self.name) + for a in apps: + textui.print_plain('%(cn)s:' % a) + textui.print_entry(a) + textui.print_plain('') + if counter == -1: + textui.print_plain('These results are truncated.') + textui.print_plain('Please refine your search and try again.') + textui.print_count(apps, '%d applications matched') + +api.register(application_find) + +class application_delete(crud.Del): + 'Delete an application' + takes_options = ( + StrEnum('type', + values=(u'config', u'role'), + doc='The type of the application', + ), + ) + + def execute(self, cn, **kw): + """ + Delete the application container. + + :param cn: The name of the application being deleted. + :param kw: Not used. + """ + if cn == "Shell Applications": + raise SyntaxError("Cannot delete shell application") + self.log.info("IPA: application_delete '%s'" % cn) + + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", + cn, + object_type='ipaContainer', + base=get_base_by_type(kw['type'])) + + return ldap.delete(dn) + + def output_for_cli(self, textui, result, cn): + """ + Output result of this command to command line interface. + """ + textui.print_plain('Deleted application "%s"' % cn) + +api.register(application_delete) + +class application_show(crud.Get): + 'Examine an existing application' + takes_options = ( + StrEnum('type', + values=(u'config', u'role'), + doc='The type of the application', + ), + Flag('all', + doc='Retrieve all application attributes' + ), + ) + def execute(self, cn, **kw): + """ + Execute the application-show operation. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", + cn, + object_type='ipaContainer', + base=get_base_by_type(kw['type'])) + + if kw.get('all', False): + return ldap.retrieve(dn) + else: + return ldap.retrieve(dn, default_attributes) + + def output_for_cli(self, textui, result, cn, **options): + if result: + textui.print_entry(result) + +api.register(application_show) + +class application_edit(crud.Mod): + 'Edit an existing application' + takes_options = ( + StrEnum('type', + values=(u'config', u'role'), + doc='The type of the application', + ), + ) + + def execute(self, cn, **kw): + """ + Execute the application-edit operation + + :param cn: The name of the application to edit + :param kw: Keyword arguments for the other LDAP attributes. + """ + self.log.info("IPA: application_edit '%s'" % cn) + + assert 'cn' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", + cn, + object_type='ipaContainer', + base=get_base_by_type(kw['type'])) + + del kw['type'] + return ldap.update(dn, **kw) + + def output_for_cli(self, textui, result, cn, **options): + """ + Output result of this command to command line interface. + """ + textui.print_name(self.name) + textui.print_entry(result) + textui.print_dashed('Updated application "%s"' % result['cn']) + +api.register(application_edit) diff --git a/ipalib/plugins/automount.py b/ipalib/plugins/automount.py new file mode 100644 index 000000000..b25f512a5 --- /dev/null +++ b/ipalib/plugins/automount.py @@ -0,0 +1,691 @@ +# Authors: +# Rob Crittenden +# +# 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 automount. + +RFC 2707bis http://www.padl.com/~lukeh/rfc2307bis.txt + +A few notes on automount: +- It was a design decision to not support different maps by location +- The default parent when adding an indirect map is auto.master +- This uses the short format for automount maps instead of the + URL format. Support for ldap as a map source in nsswitch.conf was added + in autofs version 4.1.3-197. Any version prior to that is not expected + to work. + +As an example, the following automount files: + +auto.master: +/- auto.direct +/mnt auto.mnt + +auto.mnt: +stuff -ro,soft,rsize=8192,wsize=8192 nfs.example.com:/vol/archive/stuff + +are equivalent to the following LDAP entries: + +# auto.master, automount, example.com +dn: automountmapname=auto.master,cn=automount,dc=example,dc=com +objectClass: automountMap +objectClass: top +automountMapName: auto.master + +# auto.direct, automount, example.com +dn: automountmapname=auto.direct,cn=automount,dc=example,dc=com +objectClass: automountMap +objectClass: top +automountMapName: auto.direct + +# /-, auto.master, automount, example.com +dn: automountkey=/-,automountmapname=auto.master,cn=automount,dc=example,dc=co + m +objectClass: automount +objectClass: top +automountKey: /- +automountInformation: auto.direct + +# auto.mnt, automount, example.com +dn: automountmapname=auto.mnt,cn=automount,dc=example,dc=com +objectClass: automountMap +objectClass: top +automountMapName: auto.mnt + +# /mnt, auto.master, automount, example.com +dn: automountkey=/mnt,automountmapname=auto.master,cn=automount,dc=example,dc= + com +objectClass: automount +objectClass: top +automountKey: /mnt +automountInformation: auto.mnt + +# stuff, auto.mnt, automount, example.com +dn: automountkey=stuff,automountmapname=auto.mnt,cn=automount,dc=example,dc=com +objectClass: automount +objectClass: top +automountKey: stuff +automountInformation: -ro,soft,rsize=8192,wsize=8192 nfs.example.com:/vol/arch + ive/stuff + +""" + +from ldap import explode_dn +from ipalib import crud, errors2 +from ipalib import api, Str, Flag, Object, Command + +map_attributes = ['automountMapName', 'description', ] +key_attributes = ['description', 'automountKey', 'automountInformation'] + +def display_entry(textui, entry): + # FIXME: for now delete dn here. In the future pass in the kw to + # output_for_cli() + attr = sorted(entry.keys()) + + for a in attr: + if a != 'dn': + textui.print_plain("%s: %s" % (a, entry[a])) + +def make_automount_dn(mapname): + """ + Construct automount dn from map name. + """ + # FIXME, should this be in b_ldap? + # Experimenting to see what a plugin looks like for a 3rd party who can't + # modify the backend. + import ldap + return 'automountmapname=%s,%s,%s' % ( + ldap.dn.escape_dn_chars(mapname), + api.env.container_automount, + api.env.basedn, + ) + + +def make_ldap_map(ldapuri, mapname): + """ + Convert a map name into an LDAP name. + + Note: This is unused currently. This would return map names as a + quasi ldap URL which will work with older autofs clients. We are + not currently supporting them. + """ + if not ldapuri: + return mapname + if mapname.find('ldap:') >= 0: + return mapname + + return 'ldap:%s:%s' % (api.env.host, make_automount_dn(mapname)) + + +class automount(Object): + """ + Automount object. + """ + takes_params = ( + Str('automountmapname', + cli_name='mapname', + primary_key=True, + doc='A group of related automount objects', + ), + ) +api.register(automount) + + +class automount_addmap(crud.Add): + 'Add a new automount map.' + + takes_options = ( + Str('description?', + doc='A description of the automount map'), + ) + + def execute(self, mapname, **kw): + """ + Execute the automount-addmap operation. + + Returns the entry as it will be created in LDAP. + + :param mapname: The map name being added. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'automountmapname' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + kw['automountmapname'] = mapname + kw['dn'] = make_automount_dn(mapname) + + kw['objectclass'] = ['automountMap'] + + return ldap.create(**kw) + + def output_for_cli(self, textui, result, map, **options): + """ + Output result of this command to command line interface. + """ + textui.print_plain("Automount map %s added" % map) + +api.register(automount_addmap) + + +class automount_addkey(crud.Add): + 'Add a new automount key.' + takes_options = ( + Str('automountkey', + cli_name='key', + doc='An entry in an automount map'), + Str('automountinformation', + cli_name='info', + doc='Mount information for this key'), + Str('description?', + doc='A description of the mount'), + ) + + def execute(self, mapname, **kw): + """ + Execute the automount-addkey operation. + + Returns the entry as it will be created in LDAP. + + :param mapname: The map name being added to. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'automountmapname' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + config = ldap.get_ipa_config() + # use find_entry_dn instead of make_automap_dn so we can confirm that + # the map exists + map_dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) + kw['dn'] = "automountkey=%s,%s" % (kw['automountkey'], map_dn) + + kw['automountinformation'] = make_ldap_map(config.get('automountldapuri', False), kw['automountinformation']) + + kw['objectclass'] = ['automount'] + + return ldap.create(**kw) + + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + textui.print_plain("Automount key added") + +api.register(automount_addkey) + + +class automount_delmap(crud.Del): + 'Delete an automount map.' + def execute(self, mapname, **kw): + """Delete an automount map. This will also remove all of the keys + associated with this map. + + mapname is the automount map to remove + + :param mapname: The map to be removed + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) + + # First remove all the keys for this map so we don't leave orphans + keys = api.Command['automount_getkeys'](mapname) + for k in keys: + ldap.delete(k.get('dn')) + + # Now remove the parental connection + try: + infodn = ldap.find_entry_dn("automountinformation", mapname, "automount", api.env.container_automount) + ldap.delete(infodn) + except errors2.NotFound: + # direct maps may not have this + pass + + return ldap.delete(dn) + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + print "Automount map and associated keys deleted" + +api.register(automount_delmap) + + +class automount_delkey(crud.Del): + 'Delete an automount key.' + takes_options = ( + Str('automountkey', + cli_name='key', + doc='The automount key to remove'), + ) + def execute(self, mapname, **kw): + """Delete an automount key. + + key is the automount key to remove + + :param mapname: The automount map containing the key to be removed + :param kw: "key" the key to be removed + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) + keys = api.Command['automount_getkeys'](mapname) + keydn = None + keyname = kw.get('automountkey').lower() + if keys: + for k in keys: + if k.get('automountkey').lower() == keyname: + keydn = k.get('dn') + break + if not keydn: + raise errors2.NotFound(msg='Entry not found') + return ldap.delete(keydn) + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + print "Automount key deleted" + +api.register(automount_delkey) + +class automount_modmap(crud.Mod): + 'Edit an existing automount map.' + takes_options = ( + Str('description?', + doc='A description of the automount map'), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-modmap operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param mapname: The map name to update. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'automountmapname' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) + return ldap.update(dn, **kw) + + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + print "Automount map updated" + +api.register(automount_modmap) + + +class automount_modkey(crud.Mod): + 'Edit an existing automount key.' + takes_options = ( + Str('automountkey', + cli_name='key', + doc='An entry in an automount map'), + Str('automountinformation?', + cli_name='info', + doc='Mount information for this key'), + Str('description?', + doc='A description of the automount map'), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-modkey operation. + + Returns the entry + + :param mapname: The map name to update. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'automountmapname' not in kw + assert 'dn' not in kw + keyname = kw.get('automountkey').lower() + del kw['automountkey'] + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) + keys = api.Command['automount_getkeys'](mapname) + keydn = None + if keys: + for k in keys: + if k.get('automountkey').lower() == keyname: + keydn = k.get('dn') + break + if not keydn: + raise errors2.NotFound(msg='Entry not found') + return ldap.update(keydn, **kw) + + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + print "Automount key updated" + +api.register(automount_modkey) + + +class automount_findmap(crud.Find): + 'Search automount maps.' + takes_options = ( + Flag('all', doc='Retrieve all attributes'), + ) + def execute(self, term, **kw): + ldap = self.api.Backend.ldap + + search_fields = map_attributes + + for s in search_fields: + kw[s] = term + + kw['objectclass'] = 'automountMap' + kw['base'] = api.env.container_automount + if kw.get('all', False): + kw['attributes'] = ['*'] + else: + kw['attributes'] = map_attributes + return ldap.search(**kw) + + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + entries = result[1:] + if counter == 0: + textui.print_plain("No entries found") + return + elif counter == -1: + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") + + for e in entries: + display_entry(textui, e) + textui.print_plain("") + +api.register(automount_findmap) + + +class automount_findkey(crud.Find): + 'Search automount keys.' + takes_options = ( + Flag('all?', doc='Retrieve all attributes'), + ) + def get_args(self): + return (Str('automountkey', + cli_name='key', + doc='An entry in an automount map'),) + def execute(self, term, **kw): + ldap = self.api.Backend.ldap + + search_fields = key_attributes + + for s in search_fields: + kw[s] = term + + kw['objectclass'] = 'automount' + kw['base'] = api.env.container_automount + if kw.get('all', False): + kw['attributes'] = ['*'] + else: + kw['attributes'] = key_attributes + return ldap.search(**kw) + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + entries = result[1:] + if counter == 0: + textui.print_plain("No entries found") + return + elif counter == -1: + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") + + for e in entries: + display_entry(textui, e) + textui.print_plain("") + +api.register(automount_findkey) + + +class automount_showmap(crud.Get): + 'Examine an existing automount map.' + takes_options = ( + Flag('all?', doc='Retrieve all attributes'), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-showmap operation. + + Returns the entry + + :param mapname: The automount map to retrieve + :param kw: "all" set to True = return all attributes + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) + # FIXME: should kw contain the list of attributes to display? + if kw.get('all', False): + return ldap.retrieve(dn) + else: + return ldap.retrieve(dn, map_attributes) + def output_for_cli(self, textui, result, *args, **options): + if result: + display_entry(textui, result) + +api.register(automount_showmap) + + +class automount_showkey(crud.Get): + 'Examine an existing automount key.' + takes_options = ( + Str('automountkey', + cli_name='key', + doc='The automount key to display'), + Flag('all?', doc='Retrieve all attributes'), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-showkey operation. + + Returns the entry + + :param mapname: The mapname to examine + :param kw: "automountkey" the key to retrieve + :param kw: "all" set to True = return all attributes + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) + keys = api.Command['automount_getkeys'](mapname) + keyname = kw.get('automountkey').lower() + keydn = None + if keys: + for k in keys: + if k.get('automountkey').lower() == keyname: + keydn = k.get('dn') + break + if not keydn: + raise errors2.NotFound(msg='Entry not found') + # FIXME: should kw contain the list of attributes to display? + if kw.get('all', False): + return ldap.retrieve(keydn) + else: + return ldap.retrieve(keydn, key_attributes) + def output_for_cli(self, textui, result, *args, **options): + # The automount map name associated with this key is available only + # in the dn. Add it as an attribute to display instead. + if result and not result.get('automountmapname'): + elements = explode_dn(result.get('dn').lower()) + for e in elements: + (attr, value) = e.split('=',1) + if attr == 'automountmapname': + result['automountmapname'] = value + display_entry(textui, result) + +api.register(automount_showkey) + + +class automount_getkeys(Command): + 'Retrieve all keys for an automount map.' + takes_args = ( + Str('automountmapname', + cli_name='mapname', + primary_key=True, + doc='A group of related automount objects', + ), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-getkeys operation. + + Return a list of all automount keys for this mapname + + :param mapname: Retrieve all keys for this mapname + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) + try: + keys = ldap.get_one_entry(dn, 'objectclass=*', ['*']) + except errors2.NotFound: + keys = [] + + return keys + def output_for_cli(self, textui, result, *args, **options): + for k in result: + textui.print_plain('%s' % k.get('automountkey')) + +api.register(automount_getkeys) + + +class automount_getmaps(Command): + 'Retrieve all automount maps' + takes_args = ( + Str('automountmapname?', + cli_name='mapname', + primary_key=True, + doc='A group of related automount objects', + default=u'auto.master', + ), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-getmaps operation. + + Return a list of all automount maps. + """ + + ldap = self.api.Backend.ldap + base = api.env.container_automount + "," + api.env.basedn + + search_base = "automountmapname=%s,%s" % (mapname, base) + maps = ldap.get_one_entry(search_base, "objectClass=*", ["*"]) + + return maps + def output_for_cli(self, textui, result, *args, **options): + for k in result: + textui.print_plain('%s: %s' % (k.get('automountinformation'), k.get('automountkey'))) + +api.register(automount_getmaps) + +class automount_addindirectmap(crud.Add): + """ + Add a new automap indirect mount point. + """ + + takes_options = ( + Str('parentmap?', + cli_name='parentmap', + default=u'auto.master', + doc='The parent map to connect this to.', + ), + Str('automountkey', + cli_name='key', + doc='An entry in an automount map', + ), + Str('description?', + doc='A description of the automount map', + ), + ) + + def execute(self, mapname, **kw): + """ + Execute the automount-addindirectmap operation. + + Returns the key entry as it will be created in LDAP. + + This function creates 2 LDAP entries. It creates an + automountmapname entry and an automountkey entry. + + :param mapname: The map name being added. + :param kw['parentmap'] is the top-level map to add this to. + defaulting to auto.master + :param kw['automountkey'] is the mount point + :param kw['description'] is a textual description of this map + """ + mapkw = {} + if kw.get('description'): + mapkw['description'] = kw.get('description') + newmap = api.Command['automount_addmap'](mapname, **mapkw) + + keykw = {'automountkey': kw['automountkey'], 'automountinformation': mapname} + if kw.get('description'): + keykw['description'] = kw.get('description') + newkey = api.Command['automount_addkey'](kw['parentmap'], **keykw) + + return newkey + def output_for_cli(self, textui, result, map, **options): + """ + Output result of this command to command line interface. + """ + textui.print_plain("Indirect automount map %s added" % map) + +api.register(automount_addindirectmap) + + +class automount_tofiles(Command): + 'Generate the automount maps as they would be in the filesystem' + def execute(self, **kw): + """ + Execute the automount-getmaps operation. + + Return a list of all automount maps. + """ + + ldap = self.api.Backend.ldap + base = api.env.container_automount + "," + api.env.basedn + + search_base = "automountmapname=auto.master,%s" % base + maps = ldap.get_one_entry(search_base, "objectClass=autoMount", ["*"]) + + mapkeys = {} + for m in maps: + keys = api.Command['automount_getkeys'](m.get('automountinformation').decode('UTF-8')) + mapkeys[m.get('automountinformation')] = keys + + return maps, mapkeys + def output_for_cli(self, textui, result, **options): + maps = result[0] + keys = result[1] + textui.print_plain("/etc/auto.master:") + for m in maps: + textui.print_plain('%s\t/etc/%s' % (m.get('automountkey'), m.get('automountinformation'))) + for m in maps: + textui.print_plain('---------------------------') + textui.print_plain('/etc/%s:' % m.get('automountinformation')) + mapkeys = keys.get(m.get('automountinformation')) + for k in mapkeys: + textui.print_plain('%s\t%s' % (k.get('automountkey'), k.get('automountinformation'))) + +api.register(automount_tofiles) diff --git a/ipalib/plugins/b_kerberos.py b/ipalib/plugins/b_kerberos.py deleted file mode 100644 index cc8204976..000000000 --- a/ipalib/plugins/b_kerberos.py +++ /dev/null @@ -1,34 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# 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 - -""" -Backend plugin for Kerberos. - -This wraps the python-kerberos and python-krbV bindings. -""" - -from ipalib import api -from ipalib.backend import Backend - -class krb(Backend): - """ - Kerberos backend plugin. - """ - -api.register(krb) diff --git a/ipalib/plugins/defaultoptions.py b/ipalib/plugins/defaultoptions.py new file mode 100644 index 000000000..ea2af515d --- /dev/null +++ b/ipalib/plugins/defaultoptions.py @@ -0,0 +1,137 @@ +# Authors: +# Rob Crittenden +# +# 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 plugin for default options in IPA. +""" + +from ipalib import api +from ipalib import Command # Plugin base classes +from ipalib import Str, Int # Parameter types + + +class defaultoptions_mod(Command): + """ + Options command. + """ + takes_options = ( + Int('ipamaxusernamelength?', + cli_name='maxusername', + doc='Max. Username length', + minvalue=1 + ), + Str('ipahomesrootdir?', + cli_name='homedirectory', + doc='Default location of home directories' + ), + Str('ipadefaultloginshell?', + cli_name='defaultshell', + doc='Default shell for new users' + ), + Str('ipadefaultprimarygroup?', + cli_name='defaultgroup', + doc='Default group for new users' + ), + Str('ipadefaultemaildomain?', + cli_name='emaildomain', + doc='Default e-mail domain new users' + ), + Int('ipasearchtimelimit?', + cli_name='searchtimelimit', + doc='Max. amount of time (sec.) for a search (-1 is unlimited)', + minvalue=-1, + ), + Int('ipasearchrecordslimit?', + cli_name='searchrecordslimit', + doc='Max. number of records to search (-1 is unlimited)', + minvalue=-1, + ), + Str('ipausersearchfields?', + cli_name='usersearch', + doc='A comma-separated list of fields to search when searching for users' + ), + Str('ipagroupsearchfields?', + cli_name='groupsearch', + doc='A comma-separated list of fields to search when searching for groups' + ), + ) + def execute(self, *args, **kw): + """ + Execute the defaultoptions-mod operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param args: This function takes no positional arguments + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'dn' not in kw + ldap = self.api.Backend.ldap + config = ldap.get_ipa_config() + dn = config.get('dn') + + # The LDAP routines want strings, not ints, so convert a few + # things. Otherwise it sees a string -> int conversion as a change. + for k in kw.iterkeys(): + if k.startswith("ipa", 0, 3) and type(kw[k]) is int: + kw[k] = str(kw[k]) + + return ldap.update(dn, **kw) + + def output_for_cli(self, textui, result, *args, **options): + textui.print_plain("Default options modified") + +api.register(defaultoptions_mod) + +class defaultoptions_show(Command): + 'Retrieve current default options' + def execute(self, *args, **kw): + """ + Execute the defaultoptions-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param args: Not used. + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + return ldap.get_ipa_config() + + def output_for_cli(self, textui, result, *args, **options): + textui.print_plain("Search Configuration") + textui.print_plain(" Search Time Limit (sec.): %s" % result.get('ipasearchtimelimit')) + textui.print_plain(" Search Records Limit: %s" % result.get('ipasearchrecordslimit')) + textui.print_plain(" User Search Fields: %s" % result.get('ipausersearchfields')) + textui.print_plain(" Group Search Fields: %s" % result.get('ipagroupsearchfields')) + + textui.print_plain("") + + textui.print_plain("User Settings") + textui.print_plain(" Max. Username Length: %s" % result.get('ipamaxusernamelength')) + textui.print_plain(" Root for Home Directories: %s" % result.get('ipahomesrootdir')) + textui.print_plain(" Default Shell: %s" % result.get('ipadefaultloginshell')) + textui.print_plain(" Default User Group: %s" % result.get('ipadefaultprimarygroup')) + textui.print_plain("Default E-mail Domain: %s" % result.get('ipadefaultemaildomain')) + +api.register(defaultoptions_show) diff --git a/ipalib/plugins/delegation.py b/ipalib/plugins/delegation.py new file mode 100644 index 000000000..4c207b338 --- /dev/null +++ b/ipalib/plugins/delegation.py @@ -0,0 +1,64 @@ +# Authors: +# Rob Crittenden +# +# 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 delegations. +""" + +from ipalib import frontend +from ipalib import crud +from ipalib.frontend import Param +from ipalib import api + +class delegation(frontend.Object): + """ + Delegation object. + """ + takes_params = ( + 'attributes', + 'source', + 'target', + Param('name', primary_key=True) + ) +api.register(delegation) + + +class delegation_add(crud.Add): + 'Add a new delegation.' +api.register(delegation_add) + + +class delegation_del(crud.Del): + 'Delete an existing delegation.' +api.register(delegation_del) + + +class delegation_mod(crud.Mod): + 'Edit an existing delegation.' +api.register(delegation_mod) + + +class delegation_find(crud.Find): + 'Search for a delegation.' +api.register(delegation_find) + + +class delegation_show(crud.Get): + 'Examine an existing delegation.' +api.register(delegation_show) diff --git a/ipalib/plugins/f_application.py b/ipalib/plugins/f_application.py deleted file mode 100644 index 150dbe8e1..000000000 --- a/ipalib/plugins/f_application.py +++ /dev/null @@ -1,255 +0,0 @@ -# Authors: -# Jakub Hrozek -# -# 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 application policy containers. -""" - -from ipalib import api, crud -from ipalib import Object, Command # Plugin base classes -from ipalib import Str, StrEnum, Flag # Parameter types - -def get_base_by_type(type): - if type == 'config': - return api.env.container_applications - if type == 'role': - return api.env.container_roles - -class application(Object): - 'Application object' - takes_params = ( - Str('cn', - cli_name='appname', - primary_key=True, - doc='Application name', - ), - Str('description?', - doc='Application description', - ), - ) -api.register(application) - -# The default attributes to query -default_attributes = ['cn','description'] - -class application_create(crud.Create): - 'Add a new application' - takes_options = ( - StrEnum('type', - values=(u'config', u'role'), - doc='The type of the application', - ), - ) - - def execute(self, cn, **kw): - """ - Execute the application-create operation - - The dn should not be passed as a keyword argument, it - should be constructed by this method. - - :param cn: The name of the application being added. - :param kw: Keyword arguments for the other LDAP attributes. - """ - self.log.info("IPA: application-create '%s'" % cn) - - assert 'dn' not in kw - assert 'cn' not in kw - ldap = self.api.Backend.ldap - - kw['objectClass'] = ['nsContainer', 'ipaContainer'] - if kw['type'] == 'config': - kw['dn'] = ldap.make_application_dn(cn) - if kw['type'] == 'role': - kw['dn'] = ldap.make_role_application_dn(cn) - kw['cn'] = cn - - del kw['type'] - return ldap.create(**kw) - - def output_for_cli(self, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - textui.print_name(self.name) - textui.print_entry(result) - textui.print_dashed('Added application "%s"' % result['cn']) - -api.register(application_create) - -class application_find(crud.Search): - 'Search for applications' - takes_options = ( - StrEnum('type', - values=(u'config', u'role'), - doc='The type of the application', - ), - Flag('all', - doc='Retrieve all application attributes' - ), - ) - - def execute(self, term, **kw): - """ - Execute the application-find operation - """ - ldap = self.api.Backend.ldap - - search_kw = dict() - search_kw['cn'] = term - search_kw['objectclass'] = 'ipaContainer' - search_kw['base'] = get_base_by_type(kw['type']) - search_kw['scope'] = 'one' - if kw.get('all', False): - search_kw['attributes'] = ['*'] - else: - search_kw['attributes'] = default_attributes - - return ldap.search(**search_kw) - - def output_for_cli(self, textui, result, cn, **options): - """ - Output result of this command to command line interface. - """ - counter = result[0] - apps = result[1:] - if counter == 0 or len(apps) == 0: - textui.print_plain("No applications found") - return - if len(apps) == 1: - textui.print_entry(apps[0]) - return - textui.print_name(self.name) - for a in apps: - textui.print_plain('%(cn)s:' % a) - textui.print_entry(a) - textui.print_plain('') - if counter == -1: - textui.print_plain('These results are truncated.') - textui.print_plain('Please refine your search and try again.') - textui.print_count(apps, '%d applications matched') - -api.register(application_find) - -class application_delete(crud.Del): - 'Delete an application' - takes_options = ( - StrEnum('type', - values=(u'config', u'role'), - doc='The type of the application', - ), - ) - - def execute(self, cn, **kw): - """ - Delete the application container. - - :param cn: The name of the application being deleted. - :param kw: Not used. - """ - if cn == "Shell Applications": - raise SyntaxError("Cannot delete shell application") - self.log.info("IPA: application_delete '%s'" % cn) - - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("cn", - cn, - object_type='ipaContainer', - base=get_base_by_type(kw['type'])) - - return ldap.delete(dn) - - def output_for_cli(self, textui, result, cn): - """ - Output result of this command to command line interface. - """ - textui.print_plain('Deleted application "%s"' % cn) - -api.register(application_delete) - -class application_show(crud.Get): - 'Examine an existing application' - takes_options = ( - StrEnum('type', - values=(u'config', u'role'), - doc='The type of the application', - ), - Flag('all', - doc='Retrieve all application attributes' - ), - ) - def execute(self, cn, **kw): - """ - Execute the application-show operation. - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("cn", - cn, - object_type='ipaContainer', - base=get_base_by_type(kw['type'])) - - if kw.get('all', False): - return ldap.retrieve(dn) - else: - return ldap.retrieve(dn, default_attributes) - - def output_for_cli(self, textui, result, cn, **options): - if result: - textui.print_entry(result) - -api.register(application_show) - -class application_edit(crud.Mod): - 'Edit an existing application' - takes_options = ( - StrEnum('type', - values=(u'config', u'role'), - doc='The type of the application', - ), - ) - - def execute(self, cn, **kw): - """ - Execute the application-edit operation - - :param cn: The name of the application to edit - :param kw: Keyword arguments for the other LDAP attributes. - """ - self.log.info("IPA: application_edit '%s'" % cn) - - assert 'cn' not in kw - assert 'dn' not in kw - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("cn", - cn, - object_type='ipaContainer', - base=get_base_by_type(kw['type'])) - - del kw['type'] - return ldap.update(dn, **kw) - - def output_for_cli(self, textui, result, cn, **options): - """ - Output result of this command to command line interface. - """ - textui.print_name(self.name) - textui.print_entry(result) - textui.print_dashed('Updated application "%s"' % result['cn']) - -api.register(application_edit) diff --git a/ipalib/plugins/f_automount.py b/ipalib/plugins/f_automount.py deleted file mode 100644 index b25f512a5..000000000 --- a/ipalib/plugins/f_automount.py +++ /dev/null @@ -1,691 +0,0 @@ -# Authors: -# Rob Crittenden -# -# 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 automount. - -RFC 2707bis http://www.padl.com/~lukeh/rfc2307bis.txt - -A few notes on automount: -- It was a design decision to not support different maps by location -- The default parent when adding an indirect map is auto.master -- This uses the short format for automount maps instead of the - URL format. Support for ldap as a map source in nsswitch.conf was added - in autofs version 4.1.3-197. Any version prior to that is not expected - to work. - -As an example, the following automount files: - -auto.master: -/- auto.direct -/mnt auto.mnt - -auto.mnt: -stuff -ro,soft,rsize=8192,wsize=8192 nfs.example.com:/vol/archive/stuff - -are equivalent to the following LDAP entries: - -# auto.master, automount, example.com -dn: automountmapname=auto.master,cn=automount,dc=example,dc=com -objectClass: automountMap -objectClass: top -automountMapName: auto.master - -# auto.direct, automount, example.com -dn: automountmapname=auto.direct,cn=automount,dc=example,dc=com -objectClass: automountMap -objectClass: top -automountMapName: auto.direct - -# /-, auto.master, automount, example.com -dn: automountkey=/-,automountmapname=auto.master,cn=automount,dc=example,dc=co - m -objectClass: automount -objectClass: top -automountKey: /- -automountInformation: auto.direct - -# auto.mnt, automount, example.com -dn: automountmapname=auto.mnt,cn=automount,dc=example,dc=com -objectClass: automountMap -objectClass: top -automountMapName: auto.mnt - -# /mnt, auto.master, automount, example.com -dn: automountkey=/mnt,automountmapname=auto.master,cn=automount,dc=example,dc= - com -objectClass: automount -objectClass: top -automountKey: /mnt -automountInformation: auto.mnt - -# stuff, auto.mnt, automount, example.com -dn: automountkey=stuff,automountmapname=auto.mnt,cn=automount,dc=example,dc=com -objectClass: automount -objectClass: top -automountKey: stuff -automountInformation: -ro,soft,rsize=8192,wsize=8192 nfs.example.com:/vol/arch - ive/stuff - -""" - -from ldap import explode_dn -from ipalib import crud, errors2 -from ipalib import api, Str, Flag, Object, Command - -map_attributes = ['automountMapName', 'description', ] -key_attributes = ['description', 'automountKey', 'automountInformation'] - -def display_entry(textui, entry): - # FIXME: for now delete dn here. In the future pass in the kw to - # output_for_cli() - attr = sorted(entry.keys()) - - for a in attr: - if a != 'dn': - textui.print_plain("%s: %s" % (a, entry[a])) - -def make_automount_dn(mapname): - """ - Construct automount dn from map name. - """ - # FIXME, should this be in b_ldap? - # Experimenting to see what a plugin looks like for a 3rd party who can't - # modify the backend. - import ldap - return 'automountmapname=%s,%s,%s' % ( - ldap.dn.escape_dn_chars(mapname), - api.env.container_automount, - api.env.basedn, - ) - - -def make_ldap_map(ldapuri, mapname): - """ - Convert a map name into an LDAP name. - - Note: This is unused currently. This would return map names as a - quasi ldap URL which will work with older autofs clients. We are - not currently supporting them. - """ - if not ldapuri: - return mapname - if mapname.find('ldap:') >= 0: - return mapname - - return 'ldap:%s:%s' % (api.env.host, make_automount_dn(mapname)) - - -class automount(Object): - """ - Automount object. - """ - takes_params = ( - Str('automountmapname', - cli_name='mapname', - primary_key=True, - doc='A group of related automount objects', - ), - ) -api.register(automount) - - -class automount_addmap(crud.Add): - 'Add a new automount map.' - - takes_options = ( - Str('description?', - doc='A description of the automount map'), - ) - - def execute(self, mapname, **kw): - """ - Execute the automount-addmap operation. - - Returns the entry as it will be created in LDAP. - - :param mapname: The map name being added. - :param kw: Keyword arguments for the other LDAP attributes. - """ - assert 'automountmapname' not in kw - assert 'dn' not in kw - ldap = self.api.Backend.ldap - kw['automountmapname'] = mapname - kw['dn'] = make_automount_dn(mapname) - - kw['objectclass'] = ['automountMap'] - - return ldap.create(**kw) - - def output_for_cli(self, textui, result, map, **options): - """ - Output result of this command to command line interface. - """ - textui.print_plain("Automount map %s added" % map) - -api.register(automount_addmap) - - -class automount_addkey(crud.Add): - 'Add a new automount key.' - takes_options = ( - Str('automountkey', - cli_name='key', - doc='An entry in an automount map'), - Str('automountinformation', - cli_name='info', - doc='Mount information for this key'), - Str('description?', - doc='A description of the mount'), - ) - - def execute(self, mapname, **kw): - """ - Execute the automount-addkey operation. - - Returns the entry as it will be created in LDAP. - - :param mapname: The map name being added to. - :param kw: Keyword arguments for the other LDAP attributes. - """ - assert 'automountmapname' not in kw - assert 'dn' not in kw - ldap = self.api.Backend.ldap - config = ldap.get_ipa_config() - # use find_entry_dn instead of make_automap_dn so we can confirm that - # the map exists - map_dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) - kw['dn'] = "automountkey=%s,%s" % (kw['automountkey'], map_dn) - - kw['automountinformation'] = make_ldap_map(config.get('automountldapuri', False), kw['automountinformation']) - - kw['objectclass'] = ['automount'] - - return ldap.create(**kw) - - def output_for_cli(self, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - textui.print_plain("Automount key added") - -api.register(automount_addkey) - - -class automount_delmap(crud.Del): - 'Delete an automount map.' - def execute(self, mapname, **kw): - """Delete an automount map. This will also remove all of the keys - associated with this map. - - mapname is the automount map to remove - - :param mapname: The map to be removed - :param kw: Not used. - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) - - # First remove all the keys for this map so we don't leave orphans - keys = api.Command['automount_getkeys'](mapname) - for k in keys: - ldap.delete(k.get('dn')) - - # Now remove the parental connection - try: - infodn = ldap.find_entry_dn("automountinformation", mapname, "automount", api.env.container_automount) - ldap.delete(infodn) - except errors2.NotFound: - # direct maps may not have this - pass - - return ldap.delete(dn) - def output_for_cli(self, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - print "Automount map and associated keys deleted" - -api.register(automount_delmap) - - -class automount_delkey(crud.Del): - 'Delete an automount key.' - takes_options = ( - Str('automountkey', - cli_name='key', - doc='The automount key to remove'), - ) - def execute(self, mapname, **kw): - """Delete an automount key. - - key is the automount key to remove - - :param mapname: The automount map containing the key to be removed - :param kw: "key" the key to be removed - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) - keys = api.Command['automount_getkeys'](mapname) - keydn = None - keyname = kw.get('automountkey').lower() - if keys: - for k in keys: - if k.get('automountkey').lower() == keyname: - keydn = k.get('dn') - break - if not keydn: - raise errors2.NotFound(msg='Entry not found') - return ldap.delete(keydn) - def output_for_cli(self, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - print "Automount key deleted" - -api.register(automount_delkey) - -class automount_modmap(crud.Mod): - 'Edit an existing automount map.' - takes_options = ( - Str('description?', - doc='A description of the automount map'), - ) - def execute(self, mapname, **kw): - """ - Execute the automount-modmap operation. - - The dn should not be passed as a keyword argument as it is constructed - by this method. - - Returns the entry - - :param mapname: The map name to update. - :param kw: Keyword arguments for the other LDAP attributes. - """ - assert 'automountmapname' not in kw - assert 'dn' not in kw - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) - return ldap.update(dn, **kw) - - def output_for_cli(self, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - print "Automount map updated" - -api.register(automount_modmap) - - -class automount_modkey(crud.Mod): - 'Edit an existing automount key.' - takes_options = ( - Str('automountkey', - cli_name='key', - doc='An entry in an automount map'), - Str('automountinformation?', - cli_name='info', - doc='Mount information for this key'), - Str('description?', - doc='A description of the automount map'), - ) - def execute(self, mapname, **kw): - """ - Execute the automount-modkey operation. - - Returns the entry - - :param mapname: The map name to update. - :param kw: Keyword arguments for the other LDAP attributes. - """ - assert 'automountmapname' not in kw - assert 'dn' not in kw - keyname = kw.get('automountkey').lower() - del kw['automountkey'] - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) - keys = api.Command['automount_getkeys'](mapname) - keydn = None - if keys: - for k in keys: - if k.get('automountkey').lower() == keyname: - keydn = k.get('dn') - break - if not keydn: - raise errors2.NotFound(msg='Entry not found') - return ldap.update(keydn, **kw) - - def output_for_cli(self, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - print "Automount key updated" - -api.register(automount_modkey) - - -class automount_findmap(crud.Find): - 'Search automount maps.' - takes_options = ( - Flag('all', doc='Retrieve all attributes'), - ) - def execute(self, term, **kw): - ldap = self.api.Backend.ldap - - search_fields = map_attributes - - for s in search_fields: - kw[s] = term - - kw['objectclass'] = 'automountMap' - kw['base'] = api.env.container_automount - if kw.get('all', False): - kw['attributes'] = ['*'] - else: - kw['attributes'] = map_attributes - return ldap.search(**kw) - - def output_for_cli(self, textui, result, *args, **options): - counter = result[0] - entries = result[1:] - if counter == 0: - textui.print_plain("No entries found") - return - elif counter == -1: - textui.print_plain("These results are truncated.") - textui.print_plain("Please refine your search and try again.") - - for e in entries: - display_entry(textui, e) - textui.print_plain("") - -api.register(automount_findmap) - - -class automount_findkey(crud.Find): - 'Search automount keys.' - takes_options = ( - Flag('all?', doc='Retrieve all attributes'), - ) - def get_args(self): - return (Str('automountkey', - cli_name='key', - doc='An entry in an automount map'),) - def execute(self, term, **kw): - ldap = self.api.Backend.ldap - - search_fields = key_attributes - - for s in search_fields: - kw[s] = term - - kw['objectclass'] = 'automount' - kw['base'] = api.env.container_automount - if kw.get('all', False): - kw['attributes'] = ['*'] - else: - kw['attributes'] = key_attributes - return ldap.search(**kw) - def output_for_cli(self, textui, result, *args, **options): - counter = result[0] - entries = result[1:] - if counter == 0: - textui.print_plain("No entries found") - return - elif counter == -1: - textui.print_plain("These results are truncated.") - textui.print_plain("Please refine your search and try again.") - - for e in entries: - display_entry(textui, e) - textui.print_plain("") - -api.register(automount_findkey) - - -class automount_showmap(crud.Get): - 'Examine an existing automount map.' - takes_options = ( - Flag('all?', doc='Retrieve all attributes'), - ) - def execute(self, mapname, **kw): - """ - Execute the automount-showmap operation. - - Returns the entry - - :param mapname: The automount map to retrieve - :param kw: "all" set to True = return all attributes - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) - # FIXME: should kw contain the list of attributes to display? - if kw.get('all', False): - return ldap.retrieve(dn) - else: - return ldap.retrieve(dn, map_attributes) - def output_for_cli(self, textui, result, *args, **options): - if result: - display_entry(textui, result) - -api.register(automount_showmap) - - -class automount_showkey(crud.Get): - 'Examine an existing automount key.' - takes_options = ( - Str('automountkey', - cli_name='key', - doc='The automount key to display'), - Flag('all?', doc='Retrieve all attributes'), - ) - def execute(self, mapname, **kw): - """ - Execute the automount-showkey operation. - - Returns the entry - - :param mapname: The mapname to examine - :param kw: "automountkey" the key to retrieve - :param kw: "all" set to True = return all attributes - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) - keys = api.Command['automount_getkeys'](mapname) - keyname = kw.get('automountkey').lower() - keydn = None - if keys: - for k in keys: - if k.get('automountkey').lower() == keyname: - keydn = k.get('dn') - break - if not keydn: - raise errors2.NotFound(msg='Entry not found') - # FIXME: should kw contain the list of attributes to display? - if kw.get('all', False): - return ldap.retrieve(keydn) - else: - return ldap.retrieve(keydn, key_attributes) - def output_for_cli(self, textui, result, *args, **options): - # The automount map name associated with this key is available only - # in the dn. Add it as an attribute to display instead. - if result and not result.get('automountmapname'): - elements = explode_dn(result.get('dn').lower()) - for e in elements: - (attr, value) = e.split('=',1) - if attr == 'automountmapname': - result['automountmapname'] = value - display_entry(textui, result) - -api.register(automount_showkey) - - -class automount_getkeys(Command): - 'Retrieve all keys for an automount map.' - takes_args = ( - Str('automountmapname', - cli_name='mapname', - primary_key=True, - doc='A group of related automount objects', - ), - ) - def execute(self, mapname, **kw): - """ - Execute the automount-getkeys operation. - - Return a list of all automount keys for this mapname - - :param mapname: Retrieve all keys for this mapname - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) - try: - keys = ldap.get_one_entry(dn, 'objectclass=*', ['*']) - except errors2.NotFound: - keys = [] - - return keys - def output_for_cli(self, textui, result, *args, **options): - for k in result: - textui.print_plain('%s' % k.get('automountkey')) - -api.register(automount_getkeys) - - -class automount_getmaps(Command): - 'Retrieve all automount maps' - takes_args = ( - Str('automountmapname?', - cli_name='mapname', - primary_key=True, - doc='A group of related automount objects', - default=u'auto.master', - ), - ) - def execute(self, mapname, **kw): - """ - Execute the automount-getmaps operation. - - Return a list of all automount maps. - """ - - ldap = self.api.Backend.ldap - base = api.env.container_automount + "," + api.env.basedn - - search_base = "automountmapname=%s,%s" % (mapname, base) - maps = ldap.get_one_entry(search_base, "objectClass=*", ["*"]) - - return maps - def output_for_cli(self, textui, result, *args, **options): - for k in result: - textui.print_plain('%s: %s' % (k.get('automountinformation'), k.get('automountkey'))) - -api.register(automount_getmaps) - -class automount_addindirectmap(crud.Add): - """ - Add a new automap indirect mount point. - """ - - takes_options = ( - Str('parentmap?', - cli_name='parentmap', - default=u'auto.master', - doc='The parent map to connect this to.', - ), - Str('automountkey', - cli_name='key', - doc='An entry in an automount map', - ), - Str('description?', - doc='A description of the automount map', - ), - ) - - def execute(self, mapname, **kw): - """ - Execute the automount-addindirectmap operation. - - Returns the key entry as it will be created in LDAP. - - This function creates 2 LDAP entries. It creates an - automountmapname entry and an automountkey entry. - - :param mapname: The map name being added. - :param kw['parentmap'] is the top-level map to add this to. - defaulting to auto.master - :param kw['automountkey'] is the mount point - :param kw['description'] is a textual description of this map - """ - mapkw = {} - if kw.get('description'): - mapkw['description'] = kw.get('description') - newmap = api.Command['automount_addmap'](mapname, **mapkw) - - keykw = {'automountkey': kw['automountkey'], 'automountinformation': mapname} - if kw.get('description'): - keykw['description'] = kw.get('description') - newkey = api.Command['automount_addkey'](kw['parentmap'], **keykw) - - return newkey - def output_for_cli(self, textui, result, map, **options): - """ - Output result of this command to command line interface. - """ - textui.print_plain("Indirect automount map %s added" % map) - -api.register(automount_addindirectmap) - - -class automount_tofiles(Command): - 'Generate the automount maps as they would be in the filesystem' - def execute(self, **kw): - """ - Execute the automount-getmaps operation. - - Return a list of all automount maps. - """ - - ldap = self.api.Backend.ldap - base = api.env.container_automount + "," + api.env.basedn - - search_base = "automountmapname=auto.master,%s" % base - maps = ldap.get_one_entry(search_base, "objectClass=autoMount", ["*"]) - - mapkeys = {} - for m in maps: - keys = api.Command['automount_getkeys'](m.get('automountinformation').decode('UTF-8')) - mapkeys[m.get('automountinformation')] = keys - - return maps, mapkeys - def output_for_cli(self, textui, result, **options): - maps = result[0] - keys = result[1] - textui.print_plain("/etc/auto.master:") - for m in maps: - textui.print_plain('%s\t/etc/%s' % (m.get('automountkey'), m.get('automountinformation'))) - for m in maps: - textui.print_plain('---------------------------') - textui.print_plain('/etc/%s:' % m.get('automountinformation')) - mapkeys = keys.get(m.get('automountinformation')) - for k in mapkeys: - textui.print_plain('%s\t%s' % (k.get('automountkey'), k.get('automountinformation'))) - -api.register(automount_tofiles) diff --git a/ipalib/plugins/f_defaultoptions.py b/ipalib/plugins/f_defaultoptions.py deleted file mode 100644 index ea2af515d..000000000 --- a/ipalib/plugins/f_defaultoptions.py +++ /dev/null @@ -1,137 +0,0 @@ -# Authors: -# Rob Crittenden -# -# 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 plugin for default options in IPA. -""" - -from ipalib import api -from ipalib import Command # Plugin base classes -from ipalib import Str, Int # Parameter types - - -class defaultoptions_mod(Command): - """ - Options command. - """ - takes_options = ( - Int('ipamaxusernamelength?', - cli_name='maxusername', - doc='Max. Username length', - minvalue=1 - ), - Str('ipahomesrootdir?', - cli_name='homedirectory', - doc='Default location of home directories' - ), - Str('ipadefaultloginshell?', - cli_name='defaultshell', - doc='Default shell for new users' - ), - Str('ipadefaultprimarygroup?', - cli_name='defaultgroup', - doc='Default group for new users' - ), - Str('ipadefaultemaildomain?', - cli_name='emaildomain', - doc='Default e-mail domain new users' - ), - Int('ipasearchtimelimit?', - cli_name='searchtimelimit', - doc='Max. amount of time (sec.) for a search (-1 is unlimited)', - minvalue=-1, - ), - Int('ipasearchrecordslimit?', - cli_name='searchrecordslimit', - doc='Max. number of records to search (-1 is unlimited)', - minvalue=-1, - ), - Str('ipausersearchfields?', - cli_name='usersearch', - doc='A comma-separated list of fields to search when searching for users' - ), - Str('ipagroupsearchfields?', - cli_name='groupsearch', - doc='A comma-separated list of fields to search when searching for groups' - ), - ) - def execute(self, *args, **kw): - """ - Execute the defaultoptions-mod operation. - - The dn should not be passed as a keyword argument as it is constructed - by this method. - - Returns the entry - - :param args: This function takes no positional arguments - :param kw: Keyword arguments for the other LDAP attributes. - """ - assert 'dn' not in kw - ldap = self.api.Backend.ldap - config = ldap.get_ipa_config() - dn = config.get('dn') - - # The LDAP routines want strings, not ints, so convert a few - # things. Otherwise it sees a string -> int conversion as a change. - for k in kw.iterkeys(): - if k.startswith("ipa", 0, 3) and type(kw[k]) is int: - kw[k] = str(kw[k]) - - return ldap.update(dn, **kw) - - def output_for_cli(self, textui, result, *args, **options): - textui.print_plain("Default options modified") - -api.register(defaultoptions_mod) - -class defaultoptions_show(Command): - 'Retrieve current default options' - def execute(self, *args, **kw): - """ - Execute the defaultoptions-show operation. - - The dn should not be passed as a keyword argument as it is constructed - by this method. - - Returns the entry - - :param args: Not used. - :param kw: Not used. - """ - ldap = self.api.Backend.ldap - return ldap.get_ipa_config() - - def output_for_cli(self, textui, result, *args, **options): - textui.print_plain("Search Configuration") - textui.print_plain(" Search Time Limit (sec.): %s" % result.get('ipasearchtimelimit')) - textui.print_plain(" Search Records Limit: %s" % result.get('ipasearchrecordslimit')) - textui.print_plain(" User Search Fields: %s" % result.get('ipausersearchfields')) - textui.print_plain(" Group Search Fields: %s" % result.get('ipagroupsearchfields')) - - textui.print_plain("") - - textui.print_plain("User Settings") - textui.print_plain(" Max. Username Length: %s" % result.get('ipamaxusernamelength')) - textui.print_plain(" Root for Home Directories: %s" % result.get('ipahomesrootdir')) - textui.print_plain(" Default Shell: %s" % result.get('ipadefaultloginshell')) - textui.print_plain(" Default User Group: %s" % result.get('ipadefaultprimarygroup')) - textui.print_plain("Default E-mail Domain: %s" % result.get('ipadefaultemaildomain')) - -api.register(defaultoptions_show) diff --git a/ipalib/plugins/f_delegation.py b/ipalib/plugins/f_delegation.py deleted file mode 100644 index 4c207b338..000000000 --- a/ipalib/plugins/f_delegation.py +++ /dev/null @@ -1,64 +0,0 @@ -# Authors: -# Rob Crittenden -# -# 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 delegations. -""" - -from ipalib import frontend -from ipalib import crud -from ipalib.frontend import Param -from ipalib import api - -class delegation(frontend.Object): - """ - Delegation object. - """ - takes_params = ( - 'attributes', - 'source', - 'target', - Param('name', primary_key=True) - ) -api.register(delegation) - - -class delegation_add(crud.Add): - 'Add a new delegation.' -api.register(delegation_add) - - -class delegation_del(crud.Del): - 'Delete an existing delegation.' -api.register(delegation_del) - - -class delegation_mod(crud.Mod): - 'Edit an existing delegation.' -api.register(delegation_mod) - - -class delegation_find(crud.Find): - 'Search for a delegation.' -api.register(delegation_find) - - -class delegation_show(crud.Get): - 'Examine an existing delegation.' -api.register(delegation_show) diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py deleted file mode 100644 index 33cc98f4c..000000000 --- a/ipalib/plugins/f_host.py +++ /dev/null @@ -1,287 +0,0 @@ -# Authors: -# Rob Crittenden -# -# 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 api, crud, errors2, util -from ipalib import Object # Plugin base class -from ipalib import Str, Flag # Parameter 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 errors2.NotFound: - dn = ldap.find_entry_dn("serverhostname", hostname, "ipaHost") - return dn - -def validate_host(ugettext, 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 - -default_attributes = ['cn','description','localityname','nshostlocation','nshardwareplatform','nsosversion'] - -class host(Object): - """ - Host object. - """ - takes_params = ( - Str('cn', validate_host, - cli_name='hostname', - primary_key=True, - normalizer=lambda value: value.lower(), - ), - Str('description?', - doc='Description of the host', - ), - Str('localityname?', - cli_name='locality', - doc='Locality of this host (Baltimore, MD)', - ), - Str('nshostlocation?', - cli_name='location', - doc='Location of this host (e.g. Lab 2)', - ), - Str('nshardwareplatform?', - cli_name='platform', - doc='Hardware platform of this host (e.g. Lenovo T61)', - ), - Str('nsosversion?', - cli_name='os', - doc='Operating System and version on this host (e.g. Fedora 9)', - ), - Str('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. - - If password is set then this is considered a 'bulk' host so we - do not create a kerberos service principal. - - 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 - assert 'krbprincipalname' not in kw - ldap = self.api.Backend.ldap - - kw['cn'] = hostname - kw['serverhostname'] = hostname.split('.',1)[0] - kw['dn'] = ldap.make_host_dn(hostname) - - # FIXME: do a DNS lookup to ensure host exists - - current = util.get_current_principal() - if not current: - raise errors2.NotFound('Unable to determine current user') - kw['enrolledby'] = ldap.find_entry_dn("krbPrincipalName", current, "posixAccount") - - # 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', 'ipaHost', 'pkiUser'] - - # Ensure the list of objectclasses is lower-case - kw['objectclass'] = map(lambda z: z.lower(), kw.get('objectclass')) - - if not kw.get('userpassword', False): - kw['krbprincipalname'] = "host/%s@%s" % (hostname, self.api.env.realm) - - if 'krbprincipalaux' not in kw.get('objectclass'): - kw['objectclass'].append('krbprincipalaux') - kw['objectclass'].append('krbprincipal') - else: - if 'krbprincipalaux' in kw.get('objectclass'): - kw['objectclass'].remove('krbprincipalaux') - - return ldap.create(**kw) - def output_for_cli(self, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - textui.print_plain("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, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - textui.print_plain("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, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - textui.print_plain("Host updated") - -api.register(host_mod) - - -class host_find(crud.Find): - 'Search the hosts.' - - takes_options = ( - Flag('all', doc='Retrieve all attributes'), - ) - - # FIXME: This should no longer be needed with the Param.query kwarg. -# 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'] - - search_kw = {} - for s in search_fields: - search_kw[s] = term - - # Can't use ldap.get_object_type() since cn is also used for group dns - search_kw['objectclass'] = "ipaHost" - if kw.get('all', False): - search_kw['attributes'] = ['*'] - else: - search_kw['attributes'] = default_attributes - return ldap.search(**search_kw) - def output_for_cli(self, textui, result, *args, **options): - counter = result[0] - hosts = result[1:] - if counter == 0: - textui.print_plain("No entries found") - return - - for h in hosts: - textui.print_entry(h) - if counter == -1: - textui.print_plain("These results are truncated.") - textui.print_plain("Please refine your search and try again.") -api.register(host_find) - - -class host_show(crud.Get): - 'Examine an existing host.' - takes_options = ( - Flag('all', 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, default_attributes) - del value['dn'] - return value - def output_for_cli(self, textui, result, *args, **options): - textui.print_entry(result) - -api.register(host_show) diff --git a/ipalib/plugins/f_passwd.py b/ipalib/plugins/f_passwd.py deleted file mode 100644 index a599276f4..000000000 --- a/ipalib/plugins/f_passwd.py +++ /dev/null @@ -1,71 +0,0 @@ -# Authors: -# Rob Crittenden -# -# 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 password changes. -""" - -from ipalib import api, errors, util -from ipalib import Command # Plugin base classes -from ipalib import Str, Password # Parameter types - - -class passwd(Command): - 'Edit existing password policy.' - - takes_args = ( - Password('password'), - Str('principal?', - cli_name='user', - primary_key=True, - autofill=True, - default_from=util.get_current_principal, - ), - ) - - def execute(self, principal, password): - """ - Execute the passwd operation. - - The dn should not be passed as a keyword argument as it is constructed - by this method. - - Returns the entry - - :param param uid: The login name of the user being updated. - :param kw: Not used. - """ - if principal.find('@') > 0: - u = principal.split('@') - if len(u) > 2: - raise errors.InvalidUserPrincipal(principal) - else: - principal = principal+"@"+self.api.env.realm - dn = self.Backend.ldap.find_entry_dn( - "krbprincipalname", - principal, - "posixAccount" - ) - return self.Backend.ldap.modify_password(dn, newpass=password) - - def output_for_cli(self, textui, result, principal, password): - assert password is None - textui.print_plain('Changed password for "%s"' % principal) - -api.register(passwd) diff --git a/ipalib/plugins/f_pwpolicy.py b/ipalib/plugins/f_pwpolicy.py deleted file mode 100644 index f18160b65..000000000 --- a/ipalib/plugins/f_pwpolicy.py +++ /dev/null @@ -1,127 +0,0 @@ -# Authors: -# Rob Crittenden -# -# 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 password policy. -""" - -from ipalib import api -from ipalib import Command # Plugin base classes -from ipalib import Int # Parameter types - - -class pwpolicy_mod(Command): - 'Edit existing password policy.' - takes_options = ( - Int('krbmaxpwdlife?', - cli_name='maxlife', - doc='Max. Password Lifetime (days)', - minvalue=0, - ), - Int('krbminpwdlife?', - cli_name='minlife', - doc='Min. Password Lifetime (hours)', - minvalue=0, - ), - Int('krbpwdhistorylength?', - cli_name='history', - doc='Password History Size', - minvalue=0, - ), - Int('krbpwdmindiffchars?', - cli_name='minclasses', - doc='Min. Number of Character Classes', - minvalue=0, - ), - Int('krbpwdminlength?', - cli_name='minlength', - doc='Min. Length of Password', - minvalue=0, - ), - ) - def execute(self, *args, **kw): - """ - Execute the pwpolicy-mod operation. - - The dn should not be passed as a keyword argument as it is constructed - by this method. - - Returns the entry - - :param args: This function takes no positional arguments - :param kw: Keyword arguments for the other LDAP attributes. - """ - assert 'dn' not in kw - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("cn", "accounts", "krbPwdPolicy") - - # The LDAP routines want strings, not ints, so convert a few - # things. Otherwise it sees a string -> int conversion as a change. - for k in kw.iterkeys(): - if k.startswith("krb", 0, 3) and type(kw[k]) is int: - kw[k] = str(kw[k]) - - # Convert hours and days to seconds - if kw.get('krbmaxpwdlife'): - kw['krbmaxpwdlife'] = str(int(kw.get('krbmaxpwdlife')) * 86400) - if kw.get('krbminpwdlife'): - kw['krbminpwdlife'] = str(int(kw.get('krbminpwdlife')) * 3600) - - return ldap.update(dn, **kw) - - def output_for_cli(self, textui, result, *args, **options): - textui.print_plain("Policy modified") - -api.register(pwpolicy_mod) - - -class pwpolicy_show(Command): - 'Retrieve current password policy' - def execute(self, *args, **kw): - """ - Execute the pwpolicy-show operation. - - The dn should not be passed as a keyword argument as it is constructed - by this method. - - Returns the entry - - :param args: Not used. - :param kw: Not used. - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("cn", "accounts", "krbPwdPolicy") - - policy = ldap.retrieve(dn) - - # convert some values for display purposes - policy['krbmaxpwdlife'] = str(int(policy.get('krbmaxpwdlife')) / 86400) - policy['krbminpwdlife'] = str(int(policy.get('krbminpwdlife')) / 3600) - - return policy - - def output_for_cli(self, textui, result, *args, **options): - textui.print_plain("Password Policy") - textui.print_plain("Min. Password Lifetime (hours): %s" % result.get('krbminpwdlife')) - textui.print_plain("Max. Password Lifetime (days): %s" % result.get('krbmaxpwdlife')) - textui.print_plain("Min. Number of Character Classes: %s" % result.get('krbpwdmindiffchars')) - textui.print_plain("Min. Length of Password: %s" % result.get('krbpwdminlength')) - textui.print_plain("Password History Size: %s" % result.get('krbpwdhistorylength')) - -api.register(pwpolicy_show) diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py deleted file mode 100644 index 4c6f5bd80..000000000 --- a/ipalib/plugins/f_service.py +++ /dev/null @@ -1,220 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# Rob Crittenden -# -# 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 service (Identity). -""" - -from ipalib import api, crud, errors2 -from ipalib import Object # Plugin base classes -from ipalib import Str, Flag # Parameter types - -default_attributes = ['krbprincipalname'] - -class service(Object): - """ - Service object. - """ - takes_params = ( - Str('principal', primary_key=True), - ) -api.register(service) - - -class service_add(crud.Add): - """ - Add a new service. - """ - - takes_options = ( - Flag('force', - doc='Force a service principal name', - ), - ) - def execute(self, principal, **kw): - """ - Execute the service-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 principal: The service to be added in the form: service/hostname - :param kw: Keyword arguments for the other LDAP attributes. - """ - assert 'krbprincipalname' not in kw - ldap = self.api.Backend.ldap - - force = kw.get('force', False) - try: - del kw['force'] - except: - pass - - # Break down the principal into its component parts, which may or - # may not include the realm. - sp = principal.split('/') - if len(sp) != 2: - raise errors2.MalformedServicePrincipal - service = sp[0] - - if service.lower() == "host": - raise errors2.HostService - - sr = sp[1].split('@') - if len(sr) == 1: - hostname = sr[0].lower() - realm = self.api.env.realm - elif len(sr) == 2: - hostname = sr[0].lower() - realm = sr[1] - else: - raise errors2.MalformedServicePrincipal - - """ - FIXME once DNS client is done - if not force: - fqdn = hostname + "." - rs = dnsclient.query(fqdn, dnsclient.DNS_C_IN, dnsclient.DNS_T_A) - if len(rs) == 0: - self.log.debug("IPA: DNS A record lookup failed for '%s'" % hostname) - raise ipaerror.gen_exception(ipaerror.INPUT_NOT_DNS_A_RECORD) - else: - self.log.debug("IPA: found %d records for '%s'" % (len(rs), hostname)) - """ - - # At some point we'll support multiple realms - if (realm != self.api.env.realm): - raise errors2.RealmMismatch - - # Put the principal back together again - princ_name = service + "/" + hostname + "@" + realm - - dn = ldap.make_service_dn(princ_name) - - kw['dn'] = dn - kw['objectclass'] = ['krbPrincipal', 'krbPrincipalAux', 'krbTicketPolicyAux'] - - return ldap.create(**kw) - - def output_to_cli(self, ret): - textui.print_plain("Service added") - -api.register(service_add) - - -class service_del(crud.Del): - 'Delete an existing service.' - def execute(self, principal, **kw): - """ - Delete a service principal. - - principal is the krbprincipalname of the entry to delete. - - This should be called with much care. - - :param principal: The service to be added in the form: service/hostname - :param kw: not used - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("krbprincipalname", principal) - return ldap.delete(dn) - - def output_to_cli(self, ret): - textui.print_plain("Service removed") - -api.register(service_del) - -# There is no service-mod. The principal itself contains nothing that -# is user-changeable - -class service_find(crud.Find): - 'Search the existing services.' - takes_options = ( - Flag('all', doc='Retrieve all attributes'), - ) - def execute(self, principal, **kw): - ldap = self.api.Backend.ldap - - search_kw = {} - search_kw['filter'] = "&(objectclass=krbPrincipalAux)(!(objectClass=posixAccount))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))" - search_kw['krbprincipalname'] = principal - - object_type = ldap.get_object_type("krbprincipalname") - if object_type and not kw.get('objectclass'): - search_kw['objectclass'] = object_type - - if kw.get('all', False): - search_kw['attributes'] = ['*'] - else: - search_kw['attributes'] = default_attributes - - return ldap.search(**search_kw) - - def output_for_cli(self, textui, result, *args, **options): - counter = result[0] - services = result[1:] - if counter == 0: - textui.print_plain("No entries found") - return - - for s in services: - textui.print_entry(s) - - if counter == -1: - textui.print_plain("These results are truncated.") - textui.print_plain("Please refine your search and try again.") - textui.print_count(services, '%d services matched') - -api.register(service_find) - - -class service_show(crud.Get): - 'Examine an existing service.' - takes_options = ( - Flag('all', doc='Display all service attributes'), - ) - def execute(self, principal, **kw): - """ - Execute the service-show operation. - - The dn should not be passed as a keyword argument as it is constructed - by this method. - - Returns the entry - - :param principal: The service principal to retrieve - :param kw: Not used. - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("krbprincipalname", principal) - # FIXME: should kw contain the list of attributes to display? - if kw.get('all', False): - return ldap.retrieve(dn) - else: - value = ldap.retrieve(dn, default_attributes) - del value['dn'] - return value - - def output_for_cli(self, textui, result, *args, **options): - textui.print_entry(result) - -api.register(service_show) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py deleted file mode 100644 index e4e1cdaf1..000000000 --- a/ipalib/plugins/f_user.py +++ /dev/null @@ -1,383 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# 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 user (Identity). -""" - -from ipalib import api, crud, errors2 -from ipalib import Object, Command # Plugin base classes -from ipalib import Str, Password, Flag, Int # Parameter types - - -def display_user(user): - # FIXME: for now delete dn here. In the future pass in the kw to - # output_for_cli() - attr = sorted(user.keys()) - # Always have sn following givenname - try: - l = attr.index('givenname') - attr.remove('sn') - attr.insert(l+1, 'sn') - except ValueError: - pass - - for a in attr: - if a != 'dn': - print "%s: %s" % (a, user[a]) - -default_attributes = ['uid','givenname','sn','homeDirectory','loginshell'] - - -class user(Object): - """ - User object. - """ - - takes_params = ( - Str('givenname', - cli_name='first', - doc="User's first name", - ), - Str('sn', - cli_name='last', - doc="User's last name", - ), - Str('uid', - cli_name='user', - doc="User's login name", - primary_key=True, - default_from=lambda givenname, sn: givenname[0] + sn, - normalizer=lambda value: value.lower(), - ), - Str('gecos?', - doc='GECOS field', - default_from=lambda uid: uid, - ), - Str('homedirectory?', - cli_name='home', - doc="User's home directory", - default_from=lambda uid: '/home/%s' % uid, - ), - Str('loginshell?', - cli_name='shell', - default=u'/bin/sh', - doc="User's Login shell", - ), - Str('krbprincipalname?', - cli_name='principal', - doc="User's Kerberos Principal name", - default_from=lambda uid: '%s@%s' % (uid, api.env.realm), - ), - Str('mailaddress?', - cli_name='email', - doc="User's e-mail address", - ), - Password('userpassword?', - cli_name='password', - doc="Set user's password", - ), - Str('groups?', - doc='Add account to one or more groups (comma-separated)', - ), - Int('uidnumber?', - cli_name='uid', - doc='The uid to use for this user. If not included one is automatically set.', - ), - Str('street?', - doc='The street address', - ), - ) - -api.register(user) - - -class user_add(crud.Create): - """ - Add a new user. - """ - - def execute(self, uid, **kw): - """ - Execute the user-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 uid: The login name of the user being added. - :param kw: Keyword arguments for the other LDAP attributes. - """ - assert 'uid' not in kw - assert 'dn' not in kw - ldap = self.api.Backend.ldap - kw['uid'] = uid - kw['dn'] = ldap.make_user_dn(uid) - default_group = None - - # FIXME: enforce this elsewhere -# if servercore.uid_too_long(kw['uid']): -# raise errors.UsernameTooLong - - # Get our configuration - config = ldap.get_ipa_config() - - # Let us add in some missing attributes - if kw.get('homedirectory') is None: - kw['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), kw.get('uid')) - kw['homedirectory'] = kw['homedirectory'].replace('//', '/') - kw['homedirectory'] = kw['homedirectory'].rstrip('/') - if kw.get('loginshell') is None: - kw['loginshell'] = config.get('ipadefaultloginshell') - if kw.get('gecos') is None: - kw['gecos'] = kw['uid'] - - # If uidnumber is blank the the FDS dna_plugin will automatically - # assign the next value. So we don't have to do anything with it. - - if not kw.get('gidnumber'): - try: - group_dn = ldap.find_entry_dn("cn", config.get('ipadefaultprimarygroup')) - default_group = ldap.retrieve(group_dn, ['cn', 'dn','gidNumber']) - if default_group: - kw['gidnumber'] = default_group.get('gidnumber') - except errors2.NotFound: - # Fake an LDAP error so we can return something useful to the kw - raise errors2.NotFound("The default group for new users, '%s', cannot be found." % config.get('ipadefaultprimarygroup')) - except Exception, e: - # catch everything else - raise e - - if kw.get('krbprincipalname') is None: - kw['krbprincipalname'] = "%s@%s" % (kw.get('uid'), self.api.env.realm) - - # FIXME. This is a hack so we can request separate First and Last - # name in the GUI. - if kw.get('cn') is None: - kw['cn'] = "%s %s" % (kw.get('givenname'), - kw.get('sn')) - - # some required objectclasses - kw['objectClass'] = config.get('ipauserobjectclasses') - - new_user = ldap.create(**kw) - - if default_group: - groupkw = {'users':kw.get('uid')} - api.Command['group_add_member'](default_group['cn'].decode('UTF-8'), **groupkw) - - return new_user - - def output_for_cli(self, textui, result, *args, **options): - """ - Output result of this command to command line interface. - """ - textui.print_name(self.name) - textui.print_entry(result) - textui.print_dashed('Added user "%s"' % result['uid']) - -api.register(user_add) - - -class user_del(crud.Delete): - 'Delete an existing user.' - - def execute(self, uid): - """Delete a user. Not to be confused with inactivate_user. This - makes the entry go away completely. - - uid is the uid of the user to delete - - The memberOf plugin handles removing the user from any other - groups. - - :param uid: The login name of the user being added. - :param kw: Not used. - """ - if uid == "admin": - # FIXME: do we still want a "special" user? - raise SyntaxError("admin required") -# raise ipaerror.gen_exception(ipaerror.INPUT_ADMIN_REQUIRED) - self.log.info("IPA: user-del '%s'" % uid) - - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid) - return ldap.delete(dn) - - def output_for_cli(self, textui, result, uid): - """ - Output result of this command to command line interface. - """ - textui.print_plain('Deleted user "%s"' % uid) - -api.register(user_del) - - -class user_mod(crud.Update): - 'Edit an existing user.' - def execute(self, uid, **kw): - """ - Execute the user-mod operation. - - The dn should not be passed as a keyword argument as it is constructed - by this method. - - Returns the entry - - :param uid: The login name of the user to retrieve. - :param kw: Keyword arguments for the other LDAP attributes. - """ - assert 'uid' not in kw - assert 'dn' not in kw - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid) - return ldap.update(dn, **kw) - - def output_for_cli(self, textui, result, uid, **options): - """ - Output result of this command to command line interface. - """ - textui.print_name(self.name) - textui.print_entry(result) - textui.print_dashed('Updated user "%s"' % result['uid']) - -api.register(user_mod) - - -class user_find(crud.Search): - """ - Search for users. - """ - - takes_options = ( - Flag('all', doc='Retrieve all user attributes'), - ) - - 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() - search_fields_conf_str = config.get('ipausersearchfields') - search_fields = search_fields_conf_str.split(",") - - search_kw = {} - for s in search_fields: - search_kw[s] = term - - object_type = ldap.get_object_type("uid") - if object_type and not kw.get('objectclass'): - search_kw['objectclass'] = object_type - if kw.get('all', False): - search_kw['attributes'] = ['*'] - else: - search_kw['attributes'] = default_attributes - return ldap.search(**search_kw) - - def output_for_cli(self, textui, result, uid, **options): - counter = result[0] - users = result[1:] - if counter == 0 or len(users) == 0: - textui.print_plain("No entries found") - return - if len(users) == 1: - textui.print_entry(users[0]) - return - textui.print_name(self.name) - for u in users: - gn = u.get('givenname', '') - sn= u.get('sn', '') - textui.print_plain('%s %s:' % (gn, sn)) - textui.print_entry(u) - textui.print_plain('') - if counter == -1: - textui.print_plain('These results are truncated.') - textui.print_plain('Please refine your search and try again.') - textui.print_count(users, '%d users matched') - -api.register(user_find) - - -class user_show(crud.Retrieve): - 'Examine an existing user.' - takes_options = ( - Flag('all', doc='Retrieve all user attributes'), - ) - def execute(self, uid, **kw): - """ - Execute the user-show operation. - - The dn should not be passed as a keyword argument as it is constructed - by this method. - - Returns the entry - - :param uid: The login name of the user to retrieve. - :param kw: "all" set to True = return all attributes - """ - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid) - # FIXME: should kw contain the list of attributes to display? - if kw.get('all', False): - return ldap.retrieve(dn) - else: - return ldap.retrieve(dn, default_attributes) - - def output_for_cli(self, textui, result, uid, **options): - display_user(result) - -api.register(user_show) - -class user_lock(Command): - 'Lock a user account.' - - takes_args = ( - Str('uid', primary_key=True), - ) - - def execute(self, uid, **kw): - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid) - return ldap.mark_entry_inactive(dn) - - def output_for_cli(self, textui, result, uid): - if result: - textui.print_plain('Locked user "%s"' % uid) - -api.register(user_lock) - - -class user_unlock(Command): - 'Unlock a user account.' - - takes_args = ( - Str('uid', primary_key=True), - ) - - def execute(self, uid, **kw): - ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid) - return ldap.mark_entry_active(dn) - - def output_for_cli(self, textui, result, uid): - if result: - textui.print_plain('Unlocked user "%s"' % uid) - -api.register(user_unlock) diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py new file mode 100644 index 000000000..33cc98f4c --- /dev/null +++ b/ipalib/plugins/host.py @@ -0,0 +1,287 @@ +# Authors: +# Rob Crittenden +# +# 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 api, crud, errors2, util +from ipalib import Object # Plugin base class +from ipalib import Str, Flag # Parameter 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 errors2.NotFound: + dn = ldap.find_entry_dn("serverhostname", hostname, "ipaHost") + return dn + +def validate_host(ugettext, 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 + +default_attributes = ['cn','description','localityname','nshostlocation','nshardwareplatform','nsosversion'] + +class host(Object): + """ + Host object. + """ + takes_params = ( + Str('cn', validate_host, + cli_name='hostname', + primary_key=True, + normalizer=lambda value: value.lower(), + ), + Str('description?', + doc='Description of the host', + ), + Str('localityname?', + cli_name='locality', + doc='Locality of this host (Baltimore, MD)', + ), + Str('nshostlocation?', + cli_name='location', + doc='Location of this host (e.g. Lab 2)', + ), + Str('nshardwareplatform?', + cli_name='platform', + doc='Hardware platform of this host (e.g. Lenovo T61)', + ), + Str('nsosversion?', + cli_name='os', + doc='Operating System and version on this host (e.g. Fedora 9)', + ), + Str('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. + + If password is set then this is considered a 'bulk' host so we + do not create a kerberos service principal. + + 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 + assert 'krbprincipalname' not in kw + ldap = self.api.Backend.ldap + + kw['cn'] = hostname + kw['serverhostname'] = hostname.split('.',1)[0] + kw['dn'] = ldap.make_host_dn(hostname) + + # FIXME: do a DNS lookup to ensure host exists + + current = util.get_current_principal() + if not current: + raise errors2.NotFound('Unable to determine current user') + kw['enrolledby'] = ldap.find_entry_dn("krbPrincipalName", current, "posixAccount") + + # 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', 'ipaHost', 'pkiUser'] + + # Ensure the list of objectclasses is lower-case + kw['objectclass'] = map(lambda z: z.lower(), kw.get('objectclass')) + + if not kw.get('userpassword', False): + kw['krbprincipalname'] = "host/%s@%s" % (hostname, self.api.env.realm) + + if 'krbprincipalaux' not in kw.get('objectclass'): + kw['objectclass'].append('krbprincipalaux') + kw['objectclass'].append('krbprincipal') + else: + if 'krbprincipalaux' in kw.get('objectclass'): + kw['objectclass'].remove('krbprincipalaux') + + return ldap.create(**kw) + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + textui.print_plain("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, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + textui.print_plain("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, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + textui.print_plain("Host updated") + +api.register(host_mod) + + +class host_find(crud.Find): + 'Search the hosts.' + + takes_options = ( + Flag('all', doc='Retrieve all attributes'), + ) + + # FIXME: This should no longer be needed with the Param.query kwarg. +# 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'] + + search_kw = {} + for s in search_fields: + search_kw[s] = term + + # Can't use ldap.get_object_type() since cn is also used for group dns + search_kw['objectclass'] = "ipaHost" + if kw.get('all', False): + search_kw['attributes'] = ['*'] + else: + search_kw['attributes'] = default_attributes + return ldap.search(**search_kw) + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + hosts = result[1:] + if counter == 0: + textui.print_plain("No entries found") + return + + for h in hosts: + textui.print_entry(h) + if counter == -1: + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") +api.register(host_find) + + +class host_show(crud.Get): + 'Examine an existing host.' + takes_options = ( + Flag('all', 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, default_attributes) + del value['dn'] + return value + def output_for_cli(self, textui, result, *args, **options): + textui.print_entry(result) + +api.register(host_show) diff --git a/ipalib/plugins/kerberos.py b/ipalib/plugins/kerberos.py new file mode 100644 index 000000000..cc8204976 --- /dev/null +++ b/ipalib/plugins/kerberos.py @@ -0,0 +1,34 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Backend plugin for Kerberos. + +This wraps the python-kerberos and python-krbV bindings. +""" + +from ipalib import api +from ipalib.backend import Backend + +class krb(Backend): + """ + Kerberos backend plugin. + """ + +api.register(krb) diff --git a/ipalib/plugins/passwd.py b/ipalib/plugins/passwd.py new file mode 100644 index 000000000..a599276f4 --- /dev/null +++ b/ipalib/plugins/passwd.py @@ -0,0 +1,71 @@ +# Authors: +# Rob Crittenden +# +# 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 password changes. +""" + +from ipalib import api, errors, util +from ipalib import Command # Plugin base classes +from ipalib import Str, Password # Parameter types + + +class passwd(Command): + 'Edit existing password policy.' + + takes_args = ( + Password('password'), + Str('principal?', + cli_name='user', + primary_key=True, + autofill=True, + default_from=util.get_current_principal, + ), + ) + + def execute(self, principal, password): + """ + Execute the passwd operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param param uid: The login name of the user being updated. + :param kw: Not used. + """ + if principal.find('@') > 0: + u = principal.split('@') + if len(u) > 2: + raise errors.InvalidUserPrincipal(principal) + else: + principal = principal+"@"+self.api.env.realm + dn = self.Backend.ldap.find_entry_dn( + "krbprincipalname", + principal, + "posixAccount" + ) + return self.Backend.ldap.modify_password(dn, newpass=password) + + def output_for_cli(self, textui, result, principal, password): + assert password is None + textui.print_plain('Changed password for "%s"' % principal) + +api.register(passwd) diff --git a/ipalib/plugins/pwpolicy.py b/ipalib/plugins/pwpolicy.py new file mode 100644 index 000000000..f18160b65 --- /dev/null +++ b/ipalib/plugins/pwpolicy.py @@ -0,0 +1,127 @@ +# Authors: +# Rob Crittenden +# +# 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 password policy. +""" + +from ipalib import api +from ipalib import Command # Plugin base classes +from ipalib import Int # Parameter types + + +class pwpolicy_mod(Command): + 'Edit existing password policy.' + takes_options = ( + Int('krbmaxpwdlife?', + cli_name='maxlife', + doc='Max. Password Lifetime (days)', + minvalue=0, + ), + Int('krbminpwdlife?', + cli_name='minlife', + doc='Min. Password Lifetime (hours)', + minvalue=0, + ), + Int('krbpwdhistorylength?', + cli_name='history', + doc='Password History Size', + minvalue=0, + ), + Int('krbpwdmindiffchars?', + cli_name='minclasses', + doc='Min. Number of Character Classes', + minvalue=0, + ), + Int('krbpwdminlength?', + cli_name='minlength', + doc='Min. Length of Password', + minvalue=0, + ), + ) + def execute(self, *args, **kw): + """ + Execute the pwpolicy-mod operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param args: This function takes no positional arguments + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", "accounts", "krbPwdPolicy") + + # The LDAP routines want strings, not ints, so convert a few + # things. Otherwise it sees a string -> int conversion as a change. + for k in kw.iterkeys(): + if k.startswith("krb", 0, 3) and type(kw[k]) is int: + kw[k] = str(kw[k]) + + # Convert hours and days to seconds + if kw.get('krbmaxpwdlife'): + kw['krbmaxpwdlife'] = str(int(kw.get('krbmaxpwdlife')) * 86400) + if kw.get('krbminpwdlife'): + kw['krbminpwdlife'] = str(int(kw.get('krbminpwdlife')) * 3600) + + return ldap.update(dn, **kw) + + def output_for_cli(self, textui, result, *args, **options): + textui.print_plain("Policy modified") + +api.register(pwpolicy_mod) + + +class pwpolicy_show(Command): + 'Retrieve current password policy' + def execute(self, *args, **kw): + """ + Execute the pwpolicy-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param args: Not used. + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", "accounts", "krbPwdPolicy") + + policy = ldap.retrieve(dn) + + # convert some values for display purposes + policy['krbmaxpwdlife'] = str(int(policy.get('krbmaxpwdlife')) / 86400) + policy['krbminpwdlife'] = str(int(policy.get('krbminpwdlife')) / 3600) + + return policy + + def output_for_cli(self, textui, result, *args, **options): + textui.print_plain("Password Policy") + textui.print_plain("Min. Password Lifetime (hours): %s" % result.get('krbminpwdlife')) + textui.print_plain("Max. Password Lifetime (days): %s" % result.get('krbmaxpwdlife')) + textui.print_plain("Min. Number of Character Classes: %s" % result.get('krbpwdmindiffchars')) + textui.print_plain("Min. Length of Password: %s" % result.get('krbpwdminlength')) + textui.print_plain("Password History Size: %s" % result.get('krbpwdhistorylength')) + +api.register(pwpolicy_show) diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py new file mode 100644 index 000000000..4c6f5bd80 --- /dev/null +++ b/ipalib/plugins/service.py @@ -0,0 +1,220 @@ +# Authors: +# Jason Gerard DeRose +# Rob Crittenden +# +# 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 service (Identity). +""" + +from ipalib import api, crud, errors2 +from ipalib import Object # Plugin base classes +from ipalib import Str, Flag # Parameter types + +default_attributes = ['krbprincipalname'] + +class service(Object): + """ + Service object. + """ + takes_params = ( + Str('principal', primary_key=True), + ) +api.register(service) + + +class service_add(crud.Add): + """ + Add a new service. + """ + + takes_options = ( + Flag('force', + doc='Force a service principal name', + ), + ) + def execute(self, principal, **kw): + """ + Execute the service-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 principal: The service to be added in the form: service/hostname + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'krbprincipalname' not in kw + ldap = self.api.Backend.ldap + + force = kw.get('force', False) + try: + del kw['force'] + except: + pass + + # Break down the principal into its component parts, which may or + # may not include the realm. + sp = principal.split('/') + if len(sp) != 2: + raise errors2.MalformedServicePrincipal + service = sp[0] + + if service.lower() == "host": + raise errors2.HostService + + sr = sp[1].split('@') + if len(sr) == 1: + hostname = sr[0].lower() + realm = self.api.env.realm + elif len(sr) == 2: + hostname = sr[0].lower() + realm = sr[1] + else: + raise errors2.MalformedServicePrincipal + + """ + FIXME once DNS client is done + if not force: + fqdn = hostname + "." + rs = dnsclient.query(fqdn, dnsclient.DNS_C_IN, dnsclient.DNS_T_A) + if len(rs) == 0: + self.log.debug("IPA: DNS A record lookup failed for '%s'" % hostname) + raise ipaerror.gen_exception(ipaerror.INPUT_NOT_DNS_A_RECORD) + else: + self.log.debug("IPA: found %d records for '%s'" % (len(rs), hostname)) + """ + + # At some point we'll support multiple realms + if (realm != self.api.env.realm): + raise errors2.RealmMismatch + + # Put the principal back together again + princ_name = service + "/" + hostname + "@" + realm + + dn = ldap.make_service_dn(princ_name) + + kw['dn'] = dn + kw['objectclass'] = ['krbPrincipal', 'krbPrincipalAux', 'krbTicketPolicyAux'] + + return ldap.create(**kw) + + def output_to_cli(self, ret): + textui.print_plain("Service added") + +api.register(service_add) + + +class service_del(crud.Del): + 'Delete an existing service.' + def execute(self, principal, **kw): + """ + Delete a service principal. + + principal is the krbprincipalname of the entry to delete. + + This should be called with much care. + + :param principal: The service to be added in the form: service/hostname + :param kw: not used + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("krbprincipalname", principal) + return ldap.delete(dn) + + def output_to_cli(self, ret): + textui.print_plain("Service removed") + +api.register(service_del) + +# There is no service-mod. The principal itself contains nothing that +# is user-changeable + +class service_find(crud.Find): + 'Search the existing services.' + takes_options = ( + Flag('all', doc='Retrieve all attributes'), + ) + def execute(self, principal, **kw): + ldap = self.api.Backend.ldap + + search_kw = {} + search_kw['filter'] = "&(objectclass=krbPrincipalAux)(!(objectClass=posixAccount))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))" + search_kw['krbprincipalname'] = principal + + object_type = ldap.get_object_type("krbprincipalname") + if object_type and not kw.get('objectclass'): + search_kw['objectclass'] = object_type + + if kw.get('all', False): + search_kw['attributes'] = ['*'] + else: + search_kw['attributes'] = default_attributes + + return ldap.search(**search_kw) + + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + services = result[1:] + if counter == 0: + textui.print_plain("No entries found") + return + + for s in services: + textui.print_entry(s) + + if counter == -1: + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") + textui.print_count(services, '%d services matched') + +api.register(service_find) + + +class service_show(crud.Get): + 'Examine an existing service.' + takes_options = ( + Flag('all', doc='Display all service attributes'), + ) + def execute(self, principal, **kw): + """ + Execute the service-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param principal: The service principal to retrieve + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("krbprincipalname", principal) + # FIXME: should kw contain the list of attributes to display? + if kw.get('all', False): + return ldap.retrieve(dn) + else: + value = ldap.retrieve(dn, default_attributes) + del value['dn'] + return value + + def output_for_cli(self, textui, result, *args, **options): + textui.print_entry(result) + +api.register(service_show) diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py new file mode 100644 index 000000000..e4e1cdaf1 --- /dev/null +++ b/ipalib/plugins/user.py @@ -0,0 +1,383 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 user (Identity). +""" + +from ipalib import api, crud, errors2 +from ipalib import Object, Command # Plugin base classes +from ipalib import Str, Password, Flag, Int # Parameter types + + +def display_user(user): + # FIXME: for now delete dn here. In the future pass in the kw to + # output_for_cli() + attr = sorted(user.keys()) + # Always have sn following givenname + try: + l = attr.index('givenname') + attr.remove('sn') + attr.insert(l+1, 'sn') + except ValueError: + pass + + for a in attr: + if a != 'dn': + print "%s: %s" % (a, user[a]) + +default_attributes = ['uid','givenname','sn','homeDirectory','loginshell'] + + +class user(Object): + """ + User object. + """ + + takes_params = ( + Str('givenname', + cli_name='first', + doc="User's first name", + ), + Str('sn', + cli_name='last', + doc="User's last name", + ), + Str('uid', + cli_name='user', + doc="User's login name", + primary_key=True, + default_from=lambda givenname, sn: givenname[0] + sn, + normalizer=lambda value: value.lower(), + ), + Str('gecos?', + doc='GECOS field', + default_from=lambda uid: uid, + ), + Str('homedirectory?', + cli_name='home', + doc="User's home directory", + default_from=lambda uid: '/home/%s' % uid, + ), + Str('loginshell?', + cli_name='shell', + default=u'/bin/sh', + doc="User's Login shell", + ), + Str('krbprincipalname?', + cli_name='principal', + doc="User's Kerberos Principal name", + default_from=lambda uid: '%s@%s' % (uid, api.env.realm), + ), + Str('mailaddress?', + cli_name='email', + doc="User's e-mail address", + ), + Password('userpassword?', + cli_name='password', + doc="Set user's password", + ), + Str('groups?', + doc='Add account to one or more groups (comma-separated)', + ), + Int('uidnumber?', + cli_name='uid', + doc='The uid to use for this user. If not included one is automatically set.', + ), + Str('street?', + doc='The street address', + ), + ) + +api.register(user) + + +class user_add(crud.Create): + """ + Add a new user. + """ + + def execute(self, uid, **kw): + """ + Execute the user-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 uid: The login name of the user being added. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'uid' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + kw['uid'] = uid + kw['dn'] = ldap.make_user_dn(uid) + default_group = None + + # FIXME: enforce this elsewhere +# if servercore.uid_too_long(kw['uid']): +# raise errors.UsernameTooLong + + # Get our configuration + config = ldap.get_ipa_config() + + # Let us add in some missing attributes + if kw.get('homedirectory') is None: + kw['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), kw.get('uid')) + kw['homedirectory'] = kw['homedirectory'].replace('//', '/') + kw['homedirectory'] = kw['homedirectory'].rstrip('/') + if kw.get('loginshell') is None: + kw['loginshell'] = config.get('ipadefaultloginshell') + if kw.get('gecos') is None: + kw['gecos'] = kw['uid'] + + # If uidnumber is blank the the FDS dna_plugin will automatically + # assign the next value. So we don't have to do anything with it. + + if not kw.get('gidnumber'): + try: + group_dn = ldap.find_entry_dn("cn", config.get('ipadefaultprimarygroup')) + default_group = ldap.retrieve(group_dn, ['cn', 'dn','gidNumber']) + if default_group: + kw['gidnumber'] = default_group.get('gidnumber') + except errors2.NotFound: + # Fake an LDAP error so we can return something useful to the kw + raise errors2.NotFound("The default group for new users, '%s', cannot be found." % config.get('ipadefaultprimarygroup')) + except Exception, e: + # catch everything else + raise e + + if kw.get('krbprincipalname') is None: + kw['krbprincipalname'] = "%s@%s" % (kw.get('uid'), self.api.env.realm) + + # FIXME. This is a hack so we can request separate First and Last + # name in the GUI. + if kw.get('cn') is None: + kw['cn'] = "%s %s" % (kw.get('givenname'), + kw.get('sn')) + + # some required objectclasses + kw['objectClass'] = config.get('ipauserobjectclasses') + + new_user = ldap.create(**kw) + + if default_group: + groupkw = {'users':kw.get('uid')} + api.Command['group_add_member'](default_group['cn'].decode('UTF-8'), **groupkw) + + return new_user + + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + textui.print_name(self.name) + textui.print_entry(result) + textui.print_dashed('Added user "%s"' % result['uid']) + +api.register(user_add) + + +class user_del(crud.Delete): + 'Delete an existing user.' + + def execute(self, uid): + """Delete a user. Not to be confused with inactivate_user. This + makes the entry go away completely. + + uid is the uid of the user to delete + + The memberOf plugin handles removing the user from any other + groups. + + :param uid: The login name of the user being added. + :param kw: Not used. + """ + if uid == "admin": + # FIXME: do we still want a "special" user? + raise SyntaxError("admin required") +# raise ipaerror.gen_exception(ipaerror.INPUT_ADMIN_REQUIRED) + self.log.info("IPA: user-del '%s'" % uid) + + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid) + return ldap.delete(dn) + + def output_for_cli(self, textui, result, uid): + """ + Output result of this command to command line interface. + """ + textui.print_plain('Deleted user "%s"' % uid) + +api.register(user_del) + + +class user_mod(crud.Update): + 'Edit an existing user.' + def execute(self, uid, **kw): + """ + Execute the user-mod operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param uid: The login name of the user to retrieve. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'uid' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid) + return ldap.update(dn, **kw) + + def output_for_cli(self, textui, result, uid, **options): + """ + Output result of this command to command line interface. + """ + textui.print_name(self.name) + textui.print_entry(result) + textui.print_dashed('Updated user "%s"' % result['uid']) + +api.register(user_mod) + + +class user_find(crud.Search): + """ + Search for users. + """ + + takes_options = ( + Flag('all', doc='Retrieve all user attributes'), + ) + + 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() + search_fields_conf_str = config.get('ipausersearchfields') + search_fields = search_fields_conf_str.split(",") + + search_kw = {} + for s in search_fields: + search_kw[s] = term + + object_type = ldap.get_object_type("uid") + if object_type and not kw.get('objectclass'): + search_kw['objectclass'] = object_type + if kw.get('all', False): + search_kw['attributes'] = ['*'] + else: + search_kw['attributes'] = default_attributes + return ldap.search(**search_kw) + + def output_for_cli(self, textui, result, uid, **options): + counter = result[0] + users = result[1:] + if counter == 0 or len(users) == 0: + textui.print_plain("No entries found") + return + if len(users) == 1: + textui.print_entry(users[0]) + return + textui.print_name(self.name) + for u in users: + gn = u.get('givenname', '') + sn= u.get('sn', '') + textui.print_plain('%s %s:' % (gn, sn)) + textui.print_entry(u) + textui.print_plain('') + if counter == -1: + textui.print_plain('These results are truncated.') + textui.print_plain('Please refine your search and try again.') + textui.print_count(users, '%d users matched') + +api.register(user_find) + + +class user_show(crud.Retrieve): + 'Examine an existing user.' + takes_options = ( + Flag('all', doc='Retrieve all user attributes'), + ) + def execute(self, uid, **kw): + """ + Execute the user-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param uid: The login name of the user to retrieve. + :param kw: "all" set to True = return all attributes + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid) + # FIXME: should kw contain the list of attributes to display? + if kw.get('all', False): + return ldap.retrieve(dn) + else: + return ldap.retrieve(dn, default_attributes) + + def output_for_cli(self, textui, result, uid, **options): + display_user(result) + +api.register(user_show) + +class user_lock(Command): + 'Lock a user account.' + + takes_args = ( + Str('uid', primary_key=True), + ) + + def execute(self, uid, **kw): + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid) + return ldap.mark_entry_inactive(dn) + + def output_for_cli(self, textui, result, uid): + if result: + textui.print_plain('Locked user "%s"' % uid) + +api.register(user_lock) + + +class user_unlock(Command): + 'Unlock a user account.' + + takes_args = ( + Str('uid', primary_key=True), + ) + + def execute(self, uid, **kw): + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid) + return ldap.mark_entry_active(dn) + + def output_for_cli(self, textui, result, uid): + if result: + textui.print_plain('Unlocked user "%s"' % uid) + +api.register(user_unlock) -- cgit