]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/rpc/rpcsec_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] / sys / rpc / rpcsec_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
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kobj.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/mutex.h>
48
49 #include <rpc/rpc.h>
50 #include <rpc/rpcsec_gss.h>
51
52 #include "rpcsec_gss_int.h"
53
54 #define MAX_GSS_SIZE    10240   /* XXX */
55
56 #if 0                           /* use the one from kgssapi */
57 bool_t
58 xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p)
59 {
60         char *val;
61         u_int len;
62         bool_t ret;
63
64         val = p->value;
65         len = p->length;
66         ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE);
67         p->value = val;
68         p->length = len;
69
70         return (ret);
71 }
72 #endif
73
74 bool_t
75 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
76 {
77         enum_t proc, svc;
78         bool_t ret;
79
80         proc = p->gc_proc;
81         svc = p->gc_svc;
82         ret = (xdr_u_int(xdrs, &p->gc_version) &&
83             xdr_enum(xdrs, &proc) &&
84             xdr_u_int(xdrs, &p->gc_seq) &&
85             xdr_enum(xdrs, &svc) &&
86             xdr_gss_buffer_desc(xdrs, &p->gc_handle));
87         p->gc_proc = proc;
88         p->gc_svc = svc;
89
90         return (ret);
91 }
92
93 bool_t
94 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
95 {
96
97         return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) &&
98             xdr_u_int(xdrs, &p->gr_major) &&
99             xdr_u_int(xdrs, &p->gr_minor) &&
100             xdr_u_int(xdrs, &p->gr_win) &&
101             xdr_gss_buffer_desc(xdrs, &p->gr_token));
102 }
103
104 static void
105 put_uint32(struct mbuf **mp, uint32_t v)
106 {
107         struct mbuf *m = *mp;
108         uint32_t n;
109
110         M_PREPEND(m, sizeof(uint32_t), M_WAIT);
111         n = htonl(v);
112         bcopy(&n, mtod(m, uint32_t *), sizeof(uint32_t));
113         *mp = m;
114 }
115
116 bool_t
117 xdr_rpc_gss_wrap_data(struct mbuf **argsp,
118                       gss_ctx_id_t ctx, gss_qop_t qop,
119                       rpc_gss_service_t svc, u_int seq)
120 {
121         struct mbuf     *args, *mic;
122         OM_uint32       maj_stat, min_stat;
123         int             conf_state;
124         u_int           len;
125         static char     zpad[4];
126
127         args = *argsp;
128
129         /*
130          * Prepend the sequence number before calling gss_get_mic or gss_wrap.
131          */
132         put_uint32(&args, seq);
133         len = m_length(args, NULL);
134
135         if (svc == rpc_gss_svc_integrity) {
136                 /* Checksum rpc_gss_data_t. */
137                 maj_stat = gss_get_mic_mbuf(&min_stat, ctx, qop, args, &mic);
138                 if (maj_stat != GSS_S_COMPLETE) {
139                         rpc_gss_log_debug("gss_get_mic failed");
140                         m_freem(args);
141                         return (FALSE);
142                 }
143
144                 /*
145                  * Marshal databody_integ. Note that since args is
146                  * already RPC encoded, there will be no padding.
147                  */
148                 put_uint32(&args, len);
149
150                 /*
151                  * Marshal checksum. This is likely to need padding.
152                  */
153                 len = m_length(mic, NULL);
154                 put_uint32(&mic, len);
155                 if (len != RNDUP(len)) {
156                         m_append(mic, RNDUP(len) - len, zpad);
157                 }
158
159                 /*
160                  * Concatenate databody_integ with checksum.
161                  */
162                 m_cat(args, mic);
163         } else if (svc == rpc_gss_svc_privacy) {
164                 /* Encrypt rpc_gss_data_t. */
165                 maj_stat = gss_wrap_mbuf(&min_stat, ctx, TRUE, qop,
166                     &args, &conf_state);
167                 if (maj_stat != GSS_S_COMPLETE) {
168                         rpc_gss_log_status("gss_wrap", NULL,
169                             maj_stat, min_stat);
170                         return (FALSE);
171                 }
172
173                 /*
174                  *  Marshal databody_priv and deal with RPC padding.
175                  */
176                 len = m_length(args, NULL);
177                 put_uint32(&args, len);
178                 if (len != RNDUP(len)) {
179                         m_append(args, RNDUP(len) - len, zpad);
180                 }
181         }
182         *argsp = args;
183         return (TRUE);
184 }
185
186 static uint32_t
187 get_uint32(struct mbuf **mp)
188 {
189         struct mbuf *m = *mp;
190         uint32_t n;
191
192         if (m->m_len < sizeof(uint32_t)) {
193                 m = m_pullup(m, sizeof(uint32_t));
194                 if (!m) {
195                         *mp = NULL;
196                         return (0);
197                 }
198         }
199         bcopy(mtod(m, uint32_t *), &n, sizeof(uint32_t));
200         m_adj(m, sizeof(uint32_t));
201         *mp = m;
202         return (ntohl(n));
203 }
204
205 static void
206 m_trim(struct mbuf *m, int len)
207 {
208         struct mbuf *n;
209         int off;
210
211         if (m == NULL)
212                 return;
213         n = m_getptr(m, len, &off);
214         if (n) {
215                 n->m_len = off;
216                 if (n->m_next) {
217                         m_freem(n->m_next);
218                         n->m_next = NULL;
219                 }
220         }
221 }
222
223 bool_t
224 xdr_rpc_gss_unwrap_data(struct mbuf **resultsp,
225                         gss_ctx_id_t ctx, gss_qop_t qop,
226                         rpc_gss_service_t svc, u_int seq)
227 {
228         struct mbuf     *results, *message, *mic;
229         uint32_t        len, cklen;
230         OM_uint32       maj_stat, min_stat;
231         u_int           seq_num, conf_state, qop_state;
232
233         results = *resultsp;
234         *resultsp = NULL;
235         
236         message = NULL;
237         if (svc == rpc_gss_svc_integrity) {
238                 /*
239                  * Extract the seq+message part. Remember that there
240                  * may be extra RPC padding in the checksum. The
241                  * message part is RPC encoded already so no
242                  * padding.
243                  */
244                 len = get_uint32(&results);
245                 message = results;
246                 results = m_split(results, len, M_WAIT);
247                 if (!results) {
248                         m_freem(message);
249                         return (FALSE);
250                 }
251
252                 /*
253                  * Extract the MIC and make it contiguous.
254                  */
255                 cklen = get_uint32(&results);
256                 if (!results) {
257                         m_freem(message);
258                         return (FALSE);
259                 }
260                 KASSERT(cklen <= MHLEN, ("unexpected large GSS-API checksum"));
261                 mic = results;
262                 if (cklen > mic->m_len) {
263                         mic = m_pullup(mic, cklen);
264                         if (!mic) {
265                                 m_freem(message);
266                                 return (FALSE);
267                         }
268                 }
269                 if (cklen != RNDUP(cklen))
270                         m_trim(mic, cklen);
271
272                 /* Verify checksum and QOP. */
273                 maj_stat = gss_verify_mic_mbuf(&min_stat, ctx,
274                     message, mic, &qop_state);
275                 m_freem(mic);
276                 
277                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
278                         m_freem(message);
279                         rpc_gss_log_status("gss_verify_mic", NULL,
280                             maj_stat, min_stat);
281                         return (FALSE);
282                 }
283         } else if (svc == rpc_gss_svc_privacy) {
284                 /* Decode databody_priv. */
285                 len = get_uint32(&results);
286                 if (!results)
287                         return (FALSE);
288
289                 /* Decrypt databody. */
290                 message = results;
291                 if (len != RNDUP(len))
292                         m_trim(message, len);
293                 maj_stat = gss_unwrap_mbuf(&min_stat, ctx, &message,
294                     &conf_state, &qop_state);
295                 
296                 /* Verify encryption and QOP. */
297                 if (maj_stat != GSS_S_COMPLETE) {
298                         rpc_gss_log_status("gss_unwrap", NULL,
299                             maj_stat, min_stat);
300                         return (FALSE);
301                 }
302                 if (qop_state != qop || conf_state != TRUE) {
303                         m_freem(results);
304                         return (FALSE);
305                 }
306         }
307
308         /* Decode rpc_gss_data_t (sequence number + arguments). */
309         seq_num = get_uint32(&message);
310         if (!message)
311                 return (FALSE);
312         
313         /* Verify sequence number. */
314         if (seq_num != seq) {
315                 rpc_gss_log_debug("wrong sequence number in databody");
316                 m_freem(message);
317                 return (FALSE);
318         }
319
320         *resultsp = message;
321         return (TRUE);
322 }
323
324 #ifdef DEBUG
325 #include <machine/stdarg.h>
326
327 void
328 rpc_gss_log_debug(const char *fmt, ...)
329 {
330         va_list ap;
331
332         va_start(ap, fmt);
333         printf("rpcsec_gss: ");
334         vprintf(fmt, ap);
335         printf("\n");
336         va_end(ap);
337 }
338
339 void
340 rpc_gss_log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat)
341 {
342         OM_uint32 min;
343         gss_buffer_desc msg;
344         int msg_ctx = 0;
345
346         printf("rpcsec_gss: %s: ", m);
347         
348         gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
349                            &msg_ctx, &msg);
350         printf("%s - ", (char *)msg.value);
351         gss_release_buffer(&min, &msg);
352
353         gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech,
354                            &msg_ctx, &msg);
355         printf("%s\n", (char *)msg.value);
356         gss_release_buffer(&min, &msg);
357 }
358
359 #else
360
361 void
362 rpc_gss_log_debug(__unused const char *fmt, ...)
363 {
364 }
365
366 void
367 rpc_gss_log_status(__unused const char *m, __unused gss_OID mech,
368     __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat)
369 {
370 }
371
372 #endif
373
374