/*
* 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
* 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 \
#define dummy_gss_acquire_cred \
#define dummy_gss_add_cred \
#define dummy_gss_compare_name \
#define dummy_gss_context_time \
#define dummy_gss_delete_sec_context \
#define dummy_gss_display_name \
#define dummy_gss_display_status \
#define dummy_gss_export_sec_context \
#define dummy_gss_import_name \
#define dummy_gss_import_sec_context \
#define dummy_gss_indicate_mechs \
#define dummy_gss_init_sec_context \
#define dummy_gss_inquire_context \
#define dummy_gss_inquire_cred \
#define dummy_gss_inquire_cred_by_mech \
#define dummy_gss_inquire_names_for_mech \
#define dummy_gss_internal_release_oid \
#define dummy_gss_process_context_token \
#define dummy_gss_release_cred \
#define dummy_gss_release_name \
#define dummy_gss_seal \
#define dummy_gss_sign \
#define dummy_gss_unseal \
#define dummy_gss_verify \
#define dummy_gss_wrap_size_limit \
#define dummy_pname_to_uid \
#endif
#include <stdio.h>
#include <stdlib.h>
#include <gssapiP_dummy.h>
#include <mechglueP.h>
#include <gssapi_err_generic.h>
/* private routines for dummy_mechanism */
static int der_length_size(int length);
int toksize);
/* private global variables */
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) }
*/
{{10, "\053\006\001\004\001\052\002\032\001\002"},
NULL,
NULL, /* __gss_userok */
NULL, /* _export name */
NULL, /* _store_cred */
};
{
dprintf("Entering gss_mech_initialize\n");
return (NULL);
}
token_nums = 1;
} else {
dprintf("dummy_mech.conf is found.\n");
}
if (token_nums == 1)
else
dprintf("Leaving gss_mech_initialize\n");
return (&dummy_mechanism);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering dummy_gss_acquire_cred\n");
if (actual_mechs)
*actual_mechs = NULL;
if (time_rec)
*time_rec = 0;
make_dummy_token("dummy_gss_acquire_cred");
if (time_rec) /* user may pass a null pointer */
if (actual_mechs) {
actual_mechs) == GSS_S_FAILURE) {
return (GSS_S_FAILURE);
}
}
dprintf("Leaving dummy_gss_acquire_cred\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering dummy_gss_release_cred\n");
*cred_handle = NULL;
dprintf("Leaving dummy_gss_release_cred\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ct;
{
int send_token = 0;
dprintf("Entering init_sec_context\n");
output_token->length = 0;
if (actual_mech_type)
*actual_mech_type = NULL;
if (*context_handle == GSS_C_NO_CONTEXT) {
return (GSS_S_FAILURE);
ctx->established = 0;
/*
* Initiator interpretation of config file. If 2 or more
* the client returns CONTINUE_NNED on the first call.
*/
if (token_nums >= 2) {
} else {
}
send_token = 1;
} else {
unsigned char *ptr;
int bodysize;
int err;
return (GSS_S_FAILURE);
}
*minor_status = err;
return (GSS_S_DEFECTIVE_TOKEN);
}
*minor_status = 1;
return (GSS_S_DEFECTIVE_TOKEN);
}
if (aret == GSS_S_CONTINUE_NEEDED) {
/*
* 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.
*/
return (GSS_S_FAILURE);
}
send_token = 1;
} else {
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 */
if (actual_mech_type)
if (send_token == 1) {
} else {
}
if (ret == GSS_S_COMPLETE)
return (ret);
}
/*ARGSUSED*/
void *ct;
{
unsigned char *ptr;
int bodysize;
int err;
int return_token = 0;
dprintf("Entering accept_sec_context\n");
if (src_name)
output_token->length = 0;
if (mech_type)
/* return a bogus cred handle */
/* Check for defective input token. */
&ptr, 0,
input_token->length)) {
*minor_status = err;
return (GSS_S_DEFECTIVE_TOKEN);
}
*minor_status = 1;
return (GSS_S_DEFECTIVE_TOKEN);
}
if (*context_handle == GSS_C_NO_CONTEXT) {
ctx->established = 0;
} else {
}
if (ret_flags) /* user may pass a null pointer */
*ret_flags = dummy_flags;
if (time_rec) /* user may pass a null pointer */
if (mech_type)
/*
* 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;
/*
* 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)
else
} else
/* source name is ready at GSS_S_COMPLELE */
if (status != GSS_S_COMPLETE) {
return (status);
}
}
if (status == GSS_S_COMPLETE) {
}
if (return_token == 1) {
} else {
}
if (ctx->token_number > 0)
ctx->token_number--;
return (status);
}
/*ARGSUSED*/
void *ct;
{
dprintf("In process_sec_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ct;
{
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;
}
if (*context_handle == GSS_C_NO_CONTEXT) {
*minor_status = 0;
return (GSS_S_COMPLETE);
}
dprintf("Leaving delete_sec_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ct;
{
dprintf("In context_time\n");
if (time_rec) /* user may pass a null pointer */
return (GSS_S_FAILURE);
else
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
int qop_req;
{
dprintf("Entering gss_sign\n");
if (context_handle == GSS_C_NO_CONTEXT)
return (GSS_S_NO_CONTEXT);
if (!context->established)
return (GSS_S_NO_CONTEXT);
dprintf("Leaving gss_sign\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
int *qop_state;
{
unsigned char *ptr;
int bodysize;
int err;
dprintf("Entering gss_verify\n");
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, 0,
token_buffer->length)) {
*minor_status = err;
return (GSS_S_DEFECTIVE_TOKEN);
}
if (qop_state)
dprintf("Leaving gss_verify\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
int conf_req_flag;
int qop_req;
int *conf_state;
{
dprintf("Entering gss_seal\n");
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 */
if (conf_state)
*conf_state = 1;
dprintf("Leaving gss_seal\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
int *conf_state;
int *qop_state;
{
unsigned char *ptr;
int bodysize;
int err;
dprintf("Entering gss_unseal\n");
if (context_handle == GSS_C_NO_CONTEXT)
return (GSS_S_NO_CONTEXT);
if (!context->established)
return (GSS_S_NO_CONTEXT);
&ptr, 0,
*minor_status = err;
return (GSS_S_DEFECTIVE_TOKEN);
}
if (qop_state)
if (conf_state)
*conf_state = 1;
dprintf("Leaving gss_unseal\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
int status_type;
{
dprintf("Entering display_status\n");
*message_context = 0;
dprintf("Leaving display_status\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering indicate_mechs\n");
*minor_status = 0;
if (mech_set) {
mech_set) == GSS_S_FAILURE) {
return (GSS_S_FAILURE);
}
}
dprintf("Leaving indicate_mechs\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
int *name_equal;
{
dprintf("Entering compare_name\n");
*name_equal = 1;
else
*name_equal = 0;
dprintf("Leaving compare_name\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering display_name\n");
/*
* output_name_buffer = (gss_buffer_t)
* malloc(sizeof (gss_buffer_desc));
*/
if (output_name_buffer == NULL)
return (GSS_S_FAILURE);
output_name_buffer->value = (void *)
return (GSS_S_FAILURE);
if (output_name_type)
dprintf("Leaving display_name\n");
return (status);
}
dprintf("Leaving display_name\n");
return (GSS_S_BAD_NAMETYPE);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering import_name\n");
*output_name = NULL;
*minor_status = 0;
if (input_name_type == GSS_C_NULL_OID)
return (GSS_S_BAD_NAMETYPE);
malloc(sizeof (dummy_name_desc));
return (GSS_S_FAILURE);
dprintf("Leaving import_name\n");
return (status);
}
dprintf("Leaving import_name\n");
return (GSS_S_BAD_NAMETYPE);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering release_name\n");
dprintf("Leaving release_name\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering inquire_cred\n");
if (name)
("dummy gss credential");
if (lifetime_ret)
if (cred_usage)
*cred_usage = GSS_C_BOTH;
if (mechanisms) {
mechanisms) == GSS_S_FAILURE)
return (GSS_S_FAILURE);
}
dprintf("Leaving inquire_cred\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering add_cred\n");
if ((desired_mech != GSS_C_NULL_OID) &&
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);
}
/* 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*/
void *ct;
{
dprintf("Entering export_sec_context\n");
dprintf("Leaving export_sec_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ct;
{
/* Assume that we got ctx from the interprocess token. */
dprintf("Entering import_sec_context\n");
ctx->token_number = 0;
dprintf("Leaving import_sec_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering inquire_cred_by_mech\n");
if (name)
if (initiator_lifetime)
if (acceptor_lifetime)
if (cred_usage)
*cred_usage = GSS_C_BOTH;
dprintf("Leaving inquire_cred_by_mech\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ctx;
{
dprintf("Entering inquire_names_for_mech\n");
/*
* We only know how to handle our own mechanism.
*/
if ((mechanism != GSS_C_NULL_OID) &&
*minor_status = 0;
return (GSS_S_FAILURE);
}
if (major == GSS_S_COMPLETE) {
/* Now add our members. */
== GSS_S_COMPLETE) &&
== GSS_S_COMPLETE) &&
== GSS_S_COMPLETE)) {
}
if (major != GSS_S_COMPLETE)
}
dprintf("Leaving inquire_names_for_mech\n");
return (major);
}
/*ARGSUSED*/
void *ct;
int *locally_initiated;
int *open;
{
dprintf("Entering inquire_context\n");
name1 = (dummy_name_t)
malloc(sizeof (dummy_name_desc));
if (status != GSS_S_COMPLETE)
return (status);
if (initiator_name)
name2 = (dummy_name_t)
malloc(sizeof (dummy_name_desc));
if (status != GSS_S_COMPLETE)
return (status);
if (acceptor_name)
if (lifetime_rec) /* user may pass a null pointer */
if (mech_type)
if (ret_flags)
*ret_flags = dummy_flags;
if (open)
dprintf("Leaving inquire_context\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
void *ct;
{
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*/
void *ct;
int conf_req_flag;
{
dprintf("Entering wrap_size_limit\n");
dprintf("Leaving wrap_size_limit\n");
return (GSS_S_COMPLETE);
}
/* ARGSUSED */
void *ct;
const gss_name_t name;
{
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
{
return (token);
}
static void
{
}
static gss_buffer_desc
{
} else {
}
return (buffer);
}
static gss_buffer_desc
{
int tlen;
unsigned char *t;
unsigned char *ptr;
return (buffer);
}
ptr = t;
return (buffer);
}
static int
int length;
{
return (1);
return (2);
return (3);
return (4);
else
return (5);
}
static void
unsigned char **buf;
int length;
{
} else {
}
}
static int
unsigned char **buf;
int *bufsize;
{
unsigned char sf;
int ret;
if (*bufsize < 1)
return (-1);
(*bufsize)--;
if (sf & 0x80) {
return (-1);
if (sf > DUMMY_SIZE_OF_INT)
return (-1);
ret = 0;
(*bufsize)--;
}
} else {
}
return (ret);
}
static int
unsigned int body_size;
{
/* set body_size to sequence contents size */
}
static void
int body_size;
unsigned char **buf;
int tok_type;
{
*(*buf)++ = 0x60;
*(*buf)++ = 0x06;
}
static int
int *body_size;
unsigned char **buf_in;
int tok_type;
int toksize;
{
int seqsize;
int ret = 0;
if ((toksize -= 1) < 0)
return (G_BAD_TOK_HEADER);
if (*buf++ != 0x60)
return (G_BAD_TOK_HEADER);
return (G_BAD_TOK_HEADER);
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);
return (G_BAD_TOK_HEADER);
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);
return (G_BAD_TOK_HEADER);
if (!ret) {
}
return (ret);
}