xref: /freebsd/crypto/krb5/src/lib/rpc/authgss_prot.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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
xdr_rpc_gss_buf(XDR * xdrs,gss_buffer_t buf,u_int maxsize)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
xdr_rpc_gss_cred(XDR * xdrs,struct rpc_gss_cred * p)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
xdr_rpc_gss_init_args(XDR * xdrs,gss_buffer_desc * p)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
xdr_rpc_gss_init_res(XDR * xdrs,struct rpc_gss_init_res * p)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
xdr_rpc_gss_wrap_data(XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr,gss_ctx_id_t ctx,gss_qop_t qop,rpc_gss_svc_t svc,uint32_t seq)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
xdr_rpc_gss_unwrap_data(XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr,gss_ctx_id_t ctx,gss_qop_t qop,rpc_gss_svc_t svc,uint32_t seq)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
xdr_rpc_gss_data(XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr,gss_ctx_id_t ctx,gss_qop_t qop,rpc_gss_svc_t svc,uint32_t seq)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
log_debug(const char * fmt,...)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
log_status(char * m,OM_uint32 maj_stat,OM_uint32 min_stat)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
log_hexdump(const u_char * buf,int len,int offset)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
log_debug(const char * fmt,...)352 log_debug(const char *fmt, ...)
353 {
354 }
355 
356 void
log_status(char * m,OM_uint32 maj_stat,OM_uint32 min_stat)357 log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
358 {
359 }
360 
361 void
log_hexdump(const u_char * buf,int len,int offset)362 log_hexdump(const u_char *buf, int len, int offset)
363 {
364 }
365 
366 #endif
367