Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe005dd388 | ||
|
|
430054db41 | ||
|
|
e459e5b8bc | ||
|
|
f9075f9f77 | ||
|
|
b22605ee54 | ||
|
|
48cfe6848c | ||
|
|
fe223cde95 | ||
|
|
843f4a7458 | ||
|
|
1a2cd7f408 | ||
|
|
6aebfe74fb | ||
|
|
8b70ee1ea8 | ||
|
|
4af05dde48 | ||
|
|
496e3ace85 | ||
|
|
7ddf7711f3 | ||
|
|
32721c4132 | ||
|
|
f248b22ef4 | ||
|
|
dade02d5bb | ||
|
|
6aa3c3b628 | ||
|
|
f123b01d81 | ||
|
|
d355761f23 | ||
|
|
2bc247d831 | ||
|
|
953c7cc076 | ||
|
|
45fa43540f | ||
|
|
8f25b2a74a | ||
|
|
0654fb3737 | ||
|
|
317e7061d0 | ||
|
|
ed52142c40 | ||
|
|
8d081ce894 | ||
|
|
1251c15fae | ||
|
|
ef955c9015 | ||
|
|
d5ae5e1884 | ||
|
|
73c8aa4dc4 | ||
|
|
d98d5e4751 | ||
|
|
82b129fe76 | ||
|
|
33549183ef | ||
|
|
0f16b72bcb | ||
|
|
59e68f79e4 | ||
|
|
7796b7b958 | ||
|
|
a6f01115cf | ||
|
|
33c2740d82 | ||
|
|
6f5fe80de0 | ||
|
|
8e142bc1d4 | ||
|
|
a9ee2adec3 | ||
|
|
7233944e74 | ||
|
|
cfc4f47a10 | ||
|
|
8173e5df2d | ||
|
|
09497d2df0 | ||
|
|
bbb53a1271 | ||
|
|
e49ec1048d | ||
|
|
dea35922cd | ||
|
|
69e4397421 | ||
|
|
c84c59c66f | ||
|
|
089907b485 | ||
|
|
7c5ee21a18 | ||
|
|
fcad9c9aa7 | ||
|
|
a78c47b2d3 | ||
|
|
7517e2ce21 | ||
|
|
f57a7dbf50 | ||
|
|
d2ed490ff4 | ||
|
|
00c0a62a6a | ||
|
|
4a3e3efb84 | ||
|
|
7060e3a031 | ||
|
|
ce9346e74e | ||
|
|
8de6405b11 | ||
|
|
f1ed46eb93 | ||
|
|
6c84ae5c30 | ||
|
|
67a33e5a30 | ||
|
|
ac78a84fbe | ||
|
|
143c3eb161 | ||
|
|
d76f8fceda | ||
|
|
0472067ca6 | ||
|
|
ae6549ffae | ||
|
|
794b2c32f6 | ||
|
|
fa3a69f91f | ||
|
|
8a25020149 | ||
|
|
2a605c5d07 | ||
|
|
d7a27a24b9 | ||
|
|
c2bce952d8 | ||
|
|
1aea1cc29e | ||
|
|
107f5f2d81 | ||
|
|
3a706e8620 | ||
|
|
18bf495ce8 | ||
|
|
9cdf010ca6 | ||
|
|
d551e853fc | ||
|
|
03897d8a68 | ||
|
|
4ef8258d58 | ||
|
|
e00f457f75 | ||
|
|
105b03370c | ||
|
|
957d67aca5 | ||
|
|
e0acc51ff5 | ||
|
|
665227e437 | ||
|
|
e5c292cdad | ||
|
|
8d12d497f6 | ||
|
|
b252988da6 | ||
|
|
a02fd5305e | ||
|
|
62e28e4247 | ||
|
|
e7a69b3d9f | ||
|
|
9caea3205c | ||
|
|
31b70ee324 | ||
|
|
14526c50bb | ||
|
|
c0f71b0525 | ||
|
|
0075c8b8f6 | ||
|
|
9963dcdd5b | ||
|
|
b650783a18 | ||
|
|
c016e271b2 | ||
|
|
510f806a9f | ||
|
|
c58e483095 | ||
|
|
6f0da62f5a | ||
|
|
56e179748b | ||
|
|
d207f6bf32 | ||
|
|
f8580cae4b | ||
|
|
a7d90c1ef5 | ||
|
|
7911b2466d | ||
|
|
ae3c281a64 | ||
|
|
a21214cb9e | ||
|
|
4bd1be9e90 | ||
|
|
af569508c1 | ||
|
|
574517cb16 | ||
|
|
a213253bb1 | ||
|
|
a1ed0ff77e | ||
|
|
2be07242b7 | ||
|
|
359e1a3d95 | ||
|
|
8eeba00c4f | ||
|
|
545a363dd2 | ||
|
|
3f1b373cb2 | ||
|
|
9cd5f49c74 | ||
|
|
da65cc35bd | ||
|
|
7b0ad59fea | ||
|
|
479a24f285 | ||
|
|
eec46800d5 | ||
|
|
2eb4cdb641 | ||
|
|
72dccd8244 | ||
|
|
9e80616401 | ||
|
|
abf1dc557e | ||
|
|
72cc53a22e | ||
|
|
c8c05289f8 | ||
|
|
f66160fdc9 | ||
|
|
2c41b49bfc | ||
|
|
c7ef94c62f | ||
|
|
e0c4f83abd | ||
|
|
ef0ae496b7 | ||
|
|
cfc0233369 | ||
|
|
1f30cc6527 | ||
|
|
fd0fd487df | ||
|
|
dd22bd2528 | ||
|
|
a83ae63578 | ||
|
|
191880bc9f | ||
|
|
2b2f10c2eb | ||
|
|
ba845b237f | ||
|
|
4f9e6b1bed | ||
|
|
0d72a6cf5c | ||
|
|
903c8f9dcf | ||
|
|
3bba254ccd | ||
|
|
dc8590ef66 | ||
|
|
88d8534e49 | ||
|
|
0bf0b2d251 | ||
|
|
667b82a870 | ||
|
|
dd5b189a09 | ||
|
|
f78dc0b163 | ||
|
|
4239b77a6d | ||
|
|
b035ac8eb9 | ||
|
|
adc9609ff3 | ||
|
|
9b777390fb | ||
|
|
68c113f02b | ||
|
|
4119e4e799 | ||
|
|
5a0eed0b1a | ||
|
|
a59f6e00d9 | ||
|
|
c553e3ceb2 | ||
|
|
3721bca657 | ||
|
|
d32c640df0 | ||
|
|
07fe877525 | ||
|
|
05279ef447 | ||
|
|
1cca609857 | ||
|
|
3f9d9b2626 | ||
|
|
ebac8f6f9b | ||
|
|
779aa6bc11 | ||
|
|
4acd9fe9f7 | ||
|
|
35c36f9b4e | ||
|
|
5dba2aa466 | ||
|
|
2aeb963fc9 | ||
|
|
16b3977119 | ||
|
|
1420599165 | ||
|
|
02b0e46b7f | ||
|
|
074c2f5421 | ||
|
|
9ee16e8acc | ||
|
|
14a3d85a15 | ||
|
|
e76b219c21 | ||
|
|
50d40b5a9f | ||
|
|
6a809ff58f | ||
|
|
b0636c5408 | ||
|
|
64fa6b7241 | ||
|
|
8d634d8abf | ||
|
|
a7e13f9719 | ||
|
|
5c35405e78 | ||
|
|
8d92546447 | ||
|
|
828f6e7c92 | ||
|
|
0b762d2b2a | ||
|
|
0c32ebf858 | ||
|
|
c38546d085 | ||
|
|
724c8314b5 | ||
|
|
614d3bd9c0 | ||
|
|
a2667b249e | ||
|
|
53f7a44c5c | ||
|
|
414b5fe352 | ||
|
|
07927b21ba | ||
|
|
7d1d91fc86 | ||
|
|
78298fd4e1 | ||
|
|
5154f8e639 | ||
|
|
2996cc8eae | ||
|
|
6897ad9972 | ||
|
|
bf9797f27b | ||
|
|
a5c99a6b04 | ||
|
|
203b7d1cb5 | ||
|
|
5d9f59038d | ||
|
|
07975b52c3 | ||
|
|
295b4e23b4 | ||
|
|
6ab93f8be3 | ||
|
|
f44bde9e26 | ||
|
|
4eba0481ec | ||
|
|
1611d54549 | ||
|
|
ad05218450 | ||
|
|
36cba23f3f | ||
|
|
97330785ad | ||
|
|
5419864c7e | ||
|
|
691b5d21af | ||
|
|
b8480549c6 | ||
|
|
c523e85835 | ||
|
|
bf3083c376 | ||
|
|
24db4dc876 | ||
|
|
0e03315299 | ||
|
|
a8dd070992 | ||
|
|
4352bd5a50 | ||
|
|
ccdc94b0e1 | ||
|
|
deaec9b31a | ||
|
|
a1a3b90c48 | ||
|
|
fa4b054056 | ||
|
|
a4102b9960 | ||
|
|
416c210fc3 | ||
|
|
fdd3dd29b7 | ||
|
|
8fad897ee7 | ||
|
|
79153655d7 | ||
|
|
372a5dc6b8 | ||
|
|
6518855c34 | ||
|
|
8e7e48dc78 | ||
|
|
2268ef4e3c | ||
|
|
139038c58b | ||
|
|
18fd448156 | ||
|
|
0268857483 | ||
|
|
d6d8319ece | ||
|
|
8cd9ddfdeb | ||
|
|
be7f0a6e5e | ||
|
|
d1f1612088 | ||
|
|
2011d1a36a | ||
|
|
a9c1c81a46 | ||
|
|
12067297d8 | ||
|
|
cad06382a2 | ||
|
|
232b5a9dde | ||
|
|
25c00d0d40 | ||
|
|
be21cabad4 | ||
|
|
17a5d5bff1 | ||
|
|
6bd9d156e0 | ||
|
|
b8947b829b | ||
|
|
b0ba520860 | ||
|
|
6f3721a885 | ||
|
|
827dc9afc9 | ||
|
|
0a4506ba1b | ||
|
|
ab8b1fa6f5 | ||
|
|
bb74832f31 | ||
|
|
f43dab3b78 | ||
|
|
e1fd9ebb73 | ||
|
|
04aae0eecc | ||
|
|
35876b4e11 | ||
|
|
b39d8b9375 | ||
|
|
b928e5da5d | ||
|
|
673d2b82d0 | ||
|
|
3d6d7e9fdf | ||
|
|
29012bb374 | ||
|
|
5a23d8ec3f | ||
|
|
93548f2569 | ||
|
|
d9ecb12d57 | ||
|
|
dface55b1f | ||
|
|
a7b58b3c07 | ||
|
|
4a2c7b311b | ||
|
|
83161913fb | ||
|
|
4caa5ca577 | ||
|
|
988cb5a535 | ||
|
|
c6a16a7e53 | ||
|
|
dbebed2e3a | ||
|
|
f15da10454 | ||
|
|
746a036c7e | ||
|
|
b76bb195a5 | ||
|
|
21d99b457d | ||
|
|
d6a643b798 | ||
|
|
815f18396c | ||
|
|
38728dd518 | ||
|
|
c62e5d7a18 | ||
|
|
ce05e5fd40 | ||
|
|
0c67f0e607 | ||
|
|
e86807b58c | ||
|
|
a9018da90d | ||
|
|
c1582bd322 | ||
|
|
5e7590981b | ||
|
|
fbda6ea4d3 | ||
|
|
899530bd40 | ||
|
|
06780f4d90 | ||
|
|
715ee82e3c | ||
|
|
7b855c602e | ||
|
|
42f73ea655 | ||
|
|
22022ae2ff | ||
|
|
d33a2523ee | ||
|
|
0ce3ab36b4 | ||
|
|
d4fa80b224 | ||
|
|
147123e6b9 | ||
|
|
b381acb3d0 | ||
|
|
f0c26fe094 | ||
|
|
96cf293f1f | ||
|
|
4a4f7e76da | ||
|
|
43fcfe45f1 | ||
|
|
76152e0335 | ||
|
|
6e6a07188b | ||
|
|
a2a70ab7ac | ||
|
|
526b5165fe | ||
|
|
e9d5908851 | ||
|
|
2ee7fcdfba | ||
|
|
d12908ffce | ||
|
|
097615c34c | ||
|
|
e20e1a446c | ||
|
|
7a82bc090e | ||
|
|
1d1b31a2f4 | ||
|
|
b2cdddeaea | ||
|
|
ea95f0dda0 | ||
|
|
0f2d2d36ee | ||
|
|
6f3c9a2533 | ||
|
|
e92b847850 | ||
|
|
cd702b5421 | ||
|
|
ab652aa11a | ||
|
|
35f58c9af4 | ||
|
|
f680614b5c | ||
|
|
581dfddcf7 | ||
|
|
c7ba8f5f28 | ||
|
|
7fc89bc0ba | ||
|
|
cf338b5b35 | ||
|
|
8b1eb488bd | ||
|
|
386e51168a | ||
|
|
feb94b3aa5 | ||
|
|
e7623b4f5a | ||
|
|
e39ccf5988 | ||
|
|
fd985ae43a | ||
|
|
0ab3870229 | ||
|
|
706faddf24 | ||
|
|
dd345aaca8 | ||
|
|
31ba6aa500 | ||
|
|
b9f9462055 | ||
|
|
5cc8e5b869 | ||
|
|
a0e0d57a42 | ||
|
|
3c7fe6c49d | ||
|
|
4185578705 | ||
|
|
ac2c3de889 | ||
|
|
cca7a7cd77 | ||
|
|
dbec885cb0 | ||
|
|
55ef0008b8 | ||
|
|
a3b4b476b9 | ||
|
|
b326b4afae | ||
|
|
c74c701cac | ||
|
|
59db0faf21 | ||
|
|
f1b2d8ab36 | ||
|
|
9d9d925b14 | ||
|
|
7aeb9e5860 | ||
|
|
926680ffb2 | ||
|
|
04c2b06984 | ||
|
|
a4da017272 | ||
|
|
36591995ac | ||
|
|
94835d19b5 | ||
|
|
090d4f9e9d | ||
|
|
fa85301895 | ||
|
|
ad8f90f816 | ||
|
|
2ae316d430 | ||
|
|
06183a061a | ||
|
|
5a225deaa0 | ||
|
|
0468cc6085 | ||
|
|
c8955a4d0a | ||
|
|
b6587d3361 | ||
|
|
77803587d6 | ||
|
|
21091c2bc7 | ||
|
|
54d32fcd76 | ||
|
|
45b351f8c5 | ||
|
|
8a415ff985 | ||
|
|
4ae9c78f59 | ||
|
|
ccb012b402 | ||
|
|
42b2607a6f | ||
|
|
6033d495d1 | ||
|
|
bf4c51266c | ||
|
|
8297b74974 | ||
|
|
e3e7c98ac5 | ||
|
|
4105fee2cf | ||
|
|
fc5de8216d | ||
|
|
e9b232fcf4 | ||
|
|
8542fd3012 | ||
|
|
dd094e3889 | ||
|
|
0e8bde3175 | ||
|
|
3237ade3d2 | ||
|
|
dc73813b8a | ||
|
|
436c9d85ee | ||
|
|
e8d34361c7 | ||
|
|
f8da5bfbea | ||
|
|
cb0ce1bd8b | ||
|
|
7a40948d6e | ||
|
|
03e9139504 | ||
|
|
2e11247cde | ||
|
|
22d1392a8a | ||
|
|
52782b55f5 | ||
|
|
9819058d73 |
No files matched your search
@@ -155,6 +155,7 @@ install/custodia/ipa-custodia-dmldap
|
|||||||
install/custodia/ipa-custodia-pki-tomcat
|
install/custodia/ipa-custodia-pki-tomcat
|
||||||
install/custodia/ipa-custodia-pki-tomcat-wrapped
|
install/custodia/ipa-custodia-pki-tomcat-wrapped
|
||||||
install/custodia/ipa-custodia-ra-agent
|
install/custodia/ipa-custodia-ra-agent
|
||||||
|
install/oddjob/org.freeipa.server.config-enable-sid
|
||||||
install/oddjob/org.freeipa.server.trust-enable-agent
|
install/oddjob/org.freeipa.server.trust-enable-agent
|
||||||
install/oddjob/com.redhat.idm.trust-fetch-domains
|
install/oddjob/com.redhat.idm.trust-fetch-domains
|
||||||
install/oddjob/etc/oddjobd.conf.d/ipa-server.conf
|
install/oddjob/etc/oddjobd.conf.d/ipa-server.conf
|
||||||
|
|||||||
@@ -10,6 +10,5 @@ ipaserver == @VERSION@
|
|||||||
ipatests == @VERSION@
|
ipatests == @VERSION@
|
||||||
|
|
||||||
# keep pylint version in sync with current Fedora release
|
# keep pylint version in sync with current Fedora release
|
||||||
# F36 has 2.12.2
|
# F37 has 2.15.5
|
||||||
# https://pagure.io/freeipa/issue/8818 added pylint 2.8 support
|
pylint ~= 2.15.5
|
||||||
pylint ~= 2.12.2
|
|
||||||
@@ -153,6 +153,8 @@ aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;read_keys
|
|||||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "krbcanonicalname || krbprincipalname")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Principals";allow (write) groupdn = "ldap:///cn=System: Manage Host Principals,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "krbcanonicalname || krbprincipalname")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Principals";allow (write) groupdn = "ldap:///cn=System: Manage Host Principals,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||||
|
aci: (targetattr = "memberprincipal || objectclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Resource Delegation";allow (delete,write) groupdn = "ldap:///cn=System: Manage Host Resource Delegation,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
|
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "ipasshpubkey")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host SSH Public Keys";allow (write) groupdn = "ldap:///cn=System: Manage Host SSH Public Keys,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "ipasshpubkey")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host SSH Public Keys";allow (write) groupdn = "ldap:///cn=System: Manage Host SSH Public Keys,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "description || ipaassignedidview || krbprincipalauthind || l || macaddress || nshardwareplatform || nshostlocation || nsosversion || userclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Modify Hosts";allow (write) groupdn = "ldap:///cn=System: Modify Hosts,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "description || ipaassignedidview || krbprincipalauthind || l || macaddress || nshardwareplatform || nshostlocation || nsosversion || userclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Modify Hosts";allow (write) groupdn = "ldap:///cn=System: Modify Hosts,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
@@ -161,7 +163,7 @@ aci: (targetattr = "cn || createtimestamp || entryusn || macaddress || modifytim
|
|||||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "memberof")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Read Host Membership";allow (compare,read,search) userdn = "ldap:///all";)
|
aci: (targetattr = "memberof")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Read Host Membership";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "cn || createtimestamp || description || enrolledby || entryusn || fqdn || ipaassignedidview || ipaclientversion || ipakrbauthzdata || ipasshpubkey || ipauniqueid || krbcanonicalname || krblastpwdchange || krbpasswordexpiration || krbprincipalaliases || krbprincipalauthind || krbprincipalexpiration || krbprincipalname || l || macaddress || managedby || modifytimestamp || nshardwareplatform || nshostlocation || nsosversion || objectclass || serverhostname || usercertificate || userclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Read Hosts";allow (compare,read,search) userdn = "ldap:///all";)
|
aci: (targetattr = "cn || createtimestamp || description || enrolledby || entryusn || fqdn || ipaassignedidview || ipaclientversion || ipakrbauthzdata || ipasshpubkey || ipauniqueid || krbcanonicalname || krblastpwdchange || krbpasswordexpiration || krbprincipalaliases || krbprincipalauthind || krbprincipalexpiration || krbprincipalname || l || macaddress || managedby || memberprincipal || modifytimestamp || nshardwareplatform || nshostlocation || nsosversion || objectclass || serverhostname || usercertificate || userclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Read Hosts";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Remove Hosts";allow (delete) groupdn = "ldap:///cn=System: Remove Hosts,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Remove Hosts";allow (delete) groupdn = "ldap:///cn=System: Remove Hosts,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=hostgroups,cn=accounts,dc=ipa,dc=example
|
dn: cn=hostgroups,cn=accounts,dc=ipa,dc=example
|
||||||
@@ -222,6 +224,10 @@ dn: cn=ng,cn=alt,dc=ipa,dc=example
|
|||||||
aci: (targetfilter = "(objectclass=ipanisnetgroup)")(version 3.0;acl "permission:System: Remove Netgroups";allow (delete) groupdn = "ldap:///cn=System: Remove Netgroups,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetfilter = "(objectclass=ipanisnetgroup)")(version 3.0;acl "permission:System: Remove Netgroups";allow (delete) groupdn = "ldap:///cn=System: Remove Netgroups,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=otp,cn=etc,dc=ipa,dc=example
|
dn: cn=otp,cn=etc,dc=ipa,dc=example
|
||||||
aci: (targetattr = "cn || ipatokenhotpauthwindow || ipatokenhotpsyncwindow || ipatokentotpauthwindow || ipatokentotpsyncwindow")(targetfilter = "(objectclass=ipatokenotpconfig)")(version 3.0;acl "permission:System: Read OTP Configuration";allow (compare,read,search) userdn = "ldap:///all";)
|
aci: (targetattr = "cn || ipatokenhotpauthwindow || ipatokenhotpsyncwindow || ipatokentotpauthwindow || ipatokentotpsyncwindow")(targetfilter = "(objectclass=ipatokenotpconfig)")(version 3.0;acl "permission:System: Read OTP Configuration";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
|
dn: cn=passkeyconfig,cn=etc,dc=ipa,dc=example
|
||||||
|
aci: (targetattr = "iparequireuserverification")(targetfilter = "(objectclass=ipapasskeyconfigobject)")(version 3.0;acl "permission:System: Modify Passkey Configuration";allow (write) groupdn = "ldap:///cn=System: Modify Passkey Configuration,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
|
dn: cn=passkeyconfig,cn=etc,dc=ipa,dc=example
|
||||||
|
aci: (targetattr = "cn || iparequireuserverification")(targetfilter = "(objectclass=ipapasskeyconfigobject)")(version 3.0;acl "permission:System: Read Passkey Configuration";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
dn: cn=permissions,cn=pbac,dc=ipa,dc=example
|
dn: cn=permissions,cn=pbac,dc=ipa,dc=example
|
||||||
aci: (targetattr = "member")(targetfilter = "(objectclass=ipapermission)")(version 3.0;acl "permission:System: Modify Privilege Membership";allow (write) groupdn = "ldap:///cn=System: Modify Privilege Membership,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "member")(targetfilter = "(objectclass=ipapermission)")(version 3.0;acl "permission:System: Modify Privilege Membership";allow (write) groupdn = "ldap:///cn=System: Modify Privilege Membership,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: dc=ipa,dc=example
|
dn: dc=ipa,dc=example
|
||||||
@@ -281,11 +287,15 @@ aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;read_keys
|
|||||||
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "krbcanonicalname || krbprincipalname")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Manage Service Principals";allow (write) groupdn = "ldap:///cn=System: Manage Service Principals,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "krbcanonicalname || krbprincipalname")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Manage Service Principals";allow (write) groupdn = "ldap:///cn=System: Manage Service Principals,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
||||||
|
aci: (targetattr = "memberprincipal || objectclass")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Manage Service Resource Delegation";allow (delete,write) groupdn = "ldap:///cn=System: Manage Service Resource Delegation,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
|
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
||||||
|
aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;write_delegation || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Manage Service Resource Delegation Permissions";allow (compare,read,search,write) groupdn = "ldap:///cn=System: Manage Service Resource Delegation Permissions,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
|
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "krbprincipalauthind || usercertificate")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Modify Services";allow (write) groupdn = "ldap:///cn=System: Modify Services,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "krbprincipalauthind || usercertificate")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Modify Services";allow (write) groupdn = "ldap:///cn=System: Modify Services,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || ipantsecurityidentifier || loginshell || modifytimestamp || objectclass || uid || uidnumber")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Read POSIX details of SMB services";allow (compare,read,search) userdn = "ldap:///all";)
|
aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || ipantsecurityidentifier || loginshell || modifytimestamp || objectclass || uid || uidnumber")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Read POSIX details of SMB services";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "createtimestamp || entryusn || ipakrbauthzdata || ipakrbprincipalalias || ipauniqueid || krbcanonicalname || krblastpwdchange || krbobjectreferences || krbpasswordexpiration || krbprincipalaliases || krbprincipalauthind || krbprincipalexpiration || krbprincipalname || managedby || memberof || modifytimestamp || objectclass || usercertificate")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Read Services";allow (compare,read,search) userdn = "ldap:///all";)
|
aci: (targetattr = "createtimestamp || entryusn || ipakrbauthzdata || ipakrbprincipalalias || ipauniqueid || krbcanonicalname || krblastpwdchange || krbobjectreferences || krbpasswordexpiration || krbprincipalaliases || krbprincipalauthind || krbprincipalexpiration || krbprincipalname || managedby || memberof || memberprincipal || modifytimestamp || objectclass || usercertificate")(targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Read Services";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
dn: cn=services,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Remove Services";allow (delete) groupdn = "ldap:///cn=System: Remove Services,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetfilter = "(objectclass=ipaservice)")(version 3.0;acl "permission:System: Remove Services";allow (delete) groupdn = "ldap:///cn=System: Remove Services,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=s4u2proxy,cn=etc,dc=ipa,dc=example
|
dn: cn=s4u2proxy,cn=etc,dc=ipa,dc=example
|
||||||
@@ -377,6 +387,8 @@ aci: (targetattr = "krbpasswordexpiration || krbprincipalkey || passwordhistory
|
|||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "krbpasswordexpiration || krbprincipalkey || passwordhistory || sambalmpassword || sambantpassword || userpassword")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Change User password";allow (write) groupdn = "ldap:///cn=System: Change User password,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "krbpasswordexpiration || krbprincipalkey || passwordhistory || sambalmpassword || sambantpassword || userpassword")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Change User password";allow (write) groupdn = "ldap:///cn=System: Change User password,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
|
aci: (targetattr = "ipapasskey || objectclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage Passkey Mappings";allow (write) groupdn = "ldap:///cn=System: Manage Passkey Mappings,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "ipacertmapdata || objectclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User Certificate Mappings";allow (write) groupdn = "ldap:///cn=System: Manage User Certificate Mappings,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "ipacertmapdata || objectclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User Certificate Mappings";allow (write) groupdn = "ldap:///cn=System: Manage User Certificate Mappings,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "usercertificate")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Manage User Certificates";allow (write) groupdn = "ldap:///cn=System: Manage User Certificates,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "usercertificate")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Manage User Certificates";allow (write) groupdn = "ldap:///cn=System: Manage User Certificates,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
@@ -393,7 +405,7 @@ aci: (targetattr = "audio || businesscategory || carlicense || departmentnumber
|
|||||||
dn: dc=ipa,dc=example
|
dn: dc=ipa,dc=example
|
||||||
aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || loginshell || modifytimestamp || objectclass || uid || uidnumber")(target = "ldap:///cn=users,cn=compat,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read User Compat Tree";allow (compare,read,search) userdn = "ldap:///anyone";)
|
aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || loginshell || modifytimestamp || objectclass || uid || uidnumber")(target = "ldap:///cn=users,cn=compat,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read User Compat Tree";allow (compare,read,search) userdn = "ldap:///anyone";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "ipasshpubkey || ipauniqueid || ipauserauthtype || userclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User IPA Attributes";allow (compare,read,search) userdn = "ldap:///all";)
|
aci: (targetattr = "ipapasskey || ipasshpubkey || ipauniqueid || ipauserauthtype || userclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User IPA Attributes";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "krbcanonicalname || krblastpwdchange || krbpasswordexpiration || krbprincipalaliases || krbprincipalexpiration || krbprincipalname || krbprincipaltype || nsaccountlock")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Kerberos Attributes";allow (compare,read,search) userdn = "ldap:///all";)
|
aci: (targetattr = "krbcanonicalname || krblastpwdchange || krbpasswordexpiration || krbprincipalaliases || krbprincipalexpiration || krbprincipalname || krbprincipaltype || nsaccountlock")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Kerberos Attributes";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
|
|||||||
@@ -1099,7 +1099,7 @@ option: Int('ipasearchrecordslimit?', autofill=False, cli_name='searchrecordslim
|
|||||||
option: Int('ipasearchtimelimit?', autofill=False, cli_name='searchtimelimit')
|
option: Int('ipasearchtimelimit?', autofill=False, cli_name='searchtimelimit')
|
||||||
option: Str('ipaselinuxusermapdefault?', autofill=False)
|
option: Str('ipaselinuxusermapdefault?', autofill=False)
|
||||||
option: Str('ipaselinuxusermaporder?', autofill=False)
|
option: Str('ipaselinuxusermaporder?', autofill=False)
|
||||||
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'disabled'])
|
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey', u'disabled'])
|
||||||
option: Bool('ipauserdefaultsubordinateid?', autofill=False, cli_name='user_default_subid')
|
option: Bool('ipauserdefaultsubordinateid?', autofill=False, cli_name='user_default_subid')
|
||||||
option: Str('ipauserobjectclasses*', autofill=False, cli_name='userobjectclasses')
|
option: Str('ipauserobjectclasses*', autofill=False, cli_name='userobjectclasses')
|
||||||
option: IA5Str('ipausersearchfields?', autofill=False, cli_name='usersearch')
|
option: IA5Str('ipausersearchfields?', autofill=False, cli_name='usersearch')
|
||||||
@@ -1798,7 +1798,7 @@ option: DNSNameParam('idnssoamname?', cli_name='name_server')
|
|||||||
option: Int('idnssoarefresh', autofill=True, cli_name='refresh', default=3600)
|
option: Int('idnssoarefresh', autofill=True, cli_name='refresh', default=3600)
|
||||||
option: Int('idnssoaretry', autofill=True, cli_name='retry', default=900)
|
option: Int('idnssoaretry', autofill=True, cli_name='retry', default=900)
|
||||||
option: DNSNameParam('idnssoarname', autofill=True, cli_name='admin_email', default=<DNS name hostmaster>)
|
option: DNSNameParam('idnssoarname', autofill=True, cli_name='admin_email', default=<DNS name hostmaster>)
|
||||||
option: Int('idnssoaserial', autofill=True, cli_name='serial')
|
option: Int('idnssoaserial?', cli_name='serial', deprecated=True)
|
||||||
option: Str('idnsupdatepolicy?', autofill=True, cli_name='update_policy')
|
option: Str('idnsupdatepolicy?', autofill=True, cli_name='update_policy')
|
||||||
option: Str('ip_address?')
|
option: Str('ip_address?')
|
||||||
option: Str('name_from_ip?')
|
option: Str('name_from_ip?')
|
||||||
@@ -1862,7 +1862,7 @@ option: DNSNameParam('idnssoamname?', autofill=False, cli_name='name_server')
|
|||||||
option: Int('idnssoarefresh?', autofill=False, cli_name='refresh', default=3600)
|
option: Int('idnssoarefresh?', autofill=False, cli_name='refresh', default=3600)
|
||||||
option: Int('idnssoaretry?', autofill=False, cli_name='retry', default=900)
|
option: Int('idnssoaretry?', autofill=False, cli_name='retry', default=900)
|
||||||
option: DNSNameParam('idnssoarname?', autofill=False, cli_name='admin_email', default=<DNS name hostmaster>)
|
option: DNSNameParam('idnssoarname?', autofill=False, cli_name='admin_email', default=<DNS name hostmaster>)
|
||||||
option: Int('idnssoaserial?', autofill=False, cli_name='serial')
|
option: Int('idnssoaserial?', autofill=False, cli_name='serial', deprecated=True)
|
||||||
option: Str('idnsupdatepolicy?', autofill=False, cli_name='update_policy')
|
option: Str('idnsupdatepolicy?', autofill=False, cli_name='update_policy')
|
||||||
option: Bool('idnszoneactive?', autofill=False, cli_name='zone_active')
|
option: Bool('idnszoneactive?', autofill=False, cli_name='zone_active')
|
||||||
option: Str('name_from_ip?', autofill=False)
|
option: Str('name_from_ip?', autofill=False)
|
||||||
@@ -1899,7 +1899,7 @@ option: DNSNameParam('idnssoamname?', autofill=False, cli_name='name_server')
|
|||||||
option: Int('idnssoarefresh?', autofill=False, cli_name='refresh', default=3600)
|
option: Int('idnssoarefresh?', autofill=False, cli_name='refresh', default=3600)
|
||||||
option: Int('idnssoaretry?', autofill=False, cli_name='retry', default=900)
|
option: Int('idnssoaretry?', autofill=False, cli_name='retry', default=900)
|
||||||
option: DNSNameParam('idnssoarname?', autofill=False, cli_name='admin_email', default=<DNS name hostmaster>)
|
option: DNSNameParam('idnssoarname?', autofill=False, cli_name='admin_email', default=<DNS name hostmaster>)
|
||||||
option: Int('idnssoaserial?', autofill=False, cli_name='serial')
|
option: Int('idnssoaserial?', autofill=False, cli_name='serial', deprecated=True)
|
||||||
option: Str('idnsupdatepolicy?', autofill=False, cli_name='update_policy')
|
option: Str('idnsupdatepolicy?', autofill=False, cli_name='update_policy')
|
||||||
option: Str('name_from_ip?', autofill=False)
|
option: Str('name_from_ip?', autofill=False)
|
||||||
option: Str('nsec3paramrecord?', autofill=False, cli_name='nsec3param_rec')
|
option: Str('nsec3paramrecord?', autofill=False, cli_name='nsec3param_rec')
|
||||||
@@ -2478,7 +2478,7 @@ option: Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate')
|
|||||||
option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate')
|
option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate')
|
||||||
option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth')
|
option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth')
|
||||||
option: Str('ipasshpubkey*', cli_name='sshpubkey')
|
option: Str('ipasshpubkey*', cli_name='sshpubkey')
|
||||||
option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: Str('l?', cli_name='locality')
|
option: Str('l?', cli_name='locality')
|
||||||
option: Str('macaddress*')
|
option: Str('macaddress*')
|
||||||
option: Flag('no_members', autofill=True, default=False)
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
@@ -2507,6 +2507,17 @@ option: Str('version?')
|
|||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
|
command: host_add_delegation/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('fqdn', cli_name='hostname')
|
||||||
|
arg: Str('memberprincipal+', alwaysask=True, cli_name='principal')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: host_add_managedby/1
|
command: host_add_managedby/1
|
||||||
args: 1,5,3
|
args: 1,5,3
|
||||||
arg: Str('fqdn', cli_name='hostname')
|
arg: Str('fqdn', cli_name='hostname')
|
||||||
@@ -2529,6 +2540,20 @@ option: Str('version?')
|
|||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
|
command: host_allow_add_delegation/1
|
||||||
|
args: 1,8,3
|
||||||
|
arg: Str('fqdn', cli_name='hostname')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Str('group*', alwaysask=True, cli_name='groups')
|
||||||
|
option: Str('host*', alwaysask=True, cli_name='hosts')
|
||||||
|
option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups')
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('user*', alwaysask=True, cli_name='users')
|
||||||
|
option: Str('version?')
|
||||||
|
output: Output('completed', type=[<type 'int'>])
|
||||||
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
|
output: Entry('result')
|
||||||
command: host_allow_create_keytab/1
|
command: host_allow_create_keytab/1
|
||||||
args: 1,8,3
|
args: 1,8,3
|
||||||
arg: Str('fqdn', cli_name='hostname')
|
arg: Str('fqdn', cli_name='hostname')
|
||||||
@@ -2573,6 +2598,20 @@ option: Str('version?')
|
|||||||
output: Output('result', type=[<type 'bool'>])
|
output: Output('result', type=[<type 'bool'>])
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
|
command: host_disallow_add_delegation/1
|
||||||
|
args: 1,8,3
|
||||||
|
arg: Str('fqdn', cli_name='hostname')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Str('group*', alwaysask=True, cli_name='groups')
|
||||||
|
option: Str('host*', alwaysask=True, cli_name='hosts')
|
||||||
|
option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups')
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('user*', alwaysask=True, cli_name='users')
|
||||||
|
option: Str('version?')
|
||||||
|
output: Output('completed', type=[<type 'int'>])
|
||||||
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
|
output: Entry('result')
|
||||||
command: host_disallow_create_keytab/1
|
command: host_disallow_create_keytab/1
|
||||||
args: 1,8,3
|
args: 1,8,3
|
||||||
arg: Str('fqdn', cli_name='hostname')
|
arg: Str('fqdn', cli_name='hostname')
|
||||||
@@ -2614,7 +2653,7 @@ option: Str('in_netgroup*', cli_name='in_netgroups')
|
|||||||
option: Str('in_role*', cli_name='in_roles')
|
option: Str('in_role*', cli_name='in_roles')
|
||||||
option: Str('in_sudorule*', cli_name='in_sudorules')
|
option: Str('in_sudorule*', cli_name='in_sudorules')
|
||||||
option: Str('ipaassignedidview?', autofill=False)
|
option: Str('ipaassignedidview?', autofill=False)
|
||||||
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: Str('l?', autofill=False, cli_name='locality')
|
option: Str('l?', autofill=False, cli_name='locality')
|
||||||
option: Str('macaddress*', autofill=False)
|
option: Str('macaddress*', autofill=False)
|
||||||
option: Str('man_by_host*', cli_name='man_by_hosts')
|
option: Str('man_by_host*', cli_name='man_by_hosts')
|
||||||
@@ -2654,7 +2693,7 @@ option: Bool('ipakrbokasdelegate?', autofill=False, cli_name='ok_as_delegate')
|
|||||||
option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate')
|
option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate')
|
||||||
option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth')
|
option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth')
|
||||||
option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey')
|
option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey')
|
||||||
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: Principal('krbprincipalname*', autofill=False)
|
option: Principal('krbprincipalname*', autofill=False)
|
||||||
option: Str('l?', autofill=False, cli_name='locality')
|
option: Str('l?', autofill=False, cli_name='locality')
|
||||||
option: Str('macaddress*', autofill=False)
|
option: Str('macaddress*', autofill=False)
|
||||||
@@ -2685,6 +2724,17 @@ option: Str('version?')
|
|||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
|
command: host_remove_delegation/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('fqdn', cli_name='hostname')
|
||||||
|
arg: Str('memberprincipal+', alwaysask=True, cli_name='principal')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: host_remove_managedby/1
|
command: host_remove_managedby/1
|
||||||
args: 1,5,3
|
args: 1,5,3
|
||||||
arg: Str('fqdn', cli_name='hostname')
|
arg: Str('fqdn', cli_name='hostname')
|
||||||
@@ -3327,7 +3377,7 @@ output: Output('result', type=[<type 'bool'>])
|
|||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
command: krbtpolicy_mod/1
|
command: krbtpolicy_mod/1
|
||||||
args: 1,19,3
|
args: 1,21,3
|
||||||
arg: Str('uid?', cli_name='user')
|
arg: Str('uid?', cli_name='user')
|
||||||
option: Str('addattr*', cli_name='addattr')
|
option: Str('addattr*', cli_name='addattr')
|
||||||
option: Flag('all', autofill=True, cli_name='all', default=False)
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
@@ -3335,11 +3385,13 @@ option: Str('delattr*', cli_name='delattr')
|
|||||||
option: Int('krbauthindmaxrenewableage_hardened?', autofill=False, cli_name='hardened_maxrenew')
|
option: Int('krbauthindmaxrenewableage_hardened?', autofill=False, cli_name='hardened_maxrenew')
|
||||||
option: Int('krbauthindmaxrenewableage_idp?', autofill=False, cli_name='idp_maxrenew')
|
option: Int('krbauthindmaxrenewableage_idp?', autofill=False, cli_name='idp_maxrenew')
|
||||||
option: Int('krbauthindmaxrenewableage_otp?', autofill=False, cli_name='otp_maxrenew')
|
option: Int('krbauthindmaxrenewableage_otp?', autofill=False, cli_name='otp_maxrenew')
|
||||||
|
option: Int('krbauthindmaxrenewableage_passkey?', autofill=False, cli_name='passkey_maxrenew')
|
||||||
option: Int('krbauthindmaxrenewableage_pkinit?', autofill=False, cli_name='pkinit_maxrenew')
|
option: Int('krbauthindmaxrenewableage_pkinit?', autofill=False, cli_name='pkinit_maxrenew')
|
||||||
option: Int('krbauthindmaxrenewableage_radius?', autofill=False, cli_name='radius_maxrenew')
|
option: Int('krbauthindmaxrenewableage_radius?', autofill=False, cli_name='radius_maxrenew')
|
||||||
option: Int('krbauthindmaxticketlife_hardened?', autofill=False, cli_name='hardened_maxlife')
|
option: Int('krbauthindmaxticketlife_hardened?', autofill=False, cli_name='hardened_maxlife')
|
||||||
option: Int('krbauthindmaxticketlife_idp?', autofill=False, cli_name='idp_maxlife')
|
option: Int('krbauthindmaxticketlife_idp?', autofill=False, cli_name='idp_maxlife')
|
||||||
option: Int('krbauthindmaxticketlife_otp?', autofill=False, cli_name='otp_maxlife')
|
option: Int('krbauthindmaxticketlife_otp?', autofill=False, cli_name='otp_maxlife')
|
||||||
|
option: Int('krbauthindmaxticketlife_passkey?', autofill=False, cli_name='passkey_maxlife')
|
||||||
option: Int('krbauthindmaxticketlife_pkinit?', autofill=False, cli_name='pkinit_maxlife')
|
option: Int('krbauthindmaxticketlife_pkinit?', autofill=False, cli_name='pkinit_maxlife')
|
||||||
option: Int('krbauthindmaxticketlife_radius?', autofill=False, cli_name='radius_maxlife')
|
option: Int('krbauthindmaxticketlife_radius?', autofill=False, cli_name='radius_maxlife')
|
||||||
option: Int('krbmaxrenewableage?', autofill=False, cli_name='maxrenew')
|
option: Int('krbmaxrenewableage?', autofill=False, cli_name='maxrenew')
|
||||||
@@ -3769,6 +3821,28 @@ option: Str('version?')
|
|||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
|
command: passkeyconfig_mod/1
|
||||||
|
args: 0,8,3
|
||||||
|
option: Str('addattr*', cli_name='addattr')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Str('delattr*', cli_name='delattr')
|
||||||
|
option: Bool('iparequireuserverification?', autofill=False, cli_name='require_user_verification')
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Flag('rights', autofill=True, default=False)
|
||||||
|
option: Str('setattr*', cli_name='setattr')
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
|
command: passkeyconfig_show/1
|
||||||
|
args: 0,4,3
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Flag('rights', autofill=True, default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: passwd/1
|
command: passwd/1
|
||||||
args: 3,2,3
|
args: 3,2,3
|
||||||
arg: Principal('principal', autofill=True, cli_name='user')
|
arg: Principal('principal', autofill=True, cli_name='user')
|
||||||
@@ -4076,7 +4150,7 @@ option: Int('krbpwdlockoutduration?', cli_name='lockouttime')
|
|||||||
option: Int('krbpwdmaxfailure?', cli_name='maxfail')
|
option: Int('krbpwdmaxfailure?', cli_name='maxfail')
|
||||||
option: Int('krbpwdmindiffchars?', cli_name='minclasses')
|
option: Int('krbpwdmindiffchars?', cli_name='minclasses')
|
||||||
option: Int('krbpwdminlength?', cli_name='minlength')
|
option: Int('krbpwdminlength?', cli_name='minlength')
|
||||||
option: Int('passwordgracelimit?', cli_name='gracelimit', default=-1)
|
option: Int('passwordgracelimit?', autofill=True, cli_name='gracelimit', default=-1)
|
||||||
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
option: Str('setattr*', cli_name='setattr')
|
option: Str('setattr*', cli_name='setattr')
|
||||||
option: Str('version?')
|
option: Str('version?')
|
||||||
@@ -4684,7 +4758,7 @@ option: StrEnum('ipakrbauthzdata*', cli_name='pac_type', values=[u'MS-PAC', u'PA
|
|||||||
option: Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate')
|
option: Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate')
|
||||||
option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate')
|
option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate')
|
||||||
option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth')
|
option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth')
|
||||||
option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: Flag('no_members', autofill=True, default=False)
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
option: Str('setattr*', cli_name='setattr')
|
option: Str('setattr*', cli_name='setattr')
|
||||||
@@ -4705,6 +4779,17 @@ option: Str('version?')
|
|||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
|
command: service_add_delegation/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
||||||
|
arg: Str('memberprincipal+', alwaysask=True, cli_name='principal')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: service_add_host/1
|
command: service_add_host/1
|
||||||
args: 1,5,3
|
args: 1,5,3
|
||||||
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
||||||
@@ -4743,6 +4828,20 @@ option: Str('version?')
|
|||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
|
command: service_allow_add_delegation/1
|
||||||
|
args: 1,8,3
|
||||||
|
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Str('group*', alwaysask=True, cli_name='groups')
|
||||||
|
option: Str('host*', alwaysask=True, cli_name='hosts')
|
||||||
|
option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups')
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('user*', alwaysask=True, cli_name='users')
|
||||||
|
option: Str('version?')
|
||||||
|
output: Output('completed', type=[<type 'int'>])
|
||||||
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
|
output: Entry('result')
|
||||||
command: service_allow_create_keytab/1
|
command: service_allow_create_keytab/1
|
||||||
args: 1,8,3
|
args: 1,8,3
|
||||||
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
||||||
@@ -4786,6 +4885,20 @@ option: Str('version?')
|
|||||||
output: Output('result', type=[<type 'bool'>])
|
output: Output('result', type=[<type 'bool'>])
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
|
command: service_disallow_add_delegation/1
|
||||||
|
args: 1,8,3
|
||||||
|
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Str('group*', alwaysask=True, cli_name='groups')
|
||||||
|
option: Str('host*', alwaysask=True, cli_name='hosts')
|
||||||
|
option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups')
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('user*', alwaysask=True, cli_name='users')
|
||||||
|
option: Str('version?')
|
||||||
|
output: Output('completed', type=[<type 'int'>])
|
||||||
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
|
output: Entry('result')
|
||||||
command: service_disallow_create_keytab/1
|
command: service_disallow_create_keytab/1
|
||||||
args: 1,8,3
|
args: 1,8,3
|
||||||
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
||||||
@@ -4820,7 +4933,7 @@ arg: Str('criteria?')
|
|||||||
option: Flag('all', autofill=True, cli_name='all', default=False)
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values=[u'MS-PAC', u'PAD', u'NONE'])
|
option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values=[u'MS-PAC', u'PAD', u'NONE'])
|
||||||
option: Principal('krbcanonicalname?', autofill=False, cli_name='canonical_principal')
|
option: Principal('krbcanonicalname?', autofill=False, cli_name='canonical_principal')
|
||||||
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
||||||
option: Str('man_by_host*', cli_name='man_by_hosts')
|
option: Str('man_by_host*', cli_name='man_by_hosts')
|
||||||
option: Flag('no_members', autofill=True, default=True)
|
option: Flag('no_members', autofill=True, default=True)
|
||||||
@@ -4844,7 +4957,7 @@ option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values=
|
|||||||
option: Bool('ipakrbokasdelegate?', autofill=False, cli_name='ok_as_delegate')
|
option: Bool('ipakrbokasdelegate?', autofill=False, cli_name='ok_as_delegate')
|
||||||
option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate')
|
option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate')
|
||||||
option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth')
|
option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth')
|
||||||
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
||||||
option: Flag('no_members', autofill=True, default=False)
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
@@ -4866,6 +4979,17 @@ option: Str('version?')
|
|||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
|
command: service_remove_delegation/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
||||||
|
arg: Str('memberprincipal+', alwaysask=True, cli_name='principal')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: service_remove_host/1
|
command: service_remove_host/1
|
||||||
args: 1,5,3
|
args: 1,5,3
|
||||||
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
|
||||||
@@ -5094,7 +5218,7 @@ option: Str('ipaidpsub?', cli_name='idp_user_id')
|
|||||||
option: Str('ipasshpubkey*', cli_name='sshpubkey')
|
option: Str('ipasshpubkey*', cli_name='sshpubkey')
|
||||||
option: Str('ipatokenradiusconfiglink?', cli_name='radius')
|
option: Str('ipatokenradiusconfiglink?', cli_name='radius')
|
||||||
option: Str('ipatokenradiususername?', cli_name='radius_username')
|
option: Str('ipatokenradiususername?', cli_name='radius_username')
|
||||||
option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: DateTime('krbpasswordexpiration?', cli_name='password_expiration')
|
option: DateTime('krbpasswordexpiration?', cli_name='password_expiration')
|
||||||
option: DateTime('krbprincipalexpiration?', cli_name='principal_expiration')
|
option: DateTime('krbprincipalexpiration?', cli_name='principal_expiration')
|
||||||
option: Principal('krbprincipalname*', autofill=True, cli_name='principal')
|
option: Principal('krbprincipalname*', autofill=True, cli_name='principal')
|
||||||
@@ -5160,6 +5284,17 @@ option: Str('version?')
|
|||||||
output: Output('completed', type=[<type 'int'>])
|
output: Output('completed', type=[<type 'int'>])
|
||||||
output: Output('failed', type=[<type 'dict'>])
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
|
command: stageuser_add_passkey/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('uid', cli_name='login')
|
||||||
|
arg: Str('ipapasskey+', alwaysask=True, cli_name='passkey')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: stageuser_add_principal/1
|
command: stageuser_add_principal/1
|
||||||
args: 2,4,3
|
args: 2,4,3
|
||||||
arg: Str('uid', cli_name='login')
|
arg: Str('uid', cli_name='login')
|
||||||
@@ -5209,7 +5344,7 @@ option: Str('ipantlogonscript?', autofill=False, cli_name='smb_logon_script')
|
|||||||
option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
|
option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
|
||||||
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
|
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
|
||||||
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
|
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
|
||||||
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
|
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
|
||||||
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
|
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
|
||||||
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
||||||
@@ -5275,7 +5410,7 @@ option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
|
|||||||
option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey')
|
option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey')
|
||||||
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
|
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
|
||||||
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
|
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
|
||||||
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
|
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
|
||||||
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
|
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
|
||||||
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
||||||
@@ -5343,6 +5478,17 @@ option: Str('version?')
|
|||||||
output: Output('completed', type=[<type 'int'>])
|
output: Output('completed', type=[<type 'int'>])
|
||||||
output: Output('failed', type=[<type 'dict'>])
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
|
command: stageuser_remove_passkey/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('uid', cli_name='login')
|
||||||
|
arg: Str('ipapasskey+', alwaysask=True, cli_name='passkey')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: stageuser_remove_principal/1
|
command: stageuser_remove_principal/1
|
||||||
args: 2,4,3
|
args: 2,4,3
|
||||||
arg: Str('uid', cli_name='login')
|
arg: Str('uid', cli_name='login')
|
||||||
@@ -6279,7 +6425,7 @@ option: Str('ipaidpsub?', cli_name='idp_user_id')
|
|||||||
option: Str('ipasshpubkey*', cli_name='sshpubkey')
|
option: Str('ipasshpubkey*', cli_name='sshpubkey')
|
||||||
option: Str('ipatokenradiusconfiglink?', cli_name='radius')
|
option: Str('ipatokenradiusconfiglink?', cli_name='radius')
|
||||||
option: Str('ipatokenradiususername?', cli_name='radius_username')
|
option: Str('ipatokenradiususername?', cli_name='radius_username')
|
||||||
option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: DateTime('krbpasswordexpiration?', cli_name='password_expiration')
|
option: DateTime('krbpasswordexpiration?', cli_name='password_expiration')
|
||||||
option: DateTime('krbprincipalexpiration?', cli_name='principal_expiration')
|
option: DateTime('krbprincipalexpiration?', cli_name='principal_expiration')
|
||||||
option: Principal('krbprincipalname*', autofill=True, cli_name='principal')
|
option: Principal('krbprincipalname*', autofill=True, cli_name='principal')
|
||||||
@@ -6347,6 +6493,17 @@ option: Str('version?')
|
|||||||
output: Output('completed', type=[<type 'int'>])
|
output: Output('completed', type=[<type 'int'>])
|
||||||
output: Output('failed', type=[<type 'dict'>])
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
|
command: user_add_passkey/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('uid', cli_name='login')
|
||||||
|
arg: Str('ipapasskey+', alwaysask=True, cli_name='passkey')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: user_add_principal/1
|
command: user_add_principal/1
|
||||||
args: 2,4,3
|
args: 2,4,3
|
||||||
arg: Str('uid', cli_name='login')
|
arg: Str('uid', cli_name='login')
|
||||||
@@ -6411,7 +6568,7 @@ option: Str('ipantlogonscript?', autofill=False, cli_name='smb_logon_script')
|
|||||||
option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
|
option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
|
||||||
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
|
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
|
||||||
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
|
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
|
||||||
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
|
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
|
||||||
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
|
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
|
||||||
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
||||||
@@ -6480,7 +6637,7 @@ option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path')
|
|||||||
option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey')
|
option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey')
|
||||||
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
|
option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius')
|
||||||
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
|
option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username')
|
||||||
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp'])
|
option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey'])
|
||||||
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
|
option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration')
|
||||||
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
|
option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration')
|
||||||
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
option: Principal('krbprincipalname*', autofill=False, cli_name='principal')
|
||||||
@@ -6549,6 +6706,17 @@ option: Str('version?')
|
|||||||
output: Output('completed', type=[<type 'int'>])
|
output: Output('completed', type=[<type 'int'>])
|
||||||
output: Output('failed', type=[<type 'dict'>])
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
|
command: user_remove_passkey/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('uid', cli_name='login')
|
||||||
|
arg: Str('ipapasskey+', alwaysask=True, cli_name='passkey')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: user_remove_principal/1
|
command: user_remove_principal/1
|
||||||
args: 2,4,3
|
args: 2,4,3
|
||||||
arg: Str('uid', cli_name='login')
|
arg: Str('uid', cli_name='login')
|
||||||
@@ -6667,7 +6835,7 @@ option: Flag('shared?', autofill=True, default=False)
|
|||||||
option: Str('username?', cli_name='user')
|
option: Str('username?', cli_name='user')
|
||||||
option: Bytes('vault_data')
|
option: Bytes('vault_data')
|
||||||
option: Str('version?')
|
option: Str('version?')
|
||||||
option: StrEnum('wrapping_algo?', autofill=True, default=u'aes-128-cbc', values=[u'aes-128-cbc', u'des-ede3-cbc'])
|
option: StrEnum('wrapping_algo?', autofill=True, default=u'des-ede3-cbc', values=[u'aes-128-cbc', u'des-ede3-cbc'])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
@@ -6767,7 +6935,7 @@ option: Bytes('session_key')
|
|||||||
option: Flag('shared?', autofill=True, default=False)
|
option: Flag('shared?', autofill=True, default=False)
|
||||||
option: Str('username?', cli_name='user')
|
option: Str('username?', cli_name='user')
|
||||||
option: Str('version?')
|
option: Str('version?')
|
||||||
option: StrEnum('wrapping_algo?', autofill=True, default=u'aes-128-cbc', values=[u'aes-128-cbc', u'des-ede3-cbc'])
|
option: StrEnum('wrapping_algo?', autofill=True, default=u'des-ede3-cbc', values=[u'aes-128-cbc', u'des-ede3-cbc'])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
output: PrimaryKey('value')
|
output: PrimaryKey('value')
|
||||||
@@ -7092,17 +7260,21 @@ default: hbactest/1
|
|||||||
default: host/1
|
default: host/1
|
||||||
default: host_add/1
|
default: host_add/1
|
||||||
default: host_add_cert/1
|
default: host_add_cert/1
|
||||||
|
default: host_add_delegation/1
|
||||||
default: host_add_managedby/1
|
default: host_add_managedby/1
|
||||||
default: host_add_principal/1
|
default: host_add_principal/1
|
||||||
|
default: host_allow_add_delegation/1
|
||||||
default: host_allow_create_keytab/1
|
default: host_allow_create_keytab/1
|
||||||
default: host_allow_retrieve_keytab/1
|
default: host_allow_retrieve_keytab/1
|
||||||
default: host_del/1
|
default: host_del/1
|
||||||
default: host_disable/1
|
default: host_disable/1
|
||||||
|
default: host_disallow_add_delegation/1
|
||||||
default: host_disallow_create_keytab/1
|
default: host_disallow_create_keytab/1
|
||||||
default: host_disallow_retrieve_keytab/1
|
default: host_disallow_retrieve_keytab/1
|
||||||
default: host_find/1
|
default: host_find/1
|
||||||
default: host_mod/1
|
default: host_mod/1
|
||||||
default: host_remove_cert/1
|
default: host_remove_cert/1
|
||||||
|
default: host_remove_delegation/1
|
||||||
default: host_remove_managedby/1
|
default: host_remove_managedby/1
|
||||||
default: host_remove_principal/1
|
default: host_remove_principal/1
|
||||||
default: host_show/1
|
default: host_show/1
|
||||||
@@ -7191,6 +7363,9 @@ default: output_show/1
|
|||||||
default: param/1
|
default: param/1
|
||||||
default: param_find/1
|
default: param_find/1
|
||||||
default: param_show/1
|
default: param_show/1
|
||||||
|
default: passkeyconfig/1
|
||||||
|
default: passkeyconfig_mod/1
|
||||||
|
default: passkeyconfig_show/1
|
||||||
default: passwd/1
|
default: passwd/1
|
||||||
default: permission/1
|
default: permission/1
|
||||||
default: permission_add/1
|
default: permission_add/1
|
||||||
@@ -7272,18 +7447,22 @@ default: server_state/1
|
|||||||
default: service/1
|
default: service/1
|
||||||
default: service_add/1
|
default: service_add/1
|
||||||
default: service_add_cert/1
|
default: service_add_cert/1
|
||||||
|
default: service_add_delegation/1
|
||||||
default: service_add_host/1
|
default: service_add_host/1
|
||||||
default: service_add_principal/1
|
default: service_add_principal/1
|
||||||
default: service_add_smb/1
|
default: service_add_smb/1
|
||||||
|
default: service_allow_add_delegation/1
|
||||||
default: service_allow_create_keytab/1
|
default: service_allow_create_keytab/1
|
||||||
default: service_allow_retrieve_keytab/1
|
default: service_allow_retrieve_keytab/1
|
||||||
default: service_del/1
|
default: service_del/1
|
||||||
default: service_disable/1
|
default: service_disable/1
|
||||||
|
default: service_disallow_add_delegation/1
|
||||||
default: service_disallow_create_keytab/1
|
default: service_disallow_create_keytab/1
|
||||||
default: service_disallow_retrieve_keytab/1
|
default: service_disallow_retrieve_keytab/1
|
||||||
default: service_find/1
|
default: service_find/1
|
||||||
default: service_mod/1
|
default: service_mod/1
|
||||||
default: service_remove_cert/1
|
default: service_remove_cert/1
|
||||||
|
default: service_remove_delegation/1
|
||||||
default: service_remove_host/1
|
default: service_remove_host/1
|
||||||
default: service_remove_principal/1
|
default: service_remove_principal/1
|
||||||
default: service_show/1
|
default: service_show/1
|
||||||
@@ -7312,6 +7491,7 @@ default: stageuser_add/1
|
|||||||
default: stageuser_add_cert/1
|
default: stageuser_add_cert/1
|
||||||
default: stageuser_add_certmapdata/1
|
default: stageuser_add_certmapdata/1
|
||||||
default: stageuser_add_manager/1
|
default: stageuser_add_manager/1
|
||||||
|
default: stageuser_add_passkey/1
|
||||||
default: stageuser_add_principal/1
|
default: stageuser_add_principal/1
|
||||||
default: stageuser_del/1
|
default: stageuser_del/1
|
||||||
default: stageuser_find/1
|
default: stageuser_find/1
|
||||||
@@ -7319,6 +7499,7 @@ default: stageuser_mod/1
|
|||||||
default: stageuser_remove_cert/1
|
default: stageuser_remove_cert/1
|
||||||
default: stageuser_remove_certmapdata/1
|
default: stageuser_remove_certmapdata/1
|
||||||
default: stageuser_remove_manager/1
|
default: stageuser_remove_manager/1
|
||||||
|
default: stageuser_remove_passkey/1
|
||||||
default: stageuser_remove_principal/1
|
default: stageuser_remove_principal/1
|
||||||
default: stageuser_show/1
|
default: stageuser_show/1
|
||||||
default: subid/1
|
default: subid/1
|
||||||
@@ -7407,6 +7588,7 @@ default: user_add/1
|
|||||||
default: user_add_cert/1
|
default: user_add_cert/1
|
||||||
default: user_add_certmapdata/1
|
default: user_add_certmapdata/1
|
||||||
default: user_add_manager/1
|
default: user_add_manager/1
|
||||||
|
default: user_add_passkey/1
|
||||||
default: user_add_principal/1
|
default: user_add_principal/1
|
||||||
default: user_del/1
|
default: user_del/1
|
||||||
default: user_disable/1
|
default: user_disable/1
|
||||||
@@ -7416,6 +7598,7 @@ default: user_mod/1
|
|||||||
default: user_remove_cert/1
|
default: user_remove_cert/1
|
||||||
default: user_remove_certmapdata/1
|
default: user_remove_certmapdata/1
|
||||||
default: user_remove_manager/1
|
default: user_remove_manager/1
|
||||||
|
default: user_remove_passkey/1
|
||||||
default: user_remove_principal/1
|
default: user_remove_principal/1
|
||||||
default: user_show/1
|
default: user_show/1
|
||||||
default: user_stage/1
|
default: user_stage/1
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ For more information, see http://www.freeipa.org/page/Build
|
|||||||
|
|
||||||
The quickest way to get the dependencies needed for building is:
|
The quickest way to get the dependencies needed for building is:
|
||||||
|
|
||||||
# dnf builddep -b -D "with_wheels 1" -D "with_lint 1" -D "with_doc 1" --spec freeipa.spec.in --best --allowerasing --setopt=install_weak_deps=False
|
# dnf builddep -D "with_wheels 1" -D "with_lint 1" -D "with_doc 1" --spec freeipa.spec.in --best --allowerasing --setopt=install_weak_deps=False
|
||||||
|
|
||||||
TIP: For building with latest dependencies for freeipa master enable copr repo:
|
TIP: For building with latest dependencies for freeipa master enable copr repo:
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ Developers:
|
|||||||
Alexander Bokovoy
|
Alexander Bokovoy
|
||||||
Alexander Koksharov
|
Alexander Koksharov
|
||||||
Alexander Scheel
|
Alexander Scheel
|
||||||
|
Alexandra Nikandrova
|
||||||
Alexandre Mulatinho
|
Alexandre Mulatinho
|
||||||
Alexey Slaykovsky
|
Alexey Slaykovsky
|
||||||
|
Alexey Tikhonov
|
||||||
Amit Kumar
|
Amit Kumar
|
||||||
Ana Krivokapić
|
Ana Krivokapić
|
||||||
Andika Triwidada
|
Andika Triwidada
|
||||||
@@ -33,6 +35,7 @@ Developers:
|
|||||||
Brian J. Murrell
|
Brian J. Murrell
|
||||||
Brian Turek
|
Brian Turek
|
||||||
Carl George
|
Carl George
|
||||||
|
Carla Martinez
|
||||||
Cédric Jeanneret
|
Cédric Jeanneret
|
||||||
Changmin Teng
|
Changmin Teng
|
||||||
Chris Kelley
|
Chris Kelley
|
||||||
@@ -42,6 +45,7 @@ Developers:
|
|||||||
David Kreitschmann
|
David Kreitschmann
|
||||||
David Kupka
|
David Kupka
|
||||||
David O'Brien
|
David O'Brien
|
||||||
|
David Pascual
|
||||||
David Spångberg
|
David Spångberg
|
||||||
Diane Trout
|
Diane Trout
|
||||||
Dinesh Prasanth M K
|
Dinesh Prasanth M K
|
||||||
@@ -51,8 +55,11 @@ Developers:
|
|||||||
Drew Erny
|
Drew Erny
|
||||||
Emilio Herrera
|
Emilio Herrera
|
||||||
Endi Sukma Dewata
|
Endi Sukma Dewata
|
||||||
|
Erik
|
||||||
|
Erik Belko
|
||||||
Fabiano Fidêncio
|
Fabiano Fidêncio
|
||||||
Felipe Volpone
|
Felipe Volpone
|
||||||
|
Filip Dvorak
|
||||||
Filip Skola
|
Filip Skola
|
||||||
Florence Blanc-Renaud
|
Florence Blanc-Renaud
|
||||||
Francesco Marella
|
Francesco Marella
|
||||||
@@ -69,6 +76,7 @@ Developers:
|
|||||||
Hela Basa
|
Hela Basa
|
||||||
Ian Kumlien
|
Ian Kumlien
|
||||||
Ian Pilcher
|
Ian Pilcher
|
||||||
|
Iker Pedrosa
|
||||||
Isaac Boukris
|
Isaac Boukris
|
||||||
Jakub Hrozek
|
Jakub Hrozek
|
||||||
James Groffen
|
James Groffen
|
||||||
@@ -77,12 +85,15 @@ Developers:
|
|||||||
Jan Kuparinen
|
Jan Kuparinen
|
||||||
Jan Pazdziora
|
Jan Pazdziora
|
||||||
Jan Zelený
|
Jan Zelený
|
||||||
|
Jarl Gullberg
|
||||||
Jason Gerard DeRose
|
Jason Gerard DeRose
|
||||||
Jason Woods
|
Jason Woods
|
||||||
Jayesh
|
Jayesh
|
||||||
Jayesh Garg
|
Jayesh Garg
|
||||||
Jeremy Frasier
|
Jeremy Frasier
|
||||||
Jérôme Fenal
|
Jérôme Fenal
|
||||||
|
Jerry James
|
||||||
|
Jesse Sandberg
|
||||||
jh23453
|
jh23453
|
||||||
Jim Meyering
|
Jim Meyering
|
||||||
Jochen Kellner
|
Jochen Kellner
|
||||||
@@ -102,6 +113,7 @@ Developers:
|
|||||||
Lars Sjostrom
|
Lars Sjostrom
|
||||||
Lenka Doudova
|
Lenka Doudova
|
||||||
Lenka Ryznarova
|
Lenka Ryznarova
|
||||||
|
Lenz Grimmer
|
||||||
Lewis Eason
|
Lewis Eason
|
||||||
Lubomír Rintel
|
Lubomír Rintel
|
||||||
Ludwig Krispenz
|
Ludwig Krispenz
|
||||||
@@ -117,6 +129,7 @@ Developers:
|
|||||||
Martin Nagy
|
Martin Nagy
|
||||||
Matt Rogers
|
Matt Rogers
|
||||||
Matthew Davis
|
Matthew Davis
|
||||||
|
mbhalodi
|
||||||
Michael Simacek
|
Michael Simacek
|
||||||
Michal Polovka
|
Michal Polovka
|
||||||
Michal Reznik
|
Michal Reznik
|
||||||
@@ -132,6 +145,7 @@ Developers:
|
|||||||
ndehadra
|
ndehadra
|
||||||
Nick Hatch
|
Nick Hatch
|
||||||
Nikhil Dehadrai
|
Nikhil Dehadrai
|
||||||
|
Nikola Knazekova
|
||||||
Nikolai Kondrashov
|
Nikolai Kondrashov
|
||||||
Niranjan Mallapadi
|
Niranjan Mallapadi
|
||||||
Niranjan MR
|
Niranjan MR
|
||||||
@@ -159,18 +173,22 @@ Developers:
|
|||||||
realsobek
|
realsobek
|
||||||
René Genz
|
René Genz
|
||||||
Rich Megginson
|
Rich Megginson
|
||||||
|
Ricky Tigg
|
||||||
Rishabh Dave
|
Rishabh Dave
|
||||||
Rob Crittenden
|
Rob Crittenden
|
||||||
Robbie Harwood
|
Robbie Harwood
|
||||||
Robert Collins
|
Robert Collins
|
||||||
Robert Kuska
|
Robert Kuska
|
||||||
|
s1341
|
||||||
Sam Bristow
|
Sam Bristow
|
||||||
Sam Morris
|
Sam Morris
|
||||||
|
Scott Poore
|
||||||
Sergey Orlov
|
Sergey Orlov
|
||||||
Sergio Oliveira Campos
|
Sergio Oliveira Campos
|
||||||
Serhii Tsymbaliuk
|
Serhii Tsymbaliuk
|
||||||
shanyin
|
shanyin
|
||||||
Simo Sorce
|
Simo Sorce
|
||||||
|
Simon Nussbaum
|
||||||
Slava Aseev
|
Slava Aseev
|
||||||
Spencer E. Olson
|
Spencer E. Olson
|
||||||
Stanislav Laznicka
|
Stanislav Laznicka
|
||||||
@@ -184,17 +202,20 @@ Developers:
|
|||||||
Sumit Bose
|
Sumit Bose
|
||||||
Sylvain Baubeau
|
Sylvain Baubeau
|
||||||
Takeshi MIZUTA
|
Takeshi MIZUTA
|
||||||
|
Temuri Doghonadze
|
||||||
Theodor van Nahl
|
Theodor van Nahl
|
||||||
Thierry Bordaz
|
Thierry Bordaz
|
||||||
Thomas Woerner
|
Thomas Woerner
|
||||||
Thorsten Scherf
|
Thorsten Scherf
|
||||||
Tibor Dudlák
|
Tibor Dudlák
|
||||||
Timo Aaltonen
|
Timo Aaltonen
|
||||||
|
Todd Zullinger
|
||||||
Tomáš Babej
|
Tomáš Babej
|
||||||
Tomas Halman
|
Tomas Halman
|
||||||
Tomáš Křížek
|
Tomáš Křížek
|
||||||
Troy Dawson
|
Troy Dawson
|
||||||
Varun Mylaraiah
|
Varun Mylaraiah
|
||||||
|
Viacheslav Sychov
|
||||||
Viktor Ashirov
|
Viktor Ashirov
|
||||||
Vit Mojzis
|
Vit Mojzis
|
||||||
W. Michael Petullo
|
W. Michael Petullo
|
||||||
@@ -205,6 +226,7 @@ Developers:
|
|||||||
Yuri Chornoivan
|
Yuri Chornoivan
|
||||||
Zdenek Pytela
|
Zdenek Pytela
|
||||||
zdover
|
zdover
|
||||||
|
김인수
|
||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
Gabe Alford
|
Gabe Alford
|
||||||
|
|||||||
+11
-4
@@ -23,6 +23,8 @@ PYTHON_SCRIPT_SUBDIRS = \
|
|||||||
$(top_builddir)/install/tools \
|
$(top_builddir)/install/tools \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
PRCI_DEFINITIONS_DIR = $(top_srcdir)/ipatests/prci_definitions
|
||||||
|
|
||||||
AZURE_PYTHON_SCRIPT_SUBDIR = $(top_builddir)/ipatests/azure
|
AZURE_PYTHON_SCRIPT_SUBDIR = $(top_builddir)/ipatests/azure
|
||||||
|
|
||||||
IPA_PLACEHOLDERS = freeipa ipa ipaserver ipatests
|
IPA_PLACEHOLDERS = freeipa ipa ipaserver ipatests
|
||||||
@@ -242,7 +244,7 @@ fastcodestyle: $(GENERATED_PYTHON_FILES) ipasetup.py
|
|||||||
| xargs -n1 file 2>/dev/null | grep Python \
|
| xargs -n1 file 2>/dev/null | grep Python \
|
||||||
| cut -d':' -f1; ); \
|
| cut -d':' -f1; ); \
|
||||||
if [ -n "$${PYFILES}" ] && [ -n "$${INFILES}" ]; then \
|
if [ -n "$${PYFILES}" ] && [ -n "$${INFILES}" ]; then \
|
||||||
FILES="$$( printf $${PYFILES}\\n$${INFILES} )" ; \
|
FILES="$$( printf '%s\n' "$${PYFILES}" "$${INFILES}" )" ; \
|
||||||
elif [ -n "$${PYFILES}" ]; then \
|
elif [ -n "$${PYFILES}" ]; then \
|
||||||
FILES="$${PYFILES}" ; \
|
FILES="$${PYFILES}" ; \
|
||||||
else \
|
else \
|
||||||
@@ -272,7 +274,7 @@ endif
|
|||||||
| xargs -n1 file 2>/dev/null | grep Python \
|
| xargs -n1 file 2>/dev/null | grep Python \
|
||||||
| cut -d':' -f1; ); \
|
| cut -d':' -f1; ); \
|
||||||
if [ -n "$${PYFILES}" ] && [ -n "$${INFILES}" ]; then \
|
if [ -n "$${PYFILES}" ] && [ -n "$${INFILES}" ]; then \
|
||||||
FILES="$$( printf $${PYFILES}\\n$${INFILES} )" ; \
|
FILES="$$( printf '%s\n' "$${PYFILES}" "$${INFILES}" )" ; \
|
||||||
elif [ -n "$${PYFILES}" ]; then \
|
elif [ -n "$${PYFILES}" ]; then \
|
||||||
FILES="$${PYFILES}" ; \
|
FILES="$${PYFILES}" ; \
|
||||||
else \
|
else \
|
||||||
@@ -336,6 +338,8 @@ endif # WITH_RPMLINT
|
|||||||
# There are Jinja yaml templates, which differ from reqular ones. These
|
# There are Jinja yaml templates, which differ from reqular ones. These
|
||||||
# files should be placed on skip list (YAML_TEMPLATE_FILES), otherwise
|
# files should be placed on skip list (YAML_TEMPLATE_FILES), otherwise
|
||||||
# safe_load fails.
|
# safe_load fails.
|
||||||
|
# Also check PRCI definitions yaml files jobs format and content with
|
||||||
|
# prci_checker script
|
||||||
.PHONY: yamllint
|
.PHONY: yamllint
|
||||||
yamllint:
|
yamllint:
|
||||||
YAML_TEMPLATE_FILES="\
|
YAML_TEMPLATE_FILES="\
|
||||||
@@ -357,7 +361,10 @@ yamllint:
|
|||||||
echo $${YAML}; \
|
echo $${YAML}; \
|
||||||
$(PYTHON) -c "import yaml; f = open('$${YAML}'); yaml.safe_load(f); f.close()" || { echo Your YAML file: $${YAML} has a wrong syntax or this is a Jinja template. In the latter clause, consider to add your YAML file to the YAML_TEMPLATE_FILES list in Makefile.am.; exit 1; } \
|
$(PYTHON) -c "import yaml; f = open('$${YAML}'); yaml.safe_load(f); f.close()" || { echo Your YAML file: $${YAML} has a wrong syntax or this is a Jinja template. In the latter clause, consider to add your YAML file to the YAML_TEMPLATE_FILES list in Makefile.am.; exit 1; } \
|
||||||
done; \
|
done; \
|
||||||
echo "-----------"
|
echo -e "\nCheck PRCI definitions";
|
||||||
|
@echo "-----------"
|
||||||
|
$(PYTHON) $(PRCI_DEFINITIONS_DIR)/prci_checker.py -d $(PRCI_DEFINITIONS_DIR) -s $(PRCI_DEFINITIONS_DIR)/prci_jobs_spec.yaml;
|
||||||
|
@echo "-----------"
|
||||||
|
|
||||||
# Build & lint documentation.
|
# Build & lint documentation.
|
||||||
#
|
#
|
||||||
@@ -389,7 +396,7 @@ pylint: $(GENERATED_PYTHON_FILES) ipasetup.py python_scripts
|
|||||||
-name '*~' -o \
|
-name '*~' -o \
|
||||||
-name '*.py' -print -o \
|
-name '*.py' -print -o \
|
||||||
-type f -exec grep -qsm1 '^#!.*\bpython' '{}' \; -print`; \
|
-type f -exec grep -qsm1 '^#!.*\bpython' '{}' \; -print`; \
|
||||||
FILES=`echo -e "$${FILES}\n$(AZURE_PYTHON_SCRIPT_SUBDIR)"`; \
|
FILES=`echo -e "$${FILES}\n$(AZURE_PYTHON_SCRIPT_SUBDIR)\n$(PRCI_DEFINITIONS_DIR)"`; \
|
||||||
echo -e "Pylint on $(PYTHON) is running over files:\n$${FILES}\nPlease wait ...\n"; \
|
echo -e "Pylint on $(PYTHON) is running over files:\n$${FILES}\nPlease wait ...\n"; \
|
||||||
$(PYTHON) -m pylint --version; \
|
$(PYTHON) -m pylint --version; \
|
||||||
PYTHONPATH=$(top_srcdir) $(PYTHON) -m pylint \
|
PYTHONPATH=$(top_srcdir) $(PYTHON) -m pylint \
|
||||||
|
|||||||
+9
-3
@@ -20,7 +20,7 @@
|
|||||||
# -> "1.0.0" #
|
# -> "1.0.0" #
|
||||||
########################################################
|
########################################################
|
||||||
define(IPA_VERSION_MAJOR, 4)
|
define(IPA_VERSION_MAJOR, 4)
|
||||||
define(IPA_VERSION_MINOR, 10)
|
define(IPA_VERSION_MINOR, 12)
|
||||||
define(IPA_VERSION_RELEASE, 0)
|
define(IPA_VERSION_RELEASE, 0)
|
||||||
|
|
||||||
########################################################
|
########################################################
|
||||||
@@ -86,8 +86,8 @@ define(IPA_DATA_VERSION, 20100614120000)
|
|||||||
# #
|
# #
|
||||||
########################################################
|
########################################################
|
||||||
define(IPA_API_VERSION_MAJOR, 2)
|
define(IPA_API_VERSION_MAJOR, 2)
|
||||||
# Last change: add Random Serial Numbers v3
|
# Last change: add passkey support
|
||||||
define(IPA_API_VERSION_MINOR, 249)
|
define(IPA_API_VERSION_MINOR, 253)
|
||||||
|
|
||||||
########################################################
|
########################################################
|
||||||
# Following values are auto-generated from values above
|
# Following values are auto-generated from values above
|
||||||
@@ -137,6 +137,11 @@ ifelse(IPA_VERSION_IS_GIT_SNAPSHOT, yes,
|
|||||||
IPA_GIT_VERSION),
|
IPA_GIT_VERSION),
|
||||||
NEWLINE)) dnl IPA_VERSION end
|
NEWLINE)) dnl IPA_VERSION end
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Version of MIT krb5 used to build IPA
|
||||||
|
########################################################
|
||||||
|
define(IPA_KRB5_BUILD_VERSION, translit(esyscmd(krb5-config --version | awk '{ print $NF }'), NEWLINE))
|
||||||
|
|
||||||
dnl DEBUG: uncomment following lines and run command m4 VERSION.m4
|
dnl DEBUG: uncomment following lines and run command m4 VERSION.m4
|
||||||
dnl `IPA_VERSION: ''IPA_VERSION'
|
dnl `IPA_VERSION: ''IPA_VERSION'
|
||||||
dnl `IPA_GIT_VERSION: ''IPA_GIT_VERSION'
|
dnl `IPA_GIT_VERSION: ''IPA_GIT_VERSION'
|
||||||
@@ -144,3 +149,4 @@ dnl `IPA_GIT_BRANCH: ''IPA_GIT_BRANCH'
|
|||||||
dnl `IPA_API_VERSION: ''IPA_API_VERSION'
|
dnl `IPA_API_VERSION: ''IPA_API_VERSION'
|
||||||
dnl `IPA_DATA_VERSION: ''IPA_DATA_VERSION'
|
dnl `IPA_DATA_VERSION: ''IPA_DATA_VERSION'
|
||||||
dnl `IPA_NUM_VERSION: ''IPA_NUM_VERSION'
|
dnl `IPA_NUM_VERSION: ''IPA_NUM_VERSION'
|
||||||
|
dnl `IPA_KRB5_BUILD_VERSION: ''IPA_KRB5_BUILD_VERSION'
|
||||||
+4
-2
@@ -57,6 +57,8 @@
|
|||||||
|
|
||||||
char * read_config_file(const char *filename);
|
char * read_config_file(const char *filename);
|
||||||
char * get_config_entry(char * data, const char *section, const char *key);
|
char * get_config_entry(char * data, const char *section, const char *key);
|
||||||
|
static size_t
|
||||||
|
jsonrpc_handle_response(char *ptr, size_t size, size_t nmemb, void *userdata);
|
||||||
|
|
||||||
static int debug = 0;
|
static int debug = 0;
|
||||||
|
|
||||||
@@ -642,7 +644,7 @@ curl_slist_append_log(struct curl_slist *list, char *string, bool quiet) {
|
|||||||
goto cleanup; \
|
goto cleanup; \
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
static size_t
|
||||||
jsonrpc_handle_response(char *ptr, size_t size, size_t nmemb, void *userdata) {
|
jsonrpc_handle_response(char *ptr, size_t size, size_t nmemb, void *userdata) {
|
||||||
size_t realsize = size * nmemb;
|
size_t realsize = size * nmemb;
|
||||||
curl_buffer *cb = (curl_buffer *) userdata;
|
curl_buffer *cb = (curl_buffer *) userdata;
|
||||||
@@ -722,7 +724,7 @@ jsonrpc_request(const char *ipaserver, const json_t *json, curl_buffer *response
|
|||||||
|
|
||||||
CURL_SETOPT(curl, CURLOPT_CAINFO, DEFAULT_CA_CERT_FILE);
|
CURL_SETOPT(curl, CURLOPT_CAINFO, DEFAULT_CA_CERT_FILE);
|
||||||
|
|
||||||
CURL_SETOPT(curl, CURLOPT_WRITEFUNCTION, &jsonrpc_handle_response);
|
CURL_SETOPT(curl, CURLOPT_WRITEFUNCTION, jsonrpc_handle_response);
|
||||||
CURL_SETOPT(curl, CURLOPT_WRITEDATA, response);
|
CURL_SETOPT(curl, CURLOPT_WRITEDATA, response);
|
||||||
|
|
||||||
CURL_SETOPT(curl, CURLOPT_HTTPAUTH, CURLAUTH_NEGOTIATE);
|
CURL_SETOPT(curl, CURLOPT_HTTPAUTH, CURLAUTH_NEGOTIATE);
|
||||||
|
|||||||
@@ -166,6 +166,9 @@ Specifies the mount point that the development server will register. The default
|
|||||||
.B oidc_child_debug_level <debuglevel>
|
.B oidc_child_debug_level <debuglevel>
|
||||||
Specifies the debug level of \fBoidc_child\fR, a helper process used by \fBipa-otpd\fR for OIDC/OAuth2 authentication. Level can be between 0 and 10, the higher the more details. If the level is 6 or higher HTTP debug output is added as well.
|
Specifies the debug level of \fBoidc_child\fR, a helper process used by \fBipa-otpd\fR for OIDC/OAuth2 authentication. Level can be between 0 and 10, the higher the more details. If the level is 6 or higher HTTP debug output is added as well.
|
||||||
.TP
|
.TP
|
||||||
|
.B passkey_child_debug_level <debuglevel>
|
||||||
|
Specifies the debug level of \fBpasskey_child\fR, a helper process used by \fBipa-otpd\fR for passkey authentication. Level can be between 0 and 10, the higher the more details. If the level is 6 or higher libfido2 debug output is added as well.
|
||||||
|
.TP
|
||||||
.B prompt_all <boolean>
|
.B prompt_all <boolean>
|
||||||
Specifies that all options should be prompted for in the IPA client, even optional values. Default is False.
|
Specifies that all options should be prompted for in the IPA client, even optional values. Default is False.
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ Time to wait, in milliseconds, between each e-mail sent to try to avoid overload
|
|||||||
Specifies the From: e-mail address value in the e-mails sent. The default is noreply@ipadefaultemaildomain. This value can be found by running
|
Specifies the From: e-mail address value in the e-mails sent. The default is noreply@ipadefaultemaildomain. This value can be found by running
|
||||||
.I ipa config-show
|
.I ipa config-show
|
||||||
.TP
|
.TP
|
||||||
|
.B mail_from_name <name>
|
||||||
|
Specifies the From: name value in the e-mails sent. The default is IPA-EPN.
|
||||||
|
.TP
|
||||||
.B notify_ttls <list of days>
|
.B notify_ttls <list of days>
|
||||||
This is the list of days before a password expiration when ipa-epn should notify a user that their password will soon require a reset. If this value is not specified then the default list will be used: 28, 14, 7, 3, 1.
|
This is the list of days before a password expiration when ipa-epn should notify a user that their password will soon require a reset. If this value is not specified then the default list will be used: 28, 14, 7, 3, 1.
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Configures a client machine to use IPA for authentication and identity services.
|
|||||||
|
|
||||||
By default this configures SSSD to connect to an IPA server for authentication and authorization. Optionally one can instead configure PAM and NSS (Name Switching Service) to work with an IPA server over Kerberos and LDAP.
|
By default this configures SSSD to connect to an IPA server for authentication and authorization. Optionally one can instead configure PAM and NSS (Name Switching Service) to work with an IPA server over Kerberos and LDAP.
|
||||||
|
|
||||||
An authorized user is required to join a client machine to IPA. This can take the form of a kerberos principal or a one\-time password associated with the machine.
|
An authorized account is required to join a client machine to IPA. This can take the form of a kerberos principal, a one\-time password associated with the machine, or PKINIT identity associated with the machine.
|
||||||
|
|
||||||
This same tool is used to unconfigure IPA and attempts to return the machine to its previous state. Part of this process is to unenroll the host from the IPA server. Unenrollment consists of disabling the principal key on the IPA server so that it may be re\-enrolled. The machine principal in /etc/krb5.keytab (host/<fqdn>@REALM) is used to authenticate to the IPA server to unenroll itself. If this principal does not exist then unenrollment will fail and an administrator will need to disable the host principal (ipa host\-disable <fqdn>).
|
This same tool is used to unconfigure IPA and attempts to return the machine to its previous state. Part of this process is to unenroll the host from the IPA server. Unenrollment consists of disabling the principal key on the IPA server so that it may be re\-enrolled. The machine principal in /etc/krb5.keytab (host/<fqdn>@REALM) is used to authenticate to the IPA server to unenroll itself. If this principal does not exist then unenrollment will fail and an administrator will need to disable the host principal (ipa host\-disable <fqdn>).
|
||||||
|
|
||||||
@@ -229,6 +229,22 @@ first. When this option is not specified, \fBipa\-client\-install\fR will back
|
|||||||
up SSSD config and create new one. The back up version will be restored during
|
up SSSD config and create new one. The back up version will be restored during
|
||||||
uninstall.
|
uninstall.
|
||||||
|
|
||||||
|
.SS "PKINIT OPTIONS"
|
||||||
|
.TP
|
||||||
|
\fB\-\-pkinit\-identity=\fIDENTITY\fR
|
||||||
|
Identity string for PKINIT authentication to use to join the IPA realm,
|
||||||
|
for example 'FILE:/path/to/cert.pem,/path/to/key.pem'. See krb5.conf(5)
|
||||||
|
for more information. The option is mutually exclusive with
|
||||||
|
\fB\-\-password\fR and \fB\-\-keytab\fR.
|
||||||
|
.TP
|
||||||
|
\fB\-\-pkinit\-anchor\fR=\fIFILEDIR\fR
|
||||||
|
Trust anchors (root and intermediate CA certs) for PKINIT. \fIFILEDIR\fR is
|
||||||
|
either the absolute path to a PEM bundle (for example
|
||||||
|
'FILE:/etc/pki/tls/cert.pem') or to an OpenSSL hash directory (for example
|
||||||
|
'DIR:/etc/ssl/certs/'). The option can be used multiple times. PKINIT
|
||||||
|
requires the full trust chain of the Kerberos KDC server as well as the full
|
||||||
|
trust chain of the identity certificate.
|
||||||
|
|
||||||
.SS "UNINSTALL OPTIONS"
|
.SS "UNINSTALL OPTIONS"
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-uninstall\fR
|
\fB\-\-uninstall\fR
|
||||||
@@ -237,6 +253,12 @@ Remove the IPA client software and restore the configuration to the pre\-IPA sta
|
|||||||
\fB\-U\fR, \fB\-\-unattended\fR
|
\fB\-U\fR, \fB\-\-unattended\fR
|
||||||
Unattended uninstallation. The user will not be prompted.
|
Unattended uninstallation. The user will not be prompted.
|
||||||
|
|
||||||
|
.SH "DISABLED SERVICES"
|
||||||
|
.TP
|
||||||
|
ipa-client-install will automatically disable the Name Service Caching Daemon (nscd) when configuring the SSSD client. These are competing services and cannot co-exist.
|
||||||
|
.TP
|
||||||
|
If there are other similar services providing nss capabilities they will need to be manually disabled by the user. An example is unscd, a complete replacement for nscd.
|
||||||
|
|
||||||
.SH "FILES"
|
.SH "FILES"
|
||||||
.TP
|
.TP
|
||||||
Files that will be replaced if SSSD is configured (default):
|
Files that will be replaced if SSSD is configured (default):
|
||||||
|
|||||||
@@ -136,8 +136,10 @@ O \- self\-obliterate
|
|||||||
.TP
|
.TP
|
||||||
\fBipa help commands\fR
|
\fBipa help commands\fR
|
||||||
Display a list of available commands
|
Display a list of available commands
|
||||||
|
.TP
|
||||||
\fBipa help topics\fR
|
\fBipa help topics\fR
|
||||||
Display a high\-level list of help topics
|
Display a high\-level list of help topics
|
||||||
|
.TP
|
||||||
\fBipa help user\fR
|
\fBipa help user\fR
|
||||||
Display documentation and list of commands in the "user" topic.
|
Display documentation and list of commands in the "user" topic.
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ smtp_delay = 0
|
|||||||
# This value can be found by running ipa config-show.
|
# This value can be found by running ipa config-show.
|
||||||
# mail_from =
|
# mail_from =
|
||||||
|
|
||||||
|
# Specifies the From: name value in the e-mails-sent.
|
||||||
|
# The default when unset is IPA-EPN.
|
||||||
|
# mail_from_name =
|
||||||
|
|
||||||
# The list of days before a password expiration when ipa-epn should notify
|
# The list of days before a password expiration when ipa-epn should notify
|
||||||
# a user that their password will soon require a reset.
|
# a user that their password will soon require a reset.
|
||||||
notify_ttls = 28, 14, 7, 3, 1
|
notify_ttls = 28, 14, 7, 3, 1
|
||||||
|
|||||||
@@ -460,6 +460,7 @@ AC_SUBST(VENDOR_SUFFIX)
|
|||||||
AC_SUBST([VERSION], [IPA_VERSION])
|
AC_SUBST([VERSION], [IPA_VERSION])
|
||||||
AC_SUBST([GIT_VERSION], [IPA_GIT_VERSION])
|
AC_SUBST([GIT_VERSION], [IPA_GIT_VERSION])
|
||||||
AC_SUBST([GIT_BRANCH], [IPA_GIT_BRANCH])
|
AC_SUBST([GIT_BRANCH], [IPA_GIT_BRANCH])
|
||||||
|
AC_SUBST([KRB5_BUILD_VERSION], [IPA_KRB5_BUILD_VERSION])
|
||||||
# used by Makefile.am for files depending on templates
|
# used by Makefile.am for files depending on templates
|
||||||
AC_SUBST([CONFIG_STATUS])
|
AC_SUBST([CONFIG_STATUS])
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/python3
|
||||||
#
|
#
|
||||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/python3
|
||||||
#
|
#
|
||||||
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
|
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ KEYTAB_FB = paths.IPA_DNSKEYSYNCD_KEYTAB
|
|||||||
def commenceShutdown(signum, stack):
|
def commenceShutdown(signum, stack):
|
||||||
# Declare the needed global variables
|
# Declare the needed global variables
|
||||||
global watcher_running
|
global watcher_running
|
||||||
global ldap_connection # pylint: disable=global-variable-not-assigned
|
global ldap_connection
|
||||||
|
|
||||||
logger.info('Signal %s received: Shutting down!', signum)
|
logger.info('Signal %s received: Shutting down!', signum)
|
||||||
|
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ init_with_password(const char *name, const char *password)
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
if (service_creds != GSS_C_NO_CREDENTIAL)
|
if (service_creds != GSS_C_NO_CREDENTIAL)
|
||||||
gss_release_cred(&min, &client_creds);
|
gss_release_cred(&min, &service_creds);
|
||||||
|
|
||||||
if (client_creds != GSS_C_NO_CREDENTIAL)
|
if (client_creds != GSS_C_NO_CREDENTIAL)
|
||||||
gss_release_cred(&min, &client_creds);
|
gss_release_cred(&min, &client_creds);
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ static void ipadb_context_free(krb5_context kcontext,
|
|||||||
size_t c;
|
size_t c;
|
||||||
|
|
||||||
if (*ctx != NULL) {
|
if (*ctx != NULL) {
|
||||||
|
if ((*ctx)->magic != IPA_CONTEXT_MAGIC) {
|
||||||
|
krb5_klog_syslog(LOG_ERR, "IPA context is corrupted");
|
||||||
|
*ctx = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
free((*ctx)->uri);
|
free((*ctx)->uri);
|
||||||
free((*ctx)->base);
|
free((*ctx)->base);
|
||||||
free((*ctx)->realm_base);
|
free((*ctx)->realm_base);
|
||||||
@@ -200,6 +205,7 @@ static const struct {
|
|||||||
{ "pkinit", IPADB_USER_AUTH_PKINIT },
|
{ "pkinit", IPADB_USER_AUTH_PKINIT },
|
||||||
{ "hardened", IPADB_USER_AUTH_HARDENED },
|
{ "hardened", IPADB_USER_AUTH_HARDENED },
|
||||||
{ "idp", IPADB_USER_AUTH_IDP },
|
{ "idp", IPADB_USER_AUTH_IDP },
|
||||||
|
{ "passkey", IPADB_USER_AUTH_PASSKEY },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -615,6 +621,8 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipactx->optional_pac_tkt_chksum = IPADB_TRISTATE_UNDEFINED;
|
||||||
|
|
||||||
ret = ipadb_get_connection(ipactx);
|
ret = ipadb_get_connection(ipactx);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
/* Not a fatal failure, as the LDAP server may be temporarily down. */
|
/* Not a fatal failure, as the LDAP server may be temporarily down. */
|
||||||
@@ -628,6 +636,7 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@@ -798,11 +807,20 @@ kdb_vftabl kdb_function_table = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (KRB5_KDB_DAL_MAJOR_VERSION == 9)
|
#if (KRB5_KDB_DAL_MAJOR_VERSION == 9)
|
||||||
#error DAL version 9 is not supported yet
|
|
||||||
/* Version 9 removes sign_authdata and adds issue_pac method. It is a complete
|
/* Version 9 removes sign_authdata and adds issue_pac method. It is a complete
|
||||||
* revamp of how PAC is issued, so we need to implement it differently to previous
|
* revamp of how PAC is issued, so we need to implement it differently to previous
|
||||||
* versions. */
|
* versions. */
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
|
||||||
|
krb5_db_entry *client,
|
||||||
|
krb5_keyblock *replaced_reply_key,
|
||||||
|
krb5_db_entry *server,
|
||||||
|
krb5_db_entry *signing_krbtgt,
|
||||||
|
krb5_timestamp authtime, krb5_pac old_pac,
|
||||||
|
krb5_pac new_pac,
|
||||||
|
krb5_data ***auth_indicators);
|
||||||
|
|
||||||
kdb_vftabl kdb_function_table = {
|
kdb_vftabl kdb_function_table = {
|
||||||
.maj_ver = KRB5_KDB_DAL_MAJOR_VERSION,
|
.maj_ver = KRB5_KDB_DAL_MAJOR_VERSION,
|
||||||
.min_ver = 0,
|
.min_ver = 0,
|
||||||
@@ -830,8 +848,8 @@ kdb_vftabl kdb_function_table = {
|
|||||||
.check_allowed_to_delegate = ipadb_check_allowed_to_delegate,
|
.check_allowed_to_delegate = ipadb_check_allowed_to_delegate,
|
||||||
.free_principal_e_data = ipadb_free_principal_e_data,
|
.free_principal_e_data = ipadb_free_principal_e_data,
|
||||||
.get_s4u_x509_principal = NULL,
|
.get_s4u_x509_principal = NULL,
|
||||||
.allowed_to_delegate_from = NULL,
|
.allowed_to_delegate_from = ipadb_allowed_to_delegate_from,
|
||||||
.issue_pac = NULL,
|
.issue_pac = ipadb_v9_issue_pac,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,22 @@
|
|||||||
#include "ipa_krb5.h"
|
#include "ipa_krb5.h"
|
||||||
#include "ipa_pwd.h"
|
#include "ipa_pwd.h"
|
||||||
|
|
||||||
|
/* Difference between krb5 1.20 and previous versions. From
|
||||||
|
* krb5 commit a441fbe329ebbd7775eb5d4ccc4a05eef370f08b:
|
||||||
|
* Combine the KRB5_KDB_FLAG_ISSUE_PAC and
|
||||||
|
* KRB5_FLAG_CLIENT_REFERRALS_ONLY flags into KRB5_KDB_FLAG_CLIENT.
|
||||||
|
*
|
||||||
|
* Rename the KRB5_KDB_FLAG_CANONICALIZE flag to
|
||||||
|
* KRB5_KDB_FLAG_REFERRAL_OK, and only pass it to get_principal() for
|
||||||
|
* lookup operations that can use a realm referral.
|
||||||
|
* */
|
||||||
|
#if defined(KRB5_KDB_FLAG_CLIENT)
|
||||||
|
#define CLIENT_REFERRALS_FLAGS (KRB5_KDB_FLAG_REFERRAL_OK)
|
||||||
|
#else
|
||||||
|
#define CLIENT_REFERRALS_FLAGS (KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* easier to copy the defines here than to mess with kadm5/admin.h
|
/* easier to copy the defines here than to mess with kadm5/admin.h
|
||||||
* for now */
|
* for now */
|
||||||
#define KMASK_PRINCIPAL 0x000001
|
#define KMASK_PRINCIPAL 0x000001
|
||||||
@@ -90,6 +106,7 @@ enum ipadb_user_auth {
|
|||||||
IPADB_USER_AUTH_PKINIT = 1 << 4,
|
IPADB_USER_AUTH_PKINIT = 1 << 4,
|
||||||
IPADB_USER_AUTH_HARDENED = 1 << 5,
|
IPADB_USER_AUTH_HARDENED = 1 << 5,
|
||||||
IPADB_USER_AUTH_IDP = 1 << 6,
|
IPADB_USER_AUTH_IDP = 1 << 6,
|
||||||
|
IPADB_USER_AUTH_PASSKEY = 1 << 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ipadb_user_auth_idx {
|
enum ipadb_user_auth_idx {
|
||||||
@@ -98,6 +115,7 @@ enum ipadb_user_auth_idx {
|
|||||||
IPADB_USER_AUTH_IDX_PKINIT,
|
IPADB_USER_AUTH_IDX_PKINIT,
|
||||||
IPADB_USER_AUTH_IDX_HARDENED,
|
IPADB_USER_AUTH_IDX_HARDENED,
|
||||||
IPADB_USER_AUTH_IDX_IDP,
|
IPADB_USER_AUTH_IDX_IDP,
|
||||||
|
IPADB_USER_AUTH_IDX_PASSKEY,
|
||||||
IPADB_USER_AUTH_IDX_MAX,
|
IPADB_USER_AUTH_IDX_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,6 +128,12 @@ struct ipadb_global_config {
|
|||||||
bool disable_preauth_for_spns;
|
bool disable_preauth_for_spns;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ipadb_tristate_option {
|
||||||
|
IPADB_TRISTATE_FALSE = FALSE,
|
||||||
|
IPADB_TRISTATE_TRUE = TRUE,
|
||||||
|
IPADB_TRISTATE_UNDEFINED,
|
||||||
|
};
|
||||||
|
|
||||||
#define IPA_CONTEXT_MAGIC 0x0c027ea7
|
#define IPA_CONTEXT_MAGIC 0x0c027ea7
|
||||||
struct ipadb_context {
|
struct ipadb_context {
|
||||||
int magic;
|
int magic;
|
||||||
@@ -127,6 +151,7 @@ struct ipadb_context {
|
|||||||
krb5_key_salt_tuple *def_encs;
|
krb5_key_salt_tuple *def_encs;
|
||||||
int n_def_encs;
|
int n_def_encs;
|
||||||
struct ipadb_mspac *mspac;
|
struct ipadb_mspac *mspac;
|
||||||
|
enum ipadb_tristate_option optional_pac_tkt_chksum;
|
||||||
#ifdef HAVE_KRB5_CERTAUTH_PLUGIN
|
#ifdef HAVE_KRB5_CERTAUTH_PLUGIN
|
||||||
krb5_certauth_moddata certauth_moddata;
|
krb5_certauth_moddata certauth_moddata;
|
||||||
#endif
|
#endif
|
||||||
@@ -206,6 +231,16 @@ int ipadb_ldap_attr_has_value(LDAP *lcontext, LDAPMessage *le,
|
|||||||
int ipadb_ldap_deref_results(LDAP *lcontext, LDAPMessage *le,
|
int ipadb_ldap_deref_results(LDAP *lcontext, LDAPMessage *le,
|
||||||
LDAPDerefRes **results);
|
LDAPDerefRes **results);
|
||||||
|
|
||||||
|
krb5_error_code ipadb_get_tl_data(krb5_db_entry *entry,
|
||||||
|
krb5_int16 type,
|
||||||
|
krb5_ui_2 length,
|
||||||
|
krb5_octet *data);
|
||||||
|
|
||||||
|
krb5_error_code ipadb_set_tl_data(krb5_db_entry *entry,
|
||||||
|
krb5_int16 type,
|
||||||
|
krb5_ui_2 length,
|
||||||
|
const krb5_octet *data);
|
||||||
|
|
||||||
struct ipadb_multires;
|
struct ipadb_multires;
|
||||||
krb5_error_code ipadb_multires_init(LDAP *lcontext, struct ipadb_multires **r);
|
krb5_error_code ipadb_multires_init(LDAP *lcontext, struct ipadb_multires **r);
|
||||||
void ipadb_multires_free(struct ipadb_multires *r);
|
void ipadb_multires_free(struct ipadb_multires *r);
|
||||||
@@ -309,6 +344,7 @@ krb5_error_code ipadb_get_pwd_expiration(krb5_context context,
|
|||||||
|
|
||||||
/* MS-PAC FUNCTIONS */
|
/* MS-PAC FUNCTIONS */
|
||||||
|
|
||||||
|
#if (KRB5_KDB_DAL_MAJOR_VERSION < 9)
|
||||||
krb5_error_code ipadb_sign_authdata(krb5_context context,
|
krb5_error_code ipadb_sign_authdata(krb5_context context,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
krb5_const_principal client_princ,
|
krb5_const_principal client_princ,
|
||||||
@@ -323,6 +359,18 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
|
|||||||
krb5_authdata **tgt_auth_data,
|
krb5_authdata **tgt_auth_data,
|
||||||
krb5_authdata ***signed_auth_data);
|
krb5_authdata ***signed_auth_data);
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* DAL 9 or later uses issue_pac */
|
||||||
|
krb5_error_code ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
|
||||||
|
krb5_db_entry *client,
|
||||||
|
krb5_keyblock *replaced_reply_key,
|
||||||
|
krb5_db_entry *server,
|
||||||
|
krb5_db_entry *signing_krbtgt,
|
||||||
|
krb5_timestamp authtime, krb5_pac old_pac,
|
||||||
|
krb5_pac new_pac,
|
||||||
|
krb5_data ***auth_indicators);
|
||||||
|
#endif
|
||||||
|
|
||||||
krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit);
|
krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit);
|
||||||
|
|
||||||
void ipadb_mspac_struct_free(struct ipadb_mspac **mspac);
|
void ipadb_mspac_struct_free(struct ipadb_mspac **mspac);
|
||||||
@@ -345,6 +393,12 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
|
|||||||
const krb5_db_entry *server,
|
const krb5_db_entry *server,
|
||||||
krb5_const_principal proxy);
|
krb5_const_principal proxy);
|
||||||
|
|
||||||
|
krb5_error_code ipadb_allowed_to_delegate_from(krb5_context context,
|
||||||
|
krb5_const_principal client,
|
||||||
|
krb5_const_principal server,
|
||||||
|
krb5_pac server_pac,
|
||||||
|
const krb5_db_entry *proxy);
|
||||||
|
|
||||||
/* AS AUDIT */
|
/* AS AUDIT */
|
||||||
|
|
||||||
void ipadb_audit_as_req(krb5_context kcontext,
|
void ipadb_audit_as_req(krb5_context kcontext,
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ static krb5_error_code ipa_get_init_data(krb5_context kcontext,
|
|||||||
char *map_rule = NULL;
|
char *map_rule = NULL;
|
||||||
char *match_rule = NULL;
|
char *match_rule = NULL;
|
||||||
char **domains = NULL;
|
char **domains = NULL;
|
||||||
|
bool rule_added = false;
|
||||||
|
|
||||||
const char *certmap_attrs[] = { OBJECTCLASS,
|
const char *certmap_attrs[] = { OBJECTCLASS,
|
||||||
IPA_CERTMAP_PRIORITY,
|
IPA_CERTMAP_PRIORITY,
|
||||||
@@ -171,13 +172,7 @@ static krb5_error_code ipa_get_init_data(krb5_context kcontext,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kerr == KRB5_KDB_NOENTRY) {
|
if (kerr != KRB5_KDB_NOENTRY) {
|
||||||
ret = sss_certmap_add_rule(ctx, SSS_CERTMAP_MIN_PRIO,
|
|
||||||
NULL, NULL, NULL);
|
|
||||||
if (ret != 0) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lc = ipactx->lcontext;
|
lc = ipactx->lcontext;
|
||||||
|
|
||||||
for (le = ldap_first_entry(lc, result); le;
|
for (le = ldap_first_entry(lc, result); le;
|
||||||
@@ -221,8 +216,33 @@ static krb5_error_code ipa_get_init_data(krb5_context kcontext,
|
|||||||
ret = sss_certmap_add_rule(ctx, prio, match_rule, map_rule,
|
ret = sss_certmap_add_rule(ctx, prio, match_rule, map_rule,
|
||||||
(const char **) domains);
|
(const char **) domains);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto done;
|
krb5_klog_syslog(LOG_ERR,
|
||||||
|
"Failed to add certificate mapping [%s] and "
|
||||||
|
"matching [%s] rule with error [%d][%s], "
|
||||||
|
"skipping. Please check for typos and if rule "
|
||||||
|
"syntax is supported.", map_rule, match_rule,
|
||||||
|
ret, strerror(ret));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule_added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rule_added) {
|
||||||
|
if (kerr == KRB5_KDB_NOENTRY) {
|
||||||
|
krb5_klog_syslog(LOG_INFO,
|
||||||
|
"No certificate mapping and matching rule "
|
||||||
|
"defined, trying to use the default rule.");
|
||||||
|
} else {
|
||||||
|
krb5_klog_syslog(LOG_INFO,
|
||||||
|
"No valid certificate mapping and matching rule "
|
||||||
|
"found, trying to use the default rule.");
|
||||||
|
}
|
||||||
|
ret = sss_certmap_add_rule(ctx, SSS_CERTMAP_MIN_PRIO,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,12 +158,75 @@ static bool ipadb_need_retry(struct ipadb_context *ipactx, int error)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *no_attrs[] = {
|
||||||
|
LDAP_NO_ATTRS,
|
||||||
|
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
should_support_pac_tkt_sign(struct ipadb_context *ipactx, bool *result)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
LDAPMessage *res = NULL;
|
||||||
|
char *masters_dn = NULL;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
char *kdc_filter = "(&(cn=KDC)(objectClass=ipaConfigObject)"
|
||||||
|
"(!(ipaConfigString=pacTktSignSupported)))";
|
||||||
|
|
||||||
|
if (!ipactx) {
|
||||||
|
ret = KRB5_KDB_DBNOTINITED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = asprintf(&masters_dn, "cn=masters,cn=ipa,cn=etc,%s", ipactx->base);
|
||||||
|
if (count < 0) {
|
||||||
|
ret = ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ipadb_simple_search(ipactx, masters_dn, LDAP_SCOPE_SUBTREE,
|
||||||
|
kdc_filter, no_attrs, &res);
|
||||||
|
if (ret)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
count = ldap_count_entries(ipactx->lcontext, res);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
*result = (count == 0);
|
||||||
|
|
||||||
|
done:
|
||||||
|
free(masters_dn);
|
||||||
|
ldap_msgfree(res);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int ipadb_check_connection(struct ipadb_context *ipactx)
|
static int ipadb_check_connection(struct ipadb_context *ipactx)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (ipactx->lcontext == NULL) {
|
if (ipactx->lcontext == NULL) {
|
||||||
return ipadb_get_connection(ipactx);
|
ret = ipadb_get_connection(ipactx);
|
||||||
}
|
}
|
||||||
return 0;
|
if ((ret == 0) && (ipactx->optional_pac_tkt_chksum == IPADB_TRISTATE_UNDEFINED)) {
|
||||||
|
bool pac_tkt_sign_supported;
|
||||||
|
|
||||||
|
/* Enforce PAC ticket signature verification if supported by all KDCs
|
||||||
|
* To avoid loops as all search functions call into
|
||||||
|
* ipadb_check_connection(), mark that the init is complete at this
|
||||||
|
* point. Default to not issuing PAC to be safe.
|
||||||
|
*/
|
||||||
|
ipactx->optional_pac_tkt_chksum = IPADB_TRISTATE_FALSE;
|
||||||
|
ret = should_support_pac_tkt_sign(ipactx,
|
||||||
|
&pac_tkt_sign_supported);
|
||||||
|
if (ret == 0) {
|
||||||
|
ipactx->optional_pac_tkt_chksum = !pac_tkt_sign_supported;
|
||||||
|
} else {
|
||||||
|
ipactx->optional_pac_tkt_chksum = IPADB_TRISTATE_UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code ipadb_simple_search(struct ipadb_context *ipactx,
|
krb5_error_code ipadb_simple_search(struct ipadb_context *ipactx,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ static krb5_error_code ipadb_get_delegation_acl(krb5_context kcontext,
|
|||||||
{
|
{
|
||||||
struct ipadb_context *ipactx;
|
struct ipadb_context *ipactx;
|
||||||
krb5_error_code kerr;
|
krb5_error_code kerr;
|
||||||
char *filter = NULL;
|
char *filter = NULL, *basedn = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ipactx = ipadb_get_context(kcontext);
|
ipactx = ipadb_get_context(kcontext);
|
||||||
@@ -58,12 +58,20 @@ static krb5_error_code ipadb_get_delegation_acl(krb5_context kcontext,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = asprintf(&basedn,
|
||||||
|
"cn=s4u2proxy,cn=etc,%s", ipactx->base);
|
||||||
|
if (ret == -1) {
|
||||||
|
kerr = ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* == Search ACL info == */
|
/* == Search ACL info == */
|
||||||
kerr = ipadb_deref_search(ipactx, ipactx->base,
|
kerr = ipadb_deref_search(ipactx, basedn,
|
||||||
LDAP_SCOPE_SUBTREE, filter, acl_attrs,
|
LDAP_SCOPE_SUBTREE, filter, acl_attrs,
|
||||||
search_attrs, acl_attrs, results);
|
search_attrs, acl_attrs, results);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
free(basedn);
|
||||||
free(filter);
|
free(filter);
|
||||||
return kerr;
|
return kerr;
|
||||||
}
|
}
|
||||||
@@ -106,6 +114,8 @@ static krb5_error_code ipadb_match_acl(krb5_context kcontext,
|
|||||||
bool client_missing;
|
bool client_missing;
|
||||||
bool client_found;
|
bool client_found;
|
||||||
bool target_found;
|
bool target_found;
|
||||||
|
bool is_constraint_delegation = false;
|
||||||
|
size_t nrules = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ipactx = ipadb_get_context(kcontext);
|
ipactx = ipadb_get_context(kcontext);
|
||||||
@@ -113,13 +123,17 @@ static krb5_error_code ipadb_match_acl(krb5_context kcontext,
|
|||||||
return KRB5_KDB_DBNOTINITED;
|
return KRB5_KDB_DBNOTINITED;
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = krb5_unparse_name(kcontext, client, &client_princ);
|
if ((client != NULL) && (target != NULL)) {
|
||||||
if (kerr != 0) {
|
kerr = krb5_unparse_name(kcontext, client, &client_princ);
|
||||||
goto done;
|
if (kerr != 0) {
|
||||||
}
|
goto done;
|
||||||
kerr = krb5_unparse_name(kcontext, target, &target_princ);
|
}
|
||||||
if (kerr != 0) {
|
kerr = krb5_unparse_name(kcontext, target, &target_princ);
|
||||||
goto done;
|
if (kerr != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
is_constraint_delegation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lentry = ldap_first_entry(ipactx->lcontext, results);
|
lentry = ldap_first_entry(ipactx->lcontext, results);
|
||||||
@@ -142,6 +156,25 @@ static krb5_error_code ipadb_match_acl(krb5_context kcontext,
|
|||||||
switch (ret) {
|
switch (ret) {
|
||||||
case 0:
|
case 0:
|
||||||
for (dres = deref_results; dres; dres = dres->next) {
|
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 &&
|
if (client_found == false &&
|
||||||
strcasecmp(dres->derefAttr, "ipaAllowToImpersonate") == 0) {
|
strcasecmp(dres->derefAttr, "ipaAllowToImpersonate") == 0) {
|
||||||
/* NOTE: client_missing is used to signal that the
|
/* NOTE: client_missing is used to signal that the
|
||||||
@@ -175,6 +208,10 @@ static krb5_error_code ipadb_match_acl(krb5_context kcontext,
|
|||||||
lentry = ldap_next_entry(ipactx->lcontext, lentry);
|
lentry = ldap_next_entry(ipactx->lcontext, lentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nrules > 0) {
|
||||||
|
kerr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
krb5_free_unparsed_name(kcontext, client_princ);
|
krb5_free_unparsed_name(kcontext, client_princ);
|
||||||
krb5_free_unparsed_name(kcontext, target_princ);
|
krb5_free_unparsed_name(kcontext, target_princ);
|
||||||
@@ -196,33 +233,35 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
|
|||||||
struct ipadb_e_data *ied_server, *ied_proxy;
|
struct ipadb_e_data *ied_server, *ied_proxy;
|
||||||
LDAPMessage *res = NULL;
|
LDAPMessage *res = NULL;
|
||||||
|
|
||||||
/* Handle the case where server == proxy, this is allowed in S4U*/
|
if (proxy != NULL) {
|
||||||
kerr = ipadb_get_principal(kcontext, proxy,
|
/* Handle the case where server == proxy, this is allowed in S4U */
|
||||||
KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY,
|
kerr = ipadb_get_principal(kcontext, proxy,
|
||||||
&proxy_entry);
|
CLIENT_REFERRALS_FLAGS,
|
||||||
if (kerr) {
|
&proxy_entry);
|
||||||
goto done;
|
if (kerr) {
|
||||||
}
|
|
||||||
|
|
||||||
ied_server = (struct ipadb_e_data *) server->e_data;
|
|
||||||
ied_proxy = (struct ipadb_e_data *) proxy_entry->e_data;
|
|
||||||
|
|
||||||
/* If we have SIDs for both entries, compare SIDs */
|
|
||||||
if ((ied_server->has_sid && ied_server->sid != NULL) &&
|
|
||||||
(ied_proxy->has_sid && ied_proxy->sid != NULL)) {
|
|
||||||
|
|
||||||
if (dom_sid_check(ied_server->sid, ied_proxy->sid, true)) {
|
|
||||||
kerr = 0;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, compare entry DNs */
|
ied_server = (struct ipadb_e_data *) server->e_data;
|
||||||
kerr = ulc_casecmp(ied_server->entry_dn, strlen(ied_server->entry_dn),
|
ied_proxy = (struct ipadb_e_data *) proxy_entry->e_data;
|
||||||
ied_proxy->entry_dn, strlen(ied_proxy->entry_dn),
|
|
||||||
NULL, NULL, &result);
|
/* If we have SIDs for both entries, compare SIDs */
|
||||||
if (kerr == 0 && result == 0) {
|
if ((ied_server->has_sid && ied_server->sid != NULL) &&
|
||||||
goto done;
|
(ied_proxy->has_sid && ied_proxy->sid != NULL)) {
|
||||||
|
|
||||||
|
if (dom_sid_check(ied_server->sid, ied_proxy->sid, true)) {
|
||||||
|
kerr = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, compare entry DNs */
|
||||||
|
kerr = ulc_casecmp(ied_server->entry_dn, strlen(ied_server->entry_dn),
|
||||||
|
ied_proxy->entry_dn, strlen(ied_proxy->entry_dn),
|
||||||
|
NULL, NULL, &result);
|
||||||
|
if (kerr == 0 && result == 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = krb5_unparse_name(kcontext, server->princ, &srv_principal);
|
kerr = krb5_unparse_name(kcontext, server->princ, &srv_principal);
|
||||||
@@ -241,8 +280,56 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if (kerr) {
|
||||||
|
#if KRB5_KDB_DAL_MAJOR_VERSION < 9
|
||||||
|
kerr = KRB5KDC_ERR_POLICY;
|
||||||
|
#else
|
||||||
|
kerr = KRB5KDC_ERR_BADOPTION;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
ipadb_free_principal(kcontext, proxy_entry);
|
ipadb_free_principal(kcontext, proxy_entry);
|
||||||
krb5_free_unparsed_name(kcontext, srv_principal);
|
krb5_free_unparsed_name(kcontext, srv_principal);
|
||||||
ldap_msgfree(res);
|
ldap_msgfree(res);
|
||||||
return kerr;
|
return kerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
krb5_error_code ipadb_allowed_to_delegate_from(krb5_context context,
|
||||||
|
krb5_const_principal client,
|
||||||
|
krb5_const_principal server,
|
||||||
|
krb5_pac server_pac,
|
||||||
|
const krb5_db_entry *proxy)
|
||||||
|
{
|
||||||
|
char **acl_list = NULL;
|
||||||
|
krb5_error_code kerr;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
kerr = ipadb_get_tl_data((krb5_db_entry *) proxy, KRB5_TL_CONSTRAINED_DELEGATION_ACL,
|
||||||
|
sizeof(acl_list), (krb5_octet *)&acl_list);
|
||||||
|
|
||||||
|
if (kerr != 0 && kerr != ENOENT) {
|
||||||
|
return KRB5KDC_ERR_BADOPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kerr == ENOENT) {
|
||||||
|
return KRB5_PLUGIN_OP_NOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
kerr = KRB5KDC_ERR_BADOPTION;
|
||||||
|
if (acl_list != NULL) {
|
||||||
|
krb5_principal acl;
|
||||||
|
for (i = 0; acl_list[i] != NULL; i++) {
|
||||||
|
if (krb5_parse_name(context, acl_list[i], &acl) != 0)
|
||||||
|
continue;
|
||||||
|
if ((server == NULL) ||
|
||||||
|
(krb5_principal_compare(context, server, acl) == TRUE)) {
|
||||||
|
kerr = 0;
|
||||||
|
krb5_free_principal(context, acl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
krb5_free_principal(context, acl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return kerr;
|
||||||
|
}
|
||||||
@@ -143,6 +143,15 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_IDP]);
|
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_IDP]);
|
||||||
|
} else if (strcmp(auth_indicator, "passkey") == 0) {
|
||||||
|
valid_auth_indicators++;
|
||||||
|
/* Allow hardened even if only password pre-auth is allowed */
|
||||||
|
if (!(ua & IPADB_USER_AUTH_PASSKEY)) {
|
||||||
|
*status = "Passkey pre-authentication not allowed for this user.";
|
||||||
|
kerr = KRB5KDC_ERR_POLICY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_PASSKEY]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+193
-140
@@ -401,31 +401,34 @@ static krb5_error_code ipadb_add_asserted_identity(struct ipadb_context *ipactx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_master_host(struct ipadb_context *ipactx, const char *fqdn)
|
static krb5_error_code
|
||||||
|
is_master_host(struct ipadb_context *ipactx, const char *fqdn, bool *result)
|
||||||
{
|
{
|
||||||
int ret;
|
int err;
|
||||||
char *master_host_base = NULL;
|
char *master_host_base = NULL;
|
||||||
LDAPMessage *result = NULL;
|
LDAPMessage *ldap_res = NULL;
|
||||||
krb5_error_code err;
|
|
||||||
|
|
||||||
ret = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s",
|
err = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s",
|
||||||
fqdn, ipactx->base);
|
fqdn, ipactx->base);
|
||||||
if (ret == -1) {
|
if (err == -1)
|
||||||
return false;
|
return ENOMEM;
|
||||||
}
|
|
||||||
err = ipadb_simple_search(ipactx, master_host_base, LDAP_SCOPE_BASE,
|
|
||||||
NULL, NULL, &result);
|
|
||||||
free(master_host_base);
|
|
||||||
ldap_msgfree(result);
|
|
||||||
if (err == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
err = ipadb_simple_search(ipactx, master_host_base, LDAP_SCOPE_BASE,
|
||||||
|
NULL, NULL, &ldap_res);
|
||||||
|
free(master_host_base);
|
||||||
|
ldap_msgfree(ldap_res);
|
||||||
|
if (err != KRB5_KDB_NOENTRY && err != 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
*result = err != KRB5_KDB_NOENTRY;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||||
LDAPMessage *lentry,
|
LDAPMessage *lentry,
|
||||||
|
LDAPMessage *sentry,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
TALLOC_CTX *memctx,
|
TALLOC_CTX *memctx,
|
||||||
krb5_timestamp authtime,
|
krb5_timestamp authtime,
|
||||||
@@ -565,7 +568,20 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
|||||||
unix_to_nt_time(&info3->base.last_password_change, timeres);
|
unix_to_nt_time(&info3->base.last_password_change, timeres);
|
||||||
break;
|
break;
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
info3->base.last_password_change = 0;
|
/* If second entry is present, use Kerberos attributes from it */
|
||||||
|
if (sentry != NULL) {
|
||||||
|
ret = ipadb_ldap_attr_to_time_t(ipactx->lcontext, sentry,
|
||||||
|
"krbLastPwdChange", &timeres);
|
||||||
|
switch (ret) {
|
||||||
|
case 0:
|
||||||
|
unix_to_nt_time(&info3->base.last_password_change, timeres);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info3->base.last_password_change = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return ret;
|
return ret;
|
||||||
@@ -678,9 +694,14 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
|||||||
if ((is_host || is_service)) {
|
if ((is_host || is_service)) {
|
||||||
/* it is either host or service, so get the hostname first */
|
/* it is either host or service, so get the hostname first */
|
||||||
char *sep = strchr(info3->base.account_name.string, '/');
|
char *sep = strchr(info3->base.account_name.string, '/');
|
||||||
bool is_master = is_master_host(
|
bool is_master;
|
||||||
ipactx,
|
|
||||||
sep ? sep + 1 : info3->base.account_name.string);
|
ret = is_master_host(ipactx,
|
||||||
|
sep ? sep + 1 : info3->base.account_name.string,
|
||||||
|
&is_master);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (is_master) {
|
if (is_master) {
|
||||||
/* Well known RID of domain controllers group */
|
/* Well known RID of domain controllers group */
|
||||||
if (info3->base.rid == 0) {
|
if (info3->base.rid == 0) {
|
||||||
@@ -983,16 +1004,18 @@ static krb5_error_code ipadb_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
||||||
krb5_db_entry *client,
|
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
krb5_db_entry *client,
|
||||||
|
krb5_db_entry *server,
|
||||||
|
krb5_keyblock *replaced_reply_key,
|
||||||
krb5_timestamp authtime,
|
krb5_timestamp authtime,
|
||||||
krb5_pac *pac)
|
krb5_pac *pac)
|
||||||
{
|
{
|
||||||
TALLOC_CTX *tmpctx;
|
TALLOC_CTX *tmpctx;
|
||||||
struct ipadb_e_data *ied;
|
struct ipadb_e_data *ied;
|
||||||
struct ipadb_context *ipactx;
|
struct ipadb_context *ipactx;
|
||||||
LDAPMessage *results = NULL;
|
LDAPMessage *results = NULL, *sresults = NULL;
|
||||||
LDAPMessage *lentry;
|
LDAPMessage *lentry = NULL, *sentry = NULL;
|
||||||
DATA_BLOB pac_data;
|
DATA_BLOB pac_data;
|
||||||
krb5_data data;
|
krb5_data data;
|
||||||
union PAC_INFO pac_info;
|
union PAC_INFO pac_info;
|
||||||
@@ -1048,9 +1071,40 @@ krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
bool is_trust_krbtgt;
|
||||||
|
|
||||||
|
/* Trusted domain objects are part of cn=ad,cn=trusts,$BASEDN subtree.
|
||||||
|
* Anchor the search string with ',dc=' to prevent matching anything else.
|
||||||
|
* This is to avoid a string allocation with expanded base DN. */
|
||||||
|
is_trust_krbtgt = strstr(ied->entry_dn, ",cn=ad,cn=trusts,dc=") != NULL;
|
||||||
|
|
||||||
|
if (is_trust_krbtgt) {
|
||||||
|
char *sentry_dn = strchr(ied->entry_dn, ',');
|
||||||
|
if (sentry_dn != NULL) {
|
||||||
|
/* skipped "krbprincipalname=krbtgt/SOME-REALM@AT-REALM," */
|
||||||
|
sentry_dn++;
|
||||||
|
kerr = ipadb_deref_search(ipactx, sentry_dn, LDAP_SCOPE_BASE,
|
||||||
|
"(objectclass=*)", user_pac_attrs,
|
||||||
|
deref_search_attrs, memberof_pac_attrs,
|
||||||
|
&sresults);
|
||||||
|
if (kerr) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
sentry = ldap_first_entry(ipactx->lcontext, sresults);
|
||||||
|
if (!sentry) {
|
||||||
|
kerr = ENOENT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* == Fill Info3 == */
|
/* == Fill Info3 == */
|
||||||
kerr = ipadb_fill_info3(ipactx, lentry, flags, tmpctx, authtime,
|
kerr = ipadb_fill_info3(ipactx, sentry ? sentry : lentry, sentry ? lentry : NULL,
|
||||||
&pac_info.logon_info.info->info3);
|
flags, tmpctx, authtime, &pac_info.logon_info.info->info3);
|
||||||
if (kerr) {
|
if (kerr) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -1064,9 +1118,13 @@ krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = krb5_pac_init(kcontext, pac);
|
/* krb5 1.20+ passes in a pre-created PAC structure but for previous
|
||||||
if (kerr) {
|
* versions we have to create it ourselves */
|
||||||
goto done;
|
if (pac != NULL && *pac == NULL) {
|
||||||
|
kerr = krb5_pac_init(kcontext, pac);
|
||||||
|
if (kerr) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.magic = KV5M_DATA;
|
data.magic = KV5M_DATA;
|
||||||
@@ -1149,7 +1207,7 @@ krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
|||||||
|
|
||||||
#ifdef HAVE_PAC_REQUESTER_SID
|
#ifdef HAVE_PAC_REQUESTER_SID
|
||||||
/* MS-KILE 3.3.5.6.4.8: add PAC_REQUESTER_SID only in TGT case */
|
/* MS-KILE 3.3.5.6.4.8: add PAC_REQUESTER_SID only in TGT case */
|
||||||
if ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0) {
|
if (flags & CLIENT_REFERRALS_FLAGS) {
|
||||||
union PAC_INFO pac_requester_sid;
|
union PAC_INFO pac_requester_sid;
|
||||||
/* == Package PAC_REQUESTER_SID == */
|
/* == Package PAC_REQUESTER_SID == */
|
||||||
memset(&pac_requester_sid, 0, sizeof(pac_requester_sid));
|
memset(&pac_requester_sid, 0, sizeof(pac_requester_sid));
|
||||||
@@ -1177,6 +1235,9 @@ krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
ldap_msgfree(results);
|
ldap_msgfree(results);
|
||||||
|
if (sresults != NULL) {
|
||||||
|
ldap_msgfree(sresults);
|
||||||
|
}
|
||||||
talloc_free(tmpctx);
|
talloc_free(tmpctx);
|
||||||
return kerr;
|
return kerr;
|
||||||
}
|
}
|
||||||
@@ -1553,7 +1614,7 @@ static krb5_error_code save_logon_info(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context,
|
static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context,
|
||||||
krb5_data realm)
|
krb5_data *realm)
|
||||||
{
|
{
|
||||||
struct ipadb_context *ipactx;
|
struct ipadb_context *ipactx;
|
||||||
struct ipadb_adtrusts *domain;
|
struct ipadb_adtrusts *domain;
|
||||||
@@ -1570,10 +1631,10 @@ static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context,
|
|||||||
|
|
||||||
for (i = 0; i < ipactx->mspac->num_trusts; i++) {
|
for (i = 0; i < ipactx->mspac->num_trusts; i++) {
|
||||||
domain = &ipactx->mspac->trusts[i];
|
domain = &ipactx->mspac->trusts[i];
|
||||||
if (strlen(domain->domain_name) != realm.length) {
|
if (strlen(domain->domain_name) != realm->length) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strncasecmp(domain->domain_name, realm.data, realm.length) == 0) {
|
if (strncasecmp(domain->domain_name, realm->data, realm->length) == 0) {
|
||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1582,7 +1643,7 @@ static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context,
|
static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context,
|
||||||
krb5_data realm)
|
krb5_data *realm)
|
||||||
{
|
{
|
||||||
struct ipadb_context *ipactx;
|
struct ipadb_context *ipactx;
|
||||||
struct ipadb_adtrusts *domain;
|
struct ipadb_adtrusts *domain;
|
||||||
@@ -1637,7 +1698,7 @@ static void filter_logon_info_log_message_rid(struct dom_sid *sid, uint32_t rid)
|
|||||||
|
|
||||||
static krb5_error_code check_logon_info_consistent(krb5_context context,
|
static krb5_error_code check_logon_info_consistent(krb5_context context,
|
||||||
TALLOC_CTX *memctx,
|
TALLOC_CTX *memctx,
|
||||||
krb5_const_principal client_princ,
|
krb5_db_entry *client,
|
||||||
krb5_boolean is_s4u,
|
krb5_boolean is_s4u,
|
||||||
struct PAC_LOGON_INFO_CTR *info)
|
struct PAC_LOGON_INFO_CTR *info)
|
||||||
{
|
{
|
||||||
@@ -1645,7 +1706,6 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
|
|||||||
struct ipadb_context *ipactx;
|
struct ipadb_context *ipactx;
|
||||||
bool result;
|
bool result;
|
||||||
bool is_from_trusted_domain = false;
|
bool is_from_trusted_domain = false;
|
||||||
krb5_db_entry *client_actual = NULL;
|
|
||||||
struct ipadb_e_data *ied = NULL;
|
struct ipadb_e_data *ied = NULL;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
struct dom_sid client_sid;
|
struct dom_sid client_sid;
|
||||||
@@ -1701,18 +1761,12 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_s4u && is_from_trusted_domain) {
|
if (client == NULL || (is_s4u && is_from_trusted_domain)) {
|
||||||
/* If the PAC belongs to a user from the trusted domain, we cannot compare SIDs */
|
/* If the PAC belongs to a user from the trusted domain, we cannot compare SIDs */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = ipadb_get_principal(context, client_princ, flags, &client_actual);
|
ied = (struct ipadb_e_data *)client->e_data;
|
||||||
if (kerr != 0) {
|
|
||||||
krb5_klog_syslog(LOG_ERR, "PAC issue: ipadb_get_principal failed.");
|
|
||||||
return KRB5KDC_ERR_TGT_REVOKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ied = (struct ipadb_e_data *)client_actual->e_data;
|
|
||||||
if (ied == NULL || ied->magic != IPA_E_DATA_MAGIC) {
|
if (ied == NULL || ied->magic != IPA_E_DATA_MAGIC) {
|
||||||
krb5_klog_syslog(LOG_ERR, "PAC issue: client e_data fetching failed.");
|
krb5_klog_syslog(LOG_ERR, "PAC issue: client e_data fetching failed.");
|
||||||
kerr = EINVAL;
|
kerr = EINVAL;
|
||||||
@@ -1748,14 +1802,12 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
ipadb_free_principal(context, client_actual);
|
|
||||||
|
|
||||||
return kerr;
|
return kerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code filter_logon_info(krb5_context context,
|
krb5_error_code filter_logon_info(krb5_context context,
|
||||||
TALLOC_CTX *memctx,
|
TALLOC_CTX *memctx,
|
||||||
krb5_data realm,
|
krb5_data *realm,
|
||||||
struct PAC_LOGON_INFO_CTR *info)
|
struct PAC_LOGON_INFO_CTR *info)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1782,11 +1834,43 @@ krb5_error_code filter_logon_info(krb5_context context,
|
|||||||
bool result;
|
bool result;
|
||||||
char *domstr = NULL;
|
char *domstr = NULL;
|
||||||
|
|
||||||
|
ipactx = ipadb_get_context(context);
|
||||||
|
if (!ipactx || !ipactx->mspac) {
|
||||||
|
return KRB5_KDB_DBNOTINITED;
|
||||||
|
}
|
||||||
|
|
||||||
domain = get_domain_from_realm_update(context, realm);
|
domain = get_domain_from_realm_update(context, realm);
|
||||||
if (!domain) {
|
if (!domain) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check exact sid */
|
||||||
|
result = dom_sid_check(&domain->domsid, info->info->info3.base.domain_sid, true);
|
||||||
|
if (!result) {
|
||||||
|
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 (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[k];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
domstr = dom_sid_string(NULL, info->info->info3.base.domain_sid);
|
||||||
|
krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, "
|
||||||
|
"expected domain SID = %s, "
|
||||||
|
"found domain SID = %s",
|
||||||
|
domain->domain_name, domain->domain_sid,
|
||||||
|
domstr ? domstr : "<failed to display>");
|
||||||
|
talloc_free(domstr);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point we may have changed the domain we look at, */
|
||||||
/* check netbios/flat name */
|
/* check netbios/flat name */
|
||||||
if (strcasecmp(info->info->info3.base.logon_domain.string,
|
if (strcasecmp(info->info->info3.base.logon_domain.string,
|
||||||
domain->flat_name) != 0) {
|
domain->flat_name) != 0) {
|
||||||
@@ -1798,21 +1882,6 @@ krb5_error_code filter_logon_info(krb5_context context,
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check exact sid */
|
|
||||||
result = dom_sid_check(&domain->domsid, info->info->info3.base.domain_sid, true);
|
|
||||||
if (!result) {
|
|
||||||
domstr = dom_sid_string(NULL, info->info->info3.base.domain_sid);
|
|
||||||
if (!domstr) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, "
|
|
||||||
"expected domain SID = %s, "
|
|
||||||
"found domain SID = %s",
|
|
||||||
domain->domain_name, domain->domain_sid, domstr);
|
|
||||||
talloc_free(domstr);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if this domain has been filtered out by the trust itself*/
|
/* Check if this domain has been filtered out by the trust itself*/
|
||||||
if (domain->parent != NULL) {
|
if (domain->parent != NULL) {
|
||||||
for(k = 0; k < domain->parent->len_sid_blocklist_incoming; k++) {
|
for(k = 0; k < domain->parent->len_sid_blocklist_incoming; k++) {
|
||||||
@@ -1899,10 +1968,6 @@ krb5_error_code filter_logon_info(krb5_context context,
|
|||||||
* should include different possibilities into account
|
* should include different possibilities into account
|
||||||
* */
|
* */
|
||||||
if (info->info->info3.sidcount != 0) {
|
if (info->info->info3.sidcount != 0) {
|
||||||
ipactx = ipadb_get_context(context);
|
|
||||||
if (!ipactx || !ipactx->mspac) {
|
|
||||||
return KRB5_KDB_DBNOTINITED;
|
|
||||||
}
|
|
||||||
count = info->info->info3.sidcount;
|
count = info->info->info3.sidcount;
|
||||||
i = 0;
|
i = 0;
|
||||||
j = 0;
|
j = 0;
|
||||||
@@ -1980,7 +2045,8 @@ krb5_error_code filter_logon_info(krb5_context context,
|
|||||||
|
|
||||||
|
|
||||||
static krb5_error_code ipadb_check_logon_info(krb5_context context,
|
static krb5_error_code ipadb_check_logon_info(krb5_context context,
|
||||||
krb5_const_principal client_princ,
|
krb5_db_entry *client,
|
||||||
|
krb5_db_entry *signing_krbtgt,
|
||||||
krb5_boolean is_cross_realm,
|
krb5_boolean is_cross_realm,
|
||||||
krb5_boolean is_s4u,
|
krb5_boolean is_s4u,
|
||||||
krb5_data *pac_blob,
|
krb5_data *pac_blob,
|
||||||
@@ -1989,7 +2055,7 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
|
|||||||
struct PAC_LOGON_INFO_CTR info;
|
struct PAC_LOGON_INFO_CTR info;
|
||||||
krb5_error_code kerr;
|
krb5_error_code kerr;
|
||||||
TALLOC_CTX *tmpctx;
|
TALLOC_CTX *tmpctx;
|
||||||
krb5_data origin_realm = client_princ->realm;
|
krb5_data origin_realm = {0};
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
tmpctx = talloc_new(NULL);
|
tmpctx = talloc_new(NULL);
|
||||||
@@ -2017,12 +2083,12 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
|
|||||||
return KRB5_KDB_DBNOTINITED;
|
return KRB5_KDB_DBNOTINITED;
|
||||||
}
|
}
|
||||||
/* In S4U case we might be dealing with the PAC issued by the trusted domain */
|
/* In S4U case we might be dealing with the PAC issued by the trusted domain */
|
||||||
if (is_s4u && (ipactx->mspac->trusts != NULL)) {
|
if ((ipactx->mspac->trusts != NULL)) {
|
||||||
/* Iterate through list of trusts and check if this SID belongs to
|
/* Iterate through list of trusts and check if this SID belongs to
|
||||||
* one of the domains we trust */
|
* one of the domains we trust */
|
||||||
for(int 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,
|
result = dom_sid_check(&ipactx->mspac->trusts[i].domsid,
|
||||||
requester_sid, false);
|
&client_sid, false);
|
||||||
if (result) {
|
if (result) {
|
||||||
is_from_trusted_domain = true;
|
is_from_trusted_domain = true;
|
||||||
break;
|
break;
|
||||||
@@ -2030,7 +2096,7 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_from_trusted_domain) {
|
if (!is_from_trusted_domain && !is_s4u) {
|
||||||
/* memctx is freed by the caller */
|
/* memctx is freed by the caller */
|
||||||
char *pac_sid = dom_sid_string(tmpctx, &client_sid);
|
char *pac_sid = dom_sid_string(tmpctx, &client_sid);
|
||||||
char *req_sid = dom_sid_string(tmpctx, requester_sid);
|
char *req_sid = dom_sid_string(tmpctx, requester_sid);
|
||||||
@@ -2051,11 +2117,17 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
|
|||||||
* is ours but operates on behalf of the cross-realm principal, we will
|
* is ours but operates on behalf of the cross-realm principal, we will
|
||||||
* search through the trusted domains but otherwise skip the exact SID check
|
* search through the trusted domains but otherwise skip the exact SID check
|
||||||
* as we are not responsible for the principal from the trusted domain */
|
* as we are not responsible for the principal from the trusted domain */
|
||||||
kerr = check_logon_info_consistent(context, tmpctx, client_princ, is_s4u, &info);
|
kerr = check_logon_info_consistent(context, tmpctx, client, is_s4u, &info);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = filter_logon_info(context, tmpctx, origin_realm, &info);
|
if (client != NULL) {
|
||||||
|
origin_realm = client->princ->realm;
|
||||||
|
} else {
|
||||||
|
origin_realm = signing_krbtgt->princ->realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
kerr = filter_logon_info(context, tmpctx, &origin_realm, &info);
|
||||||
if (kerr) {
|
if (kerr) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -2224,24 +2296,19 @@ done:
|
|||||||
return kerr;
|
return kerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
krb5_error_code ipadb_verify_pac(krb5_context context,
|
krb5_error_code ipadb_common_verify_pac(krb5_context context,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
krb5_const_principal client_princ,
|
krb5_db_entry *client,
|
||||||
krb5_db_entry *proxy,
|
krb5_db_entry *server,
|
||||||
krb5_db_entry *server,
|
krb5_db_entry *signing_krbtgt,
|
||||||
krb5_db_entry *krbtgt,
|
krb5_keyblock *krbtgt_key,
|
||||||
krb5_keyblock *server_key,
|
krb5_timestamp authtime,
|
||||||
krb5_keyblock *krbtgt_key,
|
krb5_pac old_pac,
|
||||||
krb5_timestamp authtime,
|
krb5_pac *pac)
|
||||||
krb5_authdata **authdata,
|
|
||||||
krb5_pac *pac)
|
|
||||||
{
|
{
|
||||||
krb5_keyblock *srv_key = NULL;
|
|
||||||
krb5_keyblock *priv_key = NULL;
|
|
||||||
krb5_error_code kerr;
|
krb5_error_code kerr;
|
||||||
krb5_ui_4 *types = NULL;
|
krb5_ui_4 *types = NULL;
|
||||||
size_t num_buffers;
|
size_t num_buffers;
|
||||||
krb5_pac old_pac = NULL;
|
|
||||||
krb5_pac new_pac = NULL;
|
krb5_pac new_pac = NULL;
|
||||||
krb5_data data;
|
krb5_data data;
|
||||||
krb5_data pac_blob = { 0 , 0, NULL};
|
krb5_data pac_blob = { 0 , 0, NULL};
|
||||||
@@ -2250,42 +2317,15 @@ krb5_error_code ipadb_verify_pac(krb5_context context,
|
|||||||
struct dom_sid *requester_sid = NULL;
|
struct dom_sid *requester_sid = NULL;
|
||||||
struct dom_sid req_sid;
|
struct dom_sid req_sid;
|
||||||
|
|
||||||
kerr = krb5_pac_parse(context,
|
if (signing_krbtgt != NULL &&
|
||||||
authdata[0]->contents,
|
ipadb_is_cross_realm_krbtgt(signing_krbtgt->princ)) {
|
||||||
authdata[0]->length,
|
|
||||||
&old_pac);
|
|
||||||
if (kerr) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* for cross realm trusts cases we need to check the right checksum.
|
|
||||||
* when the PAC is signed by our realm, we can always just check it
|
|
||||||
* passing our realm krbtgt key as the kdc checksum key (privsvr).
|
|
||||||
* But when a trusted realm passes us a PAC the kdc checksum is
|
|
||||||
* generated with that realm krbtgt key, so we need to use the cross
|
|
||||||
* realm krbtgt to check the 'server' checksum instead. */
|
|
||||||
if (ipadb_is_cross_realm_krbtgt(krbtgt->princ)) {
|
|
||||||
/* krbtgt from a trusted realm */
|
/* krbtgt from a trusted realm */
|
||||||
is_cross_realm = true;
|
is_cross_realm = true;
|
||||||
|
|
||||||
srv_key = krbtgt_key;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* krbtgt from our own realm */
|
|
||||||
priv_key = krbtgt_key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only pass with_realm TRUE when it is cross-realm ticket and S4U
|
/* In krb5 1.20+ the PAC signatures are verified prior to call to issue_pac().
|
||||||
* extension (S4U2Self or S4U2Proxy (RBCD)) was requested */
|
* In krb5 before 1.20, we do verify PAC signatures before ipadb_common_verify_pac().
|
||||||
kerr = krb5_pac_verify_ext(context, old_pac, authtime,
|
* Now we can do additional checks.
|
||||||
client_princ, srv_key, priv_key,
|
|
||||||
(is_cross_realm &&
|
|
||||||
(flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)));
|
|
||||||
if (kerr) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now that the PAC is verified, do additional checks.
|
|
||||||
* Augment it with additional info if it is coming from a different realm */
|
* Augment it with additional info if it is coming from a different realm */
|
||||||
kerr = krb5_pac_get_buffer(context, old_pac,
|
kerr = krb5_pac_get_buffer(context, old_pac,
|
||||||
KRB5_PAC_LOGON_INFO, &pac_blob);
|
KRB5_PAC_LOGON_INFO, &pac_blob);
|
||||||
@@ -2302,7 +2342,8 @@ krb5_error_code ipadb_verify_pac(krb5_context context,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
kerr = ipadb_check_logon_info(context,
|
kerr = ipadb_check_logon_info(context,
|
||||||
client_princ,
|
client,
|
||||||
|
signing_krbtgt,
|
||||||
is_cross_realm,
|
is_cross_realm,
|
||||||
(flags & KRB5_KDB_FLAGS_S4U),
|
(flags & KRB5_KDB_FLAGS_S4U),
|
||||||
&pac_blob,
|
&pac_blob,
|
||||||
@@ -2310,12 +2351,19 @@ krb5_error_code ipadb_verify_pac(krb5_context context,
|
|||||||
if (kerr != 0) {
|
if (kerr != 0) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* extract buffers and rebuilt pac from scratch so that when re-signing
|
|
||||||
* with a different cksum type does not cause issues due to mismatching
|
/* krb5 1.20+ passes in a pre-created PAC structure but for previous
|
||||||
* signature buffer lengths */
|
* versions we have to create it ourselves */
|
||||||
kerr = krb5_pac_init(context, &new_pac);
|
if (pac != NULL && *pac == NULL) {
|
||||||
if (kerr) {
|
/* extract buffers and rebuilt pac from scratch so that when re-signing
|
||||||
goto done;
|
* with a different cksum type does not cause issues due to mismatching
|
||||||
|
* signature buffer lengths */
|
||||||
|
kerr = krb5_pac_init(context, &new_pac);
|
||||||
|
if (kerr) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
new_pac = *pac;
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = krb5_pac_get_types(context, old_pac, &num_buffers, &types);
|
kerr = krb5_pac_get_types(context, old_pac, &num_buffers, &types);
|
||||||
@@ -2326,7 +2374,10 @@ krb5_error_code ipadb_verify_pac(krb5_context context,
|
|||||||
for (i = 0; i < num_buffers; i++) {
|
for (i = 0; i < num_buffers; i++) {
|
||||||
if (types[i] == KRB5_PAC_SERVER_CHECKSUM ||
|
if (types[i] == KRB5_PAC_SERVER_CHECKSUM ||
|
||||||
types[i] == KRB5_PAC_PRIVSVR_CHECKSUM ||
|
types[i] == KRB5_PAC_PRIVSVR_CHECKSUM ||
|
||||||
types[i] == KRB5_PAC_CLIENT_INFO) {
|
#ifdef KRB5_PAC_FULL_CHECKSUM
|
||||||
|
types[i] == KRB5_PAC_FULL_CHECKSUM ||
|
||||||
|
#endif
|
||||||
|
types[i] == KRB5_PAC_CLIENT_INFO) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2334,7 +2385,6 @@ krb5_error_code ipadb_verify_pac(krb5_context context,
|
|||||||
pac_blob.length != 0) {
|
pac_blob.length != 0) {
|
||||||
kerr = krb5_pac_add_buffer(context, new_pac, types[i], &pac_blob);
|
kerr = krb5_pac_add_buffer(context, new_pac, types[i], &pac_blob);
|
||||||
if (kerr) {
|
if (kerr) {
|
||||||
krb5_pac_free(context, new_pac);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2351,21 +2401,18 @@ krb5_error_code ipadb_verify_pac(krb5_context context,
|
|||||||
TALLOC_CTX *tmpctx = talloc_new(NULL);
|
TALLOC_CTX *tmpctx = talloc_new(NULL);
|
||||||
if (tmpctx == NULL) {
|
if (tmpctx == NULL) {
|
||||||
kerr = ENOMEM;
|
kerr = ENOMEM;
|
||||||
krb5_pac_free(context, new_pac);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = ipadb_client_requested_pac(context, old_pac, tmpctx, &pac_requested);
|
kerr = ipadb_client_requested_pac(context, old_pac, tmpctx, &pac_requested);
|
||||||
if (kerr != 0) {
|
if (kerr != 0) {
|
||||||
talloc_free(tmpctx);
|
talloc_free(tmpctx);
|
||||||
krb5_pac_free(context, new_pac);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = ipadb_get_pac_attrs_blob(tmpctx, &pac_requested, &pac_attrs_data);
|
kerr = ipadb_get_pac_attrs_blob(tmpctx, &pac_requested, &pac_attrs_data);
|
||||||
if (kerr) {
|
if (kerr) {
|
||||||
talloc_free(tmpctx);
|
talloc_free(tmpctx);
|
||||||
krb5_pac_free(context, new_pac);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
data.magic = KV5M_DATA;
|
data.magic = KV5M_DATA;
|
||||||
@@ -2375,7 +2422,6 @@ krb5_error_code ipadb_verify_pac(krb5_context context,
|
|||||||
kerr = krb5_pac_add_buffer(context, new_pac, PAC_TYPE_ATTRIBUTES_INFO, &data);
|
kerr = krb5_pac_add_buffer(context, new_pac, PAC_TYPE_ATTRIBUTES_INFO, &data);
|
||||||
if (kerr) {
|
if (kerr) {
|
||||||
talloc_free(tmpctx);
|
talloc_free(tmpctx);
|
||||||
krb5_pac_free(context, new_pac);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2395,31 +2441,35 @@ krb5_error_code ipadb_verify_pac(krb5_context context,
|
|||||||
krb5_free_data_contents(context, &data);
|
krb5_free_data_contents(context, &data);
|
||||||
}
|
}
|
||||||
if (kerr) {
|
if (kerr) {
|
||||||
krb5_pac_free(context, new_pac);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(KRB5_KDB_FLAG_CLIENT)
|
||||||
if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
|
if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
|
||||||
if (proxy == NULL) {
|
if (client == NULL) {
|
||||||
|
if (new_pac != *pac) {
|
||||||
|
krb5_pac_free(context, new_pac);
|
||||||
|
}
|
||||||
*pac = NULL;
|
*pac = NULL;
|
||||||
kerr = 0;
|
kerr = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = ipadb_add_transited_service(context, proxy, server,
|
kerr = ipadb_add_transited_service(context, client, server,
|
||||||
old_pac, new_pac);
|
old_pac, new_pac);
|
||||||
if (kerr) {
|
if (kerr) {
|
||||||
krb5_pac_free(context, new_pac);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
*pac = new_pac;
|
*pac = new_pac;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
krb5_free_authdata(context, authdata);
|
if (kerr != 0 && (new_pac != *pac)) {
|
||||||
krb5_pac_free(context, old_pac);
|
krb5_pac_free(context, new_pac);
|
||||||
|
}
|
||||||
krb5_free_data_contents(context, &pac_blob);
|
krb5_free_data_contents(context, &pac_blob);
|
||||||
free(types);
|
free(types);
|
||||||
return kerr;
|
return kerr;
|
||||||
@@ -2527,9 +2577,12 @@ void get_authz_data_types(krb5_context context, krb5_db_entry *entry,
|
|||||||
none_found = true;
|
none_found = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
krb5_klog_syslog(LOG_ERR, "Ignoring unsupported " \
|
/* for out-of-realm entries we suppress warnings in our defaults */
|
||||||
"authorization data type [%s].",
|
if (entry != NULL) {
|
||||||
authz_data_list[c]);
|
krb5_klog_syslog(LOG_ERR, "Ignoring unsupported " \
|
||||||
|
"authorization data type [%s].",
|
||||||
|
authz_data_list[c]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,24 +53,24 @@ struct ipadb_adtrusts {
|
|||||||
|
|
||||||
char *dom_sid_string(TALLOC_CTX *memctx, const struct dom_sid *dom_sid);
|
char *dom_sid_string(TALLOC_CTX *memctx, const struct dom_sid *dom_sid);
|
||||||
krb5_error_code filter_logon_info(krb5_context context, TALLOC_CTX *memctx,
|
krb5_error_code filter_logon_info(krb5_context context, TALLOC_CTX *memctx,
|
||||||
krb5_data realm, struct PAC_LOGON_INFO_CTR *info);
|
krb5_data *realm, struct PAC_LOGON_INFO_CTR *info);
|
||||||
void get_authz_data_types(krb5_context context, krb5_db_entry *entry,
|
void get_authz_data_types(krb5_context context, krb5_db_entry *entry,
|
||||||
bool *_with_pac, bool *_with_pad);
|
bool *_with_pac, bool *_with_pad);
|
||||||
|
|
||||||
bool ipadb_is_cross_realm_krbtgt(krb5_const_principal princ);
|
bool ipadb_is_cross_realm_krbtgt(krb5_const_principal princ);
|
||||||
krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
||||||
krb5_db_entry *client,
|
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
krb5_db_entry *client,
|
||||||
|
krb5_db_entry *server,
|
||||||
|
krb5_keyblock *replaced_reply_key,
|
||||||
krb5_timestamp authtime,
|
krb5_timestamp authtime,
|
||||||
krb5_pac *pac);
|
krb5_pac *pac);
|
||||||
krb5_error_code ipadb_verify_pac(krb5_context context,
|
krb5_error_code ipadb_common_verify_pac(krb5_context context,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
krb5_const_principal client_princ,
|
krb5_db_entry *client,
|
||||||
krb5_db_entry *proxy,
|
krb5_db_entry *server,
|
||||||
krb5_db_entry *server,
|
krb5_db_entry *signing_krbtgt,
|
||||||
krb5_db_entry *krbtgt,
|
krb5_keyblock *krbtgt_key,
|
||||||
krb5_keyblock *server_key,
|
krb5_timestamp authtime,
|
||||||
krb5_keyblock *krbtgt_key,
|
krb5_pac old_pac,
|
||||||
krb5_timestamp authtime,
|
krb5_pac *pac);
|
||||||
krb5_authdata **authdata,
|
|
||||||
krb5_pac *pac);
|
|
||||||
@@ -31,6 +31,68 @@
|
|||||||
|
|
||||||
#include "ipa_kdb_mspac_private.h"
|
#include "ipa_kdb_mspac_private.h"
|
||||||
|
|
||||||
|
static
|
||||||
|
krb5_error_code ipadb_verify_pac(krb5_context context,
|
||||||
|
unsigned int flags,
|
||||||
|
krb5_const_principal client_princ,
|
||||||
|
krb5_db_entry *proxy,
|
||||||
|
krb5_db_entry *server,
|
||||||
|
krb5_db_entry *krbtgt,
|
||||||
|
krb5_keyblock *server_key,
|
||||||
|
krb5_keyblock *krbtgt_key,
|
||||||
|
krb5_timestamp authtime,
|
||||||
|
krb5_authdata **authdata,
|
||||||
|
krb5_pac *pac)
|
||||||
|
{
|
||||||
|
krb5_error_code kerr;
|
||||||
|
krb5_pac old_pac = NULL;
|
||||||
|
kerr = krb5_pac_parse(context,
|
||||||
|
authdata[0]->contents,
|
||||||
|
authdata[0]->length,
|
||||||
|
&old_pac);
|
||||||
|
if (kerr == 0) {
|
||||||
|
krb5_keyblock *srv_key = NULL;
|
||||||
|
krb5_keyblock *priv_key = NULL;
|
||||||
|
bool is_cross_realm = false;
|
||||||
|
|
||||||
|
/* for cross realm trusts cases we need to check the right checksum.
|
||||||
|
* when the PAC is signed by our realm, we can always just check it
|
||||||
|
* passing our realm krbtgt key as the kdc checksum key (privsvr).
|
||||||
|
* But when a trusted realm passes us a PAC the kdc checksum is
|
||||||
|
* generated with that realm krbtgt key, so we need to use the cross
|
||||||
|
* realm krbtgt to check the 'server' checksum instead. */
|
||||||
|
if (ipadb_is_cross_realm_krbtgt(krbtgt->princ)) {
|
||||||
|
/* krbtgt from a trusted realm */
|
||||||
|
is_cross_realm = true;
|
||||||
|
srv_key = krbtgt_key;
|
||||||
|
} else {
|
||||||
|
/* krbtgt from our own realm */
|
||||||
|
priv_key = krbtgt_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only pass with_realm TRUE when it is cross-realm ticket and S4U
|
||||||
|
* extension (S4U2Self or S4U2Proxy (RBCD)) was requested */
|
||||||
|
kerr = krb5_pac_verify_ext(context, old_pac, authtime,
|
||||||
|
NULL, srv_key, priv_key,
|
||||||
|
(is_cross_realm &&
|
||||||
|
(flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)));
|
||||||
|
if (kerr) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
kerr = ipadb_common_verify_pac(context, flags,
|
||||||
|
proxy, server, krbtgt,
|
||||||
|
krbtgt_key,
|
||||||
|
authtime, old_pac, pac);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
krb5_free_authdata(context, authdata);
|
||||||
|
krb5_pac_free(context, old_pac);
|
||||||
|
return kerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static krb5_error_code ipadb_sign_pac(krb5_context context,
|
static krb5_error_code ipadb_sign_pac(krb5_context context,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
@@ -114,11 +176,21 @@ static krb5_error_code ipadb_sign_pac(krb5_context context,
|
|||||||
|
|
||||||
/* only pass with_realm TRUE when it is cross-realm ticket and S4U2Self
|
/* only pass with_realm TRUE when it is cross-realm ticket and S4U2Self
|
||||||
* was requested */
|
* was requested */
|
||||||
|
#ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
|
||||||
|
kerr = krb5_pac_full_sign_compat(
|
||||||
|
context, pac, authtime, client_princ, server->princ, server_key,
|
||||||
|
right_krbtgt_signing_key,
|
||||||
|
(is_issuing_referral && (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)),
|
||||||
|
pac_data
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
/* Use standard function, PAC extended KDC signature not supported */
|
||||||
kerr = krb5_pac_sign_ext(context, pac, authtime, client_princ, server_key,
|
kerr = krb5_pac_sign_ext(context, pac, authtime, client_princ, server_key,
|
||||||
right_krbtgt_signing_key,
|
right_krbtgt_signing_key,
|
||||||
(is_issuing_referral &&
|
(is_issuing_referral &&
|
||||||
(flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)),
|
(flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)),
|
||||||
pac_data);
|
pac_data);
|
||||||
|
#endif
|
||||||
|
|
||||||
done:
|
done:
|
||||||
free(princ);
|
free(princ);
|
||||||
@@ -239,7 +311,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
|
|||||||
|
|
||||||
(void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
|
(void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
|
||||||
|
|
||||||
kerr = ipadb_get_pac(context, client, flags, authtime, &pac);
|
kerr = ipadb_get_pac(context, flags, client, server, NULL, authtime, &pac);
|
||||||
if (kerr != 0 && kerr != ENOENT) {
|
if (kerr != 0 && kerr != ENOENT) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -253,7 +325,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
|
|||||||
/* check or generate pac data */
|
/* check or generate pac data */
|
||||||
if ((pac_auth_data == NULL) || (pac_auth_data[0] == NULL)) {
|
if ((pac_auth_data == NULL) || (pac_auth_data[0] == NULL)) {
|
||||||
if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
|
if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
|
||||||
kerr = ipadb_get_pac(context, client_entry, flags, authtime, &pac);
|
kerr = ipadb_get_pac(context, flags, client_entry, server, NULL, authtime, &pac);
|
||||||
if (kerr != 0 && kerr != ENOENT) {
|
if (kerr != 0 && kerr != ENOENT) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,4 +31,108 @@
|
|||||||
|
|
||||||
#include "ipa_kdb_mspac_private.h"
|
#include "ipa_kdb_mspac_private.h"
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
|
||||||
|
krb5_db_entry *client,
|
||||||
|
krb5_keyblock *replaced_reply_key,
|
||||||
|
krb5_db_entry *server,
|
||||||
|
krb5_db_entry *signing_krbtgt,
|
||||||
|
krb5_timestamp authtime,
|
||||||
|
krb5_pac old_pac,
|
||||||
|
krb5_pac new_pac,
|
||||||
|
krb5_data ***auth_indicators)
|
||||||
|
{
|
||||||
|
bool with_pac;
|
||||||
|
bool with_pad;
|
||||||
|
krb5_error_code kerr = 0;
|
||||||
|
bool is_as_req = flags & CLIENT_REFERRALS_FLAGS;
|
||||||
|
|
||||||
|
if (is_as_req) {
|
||||||
|
get_authz_data_types(context, client, &with_pac, &with_pad);
|
||||||
|
} else {
|
||||||
|
get_authz_data_types(context, server, &with_pac, &with_pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (with_pad) {
|
||||||
|
krb5_klog_syslog(LOG_ERR, "PAD authorization data is requested but " \
|
||||||
|
"currently not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a new PAC for AS-REQ or S4U2Self for our realm.
|
||||||
|
*
|
||||||
|
* For a simple cross-realm S4U2Proxy there will be the following TGS
|
||||||
|
* requests after the client realm is identified:
|
||||||
|
*
|
||||||
|
* 1. server@SREALM to SREALM for krbtgt/CREALM@SREALM -- a regular TGS
|
||||||
|
* request with server's normal TGT and no S4U2Self padata.
|
||||||
|
* 2. server@SREALM to CREALM for server@SREALM (expressed as an
|
||||||
|
* enterprise principal), with the TGT from #1 as header ticket and
|
||||||
|
* S4U2Self padata identifying the client.
|
||||||
|
* 3. server@SREALM to SREALM for server@SREALM with S4U2Self padata,
|
||||||
|
* with the referral TGT from #2 as header ticket
|
||||||
|
*
|
||||||
|
* In request 2 the PROTOCOL_TRANSITION and CROSS_REALM flags are set,
|
||||||
|
* and the request is for a local client (so client != NULL) and we
|
||||||
|
* want to make a new PAC.
|
||||||
|
*
|
||||||
|
* In request 3 the PROTOCOL_TRANSITION and CROSS_REALM flags are also
|
||||||
|
* set, but the request is for a non-local client (so client == NULL)
|
||||||
|
* and we want to copy the subject PAC contained in the referral TGT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (old_pac == NULL ||
|
||||||
|
(client != NULL && (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION))) {
|
||||||
|
/* generate initial PAC */
|
||||||
|
if (with_pac) {
|
||||||
|
krb5_boolean force_reinit_mspac = FALSE;
|
||||||
|
struct ipadb_context *ipactx = ipadb_get_context(context);
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (!ipactx) {
|
||||||
|
kerr = ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client != NULL) {
|
||||||
|
/* Be aggressive here: special case for discovering range type
|
||||||
|
* immediately after establishing the trust by IPA framework. For all
|
||||||
|
* other cases call ipadb_reinit_mspac() with force_reinit_mspac set
|
||||||
|
* to 'false' to make sure the information about trusted domains is
|
||||||
|
* updated on a regular basis for all worker processes. */
|
||||||
|
if ((krb5_princ_size(context, client->princ) == 2) &&
|
||||||
|
(strncmp(krb5_princ_component(context, client->princ, 0)->data, "HTTP",
|
||||||
|
krb5_princ_component(context, client->princ, 0)->length) == 0) &&
|
||||||
|
(ulc_casecmp(krb5_princ_component(context, client->princ, 1)->data,
|
||||||
|
krb5_princ_component(context, client->princ, 1)->length,
|
||||||
|
ipactx->kdc_hostname, strlen(ipactx->kdc_hostname),
|
||||||
|
NULL, NULL, &result) == 0)) {
|
||||||
|
force_reinit_mspac = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)ipadb_reinit_mspac(ipactx, force_reinit_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);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
kerr = ipadb_common_verify_pac(context, flags,
|
||||||
|
client, server,
|
||||||
|
signing_krbtgt,
|
||||||
|
NULL,
|
||||||
|
authtime,
|
||||||
|
old_pac, &new_pac);
|
||||||
|
if (kerr == ENOENT) {
|
||||||
|
kerr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* in krb5 1.20 no need to sign tickets anymore, KDC does it for us */
|
||||||
|
done:
|
||||||
|
return kerr;
|
||||||
|
}
|
||||||
@@ -78,10 +78,12 @@ static char *std_principal_attrs[] = {
|
|||||||
IPA_USER_AUTH_TYPE,
|
IPA_USER_AUTH_TYPE,
|
||||||
"ipatokenRadiusConfigLink",
|
"ipatokenRadiusConfigLink",
|
||||||
"ipaIdpConfigLink",
|
"ipaIdpConfigLink",
|
||||||
|
"ipaPassKey",
|
||||||
"krbAuthIndMaxTicketLife",
|
"krbAuthIndMaxTicketLife",
|
||||||
"krbAuthIndMaxRenewableAge",
|
"krbAuthIndMaxRenewableAge",
|
||||||
"ipaNTSecurityIdentifier",
|
"ipaNTSecurityIdentifier",
|
||||||
"ipaUniqueID",
|
"ipaUniqueID",
|
||||||
|
"memberPrincipal",
|
||||||
|
|
||||||
"objectClass",
|
"objectClass",
|
||||||
NULL
|
NULL
|
||||||
@@ -113,6 +115,14 @@ static char *std_principal_obj_classes[] = {
|
|||||||
|
|
||||||
#define DEFAULT_TL_DATA_CONTENT "\x00\x00\x00\x00principal@UNINITIALIZED"
|
#define DEFAULT_TL_DATA_CONTENT "\x00\x00\x00\x00principal@UNINITIALIZED"
|
||||||
|
|
||||||
|
#ifndef KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM
|
||||||
|
#define KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM "optional_pac_tkt_chksum"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE
|
||||||
|
#define KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE "pac_privsvr_enctype"
|
||||||
|
#endif
|
||||||
|
|
||||||
static int ipadb_ldap_attr_to_tl_data(LDAP *lcontext, LDAPMessage *le,
|
static int ipadb_ldap_attr_to_tl_data(LDAP *lcontext, LDAPMessage *le,
|
||||||
char *attrname,
|
char *attrname,
|
||||||
krb5_tl_data **result, int *num)
|
krb5_tl_data **result, int *num)
|
||||||
@@ -178,10 +188,56 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code ipadb_set_tl_data(krb5_db_entry *entry,
|
static bool
|
||||||
krb5_int16 type,
|
is_tgs_princ(krb5_context kcontext, krb5_const_principal princ)
|
||||||
krb5_ui_2 length,
|
{
|
||||||
const krb5_octet *data)
|
krb5_data *primary;
|
||||||
|
size_t l_tgs_name;
|
||||||
|
|
||||||
|
if (2 != krb5_princ_size(kcontext, princ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
primary = krb5_princ_component(kcontext, princ, 0);
|
||||||
|
|
||||||
|
l_tgs_name = strlen(KRB5_TGS_NAME);
|
||||||
|
|
||||||
|
if (l_tgs_name != primary->length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return 0 == memcmp(primary->data, KRB5_TGS_NAME, l_tgs_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
cmp_local_tgs_princ(krb5_context kcontext, const char *local_realm,
|
||||||
|
krb5_const_principal princ, bool *result)
|
||||||
|
{
|
||||||
|
krb5_principal local_tgs_princ;
|
||||||
|
size_t l_local_realm;
|
||||||
|
krb5_error_code kerr;
|
||||||
|
bool res;
|
||||||
|
|
||||||
|
l_local_realm = strlen(local_realm);
|
||||||
|
|
||||||
|
kerr = krb5_build_principal(kcontext, &local_tgs_princ,
|
||||||
|
l_local_realm, local_realm,
|
||||||
|
KRB5_TGS_NAME, local_realm, NULL);
|
||||||
|
if (kerr)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
res = (bool) krb5_principal_compare(kcontext, local_tgs_princ, princ);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
*result = res;
|
||||||
|
|
||||||
|
end:
|
||||||
|
krb5_free_principal(kcontext, local_tgs_princ);
|
||||||
|
return kerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5_error_code ipadb_set_tl_data(krb5_db_entry *entry,
|
||||||
|
krb5_int16 type,
|
||||||
|
krb5_ui_2 length,
|
||||||
|
const krb5_octet *data)
|
||||||
{
|
{
|
||||||
krb5_error_code kerr;
|
krb5_error_code kerr;
|
||||||
krb5_tl_data *new_td = NULL;
|
krb5_tl_data *new_td = NULL;
|
||||||
@@ -347,6 +403,25 @@ static void ipadb_validate_idp(struct ipadb_context *ipactx,
|
|||||||
ldap_value_free_len(vals);
|
ldap_value_free_len(vals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ipadb_validate_passkey(struct ipadb_context *ipactx,
|
||||||
|
LDAPMessage *lentry,
|
||||||
|
enum ipadb_user_auth *ua)
|
||||||
|
{
|
||||||
|
struct berval **vals;
|
||||||
|
|
||||||
|
if (!(*ua & IPADB_USER_AUTH_PASSKEY))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Ensure that the user has a link to an IdP config. */
|
||||||
|
vals = ldap_get_values_len(ipactx->lcontext, lentry,
|
||||||
|
"ipaPassKey");
|
||||||
|
if (vals == NULL || vals[0] == NULL)
|
||||||
|
*ua &= ~IPADB_USER_AUTH_PASSKEY;
|
||||||
|
|
||||||
|
if (vals != NULL)
|
||||||
|
ldap_value_free_len(vals);
|
||||||
|
}
|
||||||
|
|
||||||
static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx,
|
static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx,
|
||||||
LDAPMessage *lentry)
|
LDAPMessage *lentry)
|
||||||
{
|
{
|
||||||
@@ -380,6 +455,7 @@ static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx,
|
|||||||
ipadb_validate_otp(ipactx, lentry, &ua);
|
ipadb_validate_otp(ipactx, lentry, &ua);
|
||||||
ipadb_validate_radius(ipactx, lentry, &ua);
|
ipadb_validate_radius(ipactx, lentry, &ua);
|
||||||
ipadb_validate_idp(ipactx, lentry, &ua);
|
ipadb_validate_idp(ipactx, lentry, &ua);
|
||||||
|
ipadb_validate_passkey(ipactx, lentry, &ua);
|
||||||
|
|
||||||
return ua;
|
return ua;
|
||||||
}
|
}
|
||||||
@@ -564,6 +640,8 @@ static void ipadb_parse_authind_policies(krb5_context kcontext,
|
|||||||
IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED},
|
IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED},
|
||||||
{"krbAuthIndMaxTicketLife;idp",
|
{"krbAuthIndMaxTicketLife;idp",
|
||||||
IPADB_USER_AUTH_IDP, IPADB_USER_AUTH_IDX_IDP},
|
IPADB_USER_AUTH_IDP, IPADB_USER_AUTH_IDX_IDP},
|
||||||
|
{"krbAuthIndMaxTicketLife;passkey",
|
||||||
|
IPADB_USER_AUTH_PASSKEY, IPADB_USER_AUTH_IDX_PASSKEY},
|
||||||
{NULL, IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX},
|
{NULL, IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX},
|
||||||
}, age_authind_map[] = {
|
}, age_authind_map[] = {
|
||||||
{"krbAuthIndMaxRenewableAge;otp",
|
{"krbAuthIndMaxRenewableAge;otp",
|
||||||
@@ -576,6 +654,8 @@ static void ipadb_parse_authind_policies(krb5_context kcontext,
|
|||||||
IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED},
|
IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED},
|
||||||
{"krbAuthIndMaxRenewableAge;idp",
|
{"krbAuthIndMaxRenewableAge;idp",
|
||||||
IPADB_USER_AUTH_IDP, IPADB_USER_AUTH_IDX_IDP},
|
IPADB_USER_AUTH_IDP, IPADB_USER_AUTH_IDX_IDP},
|
||||||
|
{"krbAuthIndMaxRenewableAge;passkey",
|
||||||
|
IPADB_USER_AUTH_PASSKEY, IPADB_USER_AUTH_IDX_PASSKEY},
|
||||||
{NULL, IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX},
|
{NULL, IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -619,6 +699,7 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
|||||||
const krb5_octet rad_string[] = "otp\0[{\"indicators\": [\"radius\"]}]";
|
const krb5_octet rad_string[] = "otp\0[{\"indicators\": [\"radius\"]}]";
|
||||||
const krb5_octet otp_string[] = "otp\0[{\"indicators\": [\"otp\"]}]";
|
const krb5_octet otp_string[] = "otp\0[{\"indicators\": [\"otp\"]}]";
|
||||||
const krb5_octet idp_string[] = "idp\0[{\"type\":\"oauth2\",\"indicators\": [\"idp\"]}]";
|
const krb5_octet idp_string[] = "idp\0[{\"type\":\"oauth2\",\"indicators\": [\"idp\"]}]";
|
||||||
|
const krb5_octet passkey_string[] = "passkey\0[{\"indicators\": [\"passkey\"]}]";
|
||||||
struct ipadb_context *ipactx;
|
struct ipadb_context *ipactx;
|
||||||
enum ipadb_user_auth ua;
|
enum ipadb_user_auth ua;
|
||||||
LDAP *lcontext;
|
LDAP *lcontext;
|
||||||
@@ -633,6 +714,7 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
|||||||
char *uidstring;
|
char *uidstring;
|
||||||
char **authz_data_list;
|
char **authz_data_list;
|
||||||
char *princ_sid;
|
char *princ_sid;
|
||||||
|
char **acl_list;
|
||||||
krb5_timestamp restime;
|
krb5_timestamp restime;
|
||||||
bool resbool;
|
bool resbool;
|
||||||
int result;
|
int result;
|
||||||
@@ -1002,6 +1084,11 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
|||||||
sizeof(idp_string), idp_string);
|
sizeof(idp_string), idp_string);
|
||||||
if (kerr)
|
if (kerr)
|
||||||
goto done;
|
goto done;
|
||||||
|
} else if (ua & IPADB_USER_AUTH_PASSKEY) {
|
||||||
|
kerr = ipadb_set_tl_data(entry, KRB5_TL_STRING_ATTRS,
|
||||||
|
sizeof(passkey_string), passkey_string);
|
||||||
|
if (kerr)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ua & ~IPADB_USER_AUTH_NONE) {
|
if (ua & ~IPADB_USER_AUTH_NONE) {
|
||||||
@@ -1029,6 +1116,30 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
|||||||
ied->has_sid = true;
|
ied->has_sid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check if it has the serviceDelegation objectclass */
|
||||||
|
ret = ipadb_ldap_attr_has_value(lcontext, lentry,
|
||||||
|
"objectClass", "resourceDelegation");
|
||||||
|
if (ret != 0 && ret != ENOENT) {
|
||||||
|
kerr = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = ipadb_ldap_attr_to_strlist(lcontext, lentry,
|
||||||
|
"memberPrincipal", &acl_list);
|
||||||
|
if (ret != 0 && ret != ENOENT) {
|
||||||
|
kerr = KRB5_KDB_INTERNAL_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
kerr = ipadb_set_tl_data(entry, KRB5_TL_CONSTRAINED_DELEGATION_ACL,
|
||||||
|
sizeof(acl_list),
|
||||||
|
(const krb5_octet *) &acl_list);
|
||||||
|
if (kerr) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kerr = 0;
|
kerr = 0;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@@ -1362,6 +1473,9 @@ static krb5_boolean is_request_for_us(krb5_context kcontext,
|
|||||||
{
|
{
|
||||||
krb5_boolean for_us;
|
krb5_boolean for_us;
|
||||||
|
|
||||||
|
if (search_for == NULL) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
for_us = krb5_realm_compare(kcontext, local_tgs, search_for) ||
|
for_us = krb5_realm_compare(kcontext, local_tgs, search_for) ||
|
||||||
krb5_principal_compare_any_realm(kcontext,
|
krb5_principal_compare_any_realm(kcontext,
|
||||||
local_tgs, search_for);
|
local_tgs, search_for);
|
||||||
@@ -1379,11 +1493,17 @@ static krb5_error_code dbget_princ(krb5_context kcontext,
|
|||||||
LDAPMessage *res = NULL;
|
LDAPMessage *res = NULL;
|
||||||
LDAPMessage *lentry;
|
LDAPMessage *lentry;
|
||||||
uint32_t pol;
|
uint32_t pol;
|
||||||
|
krb5_boolean check = FALSE;
|
||||||
|
|
||||||
|
|
||||||
if ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0 &&
|
#if defined(KRB5_KDB_FLAG_CLIENT)
|
||||||
(flags & KRB5_KDB_FLAG_CANONICALIZE) != 0) {
|
check = flags & KRB5_KDB_FLAG_CLIENT;
|
||||||
|
#else
|
||||||
|
check = (flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) &&
|
||||||
|
(flags & KRB5_KDB_FLAG_CANONICALIZE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (check) {
|
||||||
/* AS_REQ with canonicalization*/
|
/* AS_REQ with canonicalization*/
|
||||||
krb5_principal norm_princ = NULL;
|
krb5_principal norm_princ = NULL;
|
||||||
|
|
||||||
@@ -1450,6 +1570,14 @@ done:
|
|||||||
return kerr;
|
return kerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For krb5 1.19, there is no KRB5_KDB_FLAG_REFERRAL_OK, emulate it
|
||||||
|
* See krb5 commit a441fbe329ebbd7775eb5d4ccc4a05eef370f08b */
|
||||||
|
#ifndef KRB5_KDB_FLAG_REFERRAL_OK
|
||||||
|
#ifdef KRB5_KDB_FLAG_CANONICALIZE
|
||||||
|
#define KRB5_KDB_FLAG_REFERRAL_OK KRB5_KDB_FLAG_CANONICALIZE
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static krb5_error_code dbget_alias(krb5_context kcontext,
|
static krb5_error_code dbget_alias(krb5_context kcontext,
|
||||||
struct ipadb_context *ipactx,
|
struct ipadb_context *ipactx,
|
||||||
krb5_const_principal search_for,
|
krb5_const_principal search_for,
|
||||||
@@ -1462,18 +1590,40 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
|
|||||||
char *trusted_realm = NULL;
|
char *trusted_realm = NULL;
|
||||||
krb5_db_entry *kentry = NULL;
|
krb5_db_entry *kentry = NULL;
|
||||||
krb5_data *realm;
|
krb5_data *realm;
|
||||||
|
krb5_boolean check = FALSE;
|
||||||
|
/* KRB5_NT_PRINCIPAL must be the last element */
|
||||||
|
krb5_int32 supported_types[] = {
|
||||||
|
[0] = KRB5_NT_ENTERPRISE_PRINCIPAL,
|
||||||
|
[1] = KRB5_NT_PRINCIPAL,
|
||||||
|
-1,
|
||||||
|
};
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
/* TODO: also support hostbased aliases */
|
/* 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. */
|
||||||
|
if ((flags & KRB5_KDB_FLAG_REFERRAL_OK) == 0) {
|
||||||
|
/* this is *not* TGS-REQ server principal search, remove
|
||||||
|
* KRB5_NT_PRINCIPAL from the supported principal types for this lookup */
|
||||||
|
supported_types[(sizeof(supported_types) / sizeof(supported_types[0])) - 2] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Enterprise principal name type is for potential aliases or principals
|
/* Enterprise principal name type is for potential aliases or principals
|
||||||
* from trusted realms. The logic below only applies to this type */
|
* from trusted realms. Except for the TGS-REQ server lookup, we only
|
||||||
if (krb5_princ_type(kcontext, search_for) != KRB5_NT_ENTERPRISE_PRINCIPAL) {
|
* expect enterprise principals here */
|
||||||
|
for (i = 0; supported_types[i] != -1; i++) {
|
||||||
|
if (krb5_princ_type(kcontext, search_for) == supported_types[i]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supported_types[i] == -1) {
|
||||||
return KRB5_KDB_NOENTRY;
|
return KRB5_KDB_NOENTRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enterprise principal can only have single component in the name
|
/* enterprise principal can only have single component in the name
|
||||||
* according to RFC6806 section 5. */
|
* according to RFC6806 section 5. */
|
||||||
if (krb5_princ_size(kcontext, search_for) != 1) {
|
if ((krb5_princ_type(kcontext, search_for) == KRB5_NT_ENTERPRISE_PRINCIPAL) &&
|
||||||
|
(krb5_princ_size(kcontext, search_for) != 1)) {
|
||||||
return KRB5_KDB_NOENTRY;
|
return KRB5_KDB_NOENTRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1497,6 +1647,12 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
|
|||||||
if (krb5_realm_compare(kcontext, ipactx->local_tgs, norm_princ)) {
|
if (krb5_realm_compare(kcontext, ipactx->local_tgs, norm_princ)) {
|
||||||
/* In realm alias, try to retrieve it and let the caller handle it. */
|
/* In realm alias, try to retrieve it and let the caller handle it. */
|
||||||
kerr = dbget_princ(kcontext, ipactx, norm_princ, flags, entry);
|
kerr = dbget_princ(kcontext, ipactx, norm_princ, flags, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we haven't found the principal in our realm, it might still
|
||||||
|
* be a referral to a known realm. Otherwise, bail out with the result */
|
||||||
|
if ((kerr != KRB5_KDB_NOENTRY) &&
|
||||||
|
(flags & KRB5_KDB_FLAG_REFERRAL_OK) == 0) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1507,8 +1663,14 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
|
|||||||
* both client and server referrals. But it is more useful to ignore it
|
* both client and server referrals. But it is more useful to ignore it
|
||||||
* like Windows KDC does for client referrals.
|
* like Windows KDC does for client referrals.
|
||||||
*/
|
*/
|
||||||
if (((flags & KRB5_KDB_FLAG_CANONICALIZE) == 0) &&
|
#if defined(KRB5_KDB_FLAG_CLIENT)
|
||||||
((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) == 0)) {
|
check = ((flags & KRB5_KDB_FLAG_CLIENT) == 0) &&
|
||||||
|
((flags & KRB5_KDB_FLAG_REFERRAL_OK) == 0);
|
||||||
|
#else
|
||||||
|
check = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) == 0) &&
|
||||||
|
((flags & KRB5_KDB_FLAG_CANONICALIZE) == 0);
|
||||||
|
#endif
|
||||||
|
if (check) {
|
||||||
kerr = KRB5_KDB_NOENTRY;
|
kerr = KRB5_KDB_NOENTRY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -1534,13 +1696,44 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
|
|||||||
&trusted_realm);
|
&trusted_realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kerr == KRB5_KDB_NOENTRY) {
|
||||||
|
krb5_data *hstname = NULL;
|
||||||
|
int ncomponents = krb5_princ_size(kcontext, norm_princ);
|
||||||
|
|
||||||
|
/* We did not find any alias so far for non-server principal lookups */
|
||||||
|
if ((ncomponents < 2) && ((flags & KRB5_KDB_FLAG_REFERRAL_OK) == 0)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point it is a server principal lookup that might be
|
||||||
|
* referencing a host name in a trusted domain. It might also
|
||||||
|
* have multiple service components so take the last one for the
|
||||||
|
* hostname or the domain name. See MS-ADTS 2.2.21 and MS-DRSR 2.2.4.2.
|
||||||
|
*/
|
||||||
|
hstname = krb5_princ_component(kcontext, norm_princ, ncomponents - 1);
|
||||||
|
|
||||||
|
kerr = ipadb_is_princ_from_trusted_realm(kcontext,
|
||||||
|
hstname->data,
|
||||||
|
hstname->length,
|
||||||
|
&trusted_realm);
|
||||||
|
}
|
||||||
|
|
||||||
if (kerr != 0) {
|
if (kerr != 0) {
|
||||||
|
kerr = KRB5_KDB_NOENTRY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a known trusted realm. Issue a referral depending on whether this
|
/* This is a known trusted realm. Issue a referral depending on whether this
|
||||||
* is client or server referral request */
|
* is client or server referral request */
|
||||||
if (flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) {
|
#if defined(KRB5_KDB_FLAG_CLIENT)
|
||||||
|
check = (flags & KRB5_KDB_FLAG_CLIENT) && (flags & KRB5_KDB_FLAG_REFERRAL_OK);
|
||||||
|
#else
|
||||||
|
check = (flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) &&
|
||||||
|
((flags & KRB5_KDB_FLAG_CANONICALIZE) ||
|
||||||
|
search_for->type == KRB5_NT_ENTERPRISE_PRINCIPAL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (check) {
|
||||||
/* client referral out of realm, set next realm. */
|
/* client referral out of realm, set next realm. */
|
||||||
kerr = krb5_set_principal_realm(kcontext, norm_princ, trusted_realm);
|
kerr = krb5_set_principal_realm(kcontext, norm_princ, trusted_realm);
|
||||||
if (kerr != 0) {
|
if (kerr != 0) {
|
||||||
@@ -1559,7 +1752,12 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & KRB5_KDB_FLAG_INCLUDE_PAC) {
|
#if defined(KRB5_KDB_FLAG_CLIENT)
|
||||||
|
check = flags & KRB5_KDB_FLAG_CLIENT;
|
||||||
|
#else
|
||||||
|
check = flags & KRB5_KDB_FLAG_INCLUDE_PAC;
|
||||||
|
#endif
|
||||||
|
if (check) {
|
||||||
/* TGS request where KDC wants to generate PAC
|
/* TGS request where KDC wants to generate PAC
|
||||||
* but the principal is out of our realm */
|
* but the principal is out of our realm */
|
||||||
kerr = KRB5_KDB_NOENTRY;
|
kerr = KRB5_KDB_NOENTRY;
|
||||||
@@ -1603,6 +1801,8 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext,
|
|||||||
krb5_db_entry **entry)
|
krb5_db_entry **entry)
|
||||||
{
|
{
|
||||||
struct ipadb_context *ipactx;
|
struct ipadb_context *ipactx;
|
||||||
|
bool is_local_tgs_princ;
|
||||||
|
const char *opt_pac_tkt_chksum_val;
|
||||||
krb5_error_code kerr;
|
krb5_error_code kerr;
|
||||||
|
|
||||||
*entry = NULL;
|
*entry = NULL;
|
||||||
@@ -1618,11 +1818,50 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext,
|
|||||||
|
|
||||||
/* Lookup local names and aliases first. */
|
/* Lookup local names and aliases first. */
|
||||||
kerr = dbget_princ(kcontext, ipactx, search_for, flags, entry);
|
kerr = dbget_princ(kcontext, ipactx, search_for, flags, entry);
|
||||||
if (kerr != KRB5_KDB_NOENTRY) {
|
if (kerr == KRB5_KDB_NOENTRY) {
|
||||||
|
kerr = dbget_alias(kcontext, ipactx, search_for, flags, entry);
|
||||||
|
}
|
||||||
|
if (kerr)
|
||||||
return kerr;
|
return kerr;
|
||||||
|
|
||||||
|
/* If TGS principal, some virtual attributes may be added */
|
||||||
|
if (is_tgs_princ(kcontext, (*entry)->princ)) {
|
||||||
|
kerr = cmp_local_tgs_princ(kcontext, ipactx->realm, (*entry)->princ,
|
||||||
|
&is_local_tgs_princ);
|
||||||
|
if (kerr)
|
||||||
|
return kerr;
|
||||||
|
|
||||||
|
/* for trusted AD forests we currently must use SHA-1-based
|
||||||
|
* encryption types. For details, see
|
||||||
|
* https://github.com/krb5/krb5/commit/5af907156f8f502bbe268f0c62274f88a61261e4
|
||||||
|
*/
|
||||||
|
if (!is_local_tgs_princ) {
|
||||||
|
kerr = krb5_dbe_set_string(kcontext, *entry,
|
||||||
|
KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE,
|
||||||
|
"aes256-sha1");
|
||||||
|
if (kerr)
|
||||||
|
return kerr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We should have been initialized at this point already */
|
||||||
|
if (ipactx->optional_pac_tkt_chksum == IPADB_TRISTATE_UNDEFINED) {
|
||||||
|
return KRB5_KDB_SERVER_INTERNAL_ERR;
|
||||||
|
}
|
||||||
|
/* PAC ticket signature should be optional for foreign realms, and local
|
||||||
|
* realm if not supported by all servers
|
||||||
|
*/
|
||||||
|
if (!is_local_tgs_princ || ipactx->optional_pac_tkt_chksum)
|
||||||
|
opt_pac_tkt_chksum_val = "true";
|
||||||
|
else
|
||||||
|
opt_pac_tkt_chksum_val = "false";
|
||||||
|
|
||||||
|
kerr = krb5_dbe_set_string(kcontext, *entry,
|
||||||
|
KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM,
|
||||||
|
opt_pac_tkt_chksum_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dbget_alias(kcontext, ipactx, search_for, flags, entry);
|
return kerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ipadb_free_principal_e_data(krb5_context kcontext, krb5_octet *e_data)
|
void ipadb_free_principal_e_data(krb5_context kcontext, krb5_octet *e_data)
|
||||||
@@ -1653,12 +1892,20 @@ void ipadb_free_principal_e_data(krb5_context kcontext, krb5_octet *e_data)
|
|||||||
void ipadb_free_principal(krb5_context kcontext, krb5_db_entry *entry)
|
void ipadb_free_principal(krb5_context kcontext, krb5_db_entry *entry)
|
||||||
{
|
{
|
||||||
krb5_tl_data *prev, *next;
|
krb5_tl_data *prev, *next;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
krb5_free_principal(kcontext, entry->princ);
|
krb5_free_principal(kcontext, entry->princ);
|
||||||
prev = entry->tl_data;
|
prev = entry->tl_data;
|
||||||
while(prev) {
|
while(prev) {
|
||||||
next = prev->tl_data_next;
|
next = prev->tl_data_next;
|
||||||
|
/* Handle RBCD ACL type */
|
||||||
|
if (prev->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL) {
|
||||||
|
char **acl_list = (char **) prev->tl_data_contents;
|
||||||
|
for (i = 0; (acl_list != NULL) && (acl_list[i] != NULL); i++) {
|
||||||
|
free(acl_list[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
free(prev->tl_data_contents);
|
free(prev->tl_data_contents);
|
||||||
free(prev);
|
free(prev);
|
||||||
prev = next;
|
prev = next;
|
||||||
@@ -1673,10 +1920,10 @@ void ipadb_free_principal(krb5_context kcontext, krb5_db_entry *entry)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code ipadb_get_tl_data(krb5_db_entry *entry,
|
krb5_error_code ipadb_get_tl_data(krb5_db_entry *entry,
|
||||||
krb5_int16 type,
|
krb5_int16 type,
|
||||||
krb5_ui_2 length,
|
krb5_ui_2 length,
|
||||||
krb5_octet *data)
|
krb5_octet *data)
|
||||||
{
|
{
|
||||||
krb5_tl_data *td;
|
krb5_tl_data *td;
|
||||||
|
|
||||||
@@ -1925,6 +2172,21 @@ done:
|
|||||||
return kerr;
|
return kerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool should_filter_out_attr(krb5_tl_data *data)
|
||||||
|
{
|
||||||
|
switch (data->tl_data_type) {
|
||||||
|
case KRB5_TL_CONSTRAINED_DELEGATION_ACL:
|
||||||
|
case KRB5_TL_DB_ARGS:
|
||||||
|
case KRB5_TL_KADM_DATA:
|
||||||
|
case KRB5_TL_LAST_ADMIN_UNLOCK:
|
||||||
|
case KRB5_TL_LAST_PWD_CHANGE:
|
||||||
|
case KRB5_TL_MKVNO:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods,
|
static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods,
|
||||||
krb5_tl_data *tl_data,
|
krb5_tl_data *tl_data,
|
||||||
int mod_op)
|
int mod_op)
|
||||||
@@ -1936,13 +2198,8 @@ static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods,
|
|||||||
int n, i;
|
int n, i;
|
||||||
|
|
||||||
for (n = 0, data = tl_data; data; data = data->tl_data_next) {
|
for (n = 0, data = tl_data; data; data = data->tl_data_next) {
|
||||||
if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE ||
|
if (should_filter_out_attr(data))
|
||||||
data->tl_data_type == KRB5_TL_KADM_DATA ||
|
|
||||||
data->tl_data_type == KRB5_TL_DB_ARGS ||
|
|
||||||
data->tl_data_type == KRB5_TL_MKVNO ||
|
|
||||||
data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1958,13 +2215,8 @@ static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods,
|
|||||||
|
|
||||||
for (i = 0, data = tl_data; data; data = data->tl_data_next) {
|
for (i = 0, data = tl_data; data; data = data->tl_data_next) {
|
||||||
|
|
||||||
if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE ||
|
if (should_filter_out_attr(data))
|
||||||
data->tl_data_type == KRB5_TL_KADM_DATA ||
|
|
||||||
data->tl_data_type == KRB5_TL_DB_ARGS ||
|
|
||||||
data->tl_data_type == KRB5_TL_MKVNO ||
|
|
||||||
data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
be_type = htons(data->tl_data_type);
|
be_type = htons(data->tl_data_type);
|
||||||
|
|
||||||
@@ -2716,10 +2968,43 @@ done:
|
|||||||
return kerr;
|
return kerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
remove_virtual_str_attrs(krb5_context kcontext, krb5_db_entry *entry)
|
||||||
|
{
|
||||||
|
char *str_attr_val;
|
||||||
|
krb5_error_code kerr;
|
||||||
|
const char *str_attrs[] = {
|
||||||
|
KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM,
|
||||||
|
KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE,
|
||||||
|
NULL};
|
||||||
|
|
||||||
|
for(int i = 0; str_attrs[i] != NULL; i++) {
|
||||||
|
kerr = krb5_dbe_get_string(kcontext, entry,
|
||||||
|
str_attrs[i],
|
||||||
|
&str_attr_val);
|
||||||
|
if (kerr)
|
||||||
|
return kerr;
|
||||||
|
|
||||||
|
if (str_attr_val)
|
||||||
|
kerr = krb5_dbe_set_string(kcontext, entry,
|
||||||
|
str_attrs[i],
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
krb5_dbe_free_string(kcontext, str_attr_val);
|
||||||
|
}
|
||||||
|
return kerr;
|
||||||
|
}
|
||||||
|
|
||||||
krb5_error_code ipadb_put_principal(krb5_context kcontext,
|
krb5_error_code ipadb_put_principal(krb5_context kcontext,
|
||||||
krb5_db_entry *entry,
|
krb5_db_entry *entry,
|
||||||
char **db_args)
|
char **db_args)
|
||||||
{
|
{
|
||||||
|
krb5_error_code kerr;
|
||||||
|
|
||||||
|
kerr = remove_virtual_str_attrs(kcontext, entry);
|
||||||
|
if (kerr)
|
||||||
|
return kerr;
|
||||||
|
|
||||||
if (entry->mask & KMASK_PRINCIPAL) {
|
if (entry->mask & KMASK_PRINCIPAL) {
|
||||||
return ipadb_add_principal(kcontext, entry);
|
return ipadb_add_principal(kcontext, entry);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ static int teardown(void **state)
|
|||||||
|
|
||||||
extern krb5_error_code filter_logon_info(krb5_context context,
|
extern krb5_error_code filter_logon_info(krb5_context context,
|
||||||
TALLOC_CTX *memctx,
|
TALLOC_CTX *memctx,
|
||||||
krb5_data realm,
|
krb5_data *realm,
|
||||||
struct PAC_LOGON_INFO_CTR *info);
|
struct PAC_LOGON_INFO_CTR *info);
|
||||||
|
|
||||||
static void test_filter_logon_info(void **state)
|
static void test_filter_logon_info(void **state)
|
||||||
@@ -204,7 +204,7 @@ static void test_filter_logon_info(void **state)
|
|||||||
"WRONG");
|
"WRONG");
|
||||||
assert_non_null(info->info->info3.base.logon_domain.string);
|
assert_non_null(info->info->info3.base.logon_domain.string);
|
||||||
|
|
||||||
kerr = filter_logon_info(test_ctx->krb5_ctx, test_ctx, realm, info);
|
kerr = filter_logon_info(test_ctx->krb5_ctx, test_ctx, &realm, info);
|
||||||
assert_int_equal(kerr, EINVAL);
|
assert_int_equal(kerr, EINVAL);
|
||||||
|
|
||||||
info->info->info3.base.logon_domain.string = talloc_strdup(info->info,
|
info->info->info3.base.logon_domain.string = talloc_strdup(info->info,
|
||||||
@@ -212,7 +212,7 @@ static void test_filter_logon_info(void **state)
|
|||||||
assert_non_null(info->info->info3.base.logon_domain.string);
|
assert_non_null(info->info->info3.base.logon_domain.string);
|
||||||
|
|
||||||
/* missing domain SID */
|
/* missing domain SID */
|
||||||
kerr = filter_logon_info(test_ctx->krb5_ctx, test_ctx, realm, info);
|
kerr = filter_logon_info(test_ctx->krb5_ctx, test_ctx, &realm, info);
|
||||||
assert_int_equal(kerr, EINVAL);
|
assert_int_equal(kerr, EINVAL);
|
||||||
|
|
||||||
/* wrong domain SID */
|
/* wrong domain SID */
|
||||||
@@ -220,7 +220,7 @@ static void test_filter_logon_info(void **state)
|
|||||||
assert_int_equal(ret, 0);
|
assert_int_equal(ret, 0);
|
||||||
info->info->info3.base.domain_sid = &dom_sid;
|
info->info->info3.base.domain_sid = &dom_sid;
|
||||||
|
|
||||||
kerr = filter_logon_info(test_ctx->krb5_ctx, test_ctx, realm, info);
|
kerr = filter_logon_info(test_ctx->krb5_ctx, test_ctx, &realm, info);
|
||||||
assert_int_equal(kerr, EINVAL);
|
assert_int_equal(kerr, EINVAL);
|
||||||
|
|
||||||
/* matching domain SID */
|
/* matching domain SID */
|
||||||
@@ -228,7 +228,7 @@ static void test_filter_logon_info(void **state)
|
|||||||
assert_int_equal(ret, 0);
|
assert_int_equal(ret, 0);
|
||||||
info->info->info3.base.domain_sid = &dom_sid;
|
info->info->info3.base.domain_sid = &dom_sid;
|
||||||
|
|
||||||
kerr = filter_logon_info(test_ctx->krb5_ctx, test_ctx, realm, info);
|
kerr = filter_logon_info(test_ctx->krb5_ctx, test_ctx, &realm, info);
|
||||||
assert_int_equal(kerr, 0);
|
assert_int_equal(kerr, 0);
|
||||||
|
|
||||||
/* empty SIDs */
|
/* empty SIDs */
|
||||||
@@ -243,7 +243,7 @@ static void test_filter_logon_info(void **state)
|
|||||||
assert_non_null(info->info->info3.sids[c].sid);
|
assert_non_null(info->info->info3.sids[c].sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = filter_logon_info(test_ctx->krb5_ctx, NULL, realm, info);
|
kerr = filter_logon_info(test_ctx->krb5_ctx, NULL, &realm, info);
|
||||||
assert_int_equal(kerr, 0);
|
assert_int_equal(kerr, 0);
|
||||||
assert_int_equal(info->info->info3.sidcount, 3);
|
assert_int_equal(info->info->info3.sidcount, 3);
|
||||||
|
|
||||||
@@ -297,7 +297,7 @@ static void test_filter_logon_info(void **state)
|
|||||||
assert_int_equal(ret, 0);
|
assert_int_equal(ret, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
kerr = filter_logon_info(test_ctx->krb5_ctx, NULL, realm, info);
|
kerr = filter_logon_info(test_ctx->krb5_ctx, NULL, &realm, info);
|
||||||
assert_int_equal(kerr, 0);
|
assert_int_equal(kerr, 0);
|
||||||
assert_int_equal(info->info->info3.sidcount, test_data[c].exp_sidcount);
|
assert_int_equal(info->info->info3.sidcount, test_data[c].exp_sidcount);
|
||||||
if (test_data[c].exp_sidcount == 0) {
|
if (test_data[c].exp_sidcount == 0) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
AM_CPPFLAGS := -I$(top_srcdir)/util
|
AM_CPPFLAGS := -I$(top_srcdir)/util
|
||||||
AM_CFLAGS := @LDAP_CFLAGS@ @LIBVERTO_CFLAGS@ @KRB5_CFLAGS@ @NSPR_CFLAGS@
|
AM_CFLAGS := @LDAP_CFLAGS@ @LIBVERTO_CFLAGS@ @KRB5_CFLAGS@ @NSPR_CFLAGS@
|
||||||
AM_LDFLAGS := @LDAP_LIBS@ @LIBVERTO_LIBS@ @KRAD_LIBS@ @KRB5_LIBS@
|
AM_LDFLAGS := @LDAP_LIBS@ @LIBVERTO_LIBS@ @KRAD_LIBS@ @KRB5_LIBS@ @JANSSON_LIBS@
|
||||||
|
|
||||||
noinst_HEADERS = internal.h
|
noinst_HEADERS = internal.h
|
||||||
appdir = $(libexecdir)/ipa/
|
appdir = $(libexecdir)/ipa/
|
||||||
@@ -10,7 +10,7 @@ dist_noinst_DATA = ipa-otpd.socket.in ipa-otpd@.service.in test.py
|
|||||||
systemdsystemunit_DATA = ipa-otpd.socket ipa-otpd@.service
|
systemdsystemunit_DATA = ipa-otpd.socket ipa-otpd@.service
|
||||||
|
|
||||||
ipa_otpd_SOURCES = bind.c forward.c main.c parse.c query.c queue.c stdio.c \
|
ipa_otpd_SOURCES = bind.c forward.c main.c parse.c query.c queue.c stdio.c \
|
||||||
oauth2.c
|
oauth2.c passkey.c
|
||||||
|
|
||||||
%.socket: %.socket.in
|
%.socket: %.socket.in
|
||||||
@sed -e 's|@krb5rundir[@]|$(krb5rundir)|g' \
|
@sed -e 's|@krb5rundir[@]|$(krb5rundir)|g' \
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include "krad.h"
|
#include "krad.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <ldap.h>
|
#include <ldap.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -49,6 +51,7 @@ enum ldap_query {
|
|||||||
LDAP_QUERY_RADIUS,
|
LDAP_QUERY_RADIUS,
|
||||||
LDAP_QUERY_RADIUS_USERMAP,
|
LDAP_QUERY_RADIUS_USERMAP,
|
||||||
LDAP_QUERY_IDP,
|
LDAP_QUERY_IDP,
|
||||||
|
LDAP_QUERY_PASSKEY,
|
||||||
LDAP_QUERY_END
|
LDAP_QUERY_END
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,6 +62,8 @@ enum oauth2_state {
|
|||||||
OAUTH2_GET_ACCESS_TOKEN
|
OAUTH2_GET_ACCESS_TOKEN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct otpd_queue_item_passkey;
|
||||||
|
|
||||||
struct otpd_queue_item {
|
struct otpd_queue_item {
|
||||||
struct otpd_queue_item *next;
|
struct otpd_queue_item *next;
|
||||||
krad_packet *req;
|
krad_packet *req;
|
||||||
@@ -74,6 +79,7 @@ struct otpd_queue_item {
|
|||||||
char *ipatokenRadiusConfigLink;
|
char *ipatokenRadiusConfigLink;
|
||||||
char *ipaidpSub;
|
char *ipaidpSub;
|
||||||
char *ipaidpConfigLink;
|
char *ipaidpConfigLink;
|
||||||
|
char **ipaPassKey;
|
||||||
char **ipauserauthtypes;
|
char **ipauserauthtypes;
|
||||||
char *other;
|
char *other;
|
||||||
} user;
|
} user;
|
||||||
@@ -107,6 +113,9 @@ struct otpd_queue_item {
|
|||||||
krb5_data state;
|
krb5_data state;
|
||||||
} oauth2;
|
} oauth2;
|
||||||
|
|
||||||
|
bool get_passkey_config;
|
||||||
|
struct otpd_queue_item_passkey *passkey;
|
||||||
|
|
||||||
int msgid;
|
int msgid;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,9 +170,25 @@ void otpd_log_req_(const char * const file, int line, krad_packet *req,
|
|||||||
void otpd_log_err_(const char * const file, int line, krb5_error_code code,
|
void otpd_log_err_(const char * const file, int line, krb5_error_code code,
|
||||||
const char * const tmpl, ...);
|
const char * const tmpl, ...);
|
||||||
|
|
||||||
|
int add_krad_attr_to_set(krad_packet *req, krad_attrset *attrset,
|
||||||
|
krb5_data *datap, krad_attr attr, const char *message);
|
||||||
|
|
||||||
|
int get_krad_attr_from_packet(const krad_packet *rres,
|
||||||
|
krad_attr attr, krb5_data *_data);
|
||||||
|
|
||||||
|
int get_string(LDAP *ldp, LDAPMessage *entry, const char *name,
|
||||||
|
char **out);
|
||||||
|
|
||||||
|
int get_string_array(LDAP *ldp, LDAPMessage *entry, const char *name,
|
||||||
|
char ***out);
|
||||||
|
|
||||||
|
bool auth_type_is(char **auth_types, const char *check);
|
||||||
|
|
||||||
krb5_error_code otpd_queue_item_new(krad_packet *req,
|
krb5_error_code otpd_queue_item_new(krad_packet *req,
|
||||||
struct otpd_queue_item **item);
|
struct otpd_queue_item **item);
|
||||||
|
|
||||||
|
void free_otpd_queue_item_passkey(struct otpd_queue_item *item);
|
||||||
|
|
||||||
void otpd_queue_item_free(struct otpd_queue_item *item);
|
void otpd_queue_item_free(struct otpd_queue_item *item);
|
||||||
|
|
||||||
krb5_error_code otpd_queue_iter_new(const struct otpd_queue * const *queues,
|
krb5_error_code otpd_queue_iter_new(const struct otpd_queue * const *queues,
|
||||||
@@ -206,3 +231,10 @@ const char *otpd_parse_radius_username(LDAP *ldp, LDAPMessage *entry,
|
|||||||
struct otpd_queue_item *item);
|
struct otpd_queue_item *item);
|
||||||
|
|
||||||
int oauth2(struct otpd_queue_item **item, enum oauth2_state);
|
int oauth2(struct otpd_queue_item **item, enum oauth2_state);
|
||||||
|
|
||||||
|
const char *otpd_parse_passkey(LDAP *ldp, LDAPMessage *entry,
|
||||||
|
struct otpd_queue_item *item);
|
||||||
|
|
||||||
|
bool is_passkey(struct otpd_queue_item *item);
|
||||||
|
|
||||||
|
int do_passkey(struct otpd_queue_item *item);
|
||||||
@@ -7,4 +7,4 @@ EnvironmentFile=@sysconfdir@/ipa/default.conf
|
|||||||
ExecStart=@libexecdir@/ipa/ipa-otpd $ldap_uri
|
ExecStart=@libexecdir@/ipa/ipa-otpd $ldap_uri
|
||||||
StandardInput=socket
|
StandardInput=socket
|
||||||
StandardOutput=socket
|
StandardOutput=socket
|
||||||
StandardError=syslog
|
StandardError=journal
|
||||||
@@ -59,6 +59,12 @@ static void free_elts(struct otpd_queue *q)
|
|||||||
#define otpd_queue_item_free free_elt
|
#define otpd_queue_item_free free_elt
|
||||||
#define otpd_queue_free_items free_elts
|
#define otpd_queue_free_items free_elts
|
||||||
|
|
||||||
|
void free_otpd_queue_item_passkey(struct otpd_queue_item *item)
|
||||||
|
{
|
||||||
|
(void)item; /* Unused */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static void assert_elt_equal(struct otpd_queue_item *e1,
|
static void assert_elt_equal(struct otpd_queue_item *e1,
|
||||||
struct otpd_queue_item *e2)
|
struct otpd_queue_item *e2)
|
||||||
{
|
{
|
||||||
@@ -69,7 +75,7 @@ static void assert_elt_equal(struct otpd_queue_item *e1,
|
|||||||
assert_int_equal(e1->msgid, e2->msgid);
|
assert_int_equal(e1->msgid, e2->msgid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_single_insert()
|
static void test_single_insert(void **state)
|
||||||
{
|
{
|
||||||
struct otpd_queue q = { NULL };
|
struct otpd_queue q = { NULL };
|
||||||
struct otpd_queue_item *ein, *eout;
|
struct otpd_queue_item *ein, *eout;
|
||||||
@@ -90,7 +96,7 @@ static void test_single_insert()
|
|||||||
free_elts(&q);
|
free_elts(&q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_jump_insert()
|
static void test_jump_insert(void **state)
|
||||||
{
|
{
|
||||||
struct otpd_queue q = { NULL };
|
struct otpd_queue q = { NULL };
|
||||||
struct otpd_queue_item *echeck;
|
struct otpd_queue_item *echeck;
|
||||||
@@ -106,7 +112,7 @@ static void test_jump_insert()
|
|||||||
free_elts(&q);
|
free_elts(&q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_garbage_insert()
|
static void test_garbage_insert(void **state)
|
||||||
{
|
{
|
||||||
struct otpd_queue q = { NULL };
|
struct otpd_queue q = { NULL };
|
||||||
struct otpd_queue_item *e, *g;
|
struct otpd_queue_item *e, *g;
|
||||||
@@ -121,7 +127,7 @@ static void test_garbage_insert()
|
|||||||
free_elts(&q);
|
free_elts(&q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_removal()
|
static void test_removal(void **state)
|
||||||
{
|
{
|
||||||
struct otpd_queue q = { NULL };
|
struct otpd_queue q = { NULL };
|
||||||
|
|
||||||
@@ -149,7 +155,7 @@ static void pick_id(struct otpd_queue *q, int msgid)
|
|||||||
e = otpd_queue_pop_msgid(q, msgid);
|
e = otpd_queue_pop_msgid(q, msgid);
|
||||||
assert_ptr_equal(e, NULL);
|
assert_ptr_equal(e, NULL);
|
||||||
}
|
}
|
||||||
static void test_pick_removal()
|
static void test_pick_removal(void **state)
|
||||||
{
|
{
|
||||||
struct otpd_queue q = { NULL };
|
struct otpd_queue q = { NULL };
|
||||||
|
|
||||||
@@ -166,7 +172,7 @@ static void test_pick_removal()
|
|||||||
free_elts(&q);
|
free_elts(&q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_iter()
|
static void test_iter(void **state)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
struct otpd_queue q = { NULL };
|
struct otpd_queue q = { NULL };
|
||||||
|
|||||||
@@ -88,6 +88,80 @@ void otpd_log_err_(const char * const file, int line, krb5_error_code code,
|
|||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define min(a,b) ((a) > (b) ? (b) : (a))
|
||||||
|
int add_krad_attr_to_set(krad_packet *req, krad_attrset *attrset,
|
||||||
|
krb5_data *datap, krad_attr attr, const char *message)
|
||||||
|
{
|
||||||
|
krb5_data state = {0};
|
||||||
|
char *p = datap->data;
|
||||||
|
unsigned int len = datap->length;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
state.data = p;
|
||||||
|
state.length = min(MAX_ATTRSIZE - 5, len);
|
||||||
|
p += state.length;
|
||||||
|
|
||||||
|
ret = krad_attrset_add(attrset, attr, &(state));
|
||||||
|
if (ret != 0) {
|
||||||
|
otpd_log_req(req, message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len -= state.length;
|
||||||
|
} while (len > 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Most attributes have limited length (MAX_ATTRSIZE). In order to accept longer
|
||||||
|
* values, we will concatenate all the attribute values to single krb5_data. */
|
||||||
|
int get_krad_attr_from_packet(const krad_packet *rres,
|
||||||
|
krad_attr attr, krb5_data *_data)
|
||||||
|
{
|
||||||
|
const krb5_data *rmsg;
|
||||||
|
krb5_data data = {0};
|
||||||
|
unsigned int memindex;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
rmsg = krad_packet_get_attr(rres, attr, i);
|
||||||
|
if (rmsg != NULL) {
|
||||||
|
data.length += rmsg->length;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} while (rmsg != NULL);
|
||||||
|
|
||||||
|
if (data.length == 0) {
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.data = malloc(data.length);
|
||||||
|
if (data.data == NULL) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
memindex = 0;
|
||||||
|
do {
|
||||||
|
rmsg = krad_packet_get_attr(rres, attr, i);
|
||||||
|
if (rmsg != NULL) {
|
||||||
|
memcpy(&data.data[memindex], rmsg->data, rmsg->length);
|
||||||
|
memindex += rmsg->length;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} while (rmsg != NULL);
|
||||||
|
|
||||||
|
if (memindex != data.length) {
|
||||||
|
free(data.data);
|
||||||
|
return ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*_data = data;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void on_ldap_free(verto_ctx *vctx, verto_ev *ev)
|
static void on_ldap_free(verto_ctx *vctx, verto_ev *ev)
|
||||||
{
|
{
|
||||||
(void)vctx; /* Unused */
|
(void)vctx; /* Unused */
|
||||||
|
|||||||
@@ -135,82 +135,6 @@ static void oauth2_on_child_writable(verto_ctx *vctx, verto_ev *ev)
|
|||||||
verto_del(ev);
|
verto_del(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define min(a,b) ((a) > (b) ? (b) : (a))
|
|
||||||
static int add_krad_attr_to_set(struct child_ctx *child_ctx,
|
|
||||||
krad_attrset *attrset,
|
|
||||||
krb5_data *datap,
|
|
||||||
krad_attr attr, const char *message)
|
|
||||||
{
|
|
||||||
krb5_data state = {0};
|
|
||||||
char *p = datap->data;
|
|
||||||
unsigned int len = datap->length;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
state.data = p;
|
|
||||||
state.length = min(MAX_ATTRSIZE - 5, len);
|
|
||||||
p += state.length;
|
|
||||||
|
|
||||||
ret = krad_attrset_add(attrset, attr, &(state));
|
|
||||||
if (ret != 0) {
|
|
||||||
otpd_log_req(child_ctx->item->req, message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
len -= state.length;
|
|
||||||
} while (len > 0);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Most attributes have limited length (MAX_ATTRSIZE). In order to accept longer
|
|
||||||
* values, we will concatenate all the attribute values to single krb5_data. */
|
|
||||||
static int get_krad_attr_from_packet(const krad_packet *rres,
|
|
||||||
krad_attr attr, krb5_data *_data)
|
|
||||||
{
|
|
||||||
const krb5_data *rmsg;
|
|
||||||
krb5_data data = {0};
|
|
||||||
unsigned int memindex;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
rmsg = krad_packet_get_attr(rres, attr, i);
|
|
||||||
if (rmsg != NULL) {
|
|
||||||
data.length += rmsg->length;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
} while (rmsg != NULL);
|
|
||||||
|
|
||||||
if (data.length == 0) {
|
|
||||||
return ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.data = malloc(data.length);
|
|
||||||
if (data.data == NULL) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
memindex = 0;
|
|
||||||
do {
|
|
||||||
rmsg = krad_packet_get_attr(rres, attr, i);
|
|
||||||
if (rmsg != NULL) {
|
|
||||||
memcpy(&data.data[memindex], rmsg->data, rmsg->length);
|
|
||||||
memindex += rmsg->length;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
} while (rmsg != NULL);
|
|
||||||
|
|
||||||
if (memindex != data.length) {
|
|
||||||
free(data.data);
|
|
||||||
return ERANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
*_data = data;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* oidc_child will return two lines.
|
/* oidc_child will return two lines.
|
||||||
* The first is a JSON formatted string containing the device code and other
|
* The first is a JSON formatted string containing the device code and other
|
||||||
* data needed to get the access token in the second round. This will be
|
* data needed to get the access token in the second round. This will be
|
||||||
@@ -225,7 +149,7 @@ static int handle_device_code_reply(struct child_ctx *child_ctx,
|
|||||||
krad_attrset *attrset = NULL;
|
krad_attrset *attrset = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
krb5_data data = { 0 };
|
krb5_data data = { 0 };
|
||||||
struct otpd_queue_item *state_item;
|
struct otpd_queue_item *state_item = NULL;
|
||||||
|
|
||||||
ret = otpd_queue_item_new(NULL, &state_item);
|
ret = otpd_queue_item_new(NULL, &state_item);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@@ -256,7 +180,8 @@ static int handle_device_code_reply(struct child_ctx *child_ctx,
|
|||||||
}
|
}
|
||||||
state_item->oauth2.state.length = strlen(dc_reply);
|
state_item->oauth2.state.length = strlen(dc_reply);
|
||||||
|
|
||||||
ret = add_krad_attr_to_set(child_ctx, attrset, &(state_item->oauth2.state),
|
ret = add_krad_attr_to_set(child_ctx->item->req,
|
||||||
|
attrset, &(state_item->oauth2.state),
|
||||||
krad_attr_name2num("Proxy-State"),
|
krad_attr_name2num("Proxy-State"),
|
||||||
"Failed to serialize state to attribute set");
|
"Failed to serialize state to attribute set");
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@@ -266,7 +191,7 @@ static int handle_device_code_reply(struct child_ctx *child_ctx,
|
|||||||
data.magic = 0;
|
data.magic = 0;
|
||||||
data.data = rad_reply;
|
data.data = rad_reply;
|
||||||
data.length = strlen(rad_reply);
|
data.length = strlen(rad_reply);
|
||||||
ret = add_krad_attr_to_set(child_ctx, attrset, &data,
|
ret = add_krad_attr_to_set(child_ctx->item->req, attrset, &data,
|
||||||
krad_attr_name2num("Reply-Message"),
|
krad_attr_name2num("Reply-Message"),
|
||||||
"Failed to serialize reply to attribute set");
|
"Failed to serialize reply to attribute set");
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@@ -319,7 +244,7 @@ static int check_access_token_reply(struct child_ctx *child_ctx,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void oauth2_on_child_readable(verto_ctx *, verto_ev *ev)
|
static void oauth2_on_child_readable(verto_ctx *vctx, verto_ev *ev)
|
||||||
{
|
{
|
||||||
static char buf[10240];
|
static char buf[10240];
|
||||||
ssize_t io = 0;
|
ssize_t io = 0;
|
||||||
@@ -328,6 +253,8 @@ static void oauth2_on_child_readable(verto_ctx *, verto_ev *ev)
|
|||||||
char *rad_reply;
|
char *rad_reply;
|
||||||
char *end;
|
char *end;
|
||||||
|
|
||||||
|
(void) vctx; /* Unused */
|
||||||
|
|
||||||
child_ctx = (struct child_ctx *) verto_get_private(ev);
|
child_ctx = (struct child_ctx *) verto_get_private(ev);
|
||||||
if (child_ctx == NULL) {
|
if (child_ctx == NULL) {
|
||||||
otpd_log_err(EINVAL, "Lost child context");
|
otpd_log_err(EINVAL, "Lost child context");
|
||||||
@@ -426,7 +353,7 @@ int oauth2(struct otpd_queue_item **item, enum oauth2_state oauth2_state)
|
|||||||
char *args[50] = {NULL};
|
char *args[50] = {NULL};
|
||||||
size_t args_idx = 0;
|
size_t args_idx = 0;
|
||||||
krb5_data data_state = {0};
|
krb5_data data_state = {0};
|
||||||
struct otpd_queue_item *saved_item;
|
struct otpd_queue_item *saved_item = NULL;
|
||||||
|
|
||||||
if (oauth2_state != OAUTH2_GET_DEVICE_CODE
|
if (oauth2_state != OAUTH2_GET_DEVICE_CODE
|
||||||
&& oauth2_state != OAUTH2_GET_ACCESS_TOKEN) {
|
&& oauth2_state != OAUTH2_GET_ACCESS_TOKEN) {
|
||||||
|
|||||||
@@ -34,8 +34,8 @@
|
|||||||
#define DEFAULT_RETRIES 3
|
#define DEFAULT_RETRIES 3
|
||||||
|
|
||||||
/* Convert an LDAP entry into an allocated string. */
|
/* Convert an LDAP entry into an allocated string. */
|
||||||
static int get_string(LDAP *ldp, LDAPMessage *entry, const char *name,
|
int get_string(LDAP *ldp, LDAPMessage *entry, const char *name,
|
||||||
char **out)
|
char **out)
|
||||||
{
|
{
|
||||||
struct berval **vals;
|
struct berval **vals;
|
||||||
ber_len_t i;
|
ber_len_t i;
|
||||||
@@ -69,12 +69,12 @@ static int get_string(LDAP *ldp, LDAPMessage *entry, const char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Convert an LDAP entry into an allocated string array. */
|
/* Convert an LDAP entry into an allocated string array. */
|
||||||
static int get_string_array(LDAP *ldp, LDAPMessage *entry, const char *name,
|
int get_string_array(LDAP *ldp, LDAPMessage *entry, const char *name,
|
||||||
char ***out)
|
char ***out)
|
||||||
{
|
{
|
||||||
struct berval **vals;
|
struct berval **vals;
|
||||||
ber_len_t i;
|
ber_len_t i;
|
||||||
char **buf;
|
char **buf = NULL;
|
||||||
int tmp;
|
int tmp;
|
||||||
size_t count;
|
size_t count;
|
||||||
size_t c;
|
size_t c;
|
||||||
@@ -188,6 +188,11 @@ const char *otpd_parse_user(LDAP *ldp, LDAPMessage *entry,
|
|||||||
if (i != 0 && i != ENOENT)
|
if (i != 0 && i != ENOENT)
|
||||||
return strerror(i);
|
return strerror(i);
|
||||||
|
|
||||||
|
i = get_string_array(ldp, entry, "ipaPassKey",
|
||||||
|
&item->user.ipaPassKey);
|
||||||
|
if (i != 0 && i != ENOENT)
|
||||||
|
return strerror(i);
|
||||||
|
|
||||||
i = get_string_array(ldp, entry, "ipauserauthtype",
|
i = get_string_array(ldp, entry, "ipauserauthtype",
|
||||||
&item->user.ipauserauthtypes);
|
&item->user.ipauserauthtypes);
|
||||||
if (i != 0 && i != ENOENT)
|
if (i != 0 && i != ENOENT)
|
||||||
|
|||||||
@@ -0,0 +1,824 @@
|
|||||||
|
/*
|
||||||
|
* FreeIPA 2FA companion daemon
|
||||||
|
*
|
||||||
|
* Authors: Sumit Bose <sbose@redhat.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Sumit Bose, Red Hat
|
||||||
|
* see file 'COPYING' for use and warranty information
|
||||||
|
*
|
||||||
|
* This program is free software you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file contains various helper functions for the passkey feature.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE /* for asprintf() */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
struct passkey_data {
|
||||||
|
int phase;
|
||||||
|
char *state;
|
||||||
|
union {
|
||||||
|
struct passkey_challenge {
|
||||||
|
char *domain;
|
||||||
|
json_t *credential_id_list;
|
||||||
|
int user_verification;
|
||||||
|
unsigned char *cryptographic_challenge;
|
||||||
|
} challenge;
|
||||||
|
|
||||||
|
struct sss_passkey_reply {
|
||||||
|
char *credential_id;
|
||||||
|
char *cryptographic_challenge;
|
||||||
|
char *authenticator_data;
|
||||||
|
char *assertion_signature;
|
||||||
|
char *user_id;
|
||||||
|
} response;
|
||||||
|
} data;
|
||||||
|
json_t *jdata;
|
||||||
|
json_t *jroot;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct otpd_queue_item_passkey {
|
||||||
|
char *domain;
|
||||||
|
char *ipaRequireUserVerification;
|
||||||
|
struct passkey_data *data_in;
|
||||||
|
struct passkey_data *data_out;
|
||||||
|
krb5_data state;
|
||||||
|
char* ipapasskeyDebugLevelStr;
|
||||||
|
krb5_boolean ipapasskeyDebugFido2;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void free_passkey_data(struct passkey_data *p)
|
||||||
|
{
|
||||||
|
if (p == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->phase == 1) {
|
||||||
|
free(p->data.challenge.domain);
|
||||||
|
free(p->data.challenge.cryptographic_challenge);
|
||||||
|
}
|
||||||
|
|
||||||
|
json_decref(p->jdata);
|
||||||
|
json_decref(p->jroot);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_otpd_queue_item_passkey(struct otpd_queue_item *item)
|
||||||
|
{
|
||||||
|
if (item == NULL || item->passkey == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(item->passkey->domain);
|
||||||
|
free(item->passkey->ipaRequireUserVerification);
|
||||||
|
|
||||||
|
free_passkey_data(item->passkey->data_in);
|
||||||
|
free_passkey_data(item->passkey->data_out);
|
||||||
|
|
||||||
|
free(item->passkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct otpd_queue_item_passkey *get_otpd_queue_item_passkey(void)
|
||||||
|
{
|
||||||
|
struct otpd_queue_item_passkey *p;
|
||||||
|
|
||||||
|
p = calloc(1, sizeof(struct otpd_queue_item_passkey));
|
||||||
|
if (p == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->data_in = calloc(1, sizeof(struct passkey_data));
|
||||||
|
if (p->data_in == NULL) {
|
||||||
|
free(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->data_out = calloc(1, sizeof(struct passkey_data));
|
||||||
|
if (p->data_out == NULL) {
|
||||||
|
free(p->data_in);
|
||||||
|
free(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->data_in->phase = -1;
|
||||||
|
p->data_out->phase = -1;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PASSKEY_PREFIX "passkey "
|
||||||
|
#define ENV_PASSKEY_CHILD_DEBUG_LEVEL "passkey_child_debug_level"
|
||||||
|
|
||||||
|
/* Parse the passkey configuration */
|
||||||
|
const char *otpd_parse_passkey(LDAP *ldp, LDAPMessage *entry,
|
||||||
|
struct otpd_queue_item *item)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char **objectclasses = NULL;
|
||||||
|
long dbg_lvl = 0;
|
||||||
|
const char *dbg_env = NULL;
|
||||||
|
char *endptr = NULL;
|
||||||
|
|
||||||
|
if (item->passkey == NULL) {
|
||||||
|
otpd_log_req(item->req,
|
||||||
|
"Missing passkey struct to store passkey configuration");
|
||||||
|
return strerror(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (entry != NULL) {
|
||||||
|
i = get_string_array(ldp, entry, "objectclass", &objectclasses);
|
||||||
|
if (i != 0) {
|
||||||
|
return strerror(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth_type_is(objectclasses, "ipapasskeyconfigobject")) {
|
||||||
|
free(objectclasses);
|
||||||
|
|
||||||
|
i = get_string(ldp, entry, "ipaRequireUserVerification",
|
||||||
|
&item->passkey->ipaRequireUserVerification);
|
||||||
|
if ((i != 0) && (i != ENOENT)) {
|
||||||
|
return strerror(i);
|
||||||
|
}
|
||||||
|
} else if (auth_type_is(objectclasses, "domainRelatedObject")) {
|
||||||
|
free(objectclasses);
|
||||||
|
|
||||||
|
i = get_string(ldp, entry, "associatedDomain",
|
||||||
|
&item->passkey->domain);
|
||||||
|
if ((i != 0) && (i != ENOENT)) {
|
||||||
|
return strerror(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = ldap_next_entry(ldp, entry);
|
||||||
|
};
|
||||||
|
|
||||||
|
item->passkey->ipapasskeyDebugLevelStr = NULL;
|
||||||
|
item->passkey->ipapasskeyDebugFido2 = FALSE;
|
||||||
|
dbg_env = getenv(ENV_PASSKEY_CHILD_DEBUG_LEVEL);
|
||||||
|
if (dbg_env != NULL && *dbg_env != '\0') {
|
||||||
|
errno = 0;
|
||||||
|
dbg_lvl = strtoul(dbg_env, &endptr, 10);
|
||||||
|
if (errno == 0 && *endptr == '\0') {
|
||||||
|
if (dbg_lvl < 0) {
|
||||||
|
dbg_lvl = 0;
|
||||||
|
} else if (dbg_lvl > 10) {
|
||||||
|
dbg_lvl = 10;
|
||||||
|
}
|
||||||
|
if (asprintf(&item->passkey->ipapasskeyDebugLevelStr, "%ld",
|
||||||
|
dbg_lvl) != -1) {
|
||||||
|
if (dbg_lvl > 5) {
|
||||||
|
item->passkey->ipapasskeyDebugFido2 = TRUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
otpd_log_req(item->req, "Failed to copy debug level");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
otpd_log_req(item->req,
|
||||||
|
"Cannot parse value [%s] from environment variable [%s]",
|
||||||
|
dbg_env, ENV_PASSKEY_CHILD_DEBUG_LEVEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decode_json(const char *inp, size_t size, struct passkey_data *data)
|
||||||
|
{
|
||||||
|
json_error_t jret;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
data->jroot = json_loadb(inp, size, 0, &jret);
|
||||||
|
if (data->jroot == NULL) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
data->jdata = NULL;
|
||||||
|
data->phase = -1;
|
||||||
|
|
||||||
|
ret = json_unpack(data->jroot, "{s:i, s?:s, s?:o}",
|
||||||
|
"phase", &data->phase,
|
||||||
|
"state", &data->state,
|
||||||
|
"data", &data->jdata);
|
||||||
|
if (ret != 0) {
|
||||||
|
ret = EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (data->phase) {
|
||||||
|
case 0: /* SSS_PASSKEY_PHASE_INIT */
|
||||||
|
/* no data */
|
||||||
|
if (data->jdata != NULL) {
|
||||||
|
ret = EINVAL;
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: /* SSS_PASSKEY_PHASE_REPLY */
|
||||||
|
ret = json_unpack(data->jdata, "{s:s, s:s, s:s, s:s}",
|
||||||
|
"credential_id", &data->data.response.credential_id,
|
||||||
|
"cryptographic_challenge", &data->data.response.cryptographic_challenge,
|
||||||
|
"authenticator_data", &data->data.response.authenticator_data,
|
||||||
|
"assertion_signature", &data->data.response.assertion_signature,
|
||||||
|
"user_id", &data->data.response.user_id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (ret != 0) {
|
||||||
|
json_decref(data->jdata);
|
||||||
|
data->jdata = NULL;
|
||||||
|
json_decref(data->jroot);
|
||||||
|
data->jroot = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int passkey_parse_data(const char *data, size_t size, struct otpd_queue_item *item)
|
||||||
|
{
|
||||||
|
item->passkey = get_otpd_queue_item_passkey();
|
||||||
|
if (item->passkey == NULL) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return decode_json(data, size, item->passkey->data_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_passkey(struct otpd_queue_item *item)
|
||||||
|
{
|
||||||
|
const krb5_data *data_pwd;
|
||||||
|
krb5_data data_state = { 0 };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (item->passkey != NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_pwd = krad_packet_get_attr(item->req,
|
||||||
|
krad_attr_name2num("User-Password"), 0);
|
||||||
|
ret = get_krad_attr_from_packet(item->req,
|
||||||
|
krad_attr_name2num("Proxy-State"),
|
||||||
|
&data_state);
|
||||||
|
|
||||||
|
if (data_pwd == NULL && ret == 0
|
||||||
|
&& data_state.length > strlen(PASSKEY_PREFIX)
|
||||||
|
&& strncmp(data_state.data, PASSKEY_PREFIX,
|
||||||
|
strlen(PASSKEY_PREFIX)) == 0
|
||||||
|
&& (item->user.ipauserauthtypes == NULL
|
||||||
|
|| item->user.ipauserauthtypes[0] == NULL
|
||||||
|
|| *(item->user.ipauserauthtypes[0]) == '\0'
|
||||||
|
|| auth_type_is(item->user.ipauserauthtypes, "passkey"))) {
|
||||||
|
|
||||||
|
ret = passkey_parse_data(data_state.data + strlen(PASSKEY_PREFIX),
|
||||||
|
data_state.length - strlen(PASSKEY_PREFIX) - 1,
|
||||||
|
item);
|
||||||
|
krb5_free_data_contents(NULL, &data_state);
|
||||||
|
if (ret != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define PK_PREF "passkey:"
|
||||||
|
|
||||||
|
static json_t *ipa_passkey_to_json_array(char **ipa_passkey)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const char *sep;
|
||||||
|
char *start;
|
||||||
|
size_t c;
|
||||||
|
json_t *ja = NULL;
|
||||||
|
json_t *js;
|
||||||
|
|
||||||
|
if (ipa_passkey == NULL || *ipa_passkey == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ja = json_array();
|
||||||
|
if (ja == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (c = 0; ipa_passkey[c] != NULL; c++) {
|
||||||
|
if (strncmp(ipa_passkey[c], PK_PREF, strlen(PK_PREF)) != 0) {
|
||||||
|
otpd_log_err(ret, "Missing prefix in [%s]", ipa_passkey[c]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
start = ipa_passkey[c] + strlen(PK_PREF);
|
||||||
|
sep = strchr(start, ',');
|
||||||
|
if (sep == NULL || sep == start) {
|
||||||
|
otpd_log_err(ret, "Missing seperator in [%s]", ipa_passkey[c]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
js = json_stringn(start, sep - start);
|
||||||
|
if (js == NULL) {
|
||||||
|
ret = ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = json_array_append_new(ja, js);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (ret != 0) {
|
||||||
|
json_decref(ja);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ja;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* passkey string:
|
||||||
|
* key_handle,public_key(,optional_user_id)
|
||||||
|
*/
|
||||||
|
static char *ipa_passkey_get_public_key(char **ipa_passkey, const char *key_id)
|
||||||
|
{
|
||||||
|
char *sep;
|
||||||
|
char *sep2;
|
||||||
|
size_t c;
|
||||||
|
char *start;
|
||||||
|
|
||||||
|
if (ipa_passkey == NULL || *ipa_passkey == NULL
|
||||||
|
|| key_id == NULL || *key_id == '\0') {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (c = 0; ipa_passkey[c] != NULL; c++) {
|
||||||
|
if (strncmp(ipa_passkey[c], PK_PREF, strlen(PK_PREF)) != 0) {
|
||||||
|
otpd_log_err(EINVAL, "Missing prefix in [%s]", ipa_passkey[c]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
start = ipa_passkey[c] + strlen(PK_PREF);
|
||||||
|
|
||||||
|
sep = strchr(start, ',');
|
||||||
|
if (sep == NULL || sep == start) {
|
||||||
|
otpd_log_err(EINVAL, "Missing seperator in [%s]", ipa_passkey[c]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(start, key_id, sep - start) == 0) {
|
||||||
|
sep2 = strchrnul(sep + 1, ',');
|
||||||
|
if (sep2 == sep + 1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*sep2 = '\0';
|
||||||
|
return (sep + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHALLENGE_LENGTH 32
|
||||||
|
static unsigned char *get_b64_challenge(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned char buf[CHALLENGE_LENGTH];
|
||||||
|
unsigned char *b64;
|
||||||
|
|
||||||
|
ret = RAND_bytes(buf, CHALLENGE_LENGTH);
|
||||||
|
if (ret != 1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
b64 = calloc(1, 2 * CHALLENGE_LENGTH);
|
||||||
|
if (b64 == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = EVP_EncodeBlock(b64, buf, CHALLENGE_LENGTH);
|
||||||
|
if (ret == 0) {
|
||||||
|
free(b64);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b64;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int prepare_rad_reply(struct otpd_queue_item *item)
|
||||||
|
{
|
||||||
|
krad_attrset *attrset = NULL;
|
||||||
|
int ret;
|
||||||
|
json_t *jtmp = NULL;
|
||||||
|
char *stmp = NULL;
|
||||||
|
krb5_data data = { 0 };
|
||||||
|
|
||||||
|
ret = krad_attrset_new(ctx.kctx, &attrset);
|
||||||
|
if (ret != 0) {
|
||||||
|
otpd_log_err(ret, "Failed to create radius attribute set");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtmp = json_pack("{s:i, s:s, s:o}", "phase", item->passkey->data_out->phase,
|
||||||
|
"state", item->passkey->data_out->state,
|
||||||
|
"data", item->passkey->data_out->jdata);
|
||||||
|
if (jtmp == NULL) {
|
||||||
|
ret = EIO;
|
||||||
|
otpd_log_err(ret, "Failed to pack JSON reply");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
stmp = json_dumps(jtmp, JSON_COMPACT);
|
||||||
|
if (stmp == NULL) {
|
||||||
|
ret = EIO;
|
||||||
|
otpd_log_err(ret, "Failed to dump JSON string");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = asprintf(&(data.data), "passkey %s", stmp);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = ENOMEM;
|
||||||
|
otpd_log_err(ret, "Failed to generate reply string");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
data.length = strlen(data.data);
|
||||||
|
data.magic = 0;
|
||||||
|
|
||||||
|
|
||||||
|
ret = add_krad_attr_to_set(item->req, attrset, &data,
|
||||||
|
krad_attr_name2num("Proxy-State"),
|
||||||
|
"Failed to serialize state to attribute set");
|
||||||
|
if (ret != 0) {
|
||||||
|
otpd_log_err(ret, "Failed to add Proxy-State");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = krad_packet_new_response(ctx.kctx, SECRET,
|
||||||
|
krad_code_name2num("Access-Challenge"),
|
||||||
|
attrset,
|
||||||
|
item->req, &item->rsp);
|
||||||
|
if (ret != 0) {
|
||||||
|
otpd_log_err(ret, "Failed to create radius response");
|
||||||
|
item->rsp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
krad_attrset_free(attrset);
|
||||||
|
free(stmp);
|
||||||
|
json_decref(jtmp);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
free(data.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_passkey_challenge(struct otpd_queue_item *item)
|
||||||
|
{
|
||||||
|
unsigned char *challenge = NULL;
|
||||||
|
int ret;
|
||||||
|
struct passkey_data *d;
|
||||||
|
|
||||||
|
d = item->passkey->data_out;
|
||||||
|
|
||||||
|
d->data.challenge.credential_id_list = ipa_passkey_to_json_array(
|
||||||
|
item->user.ipaPassKey);
|
||||||
|
if (d->data.challenge.credential_id_list == NULL) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Secure by default, assume user verification is enabled and disable it
|
||||||
|
* only if the option is set to 'false'. */
|
||||||
|
d->data.challenge.user_verification = 1;
|
||||||
|
if (item->passkey->ipaRequireUserVerification != NULL
|
||||||
|
&& strcasecmp(item->passkey->ipaRequireUserVerification,
|
||||||
|
"false") == 0) {
|
||||||
|
d->data.challenge.user_verification = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->data.challenge.cryptographic_challenge = get_b64_challenge();
|
||||||
|
if (d->data.challenge.cryptographic_challenge == NULL) {
|
||||||
|
ret = ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->jdata = json_pack("{s:s, s:o, s:i, s:s}",
|
||||||
|
"domain", item->passkey->domain,
|
||||||
|
"credential_id_list",
|
||||||
|
d->data.challenge.credential_id_list,
|
||||||
|
"user_verification",
|
||||||
|
d->data.challenge.user_verification,
|
||||||
|
"cryptographic_challenge",
|
||||||
|
d->data.challenge.cryptographic_challenge);
|
||||||
|
if (d->jdata == NULL) {
|
||||||
|
ret = EIO;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->phase = 1; /* SSS_PASSKEY_PHASE_CHALLENGE */
|
||||||
|
d->state = strdup("ipa_otpd state");
|
||||||
|
|
||||||
|
ret = prepare_rad_reply(item);
|
||||||
|
if (ret != 0) {
|
||||||
|
otpd_log_err(ret, "prepare_rad_reply() failed.");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
done:
|
||||||
|
free(challenge);
|
||||||
|
|
||||||
|
otpd_queue_push(&ctx.stdio.responses, item);
|
||||||
|
verto_set_flags(ctx.stdio.writer, VERTO_EV_FLAG_PERSIST |
|
||||||
|
VERTO_EV_FLAG_IO_ERROR |
|
||||||
|
VERTO_EV_FLAG_IO_READ |
|
||||||
|
VERTO_EV_FLAG_IO_WRITE);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct child_ctx {
|
||||||
|
int read_from_child;
|
||||||
|
int write_to_child;
|
||||||
|
verto_ev *read_ev;
|
||||||
|
verto_ev *write_ev;
|
||||||
|
verto_ev *child_ev;
|
||||||
|
struct otpd_queue_item *item;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void passkey_on_child_writable(verto_ctx *vctx, verto_ev *ev)
|
||||||
|
{
|
||||||
|
(void)vctx; /* Unused */
|
||||||
|
|
||||||
|
/* no input needed */
|
||||||
|
verto_del(ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void passkey_on_child_readable(verto_ctx *vctx, verto_ev *ev)
|
||||||
|
{
|
||||||
|
(void)vctx; /* Unused */
|
||||||
|
|
||||||
|
/* no output expected */
|
||||||
|
verto_del(ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void passkey_on_child_exit(verto_ctx *vctx, verto_ev *ev)
|
||||||
|
{
|
||||||
|
(void)vctx; /* Unused */
|
||||||
|
int ret;
|
||||||
|
verto_proc_status st;
|
||||||
|
struct child_ctx *child_ctx = NULL;
|
||||||
|
|
||||||
|
child_ctx = (struct child_ctx *) verto_get_private(ev);
|
||||||
|
if (child_ctx == NULL) {
|
||||||
|
otpd_log_err(EINVAL, "Lost child context");
|
||||||
|
verto_del(ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure ctx.stdio.responses will at least return an error */
|
||||||
|
child_ctx->item->rsp = NULL;
|
||||||
|
child_ctx->item->sent = 0;
|
||||||
|
|
||||||
|
st = verto_get_proc_status(ev);
|
||||||
|
|
||||||
|
if (!WIFEXITED(st)) {
|
||||||
|
otpd_log_err(0, "Child didn't exit normally.");
|
||||||
|
verto_del(ev);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The krad req might not be available at this stage anymore, so
|
||||||
|
* otpd_log_err() is used. */
|
||||||
|
otpd_log_err(0, "Child finished with status [%d].", WEXITSTATUS(st));
|
||||||
|
|
||||||
|
verto_del(ev);
|
||||||
|
|
||||||
|
if (WEXITSTATUS(st) != 0) {
|
||||||
|
/* verification failed */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = krad_packet_new_response(ctx.kctx, SECRET,
|
||||||
|
krad_code_name2num("Access-Accept"), NULL,
|
||||||
|
child_ctx->item->req, &child_ctx->item->rsp);
|
||||||
|
if (ret != 0) {
|
||||||
|
otpd_log_err(ret, "Failed to create radius response");
|
||||||
|
child_ctx->item->rsp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
otpd_queue_push(&ctx.stdio.responses, child_ctx->item);
|
||||||
|
verto_set_flags(ctx.stdio.writer, VERTO_EV_FLAG_PERSIST |
|
||||||
|
VERTO_EV_FLAG_IO_ERROR |
|
||||||
|
VERTO_EV_FLAG_IO_READ |
|
||||||
|
VERTO_EV_FLAG_IO_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_child_ctx(verto_ctx *vctx, verto_ev *ev)
|
||||||
|
{
|
||||||
|
(void)vctx; /* Unused */
|
||||||
|
struct child_ctx *child_ctx;
|
||||||
|
|
||||||
|
child_ctx = verto_get_private(ev);
|
||||||
|
|
||||||
|
free(child_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_fd_nonblocking(int fd)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
flags = fcntl(fd, F_GETFL, 0);
|
||||||
|
if (flags == -1) {
|
||||||
|
ret = errno;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||||
|
ret = errno;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PASSKEY_CHILD_PATH
|
||||||
|
#define PASSKEY_CHILD_PATH "/usr/libexec/sssd/passkey_child"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int do_passkey_response(struct otpd_queue_item *item)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
pid_t child_pid;
|
||||||
|
int pipefd_to_child[2] = { -1, -1};
|
||||||
|
int pipefd_from_child[2] = { -1, -1};
|
||||||
|
/* Up to 50 arguments to the helper supported. The amount of arguments
|
||||||
|
* is controlled inside this function. Right now max used is below 20 */
|
||||||
|
char *args[50] = {NULL};
|
||||||
|
size_t args_idx = 0;
|
||||||
|
struct child_ctx *child_ctx;
|
||||||
|
char *pk = NULL;
|
||||||
|
|
||||||
|
child_ctx = calloc(sizeof(struct child_ctx), 1);
|
||||||
|
if (child_ctx == NULL) {
|
||||||
|
ret = ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
child_ctx->item = item;
|
||||||
|
|
||||||
|
pk = ipa_passkey_get_public_key(item->user.ipaPassKey,
|
||||||
|
item->passkey->data_in->data.response.credential_id);
|
||||||
|
if (pk == NULL) {
|
||||||
|
ret = EINVAL;
|
||||||
|
otpd_log_err(ret, "No matching public key found for [%s]",
|
||||||
|
item->passkey->data_in->data.response.credential_id);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
args[args_idx++] = PASSKEY_CHILD_PATH;
|
||||||
|
args[args_idx++] = "--verify-assert";
|
||||||
|
args[args_idx++] = "--domain";
|
||||||
|
args[args_idx++] = item->passkey->domain;
|
||||||
|
args[args_idx++] = "--key-handle";
|
||||||
|
args[args_idx++] = item->passkey->data_in->data.response.credential_id;
|
||||||
|
args[args_idx++] = "--public-key";
|
||||||
|
args[args_idx++] = pk;
|
||||||
|
args[args_idx++] = "--cryptographic-challenge";
|
||||||
|
args[args_idx++] = item->passkey->data_in->data.response.cryptographic_challenge;
|
||||||
|
args[args_idx++] = "--auth-data";
|
||||||
|
args[args_idx++] = item->passkey->data_in->data.response.authenticator_data;
|
||||||
|
args[args_idx++] = "--signature";
|
||||||
|
args[args_idx++] = item->passkey->data_in->data.response.assertion_signature;
|
||||||
|
if (item->passkey->ipapasskeyDebugLevelStr != NULL) {
|
||||||
|
args[args_idx++] = "--debug-level";
|
||||||
|
args[args_idx++] = item->passkey->ipapasskeyDebugLevelStr;
|
||||||
|
}
|
||||||
|
if (item->passkey->ipapasskeyDebugFido2) {
|
||||||
|
args[args_idx++] = "--debug-libfido2";
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pipe(pipefd_from_child);
|
||||||
|
if (ret == -1) {
|
||||||
|
ret = errno;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ret = pipe(pipefd_to_child);
|
||||||
|
if (ret == -1) {
|
||||||
|
ret = errno;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
child_pid = fork();
|
||||||
|
|
||||||
|
if (child_pid == 0) { /* child */
|
||||||
|
close(pipefd_to_child[1]);
|
||||||
|
ret = dup2(pipefd_to_child[0], STDIN_FILENO);
|
||||||
|
if (ret == -1) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(pipefd_from_child[0]);
|
||||||
|
ret = dup2(pipefd_from_child[1], STDOUT_FILENO);
|
||||||
|
if (ret == -1) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
execv(args[0], args);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else if (child_pid > 0) { /* parent */
|
||||||
|
close(pipefd_to_child[0]);
|
||||||
|
set_fd_nonblocking(pipefd_to_child[1]);
|
||||||
|
child_ctx->write_to_child = pipefd_to_child[1];
|
||||||
|
|
||||||
|
close(pipefd_from_child[1]);
|
||||||
|
set_fd_nonblocking(pipefd_from_child[0]);
|
||||||
|
child_ctx->read_from_child = pipefd_from_child[0];
|
||||||
|
|
||||||
|
child_ctx->write_ev = verto_add_io(ctx.vctx, VERTO_EV_FLAG_PERSIST |
|
||||||
|
VERTO_EV_FLAG_IO_CLOSE_FD |
|
||||||
|
VERTO_EV_FLAG_IO_ERROR |
|
||||||
|
VERTO_EV_FLAG_IO_WRITE,
|
||||||
|
passkey_on_child_writable,
|
||||||
|
child_ctx->write_to_child);
|
||||||
|
if (child_ctx->write_ev == NULL) {
|
||||||
|
ret = ENOMEM;
|
||||||
|
otpd_log_err(ret, "Unable to initialize passkey writer event");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
verto_set_private(child_ctx->write_ev, child_ctx, NULL);
|
||||||
|
|
||||||
|
child_ctx->read_ev = verto_add_io(ctx.vctx, VERTO_EV_FLAG_PERSIST |
|
||||||
|
VERTO_EV_FLAG_IO_CLOSE_FD |
|
||||||
|
VERTO_EV_FLAG_IO_ERROR |
|
||||||
|
VERTO_EV_FLAG_IO_READ,
|
||||||
|
passkey_on_child_readable,
|
||||||
|
child_ctx->read_from_child);
|
||||||
|
if (child_ctx->read_ev == NULL) {
|
||||||
|
ret = ENOMEM;
|
||||||
|
otpd_log_err(ret, "Unable to initialize passkey reader event");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
verto_set_private(child_ctx->read_ev, child_ctx, NULL);
|
||||||
|
|
||||||
|
child_ctx->child_ev = verto_add_child(ctx.vctx, VERTO_EV_FLAG_NONE,
|
||||||
|
passkey_on_child_exit, child_pid);
|
||||||
|
verto_set_private(child_ctx->child_ev, child_ctx, free_child_ctx);
|
||||||
|
|
||||||
|
} else { /* error */
|
||||||
|
ret = errno;
|
||||||
|
otpd_log_err(ret, "Failed to fork passkey_child");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (ret != 0) {
|
||||||
|
free(child_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_passkey(struct otpd_queue_item *item)
|
||||||
|
{
|
||||||
|
if (item == NULL || item->passkey == NULL
|
||||||
|
|| item->passkey->data_in == NULL) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (item->passkey->data_in->phase) {
|
||||||
|
case 0: /* SSS_PASSKEY_PHASE_INIT */
|
||||||
|
return do_passkey_challenge(item);
|
||||||
|
case 2: /* SSS_PASSKEY_PHASE_REPLY */
|
||||||
|
return do_passkey_response(item);
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -36,6 +36,16 @@
|
|||||||
#define DEFAULT_TIMEOUT 15
|
#define DEFAULT_TIMEOUT 15
|
||||||
#define DEFAULT_RETRIES 3
|
#define DEFAULT_RETRIES 3
|
||||||
|
|
||||||
|
/* To read passkey configuration and attributes from a different server than
|
||||||
|
* FreeIPA you might have to the following two defines of the search filter
|
||||||
|
* for the global configuration data and the attribute name where if passkey
|
||||||
|
* information is stored in the user entry. Additionally otpd_parse_passkey()
|
||||||
|
* might need some updates depending on how the global configuration is stored
|
||||||
|
* in the configuration objects.
|
||||||
|
*/
|
||||||
|
#define PASSKEY_CONFIG_FILTER "(|(objectclass=ipapasskeyconfigobject)(&(objectclass=domain)(objectclass=domainRelatedObject)))"
|
||||||
|
#define PASSKEY_USER_ATTR "ipapasskey"
|
||||||
|
|
||||||
static char *user[] = {
|
static char *user[] = {
|
||||||
"uid",
|
"uid",
|
||||||
"ipatokenRadiusUserName",
|
"ipatokenRadiusUserName",
|
||||||
@@ -43,6 +53,7 @@ static char *user[] = {
|
|||||||
"ipaidpSub",
|
"ipaidpSub",
|
||||||
"ipaidpConfigLink",
|
"ipaidpConfigLink",
|
||||||
"ipauserauthtype",
|
"ipauserauthtype",
|
||||||
|
PASSKEY_USER_ATTR,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,7 +80,7 @@ static char *idp[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool auth_type_is(char **auth_types, const char *check)
|
bool auth_type_is(char **auth_types, const char *check)
|
||||||
{
|
{
|
||||||
size_t c;
|
size_t c;
|
||||||
|
|
||||||
@@ -122,6 +133,14 @@ static void on_query_writable(verto_ctx *vctx, verto_ev *ev)
|
|||||||
NULL, NULL, 1, &item->msgid);
|
NULL, NULL, 1, &item->msgid);
|
||||||
free(filter);
|
free(filter);
|
||||||
|
|
||||||
|
} else if (item->get_passkey_config) {
|
||||||
|
otpd_log_req(item->req, "passkey config query start:");
|
||||||
|
item->ldap_query = LDAP_QUERY_PASSKEY;
|
||||||
|
|
||||||
|
i = ldap_search_ext(verto_get_private(ev), ctx.query.base,
|
||||||
|
LDAP_SCOPE_SUBTREE, PASSKEY_CONFIG_FILTER, NULL, 0, NULL,
|
||||||
|
NULL, NULL, 0, &item->msgid);
|
||||||
|
|
||||||
} else if (auth_type_is(item->user.ipauserauthtypes, "idp")) {
|
} else if (auth_type_is(item->user.ipauserauthtypes, "idp")) {
|
||||||
otpd_log_req(item->req, "idp query start: %s",
|
otpd_log_req(item->req, "idp query start: %s",
|
||||||
item->user.ipaidpConfigLink);
|
item->user.ipaidpConfigLink);
|
||||||
@@ -283,6 +302,9 @@ static void on_query_readable(verto_ctx *vctx, verto_ev *ev)
|
|||||||
case LDAP_QUERY_IDP:
|
case LDAP_QUERY_IDP:
|
||||||
err = otpd_parse_idp(ldp, entry, item);
|
err = otpd_parse_idp(ldp, entry, item);
|
||||||
break;
|
break;
|
||||||
|
case LDAP_QUERY_PASSKEY:
|
||||||
|
err = otpd_parse_passkey(ldp, entry, item);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ldap_msgfree(entry);
|
ldap_msgfree(entry);
|
||||||
goto egress;
|
goto egress;
|
||||||
@@ -331,10 +353,35 @@ static void on_query_readable(verto_ctx *vctx, verto_ev *ev)
|
|||||||
goto egress;
|
goto egress;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LDAP_QUERY_PASSKEY:
|
||||||
|
otpd_log_req(item->req, "passkey query end: %s",
|
||||||
|
item->error == NULL ? "ok" : item->error);
|
||||||
|
if (item->passkey == NULL) {
|
||||||
|
goto egress;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
goto egress;
|
goto egress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for passkey */
|
||||||
|
if (is_passkey(item)) {
|
||||||
|
if (item->ldap_query == LDAP_QUERY_USER) {
|
||||||
|
item->get_passkey_config = true;
|
||||||
|
|
||||||
|
push = &ctx.query.requests;
|
||||||
|
event = ctx.query.io;
|
||||||
|
goto egress;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = do_passkey(item);
|
||||||
|
if (i != 0) {
|
||||||
|
goto egress;
|
||||||
|
}
|
||||||
|
/* do_passkey will call ctx.stdio.writer, so we can return here */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for oauth2 */
|
/* Check for oauth2 */
|
||||||
oauth2_state = get_oauth2_state(item->ldap_query, item);
|
oauth2_state = get_oauth2_state(item->ldap_query, item);
|
||||||
if (oauth2_state == OAUTH2_GET_ISSUER) {
|
if (oauth2_state == OAUTH2_GET_ISSUER) {
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ void otpd_queue_item_free(struct otpd_queue_item *item)
|
|||||||
free(item->error);
|
free(item->error);
|
||||||
krad_packet_free(item->req);
|
krad_packet_free(item->req);
|
||||||
krad_packet_free(item->rsp);
|
krad_packet_free(item->rsp);
|
||||||
|
|
||||||
|
free_otpd_queue_item_passkey(item);
|
||||||
|
|
||||||
free(item);
|
free(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -503,8 +503,8 @@ void test_pack_ber_user_timeout(void **state)
|
|||||||
oldgetgrgid_r = test_data->ctx->nss_ctx->getgrgid_r;
|
oldgetgrgid_r = test_data->ctx->nss_ctx->getgrgid_r;
|
||||||
test_data->ctx->nss_ctx->getgrgid_r = getgrgid_r_timeout;
|
test_data->ctx->nss_ctx->getgrgid_r = getgrgid_r_timeout;
|
||||||
|
|
||||||
ret = pack_ber_user(test_data->ctx, RESP_USER_GROUPLIST,
|
ret = pack_ber_user(test_data->ctx, RESP_USER_GROUPLIST, TEST_DOMAIN_NAME,
|
||||||
TEST_DOMAIN_NAME, "member001", 12345, 54321,
|
"member001@"TEST_DOMAIN_NAME, 12345, 54321,
|
||||||
"gecos", "homedir", "shell", NULL, &resp_val);
|
"gecos", "homedir", "shell", NULL, &resp_val);
|
||||||
test_data->ctx->nss_ctx->getgrgid_r = oldgetgrgid_r;
|
test_data->ctx->nss_ctx->getgrgid_r = oldgetgrgid_r;
|
||||||
assert_int_equal(ret, LDAP_TIMELIMIT_EXCEEDED);
|
assert_int_equal(ret, LDAP_TIMELIMIT_EXCEEDED);
|
||||||
@@ -548,15 +548,17 @@ void test_encode(void **state)
|
|||||||
assert_memory_equal(res_nam, resp_val->bv_val, resp_val->bv_len);
|
assert_memory_equal(res_nam, resp_val->bv_val, resp_val->bv_len);
|
||||||
ber_bvfree(resp_val);
|
ber_bvfree(resp_val);
|
||||||
|
|
||||||
ret = pack_ber_user(ctx, RESP_USER, TEST_DOMAIN_NAME, "test", 12345, 54321,
|
ret = pack_ber_user(ctx, RESP_USER, TEST_DOMAIN_NAME,
|
||||||
NULL, NULL, NULL, NULL, &resp_val);
|
"test@"TEST_DOMAIN_NAME, 12345, 54321, NULL, NULL,
|
||||||
|
NULL, NULL, &resp_val);
|
||||||
assert_int_equal(ret, LDAP_SUCCESS);
|
assert_int_equal(ret, LDAP_SUCCESS);
|
||||||
assert_int_equal(sizeof(res_uid), resp_val->bv_len);
|
assert_int_equal(sizeof(res_uid), resp_val->bv_len);
|
||||||
assert_memory_equal(res_uid, resp_val->bv_val, resp_val->bv_len);
|
assert_memory_equal(res_uid, resp_val->bv_val, resp_val->bv_len);
|
||||||
ber_bvfree(resp_val);
|
ber_bvfree(resp_val);
|
||||||
|
|
||||||
ret = pack_ber_group(RESP_GROUP, TEST_DOMAIN_NAME, "test_group", 54321,
|
ret = pack_ber_group(RESP_GROUP, TEST_DOMAIN_NAME,
|
||||||
NULL, NULL, &resp_val);
|
"test_group@"TEST_DOMAIN_NAME, 54321, NULL, NULL,
|
||||||
|
&resp_val);
|
||||||
assert_int_equal(ret, LDAP_SUCCESS);
|
assert_int_equal(ret, LDAP_SUCCESS);
|
||||||
assert_int_equal(sizeof(res_gid), resp_val->bv_len);
|
assert_int_equal(sizeof(res_gid), resp_val->bv_len);
|
||||||
assert_memory_equal(res_gid, resp_val->bv_val, resp_val->bv_len);
|
assert_memory_equal(res_gid, resp_val->bv_val, resp_val->bv_len);
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#define _GNU_SOURCE 1 /* for asprintf() */
|
#define _GNU_SOURCE 1 /* for asprintf() */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
@@ -106,7 +107,7 @@ static int inc_buffer(size_t buf_max, size_t *_buf_len, char **_buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __nss_to_err(enum nss_status errcode)
|
static int __nss_to_err(enum nss_status errcode)
|
||||||
{
|
{
|
||||||
switch(errcode) {
|
switch(errcode) {
|
||||||
case NSS_STATUS_SUCCESS:
|
case NSS_STATUS_SUCCESS:
|
||||||
@@ -526,6 +527,30 @@ int pack_ber_sid(const char *sid, struct berval **berval)
|
|||||||
return LDAP_SUCCESS;
|
return LDAP_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool verify_domain(const char *fqdn, const char *domain_name)
|
||||||
|
{
|
||||||
|
const char *pos = strrchr(fqdn, SSSD_DOMAIN_SEPARATOR);
|
||||||
|
if (pos == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (strcasecmp(pos + 1, domain_name) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_short_name(const char *fqdn, const char *domain_name)
|
||||||
|
{
|
||||||
|
const char *pos = strrchr(fqdn, SSSD_DOMAIN_SEPARATOR);
|
||||||
|
if (pos == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp(pos + 1, domain_name) != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strndup(fqdn, pos - fqdn);
|
||||||
|
}
|
||||||
|
|
||||||
int pack_ber_user(struct ipa_extdom_ctx *ctx,
|
int pack_ber_user(struct ipa_extdom_ctx *ctx,
|
||||||
enum response_types response_type,
|
enum response_types response_type,
|
||||||
const char *domain_name, const char *user_name,
|
const char *domain_name, const char *user_name,
|
||||||
@@ -542,19 +567,13 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx,
|
|||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
struct group grp;
|
struct group grp;
|
||||||
size_t c;
|
size_t c;
|
||||||
char *locat;
|
|
||||||
char *short_user_name = NULL;
|
char *short_user_name = NULL;
|
||||||
|
|
||||||
short_user_name = strdup(user_name);
|
short_user_name = get_short_name(user_name, domain_name);
|
||||||
if ((locat = strrchr(short_user_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
|
if (short_user_name == NULL) {
|
||||||
if (strcasecmp(locat+1, domain_name) == 0 ) {
|
/* domain mismatch */
|
||||||
locat[0] = '\0';
|
ret = LDAP_NO_SUCH_OBJECT;
|
||||||
} else {
|
goto done;
|
||||||
/* The found object is from a different domain than requested,
|
|
||||||
* that means it does not exist in the requested domain */
|
|
||||||
ret = LDAP_NO_SUCH_OBJECT;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ber = ber_alloc_t( LBER_USE_DER );
|
ber = ber_alloc_t( LBER_USE_DER );
|
||||||
@@ -657,19 +676,13 @@ int pack_ber_group(enum response_types response_type,
|
|||||||
BerElement *ber = NULL;
|
BerElement *ber = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
size_t c;
|
size_t c;
|
||||||
char *locat;
|
|
||||||
char *short_group_name = NULL;
|
char *short_group_name = NULL;
|
||||||
|
|
||||||
short_group_name = strdup(group_name);
|
short_group_name = get_short_name(group_name, domain_name);
|
||||||
if ((locat = strrchr(short_group_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
|
if (short_group_name == NULL) {
|
||||||
if (strcasecmp(locat+1, domain_name) == 0 ) {
|
/* domain mismatch */
|
||||||
locat[0] = '\0';
|
ret = LDAP_NO_SUCH_OBJECT;
|
||||||
} else {
|
goto done;
|
||||||
/* The found object is from a different domain than requested,
|
|
||||||
* that means it does not exist in the requested domain */
|
|
||||||
ret = LDAP_NO_SUCH_OBJECT;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ber = ber_alloc_t( LBER_USE_DER );
|
ber = ber_alloc_t( LBER_USE_DER );
|
||||||
@@ -735,8 +748,8 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pack_ber_name_list(struct extdom_req *req, char **fq_name_list,
|
static int pack_ber_name_list(struct extdom_req *req, char **fq_name_list,
|
||||||
struct berval **berval)
|
struct berval **berval)
|
||||||
{
|
{
|
||||||
BerElement *ber = NULL;
|
BerElement *ber = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -892,6 +905,10 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
|
|||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if (!verify_domain(pwd.pw_name, domain_name)) {
|
||||||
|
ret = LDAP_NO_SUCH_OBJECT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (request_type == REQ_FULL_WITH_GROUPS) {
|
if (request_type == REQ_FULL_WITH_GROUPS) {
|
||||||
ret = sss_nss_getorigbyusername_timeout(pwd.pw_name, get_timeout(ctx),
|
ret = sss_nss_getorigbyusername_timeout(pwd.pw_name, get_timeout(ctx),
|
||||||
@@ -971,6 +988,10 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
|
|||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if (!verify_domain(grp.gr_name, domain_name)) {
|
||||||
|
ret = LDAP_NO_SUCH_OBJECT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (request_type == REQ_FULL_WITH_GROUPS) {
|
if (request_type == REQ_FULL_WITH_GROUPS) {
|
||||||
ret = sss_nss_getorigbygroupname_timeout(grp.gr_name, get_timeout(ctx),
|
ret = sss_nss_getorigbygroupname_timeout(grp.gr_name, get_timeout(ctx),
|
||||||
@@ -1273,6 +1294,10 @@ static int handle_username_request(struct ipa_extdom_ctx *ctx,
|
|||||||
ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len);
|
ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len);
|
||||||
switch(ret) {
|
switch(ret) {
|
||||||
case 0:
|
case 0:
|
||||||
|
if (!verify_domain(pwd.pw_name, domain_name)) {
|
||||||
|
ret = LDAP_NO_SUCH_OBJECT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if (request_type == REQ_FULL_WITH_GROUPS) {
|
if (request_type == REQ_FULL_WITH_GROUPS) {
|
||||||
ret = sss_nss_getorigbyusername_timeout(pwd.pw_name,
|
ret = sss_nss_getorigbyusername_timeout(pwd.pw_name,
|
||||||
get_timeout(ctx),
|
get_timeout(ctx),
|
||||||
@@ -1363,6 +1388,10 @@ static int handle_groupname_request(struct ipa_extdom_ctx *ctx,
|
|||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if (!verify_domain(grp.gr_name, domain_name)) {
|
||||||
|
ret = LDAP_NO_SUCH_OBJECT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (request_type == REQ_FULL_WITH_GROUPS) {
|
if (request_type == REQ_FULL_WITH_GROUPS) {
|
||||||
ret = sss_nss_getorigbygroupname_timeout(grp.gr_name, get_timeout(ctx),
|
ret = sss_nss_getorigbygroupname_timeout(grp.gr_name, get_timeout(ctx),
|
||||||
|
|||||||
@@ -359,7 +359,8 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb)
|
|||||||
Slapi_ValueSet *values = NULL;
|
Slapi_ValueSet *values = NULL;
|
||||||
long grace_limit = 0;
|
long grace_limit = 0;
|
||||||
int grace_user_time;
|
int grace_user_time;
|
||||||
char *pwd_expiration = NULL;
|
char *tmpstr = NULL;
|
||||||
|
time_t pwd_expiration;
|
||||||
int pwresponse_requested = 0;
|
int pwresponse_requested = 0;
|
||||||
Slapi_PBlock *pbtm = NULL;
|
Slapi_PBlock *pbtm = NULL;
|
||||||
Slapi_Mods *smods = NULL;
|
Slapi_Mods *smods = NULL;
|
||||||
@@ -414,12 +415,17 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb)
|
|||||||
}
|
}
|
||||||
slapi_value_free(&objectclass);
|
slapi_value_free(&objectclass);
|
||||||
|
|
||||||
pwd_expiration = slapi_entry_attr_get_charptr(target_entry, "krbPasswordExpiration");
|
tmpstr = slapi_entry_attr_get_charptr(target_entry, "krbPasswordExpiration");
|
||||||
if (pwd_expiration == NULL) {
|
if (tmpstr == NULL) {
|
||||||
/* No expiration means nothing to do */
|
/* No expiration means nothing to do */
|
||||||
LOG_TRACE("No krbPasswordExpiration for %s, nothing to do\n", dn);
|
LOG_TRACE("No krbPasswordExpiration for %s, nothing to do\n", dn);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
pwd_expiration = ipapwd_gentime_to_time_t(tmpstr);
|
||||||
|
if (pwd_expiration > time(NULL)) {
|
||||||
|
/* Not expired, nothing to see here */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
ldrc = ipagraceperiod_getpolicy(target_entry, &policy_entry,
|
ldrc = ipagraceperiod_getpolicy(target_entry, &policy_entry,
|
||||||
&values, &actual_type_name,
|
&values, &actual_type_name,
|
||||||
@@ -473,7 +479,7 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb)
|
|||||||
if (pwresponse_requested) {
|
if (pwresponse_requested) {
|
||||||
slapi_pwpolicy_make_response_control(pb, -1, grace_limit - grace_user_time , -1);
|
slapi_pwpolicy_make_response_control(pb, -1, grace_limit - grace_user_time , -1);
|
||||||
}
|
}
|
||||||
} else if ((grace_limit > 0) && (grace_user_time >= grace_limit)) {
|
} else if (grace_user_time >= grace_limit) {
|
||||||
LOG_TRACE("%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";
|
errstr = "Password is expired.\n";
|
||||||
ret = LDAP_INVALID_CREDENTIALS;
|
ret = LDAP_INVALID_CREDENTIALS;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ void *ipa_otp_lasttoken_plugin_id;
|
|||||||
|
|
||||||
static bool entry_is_token(Slapi_Entry *entry)
|
static bool entry_is_token(Slapi_Entry *entry)
|
||||||
{
|
{
|
||||||
char **ocls;
|
char **ocls = NULL;
|
||||||
|
|
||||||
ocls = slapi_entry_attr_get_charray(entry, SLAPI_ATTR_OBJECTCLASS);
|
ocls = slapi_entry_attr_get_charray(entry, SLAPI_ATTR_OBJECTCLASS);
|
||||||
for (size_t i = 0; ocls != NULL && ocls[i] != NULL; i++) {
|
for (size_t i = 0; ocls != NULL && ocls[i] != NULL; i++) {
|
||||||
@@ -64,6 +64,7 @@ static bool entry_is_token(Slapi_Entry *entry)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slapi_ch_array_free(ocls);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +139,8 @@ static bool is_pwd_enabled(const char *user_dn)
|
|||||||
static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry)
|
static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry)
|
||||||
{
|
{
|
||||||
Slapi_DN *target_sdn = NULL;
|
Slapi_DN *target_sdn = NULL;
|
||||||
const char *bind_dn;
|
char *bind_dn;
|
||||||
|
bool rv = false;
|
||||||
|
|
||||||
/* Ignore internal operations. */
|
/* Ignore internal operations. */
|
||||||
if (slapi_op_internal(pb))
|
if (slapi_op_internal(pb))
|
||||||
@@ -147,23 +149,35 @@ static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry)
|
|||||||
/* Load parameters. */
|
/* Load parameters. */
|
||||||
(void) slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn);
|
(void) slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn);
|
||||||
(void) slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn);
|
(void) slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn);
|
||||||
if (target_sdn == NULL || bind_dn == NULL) {
|
if (bind_dn == NULL) {
|
||||||
LOG_FATAL("Missing parameters!\n");
|
LOG_FATAL("bind_dn parameter missing!\n");
|
||||||
return false;
|
goto done;
|
||||||
|
}
|
||||||
|
if (target_sdn == NULL) {
|
||||||
|
LOG_FATAL("target_sdn parameter missing!\n");
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry != NULL
|
if (entry != NULL
|
||||||
? !entry_is_token(entry)
|
? !entry_is_token(entry)
|
||||||
: !sdn_in_otp_container(target_sdn))
|
: !sdn_in_otp_container(target_sdn)) {
|
||||||
return true;
|
rv = true;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sdn_is_only_enabled_token(target_sdn, bind_dn))
|
if (!sdn_is_only_enabled_token(target_sdn, bind_dn)) {
|
||||||
return true;
|
rv = true;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_pwd_enabled(bind_dn))
|
if (is_pwd_enabled(bind_dn)) {
|
||||||
return true;
|
rv = true;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
done:
|
||||||
|
slapi_ch_free_string(&bind_dn);
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int send_error(Slapi_PBlock *pb, int rc, const char *errstr)
|
static inline int send_error(Slapi_PBlock *pb, int rc, const char *errstr)
|
||||||
|
|||||||
@@ -1433,7 +1433,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
|||||||
Slapi_DN *target_sdn = NULL;
|
Slapi_DN *target_sdn = NULL;
|
||||||
Slapi_DN *sdn = NULL;
|
Slapi_DN *sdn = NULL;
|
||||||
const char *dn = NULL;
|
const char *dn = NULL;
|
||||||
int method = 0;
|
ber_tag_t method = 0;
|
||||||
bool syncreq;
|
bool syncreq;
|
||||||
bool otpreq;
|
bool otpreq;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -1454,8 +1454,10 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We're only interested in simple authentication. */
|
/* We're only interested in simple authentication. */
|
||||||
if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0)
|
if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0) {
|
||||||
|
LOG("Not handled (not simple bind or NULL dn/credentials)\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Retrieve the user's entry. */
|
/* Retrieve the user's entry. */
|
||||||
sdn = slapi_sdn_dup(target_sdn);
|
sdn = slapi_sdn_dup(target_sdn);
|
||||||
@@ -1513,6 +1515,9 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reset rc to make sure errors are reported*/
|
||||||
|
rc = LDAP_INVALID_CREDENTIALS;
|
||||||
|
|
||||||
/* Authenticate the user. */
|
/* Authenticate the user. */
|
||||||
ret = ipapwd_authenticate(dn, entry, credentials);
|
ret = ipapwd_authenticate(dn, entry, credentials);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|||||||
@@ -398,6 +398,7 @@ static struct otp_token **find(const struct otp_config *cfg, const char *user_dn
|
|||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
slapi_free_search_results_internal(pb);
|
||||||
slapi_pblock_destroy(pb);
|
slapi_pblock_destroy(pb);
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -35,4 +35,5 @@ distclean: clean
|
|||||||
venv:
|
venv:
|
||||||
$(PYTHON) -m venv $(VENVDIR)
|
$(PYTHON) -m venv $(VENVDIR)
|
||||||
$(VENVDIR)/bin/python3 -m pip install -U pip setuptools
|
$(VENVDIR)/bin/python3 -m pip install -U pip setuptools
|
||||||
$(VENVDIR)/bin/python3 -m pip install -U -r ./requirements.txt
|
$(VENVDIR)/bin/python3 -m pip install -U -r ./requirements.txt \
|
||||||
|
-c constraints.txt
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _A6Record:
|
||||||
|
|
||||||
|
# A6Record
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A6 DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _AAAARecord:
|
||||||
|
|
||||||
|
# AAAARecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
AAAA DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _AFSDBRecord:
|
||||||
|
|
||||||
|
# AFSDBRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
AFSDB DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _APLRecord:
|
||||||
|
|
||||||
|
# APLRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
APL DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _ARecord:
|
||||||
|
|
||||||
|
# ARecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A DNS record.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _AccessTime:
|
||||||
|
|
||||||
|
# AccessTime
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Access time parameter type.
|
||||||
|
|
||||||
|
Accepts values conforming to generalizedTime as defined in RFC 4517 section 3.3.13 without time zone information.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Any:
|
||||||
|
|
||||||
|
# Any
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A parameter capable of holding values of any type. For internal use only.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _BinaryFile:
|
||||||
|
|
||||||
|
# BinaryFile
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Binary file parameter type.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Bool:
|
||||||
|
|
||||||
|
# Bool
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A parameter for boolean values (stored in the ``bool`` type).
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Bytes:
|
||||||
|
|
||||||
|
# Bytes
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A parameter for binary data (stored in the ``str`` type).
|
||||||
|
This class is named *Bytes* instead of *Str* so it's aligned with the
|
||||||
|
Python v3 ``(str, unicode) => (bytes, str)`` clean-up.
|
||||||
|
See: http://docs.python.org/3.0/whatsnew/3.0.html
|
||||||
|
Also see the `Str` parameter.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _BytesEnum:
|
||||||
|
|
||||||
|
# BytesEnum
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Enumerable for binary data (stored in the ``str`` type).
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _CERTRecord:
|
||||||
|
|
||||||
|
# CERTRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
CERT DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _CNAMERecord:
|
||||||
|
|
||||||
|
# CNAMERecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
CNAME DNS record.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Certificate:
|
||||||
|
|
||||||
|
# Certificate
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _CertificateSigningRequest:
|
||||||
|
|
||||||
|
# CertificateSigningRequest
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _DHCIDRecord:
|
||||||
|
|
||||||
|
# DHCIDRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
DHCID DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _DLVRecord:
|
||||||
|
|
||||||
|
# DLVRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
DLV DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _DNAMERecord:
|
||||||
|
|
||||||
|
# DNAMERecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
DNAME DNS record.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _DNOrURL:
|
||||||
|
|
||||||
|
# DNOrURL
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
DN parameter that allows, and strips, a "ldap:///" prefix on input.
|
||||||
|
|
||||||
|
Used for ``subtree`` to maintain backward compatibility.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _DNParam:
|
||||||
|
|
||||||
|
# DNParam
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
LDAP DN.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _DNSNameParam:
|
||||||
|
|
||||||
|
# DNSNameParam
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Domain name parameter type.
|
||||||
|
|
||||||
|
* `only_absolute`: a domain name has to be absolute (makes it absolute from unicode input)
|
||||||
|
* `only_relative`: a domain name has to be relative
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _DNSRecord:
|
||||||
|
|
||||||
|
# DNSRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Base class for DNS records, subclass of `Str`.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _DSRecord:
|
||||||
|
|
||||||
|
# DSRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
DS DNS record.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Data:
|
||||||
|
|
||||||
|
# Data
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Base class for the `Bytes` and `Str` parameters.
|
||||||
|
|
||||||
|
Previously `Str` was as subclass of `Bytes`. Now the common functionality
|
||||||
|
has been split into this base class so that ``isinstance(foo, Bytes)`` wont
|
||||||
|
be ``True`` when ``foo`` is actually an `Str` instance (which is confusing).
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _DateTime:
|
||||||
|
|
||||||
|
# DateTime
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
DateTime parameter type.
|
||||||
|
|
||||||
|
Accepts LDAP Generalized time without in the following format:
|
||||||
|
'%Y%m%d%H%M%SZ'
|
||||||
|
|
||||||
|
Accepts subset of values defined by ISO 8601:
|
||||||
|
'%Y-%m-%dT%H:%M:%SZ'
|
||||||
|
'%Y-%m-%dT%H:%MZ'
|
||||||
|
'%Y-%m-%dZ'
|
||||||
|
|
||||||
|
Also accepts above formats using ' ' (space) as a separator instead of 'T'.
|
||||||
|
|
||||||
|
Refer to the `man strftime` for the explanations for the %Y,%m,%d,%H.%M,%S.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Decimal:
|
||||||
|
|
||||||
|
# Decimal
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A parameter for floating-point values (stored in the ``Decimal`` type).
|
||||||
|
|
||||||
|
Python Decimal type helps overcome problems tied to plain "float" type,
|
||||||
|
e.g. problem with representation or value comparison. In order to safely
|
||||||
|
transfer the value over RPC libraries, it is being converted to string
|
||||||
|
which is then converted back to Decimal number.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Dict:
|
||||||
|
|
||||||
|
# Dict
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A parameter for dictionary.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Enum:
|
||||||
|
|
||||||
|
# Enum
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Base class for parameters with enumerable values.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _File:
|
||||||
|
|
||||||
|
# File
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Text file parameter type.
|
||||||
|
|
||||||
|
Accepts file names and loads their content into the parameter value.
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Flag:
|
||||||
|
|
||||||
|
# Flag
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A boolean parameter that always gets filled in with a default value.
|
||||||
|
|
||||||
|
This `Bool` subclass forces ``autofill=True`` in `Flag.__init__()`. If no
|
||||||
|
default is provided, it also fills in a default value of ``False``.
|
||||||
|
Lastly, unlike the `Bool` class, the default must be either ``True`` or
|
||||||
|
``False`` and cannot be ``None``.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
```
|
||||||
|
>>> flag = Flag('my_flag')
|
||||||
|
>>> (flag.autofill, flag.default)
|
||||||
|
(True, False)
|
||||||
|
```
|
||||||
|
|
||||||
|
To have a default value of ``True``, create your `Flag` intance with
|
||||||
|
``default=True``. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
>>> flag = Flag('my_flag', default=True)
|
||||||
|
>>> (flag.autofill, flag.default)
|
||||||
|
(True, True)
|
||||||
|
```
|
||||||
|
|
||||||
|
Also note that creating a `Flag` instance with ``autofill=False`` will have
|
||||||
|
no effect. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
>>> flag = Flag('my_flag', autofill=False)
|
||||||
|
>>> flag.autofill
|
||||||
|
True
|
||||||
|
```
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _ForwardRecord:
|
||||||
|
|
||||||
|
# ForwardRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Forward DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _HINFORecord:
|
||||||
|
|
||||||
|
# HINFORecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
HINFO DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _HIPRecord:
|
||||||
|
|
||||||
|
# HIPRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
HIP DNS record.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _HostPassword:
|
||||||
|
|
||||||
|
# HostPassword
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A data type for host passwords to not log password values.
|
||||||
|
|
||||||
|
The `Password` type cannot be used because it disallows
|
||||||
|
setting a password on the command-line which would break
|
||||||
|
backwards compatibility.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _IA5Str:
|
||||||
|
|
||||||
|
# IA5Str
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
An IA5String per RFC 4517.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _IPSECKEYRecord:
|
||||||
|
|
||||||
|
# IPSECKEYRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
IPSECKEY DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Int:
|
||||||
|
|
||||||
|
# Int
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A parameter for integer values (stored in the ``int`` type).
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _IntEnum:
|
||||||
|
|
||||||
|
# IntEnum
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Enumerable for integer data (stored in the ``int`` type).
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _KEYRecord:
|
||||||
|
|
||||||
|
# KEYRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
KEY DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _KXRecord:
|
||||||
|
|
||||||
|
# KXRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
KX DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _LOCRecord:
|
||||||
|
|
||||||
|
# LOCRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
LOC DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _MDRecord:
|
||||||
|
|
||||||
|
# MDRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
MD DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _MINFORecord:
|
||||||
|
|
||||||
|
# MINFORecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
MINFO DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _MXRecord:
|
||||||
|
|
||||||
|
# MXRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
MX DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _NAPTRRecord:
|
||||||
|
|
||||||
|
# NAPTRRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
NAPTR DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _NSECRecord:
|
||||||
|
|
||||||
|
# NSECRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
NSEC DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _NSRecord:
|
||||||
|
|
||||||
|
# NSRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
NS DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _NXTRecord:
|
||||||
|
|
||||||
|
# NXTRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
NXT DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Number:
|
||||||
|
|
||||||
|
# Number
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
Base class for the `Int` and `Decimal` parameters.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _OTPTokenKey:
|
||||||
|
|
||||||
|
# OTPTokenKey
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A binary password type specified in base32.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _PTRRecord:
|
||||||
|
|
||||||
|
# PTRRecord
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
PTR DNS record.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
.. _Password:
|
||||||
|
|
||||||
|
# Password
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
|
||||||
|
A parameter for passwords (stored in the ``unicode`` type).
|
||||||
Loaded 100 of 962 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user