Example #1
0
/*
 * Walk the keytab, looking for entries of this principal name,
 * with KVNO other than current kvno -1.
 *
 * These entries are now stale,
 * we only keep the current and previous entries around.
 *
 * Inspired by the code in Samba3 for 'use kerberos keytab'.
 */
krb5_error_code smb_krb5_remove_obsolete_keytab_entries(TALLOC_CTX *mem_ctx,
							krb5_context context,
							krb5_keytab keytab,
							uint32_t num_principals,
							krb5_principal *principals,
							krb5_kvno kvno,
							bool *found_previous,
							const char **error_string)
{
	TALLOC_CTX *tmp_ctx;
	krb5_error_code code;
	krb5_kt_cursor cursor;

	tmp_ctx = talloc_new(mem_ctx);
	if (tmp_ctx == NULL) {
		*error_string = "Cannot allocate tmp_ctx";
		return ENOMEM;
	}

	*found_previous = true;

	code = krb5_kt_start_seq_get(context, keytab, &cursor);
	switch (code) {
	case 0:
		break;
#ifdef HEIM_ERR_OPNOTSUPP
	case HEIM_ERR_OPNOTSUPP:
#endif
	case ENOENT:
	case KRB5_KT_END:
		/* no point enumerating if there isn't anything here */
		code = 0;
		goto done;
	default:
		*error_string = talloc_asprintf(mem_ctx,
						"failed to open keytab for read of old entries: %s\n",
						smb_get_krb5_error_message(context, code, mem_ctx));
		goto done;
	}

	do {
		krb5_kvno old_kvno = kvno - 1;
		krb5_keytab_entry entry;
		bool matched = false;
		uint32_t i;

		code = krb5_kt_next_entry(context, keytab, &entry, &cursor);
		if (code) {
			break;
		}

		for (i = 0; i < num_principals; i++) {
			krb5_boolean ok;

			ok = smb_krb5_kt_compare(context,
						&entry,
						principals[i],
						0,
						0);
			if (ok) {
				matched = true;
				break;
			}
		}

		if (!matched) {
			/*
			 * Free the entry, it wasn't the one we were looking
			 * for anyway
			 */
			krb5_kt_free_entry(context, &entry);
			/* Make sure we do not double free */
			ZERO_STRUCT(entry);
			continue;
		}

		/*
		 * Delete it, if it is not kvno - 1.
		 *
		 * Some keytab files store the kvno only in 8bits. Limit the
		 * compare to 8bits, so that we don't miss old keys and delete
		 * them.
		 */
		if ((entry.vno & 0xff) != (old_kvno & 0xff)) {
			krb5_error_code rc;

			/* Release the enumeration.  We are going to
			 * have to start this from the top again,
			 * because deletes during enumeration may not
			 * always be consistent.
			 *
			 * Also, the enumeration locks a FILE: keytab
			 */
			krb5_kt_end_seq_get(context, keytab, &cursor);

			code = krb5_kt_remove_entry(context, keytab, &entry);
			krb5_kt_free_entry(context, &entry);

			/* Make sure we do not double free */
			ZERO_STRUCT(entry);

			/* Deleted: Restart from the top */
			rc = krb5_kt_start_seq_get(context, keytab, &cursor);
			if (rc != 0) {
				krb5_kt_free_entry(context, &entry);

				/* Make sure we do not double free */
				ZERO_STRUCT(entry);

				DEBUG(1, ("failed to restart enumeration of keytab: %s\n",
					  smb_get_krb5_error_message(context,
								     code,
								     tmp_ctx)));

				talloc_free(tmp_ctx);
				return rc;
			}

			if (code != 0) {
				break;
			}

		} else {
			*found_previous = true;
		}

		/* Free the entry, we don't need it any more */
		krb5_kt_free_entry(context, &entry);
		/* Make sure we do not double free */
		ZERO_STRUCT(entry);
	} while (code != 0);

	krb5_kt_end_seq_get(context, keytab, &cursor);

	switch (code) {
	case 0:
		break;
	case ENOENT:
	case KRB5_KT_END:
		code = 0;
		break;
	default:
		*error_string = talloc_asprintf(mem_ctx,
						"failed in deleting old entries for principal: %s\n",
						smb_get_krb5_error_message(context,
									   code,
									   mem_ctx));
	}

	code = 0;
done:
	talloc_free(tmp_ctx);
	return code;
}
Example #2
0
static krb5_error_code remove_old_entries(TALLOC_CTX *parent_ctx,
        int kvno,
        krb5_principal *principals,
        bool delete_all_kvno,
        krb5_context context,
        krb5_keytab keytab,
        bool *found_previous,
        const char **error_string)
{
    krb5_error_code ret, ret2;
    krb5_kt_cursor cursor;
    TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);

    if (!mem_ctx) {
        return ENOMEM;
    }

    *found_previous = false;

    /* for each entry in the keytab */
    ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    switch (ret) {
    case 0:
        break;
#ifdef HEIM_ERR_OPNOTSUPP
    case HEIM_ERR_OPNOTSUPP:
#endif
    case ENOENT:
    case KRB5_KT_END:
        /* no point enumerating if there isn't anything here */
        talloc_free(mem_ctx);
        return 0;
    default:
        *error_string = talloc_asprintf(parent_ctx,
                                        "failed to open keytab for read of old entries: %s\n",
                                        smb_get_krb5_error_message(context, ret, mem_ctx));
        talloc_free(mem_ctx);
        return ret;
    }

    while (!ret) {
        unsigned int i;
        bool matched = false;
        krb5_keytab_entry entry;
        ret = krb5_kt_next_entry(context, keytab, &entry, &cursor);
        if (ret) {
            break;
        }
        for (i = 0; principals[i]; i++) {
            /* if it matches our principal */
            if (smb_krb5_kt_compare(context, &entry,
                                    principals[i], 0, 0)) {
                matched = true;
                break;
            }
        }

        if (!matched) {
            /* Free the entry,
             * it wasn't the one we were looking for anyway */
            krb5_kt_free_entry(context, &entry);
            continue;
        }

        /* delete it, if it is not kvno -1 */
        if (entry.vno != (kvno - 1 )) {
            /* Release the enumeration.  We are going to
             * have to start this from the top again,
             * because deletes during enumeration may not
             * always be consistent.
             *
             * Also, the enumeration locks a FILE: keytab
             */

            krb5_kt_end_seq_get(context, keytab, &cursor);

            ret = krb5_kt_remove_entry(context, keytab, &entry);
            krb5_kt_free_entry(context, &entry);

            /* Deleted: Restart from the top */
            ret2 = krb5_kt_start_seq_get(context, keytab, &cursor);
            if (ret2) {
                krb5_kt_free_entry(context, &entry);
                DEBUG(1, ("failed to restart enumeration of keytab: %s\n",
                          smb_get_krb5_error_message(context,
                                                     ret, mem_ctx)));

                talloc_free(mem_ctx);
                return ret2;
            }

            if (ret) {
                break;
            }

        } else {
            *found_previous = true;
        }

        /* Free the entry, we don't need it any more */
        krb5_kt_free_entry(context, &entry);
    }
    krb5_kt_end_seq_get(context, keytab, &cursor);

    switch (ret) {
    case 0:
        break;
    case ENOENT:
    case KRB5_KT_END:
        ret = 0;
        break;
    default:
        *error_string = talloc_asprintf(parent_ctx,
                                        "failed in deleting old entries for principal: %s\n",
                                        smb_get_krb5_error_message(context, ret, mem_ctx));
    }
    talloc_free(mem_ctx);
    return ret;
}