]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/rpc/rpcsec_gss/rpcsec_gss_prot.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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         n = m_getptr(m, len, &off);
212         if (n) {
213                 n->m_len = off;
214                 if (n->m_next) {
215                         m_freem(n->m_next);
216                         n->m_next = NULL;
217                 }
218         }
219 }
220
221 bool_t
222 xdr_rpc_gss_unwrap_data(struct mbuf **resultsp,
223                         gss_ctx_id_t ctx, gss_qop_t qop,
224                         rpc_gss_service_t svc, u_int seq)
225 {
226         struct mbuf     *results, *message, *mic;
227         uint32_t        len, cklen;
228         OM_uint32       maj_stat, min_stat;
229         u_int           seq_num, conf_state, qop_state;
230
231         results = *resultsp;
232         *resultsp = NULL;
233         
234         message = NULL;
235         if (svc == rpc_gss_svc_integrity) {
236                 /*
237                  * Extract the seq+message part. Remember that there
238                  * may be extra RPC padding in the checksum. The
239                  * message part is RPC encoded already so no
240                  * padding.
241                  */
242                 len = get_uint32(&results);
243                 message = results;
244                 results = m_split(results, len, M_WAIT);
245                 if (!results) {
246                         m_freem(message);
247                         return (FALSE);
248                 }
249
250                 /*
251                  * Extract the MIC and make it contiguous.
252                  */
253                 cklen = get_uint32(&results);
254                 KASSERT(cklen <= MHLEN, ("unexpected large GSS-API checksum"));
255                 mic = results;
256                 if (cklen > mic->m_len)
257                         mic = m_pullup(mic, cklen);
258                 if (cklen != RNDUP(cklen))
259                         m_trim(mic, cklen);
260
261                 /* Verify checksum and QOP. */
262                 maj_stat = gss_verify_mic_mbuf(&min_stat, ctx,
263                     message, mic, &qop_state);
264                 m_freem(mic);
265                 
266                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
267                         m_freem(message);
268                         rpc_gss_log_status("gss_verify_mic", NULL,
269                             maj_stat, min_stat);
270                         return (FALSE);
271                 }
272         } else if (svc == rpc_gss_svc_privacy) {
273                 /* Decode databody_priv. */
274                 len = get_uint32(&results);
275
276                 /* Decrypt databody. */
277                 message = results;
278                 if (len != RNDUP(len))
279                         m_trim(message, len);
280                 maj_stat = gss_unwrap_mbuf(&min_stat, ctx, &message,
281                     &conf_state, &qop_state);
282                 
283                 /* Verify encryption and QOP. */
284                 if (maj_stat != GSS_S_COMPLETE) {
285                         rpc_gss_log_status("gss_unwrap", NULL,
286                             maj_stat, min_stat);
287                         return (FALSE);
288                 }
289                 if (qop_state != qop || conf_state != TRUE) {
290                         m_freem(results);
291                         return (FALSE);
292                 }
293         }
294
295         /* Decode rpc_gss_data_t (sequence number + arguments). */
296         seq_num = get_uint32(&message);
297         
298         /* Verify sequence number. */
299         if (seq_num != seq) {
300                 rpc_gss_log_debug("wrong sequence number in databody");
301                 m_freem(message);
302                 return (FALSE);
303         }
304
305         *resultsp = message;
306         return (TRUE);
307 }
308
309 #ifdef DEBUG
310 #include <machine/stdarg.h>
311
312 void
313 rpc_gss_log_debug(const char *fmt, ...)
314 {
315         va_list ap;
316
317         va_start(ap, fmt);
318         printf("rpcsec_gss: ");
319         vprintf(fmt, ap);
320         printf("\n");
321         va_end(ap);
322 }
323
324 void
325 rpc_gss_log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat)
326 {
327         OM_uint32 min;
328         gss_buffer_desc msg;
329         int msg_ctx = 0;
330
331         printf("rpcsec_gss: %s: ", m);
332         
333         gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
334                            &msg_ctx, &msg);
335         printf("%s - ", (char *)msg.value);
336         gss_release_buffer(&min, &msg);
337
338         gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech,
339                            &msg_ctx, &msg);
340         printf("%s\n", (char *)msg.value);
341         gss_release_buffer(&min, &msg);
342 }
343
344 #else
345
346 void
347 rpc_gss_log_debug(__unused const char *fmt, ...)
348 {
349 }
350
351 void
352 rpc_gss_log_status(__unused const char *m, __unused gss_OID mech,
353     __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat)
354 {
355 }
356
357 #endif
358
359