1 /*
2   authgss_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 */
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include <rpc/types.h>
41 #include <rpc/xdr.h>
42 #include <rpc/auth.h>
43 #include <rpc/auth_gss.h>
44 #include <rpc/rpc.h>
45 #include <gssapi/gssapi.h>
46 
47 bool_t
xdr_rpc_gss_cred(XDR * xdrs,struct rpc_gss_cred * p)48 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
49 {
50 	bool_t xdr_stat;
51 
52 	xdr_stat = (xdr_u_int(xdrs, &p->gc_v) &&
53 		    xdr_enum(xdrs, (enum_t *)&p->gc_proc) &&
54 		    xdr_u_int(xdrs, &p->gc_seq) &&
55 		    xdr_enum(xdrs, (enum_t *)&p->gc_svc) &&
56 		    xdr_bytes(xdrs, (char **)&p->gc_ctx.value,
57 			      (u_int *)&p->gc_ctx.length, MAX_AUTH_BYTES));
58 
59 	log_debug("xdr_rpc_gss_cred: %s %s "
60 		  "(v %d, proc %d, seq %d, svc %d, ctx %p:%d)",
61 		  (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
62 		  (xdr_stat == TRUE) ? "success" : "failure",
63 		  p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc,
64 		  p->gc_ctx.value, p->gc_ctx.length);
65 
66 	return (xdr_stat);
67 }
68 
69 bool_t
xdr_rpc_gss_init_args(XDR * xdrs,gss_buffer_desc * p)70 xdr_rpc_gss_init_args(XDR *xdrs, gss_buffer_desc *p)
71 {
72 	bool_t xdr_stat;
73 
74 	xdr_stat = xdr_bytes(xdrs, (char **)&p->value,
75 			      (u_int *)&p->length, MAX_NETOBJ_SZ);
76 
77 	log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%d)",
78 		  (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
79 		  (xdr_stat == TRUE) ? "success" : "failure",
80 		  p->value, p->length);
81 
82 	return (xdr_stat);
83 }
84 
85 bool_t
xdr_rpc_gss_init_res(XDR * xdrs,struct rpc_gss_init_res * p)86 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
87 {
88 	bool_t xdr_stat;
89 
90 	xdr_stat = (xdr_bytes(xdrs, (char **)&p->gr_ctx.value,
91 			      (u_int *)&p->gr_ctx.length, MAX_NETOBJ_SZ) &&
92 		    xdr_u_int(xdrs, &p->gr_major) &&
93 		    xdr_u_int(xdrs, &p->gr_minor) &&
94 		    xdr_u_int(xdrs, &p->gr_win) &&
95 		    xdr_bytes(xdrs, (char **)&p->gr_token.value,
96 			      (u_int *)&p->gr_token.length, MAX_NETOBJ_SZ));
97 
98 	log_debug("xdr_rpc_gss_init_res %s %s "
99 		  "(ctx %p:%d, maj %d, min %d, win %d, token %p:%d)",
100 		  (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
101 		  (xdr_stat == TRUE) ? "success" : "failure",
102 		  p->gr_ctx.value, p->gr_ctx.length,
103 		  p->gr_major, p->gr_minor, p->gr_win,
104 		  p->gr_token.value, p->gr_token.length);
105 
106 	return (xdr_stat);
107 }
108 
109 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,u_int seq)110 xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
111 		      gss_ctx_id_t ctx, gss_qop_t qop,
112 		      rpc_gss_svc_t svc, u_int seq)
113 {
114 	gss_buffer_desc	databuf, wrapbuf;
115 	OM_uint32	maj_stat, min_stat;
116 	int		start, end, conf_state;
117 	bool_t		xdr_stat;
118 
119 	/* Skip databody length. */
120 	start = XDR_GETPOS(xdrs);
121 	XDR_SETPOS(xdrs, start + 4);
122 
123 	/* Marshal rpc_gss_data_t (sequence number + arguments). */
124 	if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr))
125 		return (FALSE);
126 	end = XDR_GETPOS(xdrs);
127 
128 	/* Set databuf to marshalled rpc_gss_data_t. */
129 	databuf.length = end - start - 4;
130 	XDR_SETPOS(xdrs, start + 4);
131 	databuf.value = XDR_INLINE(xdrs, databuf.length);
132 
133 	xdr_stat = FALSE;
134 
135 	if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
136 		/* Marshal databody_integ length. */
137 		XDR_SETPOS(xdrs, start);
138 		if (!xdr_u_int(xdrs, (u_int *)&databuf.length))
139 			return (FALSE);
140 
141 		/* Checksum rpc_gss_data_t. */
142 		maj_stat = gss_get_mic(&min_stat, ctx, qop,
143 				       &databuf, &wrapbuf);
144 		if (maj_stat != GSS_S_COMPLETE) {
145 			log_debug("gss_get_mic failed");
146 			return (FALSE);
147 		}
148 		/* Marshal checksum. */
149 		XDR_SETPOS(xdrs, end);
150 		xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value,
151 				     (u_int *)&wrapbuf.length, MAX_NETOBJ_SZ);
152 		gss_release_buffer(&min_stat, &wrapbuf);
153 	}
154 	else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
155 		/* Encrypt rpc_gss_data_t. */
156 		maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
157 				    &conf_state, &wrapbuf);
158 		if (maj_stat != GSS_S_COMPLETE) {
159 			log_status("gss_wrap", maj_stat, min_stat);
160 			return (FALSE);
161 		}
162 		/* Marshal databody_priv. */
163 		XDR_SETPOS(xdrs, start);
164 		xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value,
165 				     (u_int *)&wrapbuf.length, MAX_NETOBJ_SZ);
166 		gss_release_buffer(&min_stat, &wrapbuf);
167 	}
168 	return (xdr_stat);
169 }
170 
171 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,u_int seq)172 xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
173 			gss_ctx_id_t ctx, gss_qop_t qop,
174 			rpc_gss_svc_t svc, u_int seq)
175 {
176 	XDR		tmpxdrs;
177 	gss_buffer_desc	databuf, wrapbuf;
178 	OM_uint32	maj_stat, min_stat;
179 	u_int		seq_num, qop_state;
180 	int			conf_state;
181 	bool_t		xdr_stat;
182 
183 	if (xdr_func == (xdrproc_t)xdr_void || xdr_ptr == NULL)
184 		return (TRUE);
185 
186 	memset(&databuf, 0, sizeof(databuf));
187 	memset(&wrapbuf, 0, sizeof(wrapbuf));
188 
189 	if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
190 		/* Decode databody_integ. */
191 		if (!xdr_bytes(xdrs, (char **)&databuf.value, (u_int *)&databuf.length,
192 			       MAX_NETOBJ_SZ)) {
193 			log_debug("xdr decode databody_integ failed");
194 			return (FALSE);
195 		}
196 		/* Decode checksum. */
197 		if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length,
198 			       MAX_NETOBJ_SZ)) {
199 			gss_release_buffer(&min_stat, &databuf);
200 			log_debug("xdr decode checksum failed");
201 			return (FALSE);
202 		}
203 		/* Verify checksum and QOP. */
204 		maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
205 					  &wrapbuf, &qop_state);
206 		gss_release_buffer(&min_stat, &wrapbuf);
207 
208 		if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
209 			gss_release_buffer(&min_stat, &databuf);
210 			log_status("gss_verify_mic", maj_stat, min_stat);
211 			return (FALSE);
212 		}
213 	}
214 	else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
215 		/* Decode databody_priv. */
216 		if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length,
217 			       MAX_NETOBJ_SZ)) {
218 			log_debug("xdr decode databody_priv failed");
219 			return (FALSE);
220 		}
221 		/* Decrypt databody. */
222 		maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
223 				      &conf_state, &qop_state);
224 
225 		gss_release_buffer(&min_stat, &wrapbuf);
226 
227 		/* Verify encryption and QOP. */
228 		if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
229 			conf_state != TRUE) {
230 			gss_release_buffer(&min_stat, &databuf);
231 			log_status("gss_unwrap", maj_stat, min_stat);
232 			return (FALSE);
233 		}
234 	}
235 	/* Decode rpc_gss_data_t (sequence number + arguments). */
236 	xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
237 	xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
238 		    (*xdr_func)(&tmpxdrs, xdr_ptr));
239 	XDR_DESTROY(&tmpxdrs);
240 	gss_release_buffer(&min_stat, &databuf);
241 
242 	/* Verify sequence number. */
243 	if (xdr_stat == TRUE && seq_num != seq) {
244 		log_debug("wrong sequence number in databody");
245 		return (FALSE);
246 	}
247 	return (xdr_stat);
248 }
249 
250 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,u_int seq)251 xdr_rpc_gss_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
252 		 gss_ctx_id_t ctx, gss_qop_t qop,
253 		 rpc_gss_svc_t svc, u_int seq)
254 {
255 	switch (xdrs->x_op) {
256 
257 	case XDR_ENCODE:
258 		return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr,
259 					      ctx, qop, svc, seq));
260 	case XDR_DECODE:
261 		return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr,
262 						ctx, qop,svc, seq));
263 	case XDR_FREE:
264 		return (TRUE);
265 	}
266 	return (FALSE);
267 }
268 
269 #ifdef DEBUG
270 #include <ctype.h>
271 
272 void
log_debug(const char * fmt,...)273 log_debug(const char *fmt, ...)
274 {
275 	va_list ap;
276 
277 	va_start(ap, fmt);
278 	fprintf(stderr, "rpcsec_gss: ");
279 	vfprintf(stderr, fmt, ap);
280 	fprintf(stderr, "\n");
281 	va_end(ap);
282 }
283 
284 void
log_status(char * m,OM_uint32 maj_stat,OM_uint32 min_stat)285 log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
286 {
287 	OM_uint32 min;
288 	gss_buffer_desc msg;
289 	int msg_ctx = 0;
290 
291 	fprintf(stderr, "rpcsec_gss: %s: ", m);
292 
293 	gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
294 			   &msg_ctx, &msg);
295 	fprintf(stderr, "%s - ", (char *)msg.value);
296 	gss_release_buffer(&min, &msg);
297 
298 	gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID,
299 			   &msg_ctx, &msg);
300 	fprintf(stderr, "%s\n", (char *)msg.value);
301 	gss_release_buffer(&min, &msg);
302 }
303 
304 void
log_hexdump(const u_char * buf,int len,int offset)305 log_hexdump(const u_char *buf, int len, int offset)
306 {
307 	u_int i, j, jm;
308 	int c;
309 
310 	fprintf(stderr, "\n");
311 	for (i = 0; i < len; i += 0x10) {
312 		fprintf(stderr, "  %04x: ", (u_int)(i + offset));
313 		jm = len - i;
314 		jm = jm > 16 ? 16 : jm;
315 
316 		for (j = 0; j < jm; j++) {
317 			if ((j % 2) == 1)
318 				fprintf(stderr, "%02x ", (u_int) buf[i+j]);
319 			else
320 				fprintf(stderr, "%02x", (u_int) buf[i+j]);
321 		}
322 		for (; j < 16; j++) {
323 			if ((j % 2) == 1) printf("   ");
324 			else fprintf(stderr, "  ");
325 		}
326 		fprintf(stderr, " ");
327 
328 		for (j = 0; j < jm; j++) {
329 			c = buf[i+j];
330 			c = isprint(c) ? c : '.';
331 			fprintf(stderr, "%c", c);
332 		}
333 		fprintf(stderr, "\n");
334 	}
335 }
336 
337 #else
338 
339 void
log_debug(const char * fmt,...)340 log_debug(const char *fmt, ...)
341 {
342 }
343 
344 void
log_status(char * m,OM_uint32 maj_stat,OM_uint32 min_stat)345 log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
346 {
347 }
348 
349 void
log_hexdump(const u_char * buf,int len,int offset)350 log_hexdump(const u_char *buf, int len, int offset)
351 {
352 }
353 
354 #endif
355 
356 
357