On Mon, 2014-06-16 at 09:53 +0200, Petr Viktorin wrote:
> On 06/13/2014 10:20 PM, Simo Sorce wrote:
> [...]
> > 2) and I think this is a MUCH bigger issue, the Admin users are
> > unbounded and pass any Access Control Check and this means they can now
> > retrieve any key for users or machines.
> > It is already bad enough that admins can unconditionally set any key,
> > but this at least leaves back a pretty big trail (the original client
> > password/key fails to work), and is a necessary evil (password resets,
> > hosts creation/recovery).
> > But I am not very comfortable with the idea an admin can retrieve any
> > key without actually ending up changing it. Petr do we have any short
> > term plan to address the Admin's super ACI ?
> 
> No, nothing in the short term.

Ok, then I think attached is the patch 0003 we want.
This changes admins superpowers to not allow ipaProtectedOperation by
default and instead adds a specific right in cn=accounts so admin can
keep fetching keytabs for any principal. We may want to turn this into a
permission with a future patch.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York
>From e57e6286e2b8bd3764ca9501117526554d3f416b Mon Sep 17 00:00:00 2001
From: Simo Sorce <s...@redhat.com>
Date: Tue, 17 Sep 2013 00:30:14 -0400
Subject: [PATCH 3/6] keytab: Add new extended operation to get a keytab.

This new extended operation allow to create new keys or retrieve
existing ones. The new set of keys is returned as a ASN.1 structure
similar to the one that is passed in by the 'set keytab' extended
operation.

Access to the operation is regulated through a new special ACI that
allows 'retrieval' only if the user has access to an attribute named
ipaProtectedOperation postfixed by the subtypes 'read_keys' and
'write_keys' to distinguish between creation and retrieval operation.

For example for allowing retrieval by a specific user the following ACI
is set on cn=accounts:

(targetattr="ipaProtectedOperation;read_keys") ...
 ... userattr=ipaAllowedToPerform;read_keys#USERDN)

This ACI matches only if the service object hosts a new attribute named
ipaAllowedToPerform that holds the DN of the user attempting the
operation.

Resolves:
https://fedorahosted.org/freeipa/ticket/3859
---
 .../ipa-pwd-extop/ipa_pwd_extop.c                  | 571 +++++++++++++++++++++
 install/share/60basev3.ldif                        |   3 +
 install/share/default-aci.ldif                     |   7 +
 install/updates/20-aci.update                      |  13 +-
 util/ipa_krb5.h                                    |   1 +
 5 files changed, 594 insertions(+), 1 deletion(-)

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 c0bb9fda26172699e9ae7628f61b763c746188fe..e0f90832400dd470b18e21177c135f2855b6f239 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 {
+ *     request      [0] Request,
+ *     reply        [1] Reply
+ * }
+ *
+ * Request ::= SEQUENCE {
+ *     serviceIdentity [0] OCTET STRING,
+ *     getNew          [1] Boolean,
+ *     password        [2] OCTET STRING OPTIONAL,
+ *     enctypes        [3] SEQUENCE OF Int16 OPTIONAL
+ * }
+ */
+
+#define GKREQ_PASSWORD_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2)
+#define GKREQ_ENCTYPES_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 3)
+
+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 ctag;
+    ber_int_t getnew = 0;
+    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 != (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0)) {
+        LOG_FATAL("ber_peek_tag failed\n");
+        err_msg = "Invalid payload.\n";
+        rc = LDAP_PROTOCOL_ERROR;
+        goto done;
+    }
+
+    /* ber parse code */
+    rtag = ber_scanf(ber, "t[{t[a]", &ctag, &ctag, &svcname);
+    if (rtag == LBER_ERROR) {
+        LOG_FATAL("ber_scanf failed to decode service name\n");
+        err_msg = "Invalid payload.\n";
+        rc = LDAP_PROTOCOL_ERROR;
+        goto done;
+    }
+
+    rtag = ber_scanf(ber, "t[b]", &ctag, &getnew);
+    if (rtag == LBER_ERROR) {
+        LOG_FATAL("ber_scanf failed to decode request type\n");
+        err_msg = "Invalid payload.\n";
+        rc = LDAP_PROTOCOL_ERROR;
+        goto done;
+    }
+
+    rtag = ber_peek_tag(ber, &tlen);
+    if (rtag == GKREQ_PASSWORD_TAG) {
+        /* optional password present */
+        rtag = ber_scanf(ber, "[a]", &password);
+        if (rtag == LBER_ERROR) {
+            LOG_FATAL("ber_scanf failed to decode password\n");
+            err_msg = "Invalid payload.\n";
+            rc = LDAP_PROTOCOL_ERROR;
+            goto done;
+        }
+        rtag = ber_peek_tag(ber, &tlen);
+    }
+
+    if (rtag == GKREQ_ENCTYPES_TAG) {
+        rtag = ber_scanf(ber, "[{");
+        if (rtag == LBER_ERROR) {
+            LOG_FATAL("ber_scanf failed to decode enctypes\n");
+            err_msg = "Invalid payload.\n";
+            rc = LDAP_PROTOCOL_ERROR;
+            goto done;
+        }
+
+        rtag = ber_peek_tag(ber, &tlen);
+        for (num = 0; rtag == 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;
+                }
+            }
+
+            rtag = ber_scanf(ber, "i", &enctype);
+            if (rtag == 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;
+            rtag = ber_peek_tag(ber, &tlen);
+        }
+    }
+
+    rc = LDAP_SUCCESS;
+
+done:
+    if (rc != LDAP_SUCCESS) {
+        free(password);
+        free(svcname);
+        *_err_msg = err_msg;
+    } else {
+        *_password = password;
+        *_svcname = svcname;
+        *wantold = (getnew == 0);
+        *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 GKREP_KVNO_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
+#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{", GKREP_KVNO_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 552045b63d9485ccd3685942b10c3f0e5b6105b6..ff148e97c879d5652b1ce3c9b41443d84d49fe40 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,4 +66,5 @@ 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')
 objectClasses: (2.16.840.1.113730.3.8.12.23 NAME 'ipaVirtualOperation' DESC 'IPA Virtual operation objectclass' SUP top AUXILIARY MUST ( cn ) X-ORIGIN 'IPA v3' )
diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif
index 04fc185f785ee71246c6cc4f958c754158f16302..9219ae945f7e014b4a207d6e82ac7c2cbf007b85 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,dc=ipa,dc=dev,dc=lan";;)
+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 6af800111f30d26d37ceb0849f8730a3e15dad0b..77b0352c0805b1485f6a99c8a9fdf3c0228725e8 100644
--- a/install/updates/20-aci.update
+++ b/install/updates/20-aci.update
@@ -39,7 +39,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";;)'
@@ -65,3 +66,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,dc=ipa,dc=dev,dc=lan";;)
+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 7fb0355724e3c4f522097df417d2686b85619319..2431fd70b01b86266700e0d30a9cbd2b8f7c7ded 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);
-- 
1.9.3

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to