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