/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* A module that implements a dummy security mechanism.
* It's mainly used to test GSS-API application. Multiple tokens
* exchanged during security context establishment can be
* specified through dummy_mech.conf located in /etc.
*
*/
#ifndef lint
#define dummy_gss_accept_sec_context \
dummy_867227349
#define dummy_gss_acquire_cred \
dummy_352458907
#define dummy_gss_add_cred \
dummy_911432290
#define dummy_gss_compare_name \
dummy_396663848
#define dummy_gss_context_time \
dummy_955669998
#define dummy_gss_delete_sec_context \
dummy_440868788
#define dummy_gss_display_name \
dummy_999874939
#define dummy_gss_display_status \
dummy_485073729
#define dummy_gss_export_sec_context \
dummy_1044079879
#define dummy_gss_import_name \
dummy_529311438
#define dummy_gss_import_sec_context \
dummy_14542996
#define dummy_gss_indicate_mechs \
dummy_573516378
#define dummy_gss_init_sec_context \
dummy_58780705
#define dummy_gss_inquire_context \
dummy_617721319
#define dummy_gss_inquire_cred \
dummy_102985645
#define dummy_gss_inquire_cred_by_mech \
dummy_661926260
#define dummy_gss_inquire_names_for_mech \
dummy_147190586
#define dummy_gss_internal_release_oid \
dummy_706163968
#define dummy_gss_process_context_token \
dummy_191395526
#define dummy_gss_release_cred \
dummy_750368909
#define dummy_gss_release_name \
dummy_235600467
#define dummy_gss_seal \
dummy_794573849
#define dummy_gss_sign \
dummy_279838176
#define dummy_gss_unseal \
dummy_838778790
#define dummy_gss_verify \
dummy_324010348
#define dummy_gss_wrap_size_limit \
dummy_882983731
#define dummy_pname_to_uid \
dummy_345475423
#endif
#include <stdio.h>
#include <stdlib.h>
#include <gssapiP_dummy.h>
#include <mechglueP.h>
#include <gssapi_err_generic.h>
#define dummy_context_name_len 19
/* private routines for dummy_mechanism */
static dummy_token_t make_dummy_token(char *name);
static void free_dummy_token(dummy_token_t *token);
static gss_buffer_desc make_dummy_token_buffer(char *name);
static gss_buffer_desc make_dummy_token_msg(void *data, int datalen);
static int der_length_size(int length);
static void der_write_length(unsigned char ** buf, int length);
static int der_read_length(unsigned char **buf, int *bufsize);
static int g_token_size(gss_OID mech, unsigned int body_size);
static void g_make_token_header(gss_OID mech, int body_size,
unsigned char **buf, int tok_type);
static int g_verify_token_header(gss_OID mech, int *body_size,
unsigned char **buf_in, int tok_type,
int toksize);
/* private global variables */
static char dummy_srcname[] = "dummy source";
static OM_uint32 dummy_flags;
static int token_nums;
/*
* The Mech OID:
* { iso(1) org(3) internet(6) dod(1) private(4) enterprises(1) sun(42)
* products(2) gssapi(26) mechtypes(1) dummy(2) }
*/
static struct gss_config dummy_mechanism =
{{10, "\053\006\001\004\001\052\002\032\001\002"},
NULL,
dummy_gss_acquire_cred,
dummy_gss_release_cred,
dummy_gss_init_sec_context,
dummy_gss_accept_sec_context,
dummy_gss_unseal,
dummy_gss_process_context_token,
dummy_gss_delete_sec_context,
dummy_gss_context_time,
dummy_gss_display_status,
dummy_gss_indicate_mechs,
dummy_gss_compare_name,
dummy_gss_display_name,
dummy_gss_import_name,
dummy_gss_release_name,
dummy_gss_inquire_cred,
dummy_gss_add_cred,
dummy_gss_seal,
dummy_gss_export_sec_context,
dummy_gss_import_sec_context,
dummy_gss_inquire_cred_by_mech,
dummy_gss_inquire_names_for_mech,
dummy_gss_inquire_context,
dummy_gss_internal_release_oid,
dummy_gss_wrap_size_limit,
dummy_pname_to_uid,
NULL, /* __gss_userok */
NULL, /* _export name */
dummy_gss_sign,
dummy_gss_verify,
NULL, /* _store_cred */
};
gss_mechanism
gss_mech_initialize(oid)
const gss_OID oid;
{
FILE *fp;
dprintf("Entering gss_mech_initialize\n");
if (oid == NULL ||
!g_OID_equal(oid, &dummy_mechanism.mech_type)) {
fprintf(stderr, "invalid dummy mechanism oid.\n");
return (NULL);
}
fp = fopen("/etc/dummy_mech_token.conf", "rF");
if (fp == NULL) {
fprintf(stderr, "dummy_mech.conf is not found.\n");
fprintf(stderr, "Setting number tokens exchanged to 1\n");
token_nums = 1;
} else {
fscanf(fp, "%d", &token_nums);
fclose(fp);
dprintf("dummy_mech.conf is found.\n");
dprintf1("Setting number tokens exchanged to %d\n", token_nums);
}
if (token_nums == 1)
dummy_flags = GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
else
dummy_flags = GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG
| GSS_C_MUTUAL_FLAG;
dprintf("Leaving gss_mech_initialize\n");
return (&dummy_mechanism);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_acquire_cred(ctx, minor_status, desired_name, time_req, desired_mechs,
cred_usage, output_cred_handle,
actual_mechs, time_rec)
void *ctx;
OM_uint32 *minor_status;
gss_name_t desired_name;
OM_uint32 time_req;
gss_OID_set desired_mechs;
gss_cred_usage_t cred_usage;
gss_cred_id_t *output_cred_handle;
gss_OID_set *actual_mechs;
OM_uint32 *time_rec;
{
dprintf("Entering dummy_gss_acquire_cred\n");
if (actual_mechs)
*actual_mechs = NULL;
if (time_rec)
*time_rec = 0;
*output_cred_handle = (gss_cred_id_t)
make_dummy_token("dummy_gss_acquire_cred");
if (time_rec) /* user may pass a null pointer */
*time_rec = GSS_C_INDEFINITE;
if (actual_mechs) {
if (gss_copy_oid_set(minor_status, gss_mech_set_dummy,
actual_mechs) == GSS_S_FAILURE) {
return (GSS_S_FAILURE);
}
}
dprintf("Leaving dummy_gss_acquire_cred\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_release_cred(ctx, minor_status, cred_handle)
void *ctx;
OM_uint32 *minor_status;
gss_cred_id_t *cred_handle;
{
dprintf("Entering dummy_gss_release_cred\n");
free_dummy_token((dummy_token_t *)(cred_handle));
*cred_handle = NULL;
dprintf("Leaving dummy_gss_release_cred\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
context_handle, target_name, mech_type,
req_flags, time_req, input_chan_bindings,
input_token, actual_mech_type, output_token,
ret_flags, time_rec)
void *ct;
OM_uint32 *minor_status;
gss_cred_id_t claimant_cred_handle;
gss_ctx_id_t *context_handle;
gss_name_t target_name;
gss_OID mech_type;
OM_uint32 req_flags;
OM_uint32 time_req;
gss_channel_bindings_t input_chan_bindings;
gss_buffer_t input_token;
gss_OID *actual_mech_type;
gss_buffer_t output_token;
OM_uint32 *ret_flags;
OM_uint32 *time_rec;
{
dummy_gss_ctx_id_t ctx;
char token_string[64];
OM_uint32 ret;
OM_uint32 aret;
int send_token = 0;
dprintf("Entering init_sec_context\n");
output_token->length = 0;
output_token->value = NULL;
if (actual_mech_type)
*actual_mech_type = NULL;
if (*context_handle == GSS_C_NO_CONTEXT) {
if (input_token != NULL && input_token->value != NULL)
return (GSS_S_FAILURE);
ctx = (dummy_gss_ctx_id_t)malloc(sizeof (dummy_gss_ctx_id_rec));
ctx->established = 0;
ctx->last_stat = 0xffffffff;
*context_handle = (gss_ctx_id_t)ctx;
/*
* Initiator interpretation of config file. If 2 or more
* the client returns CONTINUE_NNED on the first call.
*/
if (token_nums >= 2) {
ret = GSS_S_CONTINUE_NEEDED;
} else {
ret = GSS_S_COMPLETE;
}
send_token = 1;
} else {
unsigned char *ptr;
int bodysize;
int err;
if (input_token == NULL || input_token->value == NULL) {
ctx->last_stat = GSS_S_FAILURE;
return (GSS_S_FAILURE);
}
ctx = (dummy_gss_ctx_id_t)(*context_handle);
ptr = (unsigned char *) input_token->value;
if (err = g_verify_token_header((gss_OID)gss_mech_dummy,
&bodysize, &ptr, 0, input_token->length)) {
*minor_status = err;
ctx->last_stat = GSS_S_DEFECTIVE_TOKEN;
return (GSS_S_DEFECTIVE_TOKEN);
}
if (sscanf((char *)ptr, "%d", &aret) < 1) {
*minor_status = 1;
ctx->last_stat = GSS_S_DEFECTIVE_TOKEN;
return (GSS_S_DEFECTIVE_TOKEN);
}
if (aret == GSS_S_CONTINUE_NEEDED) {
if (ctx->last_stat == GSS_S_COMPLETE) {
/*
* RFC 2078, page 36, under GSS_S_COMPLETE
* says that acceptor (target) has sufficient
* information to perform per-message
* processing. So if initiator previously
* returned GSS_S_COMPLETE, and acceptor
* says he needs more, then we have
* a problem.
*/
ctx->last_stat = GSS_S_FAILURE;
return (GSS_S_FAILURE);
}
ret = GSS_S_CONTINUE_NEEDED;
send_token = 1;
} else {
ret = GSS_S_COMPLETE;
send_token = 0;
}
}
if (ret_flags) /* user may pass a null pointer */
*ret_flags = dummy_flags;
if (time_rec) /* user may pass a null pointer */
*time_rec = GSS_C_INDEFINITE;
if (actual_mech_type)
*actual_mech_type = (gss_OID) gss_mech_dummy;
if (send_token == 1) {
sprintf(token_string, "%d", ret);
*output_token = make_dummy_token_msg(
token_string, strlen(token_string) + 1);
} else {
*output_token = make_dummy_token_msg(NULL, 0);
}
if (ret == GSS_S_COMPLETE)
ctx->established = 1;
ctx->last_stat = ret;
return (ret);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_accept_sec_context(ct, minor_status, context_handle,
verifier_cred_handle, input_token,
input_chan_bindings, src_name, mech_type,
output_token, ret_flags, time_rec,
delegated_cred_handle)
void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t *context_handle;
gss_cred_id_t verifier_cred_handle;
gss_buffer_t input_token;
gss_channel_bindings_t input_chan_bindings;
gss_name_t *src_name;
gss_OID *mech_type;
gss_buffer_t output_token;
OM_uint32 *ret_flags;
OM_uint32 *time_rec;
gss_cred_id_t *delegated_cred_handle;
{
dummy_gss_ctx_id_t ctx;
char token_string[64];
gss_buffer_desc name;
OM_uint32 status;
gss_name_t temp;
unsigned char *ptr;
int bodysize;
int err;
OM_uint32 iret;
int return_token = 0;
dprintf("Entering accept_sec_context\n");
if (src_name)
*src_name = (gss_name_t)NULL;
output_token->length = 0;
output_token->value = NULL;
if (mech_type)
*mech_type = GSS_C_NULL_OID;
/* return a bogus cred handle */
if (delegated_cred_handle)
*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
/* Check for defective input token. */
ptr = (unsigned char *) input_token->value;
if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize,
&ptr, 0,
input_token->length)) {
*minor_status = err;
return (GSS_S_DEFECTIVE_TOKEN);
}
if (sscanf((char *)ptr, "%d", &iret) < 1) {
*minor_status = 1;
return (GSS_S_DEFECTIVE_TOKEN);
}
if (*context_handle == GSS_C_NO_CONTEXT) {
ctx = (dummy_gss_ctx_id_t)malloc(sizeof (dummy_gss_ctx_id_rec));
ctx->token_number = token_nums;
ctx->established = 0;
*context_handle = (gss_ctx_id_t)ctx;
} else {
ctx = (dummy_gss_ctx_id_t)(*context_handle);
}
if (ret_flags) /* user may pass a null pointer */
*ret_flags = dummy_flags;
if (time_rec) /* user may pass a null pointer */
*time_rec = GSS_C_INDEFINITE;
if (mech_type)
*mech_type = (gss_OID)gss_mech_dummy;
/*
* RFC 2078, page 36, under GSS_S_COMPLETE, GSS_S_CONTINUE_NEEDED
* tells us whether to return a token or not.
*/
if (iret == GSS_S_CONTINUE_NEEDED)
return_token = 1;
else
return_token = 0;
if (ctx->token_number > 1) {
/*
* RFC 2078, page 36, under GSS_S_COMPLETE, says that if
* initiator is done, the target (us) has what it needs, so
* it must return GSS_S_COMPLETE;
*/
if (iret == GSS_S_CONTINUE_NEEDED)
status = GSS_S_CONTINUE_NEEDED;
else
status = GSS_S_COMPLETE;
} else
status = GSS_S_COMPLETE;
/* source name is ready at GSS_S_COMPLELE */
if ((status == GSS_S_COMPLETE) && src_name) {
name.length = strlen(dummy_srcname);
name.value = dummy_srcname;
status = dummy_gss_import_name(ct, minor_status, &name,
(gss_OID)GSS_C_NT_USER_NAME, &temp);
if (status != GSS_S_COMPLETE) {
free(*context_handle);
*context_handle = GSS_C_NO_CONTEXT;
return (status);
}
*src_name = temp;
}
if (status == GSS_S_COMPLETE) {
ctx->established = 1;
}
if (return_token == 1) {
sprintf(token_string, "%d", status);
*output_token = make_dummy_token_msg(
token_string, strlen(token_string) + 1);
} else {
*output_token = make_dummy_token_msg(NULL, 0);
}
if (ctx->token_number > 0)
ctx->token_number--;
return (status);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_process_context_token(ct, minor_status, context_handle, token_buffer)
void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
gss_buffer_t token_buffer;
{
dprintf("In process_sec_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_delete_sec_context(ct, minor_status, context_handle, output_token)
void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t *context_handle;
gss_buffer_t output_token;
{
dummy_gss_ctx_id_t ctx;
dprintf("Entering delete_sec_context\n");
/* Make the length to 0, so the output token is not sent to peer */
if (output_token) {
output_token->length = 0;
output_token->value = NULL;
}
if (*context_handle == GSS_C_NO_CONTEXT) {
*minor_status = 0;
return (GSS_S_COMPLETE);
}
ctx = (dummy_gss_ctx_id_t)*context_handle;
free(ctx);
*context_handle = GSS_C_NO_CONTEXT;
dprintf("Leaving delete_sec_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_context_time(ct, minor_status, context_handle, time_rec)
void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
OM_uint32 *time_rec;
{
dprintf("In context_time\n");
if (time_rec) /* user may pass a null pointer */
return (GSS_S_FAILURE);
else
*time_rec = GSS_C_INDEFINITE;
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_sign(ctx, minor_status, context_handle,
qop_req, message_buffer, message_token)
void *ctx;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
int qop_req;
gss_buffer_t message_buffer;
gss_buffer_t message_token;
{
char token_string[] = "dummy_gss_sign";
dummy_gss_ctx_id_t context;
dprintf("Entering gss_sign\n");
context = (dummy_gss_ctx_id_t)(context_handle);
if (context_handle == GSS_C_NO_CONTEXT)
return (GSS_S_NO_CONTEXT);
if (!context->established)
return (GSS_S_NO_CONTEXT);
*message_token = make_dummy_token_msg(
token_string, strlen(token_string));
dprintf("Leaving gss_sign\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_verify(ctx, minor_status, context_handle,
message_buffer, token_buffer, qop_state)
void *ctx;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
gss_buffer_t message_buffer;
gss_buffer_t token_buffer;
int *qop_state;
{
unsigned char *ptr;
int bodysize;
int err;
dummy_gss_ctx_id_t context;
dprintf("Entering gss_verify\n");
context = (dummy_gss_ctx_id_t)(context_handle);
if (context_handle == GSS_C_NO_CONTEXT)
return (GSS_S_NO_CONTEXT);
if (!context->established)
return (GSS_S_NO_CONTEXT);
/* Check for defective input token. */
ptr = (unsigned char *) token_buffer->value;
if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize,
&ptr, 0,
token_buffer->length)) {
*minor_status = err;
return (GSS_S_DEFECTIVE_TOKEN);
}
if (qop_state)
*qop_state = GSS_C_QOP_DEFAULT;
dprintf("Leaving gss_verify\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_seal(ctx, minor_status, context_handle, conf_req_flag,
qop_req, input_message_buffer, conf_state,
output_message_buffer)
void *ctx;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
int conf_req_flag;
int qop_req;
gss_buffer_t input_message_buffer;
int *conf_state;
gss_buffer_t output_message_buffer;
{
gss_buffer_desc output;
dummy_gss_ctx_id_t context;
dprintf("Entering gss_seal\n");
context = (dummy_gss_ctx_id_t)(context_handle);
if (context_handle == GSS_C_NO_CONTEXT)
return (GSS_S_NO_CONTEXT);
if (!context->established)
return (GSS_S_NO_CONTEXT);
/* Copy the input message to output message */
output = make_dummy_token_msg(
input_message_buffer->value, input_message_buffer->length);
if (conf_state)
*conf_state = 1;
*output_message_buffer = output;
dprintf("Leaving gss_seal\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_unseal(ctx, minor_status, context_handle,
input_message_buffer, output_message_buffer,
conf_state, qop_state)
void *ctx;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
gss_buffer_t input_message_buffer;
gss_buffer_t output_message_buffer;
int *conf_state;
int *qop_state;
{
gss_buffer_desc output;
unsigned char *ptr;
int bodysize;
int err;
dummy_gss_ctx_id_t context;
dprintf("Entering gss_unseal\n");
context = (dummy_gss_ctx_id_t)(context_handle);
if (context_handle == GSS_C_NO_CONTEXT)
return (GSS_S_NO_CONTEXT);
if (!context->established)
return (GSS_S_NO_CONTEXT);
ptr = (unsigned char *) input_message_buffer->value;
if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize,
&ptr, 0,
input_message_buffer->length)) {
*minor_status = err;
return (GSS_S_DEFECTIVE_TOKEN);
}
output.length = bodysize;
output.value = (void *)malloc(output.length);
memcpy(output.value, ptr, output.length);
*output_message_buffer = output;
if (qop_state)
*qop_state = GSS_C_QOP_DEFAULT;
if (conf_state)
*conf_state = 1;
dprintf("Leaving gss_unseal\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_display_status(ctx, minor_status, status_value, status_type,
mech_type, message_context, status_string)
void *ctx;
OM_uint32 *minor_status;
OM_uint32 status_value;
int status_type;
gss_OID mech_type;
OM_uint32 *message_context;
gss_buffer_t status_string;
{
dprintf("Entering display_status\n");
*message_context = 0;
*status_string = make_dummy_token_buffer("dummy_gss_display_status");
dprintf("Leaving display_status\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_indicate_mechs(ctx, minor_status, mech_set)
void *ctx;
OM_uint32 *minor_status;
gss_OID_set *mech_set;
{
dprintf("Entering indicate_mechs\n");
*minor_status = 0;
if (mech_set) {
if (gss_copy_oid_set(minor_status, gss_mech_set_dummy,
mech_set) == GSS_S_FAILURE) {
return (GSS_S_FAILURE);
}
}
dprintf("Leaving indicate_mechs\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_compare_name(ctx, minor_status, name1, name2, name_equal)
void *ctx;
OM_uint32 *minor_status;
gss_name_t name1;
gss_name_t name2;
int *name_equal;
{
dummy_name_t name_1 = (dummy_name_t)name1;
dummy_name_t name_2 = (dummy_name_t)name2;
dprintf("Entering compare_name\n");
if (g_OID_equal(name_1->type, name_2->type) &&
(name_1->buffer->length == name_2->buffer->length) &&
!memcmp(name_1->buffer->value, name_2->buffer->value,
name_1->buffer->length))
*name_equal = 1;
else
*name_equal = 0;
dprintf("Leaving compare_name\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_display_name(ctx, minor_status, input_name, output_name_buffer,
output_name_type)
void *ctx;
OM_uint32 *minor_status;
gss_name_t input_name;
gss_buffer_t output_name_buffer;
gss_OID *output_name_type;
{
OM_uint32 status = GSS_S_COMPLETE;
dummy_name_t name = (dummy_name_t)input_name;
dprintf("Entering display_name\n");
if (g_OID_equal(name->type, GSS_C_NT_USER_NAME) ||
g_OID_equal(name->type, GSS_C_NT_MACHINE_UID_NAME) ||
g_OID_equal(name->type, GSS_C_NT_STRING_UID_NAME) ||
g_OID_equal(name->type, GSS_C_NT_HOSTBASED_SERVICE)) {
/*
* output_name_buffer = (gss_buffer_t)
* malloc(sizeof (gss_buffer_desc));
*/
if (output_name_buffer == NULL)
return (GSS_S_FAILURE);
output_name_buffer->length = name->buffer->length;
output_name_buffer->value = (void *)
malloc(name->buffer->length);
if (output_name_buffer->value == NULL)
return (GSS_S_FAILURE);
memcpy(output_name_buffer->value, name->buffer->value,
name->buffer->length);
if (output_name_type)
*output_name_type = name->type;
dprintf("Leaving display_name\n");
return (status);
}
dprintf("Leaving display_name\n");
return (GSS_S_BAD_NAMETYPE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_import_name(ctx, minor_status, input_name_buffer,
input_name_type, output_name)
void *ctx;
OM_uint32 *minor_status;
gss_buffer_t input_name_buffer;
gss_OID input_name_type;
gss_name_t *output_name;
{
OM_uint32 status;
dprintf("Entering import_name\n");
*output_name = NULL;
*minor_status = 0;
if (input_name_type == GSS_C_NULL_OID)
return (GSS_S_BAD_NAMETYPE);
if (g_OID_equal(input_name_type, GSS_C_NT_USER_NAME) ||
g_OID_equal(input_name_type, GSS_C_NT_MACHINE_UID_NAME) ||
g_OID_equal(input_name_type, GSS_C_NT_STRING_UID_NAME) ||
g_OID_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE)) {
dummy_name_t name = (dummy_name_t)
malloc(sizeof (dummy_name_desc));
name->buffer = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
name->buffer->length = input_name_buffer->length;
name->buffer->value = (void *)malloc(input_name_buffer->length);
if (name->buffer->value == NULL)
return (GSS_S_FAILURE);
memcpy(name->buffer->value, input_name_buffer->value,
input_name_buffer->length);
status = generic_gss_copy_oid(minor_status,
input_name_type, &(name->type));
*output_name = (gss_name_t)name;
dprintf("Leaving import_name\n");
return (status);
}
dprintf("Leaving import_name\n");
return (GSS_S_BAD_NAMETYPE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_release_name(ctx, minor_status, input_name)
void *ctx;
OM_uint32 *minor_status;
gss_name_t *input_name;
{
dummy_name_t name = (dummy_name_t)*input_name;
dprintf("Entering release_name\n");
free(name->buffer->value);
generic_gss_release_oid(minor_status, &(name->type));
free(name->buffer);
free(name);
dprintf("Leaving release_name\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret,
cred_usage, mechanisms)
void *ctx;
OM_uint32 *minor_status;
gss_cred_id_t cred_handle;
gss_name_t *name;
OM_uint32 *lifetime_ret;
gss_cred_usage_t *cred_usage;
gss_OID_set *mechanisms;
{
dprintf("Entering inquire_cred\n");
if (name)
*name = (gss_name_t)make_dummy_token
("dummy gss credential");
if (lifetime_ret)
*lifetime_ret = GSS_C_INDEFINITE;
if (cred_usage)
*cred_usage = GSS_C_BOTH;
if (mechanisms) {
if (gss_copy_oid_set(minor_status, gss_mech_set_dummy,
mechanisms) == GSS_S_FAILURE)
return (GSS_S_FAILURE);
}
dprintf("Leaving inquire_cred\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_add_cred(ctx, minor_status, input_cred_handle,
desired_name, desired_mech, cred_usage,
initiator_time_req, acceptor_time_req,
output_cred_handle, actual_mechs,
initiator_time_rec, acceptor_time_rec)
void *ctx;
OM_uint32 *minor_status;
gss_cred_id_t input_cred_handle;
gss_name_t desired_name;
gss_OID desired_mech;
gss_cred_usage_t cred_usage;
OM_uint32 initiator_time_req;
OM_uint32 acceptor_time_req;
gss_cred_id_t *output_cred_handle;
gss_OID_set *actual_mechs;
OM_uint32 *initiator_time_rec;
OM_uint32 *acceptor_time_rec;
{
dprintf("Entering add_cred\n");
if ((desired_mech != GSS_C_NULL_OID) &&
(g_OID_equal(desired_mech, gss_mech_dummy)))
return (GSS_S_BAD_MECH);
*minor_status = 0;
dprintf("Leaving add_cred\n");
/* This routine likes in kerberos V5 is never be used / called by */
/* the GSS_API. It simply returns GSS_S_DUPLICATE_ELEMENT to indicate */
/* this error */
return (GSS_S_DUPLICATE_ELEMENT);
}
/* Should I add the token structure to deal with import/export */
/* of sec_context. For now, I just create dummy interprocess token, and when */
/* the peer accept it, it calls the import_sec_context.The import_sec_context */
/* creates new sec_context with status established. (rather than get it */
/* from interprocess token. it can be done because the sec context in dummy */
/* mechanism is very simple (contains only status if it's established). */
/*ARGSUSED*/
OM_uint32
dummy_gss_export_sec_context(ct, minor_status, context_handle,
interprocess_token)
void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t *context_handle;
gss_buffer_t interprocess_token;
{
char str[] = "dummy_gss_export_sec_context";
dprintf("Entering export_sec_context\n");
*interprocess_token = make_dummy_token_msg(str, strlen(str));
free(*context_handle);
*context_handle = GSS_C_NO_CONTEXT;
dprintf("Leaving export_sec_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_import_sec_context(ct, minor_status, interprocess_token,
context_handle)
void *ct;
OM_uint32 *minor_status;
gss_buffer_t interprocess_token;
gss_ctx_id_t *context_handle;
{
/* Assume that we got ctx from the interprocess token. */
dummy_gss_ctx_id_t ctx;
dprintf("Entering import_sec_context\n");
ctx = (dummy_gss_ctx_id_t)malloc(sizeof (dummy_gss_ctx_id_rec));
ctx->token_number = 0;
ctx->established = 1;
*context_handle = (gss_ctx_id_t)ctx;
dprintf("Leaving import_sec_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_inquire_cred_by_mech(ctx, minor_status, cred_handle,
mech_type, name, initiator_lifetime,
acceptor_lifetime, cred_usage)
void *ctx;
OM_uint32 *minor_status;
gss_cred_id_t cred_handle;
gss_OID mech_type;
gss_name_t *name;
OM_uint32 *initiator_lifetime;
OM_uint32 *acceptor_lifetime;
gss_cred_usage_t *cred_usage;
{
dprintf("Entering inquire_cred_by_mech\n");
if (name)
*name = (gss_name_t)make_dummy_token("dummy credential name");
if (initiator_lifetime)
*initiator_lifetime = GSS_C_INDEFINITE;
if (acceptor_lifetime)
*acceptor_lifetime = GSS_C_INDEFINITE;
if (cred_usage)
*cred_usage = GSS_C_BOTH;
dprintf("Leaving inquire_cred_by_mech\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_inquire_names_for_mech(ctx, minor_status, mechanism, name_types)
void *ctx;
OM_uint32 *minor_status;
gss_OID mechanism;
gss_OID_set *name_types;
{
OM_uint32 major, minor;
dprintf("Entering inquire_names_for_mech\n");
/*
* We only know how to handle our own mechanism.
*/
if ((mechanism != GSS_C_NULL_OID) &&
!g_OID_equal(gss_mech_dummy, mechanism)) {
*minor_status = 0;
return (GSS_S_FAILURE);
}
major = gss_create_empty_oid_set(minor_status, name_types);
if (major == GSS_S_COMPLETE) {
/* Now add our members. */
if (((major = gss_add_oid_set_member(minor_status,
(gss_OID) GSS_C_NT_USER_NAME, name_types))
== GSS_S_COMPLETE) &&
((major = gss_add_oid_set_member(minor_status,
(gss_OID) GSS_C_NT_MACHINE_UID_NAME, name_types))
== GSS_S_COMPLETE) &&
((major = gss_add_oid_set_member(minor_status,
(gss_OID) GSS_C_NT_STRING_UID_NAME, name_types))
== GSS_S_COMPLETE)) {
major = gss_add_oid_set_member(minor_status,
(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, name_types);
}
if (major != GSS_S_COMPLETE)
(void) gss_release_oid_set(&minor, name_types);
}
dprintf("Leaving inquire_names_for_mech\n");
return (major);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_inquire_context(ct, minor_status, context_handle, initiator_name,
acceptor_name, lifetime_rec, mech_type, ret_flags,
locally_initiated, open)
void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
gss_name_t *initiator_name;
gss_name_t *acceptor_name;
OM_uint32 *lifetime_rec;
gss_OID *mech_type;
OM_uint32 *ret_flags;
int *locally_initiated;
int *open;
{
dummy_gss_ctx_id_t ctx;
dummy_name_t name1, name2;
OM_uint32 status;
dprintf("Entering inquire_context\n");
ctx = (dummy_gss_ctx_id_t)(context_handle);
name1 = (dummy_name_t)
malloc(sizeof (dummy_name_desc));
name1->buffer = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
name1->buffer->length = dummy_context_name_len;
name1->buffer->value = make_dummy_token("dummy context name");
status = generic_gss_copy_oid(minor_status,
(gss_OID) GSS_C_NT_USER_NAME, &(name1->type));
if (status != GSS_S_COMPLETE)
return (status);
if (initiator_name)
*initiator_name = (gss_name_t)name1;
name2 = (dummy_name_t)
malloc(sizeof (dummy_name_desc));
name2->buffer = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
name2->buffer->length = dummy_context_name_len;
name2->buffer->value = make_dummy_token("dummy context name");
status = generic_gss_copy_oid(minor_status,
(gss_OID) GSS_C_NT_USER_NAME, &(name2->type));
if (status != GSS_S_COMPLETE)
return (status);
if (acceptor_name)
*acceptor_name = (gss_name_t)name2;
if (lifetime_rec) /* user may pass a null pointer */
*lifetime_rec = GSS_C_INDEFINITE;
if (mech_type)
*mech_type = (gss_OID)gss_mech_dummy;
if (ret_flags)
*ret_flags = dummy_flags;
if (open)
*open = ctx->established;
dprintf("Leaving inquire_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_internal_release_oid(ct, minor_status, oid)
void *ct;
OM_uint32 *minor_status;
gss_OID *oid;
{
dprintf("Entering internal_release_oid\n");
/* Similar to krb5_gss_internal_release_oid */
if (*oid != gss_mech_dummy)
return (GSS_S_CONTINUE_NEEDED); /* We don't know this oid */
*minor_status = 0;
*oid = GSS_C_NO_OID;
dprintf("Leaving internal_release_oid\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
OM_uint32
dummy_gss_wrap_size_limit(ct, minor_status, context_handle, conf_req_flag,
qop_req, req_output_size, max_input_size)
void *ct;
OM_uint32 *minor_status;
gss_ctx_id_t context_handle;
int conf_req_flag;
gss_qop_t qop_req;
OM_uint32 req_output_size;
OM_uint32 *max_input_size;
{
dprintf("Entering wrap_size_limit\n");
*max_input_size = req_output_size;
dprintf("Leaving wrap_size_limit\n");
return (GSS_S_COMPLETE);
}
/* ARGSUSED */
OM_uint32
dummy_pname_to_uid(ct, minor_status, name, uidOut)
void *ct;
OM_uint32 *minor_status;
const gss_name_t name;
uid_t *uidOut;
{
dprintf("Entering pname_to_uid\n");
*minor_status = 0;
*uidOut = 60001;
dprintf("Leaving pname_to_uid\n");
return (GSS_S_COMPLETE);
}
static dummy_token_t
make_dummy_token(char *name)
{
dummy_token_t token;
token = (dummy_token_t)malloc(strlen(name)+1);
strcpy(token, name);
return (token);
}
static void
free_dummy_token(dummy_token_t *token)
{
free(*token);
*token = NULL;
}
static gss_buffer_desc
make_dummy_token_buffer(char *name)
{
gss_buffer_desc buffer;
if (name == NULL) {
buffer.length = 0;
buffer.value = NULL;
} else {
buffer.length = strlen(name)+1;
buffer.value = make_dummy_token(name);
}
return (buffer);
}
static gss_buffer_desc
make_dummy_token_msg(void *data, int dataLen)
{
gss_buffer_desc buffer;
int tlen;
unsigned char *t;
unsigned char *ptr;
if (data == NULL) {
buffer.length = 0;
buffer.value = NULL;
return (buffer);
}
tlen = g_token_size((gss_OID)gss_mech_dummy, dataLen);
t = (unsigned char *) malloc(tlen);
ptr = t;
g_make_token_header((gss_OID)gss_mech_dummy, dataLen, &ptr, 0);
memcpy(ptr, data, dataLen);
buffer.length = tlen;
buffer.value = (void *) t;
return (buffer);
}
static int
der_length_size(length)
int length;
{
if (length < (1<<7))
return (1);
else if (length < (1<<8))
return (2);
else if (length < (1<<16))
return (3);
else if (length < (1<<24))
return (4);
else
return (5);
}
static void
der_write_length(buf, length)
unsigned char **buf;
int length;
{
if (length < (1<<7)) {
*(*buf)++ = (unsigned char) length;
} else {
*(*buf)++ = (unsigned char) (der_length_size(length)+127);
if (length >= (1<<24))
*(*buf)++ = (unsigned char) (length>>24);
if (length >= (1<<16))
*(*buf)++ = (unsigned char) ((length>>16)&0xff);
if (length >= (1<<8))
*(*buf)++ = (unsigned char) ((length>>8)&0xff);
*(*buf)++ = (unsigned char) (length&0xff);
}
}
static int
der_read_length(buf, bufsize)
unsigned char **buf;
int *bufsize;
{
unsigned char sf;
int ret;
if (*bufsize < 1)
return (-1);
sf = *(*buf)++;
(*bufsize)--;
if (sf & 0x80) {
if ((sf &= 0x7f) > ((*bufsize)-1))
return (-1);
if (sf > DUMMY_SIZE_OF_INT)
return (-1);
ret = 0;
for (; sf; sf--) {
ret = (ret<<8) + (*(*buf)++);
(*bufsize)--;
}
} else {
ret = sf;
}
return (ret);
}
static int
g_token_size(mech, body_size)
gss_OID mech;
unsigned int body_size;
{
/* set body_size to sequence contents size */
body_size += 4 + (int)mech->length; /* NEED overflow check */
return (1 + der_length_size(body_size) + body_size);
}
static void
g_make_token_header(mech, body_size, buf, tok_type)
gss_OID mech;
int body_size;
unsigned char **buf;
int tok_type;
{
*(*buf)++ = 0x60;
der_write_length(buf, 4 + mech->length + body_size);
*(*buf)++ = 0x06;
*(*buf)++ = (unsigned char) mech->length;
TWRITE_STR(*buf, mech->elements, ((int)mech->length));
*(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
*(*buf)++ = (unsigned char) (tok_type&0xff);
}
static int
g_verify_token_header(mech, body_size, buf_in, tok_type, toksize)
gss_OID mech;
int *body_size;
unsigned char **buf_in;
int tok_type;
int toksize;
{
unsigned char *buf = *buf_in;
int seqsize;
gss_OID_desc toid;
int ret = 0;
if ((toksize -= 1) < 0)
return (G_BAD_TOK_HEADER);
if (*buf++ != 0x60)
return (G_BAD_TOK_HEADER);
if ((seqsize = der_read_length(&buf, &toksize)) < 0)
return (G_BAD_TOK_HEADER);
if (seqsize != toksize)
return (G_BAD_TOK_HEADER);
if ((toksize -= 1) < 0)
return (G_BAD_TOK_HEADER);
if (*buf++ != 0x06)
return (G_BAD_TOK_HEADER);
if ((toksize -= 1) < 0)
return (G_BAD_TOK_HEADER);
toid.length = *buf++;
if ((toksize -= toid.length) < 0)
return (G_BAD_TOK_HEADER);
toid.elements = buf;
buf += toid.length;
if (!g_OID_equal(&toid, mech))
ret = G_WRONG_MECH;
/*
* G_WRONG_MECH is not returned immediately because it's more important
* to return G_BAD_TOK_HEADER if the token header is in fact bad
*/
if ((toksize -= 2) < 0)
return (G_BAD_TOK_HEADER);
if ((*buf++ != ((tok_type>>8)&0xff)) ||
(*buf++ != (tok_type&0xff)))
return (G_BAD_TOK_HEADER);
if (!ret) {
*buf_in = buf;
*body_size = toksize;
}
return (ret);
}