예제 #1
0
파일: canon_name.c 프로젝트: Akasurde/krb5
OM_uint32 krb5_gss_canonicalize_name(OM_uint32  *minor_status,
                                     const gss_name_t input_name,
                                     const gss_OID mech_type,
                                     gss_name_t *output_name)
{
    if ((mech_type != GSS_C_NULL_OID) &&
        !g_OID_equal(gss_mech_krb5, mech_type) &&
        !g_OID_equal(gss_mech_krb5_old, mech_type)) {
        *minor_status = 0;
        return(GSS_S_BAD_MECH);
    }

    return(krb5_gss_duplicate_name(minor_status, input_name, output_name));
}
예제 #2
0
static int
get_hostbased_client_name(gss_name_t client_name, gss_OID mech,
			  char **hostbased_name)
{
	u_int32_t	maj_stat, min_stat;
	gss_buffer_desc	name;
	gss_OID		name_type = GSS_C_NO_OID;
	char		*cname;
	int		res = -1;

	*hostbased_name = NULL;	    /* preset in case we fail */

	/* Get the client's gss authenticated name */
	maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
	if (maj_stat != GSS_S_COMPLETE) {
		pgsserr("get_hostbased_client_name: gss_display_name",
			maj_stat, min_stat, mech);
		goto out_err;
	}
	if (name.length >= 0xffff) {	    /* don't overflow */
		printerr(0, "ERROR: get_hostbased_client_name: "
			 "received gss_name is too long (%d bytes)\n",
			 name.length);
		goto out_rel_buf;
	}

	/* For Kerberos, transform the NT_KRB5_PRINCIPAL name to
	 * an NT_HOSTBASED_SERVICE name */
	if (g_OID_equal(&krb5oid, mech)) {
		if (get_krb5_hostbased_name(&name, &cname) == 0)
			*hostbased_name = cname;
	}

	/* No support for SPKM3, just print a warning (for now) */
	if (g_OID_equal(&spkm3oid, mech)) {
		printerr(1, "WARNING: get_hostbased_client_name: "
			 "no hostbased_name support for SPKM3\n");
	}

	res = 0;
out_rel_buf:
	gss_release_buffer(&min_stat, &name);
out_err:
	return res;
}
예제 #3
0
int
serialize_context_for_kernel(gss_ctx_id_t ctx,
			     gss_buffer_desc *buf,
			     gss_OID mech,
			     int32_t *endtime)
{
	if (g_OID_equal(&krb5oid, mech))
		return serialize_krb5_ctx(ctx, buf, endtime);
#ifdef HAVE_SPKM3_H
	else if (g_OID_equal(&spkm3oid, mech))
		return serialize_spkm3_ctx(ctx, buf, endtime);
#endif
	else {
		printerr(0, "ERROR: attempting to serialize context with "
				"unknown/unsupported mechanism oid\n");
		return -1;
	}
}
예제 #4
0
/*
 * Find the Linux svcgssd downcall file name given the mechanism
 */
char *
mech2file(gss_OID mech)
{
	struct mech2file *m2fp = m2f;

	while(m2fp->mech.length != 0) {
		if (g_OID_equal(mech,&m2fp->mech))
			return(m2fp->filename);
		m2fp++;
	}
	return NULL;
}
예제 #5
0
OM_uint32
generic_gss_display_mech_attr(
    OM_uint32         *minor_status,
    gss_const_OID      mech_attr,
    gss_buffer_t       name,
    gss_buffer_t       short_desc,
    gss_buffer_t       long_desc)
{
    size_t i;

    if (name != GSS_C_NO_BUFFER) {
        name->length = 0;
        name->value = NULL;
    }
    if (short_desc != GSS_C_NO_BUFFER) {
        short_desc->length = 0;
        short_desc->value = NULL;
    }
    if (long_desc != GSS_C_NO_BUFFER) {
        long_desc->length = 0;
        long_desc->value = NULL;
    }
    for (i = 0; i < sizeof(mech_attr_info)/sizeof(mech_attr_info[0]); i++) {
        struct mech_attr_info_desc *mai = &mech_attr_info[i];

        if (g_OID_equal(mech_attr, mai->mech_attr)) {
            if (name != GSS_C_NO_BUFFER &&
                    !g_make_string_buffer((char *)mai->name.value, name)) {
                *minor_status = ENOMEM;
                return GSS_S_FAILURE;
            }
            if (short_desc != GSS_C_NO_BUFFER &&
                    !g_make_string_buffer((char *)mai->short_desc.value,
                                          short_desc)) {
                *minor_status = ENOMEM;
                return GSS_S_FAILURE;
            }
            if (long_desc != GSS_C_NO_BUFFER &&
                    !g_make_string_buffer((char *)mai->long_desc.value,
                                          long_desc)) {
                *minor_status = ENOMEM;
                return GSS_S_FAILURE;
            }
            return GSS_S_COMPLETE;
        }
    }

    return GSS_S_BAD_MECH_ATTR;
}
/*
 * Naming extensions based local login authorization.
 */
static OM_uint32
attr_authorize_localname(OM_uint32 *minor,
                         const gss_name_t name,
                         const gss_union_name_t unionUser)
{
    OM_uint32 major = GSS_S_UNAVAILABLE; /* attribute not present */
    gss_buffer_t externalName;
    int more = -1;

    if (unionUser->name_type != GSS_C_NO_OID &&
            !g_OID_equal(unionUser->name_type, GSS_C_NT_USER_NAME))
        return (GSS_S_BAD_NAMETYPE);

    externalName = unionUser->external_name;
    assert(externalName != GSS_C_NO_BUFFER);

    while (more != 0 && major != GSS_S_COMPLETE) {
        OM_uint32 tmpMajor, tmpMinor;
        gss_buffer_desc value;
        gss_buffer_desc display_value;
        int authenticated = 0, complete = 0;

        tmpMajor = gss_get_name_attribute(minor,
                                          name,
                                          GSS_C_ATTR_LOCAL_LOGIN_USER,
                                          &authenticated,
                                          &complete,
                                          &value,
                                          &display_value,
                                          &more);
        if (GSS_ERROR(tmpMajor)) {
            major = tmpMajor;
            break;
        }

        if (authenticated &&
                value.length == externalName->length &&
                memcmp(value.value, externalName->value, externalName->length) == 0)
            major = GSS_S_COMPLETE;
        else
            major = GSS_S_UNAUTHORIZED;

        gss_release_buffer(&tmpMinor, &value);
        gss_release_buffer(&tmpMinor, &display_value);
    }

    return (major);
}
/**
 * @brief Set Security Context Option
 * @ingroup globus_gsi_gssapi_extensions
 * @details
 * GSSAPI routine to initiate the sending of a security context
 * See: <draft-ietf-cat-gssv2-cbind-04.txt>
 *
 * @param minor_status
 * @param context_handle
 * @param option
 * @param value
 *
 * @return
 */
OM_uint32
GSS_CALLCONV gss_set_sec_context_option(
    OM_uint32 *                         minor_status,
    gss_ctx_id_t *                      context_handle,
    const gss_OID                       option,
    const gss_buffer_t                  value)
{
    gss_ctx_id_desc *                   context = NULL;
    OM_uint32                           major_status = GSS_S_COMPLETE;
    OM_uint32                           local_minor_status;
    globus_result_t                     local_result = GLOBUS_SUCCESS;
    int                                 index;

    GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER;
    
    if(minor_status == NULL)
    {
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    *minor_status = (OM_uint32) GLOBUS_SUCCESS;
    
    if(context_handle == NULL)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Invalid context_handle passed to function - cannot be NULL")));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    context = *context_handle;

    if(option == GSS_C_NO_OID)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Invalid option passed to function with value: GSS_C_NO_OID")));
        major_status = GSS_S_FAILURE;
        goto exit;
    }
    
    if (*context_handle == GSS_C_NO_CONTEXT)
    {
        /* for now just malloc and zero the context */
        context = (gss_ctx_id_desc *) malloc(sizeof(gss_ctx_id_desc));
        if (context == NULL)
        {
            GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
            major_status = GSS_S_FAILURE;
            goto exit;
        }

        *context_handle = context;
        memset(context, 0, sizeof(gss_ctx_id_desc));
        context->ctx_flags = 0;

        major_status = gss_create_empty_oid_set(
            &local_minor_status,
            (gss_OID_set *) &context->extension_oids);

        /* initialize the callback_data in the context.  This needs
         * to be done so the verify_callback func can be set later.
         */
        local_result = globus_gsi_callback_data_init(
            &context->callback_data);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_RESULT(
                minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT,
                (_GGSL("The callback data in the context "
                 "could not be initialized.")));
            major_status = GSS_S_FAILURE;
            goto exit;
        }
    }
    else if(context->ctx_flags & GSS_I_CTX_INITIALIZED)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT,
            (_GGSL("The context has already been initialized!  %s should be "
             "called on a context before initialization"), __func__));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    if(g_OID_equal(option, GSS_DISALLOW_ENCRYPTION))
    {
        context->ctx_flags |= GSS_I_DISALLOW_ENCRYPTION;
    }
    else if(g_OID_equal(option, GSS_PROTECTION_FAIL_ON_CONTEXT_EXPIRATION))
    {
        context->ctx_flags |= GSS_I_PROTECTION_FAIL_ON_CONTEXT_EXPIRATION;
    }
    else if(g_OID_equal(option, GSS_APPLICATION_WILL_HANDLE_EXTENSIONS))
    {
        if(value == GSS_C_NO_BUFFER)
        {
            GLOBUS_GSI_GSSAPI_ERROR_RESULT(
                minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
                (_GGSL("Invalid buffer passed to function")));
            major_status = GSS_S_FAILURE;
            goto exit;
        }

        for(index = 0; 
            index < ((gss_OID_set_desc *) value->value)->count; 
            index++)
        {
            major_status = gss_add_oid_set_member(
                &local_minor_status,
                (gss_OID) 
                &((gss_OID_set_desc *) value->value)->elements[index],
                (gss_OID_set *) &context->extension_oids);

            if(GSS_ERROR(major_status))
            {
                GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                    minor_status, local_minor_status,
                    GLOBUS_GSI_GSSAPI_ERROR_WITH_OID);
                goto exit;
            }
        }

        local_result = globus_gsi_callback_set_extension_cb(
            context->callback_data,
            globus_i_gsi_gss_verify_extensions_callback);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_CALLBACK_DATA);
            major_status = GSS_S_FAILURE;
            goto exit;
        }

        /* if the extension_oids are set, 
         * then we set them in the callback data */
        local_result = globus_gsi_callback_set_extension_oids(
            context->callback_data,
            (void *) context->extension_oids);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_CALLBACK_DATA);
            major_status = GSS_S_FAILURE;
            goto exit;
        }

        context->ctx_flags |= GSS_I_APPLICATION_WILL_HANDLE_EXTENSIONS;
    }
    else
    {
        /* unknown option */
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_UNKNOWN_OPTION,
            (NULL));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    *context_handle = context;

 exit:

    GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT;
    return major_status;
}
예제 #8
0
static bool_t
svcauth_gss_accept_sec_context(struct svc_req *rqst,
			       struct rpc_gss_init_res *gr)
{
	struct svc_rpc_gss_data	*gd;
	struct rpc_gss_cred	*gc;
	gss_buffer_desc		 recv_tok, seqbuf;
	gss_OID			 mech;
	OM_uint32		 maj_stat = 0, min_stat = 0, ret_flags, seq;

	log_debug("in svcauth_gss_accept_context()");

	gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
	gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
	memset(gr, 0, sizeof(*gr));

	/* Deserialize arguments. */
	memset(&recv_tok, 0, sizeof(recv_tok));

	if (!svc_getargs(rqst->rq_xprt, xdr_rpc_gss_init_args,
			 (caddr_t)&recv_tok))
		return (FALSE);

	gr->gr_major = gss_accept_sec_context(&gr->gr_minor,
					      &gd->ctx,
					      svcauth_gss_creds,
					      &recv_tok,
					      GSS_C_NO_CHANNEL_BINDINGS,
					      &gd->client_name,
					      &mech,
					      &gr->gr_token,
					      &ret_flags,
					      NULL,
					      NULL);

	svc_freeargs(rqst->rq_xprt, xdr_rpc_gss_init_args, (caddr_t)&recv_tok);

	log_status("accept_sec_context", gr->gr_major, gr->gr_minor);
	if (gr->gr_major != GSS_S_COMPLETE &&
	    gr->gr_major != GSS_S_CONTINUE_NEEDED) {
		badauth(gr->gr_major, gr->gr_minor, rqst->rq_xprt);
		gd->ctx = GSS_C_NO_CONTEXT;
		goto errout;
	}
	gr->gr_ctx.value = "xxxx";
	gr->gr_ctx.length = 4;

	/* gr->gr_win = 0x00000005; ANDROS: for debugging linux kernel version...  */
	gr->gr_win = sizeof(gd->seqmask) * 8;

	/* Save client info. */
	gd->sec.mech = mech;
	gd->sec.qop = GSS_C_QOP_DEFAULT;
	gd->sec.svc = gc->gc_svc;
	gd->seq = gc->gc_seq;
	gd->win = gr->gr_win;

	if (gr->gr_major == GSS_S_COMPLETE) {
#ifdef SPKM
		/* spkm3: no src_name (anonymous) */
		if(!g_OID_equal(gss_mech_spkm3, mech)) {
#endif
		    maj_stat = gss_display_name(&min_stat, gd->client_name,
					    &gd->cname, &gd->sec.mech);
#ifdef SPKM
		}
#endif
		if (maj_stat != GSS_S_COMPLETE) {
			log_status("display_name", maj_stat, min_stat);
			goto errout;
		}
#ifdef DEBUG
#ifdef HAVE_HEIMDAL
		log_debug("accepted context for %.*s with "
			  "<mech {}, qop %d, svc %d>",
			  gd->cname.length, (char *)gd->cname.value,
			  gd->sec.qop, gd->sec.svc);
#else
		{
			gss_buffer_desc mechname;

			gss_oid_to_str(&min_stat, mech, &mechname);

			log_debug("accepted context for %.*s with "
				  "<mech %.*s, qop %d, svc %d>",
				  gd->cname.length, (char *)gd->cname.value,
				  mechname.length, (char *)mechname.value,
				  gd->sec.qop, gd->sec.svc);

			gss_release_buffer(&min_stat, &mechname);
		}
#endif
#endif /* DEBUG */
		seq = htonl(gr->gr_win);
		seqbuf.value = &seq;
		seqbuf.length = sizeof(seq);

		gss_release_buffer(&min_stat, &gd->checksum);
		maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT,
				    &seqbuf, &gd->checksum);

		if (maj_stat != GSS_S_COMPLETE) {
			goto errout;
		}


		rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
		rqst->rq_xprt->xp_verf.oa_base = gd->checksum.value;
		rqst->rq_xprt->xp_verf.oa_length = gd->checksum.length;
	}
	return (TRUE);
errout:
	gss_release_buffer(&min_stat, &gr->gr_token);
	return (FALSE);
}
예제 #9
0
/**
 * @brief Init Sec Context
 * @ingroup globus_gsi_gssapi
 */
OM_uint32 
GSS_CALLCONV gss_init_sec_context(
    OM_uint32 *                         minor_status,
    const gss_cred_id_t                 initiator_cred_handle,
    gss_ctx_id_t *                      context_handle_P,
    const gss_name_t                    target_name,
    const gss_OID                       mech_type,
    OM_uint32                           req_flags,
    OM_uint32                           time_req,
    const gss_channel_bindings_t        input_chan_bindings,
    const gss_buffer_t                  input_token,
    gss_OID *                           actual_mech_type,
    gss_buffer_t                        output_token,
    OM_uint32 *                         ret_flags,
    OM_uint32 *                         time_rec) 
{
    gss_ctx_id_desc *                   context = NULL;
    OM_uint32                           major_status = GSS_S_COMPLETE;
    OM_uint32                           local_minor_status;
    OM_uint32                           local_major_status;
    globus_result_t                     local_result;
    int                                 rc;
    char                                cbuf[1];
    globus_gsi_cert_utils_cert_type_t   cert_type;

    GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER;

    *minor_status = (OM_uint32) GLOBUS_SUCCESS;
    output_token->length = 0;

    context = *context_handle_P;

    /* module activation if not already done by calling
     * globus_module_activate
     */
    
    globus_thread_once(
        &once_control,
        globus_l_gsi_gssapi_activate_once);

    globus_mutex_lock(&globus_i_gssapi_activate_mutex);
    if (!globus_i_gssapi_active)
    {
        globus_module_activate(GLOBUS_GSI_GSSAPI_MODULE);
    }
    globus_mutex_unlock(&globus_i_gssapi_activate_mutex);
    
    if(req_flags & GSS_C_ANON_FLAG &&
       req_flags & GSS_C_DELEG_FLAG)
    {
        major_status = GSS_S_FAILURE;
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Can't initialize a context to be both anonymous and "
             "provide delegation")));
        goto error_exit;
    }

    if(req_flags & GSS_C_GLOBUS_SSL_COMPATIBLE &&
       req_flags & GSS_C_DELEG_FLAG)
    {
        major_status = GSS_S_FAILURE;
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Can't initialize a context to both use SSL compatible "
             "context establishment and provide delegation")));
        goto error_exit;
    }

    if(req_flags & GSS_C_DELEG_FLAG &&
       target_name == GSS_C_NO_NAME)
    {
        major_status = GSS_S_FAILURE;
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Need a target name for authorization prior "
             "to doing delegation")));
        goto error_exit;
    }

    
    if ((context == (gss_ctx_id_t) GSS_C_NO_CONTEXT) ||
        !(context->ctx_flags & GSS_I_CTX_INITIALIZED))
    {
        GLOBUS_I_GSI_GSSAPI_DEBUG_FPRINTF(
            2, (globus_i_gsi_gssapi_debug_fstream, 
                "Creating context w/ %s.\n",
                (initiator_cred_handle == GSS_C_NO_CREDENTIAL) ?
                "GSS_C_NO_CREDENTIAL" :
                "Credentials provided"));

        major_status = 
            globus_i_gsi_gss_create_and_fill_context(&local_minor_status,
                                                     &context,
                                                     initiator_cred_handle,
                                                     GSS_C_INITIATE,
                                                     req_flags);
        if (GSS_ERROR(major_status))
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT);
            goto error_exit;
        }

        *context_handle_P = context;

        if (actual_mech_type != NULL)
        {
            *actual_mech_type = (gss_OID) gss_mech_globus_gssapi_openssl;
        }

        if (ret_flags != NULL)
        {
            *ret_flags = 0 ;
        }
    }
    else
    {
        /* first time there is no input token, but after that
         * there will always be one
         */
    	major_status = globus_i_gsi_gss_put_token(&local_minor_status,
                                                  context, 
                                                  NULL, 
                                                  input_token);
    	if (GSS_ERROR(major_status))
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_TOKEN_FAIL);
            goto error_exit;
        }
    }

    switch (context->gss_state)
    {
    case(GSS_CON_ST_HANDSHAKE):
        
        /* do the handshake work */
        
        major_status = globus_i_gsi_gss_handshake(&local_minor_status,
                                                  context);
        
        if (major_status == GSS_S_CONTINUE_NEEDED)
        {
            break;
        }

        if(GSS_ERROR(major_status))
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_HANDSHAKE);
            context->gss_state = GSS_CON_ST_DONE;
            break;
        }

        /* make sure we are talking to the correct server */
        major_status = globus_i_gsi_gss_retrieve_peer(&local_minor_status,
                                                      context,
                                                      GSS_C_INITIATE);
        if (GSS_ERROR(major_status))
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT);
            context->gss_state = GSS_CON_ST_DONE;
            break;
        }

        local_result = globus_gsi_callback_get_cert_type(
            context->callback_data,
            &cert_type);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_CALLBACK_DATA);
            major_status = GSS_S_FAILURE;
            goto error_exit;
        }

        /* 
         * Need to check if the server is using a limited proxy. 
         * And if that is acceptable here. 
         * Caller tells us if it is not acceptable to 
         * use a limited proxy. 
         */
        if ((context->req_flags & 
             GSS_C_GLOBUS_DONT_ACCEPT_LIMITED_PROXY_FLAG)
            && GLOBUS_GSI_CERT_UTILS_IS_LIMITED_PROXY(cert_type))
        {
            major_status = GSS_S_UNAUTHORIZED;
            GLOBUS_GSI_GSSAPI_ERROR_RESULT(
                minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_PROXY_VIOLATION,
                (_GGSL("Function set to not accept limited proxies")));
            context->gss_state = GSS_CON_ST_DONE;
            break;
        }

        /* this is the mutual authentication test */
        if (target_name != NULL)
        {
            major_status = 
                gss_compare_name(&local_minor_status,
                                 context->peer_cred_handle->globusid,
                                 target_name,
                                 &rc);
            if (GSS_ERROR(major_status))
            {
                GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                    minor_status, local_minor_status,
                    GLOBUS_GSI_GSSAPI_ERROR_BAD_NAME);
                context->gss_state = GSS_CON_ST_DONE;
                break;
            }
            else if(rc == GSS_NAMES_NOT_EQUAL)
            {
                char *                  expected_name;
                char *                  actual_name;
                    
                if(g_OID_equal(((gss_name_desc*)  target_name)->name_oid,
                               GSS_C_NT_HOSTBASED_SERVICE))
                {
                    GLOBUS_GSI_GSSAPI_ERROR_RESULT(
                        minor_status,
                        GLOBUS_GSI_GSSAPI_ERROR_AUTHZ_DENIED,
                        (_GGSL("The expected name for the remote host (%s%s%s) does not match the authenticated "
                               "name of the remote host (%s%s%s). This happens when the name in the host certificate does not match the information obtained from DNS and is often a DNS configuration problem."),
                         target_name->service_name
                            ? target_name->service_name : "",
                         target_name->service_name
                            ? "@" : "",
                         target_name->host_name
                            ? target_name->host_name : "unknown",
                         context->peer_cred_handle->globusid->service_name 
                            ? context->peer_cred_handle->globusid->service_name
                            : "",
                         context->peer_cred_handle->globusid->service_name 
                            ? "@" : "",
                         context->peer_cred_handle->globusid->host_name 
                            ?  context->peer_cred_handle->globusid->host_name 
                            : "unknown"));
                }
                else
                { 
                    expected_name =
                        ((gss_name_desc*)  target_name)->x509n_oneline;
                    actual_name = 
                        ((gss_name_desc*)
                         context->peer_cred_handle->globusid)->x509n_oneline;
                    
                    GLOBUS_GSI_GSSAPI_ERROR_RESULT(
                        minor_status,
                        GLOBUS_GSI_GSSAPI_ERROR_AUTHZ_DENIED,
                        (_GGSL("The name of the remote entity (%s), and the expected "
                               "name for the remote entity (%s) do not match"),
                         actual_name, expected_name));
                }

                major_status = GSS_S_UNAUTHORIZED;
                context->gss_state = GSS_CON_ST_DONE;
                break;
            }
        }
    
        context->ret_flags |= GSS_C_MUTUAL_FLAG;
        context->ret_flags |= GSS_C_PROT_READY_FLAG; 
        context->ret_flags |= GSS_C_INTEG_FLAG
            | GSS_C_REPLAY_FLAG
            | GSS_C_SEQUENCE_FLAG
            | GSS_C_ANON_FLAG
            | GSS_C_DELEG_FLAG;
        if (GLOBUS_GSI_CERT_UTILS_IS_LIMITED_PROXY(cert_type))
        {
            context->ret_flags |= GSS_C_GLOBUS_RECEIVED_LIMITED_PROXY_FLAG;
        }
#       if LINK_WITH_INTERNAL_OPENSSL_API
        context->ret_flags |= GSS_C_TRANS_FLAG;
#       endif

        /* 
         * IF we are talking to a real SSL server,
         * we don't want to do delegation, so we are done
         */

        if (context->req_flags & GSS_C_GLOBUS_SSL_COMPATIBLE)
        {
            context->gss_state = GSS_CON_ST_DONE;
            break;
        }
            
        /*
         * If we have completed the handshake, but don't
         * have any more data to send, we can send the flag
         * now. i.e. fall through without break,
         * Otherwise, we will wait for the null byte
         * to get back in sync which we will ignore
         */

        if (output_token->length != 0)
        {
            context->gss_state=GSS_CON_ST_FLAGS;
            break;
        }

    case(GSS_CON_ST_FLAGS):

        if (input_token->length > 0)
        {   
            BIO_read(context->gss_sslbio, cbuf, 1);
        }

        /* send D if we want delegation, 0 otherwise */
        
        if (context->req_flags & GSS_C_DELEG_FLAG)
        {
            BIO_write(context->gss_sslbio, "D", 1); 
            context->gss_state = GSS_CON_ST_REQ;
        }
        else
        {
            BIO_write(context->gss_sslbio, "0", 1);
            context->gss_state = GSS_CON_ST_DONE;
        } 
        break;
            
    case(GSS_CON_ST_REQ):

        local_result = globus_gsi_proxy_inquire_req(
            context->proxy_handle,
            context->gss_sslbio);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_PROXY_NOT_RECEIVED);
            major_status = GSS_S_FAILURE;
            context->gss_state = GSS_CON_ST_DONE;
            goto error_exit;
        }
        
        local_result = globus_gsi_cred_get_cert_type(
            context->cred_handle->cred_handle,
            &cert_type);
        
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_CREDENTIAL);
            major_status = GSS_S_FAILURE;
            context->gss_state = GSS_CON_ST_DONE;
            goto error_exit;
        }
        
        local_result =
            globus_gsi_proxy_handle_set_type(
                context->proxy_handle,
                (context->req_flags & GSS_C_GLOBUS_DELEGATE_LIMITED_PROXY_FLAG)
                ? GLOBUS_GSI_CERT_UTILS_TYPE_LIMITED_PROXY
                : GLOBUS_GSI_CERT_UTILS_TYPE_IMPERSONATION_PROXY);

        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
            major_status = GSS_S_FAILURE;
            context->gss_state = GSS_CON_ST_DONE;
            goto exit;
        }

        
        local_result = globus_gsi_proxy_sign_req(
            context->proxy_handle,
            context->cred_handle->cred_handle,
            context->gss_sslbio);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
            major_status = GSS_S_FAILURE;
            context->gss_state = GSS_CON_ST_DONE;
            goto error_exit;
        }

        context->gss_state = GSS_CON_ST_DONE;
        break;
            
    case(GSS_CON_ST_CERT): ;
    case(GSS_CON_ST_DONE): ;
    } /* end of switch for gss_con_st */

    local_major_status = globus_i_gsi_gss_get_token(&local_minor_status,
                                                    context, 
                                                    NULL, 
                                                    output_token);

    if(GSS_ERROR(local_major_status))
    {
        GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
            minor_status, local_minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_TOKEN_FAIL);
        major_status = GSS_S_FAILURE;
        context->gss_state = GSS_CON_ST_DONE;
        goto error_exit;
    }

    /* some error occurred during switch */
    if(GSS_ERROR(major_status))
    {
        goto error_exit;
    }

    if (context->gss_state != GSS_CON_ST_DONE)
    {
        major_status |= GSS_S_CONTINUE_NEEDED;
    }
    else if(time_rec != NULL)
    {
        time_t                          lifetime;
        time_t                          current_time;
        
        major_status = globus_i_gsi_gss_get_context_goodtill(
            &local_minor_status,
            context,
            &lifetime);
        if(GSS_ERROR(major_status))
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT);
            goto exit;
        }

        current_time = time(NULL);

        if(current_time > lifetime)
        {
            *time_rec = 0;
        }
        else
        {
            *time_rec = (OM_uint32) (lifetime - current_time);
        }
    }
       
    if (ret_flags != NULL)
    {
        *ret_flags = context->ret_flags;
    }

    GLOBUS_I_GSI_GSSAPI_DEBUG_FPRINTF(
        2, (globus_i_gsi_gssapi_debug_fstream,
            "init_sec_context:major_status:%08x"
            ":gss_state:%d req_flags=%08x:ret_flags=%08x\n",
            (unsigned int) major_status, 
            context->gss_state,
            (unsigned int) req_flags, 
            (unsigned int) context->ret_flags));

    goto exit;

 error_exit:

    gss_delete_sec_context(&local_minor_status, 
                           (gss_ctx_id_t *) &context,
                           output_token);
    *context_handle_P = (gss_ctx_id_t) context;
 
 exit:

    GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT;
    return major_status;
}
예제 #10
0
파일: k5unsealiov.c 프로젝트: WeiY/krb5
static OM_uint32
kg_unseal_v1_iov(krb5_context context,
                 OM_uint32 *minor_status,
                 krb5_gss_ctx_id_rec *ctx,
                 gss_iov_buffer_desc *iov,
                 int iov_count,
                 size_t token_wrapper_len,
                 int *conf_state,
                 gss_qop_t *qop_state,
                 int toktype)
{
    OM_uint32 code;
    gss_iov_buffer_t header;
    gss_iov_buffer_t trailer;
    unsigned char *ptr;
    int sealalg;
    int signalg;
    krb5_checksum cksum;
    krb5_checksum md5cksum;
    size_t cksum_len = 0;
    size_t conflen = 0;
    int direction;
    krb5_ui_4 seqnum;
    OM_uint32 retval;
    size_t sumlen;
    krb5_keyusage sign_usage = KG_USAGE_SIGN;

    md5cksum.length = cksum.length = 0;
    md5cksum.contents = cksum.contents = NULL;

    header = kg_locate_header_iov(iov, iov_count, toktype);
    assert(header != NULL);

    trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
    if (trailer != NULL && trailer->buffer.length != 0) {
        *minor_status = (OM_uint32)KRB5_BAD_MSIZE;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if (header->buffer.length < token_wrapper_len + 14) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    ptr = (unsigned char *)header->buffer.value + token_wrapper_len;

    signalg  = ptr[0];
    signalg |= ptr[1] << 8;

    sealalg  = ptr[2];
    sealalg |= ptr[3] << 8;

    if (ptr[4] != 0xFF || ptr[5] != 0xFF) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if (toktype != KG_TOK_WRAP_MSG && sealalg != 0xFFFF) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if (toktype == KG_TOK_WRAP_MSG &&
        !(sealalg == 0xFFFF || sealalg == ctx->sealalg)) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
        (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
        (ctx->sealalg == SEAL_ALG_DES3KD &&
         signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
        (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
         signalg != SGN_ALG_HMAC_MD5)) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    switch (signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_MD2_5:
    case SGN_ALG_HMAC_MD5:
        cksum_len = 8;
        if (toktype != KG_TOK_WRAP_MSG)
            sign_usage = 15;
        break;
    case SGN_ALG_3:
        cksum_len = 16;
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        cksum_len = 20;
        break;
    default:
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    /* get the token parameters */
    code = kg_get_seq_num(context, ctx->seq, ptr + 14, ptr + 6, &direction,
                          &seqnum);
    if (code != 0) {
        *minor_status = code;
        return GSS_S_BAD_SIG;
    }

    /* decode the message, if SEAL */
    if (toktype == KG_TOK_WRAP_MSG) {
        if (sealalg != 0xFFFF) {
            if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
                unsigned char bigend_seqnum[4];
                krb5_keyblock *enc_key;
                size_t i;

                store_32_be(seqnum, bigend_seqnum);

                code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
                if (code != 0) {
                    retval = GSS_S_FAILURE;
                    goto cleanup;
                }

                assert(enc_key->length == 16);

                for (i = 0; i < enc_key->length; i++)
                    ((char *)enc_key->contents)[i] ^= 0xF0;

                code = kg_arcfour_docrypt_iov(context, enc_key, 0,
                                              &bigend_seqnum[0], 4,
                                              iov, iov_count);
                krb5_free_keyblock(context, enc_key);
            } else {
                code = kg_decrypt_iov(context, 0,
                                      ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
                                      0 /*EC*/, 0 /*RRC*/,
                                      ctx->enc, KG_USAGE_SEAL, NULL,
                                      iov, iov_count);
            }
            if (code != 0) {
                retval = GSS_S_FAILURE;
                goto cleanup;
            }
        }
        conflen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
    }

    if (header->buffer.length != token_wrapper_len + 14 + cksum_len + conflen) {
        retval = GSS_S_DEFECTIVE_TOKEN;
        goto cleanup;
    }

    /* compute the checksum of the message */

    /* initialize the checksum */

    switch (signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_MD2_5:
    case SGN_ALG_DES_MAC:
    case SGN_ALG_3:
        md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
        break;
    case SGN_ALG_HMAC_MD5:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
        break;
    default:
        abort();
    }

    code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
    if (code != 0) {
        retval = GSS_S_FAILURE;
        goto cleanup;
    }
    md5cksum.length = sumlen;

    /* compute the checksum of the message */
    code = kg_make_checksum_iov_v1(context, md5cksum.checksum_type,
                                   cksum_len, ctx->seq, ctx->enc,
                                   sign_usage, iov, iov_count, toktype,
                                   &md5cksum);
    if (code != 0) {
        retval = GSS_S_FAILURE;
        goto cleanup;
    }

    switch (signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_3:
        code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
                                  (g_OID_equal(ctx->mech_used,
                                               gss_mech_krb5_old) ?
                                   ctx->seq->keyblock.contents : NULL),
                                  md5cksum.contents, 16);
        if (code != 0) {
            retval = GSS_S_FAILURE;
            goto cleanup;
        }

        cksum.length = cksum_len;
        cksum.contents = md5cksum.contents + 16 - cksum.length;

        code = k5_bcmp(cksum.contents, ptr + 14, cksum.length);
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
    case SGN_ALG_HMAC_MD5:
        code = k5_bcmp(md5cksum.contents, ptr + 14, cksum_len);
        break;
    default:
        code = 0;
        retval = GSS_S_DEFECTIVE_TOKEN;
        goto cleanup;
        break;
    }

    if (code != 0) {
        code = 0;
        retval = GSS_S_BAD_SIG;
        goto cleanup;
    }

    /*
     * For GSS_C_DCE_STYLE, the caller manages the padding, because the
     * pad length is in the RPC PDU. The value of the padding may be
     * uninitialized. For normal GSS, the last bytes of the decrypted
     * data contain the pad length. kg_fixup_padding_iov() will find
     * this and fixup the last data IOV appropriately.
     */
    if (toktype == KG_TOK_WRAP_MSG &&
        (ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
        retval = kg_fixup_padding_iov(&code, iov, iov_count);
        if (retval != GSS_S_COMPLETE)
            goto cleanup;
    }

    if (conf_state != NULL)
        *conf_state = (sealalg != 0xFFFF);

    if (qop_state != NULL)
        *qop_state = GSS_C_QOP_DEFAULT;

    if ((ctx->initiate && direction != 0xff) ||
        (!ctx->initiate && direction != 0)) {
        *minor_status = (OM_uint32)G_BAD_DIRECTION;
        retval = GSS_S_BAD_SIG;
    }

    code = 0;
    retval = g_order_check(&ctx->seqstate, (gssint_uint64)seqnum);

cleanup:
    krb5_free_checksum_contents(context, &md5cksum);

    *minor_status = code;

    return retval;
}
예제 #11
0
static krb5_error_code
make_seal_token_v1_iov(krb5_context context,
                       krb5_gss_ctx_id_rec *ctx,
                       int conf_req_flag,
                       int *conf_state,
                       gss_iov_buffer_desc *iov,
                       int iov_count,
                       int toktype)
{
    krb5_error_code code = 0;
    gss_iov_buffer_t header;
    gss_iov_buffer_t padding;
    gss_iov_buffer_t trailer;
    krb5_checksum md5cksum;
    krb5_checksum cksum;
    size_t k5_headerlen = 0, k5_trailerlen = 0;
    size_t data_length = 0, assoc_data_length = 0;
    size_t tmsglen = 0, tlen;
    unsigned char *ptr;
    krb5_keyusage sign_usage = KG_USAGE_SIGN;

    assert(toktype == KG_TOK_WRAP_MSG);

    md5cksum.length = cksum.length = 0;
    md5cksum.contents = cksum.contents = NULL;

    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
    if (header == NULL)
        return EINVAL;

    padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
    if (padding == NULL && (ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
        return EINVAL;

    trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
    if (trailer != NULL)
        trailer->buffer.length = 0;

    /* Determine confounder length */
    if (toktype == KG_TOK_WRAP_MSG || conf_req_flag)
        k5_headerlen = kg_confounder_size(context, ctx->enc);

    /* Check padding length */
    if (toktype == KG_TOK_WRAP_MSG) {
        size_t k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;
        size_t gss_padlen;
        size_t conf_data_length;

        kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
        conf_data_length = k5_headerlen + data_length - assoc_data_length;

        if (k5_padlen == 1)
            gss_padlen = 1; /* one byte to indicate one byte of padding */
        else
            gss_padlen = k5_padlen - (conf_data_length % k5_padlen);

        if (ctx->gss_flags & GSS_C_DCE_STYLE) {
            /* DCE will pad the actual data itself; padding buffer optional and will be zeroed */
            gss_padlen = 0;

            if (conf_data_length % k5_padlen)
                code = KRB5_BAD_MSIZE;
        } else if (padding->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
            code = kg_allocate_iov(padding, gss_padlen);
        } else if (padding->buffer.length < gss_padlen) {
            code = KRB5_BAD_MSIZE;
        }
        if (code != 0)
            goto cleanup;

        /* Initialize padding buffer to pad itself */
        if (padding != NULL) {
            padding->buffer.length = gss_padlen;
            memset(padding->buffer.value, (int)gss_padlen, gss_padlen);
        }

        if (ctx->gss_flags & GSS_C_DCE_STYLE)
            tmsglen = k5_headerlen; /* confounder length */
        else
            tmsglen = conf_data_length + padding->buffer.length + assoc_data_length;
    }

    /* Determine token size */
    tlen = g_token_size(ctx->mech_used, 14 + ctx->cksum_size + tmsglen);

    k5_headerlen += tlen - tmsglen;

    if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
        code = kg_allocate_iov(header, k5_headerlen);
    else if (header->buffer.length < k5_headerlen)
        code = KRB5_BAD_MSIZE;
    if (code != 0)
        goto cleanup;

    header->buffer.length = k5_headerlen;

    ptr = (unsigned char *)header->buffer.value;
    g_make_token_header(ctx->mech_used, 14 + ctx->cksum_size + tmsglen, &ptr, toktype);

    /* 0..1 SIGN_ALG */
    store_16_le(ctx->signalg, &ptr[0]);

    /* 2..3 SEAL_ALG or Filler */
    if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
        store_16_le(ctx->sealalg, &ptr[2]);
    } else {
        /* No seal */
        ptr[2] = 0xFF;
        ptr[3] = 0xFF;
    }

    /* 4..5 Filler */
    ptr[4] = 0xFF;
    ptr[5] = 0xFF;

    /* pad the plaintext, encrypt if needed, and stick it in the token */

    /* initialize the checksum */
    switch (ctx->signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_MD2_5:
        md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
        break;
    case SGN_ALG_HMAC_MD5:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
        if (toktype != KG_TOK_WRAP_MSG)
            sign_usage = 15;
        break;
    default:
    case SGN_ALG_DES_MAC:
        abort ();
    }

    code = krb5_c_checksum_length(context, md5cksum.checksum_type, &k5_trailerlen);
    if (code != 0)
        goto cleanup;
    md5cksum.length = k5_trailerlen;

    if (k5_headerlen != 0) {
        code = kg_make_confounder(context, ctx->enc, ptr + 14 + ctx->cksum_size);
        if (code != 0)
            goto cleanup;
    }

    /* compute the checksum */
    code = kg_make_checksum_iov_v1(context, md5cksum.checksum_type,
                                   ctx->cksum_size, ctx->seq, ctx->enc,
                                   sign_usage, iov, iov_count, toktype,
                                   &md5cksum);
    if (code != 0)
        goto cleanup;

    switch (ctx->signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_3:
        code = kg_encrypt(context, ctx->seq, KG_USAGE_SEAL,
                          (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ?
                           ctx->seq->contents : NULL),
                          md5cksum.contents, md5cksum.contents, 16);
        if (code != 0)
            goto cleanup;

        cksum.length = ctx->cksum_size;
        cksum.contents = md5cksum.contents + 16 - cksum.length;

        memcpy(ptr + 14, cksum.contents, cksum.length);
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        assert(md5cksum.length == ctx->cksum_size);
        memcpy(ptr + 14, md5cksum.contents, md5cksum.length);
        break;
    case SGN_ALG_HMAC_MD5:
        memcpy(ptr + 14, md5cksum.contents, ctx->cksum_size);
        break;
    }

    /* create the seq_num */
    code = kg_make_seq_num(context, ctx->seq, ctx->initiate ? 0 : 0xFF,
                           (OM_uint32)ctx->seq_send, ptr + 14, ptr + 6);
    if (code != 0)
        goto cleanup;

    if (conf_req_flag) {
        if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
            unsigned char bigend_seqnum[4];
            krb5_keyblock *enc_key;
            size_t i;

            store_32_be(ctx->seq_send, bigend_seqnum);

            code = krb5_copy_keyblock(context, ctx->enc, &enc_key);
            if (code != 0)
                goto cleanup;

            assert(enc_key->length == 16);

            for (i = 0; i < enc_key->length; i++)
                ((char *)enc_key->contents)[i] ^= 0xF0;

            code = kg_arcfour_docrypt_iov(context, enc_key, 0,
                                          bigend_seqnum, 4,
                                          iov, iov_count);
            krb5_free_keyblock(context, enc_key);
        } else {
            code = kg_encrypt_iov(context, ctx->proto,
                                  ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
                                  0 /*EC*/, 0 /*RRC*/,
                                  ctx->enc, KG_USAGE_SEAL, NULL,
                                  iov, iov_count);
        }
        if (code != 0)
            goto cleanup;
    }

    ctx->seq_send++;
    ctx->seq_send &= 0xFFFFFFFFL;

    code = 0;

    if (conf_state != NULL)
        *conf_state = conf_req_flag;

cleanup:
    if (code != 0)
        kg_release_iov(iov, iov_count);
    krb5_free_checksum_contents(context, &md5cksum);

    return code;
}
예제 #12
0
u32
spkm3_make_token(struct spkm3_ctx *ctx,
		   struct xdr_buf * text, struct xdr_netobj * token,
		   int toktype)
{
	s32			checksum_type;
	char			tokhdrbuf[25];
	char			cksumdata[16];
	struct xdr_netobj	md5cksum = {.len = 0, .data = cksumdata};
	struct xdr_netobj	mic_hdr = {.len = 0, .data = tokhdrbuf};
	int			tokenlen = 0;
	unsigned char		*ptr;
	s32			now;
	int			ctxelen = 0, ctxzbit = 0;
	int			md5elen = 0, md5zbit = 0;

	now = jiffies;

	if (ctx->ctx_id.len != 16) {
		dprintk("RPC:       spkm3_make_token BAD ctx_id.len %d\n",
				ctx->ctx_id.len);
		goto out_err;
	}

	if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) {
		dprintk("RPC:       gss_spkm3_seal: unsupported I-ALG "
				"algorithm.  only support hmac-md5 I-ALG.\n");
		goto out_err;
	} else
		checksum_type = CKSUMTYPE_HMAC_MD5;

	if (!g_OID_equal(&ctx->conf_alg, &cast5_cbc_oid)) {
		dprintk("RPC:       gss_spkm3_seal: unsupported C-ALG "
				"algorithm\n");
		goto out_err;
	}

	if (toktype == SPKM_MIC_TOK) {
		/* Calculate checksum over the mic-header */
		asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit);
		spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data,
				ctxelen, ctxzbit);
		if (make_spkm3_checksum(checksum_type, &ctx->derived_integ_key,
					(char *)mic_hdr.data, mic_hdr.len,
					text, 0, &md5cksum))
			goto out_err;

		asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
		tokenlen = 10 + ctxelen + 1 + md5elen + 1;

		/* Create token header using generic routines */
		token->len = g_token_size(&ctx->mech_used, tokenlen);

		ptr = token->data;
		g_make_token_header(&ctx->mech_used, tokenlen, &ptr);

		spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
	} else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
		dprintk("RPC:       gss_spkm3_seal: SPKM_WRAP_TOK "
				"not supported\n");
		goto out_err;
	}

	/* XXX need to implement sequence numbers, and ctx->expired */

	return  GSS_S_COMPLETE;
out_err:
	token->data = NULL;
	token->len = 0;
	return GSS_S_FAILURE;
}

static int
spkm3_checksummer(struct scatterlist *sg, void *data)
{
	struct hash_desc *desc = data;

	return crypto_hash_update(desc, sg, sg->length);
}

/* checksum the plaintext data and hdrlen bytes of the token header */
s32
make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
		    unsigned int hdrlen, struct xdr_buf *body,
		    unsigned int body_offset, struct xdr_netobj *cksum)
{
	char				*cksumname;
	struct hash_desc		desc; /* XXX add to ctx? */
	struct scatterlist		sg[1];
	int err;

	switch (cksumtype) {
		case CKSUMTYPE_HMAC_MD5:
			cksumname = "hmac(md5)";
			break;
		default:
			dprintk("RPC:       spkm3_make_checksum:"
					" unsupported checksum %d", cksumtype);
			return GSS_S_FAILURE;
	}

	if (key->data == NULL || key->len <= 0) return GSS_S_FAILURE;

	desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC);
	if (IS_ERR(desc.tfm))
		return GSS_S_FAILURE;
	cksum->len = crypto_hash_digestsize(desc.tfm);
	desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;

	err = crypto_hash_setkey(desc.tfm, key->data, key->len);
	if (err)
		goto out;

	err = crypto_hash_init(&desc);
	if (err)
		goto out;

	sg_set_buf(sg, header, hdrlen);
	crypto_hash_update(&desc, sg, sg->length);

	xdr_process_buf(body, body_offset, body->len - body_offset,
			spkm3_checksummer, &desc);
	crypto_hash_final(&desc, cksum->data);

out:
	crypto_free_hash(desc.tfm);

	return err ? GSS_S_FAILURE : 0;
}
/**
 * @brief Initiate Delegation
 * @ingroup globus_gsi_gssapi_extensions_delegation
 * @details
 * This functions drives the initiating side of the credential
 * delegation process. It is expected to be called in tandem with the
 * gss_accept_delegation function.
 *
 * @param minor_status
 *        The minor status returned by this function. This parameter
 *        will be 0 upon success.
 * @param context_handle
 *        The security context over which the credential is
 *        delegated. 
 * @param cred_handle
 *        The credential to be delegated. May be GSS_C_NO_CREDENTIAL
 *        in which case the credential associated with the security
 *        context is used.
 * @param desired_mech
 *        The desired security mechanism. Currently not used. May be
 *        GSS_C_NO_OID. 
 * @param extension_oids
 *        A set of extension OIDs corresponding to buffers in the
 *        extension_buffers parameter below. The extensions specified
 *        will be added to the delegated credential. May be
 *        GSS_C_NO_BUFFER_SET. 
 * @param extension_buffers
 *        A set of extension buffers corresponding to OIDs in the
 *        extension_oids parameter above. May be
 *        GSS_C_NO_BUFFER_SET.
 * @param input_token
 *        The token that was produced by a prior call to
 *        gss_accept_delegation. This parameter will be ignored the
 *        first time this function is called.
 * @param req_flags
 *        Flags that modify the behavior of the function. Currently
 *        only GSS_C_GLOBUS_SSL_COMPATIBLE and
 *        GSS_C_GLOBUS_LIMITED_DELEG_PROXY_FLAG are checked for. The
 *        GSS_C_GLOBUS_SSL_COMPATIBLE  flag results in tokens that
 *        aren't wrapped and GSS_C_GLOBUS_LIMITED_DELEG_PROXY_FLAG
 *        causes the delegated proxy to be limited (requires that no
 *        extensions are specified.
 *        
 * @param time_req
 *        The requested period of validity (seconds) of the delegated
 *        credential. Passing a time_req of 0 cause the delegated credential to
 *        have the same lifetime as the credential that issued it. 
 * @param output_token
 *        A token that should be passed to gss_accept_delegation if the
 *        return value is GSS_S_CONTINUE_NEEDED.
 * @retval GSS_S_COMPLETE Success
 * @retval GSS_S_CONTINUE_NEEDED This function needs to be called again.
 * @retval GSS_S_FAILURE upon failure
 */
OM_uint32
GSS_CALLCONV gss_init_delegation(
    OM_uint32 *                         minor_status,
    const gss_ctx_id_t                  context_handle,
    const gss_cred_id_t                 cred_handle,
    const gss_OID                       desired_mech,
    const gss_OID_set                   extension_oids,
    const gss_buffer_set_t              extension_buffers,
    const gss_buffer_t                  input_token,
    OM_uint32                           req_flags,
    OM_uint32                           time_req,
    gss_buffer_t                        output_token)
{
    BIO *                               bio = NULL;
    BIO *                               read_bio = NULL;
    BIO *                               write_bio = NULL;
    OM_uint32                           major_status = GSS_S_COMPLETE;
    OM_uint32                           local_minor_status;
    gss_ctx_id_desc *                   context;
    gss_cred_id_desc *                  cred;
    X509 *                              cert = NULL;
    STACK_OF(X509) *                    cert_chain = NULL;
    PROXYCERTINFO *                     pci;
    globus_gsi_cert_utils_cert_type_t   cert_type;
    int                                 index;
    globus_result_t                     local_result = GLOBUS_SUCCESS;
    static char *                       _function_name_ =
        "init_delegation";
    GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER;
    
    if(minor_status == NULL)
    {
        major_status = GSS_S_FAILURE;
        goto exit;
    }
    
    *minor_status = (OM_uint32) GLOBUS_SUCCESS;

    if(context_handle == GSS_C_NO_CONTEXT)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Invalid context_handle passed to function")));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    context = (gss_ctx_id_desc *) context_handle;

    cred = (gss_cred_id_desc *) cred_handle;

    if (cred_handle == GSS_C_NO_CREDENTIAL)
    {
        cred = (gss_cred_id_desc *) context->cred_handle;
    }

    if(cred == GSS_C_NO_CREDENTIAL)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Couldn't initialize delegation credential handle")));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    if(desired_mech != GSS_C_NO_OID &&
       desired_mech != (gss_OID) gss_mech_globus_gssapi_openssl)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Invalid desired_mech passed to function")));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    if(extension_oids != GSS_C_NO_OID_SET &&
       (extension_buffers == GSS_C_NO_BUFFER_SET ||
        extension_oids->count != extension_buffers->count))
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Invalid extension parameters passed to function")));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    if(output_token == GSS_C_NO_BUFFER)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Invalid output_token passed to function")));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    output_token->length = 0;

    if(req_flags & GSS_C_GLOBUS_SSL_COMPATIBLE)
    {
        bio = BIO_new(BIO_s_mem());
        read_bio = bio;
        write_bio = bio;
    }
    else
    {
        bio = context->gss_sslbio;
    }

    /* lock the context mutex */
    globus_mutex_lock(&context->mutex);
    
    /* pass the input to the BIO */
    if(context->delegation_state != GSS_DELEGATION_START)
    {
        /*
         * first time there is no input token, but after that
         * there will always be one
         */
        if(input_token == GSS_C_NO_BUFFER)
        {
            GLOBUS_GSI_GSSAPI_ERROR_RESULT(
                minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
                (_GGSL("Invalid input_token passed to function: "
                 "delegation is not at initial state")));
            major_status = GSS_S_FAILURE;
            goto mutex_unlock;
        }

        major_status = 
            globus_i_gsi_gss_put_token(&local_minor_status,
                                       context, 
                                       read_bio, 
                                       input_token);

        if (GSS_ERROR(major_status))
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_TOKEN_FAIL);
            goto mutex_unlock;
        }
    }

    
    /* delegation state machine */
    
    switch (context->delegation_state)
    {

    case GSS_DELEGATION_START:

        /* start delegation by sending a "D" */
        BIO_write(bio, "D", 1); 
        context->delegation_state = GSS_DELEGATION_SIGN_CERT;
        break;

    case GSS_DELEGATION_SIGN_CERT:

        /* get the returned cert from the ssl BIO, make sure it is
         * correct and then sign it and place it in the output_token
         */
        local_result = globus_gsi_proxy_inquire_req(context->proxy_handle,
                                                    bio);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
            major_status = GSS_S_FAILURE;
            goto mutex_unlock;
        }

        local_result = globus_gsi_cred_get_cert_type(
            context->cred_handle->cred_handle,
            &cert_type);

        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_CREDENTIAL);
            major_status = GSS_S_FAILURE;
            context->delegation_state = GSS_DELEGATION_DONE;
            goto mutex_unlock;
        }
        /* set the requested time */

        if(time_req != 0)
        {
            if(time_req%60)
            {
                /* round up */
                time_req += 60;
            }
            
            local_result = globus_gsi_proxy_handle_set_time_valid(
                context->proxy_handle,
                time_req/60);

            if(local_result != GLOBUS_SUCCESS)
            {
                GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                    minor_status, local_result,
                    GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
                major_status = GSS_S_FAILURE;
                context->delegation_state = GSS_DELEGATION_DONE;
                goto mutex_unlock;            
            }
        }
        
        /* clear the proxycertinfo */
        
        local_result =
            globus_gsi_proxy_handle_clear_cert_info(context->proxy_handle);
        
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
            major_status = GSS_S_FAILURE;
            context->delegation_state = GSS_DELEGATION_DONE;
            goto mutex_unlock;            
        }
        

        if(cert_type == GLOBUS_GSI_CERT_UTILS_TYPE_CA)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_CREDENTIAL);
            major_status = GSS_S_FAILURE;
            context->delegation_state = GSS_DELEGATION_DONE;
            goto mutex_unlock;            
        }
        
        local_result =
            globus_gsi_proxy_handle_set_type(
                context->proxy_handle,
                (req_flags & GSS_C_GLOBUS_DELEGATE_LIMITED_PROXY_FLAG)
                ? GLOBUS_GSI_CERT_UTILS_TYPE_LIMITED_PROXY 
                : GLOBUS_GSI_CERT_UTILS_TYPE_IMPERSONATION_PROXY);
        
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
            major_status = GSS_S_FAILURE;
            context->delegation_state = GSS_DELEGATION_DONE;
            goto mutex_unlock;            
        }    

        /* set the proxycertinfo here */
        if(extension_oids != GSS_C_NO_OID_SET)
        {
            if(GLOBUS_GSI_CERT_UTILS_IS_GSI_2_PROXY(cert_type))
            {
                GLOBUS_GSI_GSSAPI_ERROR_RESULT(
                    minor_status,
                    GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
                    (_GGSL("A restricted globus proxy may not be created "
                     "from a legacy globus proxy")));
                context->delegation_state = GSS_DELEGATION_DONE;
                major_status = GSS_S_FAILURE;
                goto mutex_unlock;
            }
            
            for(index = 0; index < extension_oids->count; index++)
            {
                if(g_OID_equal((gss_OID) &extension_oids->elements[index],
                               gss_proxycertinfo_extension))
                {
                    pci = extension_buffers->elements[index].value;

                    local_result =
                        globus_gsi_proxy_handle_set_proxy_cert_info(
                            context->proxy_handle,
                            pci);
                    if(local_result != GLOBUS_SUCCESS)
                    {
                        GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                            minor_status, local_result,
                            GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
                        major_status = GSS_S_FAILURE;
                        context->delegation_state = GSS_DELEGATION_DONE;
                        goto mutex_unlock;
                    }
                }
            }
        }

        local_result = globus_gsi_proxy_sign_req(
            context->proxy_handle,
            cred->cred_handle,
            bio);
        
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
            major_status = GSS_S_FAILURE;
            context->delegation_state = GSS_DELEGATION_DONE;
            goto mutex_unlock;
        }

        local_result = globus_gsi_cred_get_cert(cred->cred_handle, &cert);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_CREDENTIAL);
            major_status = GSS_S_FAILURE;
            context->delegation_state = GSS_DELEGATION_DONE;
            goto mutex_unlock;
        }
                
        /* push the cert used to sign the proxy */
        i2d_X509_bio(bio, cert);
        X509_free(cert);
        
        /* push the number of certs in the cert chain */
        local_result = globus_gsi_cred_get_cert_chain(cred->cred_handle,
                                                      &cert_chain);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_CREDENTIAL);
            major_status = GSS_S_FAILURE;
            context->delegation_state = GSS_DELEGATION_DONE;
            goto mutex_unlock;
        }

        for(index = 0; index < sk_X509_num(cert_chain); index++)
        {
            cert = sk_X509_value(cert_chain, index);
            if(!cert)
            {
                GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT(
                    minor_status,
                    GLOBUS_GSI_GSSAPI_ERROR_WITH_OPENSSL,
                    (_GGSL("Couldn't get cert from cert chain")));
                major_status = GSS_S_FAILURE;
                context->delegation_state = GSS_DELEGATION_DONE;
                goto mutex_unlock;
            }
            
            i2d_X509_bio(bio, cert);
        }
        sk_X509_pop_free(cert_chain, X509_free);

        /* reset state machine */
        context->delegation_state = GSS_DELEGATION_START; 
        break;

    case GSS_DELEGATION_COMPLETE_CRED:
    case GSS_DELEGATION_DONE:
        break;
    }
    
    major_status = globus_i_gsi_gss_get_token(&local_minor_status,
                                              context, 
                                              write_bio, 
                                              output_token);
    if(GSS_ERROR(major_status))
    {
        GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
            minor_status, local_minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_TOKEN_FAIL);
        goto mutex_unlock;
    }

    if (context->delegation_state != GSS_DELEGATION_START)
    {
        major_status |= GSS_S_CONTINUE_NEEDED;
    }

 mutex_unlock:
    globus_mutex_unlock(&context->mutex);

 exit:

    if(req_flags & GSS_C_GLOBUS_SSL_COMPATIBLE)
    {
        BIO_free(bio);
    }
        
    GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT;
    return major_status;
}
/* V2 KRB5_CALLCONV */
OM_uint32 KRB5_CALLCONV
gss_add_cred_impersonate_name(OM_uint32 *minor_status,
			      gss_cred_id_t input_cred_handle,
			      const gss_cred_id_t impersonator_cred_handle,
			      const gss_name_t desired_name,
			      const 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)
{
    OM_uint32		status, temp_minor_status;
    OM_uint32		time_req, time_rec;
    gss_union_name_t	union_name;
    gss_union_cred_t	new_union_cred, union_cred;
    gss_cred_id_t	mech_impersonator_cred;
    gss_name_t		internal_name = GSS_C_NO_NAME;
    gss_name_t		allocated_name = GSS_C_NO_NAME;
    gss_mechanism	mech;
    gss_cred_id_t	cred = NULL;
    gss_OID		new_mechs_array = NULL;
    gss_cred_id_t *	new_cred_array = NULL;

    status = val_add_cred_impersonate_name_args(minor_status,
						input_cred_handle,
						impersonator_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);
    if (status != GSS_S_COMPLETE)
	return (status);

    mech = gssint_get_mechanism(desired_mech);
    if (!mech)
	return GSS_S_BAD_MECH;
    else if (!mech->gss_acquire_cred)
	return (GSS_S_UNAVAILABLE);

    if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
	union_cred = malloc(sizeof (gss_union_cred_desc));
	if (union_cred == NULL)
	    return (GSS_S_FAILURE);

	(void) memset(union_cred, 0, sizeof (gss_union_cred_desc));

	/* for default credentials we will use GSS_C_NO_NAME */
	internal_name = GSS_C_NO_NAME;
    } else {
	union_cred = (gss_union_cred_t)input_cred_handle;
	if (gssint_get_mechanism_cred(union_cred, desired_mech) !=
	    GSS_C_NO_CREDENTIAL)
	    return (GSS_S_DUPLICATE_ELEMENT);
    }

    mech_impersonator_cred =
	gssint_get_mechanism_cred((gss_union_cred_t)impersonator_cred_handle,
				  desired_mech);
    if (mech_impersonator_cred == GSS_C_NO_CREDENTIAL)
	return (GSS_S_NO_CRED);

    /* may need to create a mechanism specific name */
    union_name = (gss_union_name_t)desired_name;
    if (union_name->mech_type &&
	g_OID_equal(union_name->mech_type,
		    &mech->mech_type))
	internal_name = union_name->mech_name;
    else {
	if (gssint_import_internal_name(minor_status,
				        &mech->mech_type, union_name,
				        &allocated_name) != GSS_S_COMPLETE)
	    return (GSS_S_BAD_NAME);
	internal_name = allocated_name;
    }

    if (cred_usage == GSS_C_ACCEPT)
	time_req = acceptor_time_req;
    else if (cred_usage == GSS_C_INITIATE)
	time_req = initiator_time_req;
    else if (cred_usage == GSS_C_BOTH)
	time_req = (acceptor_time_req > initiator_time_req) ?
	    acceptor_time_req : initiator_time_req;
    else
	time_req = 0;

    status = mech->gss_acquire_cred_impersonate_name(minor_status,
						     mech_impersonator_cred,
						     internal_name,
						     time_req,
						     GSS_C_NULL_OID_SET,
						     cred_usage,
						     &cred,
						     NULL,
						     &time_rec);
    if (status != GSS_S_COMPLETE) {
	map_error(minor_status, mech);
	goto errout;
    }

    /* may need to set credential auxinfo strucutre */
    if (union_cred->auxinfo.creation_time == 0) {
	union_cred->auxinfo.creation_time = time(NULL);
	union_cred->auxinfo.time_rec = time_rec;
	union_cred->auxinfo.cred_usage = cred_usage;

	/*
	 * we must set the name; if name is not supplied
	 * we must do inquire cred to get it
	 */
	if (internal_name == NULL) {
	    if (mech->gss_inquire_cred == NULL ||
		((status = mech->gss_inquire_cred(
		      &temp_minor_status, cred,
		      &allocated_name, NULL, NULL,
		      NULL)) != GSS_S_COMPLETE))
		goto errout;
	    internal_name = allocated_name;
	}

	if (internal_name != GSS_C_NO_NAME) {
	    status = mech->gss_display_name(&temp_minor_status, internal_name,
					    &union_cred->auxinfo.name,
					    &union_cred->auxinfo.name_type);

	    if (status != GSS_S_COMPLETE)
		goto errout;
	}
    }

    /* now add the new credential elements */
    new_mechs_array = (gss_OID)
	malloc(sizeof (gss_OID_desc) * (union_cred->count+1));

    new_cred_array = (gss_cred_id_t *)
	malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));

    if (!new_mechs_array || !new_cred_array) {
	status = GSS_S_FAILURE;
	goto errout;
    }

    if (acceptor_time_rec)
	if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
	    *acceptor_time_rec = time_rec;
    if (initiator_time_rec)
	if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
	    *initiator_time_rec = time_rec;

    /*
     * OK, expand the mechanism array and the credential array
     */
    (void) memcpy(new_mechs_array, union_cred->mechs_array,
		  sizeof (gss_OID_desc) * union_cred->count);
    (void) memcpy(new_cred_array, union_cred->cred_array,
		  sizeof (gss_cred_id_t) * union_cred->count);

    new_cred_array[union_cred->count] = cred;
    if ((new_mechs_array[union_cred->count].elements =
	 malloc(mech->mech_type.length)) == NULL)
	goto errout;

    g_OID_copy(&new_mechs_array[union_cred->count],
	       &mech->mech_type);

    if (actual_mechs != NULL) {
	gss_OID_set_desc oids;

	oids.count = union_cred->count + 1;
	oids.elements = new_mechs_array;

	status = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
	if (GSS_ERROR(status)) {
	    free(new_mechs_array[union_cred->count].elements);
	    goto errout;
	}
    }

    if (output_cred_handle == NULL) {
	free(union_cred->mechs_array);
	free(union_cred->cred_array);
	new_union_cred = union_cred;
    } else {
	new_union_cred = malloc(sizeof (gss_union_cred_desc));
	if (new_union_cred == NULL) {
	    free(new_mechs_array[union_cred->count].elements);
	    goto errout;
	}
	*new_union_cred = *union_cred;
	*output_cred_handle = (gss_cred_id_t)new_union_cred;
    }

    new_union_cred->mechs_array = new_mechs_array;
    new_union_cred->cred_array = new_cred_array;
    new_union_cred->count++;
    new_union_cred->loopback = new_union_cred;

    /* We're done with the internal name. Free it if we allocated it. */

    if (allocated_name)
	(void) gssint_release_internal_name(&temp_minor_status,
					   &mech->mech_type,
					   &allocated_name);

    return (GSS_S_COMPLETE);

errout:
    if (new_mechs_array)
	free(new_mechs_array);
    if (new_cred_array)
	free(new_cred_array);

    if (cred != NULL && mech->gss_release_cred)
	mech->gss_release_cred(&temp_minor_status, &cred);

    if (allocated_name)
	(void) gssint_release_internal_name(&temp_minor_status,
					   &mech->mech_type,
					   &allocated_name);

    if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
	if (union_cred->auxinfo.name.value)
	    free(union_cred->auxinfo.name.value);
	free(union_cred);
    }

    return (status);
}
예제 #15
0
OM_uint32 KRB5_CALLCONV
gss_display_name_ext (OM_uint32 *minor_status,
                      gss_name_t input_name,
                      gss_OID display_as_name_type,
                      gss_buffer_t output_name_buffer)
{
    OM_uint32                status;
    gss_union_name_t        union_name;
    gss_mechanism        mech;

    status = val_dsp_name_ext_args(minor_status,
                                   input_name,
                                   display_as_name_type,
                                   output_name_buffer);
    if (status != GSS_S_COMPLETE)
        return status;

    union_name = (gss_union_name_t) input_name;

    if (union_name->mech_type) {
        mech = gssint_get_mechanism(union_name->mech_type);
        if (mech == NULL)
            status = GSS_S_BAD_NAME;
        else if (mech->gss_display_name_ext == NULL) {
            if (mech->gss_display_name != NULL &&
                union_name->name_type != GSS_C_NO_OID &&
                g_OID_equal(display_as_name_type, union_name->name_type)) {
                status = (*mech->gss_display_name)(minor_status,
                                                   union_name->mech_name,
                                                   output_name_buffer,
                                                   NULL);
                if (status != GSS_S_COMPLETE)
                    map_error(minor_status, mech);
            } else
                status = GSS_S_UNAVAILABLE;
        } else {
            status = (*mech->gss_display_name_ext)(minor_status,
                                                   union_name->mech_name,
                                                   display_as_name_type,
                                                   output_name_buffer);
            if (status != GSS_S_COMPLETE)
                map_error(minor_status, mech);
        }
        return status;
    }

    if (union_name->name_type == GSS_C_NO_OID ||
        !g_OID_equal(display_as_name_type, union_name->name_type))
        return GSS_S_UNAVAILABLE;

    if ((output_name_buffer->value =
         malloc(union_name->external_name->length + 1)) == NULL) {
        return GSS_S_FAILURE;
    }
    output_name_buffer->length = union_name->external_name->length;
    (void) memcpy(output_name_buffer->value,
                  union_name->external_name->value,
                  union_name->external_name->length);
    ((char *)output_name_buffer->value)[output_name_buffer->length] = '\0';

    return GSS_S_COMPLETE;
}
예제 #16
0
static bool_t
Svcauth_gss_accept_sec_context(struct svc_req *rqst, struct rpc_gss_init_res *gr)
{
  struct svc_rpc_gss_data *gd;
  struct rpc_gss_cred *gc;
  gss_buffer_desc recv_tok, seqbuf;
  gss_OID mech;
  OM_uint32 maj_stat = 0, min_stat = 0, ret_flags, seq;

  gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
  gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
  memset(gr, 0, sizeof(*gr));

  /* Deserialize arguments. */
  memset(&recv_tok, 0, sizeof(recv_tok));

  if(!svc_getargs(rqst->rq_xprt, (xdrproc_t)xdr_rpc_gss_init_args, (caddr_t) & recv_tok))
    return (FALSE);

  gr->gr_major = gss_accept_sec_context(&gr->gr_minor,
                                        &gd->ctx,
                                        svcauth_gss_creds,
                                        &recv_tok,
                                        GSS_C_NO_CHANNEL_BINDINGS,
                                        &gd->client_name,
                                        &mech, &gr->gr_token, &ret_flags, NULL, NULL);

  svc_freeargs(rqst->rq_xprt, (xdrproc_t)xdr_rpc_gss_init_args, (caddr_t) & recv_tok);

  if(gr->gr_major != GSS_S_COMPLETE && gr->gr_major != GSS_S_CONTINUE_NEEDED)
    {
      sockaddr_t addr;
      char ipstring[SOCK_NAME_MAX];
      copy_xprt_addr(&addr, rqst->rq_xprt);
      sprint_sockaddr(&addr, ipstring, sizeof(ipstring));

      LogWarn(COMPONENT_RPCSEC_GSS,
              "Bad authentication major=%u minor=%u addr=%s",
              gr->gr_major, gr->gr_minor, ipstring);
      gd->ctx = GSS_C_NO_CONTEXT;
      goto errout;
    }
  /*
   * ANDROS: krb5 mechglue returns ctx of size 8 - two pointers,
   * one to the mechanism oid, one to the internal_ctx_id
   */
  if((gr->gr_ctx.value = Mem_Alloc(sizeof(gss_union_ctx_id_desc))) == NULL)
    {
      LogCrit(COMPONENT_RPCSEC_GSS,
              "svcauth_gss_accept_context: out of memory");
      goto errout;
    }
  memcpy(gr->gr_ctx.value, gd->ctx, sizeof(gss_union_ctx_id_desc));
  gr->gr_ctx.length = sizeof(gss_union_ctx_id_desc);

  /* gr->gr_win = 0x00000005; ANDROS: for debugging linux kernel version...  */
  gr->gr_win = sizeof(gd->seqmask) * 8;

  /* Save client info. */
  gd->sec.mech = mech;
  gd->sec.qop = GSS_C_QOP_DEFAULT;
  gd->sec.svc = gc->gc_svc;
  gd->seq = gc->gc_seq;
  gd->win = gr->gr_win;

  if(gr->gr_major == GSS_S_COMPLETE)
    {
#ifdef SPKM
      /* spkm3: no src_name (anonymous) */
      if(!g_OID_equal(gss_mech_spkm3, mech))
        {
#endif
          maj_stat = gss_display_name(&min_stat, gd->client_name,
                                      &gd->cname, &gd->sec.mech);
	  LogFullDebug(COMPONENT_RPCSEC_GSS,
	               "cname.val: %s  cname.len: %d",
	               (char *)gd->cname.value, (int)gd->cname.length);
#ifdef SPKM
        }
#endif
      if(maj_stat != GSS_S_COMPLETE)
        {
        }
#ifdef HAVE_HEIMDAL
#else
      if(isFullDebug(COMPONENT_RPCSEC_GSS))
        {
          gss_buffer_desc mechname;

          gss_oid_to_str(&min_stat, mech, &mechname);

          gss_release_buffer(&min_stat, &mechname);
        }
#endif
      seq = htonl(gr->gr_win);
      seqbuf.value = &seq;
      seqbuf.length = sizeof(seq);

      gss_release_buffer(&min_stat, &gd->checksum);
      LogFullDebug(COMPONENT_RPCSEC_GSS,
                   "gss_sign in sec_accept_context");
      maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT, &seqbuf, &gd->checksum);

      if(maj_stat != GSS_S_COMPLETE)
        {
          goto errout;
        }

      rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
      rqst->rq_xprt->xp_verf.oa_base = gd->checksum.value;
      rqst->rq_xprt->xp_verf.oa_length = gd->checksum.length;
    }
  return (TRUE);
 errout:
  gss_release_buffer(&min_stat, &gr->gr_token);
  return (FALSE);
}
예제 #17
0
OM_uint32 KRB5_CALLCONV
gss_localname(OM_uint32 *minor,
              const gss_name_t pname,
              gss_const_OID mech_type,
              gss_buffer_t localname)
{
    OM_uint32 major, tmpMinor;
    gss_mechanism mech;
    gss_union_name_t unionName;
    gss_name_t mechName = GSS_C_NO_NAME, mechNameP;
    gss_OID selected_mech = GSS_C_NO_OID;

    if (localname != GSS_C_NO_BUFFER) {
	localname->length = 0;
	localname->value = NULL;
    }

    if (minor == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;

    *minor = 0;

    if (pname == GSS_C_NO_NAME)
        return GSS_S_CALL_INACCESSIBLE_READ;

    if (localname == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;

    unionName = (gss_union_name_t)pname;

    if (mech_type != GSS_C_NO_OID) {
        major = gssint_select_mech_type(minor, mech_type, &selected_mech);
        if (major != GSS_S_COMPLETE)
	    return major;
        mech = gssint_get_mechanism(selected_mech);
    } else
        mech = gssint_get_mechanism(unionName->mech_type);

    if (mech == NULL)
	return GSS_S_UNAVAILABLE;

    /* may need to create a mechanism specific name */
    if (unionName->mech_type == GSS_C_NO_OID ||
        (unionName->mech_type != GSS_C_NO_OID &&
         !g_OID_equal(unionName->mech_type, &mech->mech_type))) {
        major = gssint_import_internal_name(minor, &mech->mech_type,
                                            unionName, &mechName);
        if (GSS_ERROR(major))
            return major;

        mechNameP = mechName;
    } else
        mechNameP = unionName->mech_name;

    major = GSS_S_UNAVAILABLE;

    if (mech->gss_localname != NULL) {
        major = mech->gss_localname(minor, mechNameP, mech_type, localname);
        if (GSS_ERROR(major))
            map_error(minor, mech);
    }

    if (GSS_ERROR(major))
        major = attr_localname(minor, mech, mechNameP, localname);

    if (mechName != GSS_C_NO_NAME)
        gssint_release_internal_name(&tmpMinor, &mech->mech_type, &mechName);

    return major;
}
예제 #18
0
OM_uint32
gss_pname_to_uid(OM_uint32 *minor,
                 const gss_name_t pname,
                 const gss_OID mech_type,
                 uid_t *uidp)
{
    OM_uint32 major, tmpMinor;
    gss_mechanism mech;
    gss_union_name_t unionName;
    gss_name_t mechName = GSS_C_NO_NAME, mechNameP;

    /*
     * find the appropriate mechanism specific pname_to_uid procedure and
     * call it.
     */
    if (minor == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;

    *minor = 0;

    if (pname == GSS_C_NO_NAME)
        return GSS_S_CALL_INACCESSIBLE_READ;

    if (uidp == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;

    unionName = (gss_union_name_t)pname;

    if (mech_type != GSS_C_NO_OID)
        mech = gssint_get_mechanism(mech_type);
    else
        mech = gssint_get_mechanism(unionName->mech_type);

    if (mech == NULL)
	return GSS_S_UNAVAILABLE;

    /* may need to create a mechanism specific name */
    if (unionName->mech_type == GSS_C_NO_OID ||
        (unionName->mech_type != GSS_C_NO_OID &&
         !g_OID_equal(unionName->mech_type, &mech->mech_type))) {
        major = gssint_import_internal_name(minor, &mech->mech_type,
                                            unionName, &mechName);
        if (GSS_ERROR(major))
            return major;

        mechNameP = mechName;
    } else
        mechNameP = unionName->mech_name;

    major = GSS_S_UNAVAILABLE;

    if (mech->gss_pname_to_uid != NULL) {
        major = mech->gss_pname_to_uid(minor, mechNameP, mech_type, uidp);
        if (GSS_ERROR(major))
            map_error(minor, mech);
    }

    if (GSS_ERROR(major))
        major = attr_pname_to_uid(minor, mech, mechNameP, uidp);

    if (mechName != GSS_C_NO_NAME)
        gssint_release_internal_name(&tmpMinor, &mech->mech_type, &mechName);

    return major;
}
OM_uint32 GSS_CALLCONV gss_inquire_names_for_mech(
    OM_uint32 *                         minor_status,
    const gss_OID                       mechanism,
    gss_OID_set *                       name_types )
{
    static char *                       _function_name_ = "gss_inquire_names_for_mech";
    OM_uint32                           major_status;
    int                                 i;
    gss_OID                             oids[] = {
        GSS_C_NT_HOSTBASED_SERVICE,
        GSS_C_NT_ANONYMOUS,
        GSS_C_NT_EXPORT_NAME,
        (gss_OID) gss_nt_host_ip,
        (gss_OID) gss_nt_x509,
        NULL
    };

    if (minor_status == NULL || mechanism == NULL || name_types == NULL)
    {
        if (minor_status != NULL)
        {
            GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT(
                        minor_status,
                        GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
                        (_GGSL("Invalid parameter")));
        }

        major_status = GSS_S_FAILURE;

        goto out;
    }

    if (! g_OID_equal(mechanism, gss_mech_globus_gssapi_openssl))
    {
        GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT(
                    minor_status,
                    GLOBUS_GSI_GSSAPI_ERROR_BAD_MECH,
                    (_GGSL("Requested mechanism not supported")));
        major_status = GSS_S_BAD_MECH;

        goto out;
    }

    major_status = gss_create_empty_oid_set(minor_status, name_types);
    if (major_status != GSS_S_COMPLETE)
    {
        goto out;
    }

    for (i = 0; oids[i] != NULL; i++)
    {
        major_status = gss_add_oid_set_member(
            minor_status,
            oids[i],
            name_types);
        if (major_status != GSS_S_COMPLETE)
        {
            goto free_oids;
        }
    }

free_oids:
    if (major_status != GSS_S_COMPLETE)
    {
        OM_uint32                       local_major;
        OM_uint32                       local_minor;

        local_major = gss_release_oid_set(
            &local_minor,
            name_types);
    }

out:
    return major_status;
}
예제 #20
0
/**
 * @brief Export a GSSAPI credential
 * @ingroup globus_gsi_gssapi_extensions
 * @details
 * Saves the credential so it can be checkpointed and 
 * imported by gss_import_cred
 *
 * @param minor_status
 * @param cred_handle
 * @param desired_mech
 *        Should either be gss_mech_globus_gssapi_openssl or
 *        NULL (in which case gss_mech_globus_gssapi_openssl is
 *        assumed).
 * @param option_req
 * @param export_buffer
 *
 * @return
 */
OM_uint32 
GSS_CALLCONV gss_export_cred(
    OM_uint32 *                         minor_status,
    const gss_cred_id_t                 cred_handle,
    const gss_OID                       desired_mech,
    OM_uint32                           option_req,
    gss_buffer_t                        export_buffer)
{
    OM_uint32                           major_status = GLOBUS_SUCCESS;
    BIO *                               bp = NULL;
    gss_cred_id_desc *                  cred_desc = NULL;
    globus_result_t                     local_result;
    char *                              proxy_filename = NULL;

    GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER;

    cred_desc = (gss_cred_id_desc *) cred_handle;
    
    *minor_status = (OM_uint32) GLOBUS_SUCCESS;

    if (export_buffer == NULL ||
        export_buffer == GSS_C_NO_BUFFER)
    {
        major_status = GSS_S_FAILURE;
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("NULL or empty export_buffer parameter passed to function: %s"),
             __func__));
        goto exit;
    }

    export_buffer->length = 0;
    export_buffer->value = NULL;

    if (cred_handle == NULL)
    { 
        major_status = GSS_S_FAILURE;
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("NULL or empty export_buffer parameter passed to function: %s"),
             __func__));
        goto exit;
    }

    if(desired_mech != NULL &&
       g_OID_equal(desired_mech, (gss_OID) gss_mech_globus_gssapi_openssl))
    {
        major_status = GSS_S_BAD_MECH;
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_MECH,
            (_GGSL("The desired mechanism of: %s, is not supported by this "
             "GSS implementation"), desired_mech->elements));
        goto exit;
    }

    if(option_req == GSS_IMPEXP_OPAQUE_FORM)
    {
        /* When option_req is equal to EXPORT_OPAQUE_FORM (0), it exports
         * an opaque buffer suitable for storage in memory or on  
         * disk or passing to another process, which 
         * can import the buffer with gss_import_cred().
         */
        bp = BIO_new(BIO_s_mem());
        if(bp == NULL)
        {
            GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT(
                minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_OPENSSL,
                (_GGSL("Couldn't initialize IO bio for exporting credential")));
            major_status = GSS_S_FAILURE;
            goto exit;
        }

	local_result = globus_gsi_cred_write(cred_desc->cred_handle, bp);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_IMPEXP_BIO_SSL);
            major_status = GSS_S_FAILURE;
            goto exit;
        }            
		
        export_buffer->length = BIO_pending(bp);
		
        if (export_buffer->length > 0)
        {
            export_buffer->value = (char *) malloc(export_buffer->length);
            if (export_buffer->value == NULL)
            {
                export_buffer->length = 0;
                GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
                major_status = GSS_S_FAILURE;
                goto exit;
            }
			
            BIO_read(bp, export_buffer->value, export_buffer->length);
        }
        else
        {
            export_buffer->value = NULL;
        }

        major_status = GSS_S_COMPLETE;
    }
    else if(option_req == GSS_IMPEXP_MECH_SPECIFIC)
    {
        /* With option_req is equal to EXPORT_MECH_SPECIFIC (1), 
         * it exports a buffer filled with mechanism-specific 
         * information that the calling application can use 
         * to pass the credentials to another process that 
         * is not written to the GSS-API.
         */
        local_result = 
            GLOBUS_GSI_SYSCONFIG_GET_UNIQUE_PROXY_FILENAME(&proxy_filename);
        if(local_result != GLOBUS_SUCCESS)
        {
            proxy_filename = NULL;
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
            major_status = GSS_S_FAILURE;
            goto exit;
        }

        GLOBUS_I_GSI_GSSAPI_DEBUG_FPRINTF(
            3, (globus_i_gsi_gssapi_debug_fstream,
                "Writing exported cred to: %s\n", proxy_filename));

        local_result = globus_gsi_cred_write_proxy(cred_desc->cred_handle,
                                                   proxy_filename);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSI_PROXY);
            major_status = GSS_S_FAILURE;
            goto exit;
        }                                       

        export_buffer->value = globus_common_create_string(
            "X509_USER_PROXY=%s",
            proxy_filename);
        export_buffer->length = strlen(export_buffer->value)+1;
    }
    else
    {
        major_status = GSS_S_FAILURE;
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Unrecognized option_req of: %d"), option_req));
        goto exit;
    }

 exit:

    if(proxy_filename != NULL)
    { 
        free(proxy_filename);
    }
    
    if (bp) 
    {
        BIO_free(bp);
    }

    GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT;
    return major_status;
}
예제 #21
0
파일: k5seal.c 프로젝트: OPSF/uClinux
static krb5_error_code
make_seal_token_v1 (krb5_context context,
                    krb5_keyblock *enc,
                    krb5_keyblock *seq,
                    gssint_uint64 *seqnum,
                    int direction,
                    gss_buffer_t text,
                    gss_buffer_t token,
                    int signalg,
                    size_t cksum_size,
                    int sealalg,
                    int do_encrypt,
                    int toktype,
                    int bigend,
                    gss_OID oid)
{
    krb5_error_code code;
    size_t sumlen;
    char *data_ptr;
    krb5_data plaind;
    krb5_checksum md5cksum;
    krb5_checksum cksum;
    /* msglen contains the message length
     * we are signing/encrypting.  tmsglen
     * contains the length of the message
     * we plan to write out to the token.
     * tlen is the length of the token
     * including header. */
    unsigned int conflen=0, tmsglen, tlen, msglen;
    unsigned char *t, *ptr;
    unsigned char *plain;
    unsigned char pad;
    krb5_keyusage sign_usage = KG_USAGE_SIGN;


    assert((!do_encrypt) || (toktype == KG_TOK_SEAL_MSG));
    /* create the token buffer */
    /* Do we need confounder? */
    if (do_encrypt || (!bigend && (toktype == KG_TOK_SEAL_MSG)))
        conflen = kg_confounder_size(context, enc);
    else conflen = 0;

    if (toktype == KG_TOK_SEAL_MSG) {
        switch (sealalg) {
        case SEAL_ALG_MICROSOFT_RC4:
            msglen = conflen + text->length+1;
            pad = 1;
            break;
        default:
            /* XXX knows that des block size is 8 */
            msglen = (conflen+text->length+8)&(~7);
            pad = 8-(text->length%8);
        }
        tmsglen = msglen;
    } else {
        tmsglen = 0;
        msglen = text->length;
        pad = 0;
    }
    tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);

    if ((t = (unsigned char *) xmalloc(tlen)) == NULL)
        return(ENOMEM);

    /*** fill in the token */

    ptr = t;
    g_make_token_header(oid, 14+cksum_size+tmsglen, &ptr, toktype);

    /* 0..1 SIGN_ALG */
    store_16_le(signalg, &ptr[0]);

    /* 2..3 SEAL_ALG or Filler */
    if ((toktype == KG_TOK_SEAL_MSG) && do_encrypt) {
        store_16_le(sealalg, &ptr[2]);
    } else {
        /* No seal */
        ptr[2] = 0xff;
        ptr[3] = 0xff;
    }

    /* 4..5 Filler */
    ptr[4] = 0xff;
    ptr[5] = 0xff;

    /* pad the plaintext, encrypt if needed, and stick it in the token */

    /* initialize the the cksum */
    switch (signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_MD2_5:
        md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
        break;
    case SGN_ALG_HMAC_MD5:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
        if (toktype != KG_TOK_SEAL_MSG)
            sign_usage = 15;
        break;
    default:
    case SGN_ALG_DES_MAC:
        abort ();
    }

    code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
    if (code) {
        xfree(t);
        return(code);
    }
    md5cksum.length = sumlen;


    if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) {
        xfree(t);
        return(ENOMEM);
    }

    if (conflen) {
        if ((code = kg_make_confounder(context, enc, plain))) {
            xfree(plain);
            xfree(t);
            return(code);
        }
    }

    memcpy(plain+conflen, text->value, text->length);
    if (pad) memset(plain+conflen+text->length, pad, pad);

    /* compute the checksum */

    /* 8 = head of token body as specified by mech spec */
    if (! (data_ptr =
           (char *) xmalloc(8 + (bigend ? text->length : msglen)))) {
        xfree(plain);
        xfree(t);
        return(ENOMEM);
    }
    (void) memcpy(data_ptr, ptr-2, 8);
    if (bigend)
        (void) memcpy(data_ptr+8, text->value, text->length);
    else
        (void) memcpy(data_ptr+8, plain, msglen);
    plaind.length = 8 + (bigend ? text->length : msglen);
    plaind.data = data_ptr;
    code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq,
                                sign_usage, &plaind, &md5cksum);
    xfree(data_ptr);

    if (code) {
        xfree(plain);
        xfree(t);
        return(code);
    }
    switch(signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case 3:

        if ((code = kg_encrypt(context, seq, KG_USAGE_SEAL,
                               (g_OID_equal(oid, gss_mech_krb5_old) ?
                                seq->contents : NULL),
                               md5cksum.contents, md5cksum.contents, 16))) {
            krb5_free_checksum_contents(context, &md5cksum);
            xfree (plain);
            xfree(t);
            return code;
        }

        cksum.length = cksum_size;
        cksum.contents = md5cksum.contents + 16 - cksum.length;

        memcpy(ptr+14, cksum.contents, cksum.length);
        break;

    case SGN_ALG_HMAC_SHA1_DES3_KD:
        /*
         * Using key derivation, the call to krb5_c_make_checksum
         * already dealt with encrypting.
         */
        if (md5cksum.length != cksum_size)
            abort ();
        memcpy (ptr+14, md5cksum.contents, md5cksum.length);
        break;
    case SGN_ALG_HMAC_MD5:
        memcpy (ptr+14, md5cksum.contents, cksum_size);
        break;
    }

    krb5_free_checksum_contents(context, &md5cksum);

    /* create the seq_num */

    if ((code = kg_make_seq_num(context, seq, direction?0:0xff,
                                (krb5_ui_4)*seqnum, ptr+14, ptr+6))) {
        xfree (plain);
        xfree(t);
        return(code);
    }

    if (do_encrypt) {
        switch(sealalg) {
        case SEAL_ALG_MICROSOFT_RC4:
        {
            unsigned char bigend_seqnum[4];
            krb5_keyblock *enc_key;
            int i;
            store_32_be(*seqnum, bigend_seqnum);
            code = krb5_copy_keyblock (context, enc, &enc_key);
            if (code)
            {
                xfree(plain);
                xfree(t);
                return(code);
            }
            assert (enc_key->length == 16);
            for (i = 0; i <= 15; i++)
                ((char *) enc_key->contents)[i] ^=0xf0;
            code = kg_arcfour_docrypt (enc_key, 0,
                                       bigend_seqnum, 4,
                                       plain, tmsglen,
                                       ptr+14+cksum_size);
            krb5_free_keyblock (context, enc_key);
            if (code)
            {
                xfree(plain);
                xfree(t);
                return(code);
            }
        }
        break;
        default:
            if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL,
                                   (krb5_pointer) plain,
                                   (krb5_pointer) (ptr+cksum_size+14),
                                   tmsglen))) {
                xfree(plain);
                xfree(t);
                return(code);
            }
        }
    }else {
        if (tmsglen)
            memcpy(ptr+14+cksum_size, plain, tmsglen);
    }
    xfree(plain);


    /* that's it.  return the token */

    (*seqnum)++;
    *seqnum &= 0xffffffffL;

    token->length = tlen;
    token->value = (void *) t;

    return(0);
}
예제 #22
0
/*
 * spkm3_read_token()
 *
 * only SPKM_MIC_TOK with md5 intg-alg is supported
 */
u32
spkm3_read_token(struct spkm3_ctx *ctx,
		struct xdr_netobj *read_token,    /* checksum */
		struct xdr_buf *message_buffer, /* signbuf */
		int toktype)
{
	s32			checksum_type;
	s32			code;
	struct xdr_netobj	wire_cksum = {.len =0, .data = NULL};
	char			cksumdata[16];
	struct xdr_netobj	md5cksum = {.len = 0, .data = cksumdata};
	unsigned char		*ptr = (unsigned char *)read_token->data;
	unsigned char		*cksum;
	int			bodysize, md5elen;
	int			mic_hdrlen;
	u32			ret = GSS_S_DEFECTIVE_TOKEN;

	if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
					&bodysize, &ptr, read_token->len))
		goto out;

	/* decode the token */

	if (toktype != SPKM_MIC_TOK) {
		dprintk("RPC:       BAD SPKM3 token type: %d\n", toktype);
		goto out;
	}

	if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum)))
		goto out;

	if (*cksum++ != 0x03) {
		dprintk("RPC:       spkm3_read_token BAD checksum type\n");
		goto out;
	}
	md5elen = *cksum++;
	cksum++; 	/* move past the zbit */

	if (!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
		goto out;

	/* HARD CODED FOR MD5 */

	/* compute the checksum of the message.
	 * ptr + 2 = start of header piece of checksum
	 * mic_hdrlen + 2 = length of header piece of checksum
	 */
	ret = GSS_S_DEFECTIVE_TOKEN;
	if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) {
		dprintk("RPC:       gss_spkm3_seal: unsupported I-ALG "
				"algorithm\n");
		goto out;
	}

	checksum_type = CKSUMTYPE_HMAC_MD5;

	code = make_spkm3_checksum(checksum_type,
		&ctx->derived_integ_key, ptr + 2, mic_hdrlen + 2,
		message_buffer, 0, &md5cksum);

	if (code)
		goto out;

	ret = GSS_S_BAD_SIG;
	code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
	if (code) {
		dprintk("RPC:       bad MIC checksum\n");
		goto out;
	}


	ret = GSS_S_COMPLETE;
out:
	kfree(wire_cksum.data);
	return ret;
}