Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/lib/rpc/auth_gssapi.c
39536 views
1
/*
2
* Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
3
*
4
*/
5
6
#include <stdio.h>
7
#include <string.h>
8
#include <sys/errno.h>
9
10
#include <gssapi/gssapi.h>
11
#include <gssapi/gssapi_generic.h>
12
#ifdef GSSAPI_KRB5
13
#include <gssapi/gssapi_krb5.h>
14
#endif
15
16
#include <gssrpc/rpc.h>
17
#include <gssrpc/auth_gssapi.h>
18
19
#include "gssrpcint.h"
20
21
#ifdef __CODECENTER__
22
#define DEBUG_GSSAPI 1
23
#endif
24
25
#ifdef DEBUG_GSSAPI
26
int auth_debug_gssapi = DEBUG_GSSAPI;
27
extern void gssrpcint_printf(const char *format, ...);
28
#define L_PRINTF(l,args) if (auth_debug_gssapi >= l) gssrpcint_printf args
29
#define PRINTF(args) L_PRINTF(99, args)
30
#define AUTH_GSSAPI_DISPLAY_STATUS(args) \
31
if (auth_debug_gssapi) auth_gssapi_display_status args
32
#else
33
#define PRINTF(args)
34
#define L_PRINTF(l, args)
35
#define AUTH_GSSAPI_DISPLAY_STATUS(args)
36
#endif
37
38
static void auth_gssapi_nextverf(AUTH *);
39
static bool_t auth_gssapi_marshall(AUTH *, XDR *);
40
static bool_t auth_gssapi_validate(AUTH *, struct opaque_auth *);
41
static bool_t auth_gssapi_refresh(AUTH *, struct rpc_msg *);
42
static bool_t auth_gssapi_wrap(AUTH *, XDR *, xdrproc_t, caddr_t);
43
static bool_t auth_gssapi_unwrap(AUTH *, XDR *, xdrproc_t, caddr_t);
44
static void auth_gssapi_destroy(AUTH *);
45
46
static bool_t marshall_new_creds(AUTH *, bool_t, gss_buffer_t);
47
48
static struct auth_ops auth_gssapi_ops = {
49
auth_gssapi_nextverf,
50
auth_gssapi_marshall,
51
auth_gssapi_validate,
52
auth_gssapi_refresh,
53
auth_gssapi_destroy,
54
auth_gssapi_wrap,
55
auth_gssapi_unwrap,
56
};
57
58
/*
59
* the ah_private data structure for an auth_handle
60
*/
61
struct auth_gssapi_data {
62
bool_t established;
63
CLIENT *clnt;
64
gss_ctx_id_t context;
65
gss_buffer_desc client_handle;
66
uint32_t seq_num;
67
int def_cred;
68
69
/* pre-serialized ah_cred */
70
unsigned char cred_buf[MAX_AUTH_BYTES];
71
uint32_t cred_len;
72
};
73
#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private)
74
75
/*
76
* Function: auth_gssapi_create_default
77
*
78
* Purpose: Create a GSS-API style authenticator, with default
79
* options, and return the handle.
80
*
81
* Effects: See design document, section XXX.
82
*/
83
AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name)
84
{
85
AUTH *auth;
86
OM_uint32 gssstat, minor_stat;
87
gss_buffer_desc input_name;
88
gss_name_t target_name;
89
90
input_name.value = service_name;
91
input_name.length = strlen(service_name) + 1;
92
93
gssstat = gss_import_name(&minor_stat, &input_name,
94
gss_nt_service_name, &target_name);
95
if (gssstat != GSS_S_COMPLETE) {
96
AUTH_GSSAPI_DISPLAY_STATUS(("parsing name", gssstat,
97
minor_stat));
98
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
99
rpc_createerr.cf_error.re_errno = ENOMEM;
100
return NULL;
101
}
102
103
auth = auth_gssapi_create(clnt,
104
&gssstat,
105
&minor_stat,
106
GSS_C_NO_CREDENTIAL,
107
target_name,
108
GSS_C_NULL_OID,
109
GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
110
0,
111
NULL,
112
NULL,
113
NULL);
114
115
gss_release_name(&minor_stat, &target_name);
116
return auth;
117
}
118
119
/*
120
* Function: auth_gssapi_create
121
*
122
* Purpose: Create a GSS-API style authenticator, with all the
123
* options, and return the handle.
124
*
125
* Effects: See design document, section XXX.
126
*/
127
AUTH *auth_gssapi_create(
128
CLIENT *clnt,
129
OM_uint32 *gssstat,
130
OM_uint32 *minor_stat,
131
gss_cred_id_t claimant_cred_handle,
132
gss_name_t target_name,
133
gss_OID mech_type,
134
OM_uint32 req_flags,
135
OM_uint32 time_req,
136
gss_OID *actual_mech_type,
137
OM_uint32 *ret_flags,
138
OM_uint32 *time_rec)
139
{
140
AUTH *auth, *save_auth;
141
struct auth_gssapi_data *pdata;
142
struct gss_channel_bindings_struct bindings, *bindp;
143
struct sockaddr_in laddr, raddr;
144
enum clnt_stat callstat;
145
struct timeval timeout;
146
int bindings_failed;
147
rpcproc_t init_func;
148
149
auth_gssapi_init_arg call_arg;
150
auth_gssapi_init_res call_res;
151
gss_buffer_desc *input_token, isn_buf;
152
153
memset(&rpc_createerr, 0, sizeof(rpc_createerr));
154
155
/* this timeout is only used if clnt_control(clnt, CLSET_TIMEOUT) */
156
/* has not already been called.. therefore, we can just pick */
157
/* something reasonable-sounding.. */
158
timeout.tv_sec = 30;
159
timeout.tv_usec = 0;
160
161
auth = NULL;
162
pdata = NULL;
163
164
/* don't assume the caller will want to change clnt->cl_auth */
165
save_auth = clnt->cl_auth;
166
167
auth = (AUTH *) malloc(sizeof(*auth));
168
pdata = (struct auth_gssapi_data *) malloc(sizeof(*pdata));
169
if (auth == NULL || pdata == NULL) {
170
/* They needn't both have failed; clean up. */
171
free(auth);
172
free(pdata);
173
auth = NULL;
174
pdata = NULL;
175
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
176
rpc_createerr.cf_error.re_errno = ENOMEM;
177
goto cleanup;
178
}
179
memset(auth, 0, sizeof(*auth));
180
memset(pdata, 0, sizeof(*pdata));
181
182
auth->ah_ops = &auth_gssapi_ops;
183
auth->ah_private = (caddr_t) pdata;
184
185
/* initial creds are auth_msg TRUE and no handle */
186
marshall_new_creds(auth, TRUE, NULL);
187
188
/* initial verifier is empty */
189
auth->ah_verf.oa_flavor = AUTH_GSSAPI;
190
auth->ah_verf.oa_base = NULL;
191
auth->ah_verf.oa_length = 0;
192
193
AUTH_PRIVATE(auth)->established = FALSE;
194
AUTH_PRIVATE(auth)->clnt = clnt;
195
AUTH_PRIVATE(auth)->def_cred = (claimant_cred_handle ==
196
GSS_C_NO_CREDENTIAL);
197
198
clnt->cl_auth = auth;
199
200
/* start by trying latest version */
201
call_arg.version = 4;
202
bindings_failed = 0;
203
204
try_new_version:
205
/* set state for initial call to init_sec_context */
206
input_token = GSS_C_NO_BUFFER;
207
AUTH_PRIVATE(auth)->context = GSS_C_NO_CONTEXT;
208
init_func = AUTH_GSSAPI_INIT;
209
210
#ifdef GSSAPI_KRB5
211
/*
212
* OV servers up to version 3 used the old mech id. Beta 7
213
* servers used version 3 with the new mech id; however, the beta
214
* 7 gss-api accept_sec_context accepts either mech id. Thus, if
215
* any server rejects version 4, we fall back to version 3 with
216
* the old mech id; for the OV server it will be right, and for
217
* the beta 7 server it will be accepted. Not ideal, but it
218
* works.
219
*/
220
if (call_arg.version < 4 && (mech_type == gss_mech_krb5 ||
221
mech_type == GSS_C_NULL_OID))
222
mech_type = (gss_OID) gss_mech_krb5_old;
223
#endif
224
225
if (!bindings_failed && call_arg.version >= 3) {
226
if (clnt_control(clnt, CLGET_LOCAL_ADDR, &laddr) == FALSE) {
227
PRINTF(("gssapi_create: CLGET_LOCAL_ADDR failed"));
228
goto cleanup;
229
}
230
if (clnt_control(clnt, CLGET_SERVER_ADDR, &raddr) == FALSE) {
231
PRINTF(("gssapi_create: CLGET_SERVER_ADDR failed"));
232
goto cleanup;
233
}
234
235
memset(&bindings, 0, sizeof(bindings));
236
bindings.application_data.length = 0;
237
bindings.initiator_addrtype = GSS_C_AF_INET;
238
bindings.initiator_address.length = 4;
239
bindings.initiator_address.value = &laddr.sin_addr.s_addr;
240
241
bindings.acceptor_addrtype = GSS_C_AF_INET;
242
bindings.acceptor_address.length = 4;
243
bindings.acceptor_address.value = &raddr.sin_addr.s_addr;
244
bindp = &bindings;
245
} else {
246
bindp = NULL;
247
}
248
249
memset(&call_res, 0, sizeof(call_res));
250
251
next_token:
252
*gssstat = gss_init_sec_context(minor_stat,
253
claimant_cred_handle,
254
&AUTH_PRIVATE(auth)->context,
255
target_name,
256
mech_type,
257
req_flags,
258
time_req,
259
bindp,
260
input_token,
261
actual_mech_type,
262
&call_arg.token,
263
ret_flags,
264
time_rec);
265
266
if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) {
267
AUTH_GSSAPI_DISPLAY_STATUS(("initializing context", *gssstat,
268
*minor_stat));
269
goto cleanup;
270
}
271
272
/* if we got a token, pass it on */
273
if (call_arg.token.length != 0) {
274
275
/*
276
* sanity check: if we received a signed isn in the last
277
* response then there *cannot* be another token to send
278
*/
279
if (call_res.signed_isn.length != 0) {
280
PRINTF(("gssapi_create: unexpected token from init_sec\n"));
281
goto cleanup;
282
}
283
284
PRINTF(("gssapi_create: calling GSSAPI_INIT (%d)\n", init_func));
285
286
xdr_free((xdrproc_t)xdr_authgssapi_init_res, &call_res);
287
memset(&call_res, 0, sizeof(call_res));
288
callstat = clnt_call(clnt, init_func,
289
(xdrproc_t)xdr_authgssapi_init_arg, &call_arg,
290
(xdrproc_t)xdr_authgssapi_init_res, &call_res,
291
timeout);
292
gss_release_buffer(minor_stat, &call_arg.token);
293
294
if (callstat != RPC_SUCCESS) {
295
struct rpc_err err;
296
297
clnt_geterr(clnt, &err);
298
if (callstat == RPC_AUTHERROR &&
299
(err.re_why == AUTH_BADCRED || err.re_why == AUTH_FAILED)
300
&& call_arg.version >= 1) {
301
L_PRINTF(1,
302
("call_arg protocol version %d rejected, trying %d.\n",
303
call_arg.version, call_arg.version-1));
304
call_arg.version--;
305
goto try_new_version;
306
} else {
307
PRINTF(("gssapi_create: GSSAPI_INIT (%d) failed, stat %d\n",
308
init_func, callstat));
309
}
310
311
goto cleanup;
312
} else if (call_res.version != call_arg.version &&
313
!(call_arg.version == 2 && call_res.version == 1)) {
314
/*
315
* The Secure 1.1 servers always respond with version
316
* 1. Thus, if we just tried a version >=3, fall all
317
* the way back to version 1 since that is all they
318
* understand
319
*/
320
if (call_arg.version > 2 && call_res.version == 1) {
321
L_PRINTF(1,
322
("Talking to Secure 1.1 server, using version 1.\n"));
323
call_arg.version = 1;
324
goto try_new_version;
325
}
326
327
PRINTF(("gssapi_create: invalid call_res vers %d\n",
328
call_res.version));
329
goto cleanup;
330
} else if (call_res.gss_major != GSS_S_COMPLETE) {
331
AUTH_GSSAPI_DISPLAY_STATUS(("in response from server",
332
call_res.gss_major,
333
call_res.gss_minor));
334
goto cleanup;
335
}
336
337
PRINTF(("gssapi_create: GSSAPI_INIT (%d) succeeded\n", init_func));
338
init_func = AUTH_GSSAPI_CONTINUE_INIT;
339
340
/* check for client_handle */
341
if (AUTH_PRIVATE(auth)->client_handle.length == 0) {
342
if (call_res.client_handle.length == 0) {
343
PRINTF(("gssapi_create: expected client_handle\n"));
344
goto cleanup;
345
} else {
346
PRINTF(("gssapi_create: got client_handle %d\n",
347
*((uint32_t *)call_res.client_handle.value)));
348
349
GSS_DUP_BUFFER(AUTH_PRIVATE(auth)->client_handle,
350
call_res.client_handle);
351
352
/* auth_msg is TRUE; there may be more tokens */
353
marshall_new_creds(auth, TRUE,
354
&AUTH_PRIVATE(auth)->client_handle);
355
}
356
} else if (!GSS_BUFFERS_EQUAL(AUTH_PRIVATE(auth)->client_handle,
357
call_res.client_handle)) {
358
PRINTF(("gssapi_create: got different client_handle\n"));
359
goto cleanup;
360
}
361
362
/* check for token */
363
if (call_res.token.length==0 && *gssstat==GSS_S_CONTINUE_NEEDED) {
364
PRINTF(("gssapi_create: expected token\n"));
365
goto cleanup;
366
} else if (call_res.token.length != 0) {
367
if (*gssstat == GSS_S_COMPLETE) {
368
PRINTF(("gssapi_create: got unexpected token\n"));
369
goto cleanup;
370
} else {
371
/* assumes call_res is safe until init_sec_context */
372
input_token = &call_res.token;
373
PRINTF(("gssapi_create: got new token\n"));
374
}
375
}
376
}
377
378
/* check for isn */
379
if (*gssstat == GSS_S_COMPLETE) {
380
if (call_res.signed_isn.length == 0) {
381
PRINTF(("gssapi_created: expected signed isn\n"));
382
goto cleanup;
383
} else {
384
PRINTF(("gssapi_create: processing signed isn\n"));
385
386
/* don't check conf (integ only) or qop (accept default) */
387
*gssstat = gss_unseal(minor_stat,
388
AUTH_PRIVATE(auth)->context,
389
&call_res.signed_isn,
390
&isn_buf, NULL, NULL);
391
392
if (*gssstat != GSS_S_COMPLETE) {
393
AUTH_GSSAPI_DISPLAY_STATUS(("unsealing isn",
394
*gssstat, *minor_stat));
395
goto cleanup;
396
} else if (isn_buf.length != sizeof(uint32_t)) {
397
PRINTF(("gssapi_create: gss_unseal gave %d bytes\n",
398
(int) isn_buf.length));
399
goto cleanup;
400
}
401
402
AUTH_PRIVATE(auth)->seq_num = (uint32_t)
403
ntohl(*((uint32_t*)isn_buf.value));
404
*gssstat = gss_release_buffer(minor_stat, &isn_buf);
405
if (*gssstat != GSS_S_COMPLETE) {
406
AUTH_GSSAPI_DISPLAY_STATUS(("releasing unsealed isn",
407
*gssstat, *minor_stat));
408
goto cleanup;
409
}
410
411
PRINTF(("gssapi_create: isn is %d\n",
412
AUTH_PRIVATE(auth)->seq_num));
413
}
414
} else if (call_res.signed_isn.length != 0) {
415
PRINTF(("gssapi_create: got signed isn, can't check yet\n"));
416
}
417
418
/* results were okay.. continue if necessary */
419
if (*gssstat == GSS_S_CONTINUE_NEEDED) {
420
PRINTF(("gssapi_create: not done, continuing\n"));
421
goto next_token;
422
}
423
424
/*
425
* Done! Context is established, we have client_handle and isn.
426
*/
427
AUTH_PRIVATE(auth)->established = TRUE;
428
429
marshall_new_creds(auth, FALSE,
430
&AUTH_PRIVATE(auth)->client_handle);
431
432
PRINTF(("gssapi_create: done. client_handle %#x, isn %d\n\n",
433
*((uint32_t *)AUTH_PRIVATE(auth)->client_handle.value),
434
AUTH_PRIVATE(auth)->seq_num));
435
436
/* don't assume the caller will want to change clnt->cl_auth */
437
clnt->cl_auth = save_auth;
438
439
xdr_free((xdrproc_t)xdr_authgssapi_init_res, &call_res);
440
return auth;
441
442
/******************************************************************/
443
444
cleanup:
445
PRINTF(("gssapi_create: bailing\n\n"));
446
447
if (auth) {
448
if (AUTH_PRIVATE(auth))
449
auth_gssapi_destroy(auth);
450
else
451
free(auth);
452
auth = NULL;
453
}
454
455
/* don't assume the caller will want to change clnt->cl_auth */
456
clnt->cl_auth = save_auth;
457
458
if (rpc_createerr.cf_stat == 0)
459
rpc_createerr.cf_stat = RPC_AUTHERROR;
460
461
xdr_free((xdrproc_t)xdr_authgssapi_init_res, &call_res);
462
return auth;
463
}
464
465
/*
466
* Function: marshall_new_creds
467
*
468
* Purpose: (pre-)serialize auth_msg and client_handle fields of
469
* auth_gssapi_creds into auth->cred_buf
470
*
471
* Arguments:
472
*
473
* auth (r/w) the AUTH structure to modify
474
* auth_msg (r) the auth_msg field to serialize
475
* client_handle (r) the client_handle field to serialize, or
476
* NULL
477
*
478
* Returns: TRUE if successful, FALSE if not
479
*
480
* Requires: auth must point to a valid GSS-API auth structure, auth_msg
481
* must be TRUE or FALSE, client_handle must be a gss_buffer_t with a valid
482
* value and length field or NULL.
483
*
484
* Effects: auth->ah_cred is set to the serialized auth_gssapi_creds
485
* version 2 structure (stored in the cred_buf field of private data)
486
* containing version, auth_msg and client_handle.
487
* auth->ah_cred.oa_flavor is set to AUTH_GSSAPI. If cliend_handle is
488
* NULL, it is treated as if it had a length of 0 and a value of NULL.
489
*
490
* Modifies: auth
491
*/
492
static bool_t marshall_new_creds(
493
AUTH *auth,
494
bool_t auth_msg,
495
gss_buffer_t client_handle)
496
{
497
auth_gssapi_creds creds;
498
XDR xdrs;
499
500
PRINTF(("marshall_new_creds: starting\n"));
501
502
creds.version = 2;
503
504
creds.auth_msg = auth_msg;
505
if (client_handle)
506
GSS_COPY_BUFFER(creds.client_handle, *client_handle)
507
else {
508
creds.client_handle.length = 0;
509
creds.client_handle.value = NULL;
510
}
511
512
xdrmem_create(&xdrs, (caddr_t) AUTH_PRIVATE(auth)->cred_buf,
513
MAX_AUTH_BYTES, XDR_ENCODE);
514
if (! xdr_authgssapi_creds(&xdrs, &creds)) {
515
PRINTF(("marshall_new_creds: failed encoding auth_gssapi_creds\n"));
516
XDR_DESTROY(&xdrs);
517
return FALSE;
518
}
519
AUTH_PRIVATE(auth)->cred_len = xdr_getpos(&xdrs);
520
XDR_DESTROY(&xdrs);
521
522
PRINTF(("marshall_new_creds: auth_gssapi_creds is %d bytes\n",
523
AUTH_PRIVATE(auth)->cred_len));
524
525
auth->ah_cred.oa_flavor = AUTH_GSSAPI;
526
auth->ah_cred.oa_base = (char *) AUTH_PRIVATE(auth)->cred_buf;
527
auth->ah_cred.oa_length = AUTH_PRIVATE(auth)->cred_len;
528
529
PRINTF(("marshall_new_creds: succeeding\n"));
530
531
return TRUE;
532
}
533
534
535
/*
536
* Function: auth_gssapi_nextverf
537
*
538
* Purpose: None.
539
*
540
* Effects: None. Never called.
541
*/
542
static void auth_gssapi_nextverf(AUTH *auth)
543
{
544
}
545
546
/*
547
* Function: auth_gssapi_marhsall
548
*
549
* Purpose: Marshall RPC credentials and verifier onto xdr stream.
550
*
551
* Arguments:
552
*
553
* auth (r/w) AUTH structure for client
554
* xdrs (r/w) XDR stream to marshall to
555
*
556
* Returns: boolean indicating success/failure
557
*
558
* Effects:
559
*
560
* The pre-serialized credentials in cred_buf are serialized. If the
561
* context is established, the sealed sequence number is serialized as
562
* the verifier. If the context is not established, an empty verifier
563
* is serialized. The sequence number is *not* incremented, because
564
* this function is called multiple times if retransmission is required.
565
*
566
* If this took all the header fields as arguments, it could sign
567
* them.
568
*/
569
static bool_t auth_gssapi_marshall(
570
AUTH *auth,
571
XDR *xdrs)
572
{
573
OM_uint32 minor_stat;
574
gss_buffer_desc out_buf;
575
uint32_t seq_num;
576
577
if (AUTH_PRIVATE(auth)->established == TRUE) {
578
PRINTF(("gssapi_marshall: starting\n"));
579
580
seq_num = AUTH_PRIVATE(auth)->seq_num + 1;
581
582
PRINTF(("gssapi_marshall: sending seq_num %d\n", seq_num));
583
584
if (auth_gssapi_seal_seq(AUTH_PRIVATE(auth)->context, seq_num,
585
&out_buf) == FALSE) {
586
PRINTF(("gssapi_marhshall: seal failed\n"));
587
}
588
589
auth->ah_verf.oa_base = out_buf.value;
590
auth->ah_verf.oa_length = out_buf.length;
591
592
if (! xdr_opaque_auth(xdrs, &auth->ah_cred) ||
593
! xdr_opaque_auth(xdrs, &auth->ah_verf)) {
594
(void) gss_release_buffer(&minor_stat, &out_buf);
595
return FALSE;
596
}
597
(void) gss_release_buffer(&minor_stat, &out_buf);
598
} else {
599
PRINTF(("gssapi_marshall: not established, sending null verf\n"));
600
601
auth->ah_verf.oa_base = NULL;
602
auth->ah_verf.oa_length = 0;
603
604
if (! xdr_opaque_auth(xdrs, &auth->ah_cred) ||
605
! xdr_opaque_auth(xdrs, &auth->ah_verf)) {
606
return FALSE;
607
}
608
}
609
610
return TRUE;
611
}
612
613
/*
614
* Function: auth_gssapi_validate
615
*
616
* Purpose: Validate RPC response verifier from server.
617
*
618
* Effects: See design document, section XXX.
619
*/
620
static bool_t auth_gssapi_validate(
621
AUTH *auth,
622
struct opaque_auth *verf)
623
{
624
gss_buffer_desc in_buf;
625
uint32_t seq_num;
626
627
if (AUTH_PRIVATE(auth)->established == FALSE) {
628
PRINTF(("gssapi_validate: not established, noop\n"));
629
return TRUE;
630
}
631
632
PRINTF(("gssapi_validate: starting\n"));
633
634
in_buf.length = verf->oa_length;
635
in_buf.value = verf->oa_base;
636
if (auth_gssapi_unseal_seq(AUTH_PRIVATE(auth)->context, &in_buf,
637
&seq_num) == FALSE) {
638
PRINTF(("gssapi_validate: failed unsealing verifier\n"));
639
return FALSE;
640
}
641
642
/* we sent seq_num+1, so we should get back seq_num+2 */
643
if (AUTH_PRIVATE(auth)->seq_num+2 != seq_num) {
644
PRINTF(("gssapi_validate: expecting seq_num %d, got %d (%#x)\n",
645
AUTH_PRIVATE(auth)->seq_num + 2, seq_num, seq_num));
646
return FALSE;
647
}
648
PRINTF(("gssapi_validate: seq_num %d okay\n", seq_num));
649
650
/* +1 for successful transmission, +1 for successful validation */
651
AUTH_PRIVATE(auth)->seq_num += 2;
652
653
PRINTF(("gssapi_validate: succeeding\n"));
654
655
return TRUE;
656
}
657
658
/*
659
* Function: auth_gssapi_refresh
660
*
661
* Purpose: Attempts to resyncrhonize the sequence number.
662
*
663
* Effects:
664
*
665
* When the server receives a properly authenticated RPC call, it
666
* increments the sequence number it is expecting from the client.
667
* But if the server's response is lost for any reason, the client
668
* can't know whether the server ever received it, assumes it didn't,
669
* and does *not* increment its sequence number. Thus, the client's
670
* next call will fail with AUTH_REJECTEDCRED because the server will
671
* think it is a replay attack.
672
*
673
* When an AUTH_REJECTEDCRED error arrives, this function attempts to
674
* resyncrhonize by incrementing the client's sequence number and
675
* returning TRUE. If any other error arrives, it returns FALSE.
676
*/
677
static bool_t auth_gssapi_refresh(
678
AUTH *auth,
679
struct rpc_msg *msg)
680
{
681
if (msg->rm_reply.rp_rjct.rj_stat == AUTH_ERROR &&
682
msg->rm_reply.rp_rjct.rj_why == AUTH_REJECTEDVERF) {
683
PRINTF(("gssapi_refresh: rejected verifier, incrementing\n"));
684
AUTH_PRIVATE(auth)->seq_num++;
685
return TRUE;
686
} else {
687
PRINTF(("gssapi_refresh: failing\n"));
688
return FALSE;
689
}
690
}
691
692
/*
693
* Function: auth_gssapi_destroy
694
*
695
* Purpose: Destroy a GSS-API authentication structure.
696
*
697
* Effects: This function destroys the GSS-API authentication
698
* context, and sends a message to the server instructing it to
699
* invokte gss_process_token() and thereby destroy its corresponding
700
* context. Since the client doesn't really care whether the server
701
* gets this message, no failures are reported.
702
*/
703
static void auth_gssapi_destroy(AUTH *auth)
704
{
705
struct timeval timeout;
706
OM_uint32 gssstat, minor_stat;
707
gss_cred_id_t cred;
708
int callstat;
709
710
if (AUTH_PRIVATE(auth)->client_handle.length == 0) {
711
PRINTF(("gssapi_destroy: no client_handle, not calling destroy\n"));
712
goto skip_call;
713
}
714
715
PRINTF(("gssapi_destroy: marshalling new creds\n"));
716
if (!marshall_new_creds(auth, TRUE, &AUTH_PRIVATE(auth)->client_handle)) {
717
PRINTF(("gssapi_destroy: marshall_new_creds failed\n"));
718
goto skip_call;
719
}
720
721
PRINTF(("gssapi_destroy: calling GSSAPI_DESTROY\n"));
722
timeout.tv_sec = 1;
723
timeout.tv_usec = 0;
724
callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_DESTROY,
725
xdr_void, NULL, xdr_void, NULL, timeout);
726
if (callstat != RPC_SUCCESS)
727
clnt_sperror(AUTH_PRIVATE(auth)->clnt,
728
"gssapi_destroy: GSSAPI_DESTROY failed");
729
730
skip_call:
731
PRINTF(("gssapi_destroy: deleting context\n"));
732
gssstat = gss_delete_sec_context(&minor_stat,
733
&AUTH_PRIVATE(auth)->context,
734
NULL);
735
if (gssstat != GSS_S_COMPLETE)
736
AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat,
737
minor_stat));
738
if (AUTH_PRIVATE(auth)->def_cred) {
739
cred = GSS_C_NO_CREDENTIAL;
740
gssstat = gss_release_cred(&minor_stat, &cred);
741
if (gssstat != GSS_S_COMPLETE)
742
AUTH_GSSAPI_DISPLAY_STATUS(("deleting default credential",
743
gssstat, minor_stat));
744
}
745
746
free(AUTH_PRIVATE(auth)->client_handle.value);
747
free(auth->ah_private);
748
free(auth);
749
PRINTF(("gssapi_destroy: done\n"));
750
}
751
752
/*
753
* Function: auth_gssapi_wrap
754
*
755
* Purpose: encrypt the serialized arguments from xdr_func applied to
756
* xdr_ptr and write the result to xdrs.
757
*
758
* Effects: See design doc, section XXX.
759
*/
760
static bool_t auth_gssapi_wrap(
761
AUTH *auth,
762
XDR *out_xdrs,
763
xdrproc_t xdr_func,
764
caddr_t xdr_ptr)
765
{
766
OM_uint32 gssstat, minor_stat;
767
768
if (! AUTH_PRIVATE(auth)->established) {
769
PRINTF(("gssapi_wrap: context not established, noop\n"));
770
return (*xdr_func)(out_xdrs, xdr_ptr);
771
} else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat,
772
AUTH_PRIVATE(auth)->context,
773
AUTH_PRIVATE(auth)->seq_num+1,
774
out_xdrs, xdr_func, xdr_ptr)) {
775
if (gssstat != GSS_S_COMPLETE)
776
AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments",
777
gssstat, minor_stat));
778
return FALSE;
779
} else
780
return TRUE;
781
}
782
783
/*
784
* Function: auth_gssapi_unwrap
785
*
786
* Purpose: read encrypted arguments from xdrs, decrypt, and
787
* deserialize with xdr_func into xdr_ptr.
788
*
789
* Effects: See design doc, section XXX.
790
*/
791
static bool_t auth_gssapi_unwrap(
792
AUTH *auth,
793
XDR *in_xdrs,
794
xdrproc_t xdr_func,
795
caddr_t xdr_ptr)
796
{
797
OM_uint32 gssstat, minor_stat;
798
799
if (! AUTH_PRIVATE(auth)->established) {
800
PRINTF(("gssapi_unwrap: context not established, noop\n"));
801
return (*xdr_func)(in_xdrs, xdr_ptr);
802
} else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat,
803
AUTH_PRIVATE(auth)->context,
804
AUTH_PRIVATE(auth)->seq_num,
805
in_xdrs, xdr_func, xdr_ptr)) {
806
if (gssstat != GSS_S_COMPLETE)
807
AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments",
808
gssstat, minor_stat));
809
return FALSE;
810
} else
811
return TRUE;
812
}
813
814