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: stable/12/lib/librpcsec_gss/rpcsec_gss_prot.c 326025 2017-11-20 19:49:47Z pfg $ */
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
xdr_gss_buffer_desc(XDR * xdrs,gss_buffer_desc * p)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
xdr_rpc_gss_cred(XDR * xdrs,struct rpc_gss_cred * p)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
xdr_rpc_gss_init_res(XDR * xdrs,struct rpc_gss_init_res * p)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
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_service_t svc,u_int seq)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
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_service_t svc,u_int seq)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
log_debug(const char * fmt,...)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
log_status(const char * m,gss_OID mech,OM_uint32 maj_stat,OM_uint32 min_stat)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
log_debug(__unused const char * fmt,...)280 log_debug(__unused const char *fmt, ...)
281 {
282 }
283
284 void
log_status(__unused const char * m,__unused gss_OID mech,__unused OM_uint32 maj_stat,__unused OM_uint32 min_stat)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
293