2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1986, 2010, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
2N/A *
2N/A * $Header:
2N/A * /afs/gza.com/product/secure/rel-eng/src/1.1/rpc/RCS/auth_gssapi_misc.c,v
2N/A * 1.10 1994/10/27 12:39:23 jik Exp $
2N/A */
2N/A
2N/A#include <stdlib.h>
2N/A#include <gssapi/gssapi.h>
2N/A#include <rpc/rpc.h>
2N/A#include <rpc/rpcsec_defs.h>
2N/A
2N/A/*
2N/A * Miscellaneous XDR routines.
2N/A */
2N/Abool_t
2N/A__xdr_gss_buf(xdrs, buf)
2N/A XDR *xdrs;
2N/A gss_buffer_t buf;
2N/A{
2N/A uint_t cast_len, bound_len;
2N/A
2N/A /*
2N/A * We go through this contortion because size_t is a now a ulong,
2N/A * GSS-API uses ulongs.
2N/A */
2N/A
2N/A if (xdrs->x_op != XDR_DECODE) {
2N/A bound_len = cast_len = (uint_t)buf->length;
2N/A } else {
2N/A bound_len = (uint_t)-1;
2N/A }
2N/A
2N/A if (xdr_bytes(xdrs, (char **)&buf->value, &cast_len,
2N/A bound_len) == TRUE) {
2N/A if (xdrs->x_op == XDR_DECODE)
2N/A buf->length = cast_len;
2N/A
2N/A return (TRUE);
2N/A }
2N/A
2N/A return (FALSE);
2N/A}
2N/A
2N/Abool_t
2N/A__xdr_rpc_gss_creds(xdrs, creds)
2N/A XDR *xdrs;
2N/A rpc_gss_creds *creds;
2N/A{
2N/A if (!xdr_u_int(xdrs, &creds->version) ||
2N/A !xdr_u_int(xdrs, &creds->gss_proc) ||
2N/A !xdr_u_int(xdrs, &creds->seq_num) ||
2N/A !xdr_u_int(xdrs, (uint_t *)&creds->service) ||
2N/A !__xdr_gss_buf(xdrs, &creds->ctx_handle))
2N/A return (FALSE);
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/A__xdr_rpc_gss_init_arg(xdrs, init_arg)
2N/A XDR *xdrs;
2N/A rpc_gss_init_arg *init_arg;
2N/A{
2N/A if (!__xdr_gss_buf(xdrs, init_arg))
2N/A return (FALSE);
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/A__xdr_rpc_gss_init_res(xdrs, init_res)
2N/A XDR *xdrs;
2N/A rpc_gss_init_res *init_res;
2N/A{
2N/A if (!__xdr_gss_buf(xdrs, &init_res->ctx_handle) ||
2N/A !xdr_u_int(xdrs, (uint_t *)&init_res->gss_major) ||
2N/A !xdr_u_int(xdrs, (uint_t *)&init_res->gss_minor) ||
2N/A !xdr_u_int(xdrs, (uint_t *)&init_res->seq_window) ||
2N/A !__xdr_gss_buf(xdrs, &init_res->token))
2N/A return (FALSE);
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Generic routine to wrap data used by client and server sides.
2N/A */
2N/Abool_t
2N/A__rpc_gss_wrap_data(service, qop, context, seq_num, out_xdrs, xdr_func,
2N/A xdr_ptr)
2N/A OM_uint32 qop;
2N/A rpc_gss_service_t service;
2N/A gss_ctx_id_t context;
2N/A uint_t seq_num;
2N/A XDR *out_xdrs;
2N/A bool_t (*xdr_func)();
2N/A caddr_t xdr_ptr;
2N/A{
2N/A OM_uint32 minor;
2N/A gss_buffer_desc in_buf, out_buf;
2N/A XDR temp_xdrs;
2N/A bool_t conf_state;
2N/A bool_t ret = FALSE;
2N/A uint_t bufsiz;
2N/A char *buf;
2N/A
2N/A /*
2N/A * Create a temporary XDR/buffer to hold the data to be wrapped.
2N/A */
2N/A out_buf.length = 0;
2N/A bufsiz = xdr_sizeof(xdr_func, xdr_ptr) +
2N/A xdr_sizeof(xdr_u_int, &seq_num);
2N/A if ((buf = (char *)malloc(bufsiz)) == NULL) {
2N/A fprintf(stderr, dgettext(TEXT_DOMAIN, "malloc failed in "
2N/A "__rpc_gss_wrap_data\n"));
2N/A return (FALSE);
2N/A }
2N/A xdrmem_create(&temp_xdrs, buf, bufsiz, XDR_ENCODE);
2N/A
2N/A /*
2N/A * serialize the sequence number into tmp memory
2N/A */
2N/A if (!xdr_u_int(&temp_xdrs, &seq_num))
2N/A goto fail;
2N/A
2N/A /*
2N/A * serialize the arguments into tmp memory
2N/A */
2N/A if (!(*xdr_func)(&temp_xdrs, xdr_ptr))
2N/A goto fail;
2N/A
2N/A /*
2N/A * Data to be wrapped goes in in_buf. If privacy is used,
2N/A * out_buf will have wrapped data (in_buf will no longer be
2N/A * needed). If integrity is used, out_buf will have checksum
2N/A * which will follow the data in in_buf.
2N/A */
2N/A in_buf.length = xdr_getpos(&temp_xdrs);
2N/A in_buf.value = temp_xdrs.x_base;
2N/A
2N/A switch (service) {
2N/A case rpc_gss_svc_privacy:
2N/A if (gss_seal(&minor, context, TRUE, qop, &in_buf,
2N/A &conf_state, &out_buf) != GSS_S_COMPLETE)
2N/A goto fail;
2N/A in_buf.length = 0; /* in_buf not needed */
2N/A if (!conf_state)
2N/A goto fail;
2N/A break;
2N/A case rpc_gss_svc_integrity:
2N/A if (gss_sign(&minor, context, qop, &in_buf,
2N/A &out_buf) != GSS_S_COMPLETE)
2N/A goto fail;
2N/A break;
2N/A default:
2N/A goto fail;
2N/A }
2N/A
2N/A /*
2N/A * write out in_buf and out_buf as needed
2N/A */
2N/A if (in_buf.length != 0) {
2N/A if (!__xdr_gss_buf(out_xdrs, &in_buf))
2N/A goto fail;
2N/A }
2N/A
2N/A if (!__xdr_gss_buf(out_xdrs, &out_buf))
2N/A goto fail;
2N/A ret = TRUE;
2N/Afail:
2N/A XDR_DESTROY(&temp_xdrs);
2N/A if (buf)
2N/A (void) free(buf);
2N/A if (out_buf.length != 0)
2N/A (void) gss_release_buffer(&minor, &out_buf);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Generic routine to unwrap data used by client and server sides.
2N/A */
2N/Abool_t
2N/A__rpc_gss_unwrap_data(service, context, seq_num, qop_check, in_xdrs, xdr_func,
2N/A xdr_ptr)
2N/A rpc_gss_service_t service;
2N/A gss_ctx_id_t context;
2N/A uint_t seq_num;
2N/A OM_uint32 qop_check;
2N/A XDR *in_xdrs;
2N/A bool_t (*xdr_func)();
2N/A caddr_t xdr_ptr;
2N/A{
2N/A gss_buffer_desc in_buf, out_buf;
2N/A XDR temp_xdrs;
2N/A uint_t seq_num2;
2N/A bool_t conf;
2N/A OM_uint32 major = GSS_S_COMPLETE, minor = 0;
2N/A int qop;
2N/A
2N/A in_buf.value = NULL;
2N/A out_buf.value = NULL;
2N/A
2N/A /*
2N/A * Pull out wrapped data. For privacy service, this is the
2N/A * encrypted data. For integrity service, this is the data
2N/A * followed by a checksum.
2N/A */
2N/A if (!__xdr_gss_buf(in_xdrs, &in_buf))
2N/A return (FALSE);
2N/A
2N/A if (service == rpc_gss_svc_privacy) {
2N/A major = gss_unseal(&minor, context, &in_buf, &out_buf, &conf,
2N/A &qop);
2N/A free(in_buf.value);
2N/A if (major != GSS_S_COMPLETE) {
2N/A if (GSS_SUPPLEMENTARY_INFO(major))
2N/A gss_release_buffer(&minor, &out_buf);
2N/A return (FALSE);
2N/A }
2N/A /*
2N/A * Keep the returned token (unencrypted data) in in_buf.
2N/A */
2N/A in_buf.length = out_buf.length;
2N/A in_buf.value = out_buf.value;
2N/A
2N/A /*
2N/A * If privacy was not used, or if QOP is not what we are
2N/A * expecting, fail.
2N/A */
2N/A if (!conf || qop != qop_check)
2N/A goto fail;
2N/A
2N/A } else if (service == rpc_gss_svc_integrity) {
2N/A if (!__xdr_gss_buf(in_xdrs, &out_buf))
2N/A return (FALSE);
2N/A major = gss_verify(&minor, context, &in_buf, &out_buf, &qop);
2N/A free(out_buf.value);
2N/A if (major != GSS_S_COMPLETE) {
2N/A free(in_buf.value);
2N/A return (FALSE);
2N/A }
2N/A
2N/A /*
2N/A * If QOP is not what we are expecting, fail.
2N/A */
2N/A if (qop != qop_check)
2N/A goto fail;
2N/A }
2N/A
2N/A xdrmem_create(&temp_xdrs, in_buf.value, in_buf.length, XDR_DECODE);
2N/A
2N/A /*
2N/A * The data consists of the sequence number followed by the
2N/A * arguments. Make sure sequence number is what we are
2N/A * expecting (i.e., the value in the header).
2N/A */
2N/A if (!xdr_u_int(&temp_xdrs, &seq_num2))
2N/A goto fail;
2N/A if (seq_num2 != seq_num)
2N/A goto fail;
2N/A
2N/A /*
2N/A * Deserialize the arguments into xdr_ptr, and release in_buf.
2N/A */
2N/A if (!(*xdr_func)(&temp_xdrs, xdr_ptr))
2N/A goto fail;
2N/A
2N/A if (service == rpc_gss_svc_privacy)
2N/A (void) gss_release_buffer(&minor, &in_buf);
2N/A else
2N/A free(in_buf.value);
2N/A XDR_DESTROY(&temp_xdrs);
2N/A return (TRUE);
2N/Afail:
2N/A XDR_DESTROY(&temp_xdrs);
2N/A if (service == rpc_gss_svc_privacy)
2N/A (void) gss_release_buffer(&minor, &in_buf);
2N/A else
2N/A free(in_buf.value);
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/A__find_max_data_length(service, context, qop, max_tp_unit_len)
2N/A rpc_gss_service_t service;
2N/A gss_ctx_id_t context;
2N/A OM_uint32 qop;
2N/A int max_tp_unit_len;
2N/A{
2N/A int conf;
2N/A OM_uint32 maj_stat = GSS_S_COMPLETE, min_stat = 0;
2N/A OM_uint32 max_input_size;
2N/A int ret_val = 0;
2N/A
2N/A if (service == rpc_gss_svc_integrity || service == rpc_gss_svc_default)
2N/A conf = 0;
2N/A else if (service == rpc_gss_svc_privacy)
2N/A conf = 1;
2N/A else if (service == rpc_gss_svc_none)
2N/A return (max_tp_unit_len);
2N/A
2N/A maj_stat = gss_wrap_size_limit(&min_stat,
2N/A context, conf, qop,
2N/A max_tp_unit_len, &max_input_size);
2N/A
2N/A /*
2N/A * max_input_size may result in negative value
2N/A */
2N/A if (maj_stat == GSS_S_COMPLETE) {
2N/A if ((int)max_input_size <= 0)
2N/A ret_val = 0;
2N/A else
2N/A ret_val = (int)(max_input_size);
2N/A } else {
2N/A fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "gss_wrap_size_limit failed in "
2N/A "__find_max_data_length\n"));
2N/A }
2N/A
2N/A return (ret_val);
2N/A}