#include <stdlib.h>
#include <gssapi/gssapi.h>
#include <rpc/rpc.h>
#include <rpc/rpcsec_defs.h>
bool_t
__xdr_gss_buf(xdrs, buf)
XDR *xdrs;
gss_buffer_t buf;
{
u_int cast_len, bound_len;
if (xdrs->x_op != XDR_DECODE) {
bound_len = cast_len = (u_int) buf->length;
} else {
bound_len = (u_int)-1;
}
if (xdr_bytes(xdrs, (char **)&buf->value, &cast_len,
bound_len) == TRUE) {
if (xdrs->x_op == XDR_DECODE)
buf->length = cast_len;
return (TRUE);
}
return (FALSE);
}
bool_t
__xdr_rpc_gss_creds(xdrs, creds)
XDR *xdrs;
rpc_gss_creds *creds;
{
if (!xdr_u_int(xdrs, &creds->version) ||
!xdr_u_int(xdrs, &creds->gss_proc) ||
!xdr_u_int(xdrs, &creds->seq_num) ||
!xdr_u_int(xdrs, (u_int *)&creds->service) ||
!__xdr_gss_buf(xdrs, &creds->ctx_handle))
return (FALSE);
return (TRUE);
}
bool_t
__xdr_rpc_gss_init_arg(xdrs, init_arg)
XDR *xdrs;
rpc_gss_init_arg *init_arg;
{
if (!__xdr_gss_buf(xdrs, init_arg))
return (FALSE);
return (TRUE);
}
bool_t
__xdr_rpc_gss_init_res(xdrs, init_res)
XDR *xdrs;
rpc_gss_init_res *init_res;
{
if (!__xdr_gss_buf(xdrs, &init_res->ctx_handle) ||
!xdr_u_int(xdrs, (u_int *)&init_res->gss_major) ||
!xdr_u_int(xdrs, (u_int *)&init_res->gss_minor) ||
!xdr_u_int(xdrs, (u_int *)&init_res->seq_window) ||
!__xdr_gss_buf(xdrs, &init_res->token))
return (FALSE);
return (TRUE);
}
bool_t
__rpc_gss_wrap_data(service, qop, context, seq_num, out_xdrs, xdr_func,
xdr_ptr)
OM_uint32 qop;
rpc_gss_service_t service;
gss_ctx_id_t context;
u_int seq_num;
XDR *out_xdrs;
bool_t (*xdr_func)();
caddr_t xdr_ptr;
{
OM_uint32 minor;
gss_buffer_desc in_buf, out_buf;
XDR temp_xdrs;
bool_t conf_state;
bool_t ret = FALSE;
u_int bufsiz;
char *buf;
out_buf.length = 0;
bufsiz = xdr_sizeof(xdr_func, xdr_ptr) +
xdr_sizeof(xdr_u_int, &seq_num);
if ((buf = (char *)malloc(bufsiz)) == NULL) {
fprintf(stderr, dgettext(TEXT_DOMAIN, "malloc failed in "
"__rpc_gss_wrap_data\n"));
return (FALSE);
}
xdrmem_create(&temp_xdrs, buf, bufsiz, XDR_ENCODE);
if (!xdr_u_int(&temp_xdrs, &seq_num))
goto fail;
if (!(*xdr_func)(&temp_xdrs, xdr_ptr))
goto fail;
in_buf.length = xdr_getpos(&temp_xdrs);
in_buf.value = temp_xdrs.x_base;
switch (service) {
case rpc_gss_svc_privacy:
if (gss_seal(&minor, context, TRUE, qop, &in_buf,
&conf_state, &out_buf) != GSS_S_COMPLETE)
goto fail;
in_buf.length = 0;
if (!conf_state)
goto fail;
break;
case rpc_gss_svc_integrity:
if (gss_sign(&minor, context, qop, &in_buf,
&out_buf) != GSS_S_COMPLETE)
goto fail;
break;
default:
goto fail;
}
if (in_buf.length != 0) {
if (!__xdr_gss_buf(out_xdrs, &in_buf))
goto fail;
}
if (!__xdr_gss_buf(out_xdrs, &out_buf))
goto fail;
ret = TRUE;
fail:
XDR_DESTROY(&temp_xdrs);
if (buf)
(void) free(buf);
if (out_buf.length != 0)
(void) gss_release_buffer(&minor, &out_buf);
return (ret);
}
bool_t
__rpc_gss_unwrap_data(service, context, seq_num, qop_check, in_xdrs, xdr_func,
xdr_ptr)
rpc_gss_service_t service;
gss_ctx_id_t context;
u_int seq_num;
OM_uint32 qop_check;
XDR *in_xdrs;
bool_t (*xdr_func)();
caddr_t xdr_ptr;
{
gss_buffer_desc in_buf, out_buf;
XDR temp_xdrs;
u_int seq_num2;
bool_t conf;
OM_uint32 major = GSS_S_COMPLETE, minor = 0;
int qop;
in_buf.value = NULL;
out_buf.value = NULL;
if (!__xdr_gss_buf(in_xdrs, &in_buf))
return (FALSE);
if (service == rpc_gss_svc_privacy) {
major = gss_unseal(&minor, context, &in_buf, &out_buf, &conf,
&qop);
free(in_buf.value);
if (major != GSS_S_COMPLETE)
return (FALSE);
in_buf.length = out_buf.length;
in_buf.value = out_buf.value;
if (!conf || qop != qop_check)
goto fail;
} else if (service == rpc_gss_svc_integrity) {
if (!__xdr_gss_buf(in_xdrs, &out_buf))
return (FALSE);
major = gss_verify(&minor, context, &in_buf, &out_buf, &qop);
free(out_buf.value);
if (major != GSS_S_COMPLETE) {
free(in_buf.value);
return (FALSE);
}
if (qop != qop_check)
goto fail;
}
xdrmem_create(&temp_xdrs, in_buf.value, in_buf.length, XDR_DECODE);
if (!xdr_u_int(&temp_xdrs, &seq_num2))
goto fail;
if (seq_num2 != seq_num)
goto fail;
if (!(*xdr_func)(&temp_xdrs, xdr_ptr))
goto fail;
if (service == rpc_gss_svc_privacy)
(void) gss_release_buffer(&minor, &in_buf);
else
free(in_buf.value);
XDR_DESTROY(&temp_xdrs);
return (TRUE);
fail:
XDR_DESTROY(&temp_xdrs);
if (service == rpc_gss_svc_privacy)
(void) gss_release_buffer(&minor, &in_buf);
else
free(in_buf.value);
return (FALSE);
}
int
__find_max_data_length(service, context, qop, max_tp_unit_len)
rpc_gss_service_t service;
gss_ctx_id_t context;
OM_uint32 qop;
int max_tp_unit_len;
{
int conf;
OM_uint32 maj_stat = GSS_S_COMPLETE, min_stat = 0;
OM_uint32 max_input_size;
int ret_val = 0;
if (service == rpc_gss_svc_integrity || service == rpc_gss_svc_default)
conf = 0;
else if (service == rpc_gss_svc_privacy)
conf = 1;
else if (service == rpc_gss_svc_none)
return (max_tp_unit_len);
maj_stat = gss_wrap_size_limit(&min_stat,
context, conf, qop,
max_tp_unit_len, &max_input_size);
if (maj_stat == GSS_S_COMPLETE) {
if ((int)max_input_size <= 0)
ret_val = 0;
else
ret_val = (int)(max_input_size);
} else {
fprintf(stderr, dgettext(TEXT_DOMAIN,
"gss_wrap_size_limit failed in "
"__find_max_data_length\n"));
}
return (ret_val);
}