1181344Sdfr/* 2181344Sdfr rpcsec_gss_prot.c 3181344Sdfr 4181344Sdfr Copyright (c) 2000 The Regents of the University of Michigan. 5181344Sdfr All rights reserved. 6181344Sdfr 7181344Sdfr Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>. 8181344Sdfr All rights reserved, all wrongs reversed. 9181344Sdfr 10181344Sdfr Redistribution and use in source and binary forms, with or without 11181344Sdfr modification, are permitted provided that the following conditions 12181344Sdfr are met: 13181344Sdfr 14181344Sdfr 1. Redistributions of source code must retain the above copyright 15181344Sdfr notice, this list of conditions and the following disclaimer. 16181344Sdfr 2. Redistributions in binary form must reproduce the above copyright 17181344Sdfr notice, this list of conditions and the following disclaimer in the 18181344Sdfr documentation and/or other materials provided with the distribution. 19181344Sdfr 3. Neither the name of the University nor the names of its 20181344Sdfr contributors may be used to endorse or promote products derived 21181344Sdfr from this software without specific prior written permission. 22181344Sdfr 23181344Sdfr THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 24181344Sdfr WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25181344Sdfr MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26181344Sdfr DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27181344Sdfr FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28181344Sdfr CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29181344Sdfr SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 30181344Sdfr BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31181344Sdfr LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32181344Sdfr NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33181344Sdfr SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34181344Sdfr 35181344Sdfr $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $ 36181344Sdfr*/ 37181344Sdfr/* $FreeBSD$ */ 38181344Sdfr 39181344Sdfr#include <stdio.h> 40181344Sdfr#include <stdlib.h> 41181344Sdfr#include <stdarg.h> 42181344Sdfr#include <string.h> 43181344Sdfr#include <rpc/rpc.h> 44181344Sdfr#include <rpc/rpcsec_gss.h> 45181344Sdfr#include "rpcsec_gss_int.h" 46181344Sdfr 47181344Sdfr#define MAX_GSS_SIZE 10240 /* XXX */ 48181344Sdfr 49181344Sdfrbool_t 50181344Sdfrxdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p) 51181344Sdfr{ 52181344Sdfr char *val; 53181344Sdfr u_int len; 54181344Sdfr bool_t ret; 55181344Sdfr 56181344Sdfr val = p->value; 57181344Sdfr len = p->length; 58181344Sdfr ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE); 59181344Sdfr p->value = val; 60181344Sdfr p->length = len; 61181344Sdfr 62181344Sdfr return (ret); 63181344Sdfr} 64181344Sdfr 65181344Sdfrbool_t 66181344Sdfrxdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p) 67181344Sdfr{ 68181344Sdfr enum_t proc, svc; 69181344Sdfr bool_t ret; 70181344Sdfr 71181344Sdfr proc = p->gc_proc; 72181344Sdfr svc = p->gc_svc; 73181344Sdfr ret = (xdr_u_int(xdrs, &p->gc_version) && 74181344Sdfr xdr_enum(xdrs, &proc) && 75181344Sdfr xdr_u_int(xdrs, &p->gc_seq) && 76181344Sdfr xdr_enum(xdrs, &svc) && 77181344Sdfr xdr_gss_buffer_desc(xdrs, &p->gc_handle)); 78181344Sdfr p->gc_proc = proc; 79181344Sdfr p->gc_svc = svc; 80181344Sdfr 81181344Sdfr return (ret); 82181344Sdfr} 83181344Sdfr 84181344Sdfrbool_t 85181344Sdfrxdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p) 86181344Sdfr{ 87181344Sdfr 88181344Sdfr return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) && 89181344Sdfr xdr_u_int(xdrs, &p->gr_major) && 90181344Sdfr xdr_u_int(xdrs, &p->gr_minor) && 91181344Sdfr xdr_u_int(xdrs, &p->gr_win) && 92181344Sdfr xdr_gss_buffer_desc(xdrs, &p->gr_token)); 93181344Sdfr} 94181344Sdfr 95181344Sdfrbool_t 96181344Sdfrxdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, 97181344Sdfr gss_ctx_id_t ctx, gss_qop_t qop, 98181344Sdfr rpc_gss_service_t svc, u_int seq) 99181344Sdfr{ 100181344Sdfr gss_buffer_desc databuf, wrapbuf; 101181344Sdfr OM_uint32 maj_stat, min_stat; 102181344Sdfr int start, end, conf_state; 103181346Sdfr u_int len; 104181344Sdfr bool_t xdr_stat; 105181344Sdfr 106181344Sdfr /* Skip databody length. */ 107181344Sdfr start = XDR_GETPOS(xdrs); 108181344Sdfr XDR_SETPOS(xdrs, start + 4); 109181344Sdfr 110181344Sdfr /* Marshal rpc_gss_data_t (sequence number + arguments). */ 111181344Sdfr if (!xdr_u_int(xdrs, &seq) || !xdr_func(xdrs, xdr_ptr)) 112181344Sdfr return (FALSE); 113181344Sdfr end = XDR_GETPOS(xdrs); 114181344Sdfr 115181344Sdfr /* Set databuf to marshalled rpc_gss_data_t. */ 116181344Sdfr databuf.length = end - start - 4; 117181344Sdfr XDR_SETPOS(xdrs, start + 4); 118181344Sdfr databuf.value = XDR_INLINE(xdrs, databuf.length); 119181344Sdfr 120181344Sdfr xdr_stat = FALSE; 121181344Sdfr 122181344Sdfr if (svc == rpc_gss_svc_integrity) { 123181344Sdfr /* Marshal databody_integ length. */ 124181344Sdfr XDR_SETPOS(xdrs, start); 125181346Sdfr len = databuf.length; 126181346Sdfr if (!xdr_u_int(xdrs, &len)) 127181344Sdfr return (FALSE); 128181344Sdfr 129181344Sdfr /* Checksum rpc_gss_data_t. */ 130181344Sdfr maj_stat = gss_get_mic(&min_stat, ctx, qop, 131181344Sdfr &databuf, &wrapbuf); 132181344Sdfr if (maj_stat != GSS_S_COMPLETE) { 133181344Sdfr log_debug("gss_get_mic failed"); 134181344Sdfr return (FALSE); 135181344Sdfr } 136181344Sdfr /* Marshal checksum. */ 137181344Sdfr XDR_SETPOS(xdrs, end); 138181344Sdfr xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); 139181344Sdfr gss_release_buffer(&min_stat, &wrapbuf); 140181344Sdfr } 141181344Sdfr else if (svc == rpc_gss_svc_privacy) { 142181344Sdfr /* Encrypt rpc_gss_data_t. */ 143181344Sdfr maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, 144181344Sdfr &conf_state, &wrapbuf); 145181344Sdfr if (maj_stat != GSS_S_COMPLETE) { 146181344Sdfr log_status("gss_wrap", NULL, maj_stat, min_stat); 147181344Sdfr return (FALSE); 148181344Sdfr } 149181344Sdfr /* Marshal databody_priv. */ 150181344Sdfr XDR_SETPOS(xdrs, start); 151181344Sdfr xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); 152181344Sdfr gss_release_buffer(&min_stat, &wrapbuf); 153181344Sdfr } 154181344Sdfr return (xdr_stat); 155181344Sdfr} 156181344Sdfr 157181344Sdfrbool_t 158181344Sdfrxdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, 159181344Sdfr gss_ctx_id_t ctx, gss_qop_t qop, 160181344Sdfr rpc_gss_service_t svc, u_int seq) 161181344Sdfr{ 162181344Sdfr XDR tmpxdrs; 163181344Sdfr gss_buffer_desc databuf, wrapbuf; 164181344Sdfr OM_uint32 maj_stat, min_stat; 165181344Sdfr u_int seq_num, conf_state, qop_state; 166181344Sdfr bool_t xdr_stat; 167181344Sdfr 168181344Sdfr if (xdr_func == (xdrproc_t) xdr_void || xdr_ptr == NULL) 169181344Sdfr return (TRUE); 170181344Sdfr 171181344Sdfr memset(&databuf, 0, sizeof(databuf)); 172181344Sdfr memset(&wrapbuf, 0, sizeof(wrapbuf)); 173181344Sdfr 174181344Sdfr if (svc == rpc_gss_svc_integrity) { 175181344Sdfr /* Decode databody_integ. */ 176181344Sdfr if (!xdr_gss_buffer_desc(xdrs, &databuf)) { 177181344Sdfr log_debug("xdr decode databody_integ failed"); 178181344Sdfr return (FALSE); 179181344Sdfr } 180181344Sdfr /* Decode checksum. */ 181181344Sdfr if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) { 182181344Sdfr mem_free(databuf.value, databuf.length); 183181344Sdfr log_debug("xdr decode checksum failed"); 184181344Sdfr return (FALSE); 185181344Sdfr } 186181344Sdfr /* Verify checksum and QOP. */ 187181344Sdfr maj_stat = gss_verify_mic(&min_stat, ctx, &databuf, 188181344Sdfr &wrapbuf, &qop_state); 189181344Sdfr mem_free(wrapbuf.value, wrapbuf.length); 190181344Sdfr 191181344Sdfr if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { 192181344Sdfr mem_free(databuf.value, databuf.length); 193181344Sdfr log_status("gss_verify_mic", NULL, maj_stat, min_stat); 194181344Sdfr return (FALSE); 195181344Sdfr } 196181344Sdfr } else if (svc == rpc_gss_svc_privacy) { 197181344Sdfr /* Decode databody_priv. */ 198181344Sdfr if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) { 199181344Sdfr log_debug("xdr decode databody_priv failed"); 200181344Sdfr return (FALSE); 201181344Sdfr } 202181344Sdfr /* Decrypt databody. */ 203181344Sdfr maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf, 204181344Sdfr &conf_state, &qop_state); 205181344Sdfr 206181344Sdfr mem_free(wrapbuf.value, wrapbuf.length); 207181344Sdfr 208181344Sdfr /* Verify encryption and QOP. */ 209181344Sdfr if (maj_stat != GSS_S_COMPLETE || qop_state != qop || 210181344Sdfr conf_state != TRUE) { 211181344Sdfr gss_release_buffer(&min_stat, &databuf); 212181344Sdfr log_status("gss_unwrap", NULL, maj_stat, min_stat); 213181344Sdfr return (FALSE); 214181344Sdfr } 215181344Sdfr } 216181344Sdfr /* Decode rpc_gss_data_t (sequence number + arguments). */ 217181344Sdfr xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE); 218181344Sdfr xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) && 219181344Sdfr xdr_func(&tmpxdrs, xdr_ptr)); 220181344Sdfr XDR_DESTROY(&tmpxdrs); 221181344Sdfr 222181344Sdfr /* 223181344Sdfr * Integrity service allocates databuf via XDR so free it the 224181344Sdfr * same way. 225181344Sdfr */ 226181344Sdfr if (svc == rpc_gss_svc_integrity) { 227181344Sdfr xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &databuf); 228181344Sdfr } else { 229181344Sdfr gss_release_buffer(&min_stat, &databuf); 230181344Sdfr } 231181344Sdfr 232181344Sdfr /* Verify sequence number. */ 233181344Sdfr if (xdr_stat == TRUE && seq_num != seq) { 234181344Sdfr log_debug("wrong sequence number in databody"); 235181344Sdfr return (FALSE); 236181344Sdfr } 237181344Sdfr return (xdr_stat); 238181344Sdfr} 239181344Sdfr 240181344Sdfr#ifdef DEBUG 241181344Sdfr#include <ctype.h> 242181344Sdfr 243181344Sdfrvoid 244181344Sdfrlog_debug(const char *fmt, ...) 245181344Sdfr{ 246181344Sdfr va_list ap; 247181344Sdfr 248181344Sdfr va_start(ap, fmt); 249181344Sdfr fprintf(stderr, "rpcsec_gss: "); 250181344Sdfr vfprintf(stderr, fmt, ap); 251181344Sdfr fprintf(stderr, "\n"); 252181344Sdfr va_end(ap); 253181344Sdfr} 254181344Sdfr 255181344Sdfrvoid 256181344Sdfrlog_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat) 257181344Sdfr{ 258181344Sdfr OM_uint32 min; 259181344Sdfr gss_buffer_desc msg; 260181344Sdfr int msg_ctx = 0; 261181344Sdfr 262181344Sdfr fprintf(stderr, "rpcsec_gss: %s: ", m); 263181344Sdfr 264181344Sdfr gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, 265181344Sdfr &msg_ctx, &msg); 266181344Sdfr fprintf(stderr, "%s - ", (char *)msg.value); 267181344Sdfr gss_release_buffer(&min, &msg); 268181344Sdfr 269181344Sdfr gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech, 270181344Sdfr &msg_ctx, &msg); 271181344Sdfr fprintf(stderr, "%s\n", (char *)msg.value); 272181344Sdfr gss_release_buffer(&min, &msg); 273181344Sdfr} 274181344Sdfr 275181344Sdfr#else 276181344Sdfr 277181344Sdfrvoid 278181344Sdfrlog_debug(__unused const char *fmt, ...) 279181344Sdfr{ 280181344Sdfr} 281181344Sdfr 282181344Sdfrvoid 283181344Sdfrlog_status(__unused const char *m, __unused gss_OID mech, 284181344Sdfr __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat) 285181344Sdfr{ 286181344Sdfr} 287181344Sdfr 288181344Sdfr#endif 289181344Sdfr 290181344Sdfr 291