26 Commits
Author SHA1 Message Date
zpericic 3da77ab3d6 ipaserver: Move /etc/httpd/ipa to /etc/ipa/httpd 2023-11-12 17:35:42 +01:00
zpericic 958266d36c ipaserver: Use apache VirtualHost for IPA UI 2023-11-12 17:35:35 +01:00
Antonio Torres 63f5e57685 Become IPA 4.11.0
Signed-off-by: Antonio Torres <antorres@redhat.com>
2023-10-03 14:45:56 +02:00
Antonio Torres 50c555c5ea Update contributors list
Signed-off-by: Antonio Torres <antorres@redhat.com>
2023-10-03 14:43:19 +02:00
Antonio Torres f35d168ff3 Update translations to FreeIPA ipa-4-11 state
Signed-off-by: Antonio Torres <antorres@redhat.com>
2023-10-03 14:40:40 +02:00
Florence Blanc-Renaud cb14a30a15 Covscan issues: deadcode and Use after free
Covscan detected an unused value in ipa_kdb_principals.c
and a use-after-free in ipa-print-pac.c.

Fixes: https://pagure.io/freeipa/issue/9431

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2023-10-02 17:44:23 -04:00
Christian Heimes ed094e11ec Add context manager to ipalib.API
`ipalib.API` instances like `ipalib.api` now provide a context manager
that connects and disconnects the API object. Users no longer have to
deal with different types of backends or finalize the API correctly.

```python
import ipalib

with ipalib.api as api:
    api.Commands.ping()
```

See: https://pagure.io/freeipa/issue/9443
Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2023-10-02 17:40:57 -04:00
Alexander Bokovoy 305912e467 Use datetime.timezone.utc instead of newer datetime.UTC alias
datetime.UTC alias was added in Python 3.11:
https://docs.python.org/3/library/datetime.html#datetime.UTC

datetime.timezone.utc was present since Python 3.2.

Since RHEL 9 is using Python 3.9, use more compatible variant.

Fixes: https://pagure.io/freeipa/issue/9454

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rafael Guterres Jeffman <rjeffman@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2023-10-02 17:39:50 -04:00
Francisco Trivino fd01b234e3 Workshop: fix broken Sphinx cross-references.
Many of the workshop pages links are directing to URLs that end with
".rst" instead of ".html", as a result, these links are broken.

This commit introduces explicit targets and references to ensure that
the pages are correctly linked.

Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2023-09-26 16:48:39 +02:00
Mohammad Rizwan 9c10d7ee2c ipatests: restart ipa services after moving date
When system date is moved into future, it have unprecedented
behavior i.e CA becomes irresponsive or unexpected certificcate
state. Hence restart the ipa service after moving the date to
gracefully serve the request.

Fixes: https://pagure.io/freeipa/issue/9379

Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2023-09-19 13:48:07 +02:00
Christian Heimes bc9385d15c Use find_spec() in meta importer
The `find_module()` method of meta importers has been deprecated for a
long time. Python 3.12 no longer falls back to `find_module()`.

See: https://docs.python.org/3.12/whatsnew/3.12.html#removed
Related: https://pagure.io/freeipa/issue/9437
Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
2023-09-19 13:46:10 +02:00
Alexander Bokovoy 637ccae0b4 Allow ipa-otpd to access USB devices for passkeys
Main SELinux policy will allow transition of passkey_child (SSSD) to
ipa_otpd_t context to perform FIDO2 operations with USB devices.
This means ipa-otpd will need to be able to read data from sysfs and
connect to USB devices.

Add required permissions to IPA subpolicy as well. See rhbz#2238224 for
discussion.

Related: https://pagure.io/freeipa/issue/9434

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Zdenek Pytela <zpytela@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2023-09-19 08:05:42 +02:00
Rob Crittenden 169f9abb6b Don't assume KRB5CCNAME is in the environment in replica install
The replica install was unilaterally removing KRB5CCNAME from
os.environ in some cases. Instead check first to see if it is
present and only remove in that case.

Fixes: https://pagure.io/freeipa/issue/9446

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2023-09-15 13:53:12 +02:00
Rob Crittenden 54a251bcea Configure affinity during server installation
Write a new krb5.conf in case any values changed finding the
right server to configure against (e.g. for CA, KRA) and
ensure the API connection is to the remote server that
will be installed against.

When finding a CA or KRA during initial replica installation
set the remote master as well. The order is:

 - existing server value in /etc/ipa/default.conf
 - the chosen CA host if the server doesn't provide one
 - the chosen KRA host if the server doesn't provide one

This is more or less heirarchical. If a server is provided
then that is considered first. If it provides all the
optional services needed (CA and/or KRA) then it will
be used. Otherwise it will fall back to a server that provides
all the required services.

In short, providing --server either at client install or
with ipa-replica-install is no guarantee that it will
define all topology. This may be unexpected behavior.

For the case of adding a CA or KRA things are effectively
unchanged. This type of install does not appear to be
impacted by affinity issues.

Fixes: https://pagure.io/freeipa/issue/9289

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
2023-09-15 13:53:12 +02:00
Alexander Bokovoy 2220f72321 Restore selinux states if they exist at uninstall time
Related: https://pagure.io/freeipa/issue/9434

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2023-09-14 13:08:29 +02:00
Alexander Bokovoy d62be1da45 ipa-client-install: enable SELinux for SSSD
For passkeys (FIDO2) support, SSSD uses libfido2 library which needs
access to USB devices. Add SELinux booleans handling to ipa-client-install
so that correct SELinux booleans can be enabled and disabled during
install and uninstall. Ignore and record a warning when SELinux policy
does not support the boolean.

Fixes: https://pagure.io/freeipa/issue/9434

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2023-09-14 13:08:29 +02:00
Alexandra Nikandrova f7422b7812 doc: typo in basic_usage.md
Reviewed-By: Antonio Torres <antorres@redhat.com>
2023-09-13 11:23:59 +02:00
Alexander Bokovoy fc9b527dee updates: add ACIs for RBCD self-management
Fixes: https://pagure.io/freeipa/issue/9354

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Julien Rische <jrische@redhat.com>
2023-09-12 13:36:17 +02:00
Antonio Torres 4746329409 ipatests: rename 'ipatuura' directory to 'scim' in bridge tests
A recent commit [1] in ipa-tuura project renamed the 'ipatuura' django app
to 'scim'. Change it in IPA side as well to fix tests.

[1]: https://github.com/freeipa/ipa-tuura/commit/f12592cea496818af782f953e0e9643c9ea440b5

Fixes: https://pagure.io/freeipa/issue/9447

Signed-off-by: Antonio Torres <antorres@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2023-09-11 17:52:31 +02:00
Viktor Ashirov 3f874eece9 BDB tuning should be applied only when BDB backend is used
389DS supports BDB and LMDB backends. FreeIPA installation fails with
LMDB backend since it tries to apply tuning for BDB backend.

Instead, tuning for BDB should be applied only when 389DS uses BDB
backend.

Fixes: https://pagure.io/freeipa/issue/9435

Signed-off-by: Viktor Ashirov <vashirov@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2023-09-11 09:17:41 +02:00
Florence Blanc-Renaud f16b6e3e0a idp: add the ipaidpuser objectclass when needed
The ipaidpuser objectclass is required for the attribute ipaidpsub.
When a user is created or modified with --idp-user-id, the operation
must ensure that the objectclass is added if missing.

Add a test for user creation and user modification with --idp-user-id.
Fixes: https://pagure.io/freeipa/issue/9433

Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2023-09-01 13:20:34 -04:00
Rob Crittenden 37b433d4a7 Adjust test to handle revocation reason REMOVE_FROM_CRL
The dogtag REST API has a change of behavior regarding
revocation reason 8, REMOVE_FROM_CRL. The XML interface
accepts it blindly and marks the certifiate as revoked.

This is complicated within RFC 5280 but the jist is that
it only affects a certificate on hold and only for delta
CRLs.

So this modifies the behavior of revocation 8 so that
the certificate is put on hold (6) first.

Fixes: https://pagure.io/freeipa/issue/9345

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2023-08-28 13:40:39 -04:00
Rob Crittenden 0b870694f6 Use the PKI REST API wherever possible instead of XML
The XML API is already deprecated and will be removed in some
future release.

All but the updateCRL API has an equivalent in REST. The upstream
dogtag project documents most of the API at
https://github.com/dogtagpki/pki/wiki/REST-API . I say most
because not every API includes sample input/output. The
pki ca-cert command is a good substitute for seeing how the API
is used by their own tooling.

This changes no pre-existing conventions. All serial numbers are
converted to decimal prior to transmission and are treated as
strings to avoid previous limitations with sizing (which would
have been exacerbated by random serial numbers).

Fixes: https://pagure.io/freeipa/issue/9345

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
2023-08-28 13:40:39 -04:00
Mohammad Rizwan b13b8fbb47 ipatests: accommodate DST in ACME cert expiry
There is one hour time difference between expiry of ACME cert if
the certificate is issued while daylight saving is start and
expires after DST ends. For 2023 daylight saving time start at
Sunday 12 March and ends at Sunday 5 November. Every certificate
which is expiring after November 5th will have 1 hour difference in
expiry.

Fix is to use 90days+2hours to expire the cert.

Fixes: https://pagure.io/freeipa/issue/9428

Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2023-08-24 11:12:56 -04:00
Antonio Torres 4b1c5a5a83 Back to git snapshots
Signed-off-by: Antonio Torres <antorres@redhat.com>
2023-08-21 16:55:10 +02:00
Antonio Torres cb351476ed Become IPA 4.11.0beta1
Signed-off-by: Antonio Torres <antorres@redhat.com>
2023-08-21 16:45:13 +02:00
295 changed files with 28492 additions and 35947 deletions

No files matched your search

+1 -1
View File
@@ -120,7 +120,7 @@ extraction:
- lxml
- gssapi
- netaddr
- ifaddr
- netifaces
- polib
- requests
- python-augeas
+2 -2
View File
@@ -10,5 +10,5 @@ ipaserver == @VERSION@
ipatests == @VERSION@
# keep pylint version in sync with current Fedora release
# F39 has 3.0.25
pylint ~= 3.0.2
# F37 has 2.15.5
pylint ~= 2.15.5
+2 -10
View File
@@ -29,7 +29,7 @@ aci: (targetfilter = "(objectclass=ipaca)")(version 3.0;acl "permission:System:
dn: cn=cas,cn=ca,dc=ipa,dc=example
aci: (targetattr = "cn || description")(targetfilter = "(objectclass=ipaca)")(version 3.0;acl "permission:System: Modify CA";allow (write) groupdn = "ldap:///cn=System: Modify CA,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=cas,cn=ca,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || description || entryusn || ipacahsmconfiguration || ipacaid || ipacaissuerdn || ipacarandomserialnumberversion || ipacasubjectdn || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaca)")(version 3.0;acl "permission:System: Read CAs";allow (compare,read,search) userdn = "ldap:///all";)
aci: (targetattr = "cn || createtimestamp || description || entryusn || ipacaid || ipacaissuerdn || ipacarandomserialnumberversion || ipacasubjectdn || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaca)")(version 3.0;acl "permission:System: Read CAs";allow (compare,read,search) userdn = "ldap:///all";)
dn: cn=caacls,cn=ca,dc=ipa,dc=example
aci: (targetfilter = "(objectclass=ipacaacl)")(version 3.0;acl "permission:System: Add CA ACL";allow (add) groupdn = "ldap:///cn=System: Add CA ACL,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=caacls,cn=ca,dc=ipa,dc=example
@@ -147,7 +147,7 @@ aci: (targetattr = "usercertificate")(targetfilter = "(objectclass=ipahost)")(ve
dn: cn=computers,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "userpassword")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Enrollment Password";allow (write) groupdn = "ldap:///cn=System: Manage Host Enrollment Password,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=computers,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "ipaprotectedoperation;write_keys || krblastpwdchange || krbprincipalkey")(targetfilter = "(&(!(memberOf=cn=ipaservers,cn=hostgroups,cn=accounts,dc=ipa,dc=example))(objectclass=ipahost))")(version 3.0;acl "permission:System: Manage Host Keytab";allow (write) groupdn = "ldap:///cn=System: Manage Host Keytab,cn=permissions,cn=pbac,dc=ipa,dc=example";)
aci: (targetattr = "krblastpwdchange || krbprincipalkey")(targetfilter = "(&(!(memberOf=cn=ipaservers,cn=hostgroups,cn=accounts,dc=ipa,dc=example))(objectclass=ipahost))")(version 3.0;acl "permission:System: Manage Host Keytab";allow (write) groupdn = "ldap:///cn=System: Manage Host Keytab,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=computers,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;read_keys || ipaallowedtoperform;write_keys || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Keytab Permissions";allow (compare,read,search,write) groupdn = "ldap:///cn=System: Manage Host Keytab Permissions,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=computers,cn=accounts,dc=ipa,dc=example
@@ -374,14 +374,6 @@ dn: cn=sudorules,cn=sudo,dc=ipa,dc=example
aci: (targetattr = "cmdcategory || cn || createtimestamp || description || entryusn || externalhost || externaluser || hostcategory || hostmask || ipaenabledflag || ipasudoopt || ipasudorunas || ipasudorunasextgroup || ipasudorunasextuser || ipasudorunasextusergroup || ipasudorunasgroup || ipasudorunasgroupcategory || ipasudorunasusercategory || ipauniqueid || member || memberallowcmd || memberdenycmd || memberhost || memberuser || modifytimestamp || 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: dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || description || entryusn || modifytimestamp || 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:///anyone";)
dn: cn=topology,cn=ipa,cn=etc,dc=ipa,dc=example
aci: (targetfilter = "(|(objectclass=iparepltopoconf)(objectclass=iparepltoposegment))")(version 3.0;acl "permission:System: Add Topology Segments";allow (add) groupdn = "ldap:///cn=System: Add Topology Segments,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=topology,cn=ipa,cn=etc,dc=ipa,dc=example
aci: (targetattr = "iparepltoposegmentdirection || iparepltoposegmentleftnode || iparepltoposegmentrightnode || nsds5replicastripattrs || nsds5replicatedattributelist || nsds5replicatedattributelisttotal")(targetfilter = "(|(objectclass=iparepltopoconf)(objectclass=iparepltoposegment))")(version 3.0;acl "permission:System: Modify Topology Segments";allow (write) groupdn = "ldap:///cn=System: Modify Topology Segments,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=topology,cn=ipa,cn=etc,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || entryusn || iparepltopoconfroot || iparepltoposegmentdirection || iparepltoposegmentleftnode || iparepltoposegmentrightnode || iparepltoposegmentstatus || modifytimestamp || nsds5replicastripattrs || nsds5replicatedattributelist || nsds5replicatedattributelisttotal || objectclass")(targetfilter = "(|(objectclass=iparepltopoconf)(objectclass=iparepltoposegment))")(version 3.0;acl "permission:System: Read Topology Segments";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Topology Segments,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=topology,cn=ipa,cn=etc,dc=ipa,dc=example
aci: (targetfilter = "(|(objectclass=iparepltopoconf)(objectclass=iparepltoposegment))")(version 3.0;acl "permission:System: Remove Topology Segments";allow (delete) groupdn = "ldap:///cn=System: Remove Topology Segments,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=trusts,dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || entryusn || ipantadditionalsuffixes || ipantflatname || ipantsecurityidentifier || ipantsidblacklistincoming || ipantsidblacklistoutgoing || ipanttrustdirection || ipanttrusteddomainsid || ipanttrustpartner || modifytimestamp || objectclass")(version 3.0;acl "permission:System: Read Trust Information";allow (compare,read,search) userdn = "ldap:///all";)
dn: cn=trusts,dc=ipa,dc=example
+2 -3
View File
@@ -451,9 +451,8 @@ output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: batch/1
args: 1,2,2
args: 1,1,2
arg: Dict('methods*')
option: Str('keeponly*')
option: Str('version?')
output: Output('count', type=[<type 'int'>])
output: Output('results', type=[<type 'list'>, <type 'tuple'>])
@@ -1083,7 +1082,7 @@ option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('ca_renewal_master_server?', autofill=False)
option: Str('delattr*', cli_name='delattr')
option: Flag('enable_sid?', autofill=True, default=False)
option: StrEnum('ipaconfigstring*', autofill=False, cli_name='ipaconfigstring', values=[u'AllowNThash', u'KDC:Disable Last Success', u'KDC:Disable Lockout', u'KDC:Disable Default Preauth for SPNs', u'EnforceLDAPOTP'])
option: StrEnum('ipaconfigstring*', autofill=False, cli_name='ipaconfigstring', values=[u'AllowNThash', u'KDC:Disable Last Success', u'KDC:Disable Lockout', u'KDC:Disable Default Preauth for SPNs'])
option: Str('ipadefaultemaildomain?', autofill=False, cli_name='emaildomain')
option: Str('ipadefaultloginshell?', autofill=False, cli_name='defaultshell')
option: Str('ipadefaultprimarygroup?', autofill=False, cli_name='defaultgroup')
-4
View File
@@ -4,7 +4,6 @@ The following people have contributed to the FreeIPA project.
(Listed in alphabetical order within category)
Developers:
007hacky007
Abhijeet
Abhijeet Kasurde
Adam Misnyovszki
@@ -128,7 +127,6 @@ Developers:
Martin Bašti
Martin Košek
Martin Nagy
Masahiro Matsuya
Matt Rogers
Matthew Davis
mbhalodi
@@ -222,14 +220,12 @@ Developers:
Vit Mojzis
W. Michael Petullo
Weblate
Weblate Translation Memory
William Brown
William Jon McCann
Xiao-Long Chen
Yuri Chornoivan
Zdenek Pytela
zdover
zoedong
김인수
Documentation:
-2
View File
@@ -36,8 +36,6 @@ SUBDIRS = \
po \
pypi \
selinux \
selinux/nfast \
selinux/luna \
$(PYTHON_SUBDIRS) \
$(SERVER_SUBDIRS) \
$(NULL)
+4 -4
View File
@@ -20,8 +20,8 @@
# -> "1.0.0" #
########################################################
define(IPA_VERSION_MAJOR, 4)
define(IPA_VERSION_MINOR, 12)
define(IPA_VERSION_RELEASE, 2)
define(IPA_VERSION_MINOR, 11)
define(IPA_VERSION_RELEASE, 0)
########################################################
# For 'pre' releases the version will be #
@@ -86,8 +86,8 @@ define(IPA_DATA_VERSION, 20100614120000)
# #
########################################################
define(IPA_API_VERSION_MAJOR, 2)
# Last change: add keeponly option to batch command
define(IPA_API_VERSION_MINOR, 254)
# Last change: add passkey support
define(IPA_API_VERSION_MINOR, 253)
########################################################
# Following values are auto-generated from values above
-1
View File
@@ -266,7 +266,6 @@ static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *s
error_message(krberr), krberr);
in->result = NULL;
in->len = 0;
krb5_free_context(krbctx);
ret = LDAP_LOCAL_ERROR;
break;
}
+1 -7
View File
@@ -29,11 +29,6 @@
#include "ipa-client-common.h"
#include "config.h"
int remove_principal(krb5_context context, krb5_keytab ktid,
const char *principal, int debug);
int remove_realm(krb5_context context, krb5_keytab ktid,
const char *realm, int debug);
#define KERBEROS_ERROR 1
#define OOM_ERROR 2
#define KEYTAB_ERROR 3
@@ -176,8 +171,7 @@ remove_realm(krb5_context context, krb5_keytab ktid, const char *realm, int debu
}
done:
krb5_kt_end_seq_get(context, ktid, &kt_cursor);
krb5_free_unparsed_name(context, entry_princ_s);
return rval;
}
+1 -52
View File
@@ -132,56 +132,6 @@ c \- compare\p
W \- self\-write\p
O \- self\-obliterate
.SH "AUDIT AND LOGGING"
The IPA API logs audit messages to systemd journal about each command executed
through IPA API on the IPA server. These messages can be found by grepping
systemd journal with \fBjournalctl -g IPA.API\fR command. The message includes
following information:
May 21 11:31:33 master1.ipa1.test /usr/bin/ipa[247422]: [IPA.API] [autobind]: user_del: SUCCESS [ldap2_140328582446688] {"uid": ["foobar"], "continue": false, "version": "2.253"}
.TP
\fB/usr/bin/ipa[247422]\fR
executable name and PID (`/mod_wsgi` for HTTP end-point)
.TP
\fB[IPA.API]\fR
marker to allow searches with \fBjournalctl -g IPA.API\R
.TP
\fBusername@REALM\fR
authenticated Kerberos principal or \fB[autobind]\fR marker for LDAP-based operations done as root
.TP
\fBuser_del\fR
name of the command executed
.TP
\fBSUCCESS\fR
result of execution: \fBSUCCESS\fR or an exception name
.TP
\fB[ldap2_140328582446688]\fR
LDAP backend connection instance identifier. The identifier will be the same for all
operations performed under the same request. This allows to identify operations
which were executed using the same LDAP connection. For API operations that
didn't result in LDAP access, there will be \fB[no_connection_id]\fR marker.
.TP
\fB{"uid": ["foobar"], "continue": false, "version": "2.253"}\fR
a list of arguments and options passed to the IPA API command, provided in JSON
format. Credentials are filtered out.
.LP
All explicitly requested operations logged. Internal operations, initiated as
part of execution of the explicitly requested IPA API calls, aren't logged. For
HTTP end-point operations will be logged as performed by the '/mod_wsgi'
executable binary. Remaining details can be inspected through the systemd
journal as journald records execution context. See systemd.journal\-fields(7)
for details.
The details of the individual logged messages can be explained with the help of
'\fBjournalctl -x\fR' command, while full set of logged properties can be
retrieved with '\fBjournalctl -o json-pretty\fR'. See journalctl(1) for details
on the systemd journal viewer.
For the sample message above, an explanation could be requested with '\fBjournalctl -x -g ldap2_140328582446688\fR' where LDAP backend connection instance identifier can be used to uniquely fetch that individual message.
.SH "EXAMPLES"
.TP
\fBipa help commands\fR
@@ -256,5 +206,4 @@ IPA default configuration file.
ipa\-client\-install(1), ipa\-compat\-manage(1), ipactl(1), ipa\-dns\-install(1),
ipa\-getcert(1), ipa\-getkeytab(1), ipa\-join(1), ipa\-ldap\-updater(1),
ipa\-nis\-manage(1), ipa\-replica\-install(1), ipa\-replica\-manage(1), ipa\-replica\-prepare(1),
ipa\-rmkeytab(1), ipa\-server\-certinstall(2), ipa\-server\-install(1), ipa\-server\-upgrade(1),
systemd.journal\-fields(7), journalctl(1)
ipa\-rmkeytab(1), ipa\-server\-certinstall(2), ipa\-server\-install(1), ipa\-server\-upgrade(1)
+1 -7
View File
@@ -4,13 +4,7 @@ PubkeyAuthentication yes
${ENABLEPROXY}GlobalKnownHostsFile $KNOWNHOSTS
${VERIFYHOSTKEYDNS}VerifyHostKeyDNS yes
# use sss_ssh_knownhosts if available
# assumes that if a user does not have shell (/sbin/nologin),
# this will return nonzero exit code and proxy command will be ignored
${ENABLEKNOWNHOSTS}Match exec true
${ENABLEKNOWNHOSTS} KnownHostsCommand $KNOWNHOSTSCOMMAND %H
# assumes that if a user does not have shell (/sbin/nologin),
# this will return nonzero exit code and proxy command will be ignored
${ENABLEPROXY}Match exec true
${ENABLEPROXY}Match exec true
${ENABLEPROXY} ProxyCommand $KNOWNHOSTSPROXY -p %p %h
-9
View File
@@ -267,13 +267,6 @@ AC_ARG_WITH([systemdtmpfilesdir],
[systemdtmpfilesdir=$($PKG_CONFIG --define-variable=prefix='${prefix}' --variable=tmpfilesdir systemd)])
AC_SUBST([systemdtmpfilesdir])
AC_ARG_WITH([systemdcatalogdir],
AS_HELP_STRING([--with-systemdcatalogdir=DIR],
[Directory for systemd journal catalog files]),
[systemdcatalogdir=$with_systemdcatalogdir],
[systemdcatalogdir=$($PKG_CONFIG --define-variable=prefix='${prefix}' --variable=catalogdir systemd)])
AC_SUBST([systemdcatalogdir])
dnl ---------------------------------------------------------------------------
dnl - Server-only configuration
dnl ---------------------------------------------------------------------------
@@ -695,8 +688,6 @@ AC_CONFIG_FILES([
po/Makefile.in
po/Makefile.hack
selinux/Makefile
selinux/nfast/Makefile
selinux/luna/Makefile
util/Makefile
])
+1 -1
View File
@@ -116,7 +116,7 @@ ipa_kdb_tests_LDADD = \
$(top_builddir)/util/libutil.la \
-lkdb5 \
-lsss_idmap \
-l$(SAMBA_SECURITY_LIBS)\
-lsamba-security-samba4 \
-lsamba-errors \
$(NULL)
+5 -14
View File
@@ -12,7 +12,9 @@ much more easily managed.
The grouping mechanism has been built so that lookup is highly optimized
and is basically reduced to a single search that uses the derefernce
control.
control. Speed is very important in this case because KDC operations
time out very quickly and unless we add a caching layer in ipa-kdb we
must keep the number of searches down to avoid client timeouts.
The grouping mechanism is very simple a groupOfPrincipals object is
introduced, this Auxiliary class have a single optional attribute called
@@ -110,7 +112,8 @@ kinit -kt /etc/httpd/conf/ipa.keytab HTTP/ipaserver.example.com
kvno -U admin HTTP/ipaserver.example.com
# Perform S4U2Proxy
kvno -U admin -P ldap/ipaserver.example.com
kvno -k /etc/httpd/conf/ipa.keytab -U admin -P HTTP/ipaserver.example.com
ldap/ipaserver.example.com
If this works it means you successfully impersonated the admin user with
@@ -122,18 +125,6 @@ modprinc -ok_to_auth_as_delegate HTTP/ipaserver.example.com
Simo.
If IPA is compiled with krb5 1.20 and newer (KDB DAL >= 9), then the
behavior of S4U2Self changes: S4U2Self TGS-REQs produce forwardable
tickets for all requesters, except if the requester principal is set as
the proxy (impersonating service) in at least one `servicedelegation`
rule. In this case, even if the rule has no target, the KDC will
response to S4U2Self requests with a non-forwardable ticket. Hence,
granting the `ok_to_auth_as_delegate` permission to the proxy service
remains the only way for this service to obtain the evidence ticket
required for general constrained delegation requests if this ticket is
not provided by the client.
[1]
Note that here I use the term proxy in a different way than it is used in
the krb interfaces. It may seem a bit confusing but I think people will
+17 -60
View File
@@ -26,7 +26,6 @@
#include "ipa_kdb.h"
#include "ipa_krb5.h"
#include "ipa_hostname.h"
#include <kadm5/admin.h>
#define IPADB_GLOBAL_CONFIG_CACHE_TIME 60
@@ -195,9 +194,6 @@ done:
return base;
}
/* In this table all _AUTH_PASSWORD entries will be
* expanded to include _AUTH_HARDENED in ipadb_parse_user_auth()
* which means there is no need to explicitly add it here */
static const struct {
const char *name;
enum ipadb_user_auth flag;
@@ -211,19 +207,6 @@ static const struct {
{ "idp", IPADB_USER_AUTH_IDP },
{ "passkey", IPADB_USER_AUTH_PASSKEY },
{ }
},
objclass_table[] = {
{ "ipaservice", IPADB_USER_AUTH_PASSWORD },
{ "ipahost", IPADB_USER_AUTH_PASSWORD },
{ }
},
princname_table[] = {
{ KRB5_TGS_NAME, IPADB_USER_AUTH_PASSWORD },
{ KRB5_KDB_M_NAME, IPADB_USER_AUTH_PASSWORD },
{ KADM5_ADMIN_SERVICE, IPADB_USER_AUTH_PASSWORD },
{ KADM5_CHANGEPW_SERVICE, IPADB_USER_AUTH_PASSWORD },
{ KADM5_HIST_PRINCIPAL, IPADB_USER_AUTH_PASSWORD },
{ }
};
void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le,
@@ -234,48 +217,16 @@ void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le,
*userauth = IPADB_USER_AUTH_NONE;
vals = ldap_get_values_len(lcontext, le, IPA_USER_AUTH_TYPE);
if (!vals) {
/* if there is no explicit ipaUserAuthType set, use objectclass */
vals = ldap_get_values_len(lcontext, le, "objectclass");
if (!vals)
return;
if (!vals)
return;
for (i = 0; vals[i]; i++) {
for (j = 0; objclass_table[j].name; j++) {
if (strcasecmp(vals[i]->bv_val, objclass_table[j].name) == 0) {
*userauth |= objclass_table[j].flag;
break;
}
for (i = 0; vals[i]; i++) {
for (j = 0; userauth_table[j].name; j++) {
if (strcasecmp(vals[i]->bv_val, userauth_table[j].name) == 0) {
*userauth |= userauth_table[j].flag;
break;
}
}
} else {
for (i = 0; vals[i]; i++) {
for (j = 0; userauth_table[j].name; j++) {
if (strcasecmp(vals[i]->bv_val, userauth_table[j].name) == 0) {
*userauth |= userauth_table[j].flag;
break;
}
}
}
}
/* If neither ipaUserAuthType nor objectClass were definitive,
* check the krbPrincipalName to see if it is krbtgt/ or K/M one */
if (*userauth == IPADB_USER_AUTH_NONE) {
ldap_value_free_len(vals);
vals = ldap_get_values_len(lcontext, le, "krbprincipalname");
if (!vals)
return;
for (i = 0; vals[i]; i++) {
for (j = 0; princname_table[j].name; j++) {
if (strncmp(vals[i]->bv_val, princname_table[j].name,
strlen(princname_table[j].name)) == 0) {
*userauth |= princname_table[j].flag;
break;
}
}
}
}
/* If password auth is enabled, enable hardened policy too. */
if (*userauth & IPADB_USER_AUTH_PASSWORD) {
@@ -449,7 +400,6 @@ int ipadb_get_connection(struct ipadb_context *ipactx)
struct timeval tv = { 5, 0 };
LDAPMessage *res = NULL;
LDAPMessage *first;
const char *stmsg;
int ret;
int v3;
@@ -529,9 +479,16 @@ int ipadb_get_connection(struct ipadb_context *ipactx)
}
/* get adtrust options using default refresh interval */
ret = ipadb_reinit_mspac(ipactx, false, &stmsg);
if (ret && stmsg)
krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg);
ret = ipadb_reinit_mspac(ipactx, false);
if (ret && ret != ENOENT) {
/* TODO: log that there is an issue with adtrust settings */
if (ipactx->lcontext == NULL) {
/* for some reason ldap connection was reset in ipadb_reinit_mspac
* and is no longer established => failure of ipadb_get_connection
*/
goto done;
}
}
ret = 0;
+1 -46
View File
@@ -94,34 +94,6 @@
#define IPA_KRB_AUTHZ_DATA_ATTR "ipaKrbAuthzData"
#define IPA_USER_AUTH_TYPE "ipaUserAuthType"
/* Virtual managed ticket flags like "-allow_tix", are always controlled by the
* "nsAccountLock" attribute, such flags should never be set in the database.
* The following expression combine all of them, and is used to filter them
* out. */
#define IPA_KDB_TKTFLAGS_VIRTUAL_MANAGED_ALL (KRB5_KDB_DISALLOW_ALL_TIX)
/* Virtual static ticket flags are hard-coded in the KDB driver. */
/* Virtual static mandatory flags are set systematically and implicitly for all
* principals. They are filtered out from database ticket flags updates.
* (However, "KRB5_KDB_REQUIRES_PRE_AUTH" can still be unset by the
* "KDC:Disable Default Preauth for SPNs" global setting) */
#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_MANDATORY (KRB5_KDB_REQUIRES_PRE_AUTH)
/* Virtual static default ticket flags are implicitly set for user and non-user
* (SPN) principals, and not stored in the database.
* (Except if the "IPA_KDB_STRATTR_FINAL_TKTFLAGS" string attribute is "true"
* the principal) */
/* Virtual static default user ticket flags are set for users only. The
* "-allow_svr" flag is set to protect them from CVE-2024-3183. */
#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_USER (KRB5_KDB_DISALLOW_SVR)
#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_SPN (0)
/* If this string attribute is set to "true", then only the virtual managed and
* virtual static mandatory ticket flags are applied and filtered out from
* database read and write operations for the concerned user principal.
* Configurable principal ticket flags are applied, but not the configurable
* global ticket policy flags. */
#define IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS "final_user_tkt_flags"
struct ipadb_mspac;
struct dom_sid;
@@ -215,21 +187,6 @@ struct ipadb_e_data {
struct dom_sid *sid;
};
inline static krb5_error_code
ipadb_get_edata(krb5_db_entry *entry, struct ipadb_e_data **ied)
{
struct ipadb_e_data *in_ied;
in_ied = (struct ipadb_e_data *)entry->e_data;
if (!in_ied || in_ied->magic != IPA_E_DATA_MAGIC)
return EINVAL;
if (ied)
*ied = in_ied;
return 0;
}
struct ipadb_context *ipadb_get_context(krb5_context kcontext);
int ipadb_get_connection(struct ipadb_context *ipactx);
@@ -414,9 +371,7 @@ krb5_error_code ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
krb5_data ***auth_indicators);
#endif
krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx,
bool force_reinit,
const char **stmsg);
krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit);
void ipadb_mspac_struct_free(struct ipadb_mspac **mspac);
krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
+87 -104
View File
@@ -99,110 +99,120 @@ static bool ipadb_match_member(char *princ, LDAPDerefRes *dres)
return false;
}
#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
static krb5_error_code
ipadb_has_acl(krb5_context kcontext, LDAPMessage *ldap_acl, bool *res)
static krb5_error_code ipadb_match_acl(krb5_context kcontext,
LDAPMessage *results,
krb5_const_principal client,
krb5_const_principal target)
{
struct ipadb_context *ipactx;
bool in_res = false;
krb5_error_code kerr = 0;
krb5_error_code kerr;
LDAPMessage *lentry;
LDAPDerefRes *deref_results;
LDAPDerefRes *dres;
char *client_princ = NULL;
char *target_princ = NULL;
bool client_missing;
bool client_found;
bool target_found;
bool is_constraint_delegation = false;
size_t nrules = 0;
int ret;
ipactx = ipadb_get_context(kcontext);
if (!ipactx)
if (!ipactx) {
return KRB5_KDB_DBNOTINITED;
switch (ldap_count_entries(ipactx->lcontext, ldap_acl)) {
case 0:
break;
case -1:
kerr = EINVAL;
goto end;
default:
in_res = true;
goto end;
}
end:
if (res)
*res = in_res;
if ((client != NULL) && (target != NULL)) {
kerr = krb5_unparse_name(kcontext, client, &client_princ);
if (kerr != 0) {
goto done;
}
kerr = krb5_unparse_name(kcontext, target, &target_princ);
if (kerr != 0) {
goto done;
}
} else {
is_constraint_delegation = true;
}
return kerr;
}
#endif
static krb5_error_code
ipadb_match_acl(krb5_context kcontext, LDAPMessage *ldap_acl,
krb5_const_principal client, krb5_const_principal target)
{
struct ipadb_context *ipactx;
LDAPMessage *rule;
LDAPDerefRes *acis, *aci;
char *client_princ = NULL, *target_princ= NULL;
bool client_missing, client_found, target_found;
int lerr;
krb5_error_code kerr;
ipactx = ipadb_get_context(kcontext);
if (!ipactx)
return KRB5_KDB_DBNOTINITED;
kerr = krb5_unparse_name(kcontext, client, &client_princ);
if (kerr)
goto end;
kerr = krb5_unparse_name(kcontext, target, &target_princ);
if (kerr)
goto end;
lentry = ldap_first_entry(ipactx->lcontext, results);
if (!lentry) {
kerr = ENOENT;
goto done;
}
/* the default is that we fail */
kerr = KRB5KDC_ERR_BADOPTION;
kerr = ENOENT;
for (rule = ldap_first_entry(ipactx->lcontext, ldap_acl);
rule;
rule = ldap_next_entry(ipactx->lcontext, rule))
{
while (lentry) {
/* both client and target must be found in the same ACI */
client_missing = true;
client_found = false;
target_found = false;
lerr = ipadb_ldap_deref_results(ipactx->lcontext, rule, &acis);
switch (lerr) {
ret = ipadb_ldap_deref_results(ipactx->lcontext, lentry,
&deref_results);
switch (ret) {
case 0:
for (aci = acis; aci; aci = aci->next) {
if (!client_found &&
0 == strcasecmp(aci->derefAttr, "ipaAllowToImpersonate"))
{
for (dres = deref_results; dres; dres = dres->next) {
nrules++;
if (is_constraint_delegation) {
/*
Microsoft revised the S4U2Proxy rules for forwardable
tickets. All S4U2Proxy operations require forwardable
evidence tickets, but S4U2Self should issue a
forwardable ticket if the requesting service has no
ok-to-auth-as-delegate bit but also no constrained
delegation privileges for traditional S4U2Proxy.
Implement these rules, extending the
check_allowed_to_delegate() DAL method so that the KDC
can ask if a principal has any delegation privileges.
Since target principal is NULL and client principal is
NULL in this case, we simply calculate number of rules associated
with the server principal to decide whether to deny forwardable bit
*/
continue;
}
if (client_found == false &&
strcasecmp(dres->derefAttr, "ipaAllowToImpersonate") == 0) {
/* NOTE: client_missing is used to signal that the
* attribute was completely missing. This signals that
* ANY client is allowed to be impersonated.
* This logic is valid only for clients, not for targets */
client_missing = false;
client_found = ipadb_match_member(client_princ, aci);
client_found = ipadb_match_member(client_princ, dres);
}
if (!target_found &&
0 == strcasecmp(aci->derefAttr, "ipaAllowedTarget"))
{
target_found = ipadb_match_member(target_princ, aci);
if (target_found == false &&
strcasecmp(dres->derefAttr, "ipaAllowedTarget") == 0) {
target_found = ipadb_match_member(target_princ, dres);
}
}
ldap_derefresponse_free(acis);
ldap_derefresponse_free(deref_results);
break;
case ENOENT:
break;
default:
kerr = lerr;
goto end;
kerr = ret;
goto done;
}
if ((client_found || client_missing) && target_found) {
if ((client_found == true || client_missing == true) &&
target_found == true) {
kerr = 0;
goto end;
goto done;
}
lentry = ldap_next_entry(ipactx->lcontext, lentry);
}
end:
if (nrules > 0) {
kerr = 0;
}
done:
krb5_free_unparsed_name(kcontext, client_princ);
krb5_free_unparsed_name(kcontext, target_princ);
return kerr;
@@ -221,7 +231,7 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
char *srv_principal = NULL;
krb5_db_entry *proxy_entry = NULL;
struct ipadb_e_data *ied_server, *ied_proxy;
LDAPMessage *ldap_gcd_acl = NULL;
LDAPMessage *res = NULL;
if (proxy != NULL) {
/* Handle the case where server == proxy, this is allowed in S4U */
@@ -259,54 +269,27 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
goto done;
}
/* Load general constrained delegation rules */
kerr = ipadb_get_delegation_acl(kcontext, srv_principal, &ldap_gcd_acl);
kerr = ipadb_get_delegation_acl(kcontext, srv_principal, &res);
if (kerr) {
goto done;
}
#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
/*
* Microsoft revised the S4U2Proxy rules for forwardable tickets. All
* S4U2Proxy operations require forwardable evidence tickets, but
* S4U2Self should issue a forwardable ticket if the requesting service
* has no ok-to-auth-as-delegate bit but also no constrained delegation
* privileges for traditional S4U2Proxy. Implement these rules,
* extending the check_allowed_to_delegate() DAL method so that the KDC
* can ask if a principal has any delegation privileges.
*
* If target service principal is NULL, and the impersonating service has
* at least one GCD rule, then succeed.
*/
if (!proxy) {
bool has_gcd_rules;
kerr = ipadb_has_acl(kcontext, ldap_gcd_acl, &has_gcd_rules);
if (!kerr)
kerr = has_gcd_rules ? 0 : KRB5KDC_ERR_BADOPTION;
} else if (client) {
#else
if (client && proxy) {
#endif
kerr = ipadb_match_acl(kcontext, ldap_gcd_acl, client, proxy);
} else {
/* client and/or proxy is missing */
kerr = KRB5KDC_ERR_BADOPTION;
}
if (kerr)
kerr = ipadb_match_acl(kcontext, res, client, proxy);
if (kerr) {
goto done;
}
done:
if (kerr) {
#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
kerr = KRB5KDC_ERR_BADOPTION;
#else
#if KRB5_KDB_DAL_MAJOR_VERSION < 9
kerr = KRB5KDC_ERR_POLICY;
#else
kerr = KRB5KDC_ERR_BADOPTION;
#endif
}
ipadb_free_principal(kcontext, proxy_entry);
krb5_free_unparsed_name(kcontext, srv_principal);
ldap_msgfree(ldap_gcd_acl);
ldap_msgfree(res);
return kerr;
}
+5 -2
View File
@@ -119,8 +119,11 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_RADIUS]);
} else if (strcmp(auth_indicator, "pkinit") == 0) {
valid_auth_indicators++;
/* allow PKINIT unconditionally -- it has passed already at this
* point so some certificate was useful, only apply the limits */
if (!(ua & IPADB_USER_AUTH_PKINIT)) {
*status = "PKINIT pre-authentication not allowed for this user.";
kerr = KRB5KDC_ERR_POLICY;
goto done;
}
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_PKINIT]);
} else if (strcmp(auth_indicator, "hardened") == 0) {
valid_auth_indicators++;
+184 -229
View File
@@ -496,16 +496,8 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"krbCanonicalName", &strres);
if (ret) {
/* krbCanonicalName is mandatory for services but IPA services
* created before commit e6ff83e (FreeIPA 4.4.0, ~2016) had no
* normalization to set krbCanonicalName; services created after
* that version were upgraded to do have krbCanonicalName.
*
* Accept krbPrincipalName alone since they have no alias either */
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"krbPrincipalName", &strres);
if (ret)
return ret;
/* krbCanonicalName is mandatory for services */
return ret;
}
ret = krb5_parse_name(ipactx->kcontext, strres, &princ);
@@ -793,16 +785,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
return ret;
}
if (!ipactx->mspac) {
/* can't give a PAC without server NetBIOS name or primary group RID */
return ENOENT;
}
if (info3->base.primary_gid == 0) {
if (is_host || is_service) {
info3->base.primary_gid = 515; /* Well known RID for domain computers group */
} else {
info3->base.primary_gid = ipactx->mspac->fallback_rid;
if (ipactx->mspac->fallback_rid) {
info3->base.primary_gid = ipactx->mspac->fallback_rid;
} else {
/* can't give a pack without a primary group rid */
return ENOENT;
}
}
}
@@ -812,16 +804,26 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
/* always zero out, not used for Krb, only NTLM */
memset(&info3->base.key, '\0', sizeof(info3->base.key));
info3->base.logon_server.string =
talloc_strdup(memctx, ipactx->mspac->flat_server_name);
if (!info3->base.logon_server.string) {
return ENOMEM;
if (ipactx->mspac->flat_server_name) {
info3->base.logon_server.string =
talloc_strdup(memctx, ipactx->mspac->flat_server_name);
if (!info3->base.logon_server.string) {
return ENOMEM;
}
} else {
/* can't give a pack without Server NetBIOS Name :-| */
return ENOENT;
}
info3->base.logon_domain.string =
talloc_strdup(memctx, ipactx->mspac->flat_domain_name);
if (!info3->base.logon_domain.string) {
return ENOMEM;
if (ipactx->mspac->flat_domain_name) {
info3->base.logon_domain.string =
talloc_strdup(memctx, ipactx->mspac->flat_domain_name);
if (!info3->base.logon_domain.string) {
return ENOMEM;
}
} else {
/* can't give a pack without Domain NetBIOS Name :-| */
return ENOENT;
}
if (is_host || is_service) {
@@ -1034,11 +1036,6 @@ krb5_error_code ipadb_get_pac(krb5_context kcontext,
return KRB5_KDB_DBNOTINITED;
}
/* Check if PAC generator is initialized */
if (!ipactx->mspac) {
return ENOENT;
}
ied = (struct ipadb_e_data *)client->e_data;
if (ied->magic != IPA_E_DATA_MAGIC) {
return EINVAL;
@@ -1621,14 +1618,14 @@ static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context,
{
struct ipadb_context *ipactx;
struct ipadb_adtrusts *domain;
size_t i;
int i;
ipactx = ipadb_get_context(context);
if (!ipactx) {
return NULL;
}
if (!ipactx->mspac) {
if (ipactx->mspac == NULL) {
return NULL;
}
@@ -1650,7 +1647,6 @@ static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context,
{
struct ipadb_context *ipactx;
struct ipadb_adtrusts *domain;
const char *stmsg = NULL;
krb5_error_code kerr;
ipactx = ipadb_get_context(context);
@@ -1659,10 +1655,8 @@ static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context,
}
/* re-init MS-PAC info using default update interval */
kerr = ipadb_reinit_mspac(ipactx, false, &stmsg);
kerr = ipadb_reinit_mspac(ipactx, false);
if (kerr != 0) {
if (stmsg)
krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg);
return NULL;
}
domain = get_domain_from_realm(context, realm);
@@ -1715,7 +1709,6 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
struct ipadb_e_data *ied = NULL;
int flags = 0;
struct dom_sid client_sid;
const char *stmsg = NULL;
#ifdef KRB5_KDB_FLAG_ALIAS_OK
flags = KRB5_KDB_FLAG_ALIAS_OK;
#endif
@@ -1729,14 +1722,10 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
* check that our own view on the PAC details is up to date */
if (ipactx->mspac->domsid.num_auths == 0) {
/* Force re-init of KDB's view on our domain */
kerr = ipadb_reinit_mspac(ipactx, true, &stmsg);
kerr = ipadb_reinit_mspac(ipactx, true);
if (kerr != 0) {
if (stmsg) {
krb5_klog_syslog(LOG_ERR, "MS-PAC generator: %s", stmsg);
} else {
krb5_klog_syslog(LOG_ERR, "PAC issue: unable to update " \
"realm's view on PAC info");
}
krb5_klog_syslog(LOG_ERR,
"PAC issue: unable to update realm's view on PAC info");
return KRB5KDC_ERR_POLICY;
}
}
@@ -1749,7 +1738,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
if (is_s4u && (ipactx->mspac->trusts != NULL)) {
/* Iterate through list of trusts and check if this SID belongs to
* one of the domains we trust */
for(size_t i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
result = dom_sid_check(&ipactx->mspac->trusts[i].domsid,
info->info->info3.base.domain_sid, true);
if (result) {
@@ -1861,11 +1850,11 @@ krb5_error_code filter_logon_info(krb5_context context,
struct ipadb_mspac *mspac_ctx = ipactx->mspac;
result = FALSE;
/* Didn't match but perhaps the original PAC was issued by a child domain's DC? */
for (size_t m = 0; m < mspac_ctx->num_trusts; m++) {
result = dom_sid_check(&mspac_ctx->trusts[m].domsid,
for (k = 0; k < mspac_ctx->num_trusts; k++) {
result = dom_sid_check(&mspac_ctx->trusts[k].domsid,
info->info->info3.base.domain_sid, true);
if (result) {
domain = &mspac_ctx->trusts[m];
domain = &mspac_ctx->trusts[k];
break;
}
}
@@ -2094,10 +2083,10 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
return KRB5_KDB_DBNOTINITED;
}
/* In S4U case we might be dealing with the PAC issued by the trusted domain */
if (ipactx->mspac->trusts) {
if ((ipactx->mspac->trusts != NULL)) {
/* Iterate through list of trusts and check if this SID belongs to
* one of the domains we trust */
for(size_t i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
result = dom_sid_check(&ipactx->mspac->trusts[i].domsid,
&client_sid, false);
if (result) {
@@ -2327,7 +2316,6 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context,
size_t i;
struct dom_sid *requester_sid = NULL;
struct dom_sid req_sid;
TALLOC_CTX *tmpctx = NULL;
if (signing_krbtgt != NULL &&
ipadb_is_cross_realm_krbtgt(signing_krbtgt->princ)) {
@@ -2383,12 +2371,6 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context,
goto done;
}
tmpctx = talloc_new(NULL);
if (tmpctx == NULL) {
kerr = ENOMEM;
goto done;
}
for (i = 0; i < num_buffers; i++) {
if (types[i] == KRB5_PAC_SERVER_CHECKSUM ||
types[i] == KRB5_PAC_PRIVSVR_CHECKSUM ||
@@ -2416,21 +2398,32 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context,
DATA_BLOB pac_attrs_data;
krb5_boolean pac_requested;
kerr = ipadb_client_requested_pac(context, old_pac, tmpctx, &pac_requested);
if (kerr)
TALLOC_CTX *tmpctx = talloc_new(NULL);
if (tmpctx == NULL) {
kerr = ENOMEM;
goto done;
}
kerr = ipadb_client_requested_pac(context, old_pac, tmpctx, &pac_requested);
if (kerr != 0) {
talloc_free(tmpctx);
goto done;
}
kerr = ipadb_get_pac_attrs_blob(tmpctx, &pac_requested, &pac_attrs_data);
if (kerr)
if (kerr) {
talloc_free(tmpctx);
goto done;
}
data.magic = KV5M_DATA;
data.data = (char *)pac_attrs_data.data;
data.length = pac_attrs_data.length;
kerr = krb5_pac_add_buffer(context, new_pac, PAC_TYPE_ATTRIBUTES_INFO, &data);
if (kerr)
if (kerr) {
talloc_free(tmpctx);
goto done;
}
continue;
}
@@ -2477,8 +2470,6 @@ done:
if (kerr != 0 && (new_pac != *pac)) {
krb5_pac_free(context, new_pac);
}
if (tmpctx)
talloc_free(tmpctx);
krb5_free_data_contents(context, &pac_blob);
free(types);
return kerr;
@@ -2637,7 +2628,7 @@ static char *get_server_netbios_name(struct ipadb_context *ipactx)
void ipadb_mspac_struct_free(struct ipadb_mspac **mspac)
{
size_t i, j;
int i, j;
if (!*mspac) return;
@@ -2792,8 +2783,7 @@ ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
LDAPDN dn = NULL;
char **sid_blocklist_incoming = NULL;
char **sid_blocklist_outgoing = NULL;
size_t i, n;
int ret;
int ret, n, i;
ret = asprintf(&base, "cn=ad,cn=trusts,%s", ipactx->base);
if (ret == -1) {
@@ -2878,7 +2868,7 @@ ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
t[n].upn_suffixes_len = NULL;
if (t[n].upn_suffixes != NULL) {
size_t len = 0;
int len = 0;
for (; t[n].upn_suffixes[len] != NULL; len++);
@@ -2993,161 +2983,43 @@ done:
return ret;
}
krb5_error_code
ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit,
const char **stmsg)
krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit)
{
char *dom_attrs[] = { "ipaNTFlatName",
"ipaNTFallbackPrimaryGroup",
"ipaNTSecurityIdentifier",
NULL };
char *grp_attrs[] = { "ipaNTSecurityIdentifier", NULL };
krb5_error_code kerr;
LDAPMessage *result = NULL;
LDAPMessage *lentry;
struct dom_sid gsid, domsid;
char *resstr = NULL;
char *flat_domain_name = NULL;
char *flat_server_name = NULL;
char *fallback_group = NULL;
uint32_t fallback_rid;
struct dom_sid gsid;
char *resstr;
int ret;
time_t now;
const char *in_stmsg = NULL;
int err;
krb5_error_code trust_kerr = 0;
/* Do not update the mspac struct more than once a minute. This would
* avoid heavy load on the directory server if there are lots of requests
* from domains which we do not trust. */
now = time(NULL);
if (ipactx->mspac) {
if (!force_reinit &&
(now > ipactx->mspac->last_update) &&
(now - ipactx->mspac->last_update) < 60) {
/* SKIP */
err = 0;
goto end;
if (ipactx->mspac != NULL &&
(force_reinit == false) &&
(now > ipactx->mspac->last_update) &&
(now - ipactx->mspac->last_update) < 60) {
return 0;
}
if (ipactx->mspac && ipactx->mspac->num_trusts == 0) {
/* Check if there is any trust configured. If not, just return
* and do not re-initialize the MS-PAC structure. */
kerr = ipadb_mspac_check_trusted_domains(ipactx);
if (kerr == KRB5_KDB_NOENTRY) {
kerr = 0;
goto done;
} else if (kerr != 0) {
goto done;
}
if (ipactx->mspac->num_trusts == 0) {
/* Check if there is any trust configured. If not, just return
* and do not re-initialize the MS-PAC structure. */
err = ipadb_mspac_check_trusted_domains(ipactx);
if (err) {
if (err == KRB5_KDB_NOENTRY) {
/* SKIP */
err = 0;
} else {
in_stmsg = "Failed to fetch trusted domains information";
}
goto end;
}
}
}
err = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE,
"(objectclass=ipaNTDomainAttrs)", dom_attrs,
&result);
if (err == KRB5_KDB_NOENTRY) {
err = ENOENT;
in_stmsg = "Local domain NT attributes not configured";
goto end;
} else if (err) {
err = EIO;
in_stmsg = "Failed to fetch local domain NT attributes";
goto end;
}
lentry = ldap_first_entry(ipactx->lcontext, result);
if (!lentry) {
err = ENOENT;
in_stmsg = "Local domain NT attributes not configured";
goto end;
}
err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, "ipaNTFlatName",
&flat_domain_name);
if (err) {
in_stmsg = "Local domain NT flat name not configured";
goto end;
}
err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"ipaNTSecurityIdentifier", &resstr);
if (err) {
in_stmsg = "Local domain SID not configured";
goto end;
}
err = ipadb_string_to_sid(resstr, &domsid);
if (err) {
in_stmsg = "Malformed local domain SID";
goto end;
}
free(resstr);
resstr = NULL;
flat_server_name = get_server_netbios_name(ipactx);
if (!flat_server_name) {
err = ENOMEM;
goto end;
}
err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"ipaNTFallbackPrimaryGroup", &fallback_group);
if (err) {
in_stmsg = (err == ENOENT)
? "Local fallback primary group not configured"
: "Failed to fetch local fallback primary group";
goto end;
}
/* result and lentry not valid any more from here on */
ldap_msgfree(result);
result = NULL;
lentry = NULL;
err = ipadb_simple_search(ipactx, fallback_group, LDAP_SCOPE_BASE,
"(objectclass=posixGroup)", grp_attrs, &result);
if (err) {
in_stmsg = (err == KRB5_KDB_NOENTRY)
? "Local fallback primary group has no POSIX definition"
: "Failed to fetch SID of POSIX group mapped as local fallback " \
"primary group";
goto end;
}
lentry = ldap_first_entry(ipactx->lcontext, result);
if (!lentry) {
err = ENOENT;
goto end;
}
err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"ipaNTSecurityIdentifier", &resstr);
if (err) {
in_stmsg = (err == ENOENT)
? "The POSIX group set as fallback primary group has no SID " \
"configured"
: "Failed to fetch SID of POSIX group set as local fallback " \
"primary group";
goto end;
}
err = ipadb_string_to_sid(resstr, &gsid);
if (err) {
in_stmsg = "Malformed SID of POSIX group set as local fallback " \
"primary group";
goto end;
}
err = sid_split_rid(&gsid, &fallback_rid);
if (err) {
in_stmsg = "Malformed SID of POSIX group mapped as local fallback " \
"primary group";
goto end;
}
/* clean up in case we had old values around */
@@ -3155,35 +3027,118 @@ ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit,
ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac));
if (!ipactx->mspac) {
err = ENOMEM;
goto end;
kerr = ENOMEM;
goto done;
}
ipactx->mspac->last_update = now;
ipactx->mspac->flat_domain_name = flat_domain_name;
ipactx->mspac->flat_server_name = flat_server_name;
ipactx->mspac->domsid = domsid;
ipactx->mspac->fallback_group = fallback_group;
ipactx->mspac->fallback_rid = fallback_rid;
ipactx->mspac->last_update = now;
trust_kerr = ipadb_mspac_get_trusted_domains(ipactx);
if (trust_kerr)
in_stmsg = "Failed to assemble trusted domains information";
kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE,
"(objectclass=ipaNTDomainAttrs)", dom_attrs,
&result);
if (kerr == KRB5_KDB_NOENTRY) {
return ENOENT;
} else if (kerr != 0) {
return EIO;
}
end:
if (stmsg)
*stmsg = in_stmsg;
lentry = ldap_first_entry(ipactx->lcontext, result);
if (!lentry) {
kerr = ENOENT;
goto done;
}
if (resstr) free(resstr);
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"ipaNTFlatName",
&ipactx->mspac->flat_domain_name);
if (ret) {
kerr = ret;
goto done;
}
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"ipaNTSecurityIdentifier",
&resstr);
if (ret) {
kerr = ret;
goto done;
}
ret = ipadb_string_to_sid(resstr, &ipactx->mspac->domsid);
if (ret) {
kerr = ret;
free(resstr);
goto done;
}
free(resstr);
free(ipactx->mspac->flat_server_name);
ipactx->mspac->flat_server_name = get_server_netbios_name(ipactx);
if (!ipactx->mspac->flat_server_name) {
kerr = ENOMEM;
goto done;
}
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"ipaNTFallbackPrimaryGroup",
&ipactx->mspac->fallback_group);
if (ret && ret != ENOENT) {
kerr = ret;
goto done;
}
/* result and lentry not valid any more from here on */
ldap_msgfree(result);
result = NULL;
lentry = NULL;
if (err) {
if (flat_domain_name) free(flat_domain_name);
if (flat_server_name) free(flat_server_name);
if (fallback_group) free(fallback_group);
if (ret != ENOENT) {
kerr = ipadb_simple_search(ipactx, ipactx->mspac->fallback_group,
LDAP_SCOPE_BASE,
"(objectclass=posixGroup)",
grp_attrs, &result);
if (kerr && kerr != KRB5_KDB_NOENTRY) {
kerr = ret;
goto done;
}
lentry = ldap_first_entry(ipactx->lcontext, result);
if (!lentry) {
kerr = ENOENT;
goto done;
}
if (kerr == 0) {
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"ipaNTSecurityIdentifier",
&resstr);
if (ret && ret != ENOENT) {
kerr = ret;
goto done;
}
if (ret == 0) {
ret = ipadb_string_to_sid(resstr, &gsid);
if (ret) {
free(resstr);
kerr = ret;
goto done;
}
ret = sid_split_rid(&gsid, &ipactx->mspac->fallback_rid);
if (ret) {
free(resstr);
kerr = ret;
goto done;
}
free(resstr);
}
}
}
return err ? (krb5_error_code)err : trust_kerr;
kerr = ipadb_mspac_get_trusted_domains(ipactx);
done:
ldap_msgfree(result);
return kerr;
}
krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
@@ -3193,11 +3148,11 @@ krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
{
struct ipadb_context *ipactx;
bool has_transited_contents, has_client_realm, has_server_realm;
size_t i;
int i;
krb5_error_code ret;
ipactx = ipadb_get_context(kcontext);
if (!ipactx) {
if (!ipactx || !ipactx->mspac) {
return KRB5_KDB_DBNOTINITED;
}
@@ -3259,7 +3214,7 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
char **trusted_realm)
{
struct ipadb_context *ipactx;
size_t i, j, length;
int i, j, length;
const char *name;
bool result = false;
+1 -1
View File
@@ -31,7 +31,7 @@ struct ipadb_mspac {
char *fallback_group;
uint32_t fallback_rid;
size_t num_trusts;
int num_trusts;
struct ipadb_adtrusts *trusts;
time_t last_update;
};
+1 -4
View File
@@ -233,7 +233,6 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
krb5_db_entry *client_entry = NULL;
krb5_boolean is_equal;
bool force_reinit_mspac = false;
const char *stmsg = NULL;
is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
@@ -310,9 +309,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
force_reinit_mspac = true;
}
kerr = ipadb_reinit_mspac(ipactx, force_reinit_mspac, &stmsg);
if (kerr && stmsg)
krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg);
(void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
kerr = ipadb_get_pac(context, flags, client, server, NULL, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
+4 -12
View File
@@ -46,7 +46,6 @@ ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
bool with_pad;
krb5_error_code kerr = 0;
bool is_as_req = flags & CLIENT_REFERRALS_FLAGS;
const char *stmsg = NULL;
if (is_as_req) {
get_authz_data_types(context, client, &with_pac, &with_pad);
@@ -111,19 +110,12 @@ ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
force_reinit_mspac = TRUE;
}
}
(void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
/* MS-PAC generator has to be initalized */
kerr = ipadb_reinit_mspac(ipactx, force_reinit_mspac, &stmsg);
if (kerr && stmsg)
krb5_klog_syslog(LOG_ERR, "MS-PAC generator: %s", stmsg);
/* Continue even if initilization of PAC generator failed.
* It may caused by the trust objects part only. */
/* At least the core part of the PAC generator is required. */
if (!ipactx->mspac)
/* MS-PAC needs proper configuration and if it is missing, we simply skip issuing one */
if (ipactx->mspac->flat_server_name == NULL) {
return KRB5_PLUGIN_OP_NOTSUPP;
}
kerr = ipadb_get_pac(context, flags,
client, server, replaced_reply_key,
authtime, &new_pac);
+54 -306
View File
@@ -765,12 +765,9 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
"krbTicketFlags", &result);
if (ret == 0) {
entry->attributes = result;
}
/* Since principal, global policy, and virtual ticket flags are combined,
* they must always be resolved, except if we are in IPA setup mode (because
* ticket policies and virtual ticket flags are irrelevant in this case). */
if (!ipactx->override_restrictions)
} else {
*polmask |= TKTFLAGS_BIT;
}
ret = ipadb_ldap_attr_to_int(lcontext, lentry,
"krbMaxTicketLife", &result);
@@ -974,12 +971,7 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
goto done;
}
if (ret == 0) {
if (1 == krb5_princ_size(kcontext, entry->princ)) {
/* A principal must be a POSIX account AND have only one element to
* be considered a user (this is to filter out CIFS principals). */
ied->ipa_user = true;
}
ied->ipa_user = true;
ret = ipadb_ldap_attr_to_str(lcontext, lentry,
"uid", &uidstring);
if (ret != 0 && ret != ENOENT) {
@@ -1347,150 +1339,23 @@ done:
return ret;
}
static krb5_error_code
are_final_tktflags(struct ipadb_context *ipactx, krb5_db_entry *entry,
bool *final_tktflags)
static krb5_flags maybe_require_preauth(struct ipadb_context *ipactx,
krb5_db_entry *entry)
{
krb5_error_code kerr;
struct ipadb_e_data *ied;
char *str = NULL;
bool in_final_tktflags = false;
kerr = ipadb_get_edata(entry, &ied);
if (kerr)
goto end;
if (!ied->ipa_user) {
kerr = 0;
goto end;
}
kerr = krb5_dbe_get_string(ipactx->kcontext, entry,
IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS, &str);
if (kerr)
goto end;
in_final_tktflags = str && ipa_krb5_parse_bool(str);
end:
if (final_tktflags)
*final_tktflags = in_final_tktflags;
krb5_dbe_free_string(ipactx->kcontext, str);
return kerr;
}
static krb5_error_code
add_virtual_static_tktflags(struct ipadb_context *ipactx, krb5_db_entry *entry,
krb5_flags *tktflags)
{
krb5_error_code kerr;
krb5_flags vsflg;
bool final_tktflags;
const struct ipadb_global_config *gcfg;
const struct ipadb_global_config *config;
struct ipadb_e_data *ied;
vsflg = IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_MANDATORY;
kerr = ipadb_get_edata(entry, &ied);
if (kerr)
goto end;
kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
if (kerr)
goto end;
/* In practice, principal ticket flags cannot be final for SPNs. */
if (!final_tktflags)
vsflg |= ied->ipa_user ? IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_USER
: IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_SPN;
if (!ied->ipa_user) {
gcfg = ipadb_get_global_config(ipactx);
if (gcfg && gcfg->disable_preauth_for_spns)
vsflg &= ~KRB5_KDB_REQUIRES_PRE_AUTH;
config = ipadb_get_global_config(ipactx);
if (config && config->disable_preauth_for_spns) {
ied = (struct ipadb_e_data *)entry->e_data;
if (ied && ied->ipa_user != true) {
/* not a user, assume SPN */
return 0;
}
}
if (tktflags)
*tktflags |= vsflg;
end:
return kerr;
}
static krb5_error_code
get_virtual_static_tktflags_mask(struct ipadb_context *ipactx,
krb5_db_entry *entry, krb5_flags *mask)
{
krb5_error_code kerr;
krb5_flags flags = IPA_KDB_TKTFLAGS_VIRTUAL_MANAGED_ALL;
kerr = add_virtual_static_tktflags(ipactx, entry, &flags);
if (kerr)
goto end;
if (mask)
*mask = ~flags;
kerr = 0;
end:
return kerr;
}
/* Add ticket flags from the global ticket policy if it exists, otherwise
* succeed. If the global ticket policy is set, the "exists" parameter is set to
* true. */
static krb5_error_code
add_global_ticket_policy_flags(struct ipadb_context *ipactx,
bool *gtpol_exists, krb5_flags *tktflags)
{
krb5_error_code kerr;
char *policy_dn;
char *tktflags_attr[] = { "krbticketflags", NULL };
LDAPMessage *res = NULL, *first;
int ec, ldap_tktflags;
bool in_gtpol_exists = false;
ec = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s", ipactx->realm,
ipactx->base);
if (-1 == ec) {
kerr = ENOMEM;
goto end;
}
kerr = ipadb_simple_search(ipactx, policy_dn, LDAP_SCOPE_BASE,
"(objectclass=krbticketpolicyaux)",
tktflags_attr, &res);
if (kerr) {
if (KRB5_KDB_NOENTRY == kerr)
kerr = 0;
goto end;
}
first = ldap_first_entry(ipactx->lcontext, res);
if (!first) {
kerr = 0;
goto end;
}
in_gtpol_exists = true;
ec = ipadb_ldap_attr_to_int(ipactx->lcontext, first, "krbticketflags",
&ldap_tktflags);
if (0 == ec && tktflags) {
*tktflags |= (krb5_flags)ldap_tktflags;
}
kerr = 0;
end:
if (gtpol_exists)
*gtpol_exists = in_gtpol_exists;
ldap_msgfree(res);
free(policy_dn);
return kerr;
/* By default require preauth for all principals */
return KRB5_KDB_REQUIRES_PRE_AUTH;
}
static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
@@ -1503,7 +1368,6 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
char *policy_dn = NULL;
LDAPMessage *res = NULL;
LDAPMessage *first;
bool final_tktflags, has_local_tktpolicy = true;
int result;
int ret;
@@ -1512,18 +1376,12 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
return KRB5_KDB_DBNOTINITED;
}
kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
if (kerr)
goto done;
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"krbticketpolicyreference", &policy_dn);
switch (ret) {
case 0:
break;
case ENOENT:
/* If no principal ticket policy, fallback to the global one. */
has_local_tktpolicy = false;
ret = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s",
ipactx->realm, ipactx->base);
if (ret == -1) {
@@ -1567,13 +1425,12 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
}
}
if (polmask & TKTFLAGS_BIT) {
/* If global ticket policy is being applied, set flags only if
* user principal ticket flags are not final. */
if (has_local_tktpolicy || !final_tktflags) {
ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
"krbticketflags", &result);
if (ret == 0)
entry->attributes |= result;
ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
"krbticketflags", &result);
if (ret == 0) {
entry->attributes |= result;
} else {
entry->attributes |= maybe_require_preauth(ipactx, entry);
}
}
@@ -1597,25 +1454,11 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
if (polmask & MAXRENEWABLEAGE_BIT) {
entry->max_renewable_life = 604800;
}
kerr = 0;
}
if (polmask & TKTFLAGS_BIT) {
/* If the principal ticket flags were applied, then flags from the
* global ticket policy has to be applied atop of them if user principal
* ticket flags are not final. */
if (has_local_tktpolicy && !final_tktflags) {
kerr = add_global_ticket_policy_flags(ipactx, NULL,
&entry->attributes);
if (kerr)
goto done;
if (polmask & TKTFLAGS_BIT) {
entry->attributes |= maybe_require_preauth(ipactx, entry);
}
/* Virtual static ticket flags are set regardless of database content */
kerr = add_virtual_static_tktflags(ipactx, entry, &entry->attributes);
if (kerr)
goto done;
kerr = 0;
}
done:
@@ -1755,7 +1598,6 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
-1,
};
size_t i = 0;
const char *stmsg = NULL;
/* For TGS-REQ server principal lookup, KDC asks with KRB5_KDB_FLAG_REFERRAL_OK
* and client usually asks for an KRB5_NT_PRINCIPAL type principal. */
@@ -1843,11 +1685,8 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
if (kerr == KRB5_KDB_NOENTRY) {
/* If no trusted realm found, refresh trusted domain data and try again
* because it might be a freshly added trust to AD */
kerr = ipadb_reinit_mspac(ipactx, false, &stmsg);
kerr = ipadb_reinit_mspac(ipactx, false);
if (kerr != 0) {
if (stmsg)
krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s",
stmsg);
kerr = KRB5_KDB_NOENTRY;
goto done;
}
@@ -2066,7 +1905,6 @@ void ipadb_free_principal(krb5_context kcontext, krb5_db_entry *entry)
for (i = 0; (acl_list != NULL) && (acl_list[i] != NULL); i++) {
free(acl_list[i]);
}
free(acl_list);
}
free(prev->tl_data_contents);
free(prev);
@@ -2206,36 +2044,6 @@ static void ipadb_mods_free_tip(struct ipadb_mods *imods)
imods->tip--;
}
/* Use LDAP REPLACE operation to remove an attribute.
* Contrary to the DELETE operation, it will not fail if the attribute does not
* exist. */
static krb5_error_code
ipadb_ldap_replace_remove(struct ipadb_mods *imods, char *attribute)
{
krb5_error_code kerr;
LDAPMod *m = NULL;
kerr = ipadb_mods_new(imods, &m);
if (kerr)
return kerr;
m->mod_op = LDAP_MOD_REPLACE;
m->mod_type = strdup(attribute);
if (!m->mod_type) {
kerr = ENOMEM;
goto end;
}
m->mod_values = NULL;
kerr = 0;
end:
if (kerr)
ipadb_mods_free_tip(imods);
return kerr;
}
static krb5_error_code ipadb_get_ldap_mod_str(struct ipadb_mods *imods,
char *attribute, char *value,
int mod_op)
@@ -2652,93 +2460,6 @@ static krb5_error_code ipadb_get_ldap_mod_auth_ind(krb5_context kcontext,
return ret;
}
static krb5_error_code
update_tktflags(krb5_context kcontext, struct ipadb_mods *imods,
krb5_db_entry *entry, int mod_op)
{
krb5_error_code kerr;
struct ipadb_context *ipactx;
struct ipadb_e_data *ied;
bool final_tktflags;
krb5_flags tktflags_mask;
int tktflags;
ipactx = ipadb_get_context(kcontext);
if (!ipactx) {
kerr = KRB5_KDB_DBNOTINITED;
goto end;
}
if (ipactx->override_restrictions) {
/* In IPA setup mode, IPA edata might not be available. In this mode,
* ticket flags are written as they are provided. */
tktflags = (int)entry->attributes;
} else {
kerr = ipadb_get_edata(entry, &ied);
if (kerr)
goto end;
kerr = get_virtual_static_tktflags_mask(ipactx, entry, &tktflags_mask);
if (kerr)
goto end;
kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
if (kerr)
goto end;
/* Flags from the global ticket policy are filtered out only if the user
* principal flags are not final. */
if (!final_tktflags) {
krb5_flags gbl_tktflags = 0;
kerr = add_global_ticket_policy_flags(ipactx, NULL, &gbl_tktflags);
if (kerr)
goto end;
tktflags_mask &= ~gbl_tktflags;
}
tktflags = (int)(entry->attributes & tktflags_mask);
if (LDAP_MOD_REPLACE == mod_op && ied && !ied->has_tktpolaux) {
if (0 == tktflags) {
/* No point initializing principal ticket policy if there are no
* flags left after filtering out virtual and global ticket
* policy ones. */
kerr = 0;
goto end;
}
/* if the object does not have the krbTicketPolicyAux class
* we need to add it or this will fail, only for modifications.
* We always add this objectclass by default when doing an add
* from scratch. */
kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
"krbTicketPolicyAux", LDAP_MOD_ADD);
if (kerr)
goto end;
}
}
if (tktflags != 0) {
kerr = ipadb_get_ldap_mod_int(imods, "krbTicketFlags", tktflags,
mod_op);
if (kerr)
goto end;
} else if (LDAP_MOD_REPLACE == mod_op) {
/* If the principal is not being created, and there are no custom ticket
* flags to be set, remove the "krbTicketFlags" attribute. */
kerr = ipadb_ldap_replace_remove(imods, "krbTicketFlags");
if (kerr)
goto end;
}
kerr = 0;
end:
return kerr;
}
static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
struct ipadb_mods *imods,
krb5_db_entry *entry,
@@ -2814,9 +2535,36 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
/* KADM5_ATTRIBUTES */
if (entry->mask & KMASK_ATTRIBUTES) {
kerr = update_tktflags(kcontext, imods, entry, mod_op);
if (kerr)
/* if the object does not have the krbTicketPolicyAux class
* we need to add it or this will fail, only for modifications.
* We always add this objectclass by default when doing an add
* from scratch. */
if ((mod_op == LDAP_MOD_REPLACE) && entry->e_data) {
struct ipadb_e_data *ied;
ied = (struct ipadb_e_data *)entry->e_data;
if (ied->magic != IPA_E_DATA_MAGIC) {
kerr = EINVAL;
goto done;
}
if (!ied->has_tktpolaux) {
kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
"krbTicketPolicyAux",
LDAP_MOD_ADD);
if (kerr) {
goto done;
}
}
}
kerr = ipadb_get_ldap_mod_int(imods,
"krbTicketFlags",
(int)entry->attributes,
mod_op);
if (kerr) {
goto done;
}
}
/* KADM5_MAX_LIFE */
-6
View File
@@ -79,7 +79,6 @@ static void on_bind_readable(verto_ctx *vctx, verto_ev *ev)
struct otpd_queue_item *item = NULL;
int i, rslt;
(void)vctx;
int kerr = 0;
rslt = ldap_result(verto_get_private(ev), LDAP_RES_ANY, 0, NULL, &results);
if (rslt != LDAP_RES_BIND) {
@@ -119,7 +118,6 @@ static void on_bind_readable(verto_ctx *vctx, verto_ev *ev)
krad_code_name2num("Access-Accept"),
NULL, item->req, &item->rsp);
if (i != 0) {
kerr = 1;
errstr = krb5_get_error_message(ctx.kctx, i);
goto error;
}
@@ -129,10 +127,6 @@ error:
otpd_log_req(item->req, "bind end: %s",
item->rsp != NULL ? "success" : errstr);
if (kerr) {
krb5_free_error_message(ctx.kctx, errstr);
}
ldap_msgfree(results);
otpd_queue_push(&ctx.stdio.responses, item);
verto_set_flags(ctx.stdio.writer, VERTO_EV_FLAG_PERSIST |
+7 -13
View File
@@ -43,14 +43,10 @@ static void forward_cb(krb5_error_code retval, const krad_packet *request,
NULL, item->req, &item->rsp);
}
if (retval == 0) {
otpd_log_req(item->req, "forward end: %s", krad_code_num2name(code));
} else {
const char *err_msg = krb5_get_error_message(ctx.kctx, retval);
otpd_log_req(item->req, "forward end: %s",
krb5_get_error_message(ctx.kctx, retval));
krb5_free_error_message(ctx.kctx, err_msg);
}
otpd_log_req(item->req, "forward end: %s",
retval == 0
? krad_code_num2name(code)
: krb5_get_error_message(ctx.kctx, retval));
otpd_queue_push(&ctx.stdio.responses, item);
verto_set_flags(ctx.stdio.writer, VERTO_EV_FLAG_PERSIST |
@@ -121,10 +117,8 @@ krb5_error_code otpd_forward(struct otpd_queue_item **item)
*item = NULL;
error:
if (retval != 0) {
const char *err_msg = krb5_get_error_message(ctx.kctx, retval);
otpd_log_req((*item)->req, "forward end: %s", err_msg);
krb5_free_error_message(ctx.kctx, err_msg);
}
if (retval != 0)
otpd_log_req((*item)->req, "forward end: %s",
krb5_get_error_message(ctx.kctx, retval));
return retval;
}
+6 -7
View File
@@ -2165,17 +2165,17 @@ static bool handle_cross_realm_princs(struct ipasam_private *ipasam_state,
princ_l = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
remote_realm, ipasam_state->realm);
l_tdo_alias = talloc_asprintf(tmp_ctx, "%s$@%s",
princ_l_tdo = talloc_asprintf(tmp_ctx, "%s$@%s",
flat_name, ipasam_state->realm);
princ_l_tdo = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
l_tdo_alias = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
flat_name, ipasam_state->realm);
princ_r = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
ipasam_state->realm, remote_realm);
r_tdo_alias = talloc_asprintf(tmp_ctx, "%s$@%s",
princ_r_tdo = talloc_asprintf(tmp_ctx, "%s$@%s",
ipasam_state->flat_name, remote_realm);
princ_r_tdo = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
r_tdo_alias = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
ipasam_state->flat_name, remote_realm);
if (trusted_dn == NULL || princ_l == NULL || princ_l_tdo == NULL ||
@@ -2212,7 +2212,7 @@ static bool handle_cross_realm_princs(struct ipasam_private *ipasam_state,
* only used to retrieve trusted domain credentials by
* AD Trust Agents across the IPA topology */
failed += !set_krb_princ(ipasam_state, tmp_ctx,
princ_r_tdo, r_tdo_alias,
r_tdo_alias, princ_r_tdo,
pwd_incoming, trusted_dn,
(KRB_PRINC_CREATE_DISABLED |
KRB_PRINC_CREATE_AGENT_PERMISSION));
@@ -2232,9 +2232,8 @@ static bool handle_cross_realm_princs(struct ipasam_private *ipasam_state,
pwd_outgoing, trusted_dn,
KRB_PRINC_CREATE_DEFAULT);
/* Second: <krbtgt/REMOTE FLAT NAME>@<OUR REALM>, enabled by default
/* Second: <REMOTE FLAT NAME>$@<OUR REALM>, enabled by default
* as it is used for a remote DC to authenticate against IPA Samba
* Uses <REMOTE FLAT NAME$>@<OUR REALM> as an alias.
*
* A local account for the outbound trust must have
* POSIX and SMB identities associated with our domain but we associate
+1 -5
View File
@@ -30,7 +30,7 @@
* Program may make changes or additions to the list of Approved
* Interfaces.
*
* Copyright (C) 2010-2023 Red Hat, Inc.
* Copyright (C) 2010 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -67,10 +67,6 @@
"[file %s, line %d]: " fmt, \
__FILE__, __LINE__, ##__VA_ARGS__)
#define LOG_PWDPOLICY(fmt, ...) \
slapi_log_error(SLAPI_LOG_PWDPOLICY, log_func, fmt, ##__VA_ARGS__)
/* "Trace" logging is very expensive and should be avoided/replaced. TBD */
#define LOG_TRACE(fmt, ...) \
slapi_log_error(SLAPI_LOG_TRACE, log_func, fmt, ##__VA_ARGS__)
@@ -30,7 +30,7 @@
* Program may make changes or additions to the list of Approved
* Interfaces.
*
* Copyright (C) 2005-2023 Red Hat, Inc.
* Copyright (C) 2005 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -132,8 +132,7 @@ ipa_join(Slapi_PBlock *pb)
Slapi_DN *sdn;
Slapi_Backend *be;
Slapi_Entry **es = NULL;
int rc=0, ret=0, res;
size_t i;
int rc=0, ret=0, res, i;
int is_root=0;
char *krbLastPwdChange = NULL;
char *fqdn = NULL;
@@ -205,7 +204,7 @@ ipa_join(Slapi_PBlock *pb)
/* if there is none or more than one, freak out */
if (i != 1) {
LOG_TRACE("Too many entries, or entry no found (%lu)\n", i);
LOG_TRACE("Too many entries, or entry no found (%d)", i);
if (i == 0)
errMesg = "Host not found.\n";
else
@@ -218,7 +217,7 @@ ipa_join(Slapi_PBlock *pb)
/* Is this host already enrolled? */
krbLastPwdChange = slapi_entry_attr_get_charptr(targetEntry, "krbLastPwdChange");
if (NULL != krbLastPwdChange) {
LOG_TRACE("Host already enrolled\n");
LOG_TRACE("Host already enrolled");
errMesg = "Host already enrolled.\n";
rc = LDAP_OPERATIONS_ERROR;
goto free_and_return;
@@ -314,8 +313,8 @@ done:
ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, JOIN_OID);
if (!ret) ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, &retbval);
if (ret) {
errMesg = "Could not set return values\n";
LOG("%s", errMesg);
errMesg = "Could not set return values";
LOG("%s\n", errMesg);
rc = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
}
@@ -30,7 +30,7 @@
* Program may make changes or additions to the list of Approved
* Interfaces.
*
* Copyright (C) 2022-2023 Red Hat, Inc.
* Copyright (C) 2022 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -447,7 +447,7 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb)
LOG_TRACE("grace limit disabled, skipping\n");
goto done;
} else if (grace_limit < -1) {
LOG_FATAL("Invalid passwordGraceLimit value %ld\n", grace_limit);
LOG_FATAL("Invalid passwordGraceLimit value %d\n", grace_limit);
return LDAP_OPERATIONS_ERROR;
}
@@ -480,7 +480,7 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb)
slapi_pwpolicy_make_response_control(pb, -1, grace_limit - grace_user_time , -1);
}
} else if (grace_user_time >= grace_limit) {
LOG_PWDPOLICY("%s password is expired and out of grace limit\n", dn);
LOG_TRACE("%s password is expired and out of grace limit\n", dn);
errstr = "Password is expired.\n";
ret = LDAP_INVALID_CREDENTIALS;
@@ -30,7 +30,7 @@
* Program may make changes or additions to the list of Approved
* Interfaces.
*
* Copyright (C) 2010-2023 Red Hat, Inc.
* Copyright (C) 2010 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -823,15 +823,13 @@ static int ipalockout_preop(Slapi_PBlock *pb)
if (failedcount >= max_fail) {
if (lockout_duration == 0) {
errstr = "Entry permanently locked.\n";
LOG_PWDPOLICY("Entry '%s' is permanently locked.\n", dn);
ret = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
if (time_now < last_failed + lockout_duration) {
/* Too many failures */
LOG_PWDPOLICY("Too many failed logins for '%s'. %lu out of %d\n",
dn, failedcount, max_fail);
LOG_TRACE("Too many failed logins. %lu out of %d\n", failedcount, max_fail);
errstr = "Too many failed logins.\n";
ret = LDAP_UNWILLING_TO_PERFORM;
}
@@ -30,7 +30,7 @@
* Program may make changes or additions to the list of Approved
* Interfaces.
*
* Copyright (C) 2010-2023 Red Hat, Inc.
* Copyright (C) 2010 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -350,6 +350,7 @@ ipamodrdn_load_plugin_config(void)
{
int status = EOK;
int result;
int i;
Slapi_PBlock *search_pb;
Slapi_Entry **entries = NULL;
@@ -378,7 +379,7 @@ ipamodrdn_load_plugin_config(void)
goto cleanup;
}
for (size_t i = 0; (entries[i] != NULL); i++) {
for (i = 0; (entries[i] != NULL); i++) {
/* We don't care about the status here because we may have
* some invalid config entries, but we just want to continue
* looking for valid ones. */
@@ -679,8 +680,7 @@ ipamodrdn_change_attr(struct configEntry *cfgentry,
slapi_modify_internal_pb(mod_pb);
slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
if (ret != LDAP_SUCCESS) {
LOG_FATAL("Failed to change attribute '%s' in '%s' with error %d\n",
cfgentry->tattr, targetdn, ret);
LOG_FATAL("Failed to change attribute with error %d\n", ret);
ret = EFAIL;
}
ret = EOK;
@@ -33,7 +33,7 @@
* Authors:
* Nathaniel McCallum <npmccallum@redhat.com>
*
* Copyright (C) 2014-2023 Red Hat, Inc.
* Copyright (C) 2014 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -295,16 +295,14 @@ preop_mod(Slapi_PBlock *pb)
}
if (!simulate(mods, attr, cpre, &cpost) && repl == 0) {
msg = slapi_ch_smprintf("Invalid operation sequence on %s (%s)",
attr, slapi_entry_get_dn_const(epre));
msg = slapi_ch_smprintf("Invalid operation sequence on %s", attr);
goto error;
}
if (cpost < cpre) {
if (repl == 0) {
msg = slapi_ch_smprintf("Will not %s %s (%s)",
cpost == COUNTER_UNSET ? "delete" : "decrement",
attr, slapi_entry_get_dn_const(epre));
msg = slapi_ch_smprintf("Will not %s %s",
cpost == COUNTER_UNSET ? "delete" : "decrement", attr);
goto error;
}
@@ -323,9 +321,6 @@ preop_mod(Slapi_PBlock *pb)
error:
rc = LDAP_UNWILLING_TO_PERFORM;
if (msg) {
LOG("%s - error %d\n", msg, rc);
}
slapi_send_ldap_result(pb, rc, NULL, msg, 0, NULL);
if (slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc)) {
LOG_FATAL("slapi_pblock_set failed!\n");
@@ -33,7 +33,7 @@
* Authors:
* Nathaniel McCallum <npmccallum@redhat.com>
*
* Copyright (C) 2014-2023 Red Hat, Inc.
* Copyright (C) 2014 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -41,8 +41,6 @@
#include <slapi-plugin.h>
#define IPA_PLUGIN_NAME "ipa-otp-counter"
long long
ldapmod_get_value(const LDAPMod *mod, long long def);
@@ -33,7 +33,7 @@
* Authors:
* Nathaniel McCallum <npmccallum@redhat.com>
*
* Copyright (C) 2013-2023 Red Hat, Inc.
* Copyright (C) 2013 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -46,7 +46,7 @@
#include "util.h"
#define IPA_PLUGIN_NAME "ipa-otp-lasttoken"
#define PLUGIN_NAME "ipa-otp-lasttoken"
#define OTP_CONTAINER "cn=otp,%s"
static struct otp_config *otp_config;
@@ -191,14 +191,9 @@ static inline int send_error(Slapi_PBlock *pb, int rc, const char *errstr)
static int preop_del(Slapi_PBlock *pb)
{
char *dn = NULL;
if (is_allowed(pb, NULL))
return 0;
slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
LOG("Can't delete last active token (%s)", dn);
return send_error(pb, LDAP_UNWILLING_TO_PERFORM,
"Can't delete last active token");
}
@@ -226,12 +221,10 @@ static int preop_mod(Slapi_PBlock *pb)
return 0;
/* If a protected attribute is modified, deny. */
for (size_t i = 0; mods != NULL && mods[i] != NULL; i++) {
for (size_t j = 0; errors[j].attr != NULL; j++) {
if (strcasecmp(mods[i]->mod_type, errors[j].attr) == 0) {
LOG("%s (%s)", errors[j].msg, slapi_entry_get_dn_const(entry));
for (int i = 0; mods != NULL && mods[i] != NULL; i++) {
for (int j = 0; errors[j].attr != NULL; j++) {
if (strcasecmp(mods[i]->mod_type, errors[j].attr) == 0)
return send_error(pb, LDAP_UNWILLING_TO_PERFORM, errors[j].msg);
}
}
}
@@ -291,7 +284,7 @@ static int ipa_otp_lasttoken_start(Slapi_PBlock *pb)
int ipa_otp_lasttoken_init(Slapi_PBlock *pb)
{
static const Slapi_PluginDesc preop_desc = {
IPA_PLUGIN_NAME,
PLUGIN_NAME,
"FreeIPA",
"FreeIPA/1.0",
"Protect the user's last active token"
@@ -304,14 +297,14 @@ int ipa_otp_lasttoken_init(Slapi_PBlock *pb)
ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &preop_desc);
ret |= slapi_register_plugin("betxnpreoperation", 1, __func__, preop_init,
IPA_PLUGIN_NAME " betxnpreoperation", NULL,
PLUGIN_NAME " betxnpreoperation", NULL,
ipa_otp_lasttoken_plugin_id);
ret |= slapi_register_plugin("postoperation", 1, __func__, postop_init,
IPA_PLUGIN_NAME " postoperation", NULL,
PLUGIN_NAME " postoperation", NULL,
ipa_otp_lasttoken_plugin_id);
ret |= slapi_register_plugin("internalpostoperation", 1, __func__,
intpostop_init,
IPA_PLUGIN_NAME " internalpostoperation", NULL,
PLUGIN_NAME " internalpostoperation", NULL,
ipa_otp_lasttoken_plugin_id);
ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
(void *)ipa_otp_lasttoken_start);
@@ -33,7 +33,7 @@
* Authors:
* Simo Sorce <ssorce@redhat.com>
*
* Copyright (C) 2007-2023 Red Hat, Inc.
* Copyright (C) 2007-2010 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -81,9 +81,7 @@ static struct ipapwd_krbcfg *ipapwd_getConfig(void)
char **encsalts;
char **tmparray;
char *tmpstr;
int ret;
size_t i;
bool fips_enabled = false;
int i, ret;
config = calloc(1, sizeof(struct ipapwd_krbcfg));
if (!config) {
@@ -242,34 +240,27 @@ static struct ipapwd_krbcfg *ipapwd_getConfig(void)
config->allow_nt_hash = false;
if (ipapwd_fips_enabled()) {
LOG("FIPS mode is enabled, NT hashes are not allowed.\n");
fips_enabled = true;
}
sdn = slapi_sdn_new_dn_byval(ipa_etc_config_dn);
ret = ipapwd_getEntry(sdn, &config_entry, NULL);
slapi_sdn_free(&sdn);
if (ret != LDAP_SUCCESS) {
LOG_FATAL("No config Entry?\n");
goto free_and_error;
} else {
tmparray = slapi_entry_attr_get_charray(config_entry,
"ipaConfigString");
for (i = 0; tmparray && tmparray[i]; i++) {
if (strcasecmp(tmparray[i], "EnforceLDAPOTP") == 0) {
config->enforce_ldap_otp = true;
continue;
}
if (!fips_enabled) {
sdn = slapi_sdn_new_dn_byval(ipa_etc_config_dn);
ret = ipapwd_getEntry(sdn, &config_entry, NULL);
slapi_sdn_free(&sdn);
if (ret != LDAP_SUCCESS) {
LOG_FATAL("No config Entry?\n");
goto free_and_error;
} else {
tmparray = slapi_entry_attr_get_charray(config_entry,
"ipaConfigString");
for (i = 0; tmparray && tmparray[i]; i++) {
if (strcasecmp(tmparray[i], "AllowNThash") == 0) {
config->allow_nt_hash = true;
continue;
}
}
if (tmparray) slapi_ch_array_free(tmparray);
}
if (tmparray) slapi_ch_array_free(tmparray);
}
slapi_entry_free(config_entry);
slapi_entry_free(config_entry);
}
return config;
@@ -336,8 +327,7 @@ int ipapwd_getPolicy(const char *dn,
"ipaPwdUserCheck", NULL};
Slapi_Entry **es = NULL;
Slapi_Entry *pe = NULL;
int ret, res, scope;
size_t i;
int ret, res, scope, i;
int buffer_flags=0;
Slapi_ValueSet* results = NULL;
char *actual_type_name = NULL;
@@ -555,7 +545,7 @@ int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg,
}
sdn = slapi_sdn_new_dn_byref(dn);
if (!sdn) {
LOG_FATAL("Unable to convert dn to sdn %s\n", dn ? dn : "<NULL>");
LOG_FATAL("Unable to convert dn to sdn %s", dn ? dn : "<NULL>");
*errMesg = "Internal Error";
rc = LDAP_OPERATIONS_ERROR;
goto done;
@@ -574,18 +564,11 @@ int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg,
/* get the kerberos context and master key */
*config = ipapwd_getConfig();
if (NULL == *config) {
LOG_FATAL("Error Retrieving Master Key\n");
LOG_FATAL("Error Retrieving Master Key");
*errMesg = "Fatal Internal Error";
rc = LDAP_OPERATIONS_ERROR;
}
/* do not return the master key if asked */
if (check_flags & IPAPWD_CHECK_ONLY_CONFIG) {
free((*config)->kmkey->contents);
free((*config)->kmkey);
(*config)->kmkey = NULL;
}
done:
return rc;
}
@@ -611,7 +594,7 @@ int ipapwd_CheckPolicy(struct ipapwd_data *data)
/* Find the entry with the password policy */
ret = ipapwd_getPolicy(data->dn, data->target, &pol);
if (ret) {
LOG_TRACE("No password policy, use defaults\n");
LOG_TRACE("No password policy, use defaults");
}
break;
case IPA_CHANGETYPE_ADMIN:
@@ -637,14 +620,14 @@ int ipapwd_CheckPolicy(struct ipapwd_data *data)
*/
ret = ipapwd_getPolicy(data->dn, data->target, &tmppol);
if (ret) {
LOG_TRACE("No password policy, use defaults\n");
LOG_TRACE("No password policy, use defaults");
} else {
pol.max_pwd_life = tmppol.max_pwd_life;
pol.history_length = tmppol.history_length;
}
break;
default:
LOG_TRACE("Unknown password change type, use defaults\n");
LOG_TRACE("Unknown password change type, use defaults");
break;
}
@@ -877,7 +860,7 @@ int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg,
case IPA_CHANGETYPE_DSMGR:
case IPA_CHANGETYPE_ADMIN:
/* Mark as administratively reset which will unlock acct */
ret = ipapwd_setdate(data->target, smods,
ret = ipapwd_setdate(data->target, smods,
"krbLastAdminUnlock",
data->timeNow, false);
if (ret != LDAP_SUCCESS)
@@ -968,7 +951,7 @@ Slapi_Value **ipapwd_setPasswordHistory(Slapi_Mods *smods,
char **new_pwd_history = NULL;
int n = 0;
int ret;
size_t i;
int i;
pwd_history = slapi_entry_attr_get_charray(data->target,
"passwordHistory");
@@ -1100,9 +1083,10 @@ int ipapwd_set_extradata(const char *dn,
void ipapwd_free_slapi_value_array(Slapi_Value ***svals)
{
Slapi_Value **sv = *svals;
int i;
if (sv) {
for (size_t i = 0; sv[i]; i++) {
for (i = 0; sv[i]; i++) {
slapi_value_free(&sv[i]);
}
}
@@ -1118,10 +1102,8 @@ void free_ipapwd_krbcfg(struct ipapwd_krbcfg **cfg)
krb5_free_default_realm(c->krbctx, c->realm);
krb5_free_context(c->krbctx);
if (c->kmkey) {
free(c->kmkey->contents);
free(c->kmkey);
}
free(c->kmkey->contents);
free(c->kmkey);
free(c->supp_encsalts);
free(c->pref_encsalts);
slapi_ch_array_free(c->passsync_mgrs);
@@ -33,7 +33,7 @@
* Authors:
* Simo Sorce <ssorce@redhat.com>
*
* Copyright (C) 2007-2023 Red Hat, Inc.
* Copyright (C) 2007-2010 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -231,7 +231,7 @@ int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
if (!*svals) {
/* errMesg should have been set in encrypt_encode_key() */
LOG_FATAL("key encryption/encoding failed (%s)\n", *errMesg);
LOG_FATAL("key encryption/encoding failed\n");
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
@@ -267,7 +267,6 @@ int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
}
(*ntvals)[0] = slapi_value_new();
if (slapi_value_set((*ntvals)[0], nt_key, 16) == NULL) {
LOG("Failed to set value for nt_key");
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
@@ -33,7 +33,7 @@
* Authors:
* Simo Sorce <ssorce@redhat.com>
*
* Copyright (C) 2007-2023 Red Hat, Inc.
* Copyright (C) 2007-2010 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -108,7 +108,7 @@ static void filter_keys(struct ipapwd_krbcfg *krbcfg,
struct ipapwd_keyset *kset,
bool allow_nthash)
{
size_t i, j;
int i, j;
for (i = 0; i < kset->num_keys; i++) {
for (j = 0; j < krbcfg->num_supp_encsalts; j++) {
@@ -151,11 +151,11 @@ static void filter_enctypes(struct ipapwd_krbcfg *krbcfg,
bool allow_nthash)
{
/* first filter for duplicates */
for (size_t i = 0; i + 1 < *num_kenctypes; i++) {
for (size_t j = i + 1; j < *num_kenctypes; j++) {
for (int i = 0; i + 1 < *num_kenctypes; i++) {
for (int j = i + 1; j < *num_kenctypes; j++) {
if (kenctypes[i].ks_enctype == kenctypes[j].ks_enctype) {
/* duplicate, filter out */
for (size_t k = j; k + 1 < *num_kenctypes; k++) {
for (int k = j; k + 1 < *num_kenctypes; k++) {
kenctypes[k].ks_enctype = kenctypes[k + 1].ks_enctype;
kenctypes[k].ks_salttype = kenctypes[k + 1].ks_salttype;
}
@@ -166,8 +166,8 @@ static void filter_enctypes(struct ipapwd_krbcfg *krbcfg,
}
/* then filter for supported */
for (size_t i = 0; i < *num_kenctypes; i++) {
size_t j;
for (int i = 0; i < *num_kenctypes; i++) {
int j;
/* Check if supported */
for (j = 0; j < krbcfg->num_supp_encsalts; j++) {
@@ -184,7 +184,7 @@ static void filter_enctypes(struct ipapwd_krbcfg *krbcfg,
}
if (j == krbcfg->num_supp_encsalts) {
/* Unsupported, filter out */
for (size_t k = i; k + 1 < *num_kenctypes; k++) {
for (int k = i; k + 1 < *num_kenctypes; k++) {
kenctypes[k].ks_enctype = kenctypes[k + 1].ks_enctype;
kenctypes[k].ks_salttype = kenctypes[k + 1].ks_salttype;
}
@@ -344,8 +344,6 @@ parse_req_done:
rc = ipapwd_check_max_pwd_len(strlen(newPasswd), &errMesg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
bindDN, errMesg);
goto free_and_return;
}
@@ -458,7 +456,7 @@ parse_req_done:
char *cur_pw;
if (oldPasswd == NULL || *oldPasswd == '\0') {
LOG_FATAL("Old password was not provided for '%s'!\n", dn);
LOG_FATAL("Old password was not provided!\n");
rc = LDAP_INVALID_CREDENTIALS;
goto free_and_return;
}
@@ -468,7 +466,7 @@ parse_req_done:
cur_pw = slapi_entry_attr_get_charptr(targetEntry,
"userPassword");
if (!cur_pw) {
LOG_FATAL("User '%s' does not have a current password?\n", dn);
LOG_FATAL("User has no current password?\n");
rc = LDAP_UNWILLING_TO_PERFORM;
goto free_and_return;
}
@@ -487,7 +485,7 @@ parse_req_done:
slapi_value_free(&pw);
if (ret != 0) {
LOG_TRACE("Invalid password for '%s'!\n", dn);
LOG_TRACE("Invalid password!\n");
rc = LDAP_INVALID_CREDENTIALS;
goto free_and_return;
}
@@ -581,9 +579,11 @@ parse_req_done:
/* special cases */
if ((strcasecmp(dn, bindDN) != 0) &&
(strcasecmp(ipa_changepw_principal_dn, bindDN) != 0)) {
int i;
pwdata.changetype = IPA_CHANGETYPE_ADMIN;
for (size_t i = 0; i < krbcfg->num_passsync_mgrs; i++) {
for (i = 0; i < krbcfg->num_passsync_mgrs; i++) {
if (strcasecmp(krbcfg->passsync_mgrs[i], bindDN) == 0) {
pwdata.changetype = IPA_CHANGETYPE_DSMGR;
break;
@@ -606,8 +606,6 @@ parse_req_done:
errMesg = ipapwd_error2string(ret);
ret = ipapwd_to_ldap_pwpolicy_error(ret);
slapi_pwpolicy_make_response_control(pb, -1, -1, ret);
LOG_PWDPOLICY("Failed to set password credentials for"
" '%s': %s\n", dn, errMesg);
rc = LDAP_CONSTRAINT_VIOLATION;
goto free_and_return;
}
@@ -668,7 +666,7 @@ free_and_return:
if (targetEntry) slapi_entry_free(targetEntry);
if (ber) ber_free(ber, 1);
LOG("%s\n", errMesg ? errMesg : "success");
LOG("%s", errMesg ? errMesg : "success");
slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL);
return SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
@@ -734,8 +732,7 @@ static Slapi_Entry *get_entry_by_principal(const char *principal)
"krbCanonicalName",
"enrolledBy", NULL };
Slapi_Entry **es = NULL;
int res, ret;
size_t i;
int res, ret, i;
Slapi_Entry *entry = NULL;
/* Find ancestor base DN */
@@ -777,7 +774,7 @@ static Slapi_Entry *get_entry_by_principal(const char *principal)
/* if there is none or more than one, freak out */
if (i != 1) {
LOG_TRACE("Too many entries, or entry no found (%ld)\n", i);
LOG_TRACE("Too many entries, or entry no found (%d)", i);
goto free_and_return;
}
entry = slapi_entry_dup(es[0]);
@@ -812,7 +809,7 @@ static bool is_allowed_to_access_attr(Slapi_PBlock *pb, char *bindDN,
*/
be = get_realm_backend();
if (!be) {
LOG_FATAL("Could not fetch REALM backend!\n");
LOG_FATAL("Could not fetch REALM backend!");
return false;
}
if (slapi_pblock_set(pb, SLAPI_BACKEND, be)) {
@@ -871,8 +868,7 @@ static void remove_user_password(Slapi_Mods *smods,
if ((NULL != pw) && (NULL == krbLastPwdChange)) {
slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE,
"userPassword", NULL);
LOG_TRACE("Removing userPassword from host entry '%s'\n",
slapi_entry_get_dn_const(targetEntry));
LOG_TRACE("Removing userPassword from host entry\n");
}
}
if (krbLastPwdChange) slapi_ch_free_string(&krbLastPwdChange);
@@ -895,9 +891,8 @@ static int store_new_keys(Slapi_Entry *target, char *svcname, char *bind_dn,
rc = set_krbLastPwdChange(smods, time_now);
if (rc) {
rc = LDAP_OPERATIONS_ERROR;
LOG_FATAL("Failed to set krbLastPwdChange for target '%s'\n",
slapi_entry_get_dn_const(target));
err_msg = "Internal error while storing keytab data";
LOG_FATAL("Failed to set krbLastPwdChange");
err_msg = "Internal error while storing keytab data\n";
goto done;
}
@@ -910,9 +905,8 @@ static int store_new_keys(Slapi_Entry *target, char *svcname, char *bind_dn,
rc = ipapwd_apply_mods(slapi_entry_get_dn_const(target), smods);
if (rc != LDAP_SUCCESS) {
rc = LDAP_OPERATIONS_ERROR;
LOG_FATAL("Failed to apply mods to target '%s'\n",
slapi_entry_get_dn_const(target));
err_msg = "Internal error while saving keys";
LOG_FATAL("Failed to apply mods");
err_msg = "Internal error while saving keys\n";
goto done;
}
@@ -920,9 +914,8 @@ static int store_new_keys(Slapi_Entry *target, char *svcname, char *bind_dn,
svcname, time_now);
if (rc != LDAP_SUCCESS) {
rc = LDAP_OPERATIONS_ERROR;
LOG_FATAL("Failed to set extradata for target '%s'\n",
slapi_entry_get_dn_const(target));
err_msg = "Internal error while saving keytab extradata";
LOG_FATAL("Failed to set extradata");
err_msg = "Internal error while saving keytab extradata\n";
goto done;
}
@@ -1010,7 +1003,7 @@ static int decode_setkeytab_request(krb5_context krbctx,
kset->mkvno = mkvno;
rtag = ber_peek_tag(ber, &tlen);
for (size_t i = 0; rtag == LBER_SEQUENCE; i++) {
for (int i = 0; rtag == LBER_SEQUENCE; i++) {
krb5_key_data *newset;
ber_tag_t ctag;
ber_int_t type;
@@ -1188,29 +1181,29 @@ static int encode_setkeytab_reply(struct ipapwd_keyset *kset,
rc = ber_printf(ber, "{i{", (ber_int_t)kset->keys[0].key_data_kvno);
if (rc == -1) {
rc = LDAP_OPERATIONS_ERROR;
LOG_FATAL("Failed to ber_printf the kvno\n");
LOG_FATAL("Failed to ber_printf the kvno");
goto done;
}
for (size_t i = 0; i < kset->num_keys; i++) {
for (int i = 0; i < kset->num_keys; i++) {
rc = ber_printf(ber, "{i}", (ber_int_t)kset->keys[i].key_data_type[0]);
if (rc == -1) {
rc = LDAP_OPERATIONS_ERROR;
LOG_FATAL("Failed to ber_printf the enctype\n");
LOG_FATAL("Failed to ber_printf the enctype");
goto done;
}
}
rc = ber_printf(ber, "}}");
if (rc == -1) {
rc = LDAP_OPERATIONS_ERROR;
LOG_FATAL("Failed to ber_printf the termination\n");
LOG_FATAL("Failed to ber_printf the termination");
goto done;
}
rc = ber_flatten(ber, &bvp);
if (rc == -1) {
rc = LDAP_OPERATIONS_ERROR;
LOG_FATAL("Failed to ber_flatten the buffer\n");
LOG_FATAL("Failed to ber_flatten the buffer");
goto done;
}
@@ -1313,7 +1306,7 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
/* get next kvno for entry (will be 1 if this is new) and fix keyset */
kvno = ipapwd_get_cur_kvno(targetEntry) + 1;
for (size_t i = 0; i < kset->num_keys; i++) {
for (int i = 0; i < kset->num_keys; i++) {
kset->keys[i].key_data_kvno = kvno;
}
@@ -1359,7 +1352,7 @@ static int ipapwd_setkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
rc = encode_setkeytab_reply(kset, &bvp);
if (rc) {
errMesg = "Internal Error.";
errMesg = "Internal Error.\n";
goto free_and_return;
}
@@ -1379,7 +1372,7 @@ free_and_return:
if (targetEntry) slapi_entry_free(targetEntry);
if (svals) {
for (size_t i = 0; svals[i]; i++) {
for (int i = 0; svals[i]; i++) {
slapi_value_free(&svals[i]);
}
free(svals);
@@ -1389,7 +1382,7 @@ free_and_return:
if (rc == LDAP_SUCCESS)
errMesg = NULL;
LOG("%s\n", errMesg ? errMesg : "success");
LOG("%s", errMesg ? errMesg : "success");
slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL);
return SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
@@ -1410,6 +1403,7 @@ static int decode_getkeytab_request(struct berval *extop, bool *wantold,
krb5_key_salt_tuple *enctypes = NULL;
bool newkt;
bool ret;
int i;
ret = ipaasn1_dec_getkt(extop->bv_val, extop->bv_len, &newkt,
&svcname, &password, &etypes, &numtypes);
@@ -1429,7 +1423,7 @@ static int decode_getkeytab_request(struct berval *extop, bool *wantold,
goto done;
}
for (size_t i = 0; i < numtypes; i++) {
for (i = 0; i < numtypes; i++) {
enctypes[i].ks_enctype = etypes[i];
enctypes[i].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL;
}
@@ -1472,7 +1466,7 @@ static int encode_getkeytab_reply(krb5_context krbctx,
/* uses last key kvno */
kvno = keys[num_keys-1].key_data_kvno;
for (size_t i = 0; i < num_keys; i++) {
for (int i = 0; i < num_keys; i++) {
krb5_enc_data cipher = { 0 };
krb5_data plain = { 0 };
krb5_int16 plen;
@@ -1522,7 +1516,7 @@ static int encode_getkeytab_reply(krb5_context krbctx,
rc = LDAP_SUCCESS;
done:
for (size_t i = 0; i < ksc.nkeys; i++) {
for (int i = 0; i < ksc.nkeys; i ++) {
free(ksc.ksdata[i].key.contents);
}
if (rc != LDAP_SUCCESS) {
@@ -1638,7 +1632,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
* this operation. */
if (bind_dn == NULL || *bind_dn == '\0') {
/* Refuse the operation because they're bound anonymously */
err_msg = "Anonymous Binds are not allowed.";
err_msg = "Anonymous Binds are not allowed.\n";
rc = LDAP_INSUFFICIENT_ACCESS;
goto free_and_return;
}
@@ -1654,7 +1648,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
if (!extop_value) {
LOG_FATAL("Failed to retrieve extended op value from pblock\n");
err_msg = "Failed to retrieve extended operation value";
err_msg = "Failed to retrieve extended operation value\n";
rc = LDAP_OPERATIONS_ERROR;
goto free_and_return;
}
@@ -1680,7 +1674,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
/* get Entry by krbPrincipalName */
target_entry = get_entry_by_principal(service_name);
if (!target_entry) {
err_msg = "PrincipalName not found.";
err_msg = "PrincipalName not found.\n";
rc = LDAP_NO_SUCH_OBJECT;
goto free_and_return;
}
@@ -1696,7 +1690,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
if (!acl_ok) {
LOG_FATAL("Not allowed to retrieve keytab on [%s] as user [%s]!\n",
service_name, bind_dn);
err_msg = "Insufficient access rights";
err_msg = "Insufficient access rights\n";
rc = LDAP_INSUFFICIENT_ACCESS;
goto free_and_return;
}
@@ -1707,8 +1701,6 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
/* if password was passed-in, check its length */
rc = ipapwd_check_max_pwd_len(strlen(password), &err_msg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
bind_dn, err_msg);
goto free_and_return;
}
}
@@ -1720,7 +1712,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
if (!acl_ok) {
LOG_FATAL("Not allowed to set keytab on [%s]!\n",
service_name);
err_msg = "Insufficient access rights";
err_msg = "Insufficient access rights\n";
rc = LDAP_INSUFFICIENT_ACCESS;
goto free_and_return;
}
@@ -1753,7 +1745,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
if (!svals) {
rc = LDAP_OPERATIONS_ERROR;
LOG_FATAL("encrypt_encode_keys failed!\n");
err_msg = "Internal error while encrypting keys";
err_msg = "Internal error while encrypting keys\n";
goto free_and_return;
}
@@ -1773,7 +1765,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
rc = encode_getkeytab_reply(krbctx, krbcfg->kmkey, mkvno,
keys, num_keys, &bvp);
if (rc != LDAP_SUCCESS) {
err_msg = "Internal Error.";
err_msg = "Internal Error.\n";
goto free_and_return;
}
@@ -1784,7 +1776,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
free_and_return:
if (rc == LDAP_SUCCESS) err_msg = NULL;
LOG("%s\n", err_msg ? err_msg : "success");
LOG("%s", err_msg ? err_msg : "success");
slapi_send_ldap_result(pb, rc, NULL, err_msg, 0, NULL);
/* Free anything that we allocated above */
@@ -1795,7 +1787,7 @@ free_and_return:
if (target_entry) slapi_entry_free(target_entry);
if (keys) ipa_krb5_free_key_data(keys, num_keys);
if (svals) {
for (size_t i = 0; svals[i]; i++) {
for (int i = 0; svals[i]; i++) {
slapi_value_free(&svals[i]);
}
free(svals);
@@ -2039,7 +2031,7 @@ int ipapwd_init( Slapi_PBlock *pb )
"ipapwd_post_init_betxn", ipapwd_post_init_betxn,
"IPA pwd post ops betxn", NULL,
ipapwd_plugin_id);
}
}
slapi_register_plugin("preoperation", 1,
"ipapwd_pre_init", ipapwd_pre_init,
@@ -70,7 +70,6 @@
#define IPAPWD_CHECK_CONN_SECURE 0x00000001
#define IPAPWD_CHECK_DN 0x00000002
#define IPAPWD_CHECK_ONLY_CONFIG 0x00000004
#define IPA_CHANGETYPE_NORMAL 0
#define IPA_CHANGETYPE_ADMIN 1
@@ -110,7 +109,6 @@ struct ipapwd_krbcfg {
char **passsync_mgrs;
int num_passsync_mgrs;
bool allow_nt_hash;
bool enforce_ldap_otp;
};
int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e,
@@ -33,7 +33,7 @@
* Authors:
* Simo Sorce <ssorce@redhat.com>
*
* Copyright (C) 2007-2023 Red Hat, Inc.
* Copyright (C) 2007-2010 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -248,13 +248,6 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
return 0;
}
/* Get target DN */
ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
if (ret) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
/* Ok this is interesting,
* Check this is a clear text password, or refuse operation */
if ('{' == userpw[0]) {
@@ -287,8 +280,6 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
} else {
rc = ipapwd_check_max_pwd_len(strlen(userpw_clear), &errMesg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
goto done;
}
userpw = slapi_ch_strdup(userpw_clear);
@@ -338,6 +329,13 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
goto done;
}
/* Get target DN */
ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
if (ret) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
/* time to get the operation handler */
ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op);
if (ret != 0) {
@@ -361,6 +359,7 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
} else {
char *binddn;
int i;
pwdop->pwdata.changetype = IPA_CHANGETYPE_ADMIN;
@@ -368,7 +367,7 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
slapi_pblock_get(pb, SLAPI_CONN_DN, &binddn);
/* if it is a passsync manager we also need to skip resets */
for (size_t i = 0; i < krbcfg->num_passsync_mgrs; i++) {
for (i = 0; i < krbcfg->num_passsync_mgrs; i++) {
if (strcasecmp(krbcfg->passsync_mgrs[i], binddn) == 0) {
pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
break;
@@ -386,8 +385,6 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
if ((pwdop->pwdata.changetype != IPA_CHANGETYPE_DSMGR) &&
(ret != 0) ) {
errMesg = ipapwd_error2string(ret);
LOG_PWDPOLICY("Failed to add password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
rc = LDAP_CONSTRAINT_VIOLATION;
goto done;
}
@@ -510,13 +507,6 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
goto done;
}
/* Get target DN */
ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
if (ret) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
/* grab the mods - we'll put them back later with
* our modifications appended
*/
@@ -578,8 +568,6 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
rc = ipapwd_check_max_pwd_len(bv->bv_len, &errMesg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
goto done;
}
slapi_ch_free_string(&unhashedpw);
@@ -603,6 +591,14 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
/* OK we have something interesting here, start checking for
* pre-requisites */
/* Get target DN */
ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
if (ret) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
tmp_sdn = slapi_sdn_dup(sdn);
if (tmp_sdn) {
/* xxxPAR: Ideally SLAPI_MODIFY_EXISTING_ENTRY should be
@@ -799,8 +795,6 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
const char *userpw_clear = &userpw[strlen("{CLEAR}")];
rc = ipapwd_check_max_pwd_len(strlen(userpw_clear), &errMesg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
goto done;
}
unhashedpw = slapi_ch_strdup(userpw_clear);
@@ -812,8 +806,9 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
slapi_ch_free_string(&userpw);
} else if (slapi_is_encoded(userpw)) {
errMesg = "Pre-Encoded passwords are not valid";
LOG("%s (%s)\n", errMesg, slapi_sdn_get_dn(sdn));
LOG("Pre-Encoded passwords are not valid\n");
errMesg = "Pre-Encoded passwords are not valid\n";
rc = LDAP_CONSTRAINT_VIOLATION;
goto done;
}
@@ -848,6 +843,7 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
} else {
char *binddn;
Slapi_DN *bdn, *tdn;
int i;
/* Check Bind DN */
slapi_pblock_get(pb, SLAPI_CONN_DN, &binddn);
@@ -861,16 +857,18 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
pwdop->pwdata.changetype = IPA_CHANGETYPE_ADMIN;
/* if it is a passsync manager we also need to skip resets */
for (size_t i = 0; i < krbcfg->num_passsync_mgrs; i++) {
for (i = 0; i < krbcfg->num_passsync_mgrs; i++) {
if (strcasecmp(krbcfg->passsync_mgrs[i], binddn) == 0) {
pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
break;
}
}
}
slapi_sdn_free(&bdn);
slapi_sdn_free(&tdn);
}
pwdop->pwdata.dn = slapi_ch_strdup(slapi_sdn_get_dn(sdn));
@@ -886,8 +884,6 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
if ((pwdop->pwdata.changetype != IPA_CHANGETYPE_DSMGR) &&
(ret != 0)) {
errMesg = ipapwd_error2string(ret);
LOG_PWDPOLICY("Check Password Policy failed for (%s) - %s/n",
pwdop->pwdata.dn, errMesg);
rc = LDAP_CONSTRAINT_VIOLATION;
goto done;
}
@@ -980,6 +976,7 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
int num_keys;
int mkvno;
int ret;
int i;
ret = slapi_entry_attr_find(entry, "ipaNTHash", &attr);
if (ret == 0) {
@@ -1011,7 +1008,7 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
ret = LDAP_UNWILLING_TO_PERFORM;
for (size_t i = 0; i < num_keys; i++) {
for (i = 0; i < num_keys; i++) {
char nthash[16];
krb5_enc_data cipher;
krb5_data plain;
@@ -1212,20 +1209,13 @@ done:
* value at the end. This leaves only the password in creds for later
* validation.
*/
typedef enum {
OTP_IS_NOT_REQUIRED = 0,
OTP_IS_REQUIRED_EXPLICITLY,
OTP_IS_REQUIRED_IMPLICITLY
} otp_req_enum;
static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
struct berval *creds, otp_req_enum otpreq,
bool *notokens)
struct berval *creds, bool otpreq)
{
uint32_t auth_types;
/* Get the configured authentication types. */
auth_types = otp_config_auth_types(otp_config, entry);
*notokens = false;
/*
* IMPORTANT SECTION!
@@ -1255,11 +1245,7 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
/* With no tokens, succeed if tokens aren't required. */
if (tokens[0] == NULL) {
otp_token_free_array(tokens);
*notokens = true;
if (otpreq != OTP_IS_NOT_REQUIRED)
/* DENY: OTP is required, either explicitly or implicitly */
return false;
return true;
return !otpreq;
}
if (otp_token_validate_berval(tokens, creds, NULL)) {
@@ -1270,8 +1256,7 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
otp_token_free_array(tokens);
}
return (auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD) &&
(otpreq == OTP_IS_NOT_REQUIRED);
return (auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD) && !otpreq;
}
static int ipapwd_authenticate(const char *dn, Slapi_Entry *entry,
@@ -1426,11 +1411,6 @@ done:
}
#ifdef USE_OP_NOTE_MFA_AUTH
/* defined in ldap/servers/slapd/pblock.c in 389-ds but not exposed via slapi-plugin.h */
extern void slapi_pblock_set_flag_operation_notes(Slapi_PBlock *pb, uint32_t opflag);
#endif
/* PRE BIND Operation
*
* Used for:
@@ -1448,7 +1428,6 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
"krbPasswordExpiration", "krblastpwchange",
NULL
};
struct ipapwd_krbcfg *krbcfg = NULL;
struct berval *credentials = NULL;
Slapi_Entry *entry = NULL;
Slapi_DN *target_sdn = NULL;
@@ -1464,7 +1443,6 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
struct tm expire_tm;
int rc = LDAP_INVALID_CREDENTIALS;
char *errMesg = NULL;
bool notokens = false;
/* get BIND parameters */
ret |= slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &target_sdn);
@@ -1523,28 +1501,9 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
/* Try to do OTP first. */
syncreq = otpctrl_present(pb, OTP_SYNC_REQUEST_OID);
otpreq = otpctrl_present(pb, OTP_REQUIRED_OID) ?
OTP_IS_REQUIRED_EXPLICITLY : OTP_IS_NOT_REQUIRED;
if (!syncreq && (otpreq == OTP_IS_NOT_REQUIRED)) {
ret = ipapwd_gen_checks(pb, &errMesg, &krbcfg, IPAPWD_CHECK_ONLY_CONFIG);
if (ret != 0) {
LOG_FATAL("ipapwd_gen_checks failed!?\n");
slapi_entry_free(entry);
slapi_sdn_free(&sdn);
return 0;
}
if (krbcfg->enforce_ldap_otp) {
otpreq = OTP_IS_REQUIRED_IMPLICITLY;
}
}
if (!syncreq && !ipapwd_pre_bind_otp(dn, entry,
credentials, otpreq, &notokens)) {
/* We got here because ipapwd_pre_bind_otp() returned false,
* it means that either token verification failed or
* a rule for empty tokens failed current policy. */
if (!(notokens || (otpreq == OTP_IS_NOT_REQUIRED)))
goto invalid_creds;
}
otpreq = otpctrl_present(pb, OTP_REQUIRED_OID);
if (!syncreq && !ipapwd_pre_bind_otp(dn, entry, credentials, otpreq))
goto invalid_creds;
/* Ensure that there is a password. */
if (credentials->bv_len == 0) {
@@ -1552,8 +1511,6 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
} else {
rc = ipapwd_check_max_pwd_len(credentials->bv_len, &errMesg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
goto invalid_creds;
}
}
@@ -1576,23 +1533,11 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
/* Attempt to write out kerberos keys for the user. */
ipapwd_write_krb_keys(pb, discard_const(dn), entry, credentials);
#ifdef USE_OP_NOTE_MFA_AUTH
/* If it was a successful authentication with OTP required, mark it
* for access log to notice multi-factor authentication has happened
* https://www.port389.org/docs/389ds/design/mfa-operation-note-design.html
*/
if (!syncreq &&
((otpreq != OTP_IS_NOT_REQUIRED) && !notokens)) {
slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_MFA_AUTH);
}
#endif
slapi_entry_free(entry);
slapi_sdn_free(&sdn);
return 0;
invalid_creds:
free_ipapwd_krbcfg(&krbcfg);
slapi_entry_free(entry);
slapi_sdn_free(&sdn);
slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL);
@@ -45,8 +45,6 @@
#define UID_NUMBER "uidnumber"
#define GID_NUMBER "gidnumber"
#define IPA_SID "ipantsecurityidentifier"
#define IPA_UNIQUEID "ipauniqueid"
#define IPA_UNIQUEID_AUTOGENERATE "autogenerate"
#define DOM_ATTRS_FILTER OBJECTCLASS"=ipantdomainattrs"
#define DOMAIN_ID_RANGE_FILTER OBJECTCLASS"=ipadomainidrange"
#define POSIX_ACCOUNT "posixaccount"
@@ -106,6 +104,3 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
const char *base_dn,
const char *dom_sid,
struct range_info **ranges);
int sidgen_task_init(Slapi_PBlock *pb);
int ipa_sidgen_init(Slapi_PBlock *pb);
@@ -454,7 +454,6 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
uint32_t id;
char *sid = NULL;
char **objectclasses = NULL;
char *uniqueid = NULL;
Slapi_PBlock *mod_pb = NULL;
Slapi_Mods *smods = NULL;
int result;
@@ -480,18 +479,8 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
goto done;
}
uniqueid = slapi_entry_attr_get_charptr(entry, IPA_UNIQUEID);
if (uniqueid != NULL &&
strncmp(IPA_UNIQUEID_AUTOGENERATE, uniqueid,
sizeof(IPA_UNIQUEID_AUTOGENERATE)) == 0) {
LOG("Staged entry [%s] does not have Posix IDs, nothing to do.\n",
dn_str);
ret = 0;
goto done;
}
if (uid_number >= UINT32_MAX || gid_number >= UINT32_MAX) {
LOG_FATAL("ID value too large on entry [%s].\n", dn_str);
LOG_FATAL("ID value too large.\n");
ret = LDAP_CONSTRAINT_VIOLATION;
goto done;
}
@@ -508,7 +497,7 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
&has_posix_group,
&has_ipa_id_object);
if (ret != 0) {
LOG_FATAL("Cannot determine objectclasses on entry [%s].\n", dn_str);
LOG_FATAL("Cannot determine objectclasses.\n");
goto done;
}
@@ -522,16 +511,15 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
id = (uid_number != 0) ? uid_number : gid_number;
objectclass_to_add = NULL;
} else {
LOG_FATAL("Inconsistent objectclasses and attributes on entry "
"[%s], nothing to do.\n", dn_str);
LOG_FATAL("Inconsistent objectclasses and attributes, nothing to do.\n");
ret = 0;
goto done;
}
ret = find_sid_for_id(id, plugin_id, base_dn, dom_sid, ranges, &sid);
if (ret != 0) {
LOG_FATAL("Cannot convert Posix ID [%lu] into an unused SID on "
"entry [%s].\n", (unsigned long) id, dn_str);
LOG_FATAL("Cannot convert Posix ID [%lu] into an unused SID.\n",
(unsigned long) id);
goto done;
}
@@ -566,7 +554,6 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
}
done:
slapi_ch_free_string(&uniqueid);
slapi_ch_free_string(&sid);
slapi_pblock_destroy(mod_pb);
slapi_mods_free(&smods);
@@ -89,7 +89,7 @@ static void free_pblock(void *arg)
static int do_work(struct worker_ctx *worker_ctx)
{
Slapi_PBlock *pb;
int ret, failures = 0;
int ret;
size_t c;
char *filter = NULL;
char *attrs[] = { OBJECTCLASS, UID_NUMBER, GID_NUMBER, NULL };
@@ -151,7 +151,8 @@ static int do_work(struct worker_ctx *worker_ctx)
worker_ctx->base_dn, worker_ctx->dom_sid,
worker_ctx->ranges);
if (ret != 0) {
failures++;
LOG_FATAL("Cannot add SID to existing entry.\n");
goto done;
}
if (worker_ctx->delay != 0) {
@@ -161,12 +162,6 @@ static int do_work(struct worker_ctx *worker_ctx)
}
};
ret = failures;
if (ret > 0) {
LOG_FATAL("Finished with %d failures, please check the log.\n",
failures);
}
done:
slapi_ch_free_string(&filter);
pthread_cleanup_pop(1);
@@ -30,7 +30,7 @@
* Program may make changes or additions to the list of Approved
* Interfaces.
*
* Copyright (C) 2010-2023 Red Hat, Inc.
* Copyright (C) 2010 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -1185,7 +1185,7 @@ static int ipauuid_pre_op(Slapi_PBlock *pb, int modtype)
* enforce is enabled. */
errstr = slapi_ch_smprintf("Only the Directory Manager "
"can set arbitrary values "
"for %s", cfgentry->attr);
"for %s\n", cfgentry->attr);
ret = LDAP_INSUFFICIENT_ACCESS;
goto done;
}
@@ -1221,7 +1221,7 @@ done:
}
if (ret) {
LOG("operation failure [%d] - %s\n", ret, errstr);
LOG("operation failure [%d]\n", ret);
slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL);
slapi_ch_free((void **)&errstr);
ret = EFAIL;
+1 -1
View File
@@ -5,7 +5,7 @@
# from the environment for the first two.
PYTHON ?= python3
VENVDIR = ./.venv
SPHINXOPTS ?= -W --keep-going -j 1
SPHINXOPTS ?= -W --keep-going -j auto
SPHINXBUILD ?= PATH=$(VENVDIR)/bin:$$PATH sphinx-build
SOURCEDIR = .
BUILDDIR = _build
-1
View File
@@ -8,7 +8,6 @@ Make multiple ipa calls via one remote procedure call
|methods|:ref:`Dict<Dict>`|False
### Options
* keeponly : :ref:`Str<Str>`
* version : :ref:`Str<Str>`
### Output
+1 -1
View File
@@ -27,7 +27,7 @@ No arguments.
* ipauserobjectclasses : :ref:`Str<Str>`
* ipapwdexpadvnotify : :ref:`Int<Int>`
* ipaconfigstring : :ref:`StrEnum<StrEnum>`
* Values: ('AllowNThash', 'KDC:Disable Last Success', 'KDC:Disable Lockout', 'KDC:Disable Default Preauth for SPNs', 'EnforceLDAPOTP')
* Values: ('AllowNThash', 'KDC:Disable Last Success', 'KDC:Disable Lockout', 'KDC:Disable Default Preauth for SPNs')
* ipaselinuxusermaporder : :ref:`Str<Str>`
* ipaselinuxusermapdefault : :ref:`Str<Str>`
* ipakrbauthzdata : :ref:`StrEnum<StrEnum>`
-262
View File
@@ -1,262 +0,0 @@
# Audit IPA API operations
## Overview
IPA servers present an API to perform various actions that change the state of
the deployment. These actions include, among others, modifications of user and
group databases, add or remove information about hosts and Kerberos services,
HBAC and SUDO rules, and many other action types.
It is possible to observe IPA API actions through the web server logs. Each IPA
server logs their API calls in `/var/log/httpd/error_log` log file, as part of
standard Apache webserver logs. However, IPA command line utilities, when run
as `root` on IPA server, operate directly against LDAP database and results of
these operations only present in LDAP logs.
Thus, current IPA API implementation does not provide a unified method to
collect logs to audit API operations. The goal of this change is to make sure
IPA API backend logs externally-initiated operations, regardless how these
operations were invoked.
## Use Cases
- As an administrator, I'd like to collect details on who and when has called
a particular IPA API on a particular IPA server. This information needs to be
easily queried and it should be possible to correlate it across all servers
in the IPA deployment.
- As an administrator, I'd like to make sure operations performed as part of
IPA administrative utilities are audited as well.
## How to Use
`journalctl` tool can be used to query and filter through the IPA
API audit details. Each logged entry will be tagged with an 'IPA.API' label and
thus can easily be queried:
```
# journalctl -g IPA.API
...
```
`journalctl -g` allows to search through the content of the log entries'
messages. Each found entry has associated metadata which can be retrieved in a
different format, depending on other options to `journalctl` invocation.
## Design
Audit of IPA API operations should happen independently. Operations should be
logged whenever they happen.
IPA deployment heavily relies on a working systemd setup. systemd provides
logging facilities in the form of a system journal. systemd journal allows
centralized collection of the journals from individual systems, forward secure
sealing of the forwarded data, and rich metadata associated with the log
entries. Thus, it already provides an infrastructure to allow secure
centralized collection of actions performed through IPA API on IPA servers.
From administrator's point of view, when IPA API operations logged through the
systemd journal, standard journal commands can be used to retrieve and
manipulate logged entries.
## Implementation
All IPA API calls end up in `Command.__do_call()` internal method. This method
prepares execution of the command and runs it. After the command was performed,
the output is formatted. If operations require forwarding the request to a
remote IPA server, this will be performed automatically. As a result,
`Command.__do_call()` is executed by both IPA client and IPA server components.
It is possible to derive a context of operations through IPA API environment,
using `api.env.in_server` boolean.
systemd journal provides a simple Python binding, `systemd.journal`, that
allows structured logging of the messages against a `journald` daemon running
on the system. If such operation is performed in the server context, system
journal will be updated.
To aid with identification of these messages, an application name is replaced
with IPA.API and the actual name from api.env.script is made a part of the
logged message. The actual application script name is available as part of the
journal metadata anyway. Additionally, a `MESSAGE_ID` property is set to IPA
API-specific application UID, generated with Python's
`uuid.uuid3(uuid.NAMESPACE_DNS, 'IPA.API')` function call. This value is
available in IPA constants (`ipalib/constants.py`) as `SD_IPA_API_MESSAGE_ID`.
The value of the constant is `6d70f1b493df36478bc3499257cd3b17`.
If no Kerberos authentication was used but rather LDAPI autobind was in use,
the name of the authenticated principal will be replaced with `[autobind]`
text.
Messages sent with syslog `NOTICE` priority.
An example session looks like the following output:
```
# ipa -e in_server=True console
(Custom IPA interactive Python console)
api: IPA API object
pp: pretty printer
>>> api.Command.user_del('foobar')
{'result': {'failed': []}, 'value': ['foobar'], 'messages': [{'type':
'warning', 'name': 'VersionMissing', 'message': "API Version number was not
sent, forward compatibility not guaranteed. Assuming server's API version,
2.253", 'code': 13001, 'data': {'server_version': '2.253'}}], 'summary':
'Deleted user "foobar"'}
>>> ^D
now exiting InteractiveConsole...
# journalctl -g IPA.API
May 21 11:31:33 master1.ipa1.test /usr/bin/ipa[247422]: [IPA.API] [autobind]: user_del: SUCCESS [ldap2_140328582446688] {"uid": ["foobar"], "continue": false, "version": "2.253"}
```
All operations triggered through IPA API logged, including locally initiated,
as can be seen in the output above. For httpd end-point operations will be
logged as requested by the `/mod_wsgi` binary:
```
May 21 11:35:19 master1.ipa1.test /mod_wsgi[247035]: [IPA.API] admin@IPA1.TEST: ping: SUCCESS [ldap2_139910420944784] {"version": "2.253"}
```
The message includes following fields:
- executable name and PID (`/mod_wsgi` for HTTP end-point)
- `[IPA.API]` marker to allow searches with `journalctl -g IPA.API`
- authenticated Kerberos principal or `[autobind]` marker for LDAPI-based access as root
- name of the command executed
- result of execution: `SUCCESS` or an exception name
- LDAP backend instance identifier. The identifier will be the same for all operations performed under the same request. This allows to identify operations which were executed as a part of the same API request instance. For API operations that didn't result in LDAP access, there will be `[no_connection_id]` marker.
- finally, a list of arguments and options passed to the command is provided in JSON format
If an API call results in multiple operations triggered by the internal
implementation of the API command, only the external operation is recorded.
This means, for example, that a `user_del` API call will only be recorded as a
`user_del` command and not a sequence of a `user_find`, `otptoken_find`,
`subid_find`, and corresponding deletion commands which `user_del`
implementation is using.
IPA supplies a message catalog to systemd journal which allows to explain
content of the audited message and provide references to corresponding IPA API
documentation. This feature is triggered by `journalctl -x` systemd journal
command.
Full journal entry looks like the one below and can be obtained with `journalctl -o json-pretty` command:
```
{
"PRIORITY" : "5",
"_HOSTNAME" : "master1.ipa1.test",
"__SEQNUM" : "608971",
"_COMM" : "ipa",
"_AUDIT_LOGINUID" : "0",
"CODE_FUNC" : "__audit_to_journal",
"_TRANSPORT" : "journal",
"__SEQNUM_ID" : "aa96317d3ab84c16b5f131922414af11",
"_CAP_EFFECTIVE" : "1ffffffffff",
"_MACHINE_ID" : "5582ad1e90354a2e82710afb4cd4477f",
"_RUNTIME_SCOPE" : "system",
"MESSAGE" : "[IPA.API] [autobind]: user_del: SUCCESS [ldap2_140155643874720] {\"uid\": [\"zuser3\"], \"continue\": false, \"version\": \"2.253\"}",
"CODE_LINE" : "495",
"__REALTIME_TIMESTAMP" : "1716360895014405",
"__MONOTONIC_TIMESTAMP" : "5952405665424",
"_SYSTEMD_OWNER_UID" : "0",
"_SYSTEMD_UNIT" : "session-30.scope",
"_SYSTEMD_CGROUP" : "/user.slice/user-0.slice/session-30.scope",
"CODE_FILE" : "/usr/lib/python3.12/site-packages/ipalib/frontend.py",
"_SYSTEMD_SESSION" : "30",
"_SYSTEMD_INVOCATION_ID" : "d166c864dba04b478d01658aa180d50d",
"_PID" : "255232",
"IPA_API_PARAMS" : "{\"uid\": [\"zuser3\"], \"continue\": false, \"version\": \"2.253\"}",
"MESSAGE_ID" : "6d70f1b493df36478bc3499257cd3b17",
"IPA_API_ACTOR" : "[autobind]",
"_SYSTEMD_SLICE" : "user-0.slice",
"IPA_API_COMMAND" : "user_del",
"_BOOT_ID" : "cce41ab07f404ced8676400eb01bf220",
"__CURSOR" : "s=aa96317d3ab84c16b5f131922414af11;i=94acb;b=cce41ab07f404ced8676400eb01bf220;m=569e7067690;t=6190569742605;x=265dd38af30f934c",
"_AUDIT_SESSION" : "30",
"SYSLOG_IDENTIFIER" : "/usr/bin/ipa",
"_UID" : "0",
"_SYSTEMD_USER_SLICE" : "-.slice",
"_SOURCE_REALTIME_TIMESTAMP" : "1716360895014364",
"_SELINUX_CONTEXT" : "unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023",
"_CMDLINE" : "/usr/bin/python3 -I /usr/bin/ipa -e in_server=True console",
"_EXE" : "/usr/bin/python3.12",
"_GID" : "0",
"IPA_API_RESULT" : "SUCCESS"
}
```
An explanation for this audit message can be generated with `journalctl -x` command:
```
# journalctl -x -g ldap2_140155643874720
May 22 06:54:55 master1.ipa1.test /usr/bin/ipa[255232]: [🡕] [IPA.API] [autobind]: user_del: SUCCESS [ldap2_140155643874720] {"uid": ["zuser3"], "continue": false, "version": "2.253"}
░░ Subject: IPA API command was executed and result of its execution was audited
░░ Defined-by: FreeIPA
░░ Support: https://lists.fedorahosted.org/archives/list/freeipa-users@lists.fedorahosted.org/
░░ Documentation: man:ipa(1)
░░ Documentation: https://freeipa.readthedocs.io/en/latest/api/index.html
░░ Documentation: https://freeipa.readthedocs.io/en/latest/api/user_del.html
░░ FreeIPA provides an extensive API that allows to manage all aspects of IPA deployments.
░░ The following information about the API command executed is available:
░░ [IPA.API] [autobind]: user_del: SUCCESS [ldap2_140155643874720] {"uid": ["zuser3"], "continue": false, "version": "2.253"}
░░ The command was executed by '/usr/bin/ipa' utility. If the utility name
░░ is '/mod_wsgi`, then this API command came from a remote source through the IPA
░░ API end-point.
░░ The message includes following fields:
░░ - executable name and PID ('/mod_wsgi' for HTTP end-point; in this case it
░░ was '/usr/bin/ipa' command)
░░ - '[IPA.API]' marker to allow searches with 'journalctl -g IPA.API'
░░ - authenticated Kerberos principal or '[autobind]' marker for LDAPI-based
░░ access as root. In this case it was '[autobind]'
░░ - name of the command executed, in this case 'user_del'
░░ - result of execution: `SUCCESS` or an exception name. In this case it was
░░ 'SUCCESS'
░░ - LDAP backend instance identifier. The identifier will be the same for all
░░ operations performed under the same request. This allows to identify operations
░░ which were executed as a part of the same API request instance. For API
░░ operations that didn't result in LDAP access, there will be
░░ '[no_connection_id]' marker.
░░ - finally, a list of arguments and options passed to the command is provided
░░ in JSON format.
░░ ---------
░░ The following list of arguments and options were passed to the command
░░ 'user_del' by the '[autobind]' actor:
░░
░░ {"uid": ["zuser3"], "continue": false, "version": "2.253"}
░░ ---------
░░ A detailed information about FreeIPA API can be found at upstream documentation API reference:
░░ https://freeipa.readthedocs.io/en/latest/api/index.html
░░ For details on the IPA API command 'user_del' see
░░ https://freeipa.readthedocs.io/en/latest/api/user_del.html
```
## Feature Management
There is no separate management of the IPA API audit logging. Logging is always
active on IPA server.
systemd journal has own mechanisms to control rates of messages coming from the
services. The details can be found in the man page `journald.conf(5)`.
## Upgrade
There is no impact on upgrade. Once new IPA API code installed, any new
application using it will start issuing log entries to the journald.
## Test plan
Test of IPA API audit logging can be done by observing systemd journal.
+3 -21
View File
@@ -43,20 +43,6 @@ There are a few basic rules:
### Installation
#### SELinux
The two supported hardware HSMs require additional SELinux permissions
so that IPA and certmonger have access to the tokens. There is a
separate module for each one: {free}ipa-selinux-nfast and
{free}ipa-selinux-luna. These are NOT installed by default and
the user must install the appropriate one manually.
During HSM validation early in the installation a check is made to
ensure that the correct module is installed but this is a best
effort and will not cause the installation to fail if the module
is not available.
#### CA
The token name, module name and shared library must be provided to the
@@ -71,10 +57,6 @@ are generated and stored in the HSM.
| --token-name | NSS name for the token |
| --library-path | Path to PKCS#11 shared library |
| --token-password | Password for the token |
| --token-password-file | File containing the token password |
If neither --token-password nor --token-password-file are provided
then the password will be obtained interactively.
This information will be stored in new schema so that replicas can auto-detect when an HSM is configured.
@@ -82,7 +64,7 @@ ipa-ca-install will accept the same options.
```
attributeTypes: (
2.16.840.1.113730.3.8.21.1.10
2.16.840.1.113730.3.8.21.1.TBD
NAME 'ipaCaHSMConfiguration'
DESC 'HSM Configuration'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
@@ -96,11 +78,11 @@ This attribute will be semi-colon delimited and contain the HSM information need
token-name;library-path
On a replica installation the token password will be prompted by ipa-replica-install or passed using the cli options.
The token password will be prompted by ipa-replica-install or passed on the cli.
The presence of this attribute is enough to indicate that an HSM is present in the installation and the options will automatically be used for additional servers and/or services. The password will not be stored and the user must provide them on the cli. Whenever a replica, replica CA, KRA or replica KRA is added this attribute will be examined to determine whether an HSM is available or not, and what the options are.
A user can override library-path on the command-line in case it is in a different location or architecture. A different token name would mean a different token and they cannot be mixed. If not provided on the command-line then the stored value will be used.
A user can override library-path on the command-line in case it is in a different location or architecture. A different token name would mean a different token and they cannot be mixed.
The NSS module name will be the basepath of the library minus .so*.
-411
View File
@@ -1,411 +0,0 @@
# Identity Mapping
In FreeIPA deployments user and group objects get their POSIX identities (IDs)
assigned and managed in an automated way. This document describes how
identity mapping is performed and enforced in FreeIPA deployments.
## Overview
FreeIPA deployment has three major identity mapping elements:
- automated identifier assignment through LDAP
- automated identifier assignment through SSSD
- identity information consistency enforcement in LDAP and Kerberos KDC
POSIX identities are allocated to objects that need to be visible at run-time
in POSIX environment. These are typically POSIX users and groups but there are
some exceptions to these objects, to accomodate specialized use cases.
In POSIX environment user and group identities are properties of several
different objects. When login session is initiated, the login process is
started as root (ID 0) and during login flow at some point a switch to a
certain user ID is performed. User's primary group is associated with a process
and information about other groups a user is a member of is populated as
'secondary groups' of the process. During lifetime of the process these lists
are typically left intact and cannot be modified unless a process possesses
certain administrative capabilities.
Both user and group IDs in POSIX environment are represented by unsigned
integers. In Linux environment user and group ID spaces are separate and fit
into 32-bit unsigned integer since 2001. Due to historical reasons, some of
file formats might not support more than 16- or 15-bit unsigned integer spaces
for UID and GID values. FreeIPA environment assumes operations in a
contemporary environment, with 32-bit user and group IDs.
[Linux Standard Base](https://en.wikipedia.org/wiki/Linux_Standard_Base) Core
Specification defines certain reserved ID ranges. Some Linux distributions or
projects go beyond that and define own ID ranges. To avoid conflicts with these
ranges, FreeIPA defines its own default ID ranges above 16-bit space.
For interoperability purposes a mapping between POSIX and non-POSIX identities
has to be established. The only supported non-POSIX identities for which there
exists a well defined mapping mechanism are identities represented with the
help of Security IDentifiers (SIDs) from Active Directory.
## Identity ranges
Each POSIX identity issued by the FreeIPA server is generated within a certain
identity range. ID ranges serve several purposes: they help multiple
FreeIPA components to coordinate identity allocation and convey details of the
purpose of the allocated identity ranges.
ID ranges are stored in LDAP, under `cn=ranges,cn=etc,$BASEDN` subtree. LDAP
objects for ID ranges are based on the `ipaidrange` objectclass. Depending on
the type of the range, other objectclasses might be added to express additional
attributes.
As of FreeIPA 4.11, there are following ID range categories in FreeIPA:
- local FreeIPA POSIX ID range (`ipa-local` ID range type)
- POSIX ID range for local subordinate identities (`ipa-ad-trust`)
- trusted domain ID range using automated allocation based on SID of an object (`ipa-ad-trust`)
- trusted domain ID range using explicit allocation for POSIX identities (`ipa-ad-trust-posix`)
These four categories expressed using three ID range types for technical reasons.
More ID ranges can be added through the lifetime of the deployment to
accomodate administrative needs. The main requirement for these additional
ranges is to not overlap with existing ranges. Range consistency is controlled
with the help of a specialized plugin to 389-ds LDAP server, `ipa-range-check`.
When a new range conflicts with existing configuration, its acceptance will be
refused and an LDAP error `LDAP_CONSTRAINT_VIOLATION` will be returned. This
ensures all ranges are in consistent state.
Trusted domain ID ranges have information about the domain SID of the
associated domain stored directly in the range LDAP object. For the local
domain ID ranges this information is stored elsewhere because only a single
organizational domain (as opposed to DNS domains) can be present in IPA
deployment.
Information about SID and other parameters of the local domain is stored in the
LDAP object `cn=<domain>,cn=ad,cn=etc,$SUFFIX`. This information is used for ID
mapping enforcement purposes by SID generation plugin and Kerberos KDC driver.
Information about SID and other parameters of a trusted domain is stored in the
LDAP object `cn=<domain>,cn=ad,cn=trusts,$SUFFIX`. It is used by the Kerberos
KDC driver when processing Kerberos requests.
### Local FreeIPA POSIX ID range
Each FreeIPA deployment has its own primary (or local) POSIX ID range. The
range is chosen during an initial server deployment and cannot be changed.
Initial `admin` user and associated groups (e.g. `admins`) are all allocated
from this range. The range size defaults to 200000 identities but both starting
point and the size of the range can be modified with `ipa-server-install`
options.
The primary ID range corresponds to the DNA range also created during the
initial IPA server deployment. When replica is deployed, this ID range already
exists in the topology and is visible to the replica. However, a corresponding
slice of the DNA range will not be created on the replica until the DNA plugin
on the replica is not asked to allocate an ID. See `Automated Identifier Assignment Through LDAP`_
section for details how DNA ranges are used.
### POSIX ID range for local subordinate identities
Subordinate identities are a Linux Kernel feature to grant a user additional
user and group ID ranges. Amongst others, the feature can be used by container
runtime engines to implement rootless containers. Traditionally subordinate ID
ranges are configured in `/etc/subuid` and `/etc/subgid`. More details about
subordinate ranges can be found in ["Subordinate IDs"](subordinate-ids.html)
design page.
Due to a technical use of a trusted domain type to represent ID range of the
local subordinate identities, the ID range has a domain SID associated with it.
The SID has a special structure: `S-1-5-21-738065-838566-$DOMAIN_HASH`.
`S-1-5-21` is the well-known SID prefix for domain SIDs. `738065-838566`
is the representation of the string `IPA-SUB`. `DOMAIN_HASH` is the
[MURMUR-3](https://en.wikipedia.org/wiki/MurmurHash) hash of the domain name
for key `0xdeadbeef`. SSSD rejects SIDs unless they are prefixed with
`S-1-5-21`. This SID is never used for any SID generation.
### Trusted domain ID range using automated allocation based on SID of an object
Active Directory environment does not use itself any POSIX identities because
they have no meaning within the context of Windows operating system. Each
object in Active Directory has associated security identifier (SID). SIDs stay
the same for the lifetime of the object and never re-used by other objects. SID
can be used to map an object in Active Directory to POSIX environment.
There are several methods to map SIDs to POSIX IDs. FreeIPA relies on an
algorithmic method provided by SSSD. The algorithm is described in
[sssd-ad(5) manual page](https://manpages.org/sssd-ad/5) in the section
"Mapping algorithm".
On start-up, SSSD looks up all ID ranges from the active IPA server and uses
information about trusted domains to map between SIDs and POSIX IDs. This
avoids static allocation of identities in LDAP. Instead, ID ranges in
FreeIPA serve as fences, to prevent other allocators from using these ranges
for static allocation.
For each trusted domain, a separate ID range is created since every trusted
domain has unique domain SID. Each ID range will have own POSIX ID range
allocation. These allocations can be created automatically during `ipa
trust-add` operation or ID ranges can be pre-created in advance with `ipa
idrange-add` operation. The latter is useful when there is a need to explicitly
define specific POSIX ID range boundaries as `ipa trust-add` command only
allows to define a new range's size.
### Trusted domain ID range using explicit allocation for POSIX identities
In case there is already existing static mapping of POSIX identities in Active
Directory, one can explicitly define ID range assocated with the trust to
Active Directory to handle explicit allocation. In this case SSSD will not use
algorithmic method but instead will look up identities from LDAP entry (e.g.
`uidNumber` and `gidNumber` attributes).
In case of explicit allocation, ID range associated with the trusted forest
Active Directory root domain must have ID range type of `ipa-ad-trust-posix`,
as well as all other domains visible through the trust link.
## ID range allocation
During deployment FreeIPA takes a random ID range slice from `(1,10000)` and
multiplies the base offset by 200000. This base becomes a starting point for
the deployment's ID range.
Both starting point and size of the range can be overridden by an administrator
who deploys the initial server. The minimal value for the initial ID range
start cannot be less than `UID_MAX` or `GID_MAX` from `/etc/login.defs`. This
range is then used by all systems enrolled into the domain managed by this
initial server.
Thus, a default range that FreeIPA chooses the deployment ID range from is
200000...2000000000. If this is a single domain and amount of users in it is
not going to be above 200K, then FreeIPA administrators may never need to
allocate another ID range within 200000...2000000000 and that original ID range
stays fixed forever.
There are two other use cases:
- trusting another IPA or AD deployment, and
- migrating pre-existing deployment not based on IPA.
When there are multiple organizational domains around and they need to
interoperate (establish trust between them), additional ID ranges get added on
the consuming side to represent trusted domain(s). For a trusted domain that is
an Active Directory, there would be two possibilities, managed within SSSD and
IPA:
- an ID range is implicit, defined through a murmurhash3 hash of the domain
SID,
- an ID range is explicit, defined by the admin as UID/GID values stored in AD
LDAP user entries for each user. The explicitly defined ID ranges most
likely are part of a legacy setup and most likely are within `UID_MAX` and
`GID_MAX` values from `/etc/login.defs`. There are exceptions, of course.
An implicit ID range derivation by SSSD is described in `sssd-ad(5)`, section 'ID
Mapping'. Samba has own way to derive similar ID ranges based on different
properties of the domain SID, handled by individual `idmap` modules but
conceptually it is similar: a rule is chosen to map those properties to POSIX
IDs and a map is maintained, algorithmically or based on a stored mapping in
Samba's own ID database.
With Active Directory environments all domain objects have their own unique
identifier, in the form of a SID. RID value of the SID is never reused when
objects get deleted and added. This means that for a company with an Active
Directory domain of ~20-25 years and large churn of employees over that time it
is not uncommon to see RIDs above 200K. For such deployments an ID range
SSSD and IPA would need to synthesize on Linux side would have size larger than
200K.
Thus ID range landscape is 'dynamic'. At a given time SSSD on the client will
be able to see all the ID ranges defined within the domain they enrolled into.
When a new trust is established and a new ID range for that trusted domain is
added, SSSD on the client will see this new ID range and will be able to derive
user/group IDs automatically for them. Most likely there are no existing files
on the client with ownership for these IDs yet -- except networking file
systems but for those to be usable at least one system should be able to create
those files with those POSIX IDs on a compatible client.
Existing ranges never change, LDAP plugins provided by FreeIPA prevent
modifying existing ranges in IPA or delete them if there are users/groups
with IDs assigned from those ID ranges.
## Automated identifier assignment through LDAP
When algorithmic ID range is used, SSSD only maps existing users and groups
coming from trusted Active Directory domains and those so based on their SID
values. For all other range types allocation of POSIX IDs is done in advance,
typically when user or group is created or moved from staged/preserved state.
This automated allocation is done with the help of [Distributed Numeric
Assignment (DNA) plugin](https://access.redhat.com/documentation/en-us/red_hat_directory_server/11/html/administration_guide/dna)
in 389-ds LDAP server. DNA plugin has its own identity ranges and provides a
generic mechanism to assign identities to various objects across the whole LDAP
topology. During installation of the original IPA server a DNA range is created
to match the primary IPA ID range. When new replicas added to IPA topology,
their DNA plugins become aware of the overal DNA range and may ask for a
sub-set of it for own needs. This sub-allocation only happens when DNA plugin
needs a range to allocate an ID. For example, when a user or a group is created
on that replica.
Since DNA ranges only get splitted and not extended automatically, IPA ID
ranges aren't tracking changes in DNA ranges. However, if somebody adds new DNA
ranges outside of the original primary IPA ID range, then a corresponding IPA
ID range needs to be created manually. This affects a lot of legacy deployments
where no real control over use of POSIX IDs through static allocation was done.
Another automatic ID assignment happens for SIDs. For each object in LDAP that
has POSIX attributes and `ipaNTUserAttrs` or `ipaNTGroupAttrs` object classes
upon creation a SID is generated by the `ipa-sidgen` 389-ds plugin. The SID is
stored in `ipaNTSecurityIdentifier` attribute. There is also another plugin,
`ipa-sidgen-task`, which handles a task of generating of SIDs for existing
objects. Both plugins issue error messages in the 389-ds error log in case they
were unable to map POSIX ID to a SID.
## ID mapping adjustments using ID overrides
On top of automatically or algorithmically allocated POSIX IDs, administrators
have possiblity to adjust POSIX IDs locally for users and groups coming from
trusted Active Directory domains. The same mechanism can also be used for
adjustments of POSIX IDs on individual IPA clients (or groups of IPA clients)
for legacy compatibility. These mechanisms should not be used for IPA users and
groups in general case because they might break certain assumptions in SSSD and
Kerberos KDC driver.
For users and groups from trusted Active Directory domains, ID overrides in
"Default Trust View" are used by SSSD on IPA server to override any ID
retrieved from the trusted domain controler side or generated algorithmically.
This mechanism allows to migrate pre-defined POSIX IDs from Active Directory by
creating ID overrides for individual users and groups.
From SSSD point of view, these ID overrides represent `uidNumber` and
`gidNumber` attributes as if they were specified in the original LDAP object
entry.
IPA users and groups cannot have ID overrides in the "Default Trust View".
Their POSIX IDs have to be present in their own LDAP object entries.
## Security IDentifiers
While primary goal of FreeIPA is to serve identities for POSIX environment, a
large effort is put into making interoperability with other identity management
systems, out of which Active Directory is the most important one. Active
Directory is using a different method to control access to their resources than
POSIX environment and this method extends from identity management to
authorization mechanisms. It is also has visible effects on various protocols
through which FreeIPA interoperability with Active Directory is achieved.
One of the corner stones of Active Directory security model is the [security
identifier (SID)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/78eb9013-1c3a-4970-ad1f-2b1dad588a25)
assignment to each object in Active Directory that can be used for security
evaluation. Objects grouped by Active Directory domains, each domain having a
domain SID and all objects within the same domain have their SIDs starting with
the SID of the domain. The relative identifier (RID) is the unique identity of
an object within the domain scope. A full object SID, thus, is a combination of
the `<domain-SID>-<object RID>`.
Since objects are unique within the domain, RIDs can be reused in different
domains. There are common, so-called ['well-known'
identifiers](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/81d92bba-d22b-4a8c-908a-554ab29148ab),
which express the same functional objects in different domains. These
well-known objects have the same RID values but still be distinct: Objects from
`domain1.test` and `domain2.test` with the same RID values will be different.
For example, domain administrator user `Administrator` has RID value 500.
`Administrator` user from `domain1.test` would be different from
`Administrator` user from `domain2.test`, even though their individual RIDs
(500) would be the same. If `domain1.test` has SID `S-1-5-21-123-45-6789` and
`domain2.test` has SID `S-1-5-21-54-321-6789` then `Administrator` user from
`domain1.test` would have SID `S-1-5-21-123-45-6789-500` and `Administrator`
user from `domain2.test` would have SID `S-1-5-21-54-321-6789-500`.
Internally Active Directory does only use user and group names to perform
translation to a SID. Once SID of the object who authenticated the connection
is established, names don't matter anymore. For each authenticated object
within a specific connection a special security token is built which contains
this object's membership information in form of SIDs of groups it belongs to.
Access control lists attached to Active Directory objects contain SIDs as well,
making access control evaluation straightforward: security token SID details
evaluated against access control lists to grant or deny access.
This model is loosely similar to how processes in POSIX environment get
evaluated when accessing resources. Each POSIX process has user identity it is
running under, with a set of primary and secondary groups associated with the
identity as part of the process description. The difference is that POSIX UID
and GID values exist only on a single machine and a care to avoid conflicts
between multiple systems should be taken. In Active Directory model the SIDs
are already bearing domain-specific information, hence allowing to distinguish
objects belonging to different systems. The latter means for both networking
and local resources such as file systems a single access control list mechanism
can be used to address both remote and local identities.
Since SIDs do not exist in POSIX environment, mapping of objects from trusted
Active Directory domains to POSIX environment within IPA deployment is based on
other properties. In particular, a fully-qualified user or group name is used
to represent the user (or group): a user Administrator from `domain1.test`
would have a fully-qualified name `Administrator@domain1.test`, different from
the user Administrator of the domain `domain2.test` which would have a
fully-qualified name of `Administrator@domain2.test`.
Above description uses so-called user principal name (UPN) notation to describe
user names. In this notation a user name corresponds to a (case-insensitive)
Kerberos principal name. Since each Active Directory domain is a Kerberos
realm, this allows to establish mapping between identities on POSIX and Active
Directory levels through Kerberos authorization mechanism.
Active Directory has extended Kerberos protocol by adding a privilege
attributes certificate (PAC) information to the Kerberos ticket issued by
Active Directory domain controllers. The PAC part contains the security token
details of the authenticated object represented by the Kerberos principal.
These details are protected by a set of security checksums that prevent
external modifications to the PAC content. This information is detailed in the
[MS-PAC] and [MS-KILE] specifications Microsoft has published and Open Source
projects such as MIT Kerberos, Heimdal Kerberos, Samba, and FreeIPA have since
implemented.
## Enforcement of ID mapping
For trusted domains using Kerberos protocol to establish trust, a duty to
validate information falls onto Kerberos KDCs of each realm. FreeIPA KDCs
re-assess content of the presented Kerberos tickets and validate PAC issued by
a trusted domain's domain controller. This validation includes checks to make
sure only SIDs from trusted domains can be present there and a trusted domain's
KDC cannot inject SIDs that belong to IPA domain.
The latter is needed because both sides of the trust possess a key that
represents a cross-realm service principal, `krbtgt/DOMAIN1.TEST@DOMAIN2.TEST`.
This key allows KDC from `DOMAIN1.TEST` realm to issue a service ticket that a
client from `DOMAIN1.TEST` can present to a KDC from `DOMAIN2.TEST` to request
a service ticket for a service from `DOMAIN2.TEST`. If a KDC from
`DOMAIN1.TEST` goes rogue and decides to inject SIDs of groups from
`DOMAIN2.TEST` into a security token of the user from `DOMAIN1.TEST`, nothing
can stop it. Thus, a KDC from `DOMAIN2.TEST` must validate that a token encoded
in the PAC buffer of the Kerberos ticket coming from the `DOMAIN1.TEST` is
'sane'.
Sanity checks performed by the KDC in FreeIPA include multiple steps. For each
trusted domain FreeIPA records a list of SIDs that must be filtered out
unconditionally. This list is based on the section ['4.1.2.2 SID Filtering and
Claims Transformation'](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/55fc19f2-55ba-4251-8a6a-103dd7c66280)
of the [MS-PAC] specification. The list can be extended for each specific
domain using `ipa trust-mod` command for both incoming
(`--sid-blacklist-incoming`) and outgoing (`--sid-blacklist-outgoing`)
directions.
Additionally, KDC verifies that a PAC issued by a trusted domain's KDC does not
contain SIDs from IPA domain. In such case the ticket issuance will be rejected.
For each ticket issued, KDC adds information about the requestor's SID
in a separate PAC buffer. During processing of the consequent requests KDC does
validate that a requestor SID is the same as the SID of the identity of the
security token in PAC buffer. This information is then cross-verified against
the list of known trusted domains to avoid cases of impersonation exploited
through [CVE-2020-25721].
As a consequence of these checks, FreeIPA Kerberos KDC only issues initial
Kerberos tickets for principals which have SID assigned. The SID assignment in
FreeIPA is tied to presence of an ID range that covers both `uidNumber` and
`gidNumber` of the LDAP object representing the principal. If there is no such
range can be found, SID will not be issued and a Kerberos principal associated
with this LDAP object will be used for authentication. Thus, SID and POSIX
attributes are tied together.
[MS-KILE]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-kile/2a32282e-dd48-4ad9-a542-609804b02cc9
[MS-PAC]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/166d8064-c863-41e1-9c23-edaaa5f36962
[CVE-2020-25721]: https://www.samba.org/samba/security/CVE-2020-25721.html
-2
View File
@@ -32,5 +32,3 @@ FreeIPA design documentation
passkeys.md
prci_checker.md
rbcd.md
id-mapping.md
audit-ipa-api.md
+313 -396
View File
@@ -1,10 +1,12 @@
# IPA Migration
## Overview of the old plugin-based migration
## Overview
IPA has had a plugin-based migration for remote LDAP servers since version 2.0.0. It will only migrate users and groups.
IPA has had a plugin-based migration for remote LDAP servers since
version 2.0.0. It will only migrate users and groups.
It has some powerful capabilities for working around eccentricities in the remote server including:
It has some powerful capabilities for working around eccentricities in
the remote server including:
* it is idempotent
* support for both RFC2307 and 2307bis
@@ -16,272 +18,198 @@ This is insufficient for the following reasons:
* It severely limits IPA-to-IPA migration as all other entry types are lost
* User-private groups are not maintained
* Syntax errors can cause migration to fail with the only resolution being to skip broken entries or fix the remote LDAP server
* It is executed as a server-side plugin and if it runs long enough the client may disconnect
* Syntax errors can cause migration to fail with the only resolution
being to skip broken entries or fix the remote LDAP server
* It is executed as a server-side plugin and if it runs long enough the
client may disconnect
* There is no feedback during the migration beyond watching the logs
* There is no migration-specific log
The basic operation includes:
* loop through the remote user and group containers examining each entry
* if it looks like a user or group (based on objectclass) try to migrate it
* if it looks like a user or group (based on objectclass) try to
migrate it
* convert group membership from the detected or provided RFC
* retain passwords if the provider LDAP bind user can read them
* drop conflicting attributes (like kerberos)
* skip duplicates so it can be rerun multiple times
* convert groups to IPA POSIX groups
### Use cases for a new IPA to IPA migration tool
## Use Cases
There are two use-cases driving a re-implementation (or extension) of migration:
There are two use-cases driving a re-implementation (or extension) of
migration:
1. Addressing bugs in current LDAP-only migration code
2. Adding IPA-to-IPA migration including all entry types.
## IPA to IPA migration
## Migration basics
### Terminology
### General considerations
In the following sections we will describe the IPA server that has the data we are pulling the migration data from as the **remote server**, and the **local server** is the new IPA server that will receive this data. So the **local server** is the new server and also the server where the migration tool will be run from. In other words the migration tool pulls from the remote server and applies it to the local server.
LDAP stores information in a tree structure known as the Directory
Information Tree (DIT). Each node in the tree is an entry and each
entry contains information in an attribute=value form. It is a very
different storage model than a relational database as there is no
"join" capability between entries (among other things).
### Prerequisites
The organization of the entries depends on schema which defines which
object types (objectclasses) and attributes (attributetypes) are
allowed. https://ldap.com/ has a pretty decent introduction to LDAP,
schemas, etc. The important thing to understand is that in order for
an attribute to be in an entry, there must be a corresponding
objectclass which allows it, either as a MUST or MAY. The schema defines
a syntax for that attribute which defines what type of data may be
stored in it. Some LDAP servers do a better job than others at enforcing
this syntax.
You must install IPA on the new system (local server), and the domain/suffix must be the final expected values. The remote data will be converted to match the new local server. Typically it is expected that this installation be bare. The tool was not designed to merge two different installations (although it might work).
### pure LDAP migration
### IPA to IPA migration design
While it is easy to see a remote LDAP migration as a subset of IPA to
IPA it is better to keep them as separate for the following reasons:
- IPA-to-IPA migration will be implemented as an *AdminTool* standalone client tool: **/usr/sbin/ipa-migrate**
- Migration will consist of three areas:
- Schema - the LDAP schema (objectclasses and attributes)
- Config - the LDAP configuration under **cn=config** (dse.ldif)
- Database - the main LDAP database
- Allow online (LDAP over the network) or offline (LDIF file) migration. You can mix and match
LDIF (offline) with LDAP (online)
1. It represents a small subset of a typical IPA installation: only
users and groups.
2. The remote schema and DIT are unknown and different for each migration so it will require more care.
3. The quality of the data is unknown. 389-ds, used by IPA, enforces proper syntax where other servers may not.
### Online migration
### IPA to IPA migration
Online migration consists of contacting the remote server over the network and pulling in all the required information. With very large databases this could impact the tool's performance
For an IPA to IPA migration it is possible to make certain assumptions
that aren't possible in a pure LDAP migration including:
### Offline migration
1. The DIT is understood and consistent
2. Unique UID/GID/login/group name(s) so additional checking is not necessary
3. A consistent schema (perhaps variability for users and groups)
Offline migration consists of using LDIF files from the remote server
- Config - the DS config file: **/etc/dirsrv/slapd-YOUR_LDAP_INSTANCE/dse.ldif**
- Schema - all the schema files found under **/etc/dirsrv/schema/** and **/etc/dirsrv/slapd-YOUR_LDAP_INSTANCE/schema/**
- Database - You need to export the **userroot** database to an ldif file
## Design
Then copy these LDIF files to the new **local server**
### IPA to IPA migration
### Mixing online and offline methods
It would be risky to hardcode the data to pull in. It is far simpler to
iterate the things you *don't* want to migrate. This should also improve
the chances for future-proofing and preventing bugs like not migrating
some new feature area. It will require that versions only migrate up or
sideways and not backwards.
You are allowed to mix and match both approaches. The most advantageous reason to mix and match these approaches would be if you have a very large database. You can do the config and schema migration online and then use a database LDIF from the remote server for the database migration. This will perform faster than reading and comparing thousands of entries over the network. It will also be more stable. You won't have to worry about network issues breaking the process mid-migration.
IPA-to-IPA migration will be implemented as an AdminTool standalone
client.
### Dry-run migrations
#### Prerequisites
You can also do a dry-run of the migration to see what would be migrated to the new local server. In addition to a dry-run you can also record to an LDIF file what LDAP operation would be performed during the migration. This LDIF file can be inspected to see fine grained details about what the migration would do, "replayed" to perform the migration at later date, or to reuse a common deployment on multiple IPA servers.
A migration should only be done to a single IPA server. This will greatly
simplify certain things, particularly performance. We may want an option
to allow this and deny it by default.
### Migration modes
If DNS is enabled on the remote server it will need to be enabled in
the local one in order to migrate DNS data. It would need to be determined
if the DNS DIT exists in a migrated server would allow bind to be
configured (I suspect it will) but we don't want to get into a situation
where the migrated DNS data is unusable.
As of right now there are two migration modes, but in the future there could be more. Migration modes allow for easier use of the tool. the mode will define what is migrated and what is not.
#### Retain REALM/domain
#### Production mode
It will be optional to retain the same REALM and domain. This will make the
use-cases of staging and development server migration possible.
In production mode basically everything is brought over. It is assumed that the *remote server* is/was fully functional and the database and entry states are valid. This means things like DNA ranges, IDs, and SIDs (ipantsecurityidentifier) will be migrated as is.
#### Retain ranges
#### Staging mode
This is TBD. I don't know of a reason why a user wouldn't want to retain the
ranges as it would affect owned files, etc, but *someone* may want to make a
clean break. I don't believe it would be difficult to deal with as we would
just set the magic values for DNA generation.
In this mode it is assumed that the remote server was in a staging environment and that things like the DNA ranges and ID attributes (uidNumber, gidNumber, etc) should **not** be migrated as is. The DNA entry attributes will be reset to the *magic regen* value.
In order to retain the range then the remote and local ranges would need to
be compared and the migration rejected if they do not overlap (perhaps allowed
with --force).
### Migration content
As for DNA, if the range remains some effort will need to be made to set the
local DNS configuration to match what is available remotely.
This section will describe how various entries & attributes will be migrated to the local server.
This may not be ideal. The basic process would be:
#### REALM/Domain
* connect to all servers in the remote IPA installation
* collect the DNA and on-deck ranges
* determine the starting point
* set the local DNA range to this starting point + the range end - 1
For realm/domain/suffixes all the remote data will be converted to match the the new local server. This will apply to all the entries and subtrees. This is an automatic process and can not be adjusted or disabled. This is why it's important when you install the new local server that you set the realm/domain/database suffix to the expected production values.
This could well leave huge holes of allocated values within the range but the
DNA plugin should be able to handle that.
#### ID ranges
subids TBD. It may be fine to just straight migrate the range and records.
The migration mode (production or staging) will determine if the ID ranges are migrated or not. You can still skip the ID range migration in production mode using a CLI option and the tool will reset the DNA attributes (uidNumber, gidNumber, etc) to the magic regeneration value.
#### Discovery of IPA objects
#### Skipped attributes
The objects to migrate can be determined by examining the local API.
It can be iterated to discover the available class objects which contain
the container_dn and other useful information. Not all objects need
to be migrated either because they are internal objects, represent
schema or represent commands that have no underlying storage.
Initialize the API and iterate over Object:
When adding new entries to the local server the following attributes are skipped ...
api.bootstrap(in_server=True, context='migrate')
api.finalize()
Operational attributes
- modifiersname
- modifytimestamp
- creatorsname
- createtimestamp
- nsuniqueid
- dsentrydn
- entryuuid
for obj in api.Object:
work()
Standard attributes
- krbextradata
- krblastfailedauth
- krblastpwdchange
- krbloginfailedcount
- krbticketflags
- krbmkey
- ipasshpubkey --> We do keep the public key for users
- mepmanagedentry
- memberof
- krbprincipalkey
- memberofindirect
- memberindirect
- memberofindirect
- memberindirect
- userCertificate --> if issued by the remote IPA server
This gives us an alphabetized list of objects. An implicit relationship
can be determined by examining the member* values in `obj.attribute_members`
if it is present.
#### Ignored attributes
Using this list we know which are "leaf" entries which have no dependencies.
These are migrated first. Then the list is iterated again looking for
those with dependencies that are already satisfied and those are migrated.
And so on.
When comparing entries (not when adding entries) the following attributes are ignored and the value that exists on the local server will remain intact
So for example users and hosts are migrated. Then groups, which has a dependency on
users. Then hostgroups can then be migrated.
- description
- ipasshpubkey
- ipantsecurityidentifier --> except in production mode
- ipantflatname
- ipamigrationenabled
- ipauniqueid
- serverhostname
- krbpasswordexpiration
- krblastadminunlock
Some objects, like hostgroups, can be nested. These will need to be deferred until
all of their members are added. If a running list of objects that have been migrated
is maintained then it can be easily calculated which are ready for migration and
which are not without having to refer to LDAP.
#### DNS records
#### Objects to ignore
By default all DNS entries are migrated, but you can skip the DNS records via a CLI option.
The IPA API object list includes an number of internal-only objects and
some classes that represent informational commands so they can be skipped
for migration.
#### Limited migration
| Object | Reason |
| --- | ----- |
| certreq | no storage |
| class | schema |
| command | internal |
| cosentry | migration not needed |
| dns_system_records | no storage |
| metaobject | schema |
| param | internal |
| pkinit | no storage |
| topic | internal |
| userstatus | no storage |
If there are cases where you don't want to migrate the configuration or schema there are CLI options to skip each of these areas.
#### Objects TBD
#### Non-IPA content
Each DNS record type is represented as a separate class. It is probably safe
to just bulk import all dns records as there isn't any IPA-specific information in them.
Some Administrators store non-IPA content in the database tree. In order for this content to be migrated it must be specified via a CLI option.
So basically add them to the ignore list.
### Configuration migration design
#### Other Containers
The following sections of the Directory Server configuration will be migrated
Not all data in IPA can be manipulated with the API.
#### Core configuration (cn=config)
cn=certificates,cn=ipa,cn=etc,$SUFFIX contains any user-provided certificates.
I think we can skip this and require that any necessary certificates be
re-added. Otherwise, to be safe, we should validatate the trust and expiration
dates on all of them.
The core configuration attributes will be migrated to the core server. Things like performance tuning, security settings, and log rotation settings.
DNA ranges. Depending on the local ranges we could try to recover them.
#### Database settings
The various look through limits, ID scan limits, import cache size, backend indexes, and encrypted attributes are migrated.
#### Plugins
The following plugins are migrated
- Attribute Uniqueness plugins
- DNA Plugins
- MemberOf plugin
- Referential integrity plugin
- Retro Changelog plugin
- SASL Mapping plugins
- IPA DNS plugin
- IPA Enrollment plugin
- IPA Extdom plugin
- IPA Graceperiod plugin
- IPA Lockout plugin
- IPA Password Policy plugin
- IPA Topology plugin
- IPA Unique ID plugins
- IPA Winsync plugin
- Schema Compatibility plugin
- Slapi NIS plugin
### Schema migration design
By default any *missing* objectclasses and attributes are migrated. There is also a CLI option to completely overwrite the existing schema on the local server with the remote server's schema.
### Database migration design
The following subtrees and entries are migrated. Any missing entries will be added, and any existing entries will be compared and any differences will be merged into the new local server
#### Plugin entries
- Automember Definitions (subtree of ```cn=automember,cn=etc,$SUFFIX```)
- DNA Ranges (subtree of ```cn=ranges,cn=etc,$SUFFIX```)
- DNA Posix IDs (```cn=automember,cn=etc,$SUFFIX```)
- DNA SubIDs (```cn=subordinate-ids,cn=dna,cn=ipa,cn=etc,$SUFFIX```)
- MEP Templates (subtree of ```cn=templates,cn=managed entries,cn=etc,$SUFFIX```)
- MEP Definitions (subtree of ```cn=definitions,cn=managed entries,cn=etc,$SUFFIX```)
#### Etc entries
- Anonymous Limits (```cn=anonymous-limits,cn=etc,$SUFFIX```)
- CA (```cn=ca,$SUFFIX```)
- IPA Config (```cn=ipaconfig,cn=etc,$SUFFIX```)
- Sys Accounts (subtree of ```cn=sysaccounts,cn=etc,$SUFFIX```)
- Topology (subtree of ```cn=topology,cn=ipa,cn=etc,$SUFFIX```)
- Certmap (```cn=certmap,$SUFFIX```)
- Certmap Rules (subtree of ```cn=certmaprules,cn=certmap,$SUFFIX```)
- s4u2proxy (subtree of ```cn=s4u2proxy,cn=etc,$SUFFIX```)
- Passkey Config (```cn=passkeyconfig,cn=etc,$SUFFIX```)
- Desktop Profile (```cn=desktop-profile,$SUFFIX```)
- OTP (```cn=otp,cn=etc,$SUFFIX``)
- Realm (subtree of ```cn=realm domains,cn=ipa,cn=etc,$SUFFIX```)
- AD (subtree of ```cn=ad,cn=etc,$SUFFIX```)
- Master Configurations (subtree of ```cn=masters,cn=ipa,cn=etc,$SUFFIX```)
- Domain Configuration (```cn=domain level,cn=ipa,cn=etc,$SUFFIX```)
#### Accounts
- Computers (subtree of ```cn=computers,cn=accounts,$SUFFIX```)
- Administrator (uid=admin,cn=users,cn=accounts,$SUFFIX)
- Users (subtree of ```cn=users,cn=accounts,$SUFFIX```)
- Groups (subtree of ```cn=groups,cn=accounts,$SUFFIX```)
- Roles (subtree of ```cn=roles,cn=accounts,$SUFFIX```)
- Host Groups (subtree of ```cn=hostgroups,cn=accounts,$SUFFIX```)
- Services (subtree of ```cn=services,cn=accounts,$SUFFIX```)
- Views (subtree of ```cn=views,cn=accounts,$SUFFIX```)
- IP Services (subtree of ```cn=ipservices,cn=accounts,$SUFFIX```)
- Sub IDs (subtree of ```cn=subids,cn=accounts,$SUFFIX```)
#### HBAC & PBAC
- HBAC Services (subtree of ```cn=hbacservices,cn=hbac,$SUFFIX```)
- HBAC Service Groups (subtree of ```cn=hbacservicegroups,cn=hbac,$SUFFIX```)
- PBAC Privileges (subtree of ```cn=privileges,cn=pbac,$SUFFIX```)
- PBAC Permissions (subtree of ```cn=permissions,cn=pbac,$SUFFIX```)
#### Sudo
- Sudo Rules (subtree of ```cn=sudorules,cn=sudo,$SUFFIX```)
- Sudo Commands (subtree of ```cn=sudocmds,cn=sudo,$SUFFIX```)
- Sudo Command Groups (subtree of ```cn=sudocmdgroups,cn=sudo,$SUFFIX```)
#### DNS
- DNS Records (subtree of ```cn=dns,$SUFFIX```)
- DNS Servers (subtree of ```cn=servers,cn=dns,$SUFFIX```)
#### Kerberos
- Kerberos Realm & Policy (subtree of ```cn=kerberos,$SUFFIX```)
- Kerberos Password Policy (```cn=global_policy,cn=$REALM,cn=kerberos,$SUFFIX```)
- Kerberos Default Password Policy (```cn=default kerberos service password policy,cn=$REALM,cn=kerberos,$SUFFIX```)
#### Misc
- Automounts & Automount Maps (subtree of ```cn=automount,$SUFFIX```)
- Trusts (subtree of ```cn=trusts,$SUFFIX```)
- Provisioning (subtree of ```cn=accounts,cn=provisioning,$SUFFIX```)
- SELinux Usermaps (subtree of ```cn=usermap,cn=selinux,$SUFFIX```)
- DUA Config Profiles (subtree of ```ou=profile,$SUFFIX```)
- CA Certificates (subtree of ```cn=certificates,cn=ipa,cn=etc,$SUFFIX```)
#### Excluded Subtrees
- All Class Of Service (COS) entries
- ```cn=sec,cn=dns,$SUFFIX```
- ```cn=custodia,cn=ipa,cn=etc,$SUFFIX```
#### Entries NOT be to migrated
#### Items to NOT be migrated
We will not have migrate existing keys from the remote IPA server so the
following will not be migrated:
@@ -293,11 +221,127 @@ following will not be migrated:
* DNSSEC keys
* admin password
* DM password
* Anything in Custodia
* Basically anything in Custodia
### Migration steps
#### Migrating conflicting data
A simplistic view of the steps (the following might be outdated/unnecessary - TODO)
For new entries (users, groups, hosts, etc) we can do a straight LDAP
ADD after massaging necessary attributes (see Attributes to not migrate).
That is the easy part.
There are some parts of IPA that are default and will exist in both servers
such as the configuration (config commands), allow_all HBAC rule,
permissions, privileges, roles, selinux mappings, ipaservers hostgroup and more.
The strategy for this will be use the existing entry comparison in ldap2 and
modify the new IPA instation to match the original minus some specific things like
the CA subject base in the config. So in most cases we favor the remote IPA
installation except for things which are installation-dependent.
The downside of this is that it could interpret "fresher" defaults in the
new IPA server with stale ones from the old. We will need good logging around
these types of entries.
Standard boilerplate will not be evaluated, things like cosTemplates. These are not
user-modifiable and if a user decides to mess with them, they can correct it
after migration.
#### Migrating cn=config
A number of plugins are optional in IPA: nis, compat, ACME.
These will be enabled in the new IPA server if enabled in the remote at
the end of migration:
* cn=Schema Compatibility, cn=plugins, cn=config
* cn=NIS Server, cn=plugins, cn=config
Schema compatibility will be disabled during migration as it can cause
performance issues and we don't want to try to migrate anything in
cn=compat since it is generated data.
ACME is a feature of the CA. We should be able to import ipa_acme_manage
and call enable/disable within the migration if it is remotely enabled.
#### Configuration to not migrate
These will not be migrated:
* AD Trusts
* Winsync configuration (though the entries will)
* CA, KRA
* DNSSEC
#### Special migration
cn=kerberos contains the Kerberos master key as well as the default
ticket policy. Only the policy can be migrated.
#### Attributes to not migrate
Some attributes we will need to completely drop because they contain key or
server-specific information for the remote IPA server. This may also
include objectClasses that may need to be dropped if the last attribute
is removed.
* krbPrincipalKey (will require dropping objectclasses)
* krbExtraData
* ipaNTSecurityIdentifier
* memberOf (will be reconstructed after the migration)
* userCertificate if issued by the remote IPA server
#### Attributes to update to new REALM
If a REALM change is part of migration then these will need to be updated
to reflect the new installation.
* krbPrincipalKey
* krbCanonicalName
#### Attributes to change basedn
Prior to writing a new value any DN syntax attributes will need to be
examined to see if they contain the remote baseDN if it is different. If
so then the following need to be updated:
* mepManagedEntry
* mepManagedBy
#### Migrating custom schema
Schema is stored in LDAP so we *should* be able to use our ldap library
to discover differences. We probably want to do only ADD and bail if we
determine something will be a MOD or DEL.
#### Excluding specific entries
The ignore user/group options of migrate-ds were introduced so that non-compliant
entries could be skipped to not block the migration. We can ignore these for now.
#### Performance considerations
Some benefits would be likely if common entry types were added in
batches rather than individually. This would not easily allow for a
"stop on failure" approach but could be considerably faster.
The basic idea is that added entries of the same type (user, group, etc)
would be accumulated and added together. The result would be iterated
through and logged.
The memberOf plugin should be disabled. A fixup task can be run post-migration
to calculate the memberships.
#### Idempotency
The migrate-ds plugin manages idempotency because it skips over entries
that already have been migrated (or exist). This new migration will handle
it by merging the remote and local entries. This may not be desirable in
all cases.
#### Migration steps
A simplistic view of the steps
Set migration mode=True
Disable compat
@@ -314,167 +358,44 @@ Enable compat
Restart world
Run ipa-server-upgrade
#### Supported Migration Scenarios
### pure LDAP migration
There are quite a few ways that migration can be done, both for testing and production uses. Any scenario not specifically mentioned here should be considered unsupported.
The current code generally works minus a few bugs and RFEs, some of which are resolved
by doing an IPA-to-IPA migration instead. It should be maintained for now and migrated
to the standalone client in the future.
These scenarios are not enforced by code. At best we can prompt the user
for confirmation if we believe that they are non-conformant but I choose
the trade-off of allowing for unsupported migrations to the flexibility
of not trying to force square pegs into round holes.
These bugs should be considered for the existing plugin.
There are a few points to consider.
**Replicas**
All references to replicas in the existing deployment will not be migrated. There is no mechanism to one-by-one replace each server with a new one using migration. One will be migrated and new replicas will need to be manually added directly to that using ipa-replica-install.
**Kerberos**
The Kerberos master key will not be migrated. Kerberos principals are retained but the keys are not.
**Certificates**
The existing CA will be abandoned in favor of a CA on the new installation.
If the realm, domain and CA subject base (default is O=REALM) are identical between the two installations then there is no way, other than the CA private key, to distinguish between the original CA and the new CA. Therefore no certificates will be maintained in the migration. All certificates other than those already present in the new IPA server as part of installation will need to be re-issued.
If one of these doesn't match then the certificates will be retained but the backing PKI will be lost so there will be no possibility of renewals or revocation (no OCSP or CRL).
##### Scenario 1 - Production to new production
Preconditions:
* There is a existing production IPA server (or servers)
* There is a new IPA server installation with the same realm and domain
Optional:
* If desired the realm and domain may be changed. The migrated data will accommodate these changes but this will require reconfiguration of all clients, etc. beyond just re-enrollment.
Result:
* All valid IPA entries will be migrated
* All ids (uid, gid, SID, etc) will be maintained
* All certificates issued from the previous CA will be dropped unless the CA subject base DN, or the realm, is changed in the new deployment.
* All clients must re-enroll to the new deployment
* Users will have to migrate their passwords to generate Kerberos and other keys
##### Scenario 2 - Production to new staging
Preconditions:
* There is an existing production IPA server (or servers)
* There is a new IPA server installation with a different realm and domain (e.g. staging.example.test)
Result:
* All valid IPA entries will be migrated
* All ids (uid, gid, SID, etc) will be re-generated
* All certificates from the previous CA will be preserved
* Given this is a new staging deployment there will be no enrolled clients. The host entries from the production deployment will exist but all keys are dropped.
* Users will have to migrate their passwords to generate Kerberos and other keys
##### Scenario 3 - Staging to new production
Preconditions:
* There is an existing production IPA server (or servers)
* There is a new IPA server installation with a different realm and domain (e.g. staging.example.test)
Result:
* All valid IPA entries will be migrated
* All ids (uid, gid, SID, etc) will be re-generated
* All certificates from the previous CA will be removed
* Users will have to migrate their passwords to generate Kerberos and other keys
##### Scenario 4 - From IPA backup
The migration tool will have the capability to do offline migration using an LDIF file. An IPA backup is a tar ball that contains the IPA data in EXAMPLE-TEST-userRoot.ldif
Preconditions:
* A backup from an existing IPA installation exists
* There is a new IPA server installation with the same realm and domain
Result:
* All valid IPA entries will be migrated
* All ids (uid, gid, SID, etc) will be maintained
* All certificates issued from the previous CA will be dropped unless the CA subject base DN, or the realm, is changed in the new deployment.
* All clients must re-enroll to the new deployment
* Users will have to migrate their passwords to generate Kerberos and other keys
* https://pagure.io/freeipa/issue/3096 - error when migrating unknown schema
* https://pagure.io/freeipa/issue/3100 - Check for userPassword in migration
* https://pagure.io/freeipa/issue/4738 - [RFE] ipa migrate-ds should provide option for creating UPG from posixGroup objectClass
* https://pagure.io/freeipa/issue/5020 - migrate-ds: does not show migrated users if an error happened during group migration
* https://pagure.io/freeipa/issue/5693 - Passwords become "expired" when migrating from directory server to IPA
* https://pagure.io/freeipa/issue/6105 - migrate-ds is not completely ignoring attributes.
* https://pagure.io/freeipa/issue/6360 - ipa migrate-ds does not rename uniquemember/member attributes properly
* https://pagure.io/freeipa/issue/6380 - ipa migrate-ds should print warning for referrals
* https://pagure.io/freeipa/issue/7368 - ipa migrate-ds converts groupofuniquenames objects to groupofnames, but leaves groupofuniquenames objectclass present
* https://pagure.io/freeipa/issue/7749 - `ipa migrate-ds` fails to migrate user and group data from directory server to IDM.
## Logging
By default the log file will be /var/log/ipa-migrate.log and will be appended to
and not overwritten. This is so it can reflect multiple runs if they are required.
### Standard logging
At least the DN of all entries written should be logged (pkey may be sufficient).
Here is an example of the standard logging
Logging by object type could be handy and should natural since this is how the
objects will be sorted.
```
024-02-27T17:10:03Z DEBUG ================================================================================
2024-02-27T17:10:03Z INFO IPA to IPA migration starting ...
2024-02-27T17:10:03Z DEBUG Migration options:
2024-02-27T17:10:03Z DEBUG --mode=prod-mode
2024-02-27T17:10:03Z DEBUG --hostname=hpe-dl385gen8-01.hpe2.lab.eng.bos.redhat.com
2024-02-27T17:10:03Z DEBUG --verbose=False
2024-02-27T17:10:03Z DEBUG --bind-dn=cn=directory manager
2024-02-27T17:10:03Z DEBUG --bind-pw-file=None
2024-02-27T17:10:03Z DEBUG --cacertfile=None
2024-02-27T17:10:03Z DEBUG --subtree=[]
2024-02-27T17:10:03Z DEBUG --log-file=/var/log/ipa-migrate.log
2024-02-27T17:10:03Z DEBUG --skip-schema=False
2024-02-27T17:10:03Z DEBUG --skip-config=False
2024-02-27T17:10:03Z DEBUG --migrate-dns=False
2024-02-27T17:10:03Z DEBUG --dryrun=True
2024-02-27T17:10:03Z DEBUG --dryrun-record=None
2024-02-27T17:10:03Z DEBUG --force=False
2024-02-27T17:10:03Z DEBUG --version=False
2024-02-27T17:10:03Z DEBUG --quiet=False
2024-02-27T17:10:03Z DEBUG --schema-overwrite=False
2024-02-27T17:10:03Z DEBUG --reset-range=False
2024-02-27T17:10:03Z DEBUG --db-ldif=None
2024-02-27T17:10:03Z DEBUG --schema-ldif=None
2024-02-27T17:10:03Z DEBUG --config-ldif=None
2024-02-27T17:10:03Z DEBUG --no-prompt=False
2024-02-27T17:10:03Z DEBUG flushing ldapi://%2Frun%2Fslapd-HPE2-LAB-ENG-BOS-REDHAT-COM.socket from SchemaCache
2024-02-27T17:10:03Z DEBUG retrieving schema for SchemaCache url=ldapi://%2Frun%2Fslapd-HPE2-LAB-ENG-BOS-REDHAT-COM.socket conn=<ldap.ldapobject.SimpleLDAPObject object at 0x7f5a1eb68210>
2024-02-27T17:10:03Z DEBUG retrieving schema for SchemaCache url=ldap://hpe-dl385gen8-01.hpe2.lab.eng.bos.redhat.com conn=<ldap.ldapobject.SimpleLDAPObject object at 0x7f5a1e7eba10>
2024-02-27T17:10:04Z DEBUG Found realm from remote server: HPE2.LAB.ENG.BOS.REDHAT.COM
2024-02-27T17:10:04Z INFO Migrating schema ...
2024-02-27T17:10:04Z DEBUG Getting schema from the remote server ...
2024-02-27T17:10:04Z DEBUG Retrieved 1556 attributes and 349 objectClasses
2024-02-27T17:10:07Z DEBUG Migrated 0 attributes and 0 objectClasses
2024-02-27T17:10:07Z DEBUG Skipped 1556 attributes and 349 objectClasses
2024-02-27T17:10:07Z INFO Migrating configuration ...
2024-02-27T17:10:07Z DEBUG Getting config from the remote server ...
2024-02-27T17:10:08Z DEBUG flushing ldapi://%2Frun%2Fslapd-HPE2-LAB-ENG-BOS-REDHAT-COM.socket from SchemaCache
2024-02-27T17:10:08Z DEBUG retrieving schema for SchemaCache url=ldapi://%2Frun%2Fslapd-HPE2-LAB-ENG-BOS-REDHAT-COM.socket conn=<ldap.ldapobject.SimpleLDAPObject object at 0x7f5a1eb68210>
2024-02-27T17:10:09Z INFO Migrating database ... (this make take a while)
2024-02-27T17:10:11Z DEBUG Removed IPA issued userCertificate from: krbprincipalname=ldap/hpe-dl385gen8-01.hpe2.lab.eng.bos.redhat.com@HPE2.LAB.ENG.BOS.REDHAT.COM,cn=services,cn=accounts,dc=hpe2,dc=lab,dc=eng,dc=bos,dc=redhat,dc=com
2024-02-27T17:10:11Z DEBUG Skipping remote certificate entry: 'cn=HPE2.LAB.ENG.BOS.REDHAT.COM IPA CA,cn=certificates,cn=ipa,cn=etc,dc=hpe2,dc=lab,dc=eng,dc=bos,dc=redhat,dc=com' Issuer: CN=Certificate Authority,O=HPE2.LAB.ENG.BOS.REDHAT.COM
2024-02-27T17:10:11Z DEBUG Removed IPA issued userCertificate from: krbprincipalname=HTTP/hpe-dl385gen8-01.hpe2.lab.eng.bos.redhat.com@HPE2.LAB.ENG.BOS.REDHAT.COM,cn=services,cn=accounts,dc=hpe2,dc=lab,dc=eng,dc=bos,dc=redhat,dc=com
2024-02-27T17:10:16Z INFO Running ipa-server-upgrade ... (this make take a while)
2024-02-27T17:10:16Z INFO Skipping ipa-server-upgrade in dryrun mode.
2024-02-27T17:10:16Z INFO Running SIDGEN task ...
2024-02-27T17:10:16Z INFO Skipping SIDGEN task in dryrun mode.
2024-02-27T17:10:16Z INFO Migration complete!
```
DEBUG logging may want to show gory details, particularly when merging entries.
### Verbose logging
## Implementation
If get the verbose logging you simply just use the **--verbose, -v** CLI option. Here you will see the exact operations there were performed. Here is an example showing the additional information that is logged.
```
...
...
2024-02-28T15:30:53Z INFO Migrating database ... (this make take a while)
2024-02-28T15:30:53Z INFO Entry is different and will be updated: 'uid=admin,cn=users,cn=accounts,dc=hpe2,dc=lab,dc=eng,dc=bos,dc=redhat,dc=com' attribute 'ipaNTSecurityIdentifier' replaced with val 'S-1-5-21-404865364-1326736403-3398440945-501' old value: ['S-1-5-21-404865364-1326736403-3398440945-500']
2024-02-28T15:30:53Z INFO Add db entry 'uid=mark,cn=users,cn=accounts,dc=hpe2,dc=lab,dc=eng,dc=bos,dc=redhat,dc=com - users'
2024-02-28T15:30:53Z INFO Entry is different and will be updated: 'cn=HPE2.LAB.ENG.BOS.REDHAT.COM_id_range,cn=ranges,cn=etc,dc=hpe2,dc=lab,dc=eng,dc=bos,dc=redhat,dc=com' attribute 'ipaBaseID' replaced with val '9000999' old value: ['90000000']
2024-02-28T15:30:53Z INFO Entry is different and will be updated: 'cn=HPE2.LAB.ENG.BOS.REDHAT.COM_subid_range,cn=ranges,cn=etc,dc=hpe2,dc=lab,dc=eng,dc=bos,dc=redhat,dc=com' attribute 'ipaIDRangeSize' replaced with val '2147352575' old value: ['2147352576']
...
...
```
The command will be named ipa-migrate. It must determine whether the remote server is
actually an IPA server or not. ipaclient/discovery.py::ipacheckldap may be re-usable.
The standalone client should use a unique context, migration. This will
allow for a separate configuration file.
## Feature Management
@@ -484,55 +405,51 @@ No UI option will be provided. This is command-line client only.
### CLI
Overview of the CLI usage
Overview of the CLI commands.
ipa-migrate <prod-mode|stage-mode> <HOSTNAME> [options]
#### IPA to IPA
Advance knowledge of the DIT substantially reduces the number of options
necessary for migration.
| Option | Description |
| --- | --- |
| --bind-dn, -D | The bind DN to use for authentication to the remote IPA server (default is "cn=directory manager") |
| --bind-pw, -w | The password for the bind DN |
| --bind-pw-file, -j | A file that contains the password |
| --cacertfile, -Z | The CA cert file |
| --skip-schema, -S | Do not migrate the schema |
| --skip-config, -C | Do not migrate the DS configuration |
| --schema-overwrite, -O | Completely overwrite schema |
| --reset-range, -r | Reset all the DNA attributes (uidNumber, etc) to the magic regen value (-1) |
| --db-ldif, -f | An LDIF file containing the export of the userRoot database |
| --schema-ldif, -m | An LDIF file containing the schema from the remote server |
| --config-ldif, -g | The DS config file dse.ldif |
| --migrate-dns, -B | Migrate the DNS records in the database |
| --subtree, -s | Non standard IPA subtree to include in the migration |
| --dryrun, -x | try the migration without writing data |
| --dryrun-record, -o | Perform dryrun but record all the LDAP changes to a LDIF file |
| --force. -F | ignore errors and keep going |
| --version, -V | version of the tool |
| --quiet, -q | output only errors |
| --no-prompt, -n | Do not do a confirmation prompt about starting the migration |
| --log-file, -l | log to the given file |
| --verbose, -v | Display verbose output |
| --help, -h | this message |
| --dry-run | try the migration without writing data |
| --force | ignore errors and keep going |
| --version | version of the tool |
| --quiet | output only errors |
| --log-file | log to the given file |
| --help | this message |
If the DM password is not provided then you will be prompted for it.
The DM password will be prompted for interactively.
#### Examples
| Argument | Description |
| url | ldap url for remote IPA server |
# ipa-migrate prod-mode remote.server.com
# ipa-migrate prod-mode remote.server.com --dryrun
# ipa-migrate prod-mode remote.server.com -D "cn=directory manager" -j ./passwd.txt
# ipa-migrate prod-mode remote.server.com --db-ldif=/tmp/remote-userroot.ldif
# ipa-migrate prod-mode remote.server.com --skip-config --skip-schema
# ipa-migrate stage-mode remote.server.com --dryrun-record=/tmp/dryrun-ops.ldif
# ipa-migrate stage-mode remote.server.com --config-ldif=/tmp/dse.ldif --schema-ldif=/tmp/schema.ldif --db-ldif=/tmp/remote-userroot.ldif
#### pure LDAP
# ipa-migrate stage-mode remote.server.com --subtree="ou=my own data,dc=ipa,dc=com"
Will remain unchanged unless one of the bug fixes requires it (perhaps for the UPG
ticket).
### Configuration
N/A
## Upgrade
N/A
## Test plan
There are currently no tests for migration.
Some simplisitic approaches for starting testing might include:
* Count the number of entries that will be migrated and ensure they were migrated, by type (hosts, groups, etc).
* Verify that the services enabled on the remote side are enabled after migration (NIS, ACME, etc).
* Double-check, perhaps spot-checking, memberOf
* Migrate a password to ensure it was imported properly
We have a data generation script in freeipa-tools that may be leveraged to generate the data but it currently generates a LOT of entries which is likely too much for automation.
## Troubleshooting and debugging
-18
View File
@@ -173,7 +173,6 @@ any user. However, to make it usable for S4U2Proxy (constrained delegation),
the service ticket must be forwardable. In such case the Kerberos service would
be able to impersonate user and requires an explicit administrative permission.
IPA API provides a way to record this permission in both host and service
command families. The following commands have option
`--ok-to-auth-as-delegate=BOOL`:
@@ -184,23 +183,6 @@ command families. The following commands have option
This flag is equivalent to MS-SFU's `TrustedToAuthenticationForDelegation`
boolean setting.
The behavior of FreeIPA regarding S4U2Self-granted tickets differs depending of
the krb5 version that was used to compile:
* **krb5 1.20+**: KDC will always respond to S4U2Self TGS-REQ with forwardable
tickets, except if the requester principal is set as impersonator service in
at least one general constrained delegation rule (even if the rule has no
target set)
* **krb5 1.19-**: KDC will respond to all S4U2Self TGS-REQs with non-forwardable
tickets
In both cases, granting the `ok-to-auth-as-delegate` permission to a principal
will override this default behavior and allow it to obtain forwardable tickets
to itself. In practice, it means the `ok-to-auth-as-delegate` permission is
required if you want to grant a service the special privilege to impersonate
any user against services configured as targets in a general constrained
delegation rule.
### General constrained delegation design
General constrained delegation uses two objects: a rule and a target.
-1
View File
@@ -11,7 +11,6 @@ m2r2
## ipa dependencies
dnspython
jwcrypto
ifaddr
netaddr
qrcode
six
-5
View File
@@ -391,11 +391,6 @@ for Keycloak or Red Hat SSO IdPs. The template expects both Keycloak's realm
typically deployed as a part of a larger solution. These options may not be
needed for other pre-defined templates like Google or Github.
The `openid` scope is mandatory since
[Keycloak 19.0.2](https://www.keycloak.org/docs/latest/upgrading/index.html#userinfo-endpoint-changes).
Without the `openid` scope, Keycloak refuses userinfo requests with HTTP
response 403: `invalid_scope` `Missing openid scope`.
Associate IdP reference with IPA user
-------------------------------------
+11 -134
View File
@@ -78,8 +78,8 @@
%global ds_version 1.4.3.16-12
%global selinux_policy_version 3.14.3-107
%else
# version supporting LMDB and lib389.cli_ctl.dblib.run_dbscan utility
%global ds_version 2.1.0
# DNA interval enabled
%global ds_version 2.0.5-1
%global selinux_policy_version 38.1.1-1
%endif
@@ -124,11 +124,10 @@
# Make sure to use 389-ds-base versions that fix https://github.com/389ds/389-ds-base/issues/4700
# and has DNA interval enabled
# version supporting LMDB and lib389.cli_ctl.dblib.run_dbscan utility
%if 0%{?fedora} < 34
%global ds_version 1.4.4.16-1
%else
%global ds_version 2.1.0
%global ds_version 2.0.7-1
%endif
# Fix for TLS 1.3 PHA, RHBZ#1775146
@@ -174,7 +173,7 @@
%endif
# RHEL 8.3+, F32+ has 0.79.13
%global certmonger_version 0.79.17-1
%global certmonger_version 0.79.7-3
# RHEL 8.2+, F32+ has 3.58
%global nss_version 3.44.0-4
@@ -290,7 +289,6 @@ BuildRequires: gettext
BuildRequires: gettext-devel
BuildRequires: python3-devel
BuildRequires: python3-setuptools
BuildRequires: python3-argcomplete
BuildRequires: systemd >= %{systemd_version}
# systemd-tmpfiles which is executed from make install requires apache user
BuildRequires: httpd
@@ -308,12 +306,9 @@ BuildRequires: libpwquality-devel
BuildRequires: libsss_idmap-devel
BuildRequires: libsss_certmap-devel
BuildRequires: libsss_nss_idmap-devel >= %{sssd_version}
%if 0%{?fedora} >= 41
# Do not use nodejs22 on fedora < 41, https://pagure.io/freeipa/issue/9643
BuildRequires: nodejs(abi)
%elif 0%{?fedora} >= 39 || 0%{?rhel} >= 10
%if 0%{?fedora} >= 39 || 0%{?rhel} >= 10
# Do not use nodejs20 on fedora < 39, https://pagure.io/freeipa/issue/9374
BuildRequires: nodejs(abi) < 127
BuildRequires: nodejs(abi)
%else
BuildRequires: nodejs(abi) < 111
%endif
@@ -406,7 +401,7 @@ BuildRequires: python3-libipa_hbac
BuildRequires: python3-libsss_nss_idmap
BuildRequires: python3-lxml
BuildRequires: python3-netaddr >= %{python_netaddr_version}
BuildRequires: python3-ifaddr
BuildRequires: python3-netifaces
BuildRequires: python3-pki >= %{pki_version}
BuildRequires: python3-polib
BuildRequires: python3-pyasn1
@@ -719,7 +714,7 @@ Requires: oddjob-mkhomedir
Requires: libsss_autofs
Requires: autofs
Requires: libnfsidmap
Requires: (nfs-utils or nfsv4-client-utils)
Requires: nfs-utils
Requires: sssd-tools >= %{sssd_version}
Requires(post): policycoreutils
@@ -878,7 +873,6 @@ Requires: %{name}-common = %{version}-%{release}
Requires(pre): python3-ldap >= %{python_ldap_version}
Requires: gnupg2
Requires: keyutils
Requires: python3-argcomplete
Requires: python3-cffi
Requires: python3-cryptography >= 1.6
Requires: python3-dateutil
@@ -888,7 +882,7 @@ Requires: python3-gssapi >= 1.2.0
Requires: python3-jwcrypto >= 0.4.2
Requires: python3-libipa_hbac
Requires: python3-netaddr >= %{python_netaddr_version}
Requires: python3-ifaddr
Requires: python3-netifaces >= 0.10.4
Requires: python3-pyasn1 >= 0.3.2-2
Requires: python3-pyasn1-modules >= 0.3.2-2
Requires: python3-pyusb
@@ -908,7 +902,6 @@ Requires: python3-urllib3 >= 1.24.2-3
# For urllib3.util.ssl_match_hostname
Requires: python3-urllib3 >= 1.25.8
%endif
Requires: python3-systemd
%description -n python3-ipalib
IPA is an integrated solution to provide centrally managed Identity (users,
@@ -1000,26 +993,6 @@ Requires(post): selinux-policy-%{selinuxtype}
%description selinux
Custom SELinux policy module for FreeIPA
%package selinux-nfast
Summary: FreeIPA SELinux policy for nCipher nfast HSMs
BuildArch: noarch
Requires: selinux-policy-%{selinuxtype}
Requires(post): selinux-policy-%{selinuxtype}
%{?selinux_requires}
%description selinux-nfast
Custom SELinux policy module for nCipher nfast HSMs
%package selinux-luna
Summary: FreeIPA SELinux policy for Thales Luna HSMs
BuildArch: noarch
Requires: selinux-policy-%{selinuxtype}
Requires(post): selinux-policy-%{selinuxtype}
%{?selinux_requires}
%description selinux-luna
Custom SELinux policy module for Thales Luna HSMs
# with selinux
%endif
@@ -1106,15 +1079,6 @@ rm -f %{buildroot}%{_usr}/share/ipa/ui/images/product-name.png
%endif
# RHEL spec file only: END
%if 0%{?fedora} >= 38
# Register CLI tools for bash completion (fedora only)
for clitool in ipa-migrate
do
register-python-argcomplete "${clitool}" > "${clitool}"
install -p -m 0644 -D -t '%{buildroot}%{bash_completions_dir}' "${clitool}"
done
%endif
%find_lang %{gettext_domain}
%if ! %{ONLY_CLIENT}
@@ -1178,10 +1142,6 @@ fi
/bin/systemctl reload-or-try-restart oddjobd
%tmpfiles_create ipa.conf
%journal_catalog_update
%postun server
%journal_catalog_update
%posttrans server
# don't execute upgrade and restart of IPA when server is not installed
@@ -1318,23 +1278,13 @@ if [ $1 -gt 1 ] ; then
cp /etc/ipa/ca.crt /var/lib/ipa-client/pki/kdc-ca-bundle.pem
cp /etc/ipa/ca.crt /var/lib/ipa-client/pki/ca-bundle.pem
fi
%{__python3} -c 'from ipaclient.install.client import configure_krb5_snippet; configure_krb5_snippet()' >>/var/log/ipaupgrade.log 2>&1
%{__python3} -c 'from ipaclient.install.client import update_ipa_nssdb; update_ipa_nssdb()' >>/var/log/ipaupgrade.log 2>&1
chmod 0600 /var/log/ipaupgrade.log
SSH_CLIENT_SYSTEM_CONF="/etc/ssh/ssh_config"
if [ -f "$SSH_CLIENT_SYSTEM_CONF" ]; then
if grep -E -q '^HostKeyAlgorithms ssh-rsa,ssh-dss' $SSH_CLIENT_SYSTEM_CONF 2>/dev/null; then
sed -E --in-place=.orig 's/^(HostKeyAlgorithms ssh-rsa,ssh-dss)$/# disabled by ipa-client update\n# \1/' "$SSH_CLIENT_SYSTEM_CONF"
fi
# https://pagure.io/freeipa/issue/9536
# replace sss_ssh_knownhostsproxy with sss_ssh_knownhosts
if [ -f '/usr/bin/sss_ssh_knownhosts' ]; then
if grep -E -q 'Include' $SSH_CLIENT_SYSTEM_CONF 2>/dev/null ; then
SSH_CLIENT_SYSTEM_CONF="/etc/ssh/ssh_config.d/04-ipa.conf"
fi
sed -E --in-place=.orig 's/^(GlobalKnownHostsFile \/var\/lib\/sss\/pubconf\/known_hosts)$/# disabled by ipa-client update\n# \1/' $SSH_CLIENT_SYSTEM_CONF
sed -E --in-place=.orig 's/(ProxyCommand \/usr\/bin\/sss_ssh_knownhostsproxy -p \%p \%h)/# replaced by ipa-client update\n KnownHostsCommand \/usr\/bin\/sss_ssh_knownhosts \%H/' $SSH_CLIENT_SYSTEM_CONF
fi
sed -E --in-place=.orig 's/^(HostKeyAlgorithms ssh-rsa,ssh-dss)$/# disabled by ipa-client update\n# \1/' "$SSH_CLIENT_SYSTEM_CONF"
fi
fi
fi
@@ -1350,76 +1300,17 @@ fi
semodule -d ipa_custodia &> /dev/null || true;
%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2
%post selinux-nfast
%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}-nfast.pp.bz2
%post selinux-luna
%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}-luna.pp.bz2
%postun selinux
if [ $1 -eq 0 ]; then
%selinux_modules_uninstall -s %{selinuxtype} %{modulename}
semodule -e ipa_custodia &> /dev/null || true;
fi
%postun selinux-nfast
if [ $1 -eq 0 ]; then
%selinux_modules_uninstall -s %{selinuxtype} %{modulename}-nfast
fi
%postun selinux-luna
if [ $1 -eq 0 ]; then
%selinux_modules_uninstall -s %{selinuxtype} %{modulename}-luna
fi
%posttrans selinux
%selinux_relabel_post -s %{selinuxtype}
# with_selinux
%endif
%triggerin client -- sssd-common < 2.10
# Has the client been configured?
restore=0
test -f '/var/lib/ipa-client/sysrestore/sysrestore.index' && restore=$(wc -l '/var/lib/ipa-client/sysrestore/sysrestore.index' | awk '{print $1}')
if [ -f '/etc/ssh/sshd_config' -a $restore -ge 2 ]; then
SSH_CLIENT_SYSTEM_CONF="/etc/ssh/ssh_config"
if [ -f "$SSH_CLIENT_SYSTEM_CONF" ]; then
# https://pagure.io/freeipa/issue/9536
# downgrade sss_ssh_knownhosts with sss_ssh_knownhostsproxy
if [ -f '/usr/bin/sss_ssh_knownhosts' ]; then
if grep -E -q 'Include' $SSH_CLIENT_SYSTEM_CONF 2>/dev/null ; then
SSH_CLIENT_SYSTEM_CONF="/etc/ssh/ssh_config.d/04-ipa.conf"
fi
GLOBALKNOWNHOSTFILE="GlobalKnownHostsFile /var/lib/sss/pubconf/known_hosts/"
grep -qF '$GLOBALKNOWNHOSTFILE' $SSH_CLIENT_SYSTEM_CONF
if [ $? -ne 0 ]; then
sed -E --in-place=.orig '/(# IPA-related configuration changes to ssh_config)/a # added by ipa-client update\n'"$GLOBALKNOWNHOSTFILE"'' $SSH_CLIENT_SYSTEM_CONF
fi
sed -E --in-place=.orig 's/(KnownHostsCommand \/usr\/bin\/sss_ssh_knownhosts \%H)/ProxyCommand \/usr\/bin\/sss_ssh_knownhostsproxy -p \%p \%h/' $SSH_CLIENT_SYSTEM_CONF
fi
fi
fi
%triggerin client -- sssd-common >= 2.10
# Has the client been configured?
restore=0
test -f '/var/lib/ipa-client/sysrestore/sysrestore.index' && restore=$(wc -l '/var/lib/ipa-client/sysrestore/sysrestore.index' | awk '{print $1}')
if [ -f '/etc/ssh/sshd_config' -a $restore -ge 2 ]; then
SSH_CLIENT_SYSTEM_CONF="/etc/ssh/ssh_config"
if [ -f "$SSH_CLIENT_SYSTEM_CONF" ]; then
# https://pagure.io/freeipa/issue/9536
# upgrade sss_ssh_knownhostsproxy with sss_ssh_knownhosts
if [ -f '/usr/bin/sss_ssh_knownhosts' ]; then
if grep -E -q 'Include' $SSH_CLIENT_SYSTEM_CONF 2>/dev/null ; then
SSH_CLIENT_SYSTEM_CONF="/etc/ssh/ssh_config.d/04-ipa.conf"
fi
sed -E --in-place=.orig 's/^(GlobalKnownHostsFile \/var\/lib\/sss\/pubconf\/known_hosts)$/# disabled by ipa-client update\n# \1/' $SSH_CLIENT_SYSTEM_CONF
sed -E --in-place=.orig 's/(ProxyCommand \/usr\/bin\/sss_ssh_knownhostsproxy -p \%p \%h)/# replaced by ipa-client update\n KnownHostsCommand \/usr\/bin\/sss_ssh_knownhosts \%H/' $SSH_CLIENT_SYSTEM_CONF
fi
fi
fi
%triggerin client -- openssh-server < 8.2
# Has the client been configured?
@@ -1518,10 +1409,6 @@ fi
%{_sbindir}/ipa-crlgen-manage
%{_sbindir}/ipa-cert-fix
%{_sbindir}/ipa-acme-manage
%{_sbindir}/ipa-migrate
%if 0%{?fedora} >= 38
%{bash_completions_dir}/ipa-migrate
%endif
%{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit
%{_libexecdir}/certmonger/ipa-server-guard
%dir %{_libexecdir}/ipa
@@ -1554,7 +1441,6 @@ fi
%attr(644,root,root) %{_unitdir}/ipa-otpd@.service
%attr(644,root,root) %{_unitdir}/ipa-ccache-sweep.service
%attr(644,root,root) %{_unitdir}/ipa-ccache-sweep.timer
%attr(644,root,root) %{_journalcatalogdir}/ipa.catalog
# END
%attr(755,root,root) %{plugin_dir}/libipa_pwd_extop.so
%attr(755,root,root) %{plugin_dir}/libipa_enrollment_extop.so
@@ -1597,7 +1483,6 @@ fi
%{_mandir}/man1/ipa-crlgen-manage.1*
%{_mandir}/man1/ipa-cert-fix.1*
%{_mandir}/man1/ipa-acme-manage.1*
%{_mandir}/man1/ipa-migrate.1*
%files -n python3-ipaserver
@@ -1873,14 +1758,6 @@ fi
%files selinux
%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.*
%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename}
%files selinux-nfast
%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}-nfast.pp.*
%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename}-nfast
%files selinux-luna
%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}-luna.pp.*
%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename}-luna
# with selinux
%endif
-4
View File
@@ -18,10 +18,6 @@ systemdsystemunit_DATA = \
ipa-ccache-sweep.timer \
$(NULL)
dist_systemdcatalog_DATA = \
ipa.catalog \
$(NULL)
CLEANFILES = $(systemdsystemunit_DATA)
%: %.in Makefile
-58
View File
@@ -1,58 +0,0 @@
#
#
#
-- 6d70f1b493df36478bc3499257cd3b17
Subject: IPA API command was executed and result of its execution was audited
Defined-by: FreeIPA
Support: https://lists.fedorahosted.org/archives/list/freeipa-users@lists.fedorahosted.org/
Documentation: man:ipa(1)
Documentation: https://freeipa.readthedocs.io/en/latest/api/index.html
Documentation: https://freeipa.readthedocs.io/en/latest/api/@IPA_API_COMMAND@.html
FreeIPA provides an extensive API that allows to manage all aspects of IPA deployments.
The following information about the API command executed is available:
@MESSAGE@
The command was executed by '@SYSLOG_IDENTIFIER@' utility. If the utility name
is '/mod_wsgi`, then this API command came from a remote source through the IPA
API end-point.
The message includes following fields:
- executable name and PID ('/mod_wsgi' for HTTP end-point; in this case it
was '@SYSLOG_IDENTIFIER@' command)
- '[IPA.API]' marker to allow searches with 'journalctl -g IPA.API'
- authenticated Kerberos principal or '[autobind]' marker for LDAPI-based
access as root. In this case it was '@IPA_API_ACTOR@'
- name of the command executed, in this case '@IPA_API_COMMAND@'
- result of execution: `SUCCESS` or an exception name. In this case it was
'@IPA_API_RESULT@'
- LDAP backend instance identifier. The identifier will be the same for all
operations performed under the same request. This allows to identify operations
which were executed as a part of the same API request instance. For API
operations that didn't result in LDAP access, there will be
'[no_connection_id]' marker.
- finally, a list of arguments and options passed to the command is provided
in JSON format.
---------
The following list of arguments and options were passed to the command
'@IPA_API_COMMAND@' by the '@IPA_API_ACTOR@' actor:
@IPA_API_PARAMS@
---------
A detailed information about FreeIPA API can be found at upstream documentation API reference:
https://freeipa.readthedocs.io/en/latest/api/index.html
For details on the IPA API command '@IPA_API_COMMAND@' see
https://freeipa.readthedocs.io/en/latest/api/@IPA_API_COMMAND@.html
@@ -42,7 +42,7 @@ import six
from ipalib.install.kinit import kinit_keytab
from ipapython import ipautil
from ipapython.dn import DN
from ipalib import api, errors, x509, sysrestore
from ipalib import api, errors, x509
from ipaplatform.paths import paths
from ipaserver.plugins.ldap2 import ldap2
from ipaserver.install import ca, cainstance, dsinstance, certs
@@ -383,20 +383,7 @@ def retrieve_cert_continuous(reuse_existing, **kwargs):
return result
new_cert = x509.load_pem_x509_certificate(result[1].encode('ascii'))
nickname = get_nickname()
if new_cert == old_cert:
sstore = sysrestore.StateFile(paths.SYSRESTORE)
if (
sstore.get_state('pki_hsm', 'enabled')
and sstore.get_state('pki_hsm', 'token_name')
and nickname != 'ipaCert'
):
# HSMs must be networked so the cert is already present
# exception of the RA Agent certificate.
return (
ISSUED,
new_cert.public_bytes(x509.Encoding.PEM).decode("ascii"),
)
syslog.syslog(syslog.LOG_INFO, "Updated certificate not available")
# No cert available yet, tell certmonger to wait another 8 hours
return (WAIT_WITH_DELAY, 8 * 60 * 60, '')
+22 -11
View File
@@ -28,6 +28,7 @@ import shutil
import traceback
from ipalib.install import certstore
from ipapython import directivesetter
from ipapython import ipautil
from ipalib import api, errors
from ipalib import x509
@@ -36,7 +37,7 @@ from ipaserver.install import certs, cainstance
from ipaserver.plugins.ldap2 import ldap2
from ipaplatform import services
from ipaplatform.paths import paths
from ipapython.certdb import TrustFlags, get_ca_nickname
from ipapython.certdb import TrustFlags
def _main():
@@ -49,8 +50,6 @@ def _main():
dogtag_service = services.knownservices['pki_tomcatd']
ca = cainstance.CAInstance(host_name=api.env.host)
# dogtag opens its NSS database in read/write mode so we need it
# shut down so certmonger can open it read/write mode. This avoids
# database corruption. It should already be stopped by the pre-command
@@ -84,15 +83,13 @@ def _main():
api.Backend.ldap2.connect()
ca = cainstance.CAInstance(host_name=api.env.host)
ca.update_cert_config(nickname, cert)
if ca.is_renewal_master():
cainstance.update_people_entry(cert)
cainstance.update_authority_entry(cert)
if nickname in (
'auditSigningCert cert-pki-ca',
'auditSigningCert cert-pki-kra',
):
if nickname == 'auditSigningCert cert-pki-ca':
# Fix trust on the audit cert
try:
db.run_certutil(['-M',
@@ -108,9 +105,26 @@ def _main():
"Updating trust on certificate %s failed in %s" %
(nickname, db.secdir))
elif nickname == 'caSigningCert cert-pki-ca':
# Update CS.cfg
cfg_path = paths.CA_CS_CFG_PATH
config = directivesetter.get_directive(
cfg_path, 'subsystem.select', '=')
if config == 'New':
syslog.syslog(syslog.LOG_NOTICE, "Updating CS.cfg")
if cert.is_self_signed():
directivesetter.set_directive(
cfg_path, 'hierarchy.select', 'Root',
quotes=False, separator='=')
else:
directivesetter.set_directive(
cfg_path, 'hierarchy.select', 'Subordinate',
quotes=False, separator='=')
else:
syslog.syslog(syslog.LOG_NOTICE, "Not updating CS.cfg")
# Remove old external CA certificates
for ca_nick, ca_flags in db.list_certs():
if ca_flags.has_key or not ca_flags.ca:
if ca_flags.has_key:
continue
# Delete *all* certificates that use the nickname
while True:
@@ -154,11 +168,8 @@ def _main():
"%s" % e)
ca_certs = []
realm_nickname = get_ca_nickname(api.env.realm)
for ca_cert, ca_nick, ca_flags in ca_certs:
try:
if ca_nick == realm_nickname:
ca_nick = 'caSigningCert cert-pki-ca'
db.add_cert(ca_cert, ca_nick, ca_flags)
except ipautil.CalledProcessError as e:
syslog.syslog(
+1 -2
View File
@@ -8,7 +8,6 @@ attributeTypes: (2.16.840.1.113730.3.8.21.1.6 NAME 'ipaCaId' DESC 'Dogtag Author
attributeTypes: (2.16.840.1.113730.3.8.21.1.7 NAME 'ipaCaIssuerDN' DESC 'Issuer DN' SUP distinguishedName X-ORIGIN 'IPA v4.4 Lightweight CAs' )
attributeTypes: (2.16.840.1.113730.3.8.21.1.8 NAME 'ipaCaSubjectDN' DESC 'Subject DN' SUP distinguishedName X-ORIGIN 'IPA v4.4 Lightweight CAs' )
attributeTypes: (2.16.840.1.113730.3.8.21.1.9 NAME 'ipaCaRandomSerialNumberVersion' DESC 'Random Serial Number Version' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v4.9 RSNv3' )
attributeTypes: (2.16.840.1.113730.3.8.21.1.10 NAME 'ipaCaHSMConfiguration' DESC 'HSM Configuration' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v4.10 HSM' )
objectClasses: (2.16.840.1.113730.3.8.21.2.1 NAME 'ipaCertProfile' SUP top STRUCTURAL MUST ( cn $ description $ ipaCertProfileStoreIssued ) X-ORIGIN 'IPA v4.2' )
objectClasses: (2.16.840.1.113730.3.8.21.2.2 NAME 'ipaCaAcl' SUP ipaAssociation STRUCTURAL MUST cn MAY ( ipaCaCategory $ ipaCertProfileCategory $ userCategory $ hostCategory $ serviceCategory $ ipaMemberCa $ ipaMemberCertProfile $ memberService ) X-ORIGIN 'IPA v4.2' )
objectClasses: (2.16.840.1.113730.3.8.21.2.3 NAME 'ipaCa' SUP top STRUCTURAL MUST ( cn $ ipaCaId $ ipaCaSubjectDN $ ipaCaIssuerDN ) MAY ( description $ ipaCaRandomSerialNumberVersion $ ipaCaHSMConfiguration) X-ORIGIN 'IPA v4.4 Lightweight CAs' )
objectClasses: (2.16.840.1.113730.3.8.21.2.3 NAME 'ipaCa' SUP top STRUCTURAL MUST ( cn $ ipaCaId $ ipaCaSubjectDN $ ipaCaIssuerDN ) MAY ( description $ ipaCaRandomSerialNumberVersion ) X-ORIGIN 'IPA v4.4 Lightweight CAs' )
+1
View File
@@ -38,6 +38,7 @@ dist_app_DATA = \
default-trust-view.ldif \
delegation.ldif \
replica-acis.ldif \
replica-prevent-time-skew.ldif \
ds-nfiles.ldif \
ds-ipa-env.conf.template \
dns.ldif \
+2 -3
View File
@@ -87,6 +87,8 @@ pki_sslserver_subject_dn=cn=%(ipa_fqdn)s,%(ipa_subject_base)s
pki_subsystem_nickname=subsystemCert cert-pki-ca
pki_subsystem_subject_dn=cn=CA Subsystem,%(ipa_subject_base)s
pki_theme_enable=True
pki_theme_server_dir=/usr/share/pki/common-ui
pki_audit_group=pkiaudit
pki_group=pkiuser
pki_user=pkiuser
@@ -164,6 +166,3 @@ pki_audit_signing_subject_dn=cn=KRA Audit,%(ipa_subject_base)s
# We will use the dbuser created for the CA.
pki_share_db=True
pki_share_dbuser_dn=uid=pkidbuser,ou=people,o=ipaca
# KRA padding, set RSA-OAEP in FIPS mode
pki_use_oaep_rsa_keywrap=%(fips_use_oaep_rsa_keywrap)s
@@ -0,0 +1,4 @@
dn: cn=config
changetype: modify
replace: nsslapd-ignore-time-skew
nsslapd-ignore-time-skew: $SKEWVALUE
-2
View File
@@ -39,7 +39,6 @@ dist_noinst_DATA = \
ipa-pki-wait-running.in \
ipa-acme-manage.in \
ipa-subids.in \
ipa-migrate.in \
$(NULL)
nodist_sbin_SCRIPTS = \
@@ -69,7 +68,6 @@ nodist_sbin_SCRIPTS = \
ipa-crlgen-manage \
ipa-cert-fix \
ipa-acme-manage \
ipa-migrate \
$(NULL)
appdir = $(libexecdir)/ipa/
-22
View File
@@ -101,26 +101,6 @@ def parse_options():
"The CA certificate subject DN "
"(default CN=Certificate Authority,O=<realm-name>). "
"RDNs are in LDAP order (most specific RDN first)."))
parser.add_option("--token-name", dest="token_name",
default=None,
help=(
"The PKCS#11 token name if using an HSM to store "
"and generate private keys."))
parser.add_option("--token-library-path", dest="token_library_path",
default=None,
help=(
"The full path to the PKCS#11 shared library "
"needed to access the HSM device."))
parser.add_option("--token-password", dest="token_password",
default=None,
sensitive=True,
help=(
"The PKCS#11 token password for the HSM."))
parser.add_option("--token-password-file", dest="token_password_file",
default=None,
help=(
"The full path to a file containing the PKCS#11 "
" token password."))
parser.add_option("--pki-config-override", dest="pki_config_override",
default=None,
@@ -186,9 +166,7 @@ def install_replica(safe_options, options):
# Run ipa-certupdate to ensure we have the CA cert. This is
# necessary if the admin has just promoted the topology from
# CA-less to CA-ful, and ipa-certupdate has not been run yet.
print("Running ipa-certupdate...", end="", flush=True)
ipa_certupdate.run_with_args(api)
print("done")
# CertUpdate restarts DS causing broken pipe on the original
# connection, so reconnect the backend.
+2 -2
View File
@@ -192,10 +192,10 @@ class IPACustodiaTester:
usage, IPA_CUSTODIA_KEYFILE
))
if pkey.get('kid') != self.host_spn:
if pkey.key_id != self.host_spn:
raise self.error( # pylint: disable=raising-bad-type, #4772
"KID '{}' != host service principal name '{}' "
"(usage: {})".format(pkey.get('kid'), self.host_spn, usage),
"(usage: {})".format(pkey.key_id, self.host_spn, usage),
fatal=True
)
else:
-10
View File
@@ -1,10 +0,0 @@
#!/usr/bin/python3
#
# Copyright (C) 2023 FreeIPA Contributors see COPYING for license
#
# PYTHON_ARGCOMPLETE_OK
from ipaserver.install.ipa_migrate import IPAMigrate
ipa_migrate = IPAMigrate()
ipa_migrate.run()
+28 -53
View File
@@ -26,6 +26,7 @@ import os
import re
import socket
import traceback
from urllib.parse import urlparse
from xmlrpc.client import MAXINT
import ldap
@@ -357,14 +358,9 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False):
return True
def get_ruv(realm, host, dirman_passwd, nolookup=False, ca=False,
strict=True):
def get_ruv(realm, host, dirman_passwd, nolookup=False, ca=False):
"""
Return the RUV entries as a list of tuples: (hostname, rid)
If strict is True then the RUV must contain the ldap url, otherwise it is
ok to proceed with just the rid
"""
if not nolookup:
@@ -375,9 +371,10 @@ def get_ruv(realm, host, dirman_passwd, nolookup=False, ca=False,
thisrepl = replication.get_cs_replication_manager(realm, host, dirman_passwd)
else:
thisrepl = replication.ReplicationManager(realm, host, dirman_passwd)
except Exception as ex:
except Exception as e:
logger.debug("%s", traceback.format_exc())
raise RuntimeError(f"Failed to connect to server {host}: {ex}")
raise RuntimeError("Failed to connect to server {host}: {err}"
.format(host=host, err=e))
search_filter = '(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))'
try:
@@ -389,42 +386,24 @@ def get_ruv(realm, host, dirman_passwd, nolookup=False, ca=False,
raise NoRUVsFound("No RUV records found.")
servers = []
for entry in entries:
for ruv in entry['nsds50ruv']:
for e in entries:
for ruv in e['nsds50ruv']:
if ruv.startswith('{replicageneration'):
continue
# Get the RID, this is required in all cases
rid_data = re.match(
r'\{replica (\d+)',
ruv
)
if rid_data:
rid = rid_data.group(1)
data = re.match('\{replica (\d+) (ldap://.*:\d+)\}(\s+\w+\s+\w*){0,1}', ruv)
if data:
rid = data.group(1)
(
_scheme, netloc, _path, _params, _query, _fragment
) = urlparse(data.group(2))
servers.append((netloc, rid))
else:
print(f"unable to decode: {ruv} --> missing replica ID")
continue
# Attempt to extract ldap url from ruv (it's not always present)
netloc = "unknown host"
host_data = re.match(
r'(\{\w+\s+\d+\s+)ldap://(.+:\d+)',
ruv
)
if host_data:
netloc = host_data.group(2)
elif strict:
print(f"unable to decode: {ruv} --> missing LDAP url")
continue
# Ok update server list
servers.append((netloc, rid))
print("unable to decode: %s" % ruv)
return servers
def get_ruv_both_suffixes(realm, host, dirman_passwd, verbose, nolookup=False,
strict=True):
def get_ruv_both_suffixes(realm, host, dirman_passwd, verbose, nolookup=False):
"""
Get RUVs for both domain and ipaca suffixes
"""
@@ -432,20 +411,19 @@ def get_ruv_both_suffixes(realm, host, dirman_passwd, verbose, nolookup=False,
fail_gracefully = True
try:
ruvs['ca'] = get_ruv(realm, host, dirman_passwd, nolookup, True,
strict)
ruvs['ca'] = get_ruv(realm, host, dirman_passwd, nolookup, True)
except (NoRUVsFound, RuntimeError) as e:
err = f"Failed to get CS-RUVs from {host}: {e}"
err = "Failed to get CS-RUVs from {host}: {err}".format(host=host,
err=e)
if isinstance(e, RuntimeError):
fail_gracefully = False
if verbose:
print(err)
logger.debug('%s', err)
try:
ruvs['domain'] = get_ruv(realm, host, dirman_passwd, nolookup, False,
strict)
ruvs['domain'] = get_ruv(realm, host, dirman_passwd, nolookup)
except (NoRUVsFound, RuntimeError) as e:
err = f"Failed to get RUVs from {host}: {e}"
err = "Failed to get RUVs from {host}: {err}".format(host=host, err=e)
if isinstance(e, RuntimeError):
if not fail_gracefully:
raise
@@ -517,8 +495,7 @@ def clean_ruv(realm, ruv, options):
servers = get_ruv_both_suffixes(realm, options.host,
options.dirman_passwd,
options.verbose,
options.nolookup,
strict=False)
options.nolookup)
except (NoRUVsFound, RuntimeError) as e:
print(e)
sys.exit(0 if isinstance(e, NoRUVsFound) else 1)
@@ -574,8 +551,7 @@ def abort_clean_ruv(realm, ruv, options):
servers = get_ruv_both_suffixes(realm, options.host,
options.dirman_passwd,
options.verbose,
options.nolookup,
strict=False)
options.nolookup)
except (NoRUVsFound, RuntimeError) as e:
print(e)
sys.exit(0 if isinstance(e, NoRUVsFound) else 1)
@@ -734,8 +710,7 @@ def clean_dangling_ruvs(realm, host, options):
ruv_dict = get_ruv_both_suffixes(realm, master_cn,
options.dirman_passwd,
options.verbose,
options.nolookup,
strict=False)
options.nolookup)
except (RuntimeError, NoRUVsFound):
continue
@@ -743,12 +718,12 @@ def clean_dangling_ruvs(realm, host, options):
# This needs needs to be split off
if ruv_dict.get('domain'):
master_info['ruvs'] = {
(re.sub(r':\d+', '', x), y)
(re.sub(':\d+', '', x), y)
for (x, y) in ruv_dict['domain']
}
if ruv_dict.get('ca'):
master_info['csruvs'] = {
(re.sub(r':\d+', '', x), y)
(re.sub(':\d+', '', x), y)
for (x, y) in ruv_dict['ca']
}
except Exception as e:
@@ -1262,12 +1237,12 @@ def force_sync(realm, thishost, fromhost, dirman_passwd, nolookup=False):
repl.force_sync(repl.conn, fromhost)
else:
ds = dsinstance.DsInstance(realm_name=realm)
ds.replica_ignore_initial_time_skew()
ds.replica_manage_time_skew(prevent=False)
repl = replication.ReplicationManager(realm, fromhost, dirman_passwd)
repl.force_sync(repl.conn, thishost)
agreement = repl.get_replication_agreement(thishost)
repl.wait_for_repl_update(repl.conn, agreement.dn)
ds.replica_revert_time_skew()
ds.replica_manage_time_skew(prevent=True)
def show_DNA_ranges(hostname, master, realm, dirman_passwd, nextrange=False,
nolookup=False):
+1 -2
View File
@@ -30,8 +30,7 @@ dist_man1_MANS = \
ipa-crlgen-manage.1 \
ipa-cert-fix.1 \
ipa-acme-manage.1 \
ipa-migrate.1 \
$(NULL)
$(NULL)
dist_man8_MANS = \
ipactl.8 \
+1 -1
View File
@@ -27,7 +27,7 @@ Provides customized advice for various IPA configuration issues.
For the list of possible ADVICEs available, run the ipa\-advise with no arguments.
.SH "OPTIONS"
.TP
\fB\-v\fR, \fB\-\-verbose\fR
\fB\-\-v\fR, \fB\-\-verbose\fR
Print debugging information
.TP
\fB\-d\fR, \fB\-\-debug\fR
+1 -1
View File
@@ -54,7 +54,7 @@ Perform the backup on\-line. Requires the \-\-data option.
\fB\-\-disable\-role\-check\fR
Perform the backup even if this host does not have all the roles in use in the cluster. This is not recommended.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
\fB\-\-v\fR, \fB\-\-verbose\fR
Print debugging information
.TP
\fB\-d\fR, \fB\-\-debug\fR
-12
View File
@@ -85,18 +85,6 @@ Do not use DNS for hostname lookup during installation
\fB\-\-random\-serial\-numbers\fR
Enable Random Serial Numbers. Random serial numbers cannot be used in a mixed environment. Either all CA's have it enabled or none do.
.TP
\fB\-\-token\-name\fR=\fITOKEN_NAME\fR
The PKCS#11 token name if using an HSM to store and generate private keys.
.TP
\fB\-\-token\-library\-path\fR=\fITOKEN_LIBRARY_PATH\fR
The full path to the PKCS#11 shared library needed to access the HSM device.
.TP
\fB\-\-token\-password\fR=\fITOKEN_PASSWORD\fR
The PKCS#11 token password for the HSM.
.TP
\fB\-\-token\-password\-file\fR=\fITOKEN_PASSWORD_FILE\fR
The full path to a file containing the PKCS#11 token password.
.TP
\fB\-\-skip\-conncheck\fR
Skip connection check to remote master
.TP
-9
View File
@@ -54,15 +54,6 @@ Log to the given file
.TP
\fB\-\-pki\-config\-override\fR=\fIFILE\fR
File containing overrides for KRA installation.
.SS "HSM OPTIONS"
The token name and library path are retrieved from the existing
installation.
.TP
\fB\-\-token\-password\fR=\fITOKEN_PASSWORD\fR
The PKCS#11 token password for the HSM.
.TP
\fB\-\-token\-password\-file\fR=\fITOKEN_PASSWORD_FILE\fR
The full path to a file containing the PKCS#11 token password.
.SH "EXIT STATUS"
0 if the command was successful
-127
View File
@@ -1,127 +0,0 @@
.\"
.\" Copyright (C) 2024 FreeIPA Contributors see COPYING for license
.\"
.TH "ipa-migrate" "1" "Apr 2 2024" "IPA" "IPA Manual Pages"
.SH "NAME"
ipa\-migrate \- Migrate an IPA server from one machine to another
.SH "SYNOPSIS"
ipa\-migrate
.SH "DESCRIPTION"
Use the \fIipa-migrate\fR command to migrate one
IPA server to an existing local IPA server installation.
Migrate IPA schema, configuration, and database to a local IPA server. This
migration can be done online, where the tool will query the remote server. Or,
offline where LDIF files can be provided. You can mix and match online and
offline. So for example you could migrate the schema and configuration online,
and then use an exported LDIF file for the database migration portion (this
might be more useful for very large databases as you don't need to worry about
network interruptions)
.SH POSITIONAL ARGUMENTS
.TP
\fBprod\-mode\fR
In this mode everything will be migrated including the current user SIDs and
DNA ranges
.TP
\fBstage\-mode\fR
In this mode, SIDs & DNA ranges are not migrated, and DNA attributes are reset
.SH "COMMANDS"
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Use verbose output while running the migration tool.
.TP
\fB\-e\fR, \fB\-\-hostname=HOSTNAME\fR
The host name of the remote IPA server that is being migrated from.
.TP
\fB\-D\fR, \fB\-\-bind\-dn=BIND_DN\fR
The Bind DN (Distinguished Name) or an LDAP entry to bind to the remote IPA server with.
Typically this is "cn=directory manager", but it could be any entry that has
access to read the userPassword attribute. If ommitted the default is "cn=directory manager"
.TP
\fB\-w\fR, \fB\-\-bind\-pw=PASSWORD\fR
The password for the Bind DN that is authenticating against the remote IPA server. If
a password is not provided then the tool with prompt for the password if needed.
.TP
\fB\-Just\fR, \fB\-\-bind\-pw\-file=FILE_PATH\fR
Path to a file containing the password for the Bind DN.
.TP
\fB\-Z\fR, \fB\-\-cacertfile=FILE_PATH\fR
Path to a file containing a CA Certificate that the remote server trusts
.TP
\fB\-l\fR, \fB\-\-log\-file=FILE_PATH\fR
Path to a file containing the migration log. By default the tool will use \fI/var/log/ipa-migrate.log\fR
.TP
\fB\-x\fR, \fB\-\-dryrun\fR
Go through the migration process but do not write and data to the new IPA server.
.TP
\fB\-o\fR, \fB\-\-dryrun\-record=FILE_PATH\fR
Go through the migration process but do not write any data to the new IPA server. However, write the
migration operations to an LDIF file which can be applied later or reused for multiple migrations.
.TP
\fB\-r\fR, \fB\-\-reset\-range\fR
Reset the ID range for migrated users/groups. In "stage-mode" this is done automatically
.TP
\fB\-F\fR, \fB\-\-force\fR
Ignore any errors and continue to proceed with migration effort.
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Only log errors during the migration process.
.TP
\fB\-B\fR, \fB\-\-migrate\-dns\fR
Migrate thr DNS records
.TP
\fB\-S\fR, \fB\-\-skip\-schema\fR
Do not migrate the database schema
.TP
\fB\-C\fR, \fB\-\-skip\-config\fR
Do not migrate the database configuration (dse.ldif/cn=config)
.TP
\fB\-O\fR, \fB\-\-schema\-overwrite\fR
Overwrite existing schema definitions. By default duplicate schema is skipped.
.TP
\fB\-s\fR, \fB\-\-subtree=DN\fR
Specifies a custom database subtree that should be included in the migration.
This is only needed if non-default subtrees/branches were added to the database
outside of IPA.
.TP
\fB\-f\fR, \fB\-\-db\-ldif=FILE_PATH\fR
LDIF file containing the entire backend. If omitted the tool will query the remote IPA server.
.TP
\fB\-m\fR, \fB\-\-schema\-ldif=FILE_PATH\fR
LDIF file containing the schema. If omitted the tool will query the remote IPA server.
.TP
\fB\-g\fR, \fB\-\-config\-ldif=FILE_PATH\fR
LDIF file containing the entire "cn=config" DIT. If omitted the tool will query the remote IPA server.
.TP
\fB\-n\fR, \fB\-\-no\-prompt\fR
Do not prompt for confirmation before starting migration. Use at your own risk!
.SH "POST MIGRATION"
\- The server is left in migration-mode so that the migrated users can more
easily reset their passwords either by authenticating via SSSD or using the
web-based password migration page. This authentication will generate new
Kerberos keys. After passwords are reset the server should be taken out of
migration mode.
\- All hosts are preserved, but they will need to be re-enrolled using
ipa-client-install (e.g. ipa-client-install --uninstall && ipa-client-install).
\- All certificates should be re-issued against the new CA.
\- Any manually created keytabs will need to be re-created using
\fIipa-getkeytab\fR
\- Vaults are not migrated and will have to be re-created.
\- Sub CA's are not migrated and will have to be re-created.
.SH "EXIT STATUS"
0 If the command was successful
1 If an error occurred
2 If the local host or remote host is not an IPA server, the IPA server
installation is faulty, or the realm can not be determined
-13
View File
@@ -152,19 +152,6 @@ File containing overrides for CA and KRA installation.
\fB\-\-skip\-schema\-check\fR
Skip check for updated CA DS schema on the remote master
.SS "HSM OPTIONS"
The token name will be used from the existing topology.
.TP
\fB\-\-token\-library\-path\fR=\fITOKEN_LIBRARY_PATH\fR
The full path to the PKCS#11 shared library needed to access the HSM device. If the path is identical to the original install then this does not need to be provided.
.TP
\fB\-\-token\-password\fR=\fITOKEN_PASSWORD\fR
The PKCS#11 token password for the HSM.
.TP
\fB\-\-token\-password\-file\fR=\fITOKEN_PASSWORD_FILE\fR
The full path to a file containing the PKCS#11 token password.
.SS "SECRET MANAGEMENT OPTIONS"
.TP
\fB\-\-setup\-kra\fR
+1 -1
View File
@@ -73,7 +73,7 @@ Restore only the databases in this 389\-ds instance. The default is to restore a
\fB\-\-backend\fR=\fIBACKEND\fR
The backend to restore within an instance or instances. Requires data\-only backup or the \-\-data option.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
\fB\-\-v\fR, \fB\-\-verbose\fR
Print debugging information
.TP
\fB\-d\fR, \fB\-\-debug\fR
-14
View File
@@ -173,20 +173,6 @@ The subject base for certificates issued by IPA (default O=REALM.NAME). RDNs are
\fB\-\-ca\-signing\-algorithm\fR=\fIALGORITHM\fR
Signing algorithm of the IPA CA certificate. Possible values are SHA1withRSA, SHA256withRSA, SHA384withRSA, SHA512withRSA. Default value is SHA256withRSA. Use this option with --external-ca if the external CA does not support the default signing algorithm.
.SS "HSM OPTIONS"
.TP
\fB\-\-token\-name\fR=\fITOKEN_NAME\fR
The PKCS#11 token name if using an HSM to store and generate private keys.
.TP
\fB\-\-token\-library\-path\fR=\fITOKEN_LIBRARY_PATH\fR
The full path to the PKCS#11 shared library needed to access the HSM device.
.TP
\fB\-\-token\-password\fR=\fITOKEN_PASSWORD\fR
The PKCS#11 token password for the HSM.
.TP
\fB\-\-token\-password\-file\fR=\fITOKEN_PASSWORD_FILE\fR
The full path to a file containing the PKCS#11 token password.
.SS "SECRET MANAGEMENT OPTIONS"
.TP
\fB\-\-setup\-kra\fR
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+1 -12
View File
@@ -110,19 +110,8 @@ return {
{
$type: 'association',
name: 'member_user',
row_disabled_attribute: 'nsaccountlock',
columns: [
columns:[
'uid',
'givenname',
'sn',
{
name: 'nsaccountlock',
label: '@i18n:status.label',
formatter: {
$type: 'boolean_status',
invert_value: true
}
},
'uidnumber',
'mail',
'telephonenumber',
-11
View File
@@ -28,14 +28,3 @@ default:member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX
dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
remove:aci: (targetattr=cn || dnaMaxValue || dnaNextRange || dnaNextValue || dnaThreshold || dnaType || objectclass)(version 3.0;acl "permission:Read DNA Range";allow (read, search, compare) groupdn = "ldap:///cn=Read DNA Range,cn=permissions,cn=pbac,$SUFFIX";)
add:aci: (targetattr = "cn || dnaMaxValue || dnaNextRange || dnaNextValue || dnaThreshold || dnaType || objectclass")(version 3.0;acl "permission:Read DNA Range";allow (read, search, compare) groupdn = "ldap:///cn=Read DNA Range,cn=permissions,cn=pbac,$SUFFIX";)
dn: cn=Read domain level,cn=permissions,cn=pbac,$SUFFIX
default:objectClass: top
default:objectClass: groupofnames
default:objectClass: ipapermission
default:cn: Read domain level
default:ipapermissiontype: SYSTEM
default:member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX
dn: cn=masters,cn=ipa,cn=etc,$SUFFIX
add:aci: (targetattr = "ipamaxdomainlevel || ipamindomainlevel")(version 3.0;acl "permission:Read domain level";allow (read, search, compare) groupdn = "ldap:///cn=Read domain level,cn=permissions,cn=pbac,$SUFFIX";)
-2
View File
@@ -7,5 +7,3 @@ add: krbSupportedEncSaltTypes: aes128-sha2:normal
add: krbSupportedEncSaltTypes: aes128-sha2:special
add: krbSupportedEncSaltTypes: aes256-sha2:normal
add: krbSupportedEncSaltTypes: aes256-sha2:special
remove: krbDefaultEncSaltTypes: des3-hmac-sha1:special
remove: krbDefaultEncSaltTypes: arcfour-hmac:special
+1 -1
View File
@@ -54,4 +54,4 @@ add:aci: (target="ldap:///krbprincipalname=cifs/($$dn),cn=services,cn=accounts,$
# Add the default PAC type to configuration
dn: cn=ipaConfig,cn=etc,$SUFFIX
add: ipaKrbAuthzData: MS-PAC
addifnew: ipaKrbAuthzData: MS-PAC
+32 -103
View File
@@ -18,7 +18,7 @@ import logging
import dns
import getpass
import gssapi
import ifaddr
import netifaces
import os
import re
import SSSDConfig
@@ -40,7 +40,7 @@ from ipalib.constants import FQDN, IPAAPI_USER, MAXHOSTNAMELEN
from ipalib.install import certmonger, certstore, service
from ipalib.install import hostname as hostname_
from ipalib.facts import is_ipa_client_configured, is_ipa_configured
from ipalib.kinit import kinit_keytab, kinit_password, kinit_pkinit
from ipalib.install.kinit import kinit_keytab, kinit_password, kinit_pkinit
from ipalib.install.service import enroll_only, prepare_only
from ipalib.rpc import delete_persistent_client_session_data
from ipalib.util import (
@@ -167,8 +167,7 @@ def get_cert_path(cert_path):
if cert_path is not None:
return cert_path
if os.path.exists(paths.IPA_CA_CRT) and \
os.stat(paths.IPA_CA_CRT).st_size != 0:
if os.path.exists(paths.IPA_CA_CRT):
return paths.IPA_CA_CRT
return None
@@ -1145,21 +1144,7 @@ def configure_ssh_config(fstore, options):
def modify_ssh_config(options):
changes = {'PubkeyAuthentication': 'yes'}
# sss_ssh_knownhostsproxy is deprecated in favor of sss_ssh_knownhosts
# use sss_ssh_knownhosts when possible
enableknownhosts = bool(
options.sssd and os.path.isfile(paths.SSS_SSH_KNOWNHOSTS)
)
enableproxy = bool(
options.sssd and os.path.isfile(paths.SSS_SSH_KNOWNHOSTSPROXY)
and not enableknownhosts
)
if options.sssd and enableknownhosts:
changes[
'KnownHostsCommand'] = '%s %%H' % paths.SSS_SSH_KNOWNHOSTS
if options.sssd and enableproxy:
if options.sssd and os.path.isfile(paths.SSS_SSH_KNOWNHOSTSPROXY):
changes[
'ProxyCommand'] = '%s -p %%p %%h' % paths.SSS_SSH_KNOWNHOSTSPROXY
changes['GlobalKnownHostsFile'] = paths.SSSD_PUBCONF_KNOWN_HOSTS
@@ -1171,23 +1156,14 @@ def modify_ssh_config(options):
def create_ssh_ipa_config(options):
"""Add the IPA snippet for ssh"""
# sss_ssh_knownhostsproxy is deprecated in favor of sss_ssh_knownhosts
# use sss_ssh_knownhosts when possible
enableknownhosts = bool(
options.sssd and os.path.isfile(paths.SSS_SSH_KNOWNHOSTS)
)
enableproxy = bool(
options.sssd and os.path.isfile(paths.SSS_SSH_KNOWNHOSTSPROXY)
and not enableknownhosts
)
ipautil.copy_template_file(
os.path.join(paths.SSH_IPA_CONFIG_TEMPLATE),
paths.SSH_IPA_CONFIG,
dict(
ENABLEKNOWNHOSTS='' if enableknownhosts else '#',
KNOWNHOSTSCOMMAND=paths.SSS_SSH_KNOWNHOSTS,
ENABLEPROXY='' if enableproxy else '#',
KNOWNHOSTSPROXY=paths.SSS_SSH_KNOWNHOSTSPROXY,
KNOWNHOSTS=paths.SSSD_PUBCONF_KNOWN_HOSTS,
@@ -1297,7 +1273,7 @@ def create_sshd_ipa_config(options):
logger.info('Configured %s', paths.SSHD_IPA_CONFIG)
def configure_automount(options, statestore):
def configure_automount(options):
logger.info('\nConfiguring automount:')
args = [
@@ -1310,15 +1286,12 @@ def configure_automount(options, statestore):
if not options.sssd:
args.append('--no-sssd')
statestore.backup_state('installation', 'automount', True)
try:
result = run(args)
except Exception as e:
logger.error('Automount configuration failed: %s', str(e))
else:
logger.info('%s', result.output_log)
finally:
statestore.delete_state('installation', 'automount')
def configure_nisdomain(options, domain, statestore):
@@ -1374,36 +1347,31 @@ def unconfigure_nisdomain(statestore):
def get_iface_from_ip(ip_addr):
for adapter in ifaddr.get_adapters():
for ips in adapter.ips:
# IPv6 is reported as a tuple, IPv4 is reported as str
if ip_addr in (ips.ip[0], ips.ip):
return adapter.name
for interface in netifaces.interfaces():
if_addrs = netifaces.ifaddresses(interface)
for family in [netifaces.AF_INET, netifaces.AF_INET6]:
for ip in if_addrs.get(family, []):
if ip['addr'] == ip_addr:
return interface
raise RuntimeError("IP %s not assigned to any interface." % ip_addr)
def __get_ifaddr_adapters(iface=None):
if iface:
interfaces = set(iface if isinstance(iface, (list, tuple)) else [iface])
else:
interfaces = set(adapter.name for adapter in ifaddr.get_adapters())
return [
adapter
for adapter in ifaddr.get_adapters()
if adapter.name in interfaces or adapter.nice_name in interfaces
]
def get_local_ipaddresses(iface=None):
if iface:
interfaces = [iface]
else:
interfaces = netifaces.interfaces()
ips = []
for adapter in __get_ifaddr_adapters(iface):
for ifip in adapter.ips:
try:
ip_addr = ifip.ip[0] if isinstance(ifip.ip, tuple) else ifip.ip
ips.append(ipautil.CheckedIPAddress(ip_addr))
logger.debug('IP check successful: %s', ip_addr)
except ValueError as e:
logger.debug('IP check failed: %s', e)
for interface in interfaces:
if_addrs = netifaces.ifaddresses(interface)
for family in [netifaces.AF_INET, netifaces.AF_INET6]:
for ip in if_addrs.get(family, []):
try:
ips.append(ipautil.CheckedIPAddress(ip['addr']))
logger.debug('IP check successful: %s', ip['addr'])
except ValueError as e:
logger.debug('IP check failed: %s', e)
return ips
@@ -1756,8 +1724,8 @@ def cert_summary(msg, certs, indent=' '):
for cert in certs:
s += '%sSubject: %s\n' % (indent, DN(cert.subject))
s += '%sIssuer: %s\n' % (indent, DN(cert.issuer))
s += '%sValid From: %s\n' % (indent, cert.not_valid_before_utc)
s += '%sValid Until: %s\n' % (indent, cert.not_valid_after_utc)
s += '%sValid From: %s\n' % (indent, cert.not_valid_before)
s += '%sValid Until: %s\n' % (indent, cert.not_valid_after)
s += '\n'
s = s[:-1]
@@ -3337,11 +3305,7 @@ def _install(options, tdict):
configure_sshd_config(fstore, options)
if options.location:
configure_automount(options, statestore)
# Reload the state as automount install may have modified it
fstore._load()
statestore._load()
configure_automount(options)
if options.configure_firefox:
configure_firefox(options, statestore, cli_domain)
@@ -3404,15 +3368,12 @@ def uninstall(options):
fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE)
statestore.backup_state('installation', 'automount', True)
try:
run([paths.IPA_CLIENT_AUTOMOUNT, "--uninstall", "--debug"])
except CalledProcessError as e:
if e.returncode != CLIENT_NOT_CONFIGURED:
logger.error(
"Unconfigured automount client failed: %s", str(e))
finally:
statestore.delete_state('installation', 'automount')
# Reload the state as automount unconfigure may have modified it
fstore._load()
@@ -3455,7 +3416,7 @@ def uninstall(options):
# - sssd was removed after install and before uninstall
# - there are no active domains
# in both cases we cannot continue with SSSD
all_domains = []
pass
if hostname is None:
hostname = FQDN
@@ -3514,9 +3475,7 @@ def uninstall(options):
if result.returncode != 0:
logger.error("Unenrolling host failed: %s", result.error_log)
if os.path.exists(paths.IPA_DEFAULT_CONF) and os.path.exists(
paths.KRB5_KEYTAB
):
if os.path.exists(paths.IPA_DEFAULT_CONF):
logger.info(
"Removing Kerberos service principals from /etc/krb5.keytab")
try:
@@ -3568,18 +3527,6 @@ def uninstall(options):
# Clean up the SSSD cache before SSSD service is stopped or restarted
remove_file(paths.SSSD_MC_GROUP)
remove_file(paths.SSSD_MC_PASSWD)
remove_file(paths.SSSD_MC_INITGROUPS)
remove_file(paths.SSSD_MC_SID)
for root, _dirs, files in os.walk(paths.SSSD_PIPES):
for file in files:
remove_file(os.path.join(root, file))
for domain in all_domains:
name = f"domain_realm_{domain.replace('.', '_')}"
filename = os.path.join(paths.SSSD_PUBCONF_KRB5_INCLUDE_D_DIR, name)
if os.path.exists(filename):
remove_file(filename)
if was_sssd_installed:
try:
@@ -3599,20 +3546,6 @@ def uninstall(options):
sssd_ccache_file = os.path.join(paths.SSSD_DB, sssd_domain_ccache)
remove_file(sssd_ccache_file)
remove_file(paths.SSSD_LDB)
remove_file(paths.SSSD_CONFIG_LDB)
# Stop sssd-kcm.service before removing the KCM ccaches database
# it is socket-activated and will be restarted whenever needed
try:
services.service('sssd-kcm', api).stop()
except Exception as e:
logger.warning("Failed to stop sssd-kcm: %s", e)
remove_file(paths.SSSD_SECRETS)
sssd_timestamps = "timestamps_" + ipa_domain + ".ldb"
sssd_timestamps_file = os.path.join(paths.SSSD_DB, sssd_timestamps)
remove_file(sssd_timestamps_file)
# Next if-elif-elif construction deals with sssd.conf file.
# Old pre-IPA domains are preserved due merging the old sssd.conf
# during the installation of ipa-client but any new domains are
@@ -3764,16 +3697,12 @@ def uninstall(options):
logger.warning(
'Some installation state has not been restored.\n'
'This may cause re-installation to fail.\n'
'It should be safe to remove %s '
'It should be safe to remove /var/lib/ipa-client/sysrestore.state '
'but it may\n mean your system hasn\'t been restored '
'to its pre-installation state.',
os.path.join(paths.IPA_CLIENT_SYSRESTORE,
sysrestore.SYSRESTORE_STATEFILE)
)
'to its pre-installation state.')
# Remove the IPA configuration file
remove_file(paths.IPA_DEFAULT_CONF)
remove_file(paths.IPA_DEFAULT_CONF + '.ipabkp')
# Remove misc backups
remove_file(paths.OPENLDAP_LDAP_CONF + '.ipabkp')
+12 -14
View File
@@ -36,14 +36,14 @@ from six.moves.urllib.parse import urlsplit
from optparse import OptionParser # pylint: disable=deprecated-module
from ipapython import ipachangeconf
from ipaclient import discovery
from ipaclient.install import ipadiscovery
from ipaclient.install.client import (
CLIENT_NOT_CONFIGURED,
CLIENT_ALREADY_CONFIGURED,
)
from ipalib import api, errors
from ipalib.install import sysrestore
from ipalib.kinit import kinit_keytab
from ipalib.install.kinit import kinit_keytab
from ipalib.util import check_client_configuration
from ipapython import ipautil
from ipapython.ipa_log_manager import standard_logging_setup
@@ -340,16 +340,14 @@ def configure_nfs(fstore, statestore, options):
def configure_automount():
statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE)
if not statestore.get_state('installation', 'automount'):
# not called from ipa-client-install
try:
check_client_configuration()
except ScriptError as e:
print(e.msg)
sys.exit(e.rval)
try:
check_client_configuration()
except ScriptError as e:
print(e.msg)
sys.exit(e.rval)
fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE)
options, _args = parse_options()
@@ -384,12 +382,12 @@ def configure_automount():
sys.exit(CLIENT_ALREADY_CONFIGURED)
autodiscover = False
ds = discovery.IPADiscovery()
ds = ipadiscovery.IPADiscovery()
if not options.server:
print("Searching for IPA server...")
ret = ds.search(ca_cert_path=ca_cert_path)
logger.debug('Executing DNS discovery')
if ret == discovery.NO_LDAP_SERVER:
if ret == ipadiscovery.NO_LDAP_SERVER:
logger.debug('Autodiscovery did not find LDAP server')
s = urlsplit(api.env.xmlrpc_uri)
server = [s.netloc]
@@ -409,14 +407,14 @@ def configure_automount():
server = options.server
logger.debug("Verifying that %s is an IPA server", server)
ldapret = ds.ipacheckldap(server, api.env.realm, ca_cert_path)
if ldapret[0] == discovery.NO_ACCESS_TO_LDAP:
if ldapret[0] == ipadiscovery.NO_ACCESS_TO_LDAP:
print("Anonymous access to the LDAP server is disabled.")
print("Proceeding without strict verification.")
print(
"Note: This is not an error if anonymous access has been "
"explicitly restricted."
)
elif ldapret[0] == discovery.NO_TLS_LDAP:
elif ldapret[0] == ipadiscovery.NO_TLS_LDAP:
logger.warning("Unencrypted access to LDAP is not supported.")
elif ldapret[0] != 0:
sys.exit('Unable to confirm that %s is an IPA server' % server)
+3 -4
View File
@@ -26,16 +26,15 @@ class WithCertOutArgs(MethodOverride):
filename = None
if 'certificate_out' in options:
filename = options.pop('certificate_out')
result = super(WithCertOutArgs, self).forward(*keys, **options)
if filename:
try:
util.check_writable_file(filename)
except errors.FileError as e:
raise errors.ValidationError(name='certificate-out',
error=str(e))
result = super(WithCertOutArgs, self).forward(*keys, **options)
if filename:
# if result certificate / certificate_chain not present in result,
# it means Dogtag did not provide it (probably due to LWCA key
# replication lag or failure. The server transmits a warning
+9 -8
View File
@@ -43,24 +43,25 @@ class CertRetrieveOverride(MethodOverride):
)
def forward(self, *args, **options):
filename = None
if 'certificate_out' in options:
filename = options.pop('certificate_out')
result = super(CertRetrieveOverride, self).forward(*args, **options)
if filename is not None:
certificate_out = options.pop('certificate_out')
try:
util.check_writable_file(filename)
util.check_writable_file(certificate_out)
except errors.FileError as e:
raise errors.ValidationError(name='certificate-out',
error=str(e))
else:
certificate_out = None
result = super(CertRetrieveOverride, self).forward(*args, **options)
if certificate_out is not None:
if options.get('chain', False):
certs = result['result']['certificate_chain']
else:
certs = [base64.b64decode(result['result']['certificate'])]
certs = (x509.load_der_x509_certificate(cert) for cert in certs)
x509.write_certificate_list(certs, filename)
x509.write_certificate_list(certs, certificate_out)
return result
-2
View File
@@ -38,8 +38,6 @@ class hbactest(CommandOverride):
# Note that we don't actually use --detail below to see if details need
# to be printed as our execute() method will return None for corresponding
# entries and None entries will be skipped.
self.log_messages(output)
for o in self.output:
if o == 'value':
continue
+18 -53
View File
@@ -119,8 +119,8 @@ def encrypt(data, symmetric_key=None, public_key=None):
return public_key_obj.encrypt(
data,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
@@ -154,8 +154,8 @@ def decrypt(data, symmetric_key=None, private_key=None):
return private_key_obj.decrypt(
data,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
@@ -550,8 +550,10 @@ class vault_mod(Local):
class _KraConfigCache:
"""The KRA config cache stores vaultconfig-show result.
"""
def __init__(self, api):
self._dirname = os.path.join(api.env.cache_dir, 'kra-config')
def __init__(self):
self._dirname = os.path.join(
constants.USER_CACHE_PATH, 'ipa', 'kra-config'
)
def _get_filename(self, domain):
basename = DNSName(domain).ToASCII() + '.json'
@@ -627,7 +629,7 @@ class _KraConfigCache:
return True
_kra_config_cache = _KraConfigCache(api)
_kra_config_cache = _KraConfigCache()
@register(override=True, no_fail=True)
@@ -703,39 +705,14 @@ class ModVaultData(Local):
return transport_cert, wrapping_algo
def _do_internal(self, algo, transport_cert, raise_unexpected,
use_oaep=False, *args, **options):
*args, **options):
public_key = transport_cert.public_key()
# wrap session key with transport certificate
# KRA may be configured using either the default PKCS1v15 or RSA-OAEP.
# there is no way to query this info using the REST interface.
if not use_oaep:
# PKCS1v15() causes an OpenSSL exception when FIPS is enabled
# if so, we fallback to RSA-OAEP
try:
wrapped_session_key = public_key.encrypt(
algo.key,
padding.PKCS1v15()
)
except ValueError:
wrapped_session_key = public_key.encrypt(
algo.key,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
else:
wrapped_session_key = public_key.encrypt(
algo.key,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
wrapped_session_key = public_key.encrypt(
algo.key,
padding.PKCS1v15()
)
options['session_key'] = wrapped_session_key
name = self.name + '_internal'
@@ -746,7 +723,7 @@ class ModVaultData(Local):
errors.ExecutionError,
errors.GenericError):
_kra_config_cache.remove(self.api.env.domain)
if raise_unexpected and use_oaep:
if raise_unexpected:
raise
return None
@@ -755,28 +732,16 @@ class ModVaultData(Local):
Calls the internal counterpart of the command.
"""
# try call with cached transport certificate
try:
result = self._do_internal(algo, transport_cert, False,
False, *args, **options)
except errors.EncodingError:
result = self._do_internal(algo, transport_cert, False,
True, *args, **options)
result = self._do_internal(algo, transport_cert, False,
*args, **options)
if result is not None:
return result
# retrieve transport certificate (cached by vaultconfig_show)
transport_cert = self._get_vaultconfig(force_refresh=True)[0]
# call with the retrieved transport certificate
result = self._do_internal(algo, transport_cert, True,
False, *args, **options)
if result is not None:
return result
# call and use_oaep this time, last attempt
return self._do_internal(algo, transport_cert, True,
True, *args, **options)
*args, **options)
@register(no_fail=True)
+1 -1
View File
@@ -16,7 +16,7 @@ from ipapython.dnsutil import DNSName
if six.PY3:
unicode = str
__doc__ = _(r"""
__doc__ = _("""
Auto Membership Rule.
Bring clarity to the membership of hosts and users by configuring inclusive
+1 -1
View File
@@ -16,7 +16,7 @@ from ipapython.dnsutil import DNSName
if six.PY3:
unicode = str
__doc__ = _(r"""
__doc__ = _("""
Groups of users
Manage groups of users. By default, new groups are POSIX groups. You
+1 -1
View File
@@ -16,7 +16,7 @@ from ipapython.dnsutil import DNSName
if six.PY3:
unicode = str
__doc__ = _(r"""
__doc__ = _("""
Simulate use of Host-based access controls
HBAC rules control who can access what services on what hosts.
+1 -1
View File
@@ -16,7 +16,7 @@ from ipapython.dnsutil import DNSName
if six.PY3:
unicode = str
__doc__ = _(r"""
__doc__ = _("""
Cross-realm trusts
Manage trust relationship between IPA and Active Directory domains.
+1 -1
View File
@@ -16,7 +16,7 @@ from ipapython.dnsutil import DNSName
if six.PY3:
unicode = str
__doc__ = _(r"""
__doc__ = _("""
Auto Membership Rule.
Bring clarity to the membership of hosts and users by configuring inclusive
+1 -1
View File
@@ -16,7 +16,7 @@ from ipapython.dnsutil import DNSName
if six.PY3:
unicode = str
__doc__ = _(r"""
__doc__ = _("""
Groups of users
Manage groups of users. By default, new groups are POSIX groups. You
+1 -1
View File
@@ -16,7 +16,7 @@ from ipapython.dnsutil import DNSName
if six.PY3:
unicode = str
__doc__ = _(r"""
__doc__ = _("""
Cross-realm trusts
Manage trust relationship between IPA and Active Directory domains.
+7 -5
View File
@@ -13,16 +13,18 @@ import time
from . import compat
from . import schema
from ipaclient.plugins.rpcclient import rpcclient
from ipalib.constants import USER_CACHE_PATH
from ipapython.dnsutil import DNSName
logger = logging.getLogger(__name__)
class ServerInfo(MutableMapping):
_DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'servers')
def __init__(self, api):
self._dir = os.path.join(api.env.cache_dir, "servers")
hostname = DNSName(api.env.server).ToASCII()
self._filename = os.path.join(self._dir, hostname)
self._path = os.path.join(self._DIR, hostname)
self._force_check = api.env.force_schema_check
self._now = time.time()
self._dict = {}
@@ -39,7 +41,7 @@ class ServerInfo(MutableMapping):
def _read(self):
try:
with open(self._filename, 'r') as sc:
with open(self._path, 'r') as sc:
self._dict = json.load(sc)
except Exception as e:
if (isinstance(e, EnvironmentError) and
@@ -54,11 +56,11 @@ class ServerInfo(MutableMapping):
def _write(self):
try:
try:
os.makedirs(self._dir)
os.makedirs(self._DIR)
except EnvironmentError as e:
if e.errno != errno.EEXIST:
raise
with open(self._filename, 'w') as sc:
with open(self._path, 'w') as sc:
json.dump(self._dict, sc)
except EnvironmentError as e:
logger.warning('Failed to write server info: %s', e)
+8 -7
View File
@@ -18,6 +18,7 @@ import six
from ipaclient.frontend import ClientCommand, ClientMethod
from ipalib import errors, parameters, plugable
from ipalib.constants import USER_CACHE_PATH
from ipalib.errors import SchemaUpToDate
from ipalib.frontend import Object
from ipalib.output import Output
@@ -366,9 +367,9 @@ class Schema:
"""
namespaces = {'classes', 'commands', 'topics'}
_DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema', FORMAT)
def __init__(self, client, fingerprint=None, ttl=0):
self._dir = os.path.join(client.api.env.cache_dir, 'schema', FORMAT)
self._dict = {}
self._namespaces = {}
self._help = None
@@ -408,7 +409,7 @@ class Schema:
fps = []
if not ignore_cache:
try:
fps = [fsdecode(f) for f in os.listdir(self._dir)]
fps = [fsdecode(f) for f in os.listdir(self._DIR)]
except EnvironmentError:
pass
@@ -438,7 +439,7 @@ class Schema:
def _read_schema(self, fingerprint):
# It's more efficient to read zip file members at once than to open
# the zip file a couple of times, see #6690.
filename = os.path.join(self._dir, fingerprint)
filename = os.path.join(self._DIR, fingerprint)
with zipfile.ZipFile(filename, 'r') as schema:
for name in schema.namelist():
ns, _slash, key = name.partition('/')
@@ -476,13 +477,13 @@ class Schema:
def _write_schema(self, fingerprint):
try:
os.makedirs(self._dir)
os.makedirs(self._DIR)
except EnvironmentError as e:
if e.errno != errno.EEXIST:
raise
with tempfile.NamedTemporaryFile('wb', prefix=fingerprint,
dir=self._dir, delete=False) as f:
dir=self._DIR, delete=False) as f:
try:
self._write_schema_data(f)
ipautil.flush_sync(f)
@@ -491,7 +492,7 @@ class Schema:
os.unlink(f.name)
raise
else:
os.rename(f.name, os.path.join(self._dir, fingerprint))
os.rename(f.name, os.path.join(self._DIR, fingerprint))
def _write_schema_data(self, fileobj):
with zipfile.ZipFile(fileobj, 'w', zipfile.ZIP_DEFLATED) as schema:
@@ -584,7 +585,7 @@ def get_package(server_info, client):
for plugin_cls in (_SchemaCommandPlugin, _SchemaObjectPlugin):
for full_name in schema[plugin_cls.schema_key]:
plugin = plugin_cls(schema, str(full_name))
plugin = module.register()(plugin) # pylint: disable=no-member
plugin = module.register()(plugin)
sys.modules[module_name] = module
for full_name, topic in six.iteritems(schema['topics']):
+4 -11
View File
@@ -955,19 +955,12 @@ class API(plugable.API):
import os
import ipalib
try:
from ipalib import kinit
except ImportError:
from ipalib.install import kinit
# set a custom ccache to isolate from the environment
ccache_name = "FILE:/path/to/tmp/service.ccache"
os.environ["KRB5CCNAME"] = ccache_name
# optional: automatic authentication with a KRB5 keytab
os.environ["KRB5_CLIENT_KTNAME"] = "/path/to/service.keytab"
# or with password
kinit.kinit_passwd("username", "password", ccache_name)
os.environ.update(
KRB5_CLIENT_KTNAME="/path/to/service.keytab",
KRB5RCACHENAME="FILE:/path/to/tmp/service.ccache",
)
# optional: override settings (once per process)
overrides = {}
+1 -1
View File
@@ -469,7 +469,7 @@ class NameSpace(ReadOnly):
if isinstance(key, str):
return self.__map[key]
if type(key) in (int, slice):
return self.__members[key]
return self.__members[key] # pylint: disable=invalid-sequence-index
raise TypeError(
TYPE_ERROR % ('key', (str, int, slice, 'object with __name__'),
key, type(key))
+2 -14
View File
@@ -957,17 +957,6 @@ class IPACompleter(rlcompleter.Completer):
return super()._callable_postfix(val, word)
class InteractiveConsole(code.InteractiveConsole):
def showtraceback(self):
ei = sys.exc_info()
e = ei[1]
if isinstance(e, PublicError):
self.write('IPA public error exception: %s: %s\n' %
(e.__class__.__name__, str(e)))
else:
super().showtraceback()
class console(frontend.Command):
"""Start the IPA interactive Python console, or run a script.
@@ -1029,14 +1018,13 @@ class console(frontend.Command):
else:
if readline is not None:
self._setup_tab_completion(local)
cons = InteractiveConsole(local)
cons.interact(
code.interact(
"\n".join((
"(Custom IPA interactive Python console)",
" api: IPA API object",
" pp: pretty printer",
)),
exitmsg=None
local=local
)
Loaded 100 of 295 files, more files were not shown because too many files have changed in this diff. Show more