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