]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/librpcsec_gss/rpcsec_gss_prot.c
ident(1): Normalizing date format
[FreeBSD/FreeBSD.git] / lib / librpcsec_gss / rpcsec_gss_prot.c
1 /*
2   SPDX-License-Identifier: BSD-3-Clause
3
4   rpcsec_gss_prot.c
5   
6   Copyright (c) 2000 The Regents of the University of Michigan.
7   All rights reserved.
8   
9   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
10   All rights reserved, all wrongs reversed.
11   
12   Redistribution and use in source and binary forms, with or without
13   modification, are permitted provided that the following conditions
14   are met:
15
16   1. Redistributions of source code must retain the above copyright
17      notice, this list of conditions and the following disclaimer.
18   2. Redistributions in binary form must reproduce the above copyright
19      notice, this list of conditions and the following disclaimer in the
20      documentation and/or other materials provided with the distribution.
21   3. Neither the name of the University nor the names of its
22      contributors may be used to endorse or promote products derived
23      from this software without specific prior written permission.
24
25   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
26   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
32   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
37   $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $
38 */
39 /* $FreeBSD$ */
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <rpc/rpc.h>
46 #include <rpc/rpcsec_gss.h>
47 #include "rpcsec_gss_int.h"
48
49 #define MAX_GSS_SIZE    10240   /* XXX */
50
51 bool_t
52 xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p)
53 {
54         char *val;
55         u_int len;
56         bool_t ret;
57
58         val = p->value;
59         len = p->length;
60         ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE);
61         p->value = val;
62         p->length = len;
63
64         return (ret);
65 }
66
67 bool_t
68 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
69 {
70         enum_t proc, svc;
71         bool_t ret;
72
73         proc = p->gc_proc;
74         svc = p->gc_svc;
75         ret = (xdr_u_int(xdrs, &p->gc_version) &&
76             xdr_enum(xdrs, &proc) &&
77             xdr_u_int(xdrs, &p->gc_seq) &&
78             xdr_enum(xdrs, &svc) &&
79             xdr_gss_buffer_desc(xdrs, &p->gc_handle));
80         p->gc_proc = proc;
81         p->gc_svc = svc;
82
83         return (ret);
84 }
85
86 bool_t
87 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
88 {
89
90         return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) &&
91             xdr_u_int(xdrs, &p->gr_major) &&
92             xdr_u_int(xdrs, &p->gr_minor) &&
93             xdr_u_int(xdrs, &p->gr_win) &&
94             xdr_gss_buffer_desc(xdrs, &p->gr_token));
95 }
96
97 bool_t
98 xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
99                       gss_ctx_id_t ctx, gss_qop_t qop,
100                       rpc_gss_service_t svc, u_int seq)
101 {
102         gss_buffer_desc databuf, wrapbuf;
103         OM_uint32       maj_stat, min_stat;
104         int             start, end, conf_state;
105         u_int           len;
106         bool_t          xdr_stat;
107
108         /* Skip databody length. */
109         start = XDR_GETPOS(xdrs);
110         XDR_SETPOS(xdrs, start + 4);
111         
112         /* Marshal rpc_gss_data_t (sequence number + arguments). */
113         if (!xdr_u_int(xdrs, &seq) || !xdr_func(xdrs, xdr_ptr))
114                 return (FALSE);
115         end = XDR_GETPOS(xdrs);
116
117         /* Set databuf to marshalled rpc_gss_data_t. */
118         databuf.length = end - start - 4;
119         XDR_SETPOS(xdrs, start + 4);
120         databuf.value = XDR_INLINE(xdrs, databuf.length);
121
122         xdr_stat = FALSE;
123         
124         if (svc == rpc_gss_svc_integrity) {
125                 /* Marshal databody_integ length. */
126                 XDR_SETPOS(xdrs, start);
127                 len = databuf.length;
128                 if (!xdr_u_int(xdrs, &len))
129                         return (FALSE);
130                 
131                 /* Checksum rpc_gss_data_t. */
132                 maj_stat = gss_get_mic(&min_stat, ctx, qop,
133                                        &databuf, &wrapbuf);
134                 if (maj_stat != GSS_S_COMPLETE) {
135                         log_debug("gss_get_mic failed");
136                         return (FALSE);
137                 }
138                 /* Marshal checksum. */
139                 XDR_SETPOS(xdrs, end);
140                 xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf);
141                 gss_release_buffer(&min_stat, &wrapbuf);
142         }               
143         else if (svc == rpc_gss_svc_privacy) {
144                 /* Encrypt rpc_gss_data_t. */
145                 maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
146                                     &conf_state, &wrapbuf);
147                 if (maj_stat != GSS_S_COMPLETE) {
148                         log_status("gss_wrap", NULL, maj_stat, min_stat);
149                         return (FALSE);
150                 }
151                 /* Marshal databody_priv. */
152                 XDR_SETPOS(xdrs, start);
153                 xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf);
154                 gss_release_buffer(&min_stat, &wrapbuf);
155         }
156         return (xdr_stat);
157 }
158
159 bool_t
160 xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
161                         gss_ctx_id_t ctx, gss_qop_t qop,
162                         rpc_gss_service_t svc, u_int seq)
163 {
164         XDR             tmpxdrs;
165         gss_buffer_desc databuf, wrapbuf;
166         OM_uint32       maj_stat, min_stat;
167         u_int           seq_num, conf_state, qop_state;
168         bool_t          xdr_stat;
169
170         if (xdr_func == (xdrproc_t) xdr_void || xdr_ptr == NULL)
171                 return (TRUE);
172         
173         memset(&databuf, 0, sizeof(databuf));
174         memset(&wrapbuf, 0, sizeof(wrapbuf));
175         
176         if (svc == rpc_gss_svc_integrity) {
177                 /* Decode databody_integ. */
178                 if (!xdr_gss_buffer_desc(xdrs, &databuf)) {
179                         log_debug("xdr decode databody_integ failed");
180                         return (FALSE);
181                 }
182                 /* Decode checksum. */
183                 if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
184                         mem_free(databuf.value, databuf.length);
185                         log_debug("xdr decode checksum failed");
186                         return (FALSE);
187                 }
188                 /* Verify checksum and QOP. */
189                 maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
190                                           &wrapbuf, &qop_state);
191                 mem_free(wrapbuf.value, wrapbuf.length);
192                 
193                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
194                         mem_free(databuf.value, databuf.length);
195                         log_status("gss_verify_mic", NULL, maj_stat, min_stat);
196                         return (FALSE);
197                 }
198         } else if (svc == rpc_gss_svc_privacy) {
199                 /* Decode databody_priv. */
200                 if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) {
201                         log_debug("xdr decode databody_priv failed");
202                         return (FALSE);
203                 }
204                 /* Decrypt databody. */
205                 maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
206                                       &conf_state, &qop_state);
207                 
208                 mem_free(wrapbuf.value, wrapbuf.length);
209                 
210                 /* Verify encryption and QOP. */
211                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
212                         conf_state != TRUE) {
213                         gss_release_buffer(&min_stat, &databuf);
214                         log_status("gss_unwrap", NULL, maj_stat, min_stat);
215                         return (FALSE);
216                 }
217         }
218         /* Decode rpc_gss_data_t (sequence number + arguments). */
219         xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
220         xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
221             xdr_func(&tmpxdrs, xdr_ptr));
222         XDR_DESTROY(&tmpxdrs);
223
224         /*
225          * Integrity service allocates databuf via XDR so free it the
226          * same way.
227          */
228         if (svc == rpc_gss_svc_integrity) {
229                 xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &databuf);
230         } else {
231                 gss_release_buffer(&min_stat, &databuf);
232         }
233         
234         /* Verify sequence number. */
235         if (xdr_stat == TRUE && seq_num != seq) {
236                 log_debug("wrong sequence number in databody");
237                 return (FALSE);
238         }
239         return (xdr_stat);
240 }
241
242 #ifdef DEBUG
243 #include <ctype.h>
244
245 void
246 log_debug(const char *fmt, ...)
247 {
248         va_list ap;
249
250         va_start(ap, fmt);
251         fprintf(stderr, "rpcsec_gss: ");
252         vfprintf(stderr, fmt, ap);
253         fprintf(stderr, "\n");
254         va_end(ap);
255 }
256
257 void
258 log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat)
259 {
260         OM_uint32 min;
261         gss_buffer_desc msg;
262         int msg_ctx = 0;
263
264         fprintf(stderr, "rpcsec_gss: %s: ", m);
265         
266         gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
267                            &msg_ctx, &msg);
268         fprintf(stderr, "%s - ", (char *)msg.value);
269         gss_release_buffer(&min, &msg);
270
271         gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech,
272                            &msg_ctx, &msg);
273         fprintf(stderr, "%s\n", (char *)msg.value);
274         gss_release_buffer(&min, &msg);
275 }
276
277 #else
278
279 void
280 log_debug(__unused const char *fmt, ...)
281 {
282 }
283
284 void
285 log_status(__unused const char *m, __unused gss_OID mech,
286     __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat)
287 {
288 }
289
290 #endif
291
292