1 /* 2 rpcsec_gss_prot.c 3 4 SPDX-License-Identifier: BSD-3-Clause 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 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kobj.h> 43 #include <sys/lock.h> 44 #include <sys/malloc.h> 45 #include <sys/mbuf.h> 46 #include <sys/mutex.h> 47 48 #include <rpc/rpc.h> 49 #include <rpc/rpcsec_gss.h> 50 51 #include "rpcsec_gss_int.h" 52 53 #define MAX_GSS_SIZE 10240 /* XXX */ 54 55 #if 0 /* use the one from kgssapi */ 56 bool_t 57 xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p) 58 { 59 char *val; 60 u_int len; 61 bool_t ret; 62 63 val = p->value; 64 len = p->length; 65 ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE); 66 p->value = val; 67 p->length = len; 68 69 return (ret); 70 } 71 #endif 72 73 bool_t 74 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p) 75 { 76 enum_t proc, svc; 77 bool_t ret; 78 79 proc = p->gc_proc; 80 svc = p->gc_svc; 81 ret = (xdr_u_int(xdrs, &p->gc_version) && 82 xdr_enum(xdrs, &proc) && 83 xdr_u_int(xdrs, &p->gc_seq) && 84 xdr_enum(xdrs, &svc) && 85 xdr_gss_buffer_desc(xdrs, &p->gc_handle)); 86 p->gc_proc = proc; 87 p->gc_svc = svc; 88 89 return (ret); 90 } 91 92 bool_t 93 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p) 94 { 95 96 return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) && 97 xdr_u_int(xdrs, &p->gr_major) && 98 xdr_u_int(xdrs, &p->gr_minor) && 99 xdr_u_int(xdrs, &p->gr_win) && 100 xdr_gss_buffer_desc(xdrs, &p->gr_token)); 101 } 102 103 static void 104 put_uint32(struct mbuf **mp, uint32_t v) 105 { 106 struct mbuf *m = *mp; 107 uint32_t n; 108 109 M_PREPEND(m, sizeof(uint32_t), M_WAITOK); 110 n = htonl(v); 111 bcopy(&n, mtod(m, uint32_t *), sizeof(uint32_t)); 112 *mp = m; 113 } 114 115 bool_t 116 xdr_rpc_gss_wrap_data(struct mbuf **argsp, 117 gss_ctx_id_t ctx, gss_qop_t qop, 118 rpc_gss_service_t svc, u_int seq) 119 { 120 struct mbuf *args, *mic; 121 OM_uint32 maj_stat, min_stat; 122 int conf_state; 123 u_int len; 124 static char zpad[4]; 125 126 args = *argsp; 127 128 /* 129 * Prepend the sequence number before calling gss_get_mic or gss_wrap. 130 */ 131 put_uint32(&args, seq); 132 len = m_length(args, NULL); 133 134 if (svc == rpc_gss_svc_integrity) { 135 /* Checksum rpc_gss_data_t. */ 136 maj_stat = gss_get_mic_mbuf(&min_stat, ctx, qop, args, &mic); 137 if (maj_stat != GSS_S_COMPLETE) { 138 rpc_gss_log_debug("gss_get_mic failed"); 139 m_freem(args); 140 return (FALSE); 141 } 142 143 /* 144 * Marshal databody_integ. Note that since args is 145 * already RPC encoded, there will be no padding. 146 */ 147 put_uint32(&args, len); 148 149 /* 150 * Marshal checksum. This is likely to need padding. 151 */ 152 len = m_length(mic, NULL); 153 put_uint32(&mic, len); 154 if (len != RNDUP(len)) { 155 m_append(mic, RNDUP(len) - len, zpad); 156 } 157 158 /* 159 * Concatenate databody_integ with checksum. 160 */ 161 m_cat(args, mic); 162 } else if (svc == rpc_gss_svc_privacy) { 163 /* Encrypt rpc_gss_data_t. */ 164 maj_stat = gss_wrap_mbuf(&min_stat, ctx, TRUE, qop, 165 &args, &conf_state); 166 if (maj_stat != GSS_S_COMPLETE) { 167 rpc_gss_log_status("gss_wrap", NULL, 168 maj_stat, min_stat); 169 return (FALSE); 170 } 171 172 /* 173 * Marshal databody_priv and deal with RPC padding. 174 */ 175 len = m_length(args, NULL); 176 put_uint32(&args, len); 177 if (len != RNDUP(len)) { 178 m_append(args, RNDUP(len) - len, zpad); 179 } 180 } 181 *argsp = args; 182 return (TRUE); 183 } 184 185 static uint32_t 186 get_uint32(struct mbuf **mp) 187 { 188 struct mbuf *m = *mp; 189 uint32_t n; 190 191 if (m->m_len < sizeof(uint32_t)) { 192 m = m_pullup(m, sizeof(uint32_t)); 193 if (!m) { 194 *mp = NULL; 195 return (0); 196 } 197 } 198 bcopy(mtod(m, uint32_t *), &n, sizeof(uint32_t)); 199 m_adj(m, sizeof(uint32_t)); 200 *mp = m; 201 return (ntohl(n)); 202 } 203 204 static void 205 m_trim(struct mbuf *m, int len) 206 { 207 struct mbuf *n; 208 int off; 209 210 if (m == NULL) 211 return; 212 n = m_getptr(m, len, &off); 213 if (n) { 214 n->m_len = off; 215 if (n->m_next) { 216 m_freem(n->m_next); 217 n->m_next = NULL; 218 } 219 } 220 } 221 222 bool_t 223 xdr_rpc_gss_unwrap_data(struct mbuf **resultsp, 224 gss_ctx_id_t ctx, gss_qop_t qop, 225 rpc_gss_service_t svc, u_int seq) 226 { 227 struct mbuf *results, *message, *mic; 228 uint32_t len, cklen; 229 OM_uint32 maj_stat, min_stat; 230 u_int seq_num, conf_state, qop_state; 231 232 results = *resultsp; 233 *resultsp = NULL; 234 235 message = NULL; 236 if (svc == rpc_gss_svc_integrity) { 237 /* 238 * Extract the seq+message part. Remember that there 239 * may be extra RPC padding in the checksum. The 240 * message part is RPC encoded already so no 241 * padding. 242 */ 243 len = get_uint32(&results); 244 message = results; 245 results = m_split(results, len, M_WAITOK); 246 if (!results) { 247 m_freem(message); 248 return (FALSE); 249 } 250 251 /* 252 * Extract the MIC and make it contiguous. 253 */ 254 cklen = get_uint32(&results); 255 if (!results) { 256 m_freem(message); 257 return (FALSE); 258 } 259 KASSERT(cklen <= MHLEN, ("unexpected large GSS-API checksum")); 260 mic = results; 261 if (cklen > mic->m_len) { 262 mic = m_pullup(mic, cklen); 263 if (!mic) { 264 m_freem(message); 265 return (FALSE); 266 } 267 } 268 if (cklen != RNDUP(cklen)) 269 m_trim(mic, cklen); 270 271 /* Verify checksum and QOP. */ 272 maj_stat = gss_verify_mic_mbuf(&min_stat, ctx, 273 message, mic, &qop_state); 274 m_freem(mic); 275 276 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { 277 m_freem(message); 278 rpc_gss_log_status("gss_verify_mic", NULL, 279 maj_stat, min_stat); 280 return (FALSE); 281 } 282 } else if (svc == rpc_gss_svc_privacy) { 283 /* Decode databody_priv. */ 284 len = get_uint32(&results); 285 if (!results) 286 return (FALSE); 287 288 /* Decrypt databody. */ 289 message = results; 290 if (len != RNDUP(len)) 291 m_trim(message, len); 292 maj_stat = gss_unwrap_mbuf(&min_stat, ctx, &message, 293 &conf_state, &qop_state); 294 295 /* Verify encryption and QOP. */ 296 if (maj_stat != GSS_S_COMPLETE) { 297 rpc_gss_log_status("gss_unwrap", NULL, 298 maj_stat, min_stat); 299 return (FALSE); 300 } 301 if (qop_state != qop || conf_state != TRUE) { 302 m_freem(results); 303 return (FALSE); 304 } 305 } 306 307 /* Decode rpc_gss_data_t (sequence number + arguments). */ 308 seq_num = get_uint32(&message); 309 if (!message) 310 return (FALSE); 311 312 /* Verify sequence number. */ 313 if (seq_num != seq) { 314 rpc_gss_log_debug("wrong sequence number in databody"); 315 m_freem(message); 316 return (FALSE); 317 } 318 319 *resultsp = message; 320 return (TRUE); 321 } 322 323 #ifdef DEBUG 324 #include <machine/stdarg.h> 325 326 void 327 rpc_gss_log_debug(const char *fmt, ...) 328 { 329 va_list ap; 330 331 va_start(ap, fmt); 332 printf("rpcsec_gss: "); 333 vprintf(fmt, ap); 334 printf("\n"); 335 va_end(ap); 336 } 337 338 void 339 rpc_gss_log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat) 340 { 341 OM_uint32 min; 342 gss_buffer_desc msg; 343 int msg_ctx = 0; 344 345 printf("rpcsec_gss: %s: ", m); 346 347 gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, 348 &msg_ctx, &msg); 349 printf("%s - ", (char *)msg.value); 350 gss_release_buffer(&min, &msg); 351 352 gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech, 353 &msg_ctx, &msg); 354 printf("%s\n", (char *)msg.value); 355 gss_release_buffer(&min, &msg); 356 } 357 358 #else 359 360 void 361 rpc_gss_log_debug(__unused const char *fmt, ...) 362 { 363 } 364 365 void 366 rpc_gss_log_status(__unused const char *m, __unused gss_OID mech, 367 __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat) 368 { 369 } 370 371 #endif 372 373 374