1 /* lib/rpc/authgss_prot.c */ 2 /* 3 Copyright (c) 2000 The Regents of the University of Michigan. 4 All rights reserved. 5 6 Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>. 7 All rights reserved, all wrongs reversed. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions 11 are met: 12 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 2. Redistributions in binary form must reproduce the above copyright 16 notice, this list of conditions and the following disclaimer in the 17 documentation and/or other materials provided with the distribution. 18 3. Neither the name of the University nor the names of its 19 contributors may be used to endorse or promote products derived 20 from this software without specific prior written permission. 21 22 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 23 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 29 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 34 Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp 35 */ 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <stdarg.h> 40 #include <string.h> 41 #include <gssrpc/rpc.h> 42 #ifdef HAVE_HEIMDAL 43 #include <gssapi.h> 44 #else 45 #include <gssapi/gssapi.h> 46 #endif 47 48 bool_t 49 xdr_rpc_gss_buf(XDR *xdrs, gss_buffer_t buf, u_int maxsize) 50 { 51 bool_t xdr_stat; 52 u_int tmplen; 53 char *cp; 54 55 if (xdrs->x_op != XDR_DECODE) { 56 if (buf->length > UINT_MAX) 57 return (FALSE); 58 else 59 tmplen = buf->length; 60 } 61 cp = buf->value; 62 xdr_stat = xdr_bytes(xdrs, &cp, &tmplen, maxsize); 63 buf->value = cp; 64 65 if (xdr_stat && xdrs->x_op == XDR_DECODE) 66 buf->length = tmplen; 67 68 return (xdr_stat); 69 } 70 71 bool_t 72 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p) 73 { 74 bool_t xdr_stat; 75 76 xdr_stat = (xdr_u_int(xdrs, &p->gc_v) && 77 xdr_enum(xdrs, (enum_t *)&p->gc_proc) && 78 xdr_u_int32(xdrs, &p->gc_seq) && 79 xdr_enum(xdrs, (enum_t *)&p->gc_svc) && 80 xdr_rpc_gss_buf(xdrs, &p->gc_ctx, MAX_AUTH_BYTES)); 81 82 log_debug("xdr_rpc_gss_cred: %s %s " 83 "(v %d, proc %d, seq %d, svc %d, ctx %p:%d)", 84 (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", 85 (xdr_stat == TRUE) ? "success" : "failure", 86 p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc, 87 p->gc_ctx.value, p->gc_ctx.length); 88 89 return (xdr_stat); 90 } 91 92 bool_t 93 xdr_rpc_gss_init_args(XDR *xdrs, gss_buffer_desc *p) 94 { 95 bool_t xdr_stat; 96 97 xdr_stat = xdr_rpc_gss_buf(xdrs, p, MAX_NETOBJ_SZ); 98 99 log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%d)", 100 (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", 101 (xdr_stat == TRUE) ? "success" : "failure", 102 p->value, p->length); 103 104 return (xdr_stat); 105 } 106 107 bool_t 108 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p) 109 { 110 bool_t xdr_stat; 111 112 xdr_stat = (xdr_rpc_gss_buf(xdrs, &p->gr_ctx, MAX_NETOBJ_SZ) && 113 xdr_u_int32(xdrs, &p->gr_major) && 114 xdr_u_int32(xdrs, &p->gr_minor) && 115 xdr_u_int32(xdrs, &p->gr_win) && 116 xdr_rpc_gss_buf(xdrs, &p->gr_token, MAX_NETOBJ_SZ)); 117 118 log_debug("xdr_rpc_gss_init_res %s %s " 119 "(ctx %p:%d, maj %d, min %d, win %d, token %p:%d)", 120 (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", 121 (xdr_stat == TRUE) ? "success" : "failure", 122 p->gr_ctx.value, p->gr_ctx.length, 123 p->gr_major, p->gr_minor, p->gr_win, 124 p->gr_token.value, p->gr_token.length); 125 126 return (xdr_stat); 127 } 128 129 bool_t 130 xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, 131 gss_ctx_id_t ctx, gss_qop_t qop, 132 rpc_gss_svc_t svc, uint32_t seq) 133 { 134 XDR tmpxdrs; 135 gss_buffer_desc databuf, wrapbuf; 136 OM_uint32 maj_stat, min_stat; 137 int conf_state; 138 bool_t xdr_stat; 139 140 xdralloc_create(&tmpxdrs, XDR_ENCODE); 141 142 xdr_stat = FALSE; 143 144 /* Marshal rpc_gss_data_t (sequence number + arguments). */ 145 if (!xdr_u_int32(&tmpxdrs, &seq) || !(*xdr_func)(&tmpxdrs, xdr_ptr)) 146 goto errout; 147 148 /* Set databuf to marshalled rpc_gss_data_t. */ 149 databuf.length = xdr_getpos(&tmpxdrs); 150 databuf.value = xdralloc_getdata(&tmpxdrs); 151 152 if (svc == RPCSEC_GSS_SVC_INTEGRITY) { 153 if (!xdr_rpc_gss_buf(xdrs, &databuf, (unsigned int)-1)) 154 goto errout; 155 156 /* Checksum rpc_gss_data_t. */ 157 maj_stat = gss_get_mic(&min_stat, ctx, qop, 158 &databuf, &wrapbuf); 159 if (maj_stat != GSS_S_COMPLETE) { 160 log_debug("gss_get_mic failed"); 161 goto errout; 162 } 163 /* Marshal checksum. */ 164 xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1); 165 gss_release_buffer(&min_stat, &wrapbuf); 166 } 167 else if (svc == RPCSEC_GSS_SVC_PRIVACY) { 168 /* Encrypt rpc_gss_data_t. */ 169 maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, 170 &conf_state, &wrapbuf); 171 if (maj_stat != GSS_S_COMPLETE) { 172 log_status("gss_wrap", maj_stat, min_stat); 173 goto errout; 174 } 175 /* Marshal databody_priv. */ 176 xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1); 177 gss_release_buffer(&min_stat, &wrapbuf); 178 } 179 errout: 180 xdr_destroy(&tmpxdrs); 181 return (xdr_stat); 182 } 183 184 bool_t 185 xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, 186 gss_ctx_id_t ctx, gss_qop_t qop, 187 rpc_gss_svc_t svc, uint32_t seq) 188 { 189 XDR tmpxdrs; 190 gss_buffer_desc databuf, wrapbuf; 191 OM_uint32 maj_stat, min_stat; 192 uint32_t seq_num; 193 int conf_state; 194 gss_qop_t qop_state; 195 bool_t xdr_stat; 196 197 if (xdr_func == xdr_void || xdr_ptr == NULL) 198 return (TRUE); 199 200 memset(&databuf, 0, sizeof(databuf)); 201 memset(&wrapbuf, 0, sizeof(wrapbuf)); 202 203 if (svc == RPCSEC_GSS_SVC_INTEGRITY) { 204 /* Decode databody_integ. */ 205 if (!xdr_rpc_gss_buf(xdrs, &databuf, (unsigned int)-1)) { 206 log_debug("xdr decode databody_integ failed"); 207 return (FALSE); 208 } 209 /* Decode checksum. */ 210 if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1)) { 211 gss_release_buffer(&min_stat, &databuf); 212 log_debug("xdr decode checksum failed"); 213 return (FALSE); 214 } 215 /* Verify checksum and QOP. */ 216 maj_stat = gss_verify_mic(&min_stat, ctx, &databuf, 217 &wrapbuf, &qop_state); 218 free(wrapbuf.value); 219 220 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { 221 gss_release_buffer(&min_stat, &databuf); 222 log_status("gss_verify_mic", maj_stat, min_stat); 223 return (FALSE); 224 } 225 } 226 else if (svc == RPCSEC_GSS_SVC_PRIVACY) { 227 /* Decode databody_priv. */ 228 if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1)) { 229 log_debug("xdr decode databody_priv failed"); 230 return (FALSE); 231 } 232 /* Decrypt databody. */ 233 maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf, 234 &conf_state, &qop_state); 235 236 free(wrapbuf.value); 237 238 /* Verify encryption and QOP. */ 239 if (maj_stat != GSS_S_COMPLETE || qop_state != qop || 240 conf_state != TRUE) { 241 gss_release_buffer(&min_stat, &databuf); 242 log_status("gss_unwrap", maj_stat, min_stat); 243 return (FALSE); 244 } 245 } 246 /* Decode rpc_gss_data_t (sequence number + arguments). */ 247 xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE); 248 xdr_stat = (xdr_u_int32(&tmpxdrs, &seq_num) && 249 (*xdr_func)(&tmpxdrs, xdr_ptr)); 250 XDR_DESTROY(&tmpxdrs); 251 gss_release_buffer(&min_stat, &databuf); 252 253 /* Verify sequence number. */ 254 if (xdr_stat == TRUE && seq_num != seq) { 255 log_debug("wrong sequence number in databody"); 256 return (FALSE); 257 } 258 return (xdr_stat); 259 } 260 261 bool_t 262 xdr_rpc_gss_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, 263 gss_ctx_id_t ctx, gss_qop_t qop, 264 rpc_gss_svc_t svc, uint32_t seq) 265 { 266 switch (xdrs->x_op) { 267 268 case XDR_ENCODE: 269 return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr, 270 ctx, qop, svc, seq)); 271 case XDR_DECODE: 272 return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr, 273 ctx, qop,svc, seq)); 274 case XDR_FREE: 275 return (TRUE); 276 } 277 return (FALSE); 278 } 279 280 #ifdef DEBUG 281 #include <ctype.h> 282 283 void 284 log_debug(const char *fmt, ...) 285 { 286 va_list ap; 287 288 va_start(ap, fmt); 289 fprintf(stderr, "rpcsec_gss: "); 290 vfprintf(stderr, fmt, ap); 291 fprintf(stderr, "\n"); 292 va_end(ap); 293 } 294 295 void 296 log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat) 297 { 298 OM_uint32 min, msg_ctx; 299 gss_buffer_desc msgg, msgm; 300 301 msg_ctx = 0; 302 gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, 303 &msg_ctx, &msgg); 304 msg_ctx = 0; 305 gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID, 306 &msg_ctx, &msgm); 307 308 log_debug("%s: %.*s - %.*s\n", m, 309 msgg.length, (char *)msgg.value, 310 msgm.length, (char *)msgm.value); 311 312 gss_release_buffer(&min, &msgg); 313 gss_release_buffer(&min, &msgm); 314 } 315 316 void 317 log_hexdump(const u_char *buf, int len, int offset) 318 { 319 u_int i, j, jm; 320 int c; 321 322 fprintf(stderr, "\n"); 323 for (i = 0; i < len; i += 0x10) { 324 fprintf(stderr, " %04x: ", (u_int)(i + offset)); 325 jm = len - i; 326 jm = jm > 16 ? 16 : jm; 327 328 for (j = 0; j < jm; j++) { 329 if ((j % 2) == 1) 330 fprintf(stderr, "%02x ", (u_int) buf[i+j]); 331 else 332 fprintf(stderr, "%02x", (u_int) buf[i+j]); 333 } 334 for (; j < 16; j++) { 335 if ((j % 2) == 1) printf(" "); 336 else fprintf(stderr, " "); 337 } 338 fprintf(stderr, " "); 339 340 for (j = 0; j < jm; j++) { 341 c = buf[i+j]; 342 c = isprint(c) ? c : '.'; 343 fprintf(stderr, "%c", c); 344 } 345 fprintf(stderr, "\n"); 346 } 347 } 348 349 #else 350 351 void 352 log_debug(const char *fmt, ...) 353 { 354 } 355 356 void 357 log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat) 358 { 359 } 360 361 void 362 log_hexdump(const u_char *buf, int len, int offset) 363 { 364 } 365 366 #endif 367