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