1 /* 2 SPDX-License-Identifier: BSD-3-Clause 3 4 rpcsec_gss_prot.c 5 6 Copyright (c) 2000 The Regents of the University of Michigan. 7 All rights reserved. 8 9 Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>. 10 All rights reserved, all wrongs reversed. 11 12 Redistribution and use in source and binary forms, with or without 13 modification, are permitted provided that the following conditions 14 are met: 15 16 1. Redistributions of source code must retain the above copyright 17 notice, this list of conditions and the following disclaimer. 18 2. Redistributions in binary form must reproduce the above copyright 19 notice, this list of conditions and the following disclaimer in the 20 documentation and/or other materials provided with the distribution. 21 3. Neither the name of the University nor the names of its 22 contributors may be used to endorse or promote products derived 23 from this software without specific prior written permission. 24 25 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 26 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 32 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 37 $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $ 38 */ 39 /* $FreeBSD$ */ 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <stdarg.h> 44 #include <string.h> 45 #include <rpc/rpc.h> 46 #include <rpc/rpcsec_gss.h> 47 #include "rpcsec_gss_int.h" 48 49 #define MAX_GSS_SIZE 10240 /* XXX */ 50 51 bool_t 52 xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p) 53 { 54 char *val; 55 u_int len; 56 bool_t ret; 57 58 val = p->value; 59 len = p->length; 60 ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE); 61 p->value = val; 62 p->length = len; 63 64 return (ret); 65 } 66 67 bool_t 68 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p) 69 { 70 enum_t proc, svc; 71 bool_t ret; 72 73 proc = p->gc_proc; 74 svc = p->gc_svc; 75 ret = (xdr_u_int(xdrs, &p->gc_version) && 76 xdr_enum(xdrs, &proc) && 77 xdr_u_int(xdrs, &p->gc_seq) && 78 xdr_enum(xdrs, &svc) && 79 xdr_gss_buffer_desc(xdrs, &p->gc_handle)); 80 p->gc_proc = proc; 81 p->gc_svc = svc; 82 83 return (ret); 84 } 85 86 bool_t 87 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p) 88 { 89 90 return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) && 91 xdr_u_int(xdrs, &p->gr_major) && 92 xdr_u_int(xdrs, &p->gr_minor) && 93 xdr_u_int(xdrs, &p->gr_win) && 94 xdr_gss_buffer_desc(xdrs, &p->gr_token)); 95 } 96 97 bool_t 98 xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, 99 gss_ctx_id_t ctx, gss_qop_t qop, 100 rpc_gss_service_t svc, u_int seq) 101 { 102 gss_buffer_desc databuf, wrapbuf; 103 OM_uint32 maj_stat, min_stat; 104 int start, end, conf_state; 105 u_int len; 106 bool_t xdr_stat; 107 108 /* Skip databody length. */ 109 start = XDR_GETPOS(xdrs); 110 XDR_SETPOS(xdrs, start + 4); 111 112 /* Marshal rpc_gss_data_t (sequence number + arguments). */ 113 if (!xdr_u_int(xdrs, &seq) || !xdr_func(xdrs, xdr_ptr)) 114 return (FALSE); 115 end = XDR_GETPOS(xdrs); 116 117 /* Set databuf to marshalled rpc_gss_data_t. */ 118 databuf.length = end - start - 4; 119 XDR_SETPOS(xdrs, start + 4); 120 databuf.value = XDR_INLINE(xdrs, databuf.length); 121 122 xdr_stat = FALSE; 123 124 if (svc == rpc_gss_svc_integrity) { 125 /* Marshal databody_integ length. */ 126 XDR_SETPOS(xdrs, start); 127 len = databuf.length; 128 if (!xdr_u_int(xdrs, &len)) 129 return (FALSE); 130 131 /* Checksum rpc_gss_data_t. */ 132 maj_stat = gss_get_mic(&min_stat, ctx, qop, 133 &databuf, &wrapbuf); 134 if (maj_stat != GSS_S_COMPLETE) { 135 log_debug("gss_get_mic failed"); 136 return (FALSE); 137 } 138 /* Marshal checksum. */ 139 XDR_SETPOS(xdrs, end); 140 xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); 141 gss_release_buffer(&min_stat, &wrapbuf); 142 } 143 else if (svc == rpc_gss_svc_privacy) { 144 /* Encrypt rpc_gss_data_t. */ 145 maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, 146 &conf_state, &wrapbuf); 147 if (maj_stat != GSS_S_COMPLETE) { 148 log_status("gss_wrap", NULL, maj_stat, min_stat); 149 return (FALSE); 150 } 151 /* Marshal databody_priv. */ 152 XDR_SETPOS(xdrs, start); 153 xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); 154 gss_release_buffer(&min_stat, &wrapbuf); 155 } 156 return (xdr_stat); 157 } 158 159 bool_t 160 xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, 161 gss_ctx_id_t ctx, gss_qop_t qop, 162 rpc_gss_service_t svc, u_int seq) 163 { 164 XDR tmpxdrs; 165 gss_buffer_desc databuf, wrapbuf; 166 OM_uint32 maj_stat, min_stat; 167 u_int seq_num, conf_state, qop_state; 168 bool_t xdr_stat; 169 170 if (xdr_func == (xdrproc_t) xdr_void || xdr_ptr == NULL) 171 return (TRUE); 172 173 memset(&databuf, 0, sizeof(databuf)); 174 memset(&wrapbuf, 0, sizeof(wrapbuf)); 175 176 if (svc == rpc_gss_svc_integrity) { 177 /* Decode databody_integ. */ 178 if (!xdr_gss_buffer_desc(xdrs, &databuf)) { 179 log_debug("xdr decode databody_integ failed"); 180 return (FALSE); 181 } 182 /* Decode checksum. */ 183 if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) { 184 mem_free(databuf.value, databuf.length); 185 log_debug("xdr decode checksum failed"); 186 return (FALSE); 187 } 188 /* Verify checksum and QOP. */ 189 maj_stat = gss_verify_mic(&min_stat, ctx, &databuf, 190 &wrapbuf, &qop_state); 191 mem_free(wrapbuf.value, wrapbuf.length); 192 193 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { 194 mem_free(databuf.value, databuf.length); 195 log_status("gss_verify_mic", NULL, maj_stat, min_stat); 196 return (FALSE); 197 } 198 } else if (svc == rpc_gss_svc_privacy) { 199 /* Decode databody_priv. */ 200 if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) { 201 log_debug("xdr decode databody_priv failed"); 202 return (FALSE); 203 } 204 /* Decrypt databody. */ 205 maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf, 206 &conf_state, &qop_state); 207 208 mem_free(wrapbuf.value, wrapbuf.length); 209 210 /* Verify encryption and QOP. */ 211 if (maj_stat != GSS_S_COMPLETE || qop_state != qop || 212 conf_state != TRUE) { 213 gss_release_buffer(&min_stat, &databuf); 214 log_status("gss_unwrap", NULL, maj_stat, min_stat); 215 return (FALSE); 216 } 217 } 218 /* Decode rpc_gss_data_t (sequence number + arguments). */ 219 xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE); 220 xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) && 221 xdr_func(&tmpxdrs, xdr_ptr)); 222 XDR_DESTROY(&tmpxdrs); 223 224 /* 225 * Integrity service allocates databuf via XDR so free it the 226 * same way. 227 */ 228 if (svc == rpc_gss_svc_integrity) { 229 xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &databuf); 230 } else { 231 gss_release_buffer(&min_stat, &databuf); 232 } 233 234 /* Verify sequence number. */ 235 if (xdr_stat == TRUE && seq_num != seq) { 236 log_debug("wrong sequence number in databody"); 237 return (FALSE); 238 } 239 return (xdr_stat); 240 } 241 242 #ifdef DEBUG 243 #include <ctype.h> 244 245 void 246 log_debug(const char *fmt, ...) 247 { 248 va_list ap; 249 250 va_start(ap, fmt); 251 fprintf(stderr, "rpcsec_gss: "); 252 vfprintf(stderr, fmt, ap); 253 fprintf(stderr, "\n"); 254 va_end(ap); 255 } 256 257 void 258 log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat) 259 { 260 OM_uint32 min; 261 gss_buffer_desc msg; 262 int msg_ctx = 0; 263 264 fprintf(stderr, "rpcsec_gss: %s: ", m); 265 266 gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, 267 &msg_ctx, &msg); 268 fprintf(stderr, "%s - ", (char *)msg.value); 269 gss_release_buffer(&min, &msg); 270 271 gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech, 272 &msg_ctx, &msg); 273 fprintf(stderr, "%s\n", (char *)msg.value); 274 gss_release_buffer(&min, &msg); 275 } 276 277 #else 278 279 void 280 log_debug(__unused const char *fmt, ...) 281 { 282 } 283 284 void 285 log_status(__unused const char *m, __unused gss_OID mech, 286 __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat) 287 { 288 } 289 290 #endif 291 292 293