Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / gssapi_link.c
blob954e34e7e60c53aa5911516a0fbd53d0d9618233
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
21 * Id: gssapi_link.c,v 1.14 2009/10/24 23:47:36 tbox Exp
24 #include <config.h>
26 #ifdef GSSAPI
28 #include <isc/buffer.h>
29 #include <isc/mem.h>
30 #include <isc/string.h>
31 #include <isc/util.h>
33 #include <dst/result.h>
35 #include "dst_internal.h"
36 #include "dst_parse.h"
38 #include <dst/gssapi.h>
40 #define INITIAL_BUFFER_SIZE 1024
41 #define BUFFER_EXTRA 1024
43 #define REGION_TO_GBUFFER(r, gb) \
44 do { \
45 (gb).length = (r).length; \
46 (gb).value = (r).base; \
47 } while (0)
50 struct dst_gssapi_signverifyctx {
51 isc_buffer_t *buffer;
54 /*%
55 * Allocate a temporary "context" for use in gathering data for signing
56 * or verifying.
58 static isc_result_t
59 gssapi_create_signverify_ctx(dst_key_t *key, dst_context_t *dctx) {
60 dst_gssapi_signverifyctx_t *ctx;
61 isc_result_t result;
63 UNUSED(key);
65 ctx = isc_mem_get(dctx->mctx, sizeof(dst_gssapi_signverifyctx_t));
66 if (ctx == NULL)
67 return (ISC_R_NOMEMORY);
68 ctx->buffer = NULL;
69 result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
70 INITIAL_BUFFER_SIZE);
71 if (result != ISC_R_SUCCESS) {
72 isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
73 return (result);
76 dctx->ctxdata.gssctx = ctx;
78 return (ISC_R_SUCCESS);
81 /*%
82 * Destroy the temporary sign/verify context.
84 static void
85 gssapi_destroy_signverify_ctx(dst_context_t *dctx) {
86 dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
88 if (ctx != NULL) {
89 if (ctx->buffer != NULL)
90 isc_buffer_free(&ctx->buffer);
91 isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
92 dctx->ctxdata.gssctx = NULL;
96 /*%
97 * Add data to our running buffer of data we will be signing or verifying.
98 * This code will see if the new data will fit in our existing buffer, and
99 * copy it in if it will. If not, it will attempt to allocate a larger
100 * buffer and copy old+new into it, and free the old buffer.
102 static isc_result_t
103 gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
104 dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
105 isc_buffer_t *newbuffer = NULL;
106 isc_region_t r;
107 unsigned int length;
108 isc_result_t result;
110 result = isc_buffer_copyregion(ctx->buffer, data);
111 if (result == ISC_R_SUCCESS)
112 return (ISC_R_SUCCESS);
114 length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA;
116 result = isc_buffer_allocate(dctx->mctx, &newbuffer, length);
117 if (result != ISC_R_SUCCESS)
118 return (result);
120 isc_buffer_usedregion(ctx->buffer, &r);
121 (void)isc_buffer_copyregion(newbuffer, &r);
122 (void)isc_buffer_copyregion(newbuffer, data);
124 isc_buffer_free(&ctx->buffer);
125 ctx->buffer = newbuffer;
127 return (ISC_R_SUCCESS);
131 * Sign.
133 static isc_result_t
134 gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
135 dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
136 isc_region_t message;
137 gss_buffer_desc gmessage, gsig;
138 OM_uint32 minor, gret;
139 gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
140 char buf[1024];
143 * Convert the data we wish to sign into a structure gssapi can
144 * understand.
146 isc_buffer_usedregion(ctx->buffer, &message);
147 REGION_TO_GBUFFER(message, gmessage);
150 * Generate the signature.
152 gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage,
153 &gsig);
156 * If it did not complete, we log the result and return a generic
157 * failure code.
159 if (gret != GSS_S_COMPLETE) {
160 gss_log(3, "GSS sign error: %s",
161 gss_error_tostring(gret, minor, buf, sizeof(buf)));
162 return (ISC_R_FAILURE);
166 * If it will not fit in our allocated buffer, return that we need
167 * more space.
169 if (gsig.length > isc_buffer_availablelength(sig)) {
170 gss_release_buffer(&minor, &gsig);
171 return (ISC_R_NOSPACE);
175 * Copy the output into our buffer space, and release the gssapi
176 * allocated space.
178 isc_buffer_putmem(sig, gsig.value, gsig.length);
179 if (gsig.length != 0)
180 gss_release_buffer(&minor, &gsig);
182 return (ISC_R_SUCCESS);
186 * Verify.
188 static isc_result_t
189 gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
190 dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
191 isc_region_t message, r;
192 gss_buffer_desc gmessage, gsig;
193 OM_uint32 minor, gret;
194 gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
195 unsigned char *buf;
196 char err[1024];
199 * Convert the data we wish to sign into a structure gssapi can
200 * understand.
202 isc_buffer_usedregion(ctx->buffer, &message);
203 REGION_TO_GBUFFER(message, gmessage);
206 * XXXMLG
207 * It seem that gss_verify_mic() modifies the signature buffer,
208 * at least on Heimdal's implementation. Copy it here to an allocated
209 * buffer.
211 buf = isc_mem_allocate(dst__memory_pool, sig->length);
212 if (buf == NULL)
213 return (ISC_R_FAILURE);
214 memcpy(buf, sig->base, sig->length);
215 r.base = buf;
216 r.length = sig->length;
217 REGION_TO_GBUFFER(r, gsig);
220 * Verify the data.
222 gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);
224 isc_mem_free(dst__memory_pool, buf);
227 * Convert return codes into something useful to us.
229 if (gret != GSS_S_COMPLETE) {
230 gss_log(3, "GSS verify error: %s",
231 gss_error_tostring(gret, minor, err, sizeof(err)));
232 if (gret == GSS_S_DEFECTIVE_TOKEN ||
233 gret == GSS_S_BAD_SIG ||
234 gret == GSS_S_DUPLICATE_TOKEN ||
235 gret == GSS_S_OLD_TOKEN ||
236 gret == GSS_S_UNSEQ_TOKEN ||
237 gret == GSS_S_GAP_TOKEN ||
238 gret == GSS_S_CONTEXT_EXPIRED ||
239 gret == GSS_S_NO_CONTEXT ||
240 gret == GSS_S_FAILURE)
241 return(DST_R_VERIFYFAILURE);
242 else
243 return (ISC_R_FAILURE);
246 return (ISC_R_SUCCESS);
249 static isc_boolean_t
250 gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) {
251 gss_ctx_id_t gsskey1 = key1->keydata.gssctx;
252 gss_ctx_id_t gsskey2 = key2->keydata.gssctx;
254 /* No idea */
255 return (ISC_TF(gsskey1 == gsskey2));
258 static isc_result_t
259 gssapi_generate(dst_key_t *key, int unused, void (*callback)(int)) {
260 UNUSED(key);
261 UNUSED(unused);
262 UNUSED(callback);
264 /* No idea */
265 return (ISC_R_FAILURE);
268 static isc_boolean_t
269 gssapi_isprivate(const dst_key_t *key) {
270 UNUSED(key);
271 return (ISC_TRUE);
274 static void
275 gssapi_destroy(dst_key_t *key) {
276 REQUIRE(key != NULL);
277 dst_gssapi_deletectx(key->mctx, &key->keydata.gssctx);
278 key->keydata.gssctx = NULL;
281 static dst_func_t gssapi_functions = {
282 gssapi_create_signverify_ctx,
283 gssapi_destroy_signverify_ctx,
284 gssapi_adddata,
285 gssapi_sign,
286 gssapi_verify,
287 NULL, /*%< computesecret */
288 gssapi_compare,
289 NULL, /*%< paramcompare */
290 gssapi_generate,
291 gssapi_isprivate,
292 gssapi_destroy,
293 NULL, /*%< todns */
294 NULL, /*%< fromdns */
295 NULL, /*%< tofile */
296 NULL, /*%< parse */
297 NULL, /*%< cleanup */
298 NULL, /*%< fromlabel */
301 isc_result_t
302 dst__gssapi_init(dst_func_t **funcp) {
303 REQUIRE(funcp != NULL);
304 if (*funcp == NULL)
305 *funcp = &gssapi_functions;
306 return (ISC_R_SUCCESS);
309 #else
310 int gssapi_link_unneeded = 1;
311 #endif
313 /*! \file */