diff options
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c | 571 | ||||
-rw-r--r-- | install/share/60basev3.ldif | 3 | ||||
-rw-r--r-- | install/share/default-aci.ldif | 7 | ||||
-rw-r--r-- | install/updates/20-aci.update | 13 | ||||
-rw-r--r-- | util/ipa_krb5.h | 1 |
5 files changed, 594 insertions, 1 deletions
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c index 0b084a4d1..90a92f1ef 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c @@ -1268,6 +1268,571 @@ free_and_return: return SLAPI_PLUGIN_EXTENDED_SENT_RESULT; } +/* Format of getkeytab request + * + * KeytabGetRequest ::= CHOICE { + * newkeys [0] Newkeys, + * curkeys [1] CurrentKeys, + * reply [2] Reply + * } + * + * NewKeys ::= SEQUENCE { + * serviceIdentity [0] OCTET STRING, + * enctypes [1] SEQUENCE OF Int16 + * password [2] OCTET STRING OPTIONAL, + * } + * + * CurrentKeys ::= SEQUENCE { + * serviceIdentity [0] OCTET STRING, + * } + */ + +#define GK_REQUEST_NEWKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) +#define GK_REQUEST_CURKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +#define GKREQ_SVCNAME_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +#define GKREQ_ENCTYPES_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +#define GKREQ_PASSWORD_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) + +static int decode_getkeytab_request(struct berval *extop, bool *wantold, + char **_svcname, char **_password, + krb5_key_salt_tuple **kenctypes, + int *num_kenctypes, char **_err_msg) +{ + int rc = LDAP_OPERATIONS_ERROR; + char *err_msg = NULL; + BerElement *ber = NULL; + ber_len_t tlen; + ber_tag_t rtag; + ber_tag_t ttag; + ber_tag_t ctag; + char *svcname = NULL; + char *password = NULL; + ber_int_t enctype; + krb5_key_salt_tuple *enctypes = NULL; + int num = 0; + + ber = ber_init(extop); + if (ber == NULL) { + err_msg = "KeytabGet Request decode failed.\n"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + + /* check this is a request */ + rtag = ber_peek_tag(ber, &tlen); + if (rtag != GK_REQUEST_NEWKEYS && rtag != GK_REQUEST_CURKEYS) { + LOG_FATAL("ber_peek_tag failed, wrong request type\n"); + err_msg = "Invalid payload.\n"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + + /* ber parse code */ + ttag = ber_scanf(ber, "{t[a]", &ctag, &svcname); + if (ttag == LBER_ERROR || ctag != GKREQ_SVCNAME_TAG) { + LOG_FATAL("ber_scanf failed to decode service name\n"); + err_msg = "Invalid payload.\n"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + + if (rtag == GK_REQUEST_CURKEYS) { + rc = LDAP_SUCCESS; + goto done; + } + + ttag = ber_peek_tag(ber, &tlen); + if (ttag != GKREQ_ENCTYPES_TAG) { + LOG_FATAL("ber_peek_tag failed to find enctypes\n"); + err_msg = "Invalid payload.\n"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + ttag = ber_peek_tag(ber, &tlen); + for (num = 0; ttag == LBER_INTEGER; num++) { + if ((num % 10) == 0) { + /* allocate space for at least 10 more enctypes */ + enctypes = realloc(enctypes, + (num + 10) * sizeof(krb5_key_salt_tuple)); + if (!enctypes) { + LOG_FATAL("allocation failed\n"); + err_msg = "Internal error\n"; + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + } + + ttag = ber_scanf(ber, "i", &enctype); + if (ttag == LBER_ERROR) { + LOG_FATAL("ber_scanf failed to decode enctype\n"); + err_msg = "Invalid payload.\n"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + + enctypes[num].ks_enctype = enctype; + enctypes[num].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; + ttag = ber_peek_tag(ber, &tlen); + } + + /* ttag peek done as last step of the previous for loop */ + if (ttag == GKREQ_PASSWORD_TAG) { + /* optional password present */ + ttag = ber_scanf(ber, "[a]", &password); + if (ttag == LBER_ERROR) { + LOG_FATAL("ber_scanf failed to decode password\n"); + err_msg = "Invalid payload.\n"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + } + + rc = LDAP_SUCCESS; + +done: + if (rc != LDAP_SUCCESS) { + free(password); + free(svcname); + *_err_msg = err_msg; + } else { + *_password = password; + *_svcname = svcname; + *wantold = (rtag == GK_REQUEST_CURKEYS); + *kenctypes = enctypes; + *num_kenctypes = num; + } + if (ber) ber_free(ber, 1); + return rc; +} + +/* Format of getkeytab reply + * + * Reply ::= SEQUENCE { + * new_kvno Int32 + * keys SEQUENCE OF KrbKey, + * } + * + * KrbKey ::= SEQUENCE { + * key [0] EncryptionKey, + * salt [1] KrbSalt OPTIONAL, + * s2kparams [2] OCTET STRING OPTIONAL, + * } + * + * EncryptionKey ::= SEQUENCE { + * keytype [0] Int32, + * keyvalue [1] OCTET STRING + * } + * + * KrbSalt ::= SEQUENCE { + * type [0] Int32, + * salt [1] OCTET STRING + * } + */ + +#define GK_REPLY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) +#define GKREP_KEY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) +#define GKREP_SALT_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +#define GKREP_S2KPARAMS_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) +#define GKREP_KEYTYPE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) +#define GKREP_KEYVALUE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +#define GKREP_SALTTYPE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) +#define GKREP_SALTVALUE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) + +static int encode_getkeytab_reply(krb5_context krbctx, + krb5_keyblock *kmkey, int mkvno, + krb5_key_data *keys, int num_keys, + struct berval **_bvp) +{ + int rc = LDAP_OPERATIONS_ERROR; + struct berval *bvp = NULL; + BerElement *ber = NULL; + ber_int_t kvno; + krb5_data plain = { 0 }; + + ber = ber_alloc(); + if (!ber) { + LOG_OOM(); + goto done; + } + + /* uses last key kvno */ + kvno = keys[num_keys-1].key_data_kvno; + + rc = ber_printf(ber, "t{i{", GK_REPLY_TAG, kvno); + if (rc == -1) { + rc = LDAP_OPERATIONS_ERROR; + LOG_FATAL("Failed to initiate key buffer\n"); + goto done; + } + + for (int i = 0; i < num_keys; i++) { + krb5_enc_data cipher = { 0 }; + krb5_int16 plen; + void *p; + + /* retrieve plain key */ + memcpy(&plen, keys[i].key_data_contents[0], 2); + cipher.ciphertext.data = (char *)keys[i].key_data_contents[0] + 2; + cipher.ciphertext.length = keys[i].key_data_length[0] - 2; + cipher.enctype = kmkey->enctype; + cipher.kvno = mkvno; + + plain.length = le16toh(plen); + p = realloc(plain.data, plain.length); + if (!p) { + LOG_FATAL("Failed to allocate plain buffer\n"); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + plain.data = p; + + rc = krb5_c_decrypt(krbctx, kmkey, 0, 0, &cipher, &plain); + if (rc) { + LOG_FATAL("Failed to decrypt keys\n"); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + rc = ber_printf(ber, + "{t[{t[i]t[o]}]", + GKREP_KEY_TAG, + GKREP_KEYTYPE_TAG, + (ber_int_t)keys[i].key_data_type[0], + GKREP_KEYVALUE_TAG, + plain.data, (ber_len_t)plain.length); + if (rc == -1) { + LOG_FATAL("Failed to encode key data\n"); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + /* if salt available, add it */ + if (keys[i].key_data_length[1] != 0) { + rc = ber_printf(ber, + "t[{t[i]t[o]}]", + GKREP_SALT_TAG, + GKREP_SALTTYPE_TAG, + (ber_int_t)keys[i].key_data_type[1], + GKREP_SALTVALUE_TAG, + keys[i].key_data_contents[1], + (ber_len_t)keys[i].key_data_length[1]); + if (rc == -1) { + LOG_FATAL("Failed to encode salt data\n"); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + } + + rc = ber_printf(ber, "}"); + if (rc == -1) { + LOG_FATAL("Failed to encode data\n"); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + } + + rc = ber_printf(ber, "}}"); + if (rc == -1) { + LOG_FATAL("Failed to terminate key buffer\n"); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + rc = ber_flatten(ber, &bvp); + if (rc == -1) { + LOG_FATAL("Failed to encode key buffer\n"); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + rc = LDAP_SUCCESS; + +done: + if (rc != LDAP_SUCCESS) { + if (bvp) ber_bvfree(bvp); + } else { + *_bvp = bvp; + } + if (ber) ber_free(ber, 1); + free(plain.data); + return rc; +} + +static int get_decoded_key_data(char *svcname, + krb5_key_data **_keys, int *_num_keys, + int *_mkvno, char **_err_msg) +{ + int rc = LDAP_OPERATIONS_ERROR; + char *err_msg = NULL; + krb5_key_data *keys = NULL; + int num_keys = 0; + int mkvno = 0; + Slapi_Entry *target = NULL; + Slapi_Attr *attr; + Slapi_Value *keys_value; + const struct berval *encoded_keys; + + target = get_entry_by_principal(svcname); + if (!target) { + err_msg = "PrincipalName disappeared while processing.\n"; + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + rc = slapi_entry_attr_find(target, "krbPrincipalKey", &attr); + if (rc) { + err_msg = "krbPrincipalKey not found\n"; + rc = LDAP_NO_SUCH_ATTRIBUTE; + goto done; + } + rc = slapi_attr_first_value(attr, &keys_value); + if (rc) { + err_msg = "Error retrieving krbPrincipalKey\n"; + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + encoded_keys = slapi_value_get_berval(keys_value); + if (!encoded_keys) { + err_msg = "Error retrieving encoded krbPrincipalKey\n"; + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + rc = ber_decode_krb5_key_data(discard_const(encoded_keys), + &mkvno, &num_keys, &keys); + if (rc) { + err_msg = "Error retrieving decoded krbPrincipalKey\n"; + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + if (num_keys <= 0) { + err_msg = "No krbPrincipalKeys available\n"; + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + + rc = LDAP_SUCCESS; + +done: + if (rc != LDAP_SUCCESS) { + if (keys) ipa_krb5_free_key_data(keys, num_keys); + *_err_msg = err_msg; + } else { + *_mkvno = mkvno; + *_keys = keys; + *_num_keys = num_keys; + } + if (target) slapi_entry_free(target); + return rc; +} + +#define WRITEKEYS_OP_CHECK "ipaProtectedOperation;write_keys" +#define READKEYS_OP_CHECK "ipaProtectedOperation;read_keys" + +/* Password Modify Extended operation plugin function */ +static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) +{ + char *bind_dn = NULL; + char *err_msg = NULL; + int rc = 0; + krb5_context krbctx = NULL; + krb5_error_code krberr; + struct berval *extop_value = NULL; + BerElement *ber = NULL; + char *service_name = NULL; + char *svcname; + Slapi_Entry *target_entry = NULL; + bool acl_ok = false; + char *password = NULL; + int num_kenctypes = 0; + krb5_key_salt_tuple *kenctypes = NULL; + int mkvno = 0; + int num_keys = 0; + krb5_key_data *keys = NULL; + struct ipapwd_data data = { 0 }; + Slapi_Value **svals = NULL; + struct berval *bvp = NULL; + LDAPControl new_ctrl; + bool wantold = false; + + /* Get Bind DN */ + slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn); + + /* If the connection is bound anonymously, we must refuse to process + * this operation. */ + if (bind_dn == NULL || *bind_dn == '\0') { + /* Refuse the operation because they're bound anonymously */ + err_msg = "Anonymous Binds are not allowed.\n"; + rc = LDAP_INSUFFICIENT_ACCESS; + goto free_and_return; + } + + krberr = krb5_init_context(&krbctx); + if (krberr) { + LOG_FATAL("krb5_init_context failed\n"); + rc = LDAP_OPERATIONS_ERROR; + goto free_and_return; + } + + /* Get the ber value of the extended operation */ + slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value); + if (!extop_value) { + LOG_FATAL("Failed to retrieve extended op value from pblock\n"); + err_msg = "Failed to retrieve extended operation value\n"; + rc = LDAP_OPERATIONS_ERROR; + goto free_and_return; + } + + rc = decode_getkeytab_request(extop_value, &wantold, &service_name, + &password, &kenctypes, &num_kenctypes, + &err_msg); + if (rc != LDAP_SUCCESS) { + goto free_and_return; + } + + /* make sure it is a valid name */ + svcname = check_service_name(krbctx, service_name); + if (!svcname) { + rc = LDAP_OPERATIONS_ERROR; + goto free_and_return; + } + slapi_ch_free_string(&service_name); + service_name = svcname; + + /* check entry */ + + /* get Entry by krbPrincipalName */ + target_entry = get_entry_by_principal(service_name); + if (!target_entry) { + err_msg = "PrincipalName not found.\n"; + rc = LDAP_NO_SUCH_OBJECT; + goto free_and_return; + } + + /* ok access allowed */ + /* do we need to create new keys ? */ + if (wantold) { /* requesting to retrieve existing ones */ + + /* check if we are allowed to *read* keys */ + acl_ok = is_allowed_to_access_attr(pb, bind_dn, target_entry, + READKEYS_OP_CHECK, NULL, + SLAPI_ACL_READ); + if (!acl_ok) { + LOG_FATAL("Not allowed to retrieve keytab on [%s]!\n", + service_name); + err_msg = "Insufficient access rights\n"; + rc = LDAP_INSUFFICIENT_ACCESS; + goto free_and_return; + } + + } else { + + /* check if we are allowed to *write* keys */ + acl_ok = is_allowed_to_access_attr(pb, bind_dn, target_entry, + WRITEKEYS_OP_CHECK, NULL, + SLAPI_ACL_WRITE); + if (!acl_ok) { + LOG_FATAL("Not allowed to set keytab on [%s]!\n", + service_name); + err_msg = "Insufficient access rights\n"; + rc = LDAP_INSUFFICIENT_ACCESS; + goto free_and_return; + } + + for (int i = 0; i < num_kenctypes; i++) { + + /* Check if supported */ + for (int j = 0; j < krbcfg->num_supp_encsalts; j++) { + if (kenctypes[i].ks_enctype == + krbcfg->supp_encsalts[j].ks_enctype) { + continue; + } + } + /* Unsupported, filter out */ + for (int j = i; j + 1 < num_kenctypes; j++) { + kenctypes[j].ks_enctype = kenctypes[j + 1].ks_enctype; + kenctypes[j].ks_salttype = kenctypes[j + 1].ks_salttype; + } + num_kenctypes--; + i--; + } + + /* check if we have any left */ + if (num_kenctypes == 0 && kenctypes != NULL) { + LOG_FATAL("keyset filtering rejected all proposed keys\n"); + err_msg = "All enctypes provided are unsupported"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto free_and_return; + } + + /* only target is used, leave everything else NULL, + * if password is not provided we want to generate a random key */ + data.target = target_entry; + data.password = password; + + svals = ipapwd_encrypt_encode_key(krbcfg, &data, + kenctypes ? num_kenctypes : + krbcfg->num_pref_encsalts, + kenctypes ? kenctypes : + krbcfg->pref_encsalts, + &err_msg); + if (!svals) { + rc = LDAP_OPERATIONS_ERROR; + LOG_FATAL("encrypt_encode_keys failed!\n"); + err_msg = "Internal error while encrypting keys\n"; + goto free_and_return; + } + + rc = store_new_keys(target_entry, service_name, bind_dn, svals, + &err_msg); + if (rc != LDAP_SUCCESS) { + goto free_and_return; + } + } + + rc = get_decoded_key_data(service_name, + &keys, &num_keys, &mkvno, &err_msg); + if (rc != LDAP_SUCCESS) { + goto free_and_return; + } + + rc = encode_getkeytab_reply(krbctx, krbcfg->kmkey, mkvno, + keys, num_keys, &bvp); + if (rc != LDAP_SUCCESS) { + err_msg = "Internal Error.\n"; + goto free_and_return; + } + + new_ctrl.ldctl_oid = KEYTAB_GET_OID; + new_ctrl.ldctl_value = *bvp; + new_ctrl.ldctl_iscritical = 0; + rc = slapi_pblock_set(pb, SLAPI_ADD_RESCONTROL, &new_ctrl); + +free_and_return: + if (rc == LDAP_SUCCESS) err_msg = NULL; + LOG("%s", err_msg ? err_msg : "success"); + slapi_send_ldap_result(pb, rc, NULL, err_msg, 0, NULL); + + /* Free anything that we allocated above */ + if (krbctx) krb5_free_context(krbctx); + free(kenctypes); + free(service_name); + free(password); + if (target_entry) slapi_entry_free(target_entry); + if (keys) ipa_krb5_free_key_data(keys, num_keys); + if (svals) { + for (int i = 0; svals[i]; i++) { + slapi_value_free(&svals[i]); + } + free(svals); + } + if (ber) ber_free(ber, 1); + if (bvp) ber_bvfree(bvp); + + return SLAPI_PLUGIN_EXTENDED_SENT_RESULT; +} + static int ipapwd_extop(Slapi_PBlock *pb) { struct ipapwd_krbcfg *krbcfg = NULL; @@ -1305,6 +1870,11 @@ static int ipapwd_extop(Slapi_PBlock *pb) free_ipapwd_krbcfg(&krbcfg); return ret; } + if (strcasecmp(oid, KEYTAB_GET_OID) == 0) { + ret = ipapwd_getkeytab(pb, krbcfg); + free_ipapwd_krbcfg(&krbcfg); + return ret; + } errMesg = "Request OID does not match supported OIDs.\n"; rc = LDAP_OPERATIONS_ERROR; @@ -1438,6 +2008,7 @@ done: static char *ipapwd_oid_list[] = { EXOP_PASSWD_OID, KEYTAB_SET_OID, + KEYTAB_GET_OID, NULL }; diff --git a/install/share/60basev3.ldif b/install/share/60basev3.ldif index 8b92af247..6282dc16a 100644 --- a/install/share/60basev3.ldif +++ b/install/share/60basev3.ldif @@ -46,6 +46,8 @@ attributeTypes: (2.16.840.1.113730.3.8.11.46 NAME 'ipaPermLocation' DESC 'Locati attributeTypes: (2.16.840.1.113730.3.8.11.47 NAME 'ipaPermRight' DESC 'IPA permission rights' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.48 NAME 'ipaPermTargetFilter' DESC 'IPA permission target filter' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.49 NAME 'ipaPermTarget' DESC 'IPA permission target' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) +attributeTypes: (2.16.840.1.113730.3.8.11.51 NAME 'ipaAllowedToPerform' DESC 'DNs allowed to perform an operation' SUP distinguishedName X-ORIGIN 'IPA-v3') +attributeTypes: (2.16.840.1.113730.3.8.11.52 NAME 'ipaProtectedOperation' DESC 'Operation to be protected' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) objectClasses: (2.16.840.1.113730.3.8.12.1 NAME 'ipaExternalGroup' SUP top STRUCTURAL MUST ( cn ) MAY ( ipaExternalMember $ memberOf $ description $ owner) X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.2 NAME 'ipaNTUserAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier ) MAY ( ipaNTHash $ ipaNTLogonScript $ ipaNTProfilePath $ ipaNTHomeDirectory $ ipaNTHomeDirectoryDrive ) X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.3 NAME 'ipaNTGroupAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier ) X-ORIGIN 'IPA v3' ) @@ -64,3 +66,4 @@ objectClasses: (2.16.840.1.113730.3.8.12.17 NAME 'ipaTrustedADDomainRange' SUP i objectClasses: (2.16.840.1.113730.3.8.12.19 NAME 'ipaUserAuthTypeClass' SUP top AUXILIARY DESC 'Class for authentication methods definition' MAY ipaUserAuthType X-ORIGIN 'IPA v3') objectClasses: (2.16.840.1.113730.3.8.12.20 NAME 'ipaUser' AUXILIARY MUST ( uid ) MAY ( userClass ) X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.21 NAME 'ipaPermissionV2' DESC 'IPA Permission objectclass, version 2' SUP ipaPermission AUXILIARY MUST ( ipaPermBindRuleType $ ipaPermLocation ) MAY ( ipaPermDefaultAttr $ ipaPermIncludedAttr $ ipaPermExcludedAttr $ ipaPermRight $ ipaPermTargetFilter $ ipaPermTarget ) X-ORIGIN 'IPA v3' ) +objectclasses: (2.16.840.1.113730.3.8.12.22 NAME 'ipaAllowedOperations' SUP top AUXILIARY DESC 'Class to apply access controls to arbitrary operations' MAY ( ipaAllowedToPerform $ ipaProtectedOperation ) X-ORIGIN 'IPA v3') diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif index a4a5d9954..af7eedb0b 100644 --- a/install/share/default-aci.ldif +++ b/install/share/default-aci.ldif @@ -26,6 +26,13 @@ changetype: modify add: aci aci: (targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policy"; allow (write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) aci: (targetattr = "aci")(version 3.0;acl "Admins can manage delegations"; allow (write, delete) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) +aci: (targetattr="ipaProtectedOperation;read_keys")(version 3.0; acl "Users allowed to retrieve keytab keys"; allow(read) userattr="ipaAllowedToPerform;read_keys#USERDN";) +aci: (targetattr="ipaProtectedOperation;read_keys")(version 3.0; acl "Groups allowed to retrieve keytab keys"; allow(read) userattr="ipaAllowedToPerform;read_keys#GROUPDN";) +aci: (targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Users allowed to create keytab keys"; allow(write) userattr="ipaAllowedToPerform;write_keys#USERDN";) +aci: (targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Groups allowed to create keytab keys"; allow(write) userattr="ipaAllowedToPerform;write_keys#GROUPDN";) +aci: (targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Entities are allowed to rekey themselves"; allow(write) userdn="ldap:///self";) +aci: (targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Admins are allowed to rekey any entity"; allow(write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) +aci: (targetfilter="(|(objectclass=ipaHost)(objectclass=ipaService))")(targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Entities are allowed to rekey managed entries"; allow(write) userattr="managedby#USERDN";) dn: cn=services,cn=accounts,$SUFFIX changetype: modify diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update index 4eb5c737a..76179bfb6 100644 --- a/install/updates/20-aci.update +++ b/install/updates/20-aci.update @@ -43,7 +43,8 @@ remove:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword | remove:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbUPEnabled || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || krbTicketFlags || ipaUniqueId || memberOf || serverHostName || enrolledBy || ipaNTHash")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' remove:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbUPEnabled || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || ipaUniqueId || memberOf || serverHostName || enrolledBy || ipaNTHash")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' remove:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbUPEnabled || krbTicketPolicyReference || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || ipaUniqueId || memberOf || serverHostName || enrolledBy || ipaNTHash")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' -add:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbPasswordExpiration || krbPwdHistory || krbLastPwdChange || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || ipaUniqueId || memberOf || enrolledBy || ipaNTHash")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' +remove:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbPasswordExpiration || krbPwdHistory || krbLastPwdChange || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || ipaUniqueId || memberOf || enrolledBy || ipaNTHash")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' +add:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbPasswordExpiration || krbPwdHistory || krbLastPwdChange || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || ipaUniqueId || memberOf || enrolledBy || ipaNTHash || ipaProtectedOperation")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' # Write-only remove:aci:'(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Admins can write passwords"; allow (add,delete,write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' add:aci:'(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || ipaNTHash")(version 3.0; acl "Admins can write passwords"; allow (add,delete,write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' @@ -69,3 +70,13 @@ remove:aci: '(targetattr = "*")(version 3.0; acl "No anonymous access to hbac"; dn: cn=sudo,$SUFFIX remove:aci: '(targetattr = "*")(version 3.0; acl "No anonymous access to sudo"; deny (read,search,compare) userdn != "ldap:///all";)' + +# Get Keytab operation Access Control +dn: cn=accounts,$SUFFIX +add:aci: '(targetattr="ipaProtectedOperation;read_keys")(version 3.0; acl "Users allowed to retrieve keytab keys"; allow(read) userattr="ipaAllowedToPerform;read_keys#USERDN";)' +add:aci: '(targetattr="ipaProtectedOperation;read_keys")(version 3.0; acl "Groups allowed to retrieve keytab keys"; allow(read) userattr="ipaAllowedToPerform;read_keys#GROUPDN";)' +add:aci: '(targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Users allowed to create keytab keys"; allow(write) userattr="ipaAllowedToPerform;write_keys#USERDN";)' +add:aci: '(targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Groups allowed to create keytab keys"; allow(write) userattr="ipaAllowedToPerform;write_keys#GROUPDN";)' +add:aci: '(targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Entities are allowed to rekey themselves"; allow(write) userdn="ldap:///self";)' +add:aci: '(targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Admins are allowed to rekey any entity"; allow(write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' +add:aci: '(targetfilter="(|(objectclass=ipaHost)(objectclass=ipaService))")(targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Entities are allowed to rekey managed entries"; allow(write) userattr="managedby#USERDN";)' diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h index 7fb035572..2431fd70b 100644 --- a/util/ipa_krb5.h +++ b/util/ipa_krb5.h @@ -27,6 +27,7 @@ struct keys_container { #define KEYTAB_SET_OID "2.16.840.1.113730.3.8.10.1" #define KEYTAB_RET_OID "2.16.840.1.113730.3.8.10.2" +#define KEYTAB_GET_OID "2.16.840.1.113730.3.8.10.5" void ipa_krb5_free_ktypes(krb5_context context, krb5_enctype *val); |