From 9304b649a32c57e80f53913d7fbdee92fd76a251 Mon Sep 17 00:00:00 2001 From: Tomas Babej Date: Wed, 14 May 2014 13:09:28 +0200 Subject: sudorule: Allow using external groups as groups of runAsUsers Adds a new attribute ipaSudoRunAsExtUserGroup and corresponding hooks sudorule plugin. https://fedorahosted.org/freeipa/ticket/4263 Reviewed-By: Petr Viktorin --- ACI.txt | 4 +-- install/share/65ipasudo.ldif | 4 ++- install/share/schema_compat.uldif | 1 + install/updates/10-schema_compat.update | 1 + ipalib/plugins/sudorule.py | 54 ++++++++++++++++++++++++++++++--- 5 files changed, 57 insertions(+), 7 deletions(-) diff --git a/ACI.txt b/ACI.txt index f61c0f18c..22b10e3dd 100644 --- a/ACI.txt +++ b/ACI.txt @@ -207,9 +207,9 @@ aci: (targetfilter = "(objectclass=ipasudorule)")(version 3.0;acl "permission:Sy dn: cn=System: Delete Sudo rule,cn=permissions,cn=pbac,dc=ipa,dc=example aci: (targetfilter = "(objectclass=ipasudorule)")(version 3.0;acl "permission:System: Delete Sudo rule";allow (delete) groupdn = "ldap:///cn=System: Delete Sudo rule,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=System: Modify Sudo rule,cn=permissions,cn=pbac,dc=ipa,dc=example -aci: (targetattr = "cmdcategory || description || externalhost || externaluser || hostcategory || hostmask || ipaenabledflag || ipasudoopt || ipasudorunas || ipasudorunasextgroup || ipasudorunasextuser || ipasudorunasgroup || ipasudorunasgroupcategory || ipasudorunasusercategory || memberallowcmd || memberdenycmd || memberhost || memberuser || sudonotafter || sudonotbefore || sudoorder || usercategory")(targetfilter = "(objectclass=ipasudorule)")(version 3.0;acl "permission:System: Modify Sudo rule";allow (write) groupdn = "ldap:///cn=System: Modify Sudo rule,cn=permissions,cn=pbac,dc=ipa,dc=example";) +aci: (targetattr = "cmdcategory || description || externalhost || externaluser || hostcategory || hostmask || ipaenabledflag || ipasudoopt || ipasudorunas || ipasudorunasextgroup || ipasudorunasextuser || ipasudorunasextusergroup || ipasudorunasgroup || ipasudorunasgroupcategory || ipasudorunasusercategory || memberallowcmd || memberdenycmd || memberhost || memberuser || sudonotafter || sudonotbefore || sudoorder || usercategory")(targetfilter = "(objectclass=ipasudorule)")(version 3.0;acl "permission:System: Modify Sudo rule";allow (write) groupdn = "ldap:///cn=System: Modify Sudo rule,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=System: Read Sudo Rules,cn=permissions,cn=pbac,dc=ipa,dc=example -aci: (targetattr = "cmdcategory || cn || description || externalhost || externaluser || hostcategory || hostmask || ipaenabledflag || ipasudoopt || ipasudorunas || ipasudorunasextgroup || ipasudorunasextuser || ipasudorunasgroup || ipasudorunasgroupcategory || ipasudorunasusercategory || ipauniqueid || member || memberallowcmd || memberdenycmd || memberhost || memberuser || objectclass || sudonotafter || sudonotbefore || sudoorder || usercategory")(targetfilter = "(objectclass=ipasudorule)")(version 3.0;acl "permission:System: Read Sudo Rules";allow (compare,read,search) userdn = "ldap:///all";) +aci: (targetattr = "cmdcategory || cn || description || externalhost || externaluser || hostcategory || hostmask || ipaenabledflag || ipasudoopt || ipasudorunas || ipasudorunasextgroup || ipasudorunasextuser || ipasudorunasextusergroup || ipasudorunasgroup || ipasudorunasgroupcategory || ipasudorunasusercategory || ipauniqueid || member || memberallowcmd || memberdenycmd || memberhost || memberuser || objectclass || sudonotafter || sudonotbefore || sudoorder || usercategory")(targetfilter = "(objectclass=ipasudorule)")(version 3.0;acl "permission:System: Read Sudo Rules";allow (compare,read,search) userdn = "ldap:///all";) dn: cn=System: Read Sudoers compat tree,cn=permissions,cn=pbac,dc=ipa,dc=example aci: (targetattr = "cn || description || objectclass || ou || sudocommand || sudohost || sudonotafter || sudonotbefore || sudooption || sudoorder || sudorunas || sudorunasgroup || sudorunasuser || sudouser")(target = "ldap:///ou=sudoers,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read Sudoers compat tree";allow (compare,read,search) userdn = "ldap:///all";) dn: cn=System: Read Trust Information,cn=permissions,cn=pbac,dc=ipa,dc=example diff --git a/install/share/65ipasudo.ldif b/install/share/65ipasudo.ldif index 3ad103f8a..8895b0dd7 100644 --- a/install/share/65ipasudo.ldif +++ b/install/share/65ipasudo.ldif @@ -31,8 +31,10 @@ attributeTypes: (2.16.840.1.113730.3.8.7.11 NAME 'ipaSudoRunAsGroupCategory' DES attributeTypes: (2.16.840.1.113730.3.8.7.12 NAME 'hostMask' DESC 'IP mask to identify a subnet.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) ## Attribute to store sudo command attributeTypes: (2.16.840.1.113730.3.8.7.13 NAME 'sudoCmd' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactMatch ORDERING caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) +## Attribute to store a name of the user not managed by IPA. Command witll be executed under his identity. +attributeTypes: (2.16.840.1.113730.3.8.7.14 NAME 'ipaSudoRunAsExtUserGroup' DESC 'Multivalue string attribute that allows storing groups of users that are not managed by IPA the command can be run as' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4' ) ## Object class for SUDO rules -objectClasses: (2.16.840.1.113730.3.8.8.1 NAME 'ipaSudoRule' SUP ipaAssociation STRUCTURAL MAY ( externalUser $ externalHost $ hostMask $ memberAllowCmd $ memberDenyCmd $ cmdCategory $ ipaSudoOpt $ ipaSudoRunAs $ ipaSudoRunAsExtUser $ ipaSudoRunAsUserCategory $ ipaSudoRunAsGroup $ ipaSudoRunAsExtGroup $ ipaSudoRunAsGroupCategory $ sudoNotBefore $ sudoNotAfter $ sudoOrder ) X-ORIGIN 'IPA v2' ) +objectClasses: (2.16.840.1.113730.3.8.8.1 NAME 'ipaSudoRule' SUP ipaAssociation STRUCTURAL MAY ( externalUser $ externalHost $ hostMask $ memberAllowCmd $ memberDenyCmd $ cmdCategory $ ipaSudoOpt $ ipaSudoRunAs $ ipaSudoRunAsExtUser $ ipaSudoRunAsUserCategory $ ipaSudoRunAsGroup $ ipaSudoRunAsExtGroup $ ipaSudoRunAsGroupCategory $ sudoNotBefore $ sudoNotAfter $ sudoOrder $ ipaSudoRunAsExtUserGroup ) X-ORIGIN 'IPA v2' ) ## Object class for SUDO commands objectClasses: (2.16.840.1.113730.3.8.8.2 NAME 'ipaSudoCmd' DESC 'IPA object class for SUDO command' STRUCTURAL MUST ( ipaUniqueID $ sudoCmd ) MAY ( memberOf $ description ) X-ORIGIN 'IPA v2' ) ## Object class for groups of the SUDO commands diff --git a/install/share/schema_compat.uldif b/install/share/schema_compat.uldif index 3d2681d64..79fce21b0 100644 --- a/install/share/schema_compat.uldif +++ b/install/share/schema_compat.uldif @@ -92,6 +92,7 @@ add:schema-compat-entry-attribute: 'sudoCommand=%ifeq("cmdCategory","all","ALL", add:schema-compat-entry-attribute: 'sudoCommand=!%deref("memberDenyCmd","sudoCmd")' add:schema-compat-entry-attribute: 'sudoCommand=!%deref_r("memberDenyCmd","member","sudoCmd")' add:schema-compat-entry-attribute: 'sudoRunAsUser=%{ipaSudoRunAsExtUser}' +add:schema-compat-entry-attribute: 'sudoRunAsUser=%%%{ipaSudoRunAsExtUserGroup}' add:schema-compat-entry-attribute: 'sudoRunAsUser=%deref("ipaSudoRunAs","uid")' add:schema-compat-entry-attribute: 'sudoRunAsUser=%ifeq("ipaSudoRunAsUserCategory","all","ALL","%%%deref_f(\"ipaSudoRunAs\",\"(objectclass=posixGroup)\",\"cn\")")' add:schema-compat-entry-attribute: 'sudoRunAsGroup=%{ipaSudoRunAsExtGroup}' diff --git a/install/updates/10-schema_compat.update b/install/updates/10-schema_compat.update index c45734c55..6f0ed9080 100644 --- a/install/updates/10-schema_compat.update +++ b/install/updates/10-schema_compat.update @@ -4,6 +4,7 @@ replace: schema-compat-entry-attribute:'sudoRunAsGroup=%deref("ipaSudoRunAs","cn dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config add:schema-compat-entry-attribute: 'sudoHost=%ifeq("hostCategory","all","ALL","%{hostMask}")' +add:schema-compat-entry-attribute: 'sudoRunAsUser=%%%{ipaSudoRunAsExtUserGroup}' # Change padding for host and userCategory so the pad returns the same value # as the original, '' or -. diff --git a/ipalib/plugins/sudorule.py b/ipalib/plugins/sudorule.py index a304373b3..935ffded7 100644 --- a/ipalib/plugins/sudorule.py +++ b/ipalib/plugins/sudorule.py @@ -132,7 +132,7 @@ class sudorule(LDAPObject): 'memberallowcmd', 'memberdenycmd', 'ipasudoopt', 'ipasudorunas', 'ipasudorunasgroup', 'ipasudorunasusercategory', 'ipasudorunasgroupcategory', - 'sudoorder', 'hostmask', + 'sudoorder', 'hostmask', 'ipasudorunasextusergroup', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' @@ -153,7 +153,8 @@ class sudorule(LDAPObject): 'cmdcategory', 'cn', 'description', 'externalhost', 'externaluser', 'hostcategory', 'hostmask', 'ipaenabledflag', 'ipasudoopt', 'ipasudorunas', 'ipasudorunasextgroup', - 'ipasudorunasextuser', 'ipasudorunasgroup', + 'ipasudorunasextuser', 'ipasudorunasextusergroup', + 'ipasudorunasgroup', 'ipasudorunasgroupcategory', 'ipasudorunasusercategory', 'ipauniqueid', 'memberallowcmd', 'memberdenycmd', 'memberhost', 'memberuser', 'sudonotafter', 'sudonotbefore', @@ -193,6 +194,7 @@ class sudorule(LDAPObject): 'description', 'ipaenabledflag', 'usercategory', 'hostcategory', 'cmdcategory', 'ipasudorunasusercategory', 'ipasudorunasgroupcategory', 'externaluser', + 'ipasudorunasextusergroup', 'ipasudorunasextuser', 'ipasudorunasextgroup', 'memberdenycmd', 'memberallowcmd', 'memberuser', 'memberhost', 'externalhost', 'sudonotafter', 'hostmask', 'sudoorder', 'sudonotbefore', @@ -318,6 +320,12 @@ class sudorule(LDAPObject): label=_('RunAs External User'), doc=_('External User the commands can run as (sudorule-find only)'), ), + Str('ipasudorunasextusergroup?', + cli_name='runasexternalusergroup', + label=_('External Groups of RunAs Users'), + doc=_('External Groups of users that the command can run as'), + flags=['no_create', 'no_update', 'no_search'], + ), Str('ipasudorunasextgroup?', validate_runasextgroup, cli_name='runasexternalgroup', label=_('RunAs External Group'), @@ -731,7 +739,26 @@ class sudorule_add_runasuser(LDAPAddMember): def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) - return add_external_post_callback('ipasudorunas', 'user', 'ipasudorunasextuser', ldap, completed, failed, dn, entry_attrs, keys, options) + + # Since external_post_callback returns the total number of completed + # entries yet (that is, any external users it added plus the value of + # passed variable 'completed', we need to pass 0 as completed, + # so that the entries added by the framework are not counted twice + # (once in each call of add_external_post_callback) + + (completed_ex_users, dn) = add_external_post_callback( + 'ipasudorunas', 'user', + 'ipasudorunasextuser', + ldap, 0, failed, dn, entry_attrs, + keys, options) + + (completed_ex_groups, dn) = add_external_post_callback( + 'ipasudorunas', 'group', + 'ipasudorunasextusergroup', + ldap, 0, failed, dn, entry_attrs, + keys, options) + + return (completed + completed_ex_users + completed_ex_groups, dn) @register() @@ -744,7 +771,26 @@ class sudorule_remove_runasuser(LDAPRemoveMember): def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) - return remove_external_post_callback('ipasudorunas', 'user', 'ipasudorunasextuser', ldap, completed, failed, dn, entry_attrs, keys, options) + + # Since external_post_callback returns the total number of completed + # entries yet (that is, any external users it added plus the value of + # passed variable 'completed', we need to pass 0 as completed, + # so that the entries added by the framework are not counted twice + # (once in each call of remove_external_post_callback) + + (completed_ex_users, dn) = remove_external_post_callback( + 'ipasudorunas', 'user', + 'ipasudorunasextuser', + ldap, 0, failed, dn, entry_attrs, + keys, options) + + (completed_ex_groups, dn) = remove_external_post_callback( + 'ipasudorunas', 'group', + 'ipasudorunasextusergroup', + ldap, 0, failed, dn, entry_attrs, + keys, options) + + return (completed + completed_ex_users + completed_ex_groups, dn) @register() -- cgit