|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
Packit |
e9919e |
*
|
|
Packit |
e9919e |
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
Packit |
e9919e |
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
Packit |
e9919e |
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
Packit |
e9919e |
*
|
|
Packit |
e9919e |
* See the COPYRIGHT file distributed with this work for additional
|
|
Packit |
e9919e |
* information regarding copyright ownership.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#include <config.h>
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#ifdef GSSAPI
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#include <stdbool.h>
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#include <isc/base64.h>
|
|
Packit |
e9919e |
#include <isc/buffer.h>
|
|
Packit |
e9919e |
#include <isc/mem.h>
|
|
Packit |
e9919e |
#include <isc/print.h>
|
|
Packit |
e9919e |
#include <isc/string.h>
|
|
Packit |
e9919e |
#include <isc/util.h>
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#include <dst/result.h>
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#include "dst_internal.h"
|
|
Packit |
e9919e |
#include "dst_parse.h"
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#include <dst/gssapi.h>
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#define INITIAL_BUFFER_SIZE 1024
|
|
Packit |
e9919e |
#define BUFFER_EXTRA 1024
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#define REGION_TO_GBUFFER(r, gb) \
|
|
Packit |
e9919e |
do { \
|
|
Packit |
e9919e |
(gb).length = (r).length; \
|
|
Packit |
e9919e |
(gb).value = (r).base; \
|
|
Packit |
e9919e |
} while (0)
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#define GBUFFER_TO_REGION(gb, r) \
|
|
Packit |
e9919e |
do { \
|
|
Packit |
e9919e |
(r).length = (unsigned int)(gb).length; \
|
|
Packit |
e9919e |
(r).base = (gb).value; \
|
|
Packit |
e9919e |
} while (0)
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
struct dst_gssapi_signverifyctx {
|
|
Packit |
e9919e |
isc_buffer_t *buffer;
|
|
Packit |
e9919e |
};
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*%
|
|
Packit |
e9919e |
* Allocate a temporary "context" for use in gathering data for signing
|
|
Packit |
e9919e |
* or verifying.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
static isc_result_t
|
|
Packit |
e9919e |
gssapi_create_signverify_ctx(dst_key_t *key, dst_context_t *dctx) {
|
|
Packit |
e9919e |
dst_gssapi_signverifyctx_t *ctx;
|
|
Packit |
e9919e |
isc_result_t result;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
UNUSED(key);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
ctx = isc_mem_get(dctx->mctx, sizeof(dst_gssapi_signverifyctx_t));
|
|
Packit |
e9919e |
if (ctx == NULL)
|
|
Packit |
e9919e |
return (ISC_R_NOMEMORY);
|
|
Packit |
e9919e |
ctx->buffer = NULL;
|
|
Packit |
e9919e |
result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
|
|
Packit |
e9919e |
INITIAL_BUFFER_SIZE);
|
|
Packit |
e9919e |
if (result != ISC_R_SUCCESS) {
|
|
Packit |
e9919e |
isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
|
|
Packit |
e9919e |
return (result);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
dctx->ctxdata.gssctx = ctx;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
return (ISC_R_SUCCESS);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*%
|
|
Packit |
e9919e |
* Destroy the temporary sign/verify context.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
static void
|
|
Packit |
e9919e |
gssapi_destroy_signverify_ctx(dst_context_t *dctx) {
|
|
Packit |
e9919e |
dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
if (ctx != NULL) {
|
|
Packit |
e9919e |
if (ctx->buffer != NULL)
|
|
Packit |
e9919e |
isc_buffer_free(&ctx->buffer);
|
|
Packit |
e9919e |
isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
|
|
Packit |
e9919e |
dctx->ctxdata.gssctx = NULL;
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*%
|
|
Packit |
e9919e |
* Add data to our running buffer of data we will be signing or verifying.
|
|
Packit |
e9919e |
* This code will see if the new data will fit in our existing buffer, and
|
|
Packit |
e9919e |
* copy it in if it will. If not, it will attempt to allocate a larger
|
|
Packit |
e9919e |
* buffer and copy old+new into it, and free the old buffer.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
static isc_result_t
|
|
Packit |
e9919e |
gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
|
|
Packit |
e9919e |
dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
|
|
Packit |
e9919e |
isc_buffer_t *newbuffer = NULL;
|
|
Packit |
e9919e |
isc_region_t r;
|
|
Packit |
e9919e |
unsigned int length;
|
|
Packit |
e9919e |
isc_result_t result;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
result = isc_buffer_copyregion(ctx->buffer, data);
|
|
Packit |
e9919e |
if (result == ISC_R_SUCCESS)
|
|
Packit |
e9919e |
return (ISC_R_SUCCESS);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
result = isc_buffer_allocate(dctx->mctx, &newbuffer, length);
|
|
Packit |
e9919e |
if (result != ISC_R_SUCCESS)
|
|
Packit |
e9919e |
return (result);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
isc_buffer_usedregion(ctx->buffer, &r);
|
|
Packit |
e9919e |
(void)isc_buffer_copyregion(newbuffer, &r);
|
|
Packit |
e9919e |
(void)isc_buffer_copyregion(newbuffer, data);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
isc_buffer_free(&ctx->buffer);
|
|
Packit |
e9919e |
ctx->buffer = newbuffer;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
return (ISC_R_SUCCESS);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*%
|
|
Packit |
e9919e |
* Sign.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
static isc_result_t
|
|
Packit |
e9919e |
gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
|
|
Packit |
e9919e |
dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
|
|
Packit |
e9919e |
isc_region_t message;
|
|
Packit |
e9919e |
gss_buffer_desc gmessage, gsig;
|
|
Packit |
e9919e |
OM_uint32 minor, gret;
|
|
Packit |
e9919e |
gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
|
|
Packit |
e9919e |
char buf[1024];
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* Convert the data we wish to sign into a structure gssapi can
|
|
Packit |
e9919e |
* understand.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
isc_buffer_usedregion(ctx->buffer, &message);
|
|
Packit |
e9919e |
REGION_TO_GBUFFER(message, gmessage);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* Generate the signature.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage,
|
|
Packit |
e9919e |
&gsig;;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* If it did not complete, we log the result and return a generic
|
|
Packit |
e9919e |
* failure code.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
if (gret != GSS_S_COMPLETE) {
|
|
Packit |
e9919e |
gss_log(3, "GSS sign error: %s",
|
|
Packit |
e9919e |
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
|
Packit |
e9919e |
return (ISC_R_FAILURE);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* If it will not fit in our allocated buffer, return that we need
|
|
Packit |
e9919e |
* more space.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
if (gsig.length > isc_buffer_availablelength(sig)) {
|
|
Packit |
e9919e |
gss_release_buffer(&minor, &gsig;;
|
|
Packit |
e9919e |
return (ISC_R_NOSPACE);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* Copy the output into our buffer space, and release the gssapi
|
|
Packit |
e9919e |
* allocated space.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
isc_buffer_putmem(sig, gsig.value, (unsigned int)gsig.length);
|
|
Packit |
e9919e |
if (gsig.length != 0U)
|
|
Packit |
e9919e |
gss_release_buffer(&minor, &gsig;;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
return (ISC_R_SUCCESS);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*%
|
|
Packit |
e9919e |
* Verify.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
static isc_result_t
|
|
Packit |
e9919e |
gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
|
|
Packit |
e9919e |
dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
|
|
Packit |
e9919e |
isc_region_t message, r;
|
|
Packit |
e9919e |
gss_buffer_desc gmessage, gsig;
|
|
Packit |
e9919e |
OM_uint32 minor, gret;
|
|
Packit |
e9919e |
gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
|
|
Packit |
e9919e |
unsigned char *buf;
|
|
Packit |
e9919e |
char err[1024];
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* Convert the data we wish to sign into a structure gssapi can
|
|
Packit |
e9919e |
* understand.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
isc_buffer_usedregion(ctx->buffer, &message);
|
|
Packit |
e9919e |
REGION_TO_GBUFFER(message, gmessage);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* XXXMLG
|
|
Packit |
e9919e |
* It seem that gss_verify_mic() modifies the signature buffer,
|
|
Packit |
e9919e |
* at least on Heimdal's implementation. Copy it here to an allocated
|
|
Packit |
e9919e |
* buffer.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
buf = isc_mem_allocate(dst__memory_pool, sig->length);
|
|
Packit |
e9919e |
if (buf == NULL)
|
|
Packit |
e9919e |
return (ISC_R_FAILURE);
|
|
Packit |
e9919e |
memmove(buf, sig->base, sig->length);
|
|
Packit |
e9919e |
r.base = buf;
|
|
Packit |
e9919e |
r.length = sig->length;
|
|
Packit |
e9919e |
REGION_TO_GBUFFER(r, gsig);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* Verify the data.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
isc_mem_free(dst__memory_pool, buf);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*
|
|
Packit |
e9919e |
* Convert return codes into something useful to us.
|
|
Packit |
e9919e |
*/
|
|
Packit |
e9919e |
if (gret != GSS_S_COMPLETE) {
|
|
Packit |
e9919e |
gss_log(3, "GSS verify error: %s",
|
|
Packit |
e9919e |
gss_error_tostring(gret, minor, err, sizeof(err)));
|
|
Packit |
e9919e |
if (gret == GSS_S_DEFECTIVE_TOKEN ||
|
|
Packit |
e9919e |
gret == GSS_S_BAD_SIG ||
|
|
Packit |
e9919e |
gret == GSS_S_DUPLICATE_TOKEN ||
|
|
Packit |
e9919e |
gret == GSS_S_OLD_TOKEN ||
|
|
Packit |
e9919e |
gret == GSS_S_UNSEQ_TOKEN ||
|
|
Packit |
e9919e |
gret == GSS_S_GAP_TOKEN ||
|
|
Packit |
e9919e |
gret == GSS_S_CONTEXT_EXPIRED ||
|
|
Packit |
e9919e |
gret == GSS_S_NO_CONTEXT ||
|
|
Packit |
e9919e |
gret == GSS_S_FAILURE)
|
|
Packit |
e9919e |
return(DST_R_VERIFYFAILURE);
|
|
Packit |
e9919e |
else
|
|
Packit |
e9919e |
return (ISC_R_FAILURE);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
return (ISC_R_SUCCESS);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
static bool
|
|
Packit |
e9919e |
gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) {
|
|
Packit |
e9919e |
gss_ctx_id_t gsskey1 = key1->keydata.gssctx;
|
|
Packit |
e9919e |
gss_ctx_id_t gsskey2 = key2->keydata.gssctx;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/* No idea */
|
|
Packit |
e9919e |
return (gsskey1 == gsskey2);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
static isc_result_t
|
|
Packit |
e9919e |
gssapi_generate(dst_key_t *key, int unused, void (*callback)(int)) {
|
|
Packit |
e9919e |
UNUSED(key);
|
|
Packit |
e9919e |
UNUSED(unused);
|
|
Packit |
e9919e |
UNUSED(callback);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/* No idea */
|
|
Packit |
e9919e |
return (ISC_R_FAILURE);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
static bool
|
|
Packit |
e9919e |
gssapi_isprivate(const dst_key_t *key) {
|
|
Packit |
e9919e |
UNUSED(key);
|
|
Packit |
e9919e |
return (true);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
static void
|
|
Packit |
e9919e |
gssapi_destroy(dst_key_t *key) {
|
|
Packit |
e9919e |
REQUIRE(key != NULL);
|
|
Packit |
e9919e |
dst_gssapi_deletectx(key->mctx, &key->keydata.gssctx);
|
|
Packit |
e9919e |
key->keydata.gssctx = NULL;
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
static isc_result_t
|
|
Packit |
e9919e |
gssapi_restore(dst_key_t *key, const char *keystr) {
|
|
Packit |
e9919e |
OM_uint32 major, minor;
|
|
Packit |
e9919e |
unsigned int len;
|
|
Packit |
e9919e |
isc_buffer_t *b = NULL;
|
|
Packit |
e9919e |
isc_region_t r;
|
|
Packit |
e9919e |
gss_buffer_desc gssbuffer;
|
|
Packit |
e9919e |
isc_result_t result;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
len = strlen(keystr);
|
|
Packit |
e9919e |
if ((len % 4) != 0U)
|
|
Packit |
e9919e |
return (ISC_R_BADBASE64);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
len = (len / 4) * 3;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
result = isc_buffer_allocate(key->mctx, &b, len);
|
|
Packit |
e9919e |
if (result != ISC_R_SUCCESS)
|
|
Packit |
e9919e |
return (result);
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
result = isc_base64_decodestring(keystr, b);
|
|
Packit |
e9919e |
if (result != ISC_R_SUCCESS) {
|
|
Packit |
e9919e |
isc_buffer_free(&b);
|
|
Packit |
e9919e |
return (result);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
isc_buffer_remainingregion(b, &r);
|
|
Packit |
e9919e |
REGION_TO_GBUFFER(r, gssbuffer);
|
|
Packit |
e9919e |
major = gss_import_sec_context(&minor, &gssbuffer,
|
|
Packit |
e9919e |
&key->keydata.gssctx);
|
|
Packit |
e9919e |
if (major != GSS_S_COMPLETE) {
|
|
Packit |
e9919e |
isc_buffer_free(&b);
|
|
Packit |
e9919e |
return (ISC_R_FAILURE);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
isc_buffer_free(&b);
|
|
Packit |
e9919e |
return (ISC_R_SUCCESS);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
static isc_result_t
|
|
Packit |
e9919e |
gssapi_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
|
|
Packit |
e9919e |
OM_uint32 major, minor;
|
|
Packit |
e9919e |
gss_buffer_desc gssbuffer;
|
|
Packit |
e9919e |
size_t len;
|
|
Packit |
e9919e |
char *buf;
|
|
Packit |
e9919e |
isc_buffer_t b;
|
|
Packit |
e9919e |
isc_region_t r;
|
|
Packit |
e9919e |
isc_result_t result;
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
major = gss_export_sec_context(&minor, &key->keydata.gssctx,
|
|
Packit |
e9919e |
&gssbuffer);
|
|
Packit |
e9919e |
if (major != GSS_S_COMPLETE) {
|
|
Packit |
e9919e |
fprintf(stderr, "gss_export_sec_context -> %u, %u\n",
|
|
Packit |
e9919e |
major, minor);
|
|
Packit |
e9919e |
return (ISC_R_FAILURE);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
if (gssbuffer.length == 0U)
|
|
Packit |
e9919e |
return (ISC_R_FAILURE);
|
|
Packit |
e9919e |
len = ((gssbuffer.length + 2)/3) * 4;
|
|
Packit |
e9919e |
buf = isc_mem_get(mctx, len);
|
|
Packit |
e9919e |
if (buf == NULL) {
|
|
Packit |
e9919e |
gss_release_buffer(&minor, &gssbuffer);
|
|
Packit |
e9919e |
return (ISC_R_NOMEMORY);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
isc_buffer_init(&b, buf, (unsigned int)len);
|
|
Packit |
e9919e |
GBUFFER_TO_REGION(gssbuffer, r);
|
|
Packit |
e9919e |
result = isc_base64_totext(&r, 0, "", &b);
|
|
Packit |
e9919e |
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
|
Packit |
e9919e |
gss_release_buffer(&minor, &gssbuffer);
|
|
Packit |
e9919e |
*buffer = buf;
|
|
Packit |
e9919e |
*length = (int)len;
|
|
Packit |
e9919e |
return (ISC_R_SUCCESS);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
static dst_func_t gssapi_functions = {
|
|
Packit |
e9919e |
gssapi_create_signverify_ctx,
|
|
Packit |
e9919e |
NULL, /*%< createctx2 */
|
|
Packit |
e9919e |
gssapi_destroy_signverify_ctx,
|
|
Packit |
e9919e |
gssapi_adddata,
|
|
Packit |
e9919e |
gssapi_sign,
|
|
Packit |
e9919e |
gssapi_verify,
|
|
Packit |
e9919e |
NULL, /*%< verify2 */
|
|
Packit |
e9919e |
NULL, /*%< computesecret */
|
|
Packit |
e9919e |
gssapi_compare,
|
|
Packit |
e9919e |
NULL, /*%< paramcompare */
|
|
Packit |
e9919e |
gssapi_generate,
|
|
Packit |
e9919e |
gssapi_isprivate,
|
|
Packit |
e9919e |
gssapi_destroy,
|
|
Packit |
e9919e |
NULL, /*%< todns */
|
|
Packit |
e9919e |
NULL, /*%< fromdns */
|
|
Packit |
e9919e |
NULL, /*%< tofile */
|
|
Packit |
e9919e |
NULL, /*%< parse */
|
|
Packit |
e9919e |
NULL, /*%< cleanup */
|
|
Packit |
e9919e |
NULL, /*%< fromlabel */
|
|
Packit |
e9919e |
gssapi_dump,
|
|
Packit |
e9919e |
gssapi_restore,
|
|
Packit |
e9919e |
};
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
isc_result_t
|
|
Packit |
e9919e |
dst__gssapi_init(dst_func_t **funcp) {
|
|
Packit |
e9919e |
REQUIRE(funcp != NULL);
|
|
Packit |
e9919e |
if (*funcp == NULL)
|
|
Packit |
e9919e |
*funcp = &gssapi_functions;
|
|
Packit |
e9919e |
return (ISC_R_SUCCESS);
|
|
Packit |
e9919e |
}
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
#else
|
|
Packit |
e9919e |
int gssapi_link_unneeded = 1;
|
|
Packit |
e9919e |
#endif
|
|
Packit |
e9919e |
|
|
Packit |
e9919e |
/*! \file */
|