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