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 */
auth_gssapi_create_default(CLIENT * clnt,char * service_name)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 */
auth_gssapi_create(CLIENT * clnt,OM_uint32 * gssstat,OM_uint32 * minor_stat,gss_cred_id_t claimant_cred_handle,gss_name_t target_name,gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,gss_OID * actual_mech_type,OM_uint32 * ret_flags,OM_uint32 * time_rec)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(xdr_authgssapi_init_res, &call_res);
287 memset(&call_res, 0, sizeof(call_res));
288 callstat = clnt_call(clnt, init_func,
289 xdr_authgssapi_init_arg, &call_arg,
290 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(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(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 */
marshall_new_creds(AUTH * auth,bool_t auth_msg,gss_buffer_t client_handle)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 */
auth_gssapi_nextverf(AUTH * auth)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 */
auth_gssapi_marshall(AUTH * auth,XDR * xdrs)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 */
auth_gssapi_validate(AUTH * auth,struct opaque_auth * verf)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 */
auth_gssapi_refresh(AUTH * auth,struct rpc_msg * msg)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 */
auth_gssapi_destroy(AUTH * auth)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 */
auth_gssapi_wrap(AUTH * auth,XDR * out_xdrs,bool_t (* xdr_func)(),caddr_t xdr_ptr)760 static bool_t auth_gssapi_wrap(
761 AUTH *auth,
762 XDR *out_xdrs,
763 bool_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 */
auth_gssapi_unwrap(AUTH * auth,XDR * in_xdrs,bool_t (* xdr_func)(),caddr_t xdr_ptr)791 static bool_t auth_gssapi_unwrap(
792 AUTH *auth,
793 XDR *in_xdrs,
794 bool_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