1184588Sdfr/* 2184588Sdfr rpcsec_gss_prot.c 3184588Sdfr 4184588Sdfr Copyright (c) 2000 The Regents of the University of Michigan. 5184588Sdfr All rights reserved. 6184588Sdfr 7184588Sdfr Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>. 8184588Sdfr All rights reserved, all wrongs reversed. 9184588Sdfr 10184588Sdfr Redistribution and use in source and binary forms, with or without 11184588Sdfr modification, are permitted provided that the following conditions 12184588Sdfr are met: 13184588Sdfr 14184588Sdfr 1. Redistributions of source code must retain the above copyright 15184588Sdfr notice, this list of conditions and the following disclaimer. 16184588Sdfr 2. Redistributions in binary form must reproduce the above copyright 17184588Sdfr notice, this list of conditions and the following disclaimer in the 18184588Sdfr documentation and/or other materials provided with the distribution. 19184588Sdfr 3. Neither the name of the University nor the names of its 20184588Sdfr contributors may be used to endorse or promote products derived 21184588Sdfr from this software without specific prior written permission. 22184588Sdfr 23184588Sdfr THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 24184588Sdfr WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25184588Sdfr MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26184588Sdfr DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27184588Sdfr FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28184588Sdfr CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29184588Sdfr SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 30184588Sdfr BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31184588Sdfr LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32184588Sdfr NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33184588Sdfr SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34184588Sdfr 35184588Sdfr $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $ 36184588Sdfr*/ 37184588Sdfr 38184588Sdfr#include <sys/cdefs.h> 39184588Sdfr__FBSDID("$FreeBSD$"); 40184588Sdfr 41184588Sdfr#include <sys/param.h> 42184588Sdfr#include <sys/systm.h> 43184588Sdfr#include <sys/kobj.h> 44184588Sdfr#include <sys/lock.h> 45184588Sdfr#include <sys/malloc.h> 46184588Sdfr#include <sys/mbuf.h> 47184588Sdfr#include <sys/mutex.h> 48184588Sdfr 49184588Sdfr#include <rpc/rpc.h> 50184588Sdfr#include <rpc/rpcsec_gss.h> 51184588Sdfr 52184588Sdfr#include "rpcsec_gss_int.h" 53184588Sdfr 54184588Sdfr#define MAX_GSS_SIZE 10240 /* XXX */ 55184588Sdfr 56184588Sdfr#if 0 /* use the one from kgssapi */ 57184588Sdfrbool_t 58184588Sdfrxdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p) 59184588Sdfr{ 60184588Sdfr char *val; 61184588Sdfr u_int len; 62184588Sdfr bool_t ret; 63184588Sdfr 64184588Sdfr val = p->value; 65184588Sdfr len = p->length; 66184588Sdfr ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE); 67184588Sdfr p->value = val; 68184588Sdfr p->length = len; 69184588Sdfr 70184588Sdfr return (ret); 71184588Sdfr} 72184588Sdfr#endif 73184588Sdfr 74184588Sdfrbool_t 75184588Sdfrxdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p) 76184588Sdfr{ 77184588Sdfr enum_t proc, svc; 78184588Sdfr bool_t ret; 79184588Sdfr 80184588Sdfr proc = p->gc_proc; 81184588Sdfr svc = p->gc_svc; 82184588Sdfr ret = (xdr_u_int(xdrs, &p->gc_version) && 83184588Sdfr xdr_enum(xdrs, &proc) && 84184588Sdfr xdr_u_int(xdrs, &p->gc_seq) && 85184588Sdfr xdr_enum(xdrs, &svc) && 86184588Sdfr xdr_gss_buffer_desc(xdrs, &p->gc_handle)); 87184588Sdfr p->gc_proc = proc; 88184588Sdfr p->gc_svc = svc; 89184588Sdfr 90184588Sdfr return (ret); 91184588Sdfr} 92184588Sdfr 93184588Sdfrbool_t 94184588Sdfrxdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p) 95184588Sdfr{ 96184588Sdfr 97184588Sdfr return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) && 98184588Sdfr xdr_u_int(xdrs, &p->gr_major) && 99184588Sdfr xdr_u_int(xdrs, &p->gr_minor) && 100184588Sdfr xdr_u_int(xdrs, &p->gr_win) && 101184588Sdfr xdr_gss_buffer_desc(xdrs, &p->gr_token)); 102184588Sdfr} 103184588Sdfr 104184588Sdfrstatic void 105184588Sdfrput_uint32(struct mbuf **mp, uint32_t v) 106184588Sdfr{ 107184588Sdfr struct mbuf *m = *mp; 108184588Sdfr uint32_t n; 109184588Sdfr 110243882Sglebius M_PREPEND(m, sizeof(uint32_t), M_WAITOK); 111184588Sdfr n = htonl(v); 112184588Sdfr bcopy(&n, mtod(m, uint32_t *), sizeof(uint32_t)); 113184588Sdfr *mp = m; 114184588Sdfr} 115184588Sdfr 116184588Sdfrbool_t 117184588Sdfrxdr_rpc_gss_wrap_data(struct mbuf **argsp, 118184588Sdfr gss_ctx_id_t ctx, gss_qop_t qop, 119184588Sdfr rpc_gss_service_t svc, u_int seq) 120184588Sdfr{ 121184588Sdfr struct mbuf *args, *mic; 122184588Sdfr OM_uint32 maj_stat, min_stat; 123184588Sdfr int conf_state; 124184588Sdfr u_int len; 125184588Sdfr static char zpad[4]; 126184588Sdfr 127184588Sdfr args = *argsp; 128184588Sdfr 129184588Sdfr /* 130184588Sdfr * Prepend the sequence number before calling gss_get_mic or gss_wrap. 131184588Sdfr */ 132184588Sdfr put_uint32(&args, seq); 133184588Sdfr len = m_length(args, NULL); 134184588Sdfr 135184588Sdfr if (svc == rpc_gss_svc_integrity) { 136184588Sdfr /* Checksum rpc_gss_data_t. */ 137184588Sdfr maj_stat = gss_get_mic_mbuf(&min_stat, ctx, qop, args, &mic); 138184588Sdfr if (maj_stat != GSS_S_COMPLETE) { 139184588Sdfr rpc_gss_log_debug("gss_get_mic failed"); 140184588Sdfr m_freem(args); 141184588Sdfr return (FALSE); 142184588Sdfr } 143184588Sdfr 144184588Sdfr /* 145184588Sdfr * Marshal databody_integ. Note that since args is 146184588Sdfr * already RPC encoded, there will be no padding. 147184588Sdfr */ 148184588Sdfr put_uint32(&args, len); 149184588Sdfr 150184588Sdfr /* 151184588Sdfr * Marshal checksum. This is likely to need padding. 152184588Sdfr */ 153184588Sdfr len = m_length(mic, NULL); 154184588Sdfr put_uint32(&mic, len); 155184588Sdfr if (len != RNDUP(len)) { 156184588Sdfr m_append(mic, RNDUP(len) - len, zpad); 157184588Sdfr } 158184588Sdfr 159184588Sdfr /* 160184588Sdfr * Concatenate databody_integ with checksum. 161184588Sdfr */ 162184588Sdfr m_cat(args, mic); 163184588Sdfr } else if (svc == rpc_gss_svc_privacy) { 164184588Sdfr /* Encrypt rpc_gss_data_t. */ 165184588Sdfr maj_stat = gss_wrap_mbuf(&min_stat, ctx, TRUE, qop, 166184588Sdfr &args, &conf_state); 167184588Sdfr if (maj_stat != GSS_S_COMPLETE) { 168184588Sdfr rpc_gss_log_status("gss_wrap", NULL, 169184588Sdfr maj_stat, min_stat); 170184588Sdfr return (FALSE); 171184588Sdfr } 172184588Sdfr 173184588Sdfr /* 174184588Sdfr * Marshal databody_priv and deal with RPC padding. 175184588Sdfr */ 176184588Sdfr len = m_length(args, NULL); 177184588Sdfr put_uint32(&args, len); 178184588Sdfr if (len != RNDUP(len)) { 179184588Sdfr m_append(args, RNDUP(len) - len, zpad); 180184588Sdfr } 181184588Sdfr } 182184588Sdfr *argsp = args; 183184588Sdfr return (TRUE); 184184588Sdfr} 185184588Sdfr 186184588Sdfrstatic uint32_t 187184588Sdfrget_uint32(struct mbuf **mp) 188184588Sdfr{ 189184588Sdfr struct mbuf *m = *mp; 190184588Sdfr uint32_t n; 191184588Sdfr 192184588Sdfr if (m->m_len < sizeof(uint32_t)) { 193184588Sdfr m = m_pullup(m, sizeof(uint32_t)); 194184588Sdfr if (!m) { 195184588Sdfr *mp = NULL; 196184588Sdfr return (0); 197184588Sdfr } 198184588Sdfr } 199184588Sdfr bcopy(mtod(m, uint32_t *), &n, sizeof(uint32_t)); 200184588Sdfr m_adj(m, sizeof(uint32_t)); 201184588Sdfr *mp = m; 202184588Sdfr return (ntohl(n)); 203184588Sdfr} 204184588Sdfr 205184588Sdfrstatic void 206184588Sdfrm_trim(struct mbuf *m, int len) 207184588Sdfr{ 208184588Sdfr struct mbuf *n; 209184588Sdfr int off; 210184588Sdfr 211249096Sgnn if (m == NULL) 212249096Sgnn return; 213184588Sdfr n = m_getptr(m, len, &off); 214184588Sdfr if (n) { 215184588Sdfr n->m_len = off; 216184588Sdfr if (n->m_next) { 217184588Sdfr m_freem(n->m_next); 218184588Sdfr n->m_next = NULL; 219184588Sdfr } 220184588Sdfr } 221184588Sdfr} 222184588Sdfr 223184588Sdfrbool_t 224184588Sdfrxdr_rpc_gss_unwrap_data(struct mbuf **resultsp, 225184588Sdfr gss_ctx_id_t ctx, gss_qop_t qop, 226184588Sdfr rpc_gss_service_t svc, u_int seq) 227184588Sdfr{ 228184588Sdfr struct mbuf *results, *message, *mic; 229184588Sdfr uint32_t len, cklen; 230184588Sdfr OM_uint32 maj_stat, min_stat; 231184588Sdfr u_int seq_num, conf_state, qop_state; 232184588Sdfr 233184588Sdfr results = *resultsp; 234184588Sdfr *resultsp = NULL; 235184588Sdfr 236184588Sdfr message = NULL; 237184588Sdfr if (svc == rpc_gss_svc_integrity) { 238184588Sdfr /* 239184588Sdfr * Extract the seq+message part. Remember that there 240184588Sdfr * may be extra RPC padding in the checksum. The 241184588Sdfr * message part is RPC encoded already so no 242184588Sdfr * padding. 243184588Sdfr */ 244184588Sdfr len = get_uint32(&results); 245184588Sdfr message = results; 246243882Sglebius results = m_split(results, len, M_WAITOK); 247184588Sdfr if (!results) { 248184588Sdfr m_freem(message); 249184588Sdfr return (FALSE); 250184588Sdfr } 251184588Sdfr 252184588Sdfr /* 253184588Sdfr * Extract the MIC and make it contiguous. 254184588Sdfr */ 255184588Sdfr cklen = get_uint32(&results); 256249096Sgnn if (!results) { 257249096Sgnn m_freem(message); 258249096Sgnn return (FALSE); 259249096Sgnn } 260184588Sdfr KASSERT(cklen <= MHLEN, ("unexpected large GSS-API checksum")); 261184588Sdfr mic = results; 262249096Sgnn if (cklen > mic->m_len) { 263184588Sdfr mic = m_pullup(mic, cklen); 264249096Sgnn if (!mic) { 265249096Sgnn m_freem(message); 266249096Sgnn return (FALSE); 267249096Sgnn } 268249096Sgnn } 269184588Sdfr if (cklen != RNDUP(cklen)) 270184588Sdfr m_trim(mic, cklen); 271184588Sdfr 272184588Sdfr /* Verify checksum and QOP. */ 273184588Sdfr maj_stat = gss_verify_mic_mbuf(&min_stat, ctx, 274184588Sdfr message, mic, &qop_state); 275184588Sdfr m_freem(mic); 276184588Sdfr 277184588Sdfr if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { 278184588Sdfr m_freem(message); 279184588Sdfr rpc_gss_log_status("gss_verify_mic", NULL, 280184588Sdfr maj_stat, min_stat); 281184588Sdfr return (FALSE); 282184588Sdfr } 283184588Sdfr } else if (svc == rpc_gss_svc_privacy) { 284184588Sdfr /* Decode databody_priv. */ 285184588Sdfr len = get_uint32(&results); 286249096Sgnn if (!results) 287249096Sgnn return (FALSE); 288184588Sdfr 289184588Sdfr /* Decrypt databody. */ 290184588Sdfr message = results; 291184588Sdfr if (len != RNDUP(len)) 292184588Sdfr m_trim(message, len); 293184588Sdfr maj_stat = gss_unwrap_mbuf(&min_stat, ctx, &message, 294184588Sdfr &conf_state, &qop_state); 295184588Sdfr 296184588Sdfr /* Verify encryption and QOP. */ 297184588Sdfr if (maj_stat != GSS_S_COMPLETE) { 298184588Sdfr rpc_gss_log_status("gss_unwrap", NULL, 299184588Sdfr maj_stat, min_stat); 300184588Sdfr return (FALSE); 301184588Sdfr } 302184588Sdfr if (qop_state != qop || conf_state != TRUE) { 303184588Sdfr m_freem(results); 304184588Sdfr return (FALSE); 305184588Sdfr } 306184588Sdfr } 307184588Sdfr 308184588Sdfr /* Decode rpc_gss_data_t (sequence number + arguments). */ 309184588Sdfr seq_num = get_uint32(&message); 310249096Sgnn if (!message) 311249096Sgnn return (FALSE); 312184588Sdfr 313184588Sdfr /* Verify sequence number. */ 314184588Sdfr if (seq_num != seq) { 315184588Sdfr rpc_gss_log_debug("wrong sequence number in databody"); 316184588Sdfr m_freem(message); 317184588Sdfr return (FALSE); 318184588Sdfr } 319184588Sdfr 320184588Sdfr *resultsp = message; 321184588Sdfr return (TRUE); 322184588Sdfr} 323184588Sdfr 324184588Sdfr#ifdef DEBUG 325201853Sbrooks#include <machine/stdarg.h> 326184588Sdfr 327184588Sdfrvoid 328184588Sdfrrpc_gss_log_debug(const char *fmt, ...) 329184588Sdfr{ 330184588Sdfr va_list ap; 331184588Sdfr 332184588Sdfr va_start(ap, fmt); 333201853Sbrooks printf("rpcsec_gss: "); 334201853Sbrooks vprintf(fmt, ap); 335201853Sbrooks printf("\n"); 336184588Sdfr va_end(ap); 337184588Sdfr} 338184588Sdfr 339184588Sdfrvoid 340184588Sdfrrpc_gss_log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat) 341184588Sdfr{ 342184588Sdfr OM_uint32 min; 343184588Sdfr gss_buffer_desc msg; 344184588Sdfr int msg_ctx = 0; 345184588Sdfr 346201853Sbrooks printf("rpcsec_gss: %s: ", m); 347184588Sdfr 348184588Sdfr gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, 349184588Sdfr &msg_ctx, &msg); 350184588Sdfr printf("%s - ", (char *)msg.value); 351184588Sdfr gss_release_buffer(&min, &msg); 352184588Sdfr 353184588Sdfr gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech, 354184588Sdfr &msg_ctx, &msg); 355184588Sdfr printf("%s\n", (char *)msg.value); 356184588Sdfr gss_release_buffer(&min, &msg); 357184588Sdfr} 358184588Sdfr 359184588Sdfr#else 360184588Sdfr 361184588Sdfrvoid 362184588Sdfrrpc_gss_log_debug(__unused const char *fmt, ...) 363184588Sdfr{ 364184588Sdfr} 365184588Sdfr 366184588Sdfrvoid 367184588Sdfrrpc_gss_log_status(__unused const char *m, __unused gss_OID mech, 368184588Sdfr __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat) 369184588Sdfr{ 370184588Sdfr} 371184588Sdfr 372184588Sdfr#endif 373184588Sdfr 374184588Sdfr 375