1 /*
2 rpcsec_gss_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 $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $
36 */
37 /* $FreeBSD$ */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <rpc/rpc.h>
44 #include <rpc/rpcsec_gss.h>
45 #include "rpcsec_gss_int.h"
46
47 #define MAX_GSS_SIZE 10240 /* XXX */
48
49 bool_t
xdr_gss_buffer_desc(XDR * xdrs,gss_buffer_desc * p)50 xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p)
51 {
52 char *val;
53 u_int len;
54 bool_t ret;
55
56 val = p->value;
57 len = p->length;
58 ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE);
59 p->value = val;
60 p->length = len;
61
62 return (ret);
63 }
64
65 bool_t
xdr_rpc_gss_cred(XDR * xdrs,struct rpc_gss_cred * p)66 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
67 {
68 enum_t proc, svc;
69 bool_t ret;
70
71 proc = p->gc_proc;
72 svc = p->gc_svc;
73 ret = (xdr_u_int(xdrs, &p->gc_version) &&
74 xdr_enum(xdrs, &proc) &&
75 xdr_u_int(xdrs, &p->gc_seq) &&
76 xdr_enum(xdrs, &svc) &&
77 xdr_gss_buffer_desc(xdrs, &p->gc_handle));
78 p->gc_proc = proc;
79 p->gc_svc = svc;
80
81 return (ret);
82 }
83
84 bool_t
xdr_rpc_gss_init_res(XDR * xdrs,struct rpc_gss_init_res * p)85 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
86 {
87
88 return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) &&
89 xdr_u_int(xdrs, &p->gr_major) &&
90 xdr_u_int(xdrs, &p->gr_minor) &&
91 xdr_u_int(xdrs, &p->gr_win) &&
92 xdr_gss_buffer_desc(xdrs, &p->gr_token));
93 }
94
95 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_service_t svc,u_int seq)96 xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
97 gss_ctx_id_t ctx, gss_qop_t qop,
98 rpc_gss_service_t svc, u_int seq)
99 {
100 gss_buffer_desc databuf, wrapbuf;
101 OM_uint32 maj_stat, min_stat;
102 int start, end, conf_state;
103 u_int len;
104 bool_t xdr_stat;
105
106 /* Skip databody length. */
107 start = XDR_GETPOS(xdrs);
108 XDR_SETPOS(xdrs, start + 4);
109
110 /* Marshal rpc_gss_data_t (sequence number + arguments). */
111 if (!xdr_u_int(xdrs, &seq) || !xdr_func(xdrs, xdr_ptr))
112 return (FALSE);
113 end = XDR_GETPOS(xdrs);
114
115 /* Set databuf to marshalled rpc_gss_data_t. */
116 databuf.length = end - start - 4;
117 XDR_SETPOS(xdrs, start + 4);
118 databuf.value = XDR_INLINE(xdrs, databuf.length);
119
120 xdr_stat = FALSE;
121
122 if (svc == rpc_gss_svc_integrity) {
123 /* Marshal databody_integ length. */
124 XDR_SETPOS(xdrs, start);
125 len = databuf.length;
126 if (!xdr_u_int(xdrs, &len))
127 return (FALSE);
128
129 /* Checksum rpc_gss_data_t. */
130 maj_stat = gss_get_mic(&min_stat, ctx, qop,
131 &databuf, &wrapbuf);
132 if (maj_stat != GSS_S_COMPLETE) {
133 log_debug("gss_get_mic failed");
134 return (FALSE);
135 }
136 /* Marshal checksum. */
137 XDR_SETPOS(xdrs, end);
138 xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf);
139 gss_release_buffer(&min_stat, &wrapbuf);
140 }
141 else if (svc == rpc_gss_svc_privacy) {
142 /* Encrypt rpc_gss_data_t. */
143 maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
144 &conf_state, &wrapbuf);
145 if (maj_stat != GSS_S_COMPLETE) {
146 log_status("gss_wrap", NULL, maj_stat, min_stat);
147 return (FALSE);
148 }
149 /* Marshal databody_priv. */
150 XDR_SETPOS(xdrs, start);
151 xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf);
152 gss_release_buffer(&min_stat, &wrapbuf);
153 }
154 return (xdr_stat);
155 }
156
157 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_service_t svc,u_int seq)158 xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
159 gss_ctx_id_t ctx, gss_qop_t qop,
160 rpc_gss_service_t svc, u_int seq)
161 {
162 XDR tmpxdrs;
163 gss_buffer_desc databuf, wrapbuf;
164 OM_uint32 maj_stat, min_stat;
165 u_int seq_num, conf_state, qop_state;
166 bool_t xdr_stat;
167
168 if (xdr_func == (xdrproc_t) xdr_void || xdr_ptr == NULL)
169 return (TRUE);
170
171 memset(&databuf, 0, sizeof(databuf));
172 memset(&wrapbuf, 0, sizeof(wrapbuf));
173
174 if (svc == rpc_gss_svc_integrity) {
175 /* Decode databody_integ. */
176 if (!xdr_gss_buffer_desc(xdrs, &databuf)) {
177 log_debug("xdr decode databody_integ failed");
178 return (FALSE);
179 }
180 /* Decode checksum. */
181 if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
182 mem_free(databuf.value, databuf.length);
183 log_debug("xdr decode checksum failed");
184 return (FALSE);
185 }
186 /* Verify checksum and QOP. */
187 maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
188 &wrapbuf, &qop_state);
189 mem_free(wrapbuf.value, wrapbuf.length);
190
191 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
192 mem_free(databuf.value, databuf.length);
193 log_status("gss_verify_mic", NULL, maj_stat, min_stat);
194 return (FALSE);
195 }
196 } else if (svc == rpc_gss_svc_privacy) {
197 /* Decode databody_priv. */
198 if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
199 log_debug("xdr decode databody_priv failed");
200 return (FALSE);
201 }
202 /* Decrypt databody. */
203 maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
204 &conf_state, &qop_state);
205
206 mem_free(wrapbuf.value, wrapbuf.length);
207
208 /* Verify encryption and QOP. */
209 if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
210 conf_state != TRUE) {
211 gss_release_buffer(&min_stat, &databuf);
212 log_status("gss_unwrap", NULL, maj_stat, min_stat);
213 return (FALSE);
214 }
215 }
216 /* Decode rpc_gss_data_t (sequence number + arguments). */
217 xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
218 xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
219 xdr_func(&tmpxdrs, xdr_ptr));
220 XDR_DESTROY(&tmpxdrs);
221
222 /*
223 * Integrity service allocates databuf via XDR so free it the
224 * same way.
225 */
226 if (svc == rpc_gss_svc_integrity) {
227 xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &databuf);
228 } else {
229 gss_release_buffer(&min_stat, &databuf);
230 }
231
232 /* Verify sequence number. */
233 if (xdr_stat == TRUE && seq_num != seq) {
234 log_debug("wrong sequence number in databody");
235 return (FALSE);
236 }
237 return (xdr_stat);
238 }
239
240 #ifdef DEBUG
241 #include <ctype.h>
242
243 void
log_debug(const char * fmt,...)244 log_debug(const char *fmt, ...)
245 {
246 va_list ap;
247
248 va_start(ap, fmt);
249 fprintf(stderr, "rpcsec_gss: ");
250 vfprintf(stderr, fmt, ap);
251 fprintf(stderr, "\n");
252 va_end(ap);
253 }
254
255 void
log_status(const char * m,gss_OID mech,OM_uint32 maj_stat,OM_uint32 min_stat)256 log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat)
257 {
258 OM_uint32 min;
259 gss_buffer_desc msg;
260 int msg_ctx = 0;
261
262 fprintf(stderr, "rpcsec_gss: %s: ", m);
263
264 gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
265 &msg_ctx, &msg);
266 fprintf(stderr, "%s - ", (char *)msg.value);
267 gss_release_buffer(&min, &msg);
268
269 gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech,
270 &msg_ctx, &msg);
271 fprintf(stderr, "%s\n", (char *)msg.value);
272 gss_release_buffer(&min, &msg);
273 }
274
275 #else
276
277 void
log_debug(__unused const char * fmt,...)278 log_debug(__unused const char *fmt, ...)
279 {
280 }
281
282 void
log_status(__unused const char * m,__unused gss_OID mech,__unused OM_uint32 maj_stat,__unused OM_uint32 min_stat)283 log_status(__unused const char *m, __unused gss_OID mech,
284 __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat)
285 {
286 }
287
288 #endif
289
290
291