1181344Sdfr/*
2181344Sdfr  rpcsec_gss_prot.c
3181344Sdfr
4181344Sdfr  Copyright (c) 2000 The Regents of the University of Michigan.
5181344Sdfr  All rights reserved.
6181344Sdfr
7181344Sdfr  Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
8181344Sdfr  All rights reserved, all wrongs reversed.
9181344Sdfr
10181344Sdfr  Redistribution and use in source and binary forms, with or without
11181344Sdfr  modification, are permitted provided that the following conditions
12181344Sdfr  are met:
13181344Sdfr
14181344Sdfr  1. Redistributions of source code must retain the above copyright
15181344Sdfr     notice, this list of conditions and the following disclaimer.
16181344Sdfr  2. Redistributions in binary form must reproduce the above copyright
17181344Sdfr     notice, this list of conditions and the following disclaimer in the
18181344Sdfr     documentation and/or other materials provided with the distribution.
19181344Sdfr  3. Neither the name of the University nor the names of its
20181344Sdfr     contributors may be used to endorse or promote products derived
21181344Sdfr     from this software without specific prior written permission.
22181344Sdfr
23181344Sdfr  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24181344Sdfr  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25181344Sdfr  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26181344Sdfr  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27181344Sdfr  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28181344Sdfr  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29181344Sdfr  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30181344Sdfr  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31181344Sdfr  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32181344Sdfr  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33181344Sdfr  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34181344Sdfr
35181344Sdfr  $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $
36181344Sdfr*/
37181344Sdfr/* $FreeBSD$ */
38181344Sdfr
39181344Sdfr#include <stdio.h>
40181344Sdfr#include <stdlib.h>
41181344Sdfr#include <stdarg.h>
42181344Sdfr#include <string.h>
43181344Sdfr#include <rpc/rpc.h>
44181344Sdfr#include <rpc/rpcsec_gss.h>
45181344Sdfr#include "rpcsec_gss_int.h"
46181344Sdfr
47181344Sdfr#define MAX_GSS_SIZE	10240	/* XXX */
48181344Sdfr
49181344Sdfrbool_t
50181344Sdfrxdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p)
51181344Sdfr{
52181344Sdfr	char *val;
53181344Sdfr	u_int len;
54181344Sdfr	bool_t ret;
55181344Sdfr
56181344Sdfr	val = p->value;
57181344Sdfr	len = p->length;
58181344Sdfr	ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE);
59181344Sdfr	p->value = val;
60181344Sdfr	p->length = len;
61181344Sdfr
62181344Sdfr	return (ret);
63181344Sdfr}
64181344Sdfr
65181344Sdfrbool_t
66181344Sdfrxdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
67181344Sdfr{
68181344Sdfr	enum_t proc, svc;
69181344Sdfr	bool_t ret;
70181344Sdfr
71181344Sdfr	proc = p->gc_proc;
72181344Sdfr	svc = p->gc_svc;
73181344Sdfr	ret = (xdr_u_int(xdrs, &p->gc_version) &&
74181344Sdfr	    xdr_enum(xdrs, &proc) &&
75181344Sdfr	    xdr_u_int(xdrs, &p->gc_seq) &&
76181344Sdfr	    xdr_enum(xdrs, &svc) &&
77181344Sdfr	    xdr_gss_buffer_desc(xdrs, &p->gc_handle));
78181344Sdfr	p->gc_proc = proc;
79181344Sdfr	p->gc_svc = svc;
80181344Sdfr
81181344Sdfr	return (ret);
82181344Sdfr}
83181344Sdfr
84181344Sdfrbool_t
85181344Sdfrxdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
86181344Sdfr{
87181344Sdfr
88181344Sdfr	return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) &&
89181344Sdfr	    xdr_u_int(xdrs, &p->gr_major) &&
90181344Sdfr	    xdr_u_int(xdrs, &p->gr_minor) &&
91181344Sdfr	    xdr_u_int(xdrs, &p->gr_win) &&
92181344Sdfr	    xdr_gss_buffer_desc(xdrs, &p->gr_token));
93181344Sdfr}
94181344Sdfr
95181344Sdfrbool_t
96181344Sdfrxdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
97181344Sdfr		      gss_ctx_id_t ctx, gss_qop_t qop,
98181344Sdfr		      rpc_gss_service_t svc, u_int seq)
99181344Sdfr{
100181344Sdfr	gss_buffer_desc	databuf, wrapbuf;
101181344Sdfr	OM_uint32	maj_stat, min_stat;
102181344Sdfr	int		start, end, conf_state;
103181346Sdfr	u_int		len;
104181344Sdfr	bool_t		xdr_stat;
105181344Sdfr
106181344Sdfr	/* Skip databody length. */
107181344Sdfr	start = XDR_GETPOS(xdrs);
108181344Sdfr	XDR_SETPOS(xdrs, start + 4);
109181344Sdfr
110181344Sdfr	/* Marshal rpc_gss_data_t (sequence number + arguments). */
111181344Sdfr	if (!xdr_u_int(xdrs, &seq) || !xdr_func(xdrs, xdr_ptr))
112181344Sdfr		return (FALSE);
113181344Sdfr	end = XDR_GETPOS(xdrs);
114181344Sdfr
115181344Sdfr	/* Set databuf to marshalled rpc_gss_data_t. */
116181344Sdfr	databuf.length = end - start - 4;
117181344Sdfr	XDR_SETPOS(xdrs, start + 4);
118181344Sdfr	databuf.value = XDR_INLINE(xdrs, databuf.length);
119181344Sdfr
120181344Sdfr	xdr_stat = FALSE;
121181344Sdfr
122181344Sdfr	if (svc == rpc_gss_svc_integrity) {
123181344Sdfr		/* Marshal databody_integ length. */
124181344Sdfr		XDR_SETPOS(xdrs, start);
125181346Sdfr		len = databuf.length;
126181346Sdfr		if (!xdr_u_int(xdrs, &len))
127181344Sdfr			return (FALSE);
128181344Sdfr
129181344Sdfr		/* Checksum rpc_gss_data_t. */
130181344Sdfr		maj_stat = gss_get_mic(&min_stat, ctx, qop,
131181344Sdfr				       &databuf, &wrapbuf);
132181344Sdfr		if (maj_stat != GSS_S_COMPLETE) {
133181344Sdfr			log_debug("gss_get_mic failed");
134181344Sdfr			return (FALSE);
135181344Sdfr		}
136181344Sdfr		/* Marshal checksum. */
137181344Sdfr		XDR_SETPOS(xdrs, end);
138181344Sdfr		xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf);
139181344Sdfr		gss_release_buffer(&min_stat, &wrapbuf);
140181344Sdfr	}
141181344Sdfr	else if (svc == rpc_gss_svc_privacy) {
142181344Sdfr		/* Encrypt rpc_gss_data_t. */
143181344Sdfr		maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
144181344Sdfr				    &conf_state, &wrapbuf);
145181344Sdfr		if (maj_stat != GSS_S_COMPLETE) {
146181344Sdfr			log_status("gss_wrap", NULL, maj_stat, min_stat);
147181344Sdfr			return (FALSE);
148181344Sdfr		}
149181344Sdfr		/* Marshal databody_priv. */
150181344Sdfr		XDR_SETPOS(xdrs, start);
151181344Sdfr		xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf);
152181344Sdfr		gss_release_buffer(&min_stat, &wrapbuf);
153181344Sdfr	}
154181344Sdfr	return (xdr_stat);
155181344Sdfr}
156181344Sdfr
157181344Sdfrbool_t
158181344Sdfrxdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
159181344Sdfr			gss_ctx_id_t ctx, gss_qop_t qop,
160181344Sdfr			rpc_gss_service_t svc, u_int seq)
161181344Sdfr{
162181344Sdfr	XDR		tmpxdrs;
163181344Sdfr	gss_buffer_desc	databuf, wrapbuf;
164181344Sdfr	OM_uint32	maj_stat, min_stat;
165181344Sdfr	u_int		seq_num, conf_state, qop_state;
166181344Sdfr	bool_t		xdr_stat;
167181344Sdfr
168181344Sdfr	if (xdr_func == (xdrproc_t) xdr_void || xdr_ptr == NULL)
169181344Sdfr		return (TRUE);
170181344Sdfr
171181344Sdfr	memset(&databuf, 0, sizeof(databuf));
172181344Sdfr	memset(&wrapbuf, 0, sizeof(wrapbuf));
173181344Sdfr
174181344Sdfr	if (svc == rpc_gss_svc_integrity) {
175181344Sdfr		/* Decode databody_integ. */
176181344Sdfr		if (!xdr_gss_buffer_desc(xdrs, &databuf)) {
177181344Sdfr			log_debug("xdr decode databody_integ failed");
178181344Sdfr			return (FALSE);
179181344Sdfr		}
180181344Sdfr		/* Decode checksum. */
181181344Sdfr		if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
182181344Sdfr			mem_free(databuf.value, databuf.length);
183181344Sdfr			log_debug("xdr decode checksum failed");
184181344Sdfr			return (FALSE);
185181344Sdfr		}
186181344Sdfr		/* Verify checksum and QOP. */
187181344Sdfr		maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
188181344Sdfr					  &wrapbuf, &qop_state);
189181344Sdfr		mem_free(wrapbuf.value, wrapbuf.length);
190181344Sdfr
191181344Sdfr		if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
192181344Sdfr			mem_free(databuf.value, databuf.length);
193181344Sdfr			log_status("gss_verify_mic", NULL, maj_stat, min_stat);
194181344Sdfr			return (FALSE);
195181344Sdfr		}
196181344Sdfr	} else if (svc == rpc_gss_svc_privacy) {
197181344Sdfr		/* Decode databody_priv. */
198181344Sdfr		if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
199181344Sdfr			log_debug("xdr decode databody_priv failed");
200181344Sdfr			return (FALSE);
201181344Sdfr		}
202181344Sdfr		/* Decrypt databody. */
203181344Sdfr		maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
204181344Sdfr				      &conf_state, &qop_state);
205181344Sdfr
206181344Sdfr		mem_free(wrapbuf.value, wrapbuf.length);
207181344Sdfr
208181344Sdfr		/* Verify encryption and QOP. */
209181344Sdfr		if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
210181344Sdfr			conf_state != TRUE) {
211181344Sdfr			gss_release_buffer(&min_stat, &databuf);
212181344Sdfr			log_status("gss_unwrap", NULL, maj_stat, min_stat);
213181344Sdfr			return (FALSE);
214181344Sdfr		}
215181344Sdfr	}
216181344Sdfr	/* Decode rpc_gss_data_t (sequence number + arguments). */
217181344Sdfr	xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
218181344Sdfr	xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
219181344Sdfr	    xdr_func(&tmpxdrs, xdr_ptr));
220181344Sdfr	XDR_DESTROY(&tmpxdrs);
221181344Sdfr
222181344Sdfr	/*
223181344Sdfr	 * Integrity service allocates databuf via XDR so free it the
224181344Sdfr	 * same way.
225181344Sdfr	 */
226181344Sdfr	if (svc == rpc_gss_svc_integrity) {
227181344Sdfr		xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &databuf);
228181344Sdfr	} else {
229181344Sdfr		gss_release_buffer(&min_stat, &databuf);
230181344Sdfr	}
231181344Sdfr
232181344Sdfr	/* Verify sequence number. */
233181344Sdfr	if (xdr_stat == TRUE && seq_num != seq) {
234181344Sdfr		log_debug("wrong sequence number in databody");
235181344Sdfr		return (FALSE);
236181344Sdfr	}
237181344Sdfr	return (xdr_stat);
238181344Sdfr}
239181344Sdfr
240181344Sdfr#ifdef DEBUG
241181344Sdfr#include <ctype.h>
242181344Sdfr
243181344Sdfrvoid
244181344Sdfrlog_debug(const char *fmt, ...)
245181344Sdfr{
246181344Sdfr	va_list ap;
247181344Sdfr
248181344Sdfr	va_start(ap, fmt);
249181344Sdfr	fprintf(stderr, "rpcsec_gss: ");
250181344Sdfr	vfprintf(stderr, fmt, ap);
251181344Sdfr	fprintf(stderr, "\n");
252181344Sdfr	va_end(ap);
253181344Sdfr}
254181344Sdfr
255181344Sdfrvoid
256181344Sdfrlog_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat)
257181344Sdfr{
258181344Sdfr	OM_uint32 min;
259181344Sdfr	gss_buffer_desc msg;
260181344Sdfr	int msg_ctx = 0;
261181344Sdfr
262181344Sdfr	fprintf(stderr, "rpcsec_gss: %s: ", m);
263181344Sdfr
264181344Sdfr	gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
265181344Sdfr			   &msg_ctx, &msg);
266181344Sdfr	fprintf(stderr, "%s - ", (char *)msg.value);
267181344Sdfr	gss_release_buffer(&min, &msg);
268181344Sdfr
269181344Sdfr	gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech,
270181344Sdfr			   &msg_ctx, &msg);
271181344Sdfr	fprintf(stderr, "%s\n", (char *)msg.value);
272181344Sdfr	gss_release_buffer(&min, &msg);
273181344Sdfr}
274181344Sdfr
275181344Sdfr#else
276181344Sdfr
277181344Sdfrvoid
278181344Sdfrlog_debug(__unused const char *fmt, ...)
279181344Sdfr{
280181344Sdfr}
281181344Sdfr
282181344Sdfrvoid
283181344Sdfrlog_status(__unused const char *m, __unused gss_OID mech,
284181344Sdfr    __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat)
285181344Sdfr{
286181344Sdfr}
287181344Sdfr
288181344Sdfr#endif
289181344Sdfr
290181344Sdfr
291