18f55a568SDoug Rabson /* 28f55a568SDoug Rabson rpcsec_gss_prot.c 38f55a568SDoug Rabson 48f55a568SDoug Rabson Copyright (c) 2000 The Regents of the University of Michigan. 58f55a568SDoug Rabson All rights reserved. 68f55a568SDoug Rabson 78f55a568SDoug Rabson Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>. 88f55a568SDoug Rabson All rights reserved, all wrongs reversed. 98f55a568SDoug Rabson 108f55a568SDoug Rabson Redistribution and use in source and binary forms, with or without 118f55a568SDoug Rabson modification, are permitted provided that the following conditions 128f55a568SDoug Rabson are met: 138f55a568SDoug Rabson 148f55a568SDoug Rabson 1. Redistributions of source code must retain the above copyright 158f55a568SDoug Rabson notice, this list of conditions and the following disclaimer. 168f55a568SDoug Rabson 2. Redistributions in binary form must reproduce the above copyright 178f55a568SDoug Rabson notice, this list of conditions and the following disclaimer in the 188f55a568SDoug Rabson documentation and/or other materials provided with the distribution. 198f55a568SDoug Rabson 3. Neither the name of the University nor the names of its 208f55a568SDoug Rabson contributors may be used to endorse or promote products derived 218f55a568SDoug Rabson from this software without specific prior written permission. 228f55a568SDoug Rabson 238f55a568SDoug Rabson THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 248f55a568SDoug Rabson WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 258f55a568SDoug Rabson MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 268f55a568SDoug Rabson DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 278f55a568SDoug Rabson FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 288f55a568SDoug Rabson CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 298f55a568SDoug Rabson SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 308f55a568SDoug Rabson BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 318f55a568SDoug Rabson LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 328f55a568SDoug Rabson NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 338f55a568SDoug Rabson SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 348f55a568SDoug Rabson 358f55a568SDoug Rabson $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $ 368f55a568SDoug Rabson */ 378f55a568SDoug Rabson /* $FreeBSD$ */ 388f55a568SDoug Rabson 398f55a568SDoug Rabson #include <stdio.h> 408f55a568SDoug Rabson #include <stdlib.h> 418f55a568SDoug Rabson #include <stdarg.h> 428f55a568SDoug Rabson #include <string.h> 438f55a568SDoug Rabson #include <rpc/rpc.h> 448f55a568SDoug Rabson #include <rpc/rpcsec_gss.h> 458f55a568SDoug Rabson #include "rpcsec_gss_int.h" 468f55a568SDoug Rabson 478f55a568SDoug Rabson #define MAX_GSS_SIZE 10240 /* XXX */ 488f55a568SDoug Rabson 498f55a568SDoug Rabson bool_t 508f55a568SDoug Rabson xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p) 518f55a568SDoug Rabson { 528f55a568SDoug Rabson char *val; 538f55a568SDoug Rabson u_int len; 548f55a568SDoug Rabson bool_t ret; 558f55a568SDoug Rabson 568f55a568SDoug Rabson val = p->value; 578f55a568SDoug Rabson len = p->length; 588f55a568SDoug Rabson ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE); 598f55a568SDoug Rabson p->value = val; 608f55a568SDoug Rabson p->length = len; 618f55a568SDoug Rabson 628f55a568SDoug Rabson return (ret); 638f55a568SDoug Rabson } 648f55a568SDoug Rabson 658f55a568SDoug Rabson bool_t 668f55a568SDoug Rabson xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p) 678f55a568SDoug Rabson { 688f55a568SDoug Rabson enum_t proc, svc; 698f55a568SDoug Rabson bool_t ret; 708f55a568SDoug Rabson 718f55a568SDoug Rabson proc = p->gc_proc; 728f55a568SDoug Rabson svc = p->gc_svc; 738f55a568SDoug Rabson ret = (xdr_u_int(xdrs, &p->gc_version) && 748f55a568SDoug Rabson xdr_enum(xdrs, &proc) && 758f55a568SDoug Rabson xdr_u_int(xdrs, &p->gc_seq) && 768f55a568SDoug Rabson xdr_enum(xdrs, &svc) && 778f55a568SDoug Rabson xdr_gss_buffer_desc(xdrs, &p->gc_handle)); 788f55a568SDoug Rabson p->gc_proc = proc; 798f55a568SDoug Rabson p->gc_svc = svc; 808f55a568SDoug Rabson 818f55a568SDoug Rabson return (ret); 828f55a568SDoug Rabson } 838f55a568SDoug Rabson 848f55a568SDoug Rabson bool_t 858f55a568SDoug Rabson xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p) 868f55a568SDoug Rabson { 878f55a568SDoug Rabson 888f55a568SDoug Rabson return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) && 898f55a568SDoug Rabson xdr_u_int(xdrs, &p->gr_major) && 908f55a568SDoug Rabson xdr_u_int(xdrs, &p->gr_minor) && 918f55a568SDoug Rabson xdr_u_int(xdrs, &p->gr_win) && 928f55a568SDoug Rabson xdr_gss_buffer_desc(xdrs, &p->gr_token)); 938f55a568SDoug Rabson } 948f55a568SDoug Rabson 958f55a568SDoug Rabson bool_t 968f55a568SDoug Rabson xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, 978f55a568SDoug Rabson gss_ctx_id_t ctx, gss_qop_t qop, 988f55a568SDoug Rabson rpc_gss_service_t svc, u_int seq) 998f55a568SDoug Rabson { 1008f55a568SDoug Rabson gss_buffer_desc databuf, wrapbuf; 1018f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 1028f55a568SDoug Rabson int start, end, conf_state; 1038f55a568SDoug Rabson bool_t xdr_stat; 1048f55a568SDoug Rabson 1058f55a568SDoug Rabson /* Skip databody length. */ 1068f55a568SDoug Rabson start = XDR_GETPOS(xdrs); 1078f55a568SDoug Rabson XDR_SETPOS(xdrs, start + 4); 1088f55a568SDoug Rabson 1098f55a568SDoug Rabson /* Marshal rpc_gss_data_t (sequence number + arguments). */ 1108f55a568SDoug Rabson if (!xdr_u_int(xdrs, &seq) || !xdr_func(xdrs, xdr_ptr)) 1118f55a568SDoug Rabson return (FALSE); 1128f55a568SDoug Rabson end = XDR_GETPOS(xdrs); 1138f55a568SDoug Rabson 1148f55a568SDoug Rabson /* Set databuf to marshalled rpc_gss_data_t. */ 1158f55a568SDoug Rabson databuf.length = end - start - 4; 1168f55a568SDoug Rabson XDR_SETPOS(xdrs, start + 4); 1178f55a568SDoug Rabson databuf.value = XDR_INLINE(xdrs, databuf.length); 1188f55a568SDoug Rabson 1198f55a568SDoug Rabson xdr_stat = FALSE; 1208f55a568SDoug Rabson 1218f55a568SDoug Rabson if (svc == rpc_gss_svc_integrity) { 1228f55a568SDoug Rabson /* Marshal databody_integ length. */ 1238f55a568SDoug Rabson XDR_SETPOS(xdrs, start); 1248f55a568SDoug Rabson if (!xdr_u_int(xdrs, &databuf.length)) 1258f55a568SDoug Rabson return (FALSE); 1268f55a568SDoug Rabson 1278f55a568SDoug Rabson /* Checksum rpc_gss_data_t. */ 1288f55a568SDoug Rabson maj_stat = gss_get_mic(&min_stat, ctx, qop, 1298f55a568SDoug Rabson &databuf, &wrapbuf); 1308f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 1318f55a568SDoug Rabson log_debug("gss_get_mic failed"); 1328f55a568SDoug Rabson return (FALSE); 1338f55a568SDoug Rabson } 1348f55a568SDoug Rabson /* Marshal checksum. */ 1358f55a568SDoug Rabson XDR_SETPOS(xdrs, end); 1368f55a568SDoug Rabson xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); 1378f55a568SDoug Rabson gss_release_buffer(&min_stat, &wrapbuf); 1388f55a568SDoug Rabson } 1398f55a568SDoug Rabson else if (svc == rpc_gss_svc_privacy) { 1408f55a568SDoug Rabson /* Encrypt rpc_gss_data_t. */ 1418f55a568SDoug Rabson maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, 1428f55a568SDoug Rabson &conf_state, &wrapbuf); 1438f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 1448f55a568SDoug Rabson log_status("gss_wrap", NULL, maj_stat, min_stat); 1458f55a568SDoug Rabson return (FALSE); 1468f55a568SDoug Rabson } 1478f55a568SDoug Rabson /* Marshal databody_priv. */ 1488f55a568SDoug Rabson XDR_SETPOS(xdrs, start); 1498f55a568SDoug Rabson xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); 1508f55a568SDoug Rabson gss_release_buffer(&min_stat, &wrapbuf); 1518f55a568SDoug Rabson } 1528f55a568SDoug Rabson return (xdr_stat); 1538f55a568SDoug Rabson } 1548f55a568SDoug Rabson 1558f55a568SDoug Rabson bool_t 1568f55a568SDoug Rabson xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, 1578f55a568SDoug Rabson gss_ctx_id_t ctx, gss_qop_t qop, 1588f55a568SDoug Rabson rpc_gss_service_t svc, u_int seq) 1598f55a568SDoug Rabson { 1608f55a568SDoug Rabson XDR tmpxdrs; 1618f55a568SDoug Rabson gss_buffer_desc databuf, wrapbuf; 1628f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 1638f55a568SDoug Rabson u_int seq_num, conf_state, qop_state; 1648f55a568SDoug Rabson bool_t xdr_stat; 1658f55a568SDoug Rabson 1668f55a568SDoug Rabson if (xdr_func == (xdrproc_t) xdr_void || xdr_ptr == NULL) 1678f55a568SDoug Rabson return (TRUE); 1688f55a568SDoug Rabson 1698f55a568SDoug Rabson memset(&databuf, 0, sizeof(databuf)); 1708f55a568SDoug Rabson memset(&wrapbuf, 0, sizeof(wrapbuf)); 1718f55a568SDoug Rabson 1728f55a568SDoug Rabson if (svc == rpc_gss_svc_integrity) { 1738f55a568SDoug Rabson /* Decode databody_integ. */ 1748f55a568SDoug Rabson if (!xdr_gss_buffer_desc(xdrs, &databuf)) { 1758f55a568SDoug Rabson log_debug("xdr decode databody_integ failed"); 1768f55a568SDoug Rabson return (FALSE); 1778f55a568SDoug Rabson } 1788f55a568SDoug Rabson /* Decode checksum. */ 1798f55a568SDoug Rabson if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) { 1808f55a568SDoug Rabson mem_free(databuf.value, databuf.length); 1818f55a568SDoug Rabson log_debug("xdr decode checksum failed"); 1828f55a568SDoug Rabson return (FALSE); 1838f55a568SDoug Rabson } 1848f55a568SDoug Rabson /* Verify checksum and QOP. */ 1858f55a568SDoug Rabson maj_stat = gss_verify_mic(&min_stat, ctx, &databuf, 1868f55a568SDoug Rabson &wrapbuf, &qop_state); 1878f55a568SDoug Rabson mem_free(wrapbuf.value, wrapbuf.length); 1888f55a568SDoug Rabson 1898f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { 1908f55a568SDoug Rabson mem_free(databuf.value, databuf.length); 1918f55a568SDoug Rabson log_status("gss_verify_mic", NULL, maj_stat, min_stat); 1928f55a568SDoug Rabson return (FALSE); 1938f55a568SDoug Rabson } 1948f55a568SDoug Rabson } else if (svc == rpc_gss_svc_privacy) { 1958f55a568SDoug Rabson /* Decode databody_priv. */ 1968f55a568SDoug Rabson if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) { 1978f55a568SDoug Rabson log_debug("xdr decode databody_priv failed"); 1988f55a568SDoug Rabson return (FALSE); 1998f55a568SDoug Rabson } 2008f55a568SDoug Rabson /* Decrypt databody. */ 2018f55a568SDoug Rabson maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf, 2028f55a568SDoug Rabson &conf_state, &qop_state); 2038f55a568SDoug Rabson 2048f55a568SDoug Rabson mem_free(wrapbuf.value, wrapbuf.length); 2058f55a568SDoug Rabson 2068f55a568SDoug Rabson /* Verify encryption and QOP. */ 2078f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE || qop_state != qop || 2088f55a568SDoug Rabson conf_state != TRUE) { 2098f55a568SDoug Rabson gss_release_buffer(&min_stat, &databuf); 2108f55a568SDoug Rabson log_status("gss_unwrap", NULL, maj_stat, min_stat); 2118f55a568SDoug Rabson return (FALSE); 2128f55a568SDoug Rabson } 2138f55a568SDoug Rabson } 2148f55a568SDoug Rabson /* Decode rpc_gss_data_t (sequence number + arguments). */ 2158f55a568SDoug Rabson xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE); 2168f55a568SDoug Rabson xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) && 2178f55a568SDoug Rabson xdr_func(&tmpxdrs, xdr_ptr)); 2188f55a568SDoug Rabson XDR_DESTROY(&tmpxdrs); 2198f55a568SDoug Rabson 2208f55a568SDoug Rabson /* 2218f55a568SDoug Rabson * Integrity service allocates databuf via XDR so free it the 2228f55a568SDoug Rabson * same way. 2238f55a568SDoug Rabson */ 2248f55a568SDoug Rabson if (svc == rpc_gss_svc_integrity) { 2258f55a568SDoug Rabson xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &databuf); 2268f55a568SDoug Rabson } else { 2278f55a568SDoug Rabson gss_release_buffer(&min_stat, &databuf); 2288f55a568SDoug Rabson } 2298f55a568SDoug Rabson 2308f55a568SDoug Rabson /* Verify sequence number. */ 2318f55a568SDoug Rabson if (xdr_stat == TRUE && seq_num != seq) { 2328f55a568SDoug Rabson log_debug("wrong sequence number in databody"); 2338f55a568SDoug Rabson return (FALSE); 2348f55a568SDoug Rabson } 2358f55a568SDoug Rabson return (xdr_stat); 2368f55a568SDoug Rabson } 2378f55a568SDoug Rabson 2388f55a568SDoug Rabson #ifdef DEBUG 2398f55a568SDoug Rabson #include <ctype.h> 2408f55a568SDoug Rabson 2418f55a568SDoug Rabson void 2428f55a568SDoug Rabson log_debug(const char *fmt, ...) 2438f55a568SDoug Rabson { 2448f55a568SDoug Rabson va_list ap; 2458f55a568SDoug Rabson 2468f55a568SDoug Rabson va_start(ap, fmt); 2478f55a568SDoug Rabson fprintf(stderr, "rpcsec_gss: "); 2488f55a568SDoug Rabson vfprintf(stderr, fmt, ap); 2498f55a568SDoug Rabson fprintf(stderr, "\n"); 2508f55a568SDoug Rabson va_end(ap); 2518f55a568SDoug Rabson } 2528f55a568SDoug Rabson 2538f55a568SDoug Rabson void 2548f55a568SDoug Rabson log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat) 2558f55a568SDoug Rabson { 2568f55a568SDoug Rabson OM_uint32 min; 2578f55a568SDoug Rabson gss_buffer_desc msg; 2588f55a568SDoug Rabson int msg_ctx = 0; 2598f55a568SDoug Rabson 2608f55a568SDoug Rabson fprintf(stderr, "rpcsec_gss: %s: ", m); 2618f55a568SDoug Rabson 2628f55a568SDoug Rabson gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, 2638f55a568SDoug Rabson &msg_ctx, &msg); 2648f55a568SDoug Rabson fprintf(stderr, "%s - ", (char *)msg.value); 2658f55a568SDoug Rabson gss_release_buffer(&min, &msg); 2668f55a568SDoug Rabson 2678f55a568SDoug Rabson gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech, 2688f55a568SDoug Rabson &msg_ctx, &msg); 2698f55a568SDoug Rabson fprintf(stderr, "%s\n", (char *)msg.value); 2708f55a568SDoug Rabson gss_release_buffer(&min, &msg); 2718f55a568SDoug Rabson } 2728f55a568SDoug Rabson 2738f55a568SDoug Rabson #else 2748f55a568SDoug Rabson 2758f55a568SDoug Rabson void 2768f55a568SDoug Rabson log_debug(__unused const char *fmt, ...) 2778f55a568SDoug Rabson { 2788f55a568SDoug Rabson } 2798f55a568SDoug Rabson 2808f55a568SDoug Rabson void 2818f55a568SDoug Rabson log_status(__unused const char *m, __unused gss_OID mech, 2828f55a568SDoug Rabson __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat) 2838f55a568SDoug Rabson { 2848f55a568SDoug Rabson } 2858f55a568SDoug Rabson 2868f55a568SDoug Rabson #endif 2878f55a568SDoug Rabson 2888f55a568SDoug Rabson 289