]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/librpcsec_gss/rpcsec_gss_prot.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / librpcsec_gss / rpcsec_gss_prot.c
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
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
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
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
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
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
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
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
278 log_debug(__unused const char *fmt, ...)
279 {
280 }
281
282 void
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