4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
29 * A module that implements a dummy security mechanism.
30 * It's mainly used to test GSS-API application. Multiple tokens
31 * exchanged during security context establishment can be
32 * specified through dummy_mech.conf located in /etc.
35 #include <sys/types.h>
36 #include <sys/modctl.h>
37 #include <sys/errno.h>
38 #include <gssapiP_dummy.h>
39 #include <gssapi_err_generic.h>
40 #include <mechglueP.h>
41 #include <gssapi/kgssapi_defs.h>
42 #include <sys/debug.h>
44 #ifdef DUMMY_MECH_DEBUG
46 * Kernel kgssd module debugging aid. The global variable "dummy_mech_log"
47 * is a bit mask which allows various types of debugging messages
50 * dummy_mech_log & 1 will cause actual failures to be printed.
51 * dummy_mech_log & 2 will cause informational messages to be
52 * printed on the client side of kgssd.
53 * dummy_mech_log & 4 will cause informational messages to be
54 * printed on the server side of kgssd.
55 * dummy_mech_log & 8 will cause informational messages to be
56 * printed on both client and server side of kgssd.
59 uint_t dummy_mech_log
= 1;
63 #define MAGIC_TOKEN_NUMBER 12345
64 /* private routines for dummy_mechanism */
65 static gss_buffer_desc
make_dummy_token_msg(void *data
, int datalen
);
67 static int der_length_size(int);
69 static void der_write_length(unsigned char **, int);
70 static int der_read_length(unsigned char **, int *);
71 static int g_token_size(gss_OID mech
, unsigned int body_size
);
72 static void g_make_token_header(gss_OID mech
, int body_size
,
73 unsigned char **buf
, int tok_type
);
74 static int g_verify_token_header(gss_OID mech
, int *body_size
,
75 unsigned char **buf_in
, int tok_type
,
78 /* private global variables */
79 static int dummy_token_nums
;
83 * { iso(1) org(3) internet(6) dod(1) private(4) enterprises(1) sun(42)
84 * products(2) gssapi(26) mechtypes(1) dummy(2) }
87 static struct gss_config dummy_mechanism
=
88 {{10, "\053\006\001\004\001\052\002\032\001\002"},
93 dummy_gss_delete_sec_context
,
95 dummy_gss_import_sec_context
,
101 gss_mech_initialize()
103 dprintf("Entering gss_mech_initialize\n");
105 if (dummy_token_nums
== 0)
106 dummy_token_nums
= 1;
108 dprintf("Leaving gss_mech_initialize\n");
109 return (&dummy_mechanism
);
113 * Clean up after a failed mod_install()
123 * Module linkage information for the kernel.
125 extern struct mod_ops mod_miscops
;
127 static struct modlmisc modlmisc
= {
128 &mod_miscops
, "in-kernel dummy GSS mechanism"
131 static struct modlinkage modlinkage
= {
137 static int dummy_fini_code
= EBUSY
;
143 gss_mechanism mech
, tmp
;
145 mech
= gss_mech_initialize();
147 mutex_enter(&__kgss_mech_lock
);
148 tmp
= __kgss_get_mechanism(&mech
->mech_type
);
151 "dummy GSS mechanism: mechanism already in table.\n");
152 if (tmp
->uses_kmod
== TRUE
) {
153 DUMMY_MECH_LOG0(8, "dummy GSS mechanism: mechanism "
154 "table supports kernel operations!\n");
157 * keep us loaded, but let us be unloadable. This
158 * will give the developer time to trouble shoot
162 __kgss_add_mechanism(mech
);
163 ASSERT(__kgss_get_mechanism(&mech
->mech_type
) == mech
);
165 mutex_exit(&__kgss_mech_lock
);
167 if ((retval
= mod_install(&modlinkage
)) != 0)
168 gss_mech_fini(); /* clean up */
176 int ret
= dummy_fini_code
;
179 ret
= (mod_remove(&modlinkage
));
185 _info(struct modinfo
*modinfop
)
187 return (mod_info(&modlinkage
, modinfop
));
193 dummy_gss_sign(context
, minor_status
, context_handle
,
194 qop_req
, message_buffer
, message_token
,
197 OM_uint32
*minor_status
;
198 gss_ctx_id_t context_handle
;
200 gss_buffer_t message_buffer
;
201 gss_buffer_t message_token
;
202 OM_uint32 gssd_ctx_verifier
;
204 dummy_gss_ctx_id_rec
*ctx
;
205 char token_string
[] = "dummy_gss_sign";
207 dprintf("Entering gss_sign\n");
209 if (context_handle
== GSS_C_NO_CONTEXT
)
210 return (GSS_S_NO_CONTEXT
);
211 ctx
= (dummy_gss_ctx_id_rec
*) context_handle
;
212 ASSERT(ctx
->established
== 1);
213 ASSERT(ctx
->token_number
== MAGIC_TOKEN_NUMBER
);
215 *message_token
= make_dummy_token_msg(
216 token_string
, strlen(token_string
));
218 dprintf("Leaving gss_sign\n");
219 return (GSS_S_COMPLETE
);
224 dummy_gss_verify(context
, minor_status
, context_handle
,
225 message_buffer
, token_buffer
, qop_state
,
228 OM_uint32
*minor_status
;
229 gss_ctx_id_t context_handle
;
230 gss_buffer_t message_buffer
;
231 gss_buffer_t token_buffer
;
233 OM_uint32 gssd_ctx_verifier
;
238 dummy_gss_ctx_id_rec
*ctx
;
240 dprintf("Entering gss_verify\n");
242 if (context_handle
== GSS_C_NO_CONTEXT
)
243 return (GSS_S_NO_CONTEXT
);
245 ctx
= (dummy_gss_ctx_id_rec
*) context_handle
;
246 ASSERT(ctx
->established
== 1);
247 ASSERT(ctx
->token_number
== MAGIC_TOKEN_NUMBER
);
248 /* Check for defective input token. */
250 ptr
= (unsigned char *) token_buffer
->value
;
251 if (err
= g_verify_token_header((gss_OID
)gss_mech_dummy
, &bodysize
,
253 token_buffer
->length
)) {
255 return (GSS_S_DEFECTIVE_TOKEN
);
258 *qop_state
= GSS_C_QOP_DEFAULT
;
260 dprintf("Leaving gss_verify\n");
261 return (GSS_S_COMPLETE
);
266 dummy_gss_seal(context
, minor_status
, context_handle
, conf_req_flag
,
267 qop_req
, input_message_buffer
, conf_state
,
268 output_message_buffer
, gssd_ctx_verifier
)
270 OM_uint32
*minor_status
;
271 gss_ctx_id_t context_handle
;
274 gss_buffer_t input_message_buffer
;
276 gss_buffer_t output_message_buffer
;
277 OM_uint32 gssd_ctx_verifier
;
279 gss_buffer_desc output
;
280 dummy_gss_ctx_id_rec
*ctx
;
281 dprintf("Entering gss_seal\n");
283 if (context_handle
== GSS_C_NO_CONTEXT
)
284 return (GSS_S_NO_CONTEXT
);
285 ctx
= (dummy_gss_ctx_id_rec
*) context_handle
;
286 ASSERT(ctx
->established
== 1);
287 ASSERT(ctx
->token_number
== MAGIC_TOKEN_NUMBER
);
288 /* Copy the input message to output message */
289 output
= make_dummy_token_msg(
290 input_message_buffer
->value
, input_message_buffer
->length
);
295 *output_message_buffer
= output
;
297 dprintf("Leaving gss_seal\n");
298 return (GSS_S_COMPLETE
);
303 dummy_gss_unseal(context
, minor_status
, context_handle
,
304 input_message_buffer
, output_message_buffer
,
305 conf_state
, qop_state
, gssd_ctx_verifier
)
307 OM_uint32
*minor_status
;
308 gss_ctx_id_t context_handle
;
309 gss_buffer_t input_message_buffer
;
310 gss_buffer_t output_message_buffer
;
313 OM_uint32 gssd_ctx_verifier
;
315 gss_buffer_desc output
;
316 dummy_gss_ctx_id_rec
*ctx
;
321 dprintf("Entering gss_unseal\n");
323 if (context_handle
== GSS_C_NO_CONTEXT
)
324 return (GSS_S_NO_CONTEXT
);
326 ctx
= (dummy_gss_ctx_id_rec
*) context_handle
;
327 ASSERT(ctx
->established
== 1);
328 ASSERT(ctx
->token_number
== MAGIC_TOKEN_NUMBER
);
330 ptr
= (unsigned char *) input_message_buffer
->value
;
331 if (err
= g_verify_token_header((gss_OID
)gss_mech_dummy
, &bodysize
,
333 input_message_buffer
->length
)) {
335 return (GSS_S_DEFECTIVE_TOKEN
);
337 output
.length
= bodysize
;
338 output
.value
= (void *)MALLOC(output
.length
);
339 (void) memcpy(output
.value
, ptr
, output
.length
);
341 *output_message_buffer
= output
;
342 *qop_state
= GSS_C_QOP_DEFAULT
;
347 dprintf("Leaving gss_unseal\n");
348 return (GSS_S_COMPLETE
);
353 dummy_gss_import_sec_context(ct
, minor_status
, interprocess_token
,
356 OM_uint32
*minor_status
;
357 gss_buffer_t interprocess_token
;
358 gss_ctx_id_t
*context_handle
;
364 /* Assume that we got ctx from the interprocess token. */
365 dummy_gss_ctx_id_t ctx
;
367 dprintf("Entering import_sec_context\n");
368 ptr
= (unsigned char *) interprocess_token
->value
;
369 if (err
= g_verify_token_header((gss_OID
)gss_mech_dummy
, &bodysize
,
371 interprocess_token
->length
)) {
373 return (GSS_S_DEFECTIVE_TOKEN
);
375 ctx
= (dummy_gss_ctx_id_t
)MALLOC(sizeof (dummy_gss_ctx_id_rec
));
376 ctx
->token_number
= MAGIC_TOKEN_NUMBER
;
377 ctx
->established
= 1;
379 *context_handle
= (gss_ctx_id_t
)ctx
;
381 dprintf("Leaving import_sec_context\n");
382 return (GSS_S_COMPLETE
);
387 dummy_gss_delete_sec_context(ct
, minor_status
,
388 context_handle
, output_token
,
391 OM_uint32
*minor_status
;
392 gss_ctx_id_t
*context_handle
;
393 gss_buffer_t output_token
;
394 OM_uint32 gssd_ctx_verifier
;
396 dummy_gss_ctx_id_t ctx
;
398 dprintf("Entering delete_sec_context\n");
400 /* Make the length to 0, so the output token is not sent to peer */
402 output_token
->length
= 0;
403 output_token
->value
= NULL
;
406 if (*context_handle
== GSS_C_NO_CONTEXT
) {
408 return (GSS_S_COMPLETE
);
411 ctx
= (dummy_gss_ctx_id_rec
*) *context_handle
;
412 ASSERT(ctx
->established
== 1);
413 ASSERT(ctx
->token_number
== MAGIC_TOKEN_NUMBER
);
415 FREE(ctx
, sizeof (dummy_gss_ctx_id_rec
));
416 *context_handle
= GSS_C_NO_CONTEXT
;
418 dprintf("Leaving delete_sec_context\n");
419 return (GSS_S_COMPLETE
);
423 der_length_size(int length
)
427 else if (length
< (1<<8))
429 else if (length
< (1<<16))
431 else if (length
< (1<<24))
438 der_write_length(unsigned char ** buf
, int length
)
440 if (length
< (1<<7)) {
441 *(*buf
)++ = (unsigned char) length
;
443 *(*buf
)++ = (unsigned char) (der_length_size(length
)+127);
444 if (length
>= (1<<24))
445 *(*buf
)++ = (unsigned char) (length
>>24);
446 if (length
>= (1<<16))
447 *(*buf
)++ = (unsigned char) ((length
>>16)&0xff);
448 if (length
>= (1<<8))
449 *(*buf
)++ = (unsigned char) ((length
>>8)&0xff);
450 *(*buf
)++ = (unsigned char) (length
&0xff);
455 der_read_length(buf
, bufsize
)
467 if ((sf
&= 0x7f) > ((*bufsize
)-1))
469 if (sf
> DUMMY_SIZE_OF_INT
)
473 ret
= (ret
<<8) + (*(*buf
)++);
484 g_token_size(mech
, body_size
)
486 unsigned int body_size
;
488 /* set body_size to sequence contents size */
489 body_size
+= 4 + (int)mech
->length
; /* NEED overflow check */
490 return (1 + der_length_size(body_size
) + body_size
);
494 g_make_token_header(mech
, body_size
, buf
, tok_type
)
501 der_write_length(buf
, 4 + mech
->length
+ body_size
);
503 *(*buf
)++ = (unsigned char) mech
->length
;
504 TWRITE_STR(*buf
, mech
->elements
, ((int)mech
->length
));
505 *(*buf
)++ = (unsigned char) ((tok_type
>>8)&0xff);
506 *(*buf
)++ = (unsigned char) (tok_type
&0xff);
510 g_verify_token_header(mech
, body_size
, buf_in
, tok_type
, toksize
)
513 unsigned char **buf_in
;
517 unsigned char *buf
= *buf_in
;
522 if ((toksize
-= 1) < 0)
523 return (G_BAD_TOK_HEADER
);
525 return (G_BAD_TOK_HEADER
);
527 if ((seqsize
= der_read_length(&buf
, &toksize
)) < 0)
528 return (G_BAD_TOK_HEADER
);
530 if (seqsize
!= toksize
)
531 return (G_BAD_TOK_HEADER
);
533 if ((toksize
-= 1) < 0)
534 return (G_BAD_TOK_HEADER
);
536 return (G_BAD_TOK_HEADER
);
538 if ((toksize
-= 1) < 0)
539 return (G_BAD_TOK_HEADER
);
540 toid
.length
= *buf
++;
542 if ((toksize
-= toid
.length
) < 0)
543 return (G_BAD_TOK_HEADER
);
547 if (! g_OID_equal(&toid
, mech
))
551 * G_WRONG_MECH is not returned immediately because it's more important
552 * to return G_BAD_TOK_HEADER if the token header is in fact bad
555 if ((toksize
-= 2) < 0)
556 return (G_BAD_TOK_HEADER
);
558 if ((*buf
++ != ((tok_type
>>8)&0xff)) ||
559 (*buf
++ != (tok_type
&0xff)))
560 return (G_BAD_TOK_HEADER
);
564 *body_size
= toksize
;
570 static gss_buffer_desc
571 make_dummy_token_msg(void *data
, int dataLen
)
573 gss_buffer_desc buffer
;
584 tlen
= g_token_size((gss_OID
)gss_mech_dummy
, dataLen
);
585 t
= (unsigned char *) MALLOC(tlen
);
588 g_make_token_header((gss_OID
)gss_mech_dummy
, dataLen
, &ptr
, 0);
589 (void) memcpy(ptr
, data
, dataLen
);
591 buffer
.length
= tlen
;
592 buffer
.value
= (void *) t
;