Beispiel #1
0
OM_uint32 _gss_spnego_unseal
           (OM_uint32 * minor_status,
            gss_ctx_id_t context_handle,
            gss_buffer_t input_message_buffer,
            gss_buffer_t output_message_buffer,
            int * conf_state,
            int * qop_state
           )
{
    gssspnego_ctx ctx;

    *minor_status = 0;

    if (context_handle == GSS_C_NO_CONTEXT) {
	return GSS_S_NO_CONTEXT;
    }

    ctx = (gssspnego_ctx)context_handle;

    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
	return GSS_S_NO_CONTEXT;
    }

    return gss_unseal(minor_status,
		      ctx->negotiated_ctx_id,
		      input_message_buffer,
		      output_message_buffer,
		      conf_state,
		      qop_state);
}
Beispiel #2
0
static int
krb5_decode(void *app_data, void *buf, int len, int level,
            struct connectdata *conn)
{
  gss_ctx_id_t *context = app_data;
  OM_uint32 maj, min;
  gss_buffer_desc enc, dec;

  /* shut gcc up */
  level = 0;
  conn = NULL;

  enc.value = buf;
  enc.length = len;
  maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL);
  if(maj != GSS_S_COMPLETE) {
    if(len >= 4)
      strcpy(buf, "599 ");
    return -1;
  }

  memcpy(buf, dec.value, dec.length);
  len = dec.length;
  gss_release_buffer(&min, &dec);

  return len;
}
Beispiel #3
0
bool_t auth_gssapi_unseal_seq(
     gss_ctx_id_t context,
     gss_buffer_t in_buf,
     uint32_t *seq_num)
{
     gss_buffer_desc out_buf;
     OM_uint32 gssstat, minor_stat;
     uint32_t nl_seq_num;

     gssstat = gss_unseal(&minor_stat, context, in_buf, &out_buf,
			  NULL, NULL);
     if (gssstat != GSS_S_COMPLETE) {
	  PRINTF(("gssapi_unseal_seq: failed\n"));
	  AUTH_GSSAPI_DISPLAY_STATUS(("unsealing sequence number",
				      gssstat, minor_stat));
	  return FALSE;
     } else if (out_buf.length != sizeof(uint32_t)) {
	  PRINTF(("gssapi_unseal_seq: unseal gave %d bytes\n",
		  (int) out_buf.length));
	  gss_release_buffer(&minor_stat, &out_buf);
	  return FALSE;
     }

     nl_seq_num = *((uint32_t *) out_buf.value);
     *seq_num = (uint32_t) ntohl(nl_seq_num);
     gss_release_buffer(&minor_stat, &out_buf);

     return TRUE;
}
Beispiel #4
0
static int
k5_decrypt(
    void *cookie,
    void *buf,
    ssize_t buflen,
    void **decbuf,
    ssize_t *decbuflen)
{
    struct tcp_conn *rc = cookie;
    gss_buffer_desc enctok;
    gss_buffer_desc dectok;
    OM_uint32 maj_stat, min_stat;
    int conf_state, qop_state;

    if (rc->conf_fn && rc->conf_fn("kencrypt", rc->datap)) {
	auth_debug(1, _("krb5: k5_decrypt: enter\n"));
	if (rc->auth == 1) {
	    enctok.length = buflen;
	    enctok.value  = buf;    

	    auth_debug(1, _("krb5: k5_decrypt: decrypting %zu bytes\n"), enctok.length);

	    assert(rc->gss_context != GSS_C_NO_CONTEXT);
	    maj_stat = gss_unseal(&min_stat, rc->gss_context, &enctok, &dectok,
			      &conf_state, &qop_state);
	    if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
		auth_debug(1, _("krb5 decrypt error from %s: %s\n"),
			   rc->hostname, gss_error(maj_stat, min_stat));
		return (-1);
	    }
	    auth_debug(1, _("krb5: k5_decrypt: give %zu bytes\n"),
		       dectok.length);
	    *decbuf = dectok.value;
	    *decbuflen = dectok.length;
	} else {
	    *decbuf = buf;
	    *decbuflen = buflen;
	}
	auth_debug(1, _("krb5: k5_decrypt: exit\n"));
    } else {
	*decbuf = buf;
	*decbuflen = buflen;
    }
    return (0);
}
Beispiel #5
0
static int
krb5_decode(void *app_data, void *buf, int len,
            int level UNUSED_PARAM,
            struct connectdata *conn UNUSED_PARAM)
{
  gss_ctx_id_t *context = app_data;
  OM_uint32 maj, min;
  gss_buffer_desc enc, dec;

  (void)level;
  (void)conn;

  enc.value = buf;
  enc.length = len;
  maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL);
  if(maj != GSS_S_COMPLETE) {
    if(len >= 4)
      strcpy(buf, "599 ");
    return -1;
  }

  memcpy(buf, dec.value, dec.length);
  len = curlx_uztosi(dec.length);
  gss_release_buffer(&min, &dec);

  return len;
}

static int
krb5_overhead(void *app_data, int level, int len)
Beispiel #6
0
/*
 * Function: auth_gssapi_create
 *
 * Purpose: Create a GSS-API style authenticator, with all the
 * options, and return the handle.
 *
 * Effects: See design document, section XXX.
 */
AUTH *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)
{
     AUTH *auth, *save_auth;
     struct auth_gssapi_data *pdata;
     struct gss_channel_bindings_struct bindings, *bindp;
     struct sockaddr_in laddr, raddr;
     enum clnt_stat callstat;
     struct timeval timeout;
     int bindings_failed;
     rpcproc_t init_func;
     
     auth_gssapi_init_arg call_arg;
     auth_gssapi_init_res call_res;
     gss_buffer_desc *input_token, isn_buf;
     
     memset(&rpc_createerr, 0, sizeof(rpc_createerr));
     
     /* this timeout is only used if clnt_control(clnt, CLSET_TIMEOUT) */
     /* has not already been called.. therefore, we can just pick */
     /* something reasonable-sounding.. */
     timeout.tv_sec = 30;
     timeout.tv_usec = 0;
     
     auth = NULL;
     pdata = NULL;
     
     /* don't assume the caller will want to change clnt->cl_auth */
     save_auth = clnt->cl_auth;

     auth = (AUTH *) malloc(sizeof(*auth));
     pdata = (struct auth_gssapi_data *) malloc(sizeof(*pdata));
     if (auth == NULL || pdata == NULL) {
	  /* They needn't both have failed; clean up.  */
	  free(auth);
	  free(pdata);
	  auth = NULL;
	  pdata = NULL;
	  rpc_createerr.cf_stat = RPC_SYSTEMERROR;
	  rpc_createerr.cf_error.re_errno = ENOMEM;
	  goto cleanup;
     }
     memset((char *) auth, 0, sizeof(*auth));
     memset((char *) pdata, 0, sizeof(*pdata));
     
     auth->ah_ops = &auth_gssapi_ops;
     auth->ah_private = (caddr_t) pdata;
     
     /* initial creds are auth_msg TRUE and no handle */
     marshall_new_creds(auth, TRUE, NULL);
     
     /* initial verifier is empty */
     auth->ah_verf.oa_flavor = AUTH_GSSAPI;
     auth->ah_verf.oa_base = NULL;
     auth->ah_verf.oa_length = 0;
     
     AUTH_PRIVATE(auth)->established = FALSE;
     AUTH_PRIVATE(auth)->clnt = clnt;
     AUTH_PRIVATE(auth)->def_cred = (claimant_cred_handle ==
				     GSS_C_NO_CREDENTIAL);
     
     clnt->cl_auth = auth;

     /* start by trying latest version */
     call_arg.version = 4;
     bindings_failed = 0;

try_new_version:
     /* set state for initial call to init_sec_context */
     input_token = GSS_C_NO_BUFFER;
     AUTH_PRIVATE(auth)->context = GSS_C_NO_CONTEXT;
     init_func = AUTH_GSSAPI_INIT;

#ifdef GSSAPI_KRB5
     /*
      * OV servers up to version 3 used the old mech id.  Beta 7
      * servers used version 3 with the new mech id; however, the beta
      * 7 gss-api accept_sec_context accepts either mech id.  Thus, if
      * any server rejects version 4, we fall back to version 3 with
      * the old mech id; for the OV server it will be right, and for
      * the beta 7 server it will be accepted.  Not ideal, but it
      * works.
      */
     if (call_arg.version < 4 && (mech_type == gss_mech_krb5 ||
				  mech_type == GSS_C_NULL_OID))
	  mech_type = (gss_OID) gss_mech_krb5_old;
#endif

     if (!bindings_failed && call_arg.version >= 3) {
	  if (clnt_control(clnt, CLGET_LOCAL_ADDR, &laddr) == FALSE) {
	       PRINTF(("gssapi_create: CLGET_LOCAL_ADDR failed"));
	       goto cleanup;
	  }
	  if (clnt_control(clnt, CLGET_SERVER_ADDR, &raddr) == FALSE) {
	       PRINTF(("gssapi_create: CLGET_SERVER_ADDR failed"));
	       goto cleanup;
	  }

	  memset(&bindings, 0, sizeof(bindings));
	  bindings.application_data.length = 0;
	  bindings.initiator_addrtype = GSS_C_AF_INET;
	  bindings.initiator_address.length = 4;
	  bindings.initiator_address.value = &laddr.sin_addr.s_addr;
	  
	  bindings.acceptor_addrtype = GSS_C_AF_INET;
	  bindings.acceptor_address.length = 4;
	  bindings.acceptor_address.value = &raddr.sin_addr.s_addr;
	  bindp = &bindings;
     } else {
	  bindp = NULL;
     }
     
     memset((char *) &call_res, 0, sizeof(call_res));
     
next_token:
     *gssstat = gss_init_sec_context(minor_stat,
				     claimant_cred_handle,
				     &AUTH_PRIVATE(auth)->context,
				     target_name,
				     mech_type,
				     req_flags,
				     time_req,
				     bindp,
				     input_token,
				     actual_mech_type,
				     &call_arg.token,
				     ret_flags,
				     time_rec);
     
     if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) {
	  AUTH_GSSAPI_DISPLAY_STATUS(("initializing context", *gssstat,
				      *minor_stat));
	  goto cleanup;
     }
     
     /* if we got a token, pass it on */
     if (call_arg.token.length != 0) {
	  
	  /*
	   * sanity check: if we received a signed isn in the last
	   * response then there *cannot* be another token to send
	   */
	  if (call_res.signed_isn.length != 0) {
	       PRINTF(("gssapi_create: unexpected token from init_sec\n"));
	       goto cleanup;
	  }
	  
	  PRINTF(("gssapi_create: calling GSSAPI_INIT (%d)\n", init_func));
	  
	  memset((char *) &call_res, 0, sizeof(call_res));
	  callstat = clnt_call(clnt, init_func,
			       xdr_authgssapi_init_arg, &call_arg,
			       xdr_authgssapi_init_res, &call_res,
			       timeout);
	  gss_release_buffer(minor_stat, &call_arg.token);
	  
	  if (callstat != RPC_SUCCESS) {
	       struct rpc_err err;

	       clnt_geterr(clnt, &err);
	       if (callstat == RPC_AUTHERROR &&
		   (err.re_why == AUTH_BADCRED || err.re_why == AUTH_FAILED)
		   && call_arg.version >= 1) {
		    L_PRINTF(1,
			     ("call_arg protocol version %d rejected, trying %d.\n",
			    call_arg.version, call_arg.version-1));
		    call_arg.version--;
		    goto try_new_version;
	       } else {
		    PRINTF(("gssapi_create: GSSAPI_INIT (%d) failed, stat %d\n",
			    init_func, callstat));
	       }
	       
	       goto cleanup;
	  } else if (call_res.version != call_arg.version &&
		     !(call_arg.version == 2 && call_res.version == 1)) {
	       /*
		* The Secure 1.1 servers always respond with version
		* 1.  Thus, if we just tried a version >=3, fall all
		* the way back to version 1 since that is all they
		* understand
		*/
	       if (call_arg.version > 2 && call_res.version == 1) {
		    L_PRINTF(1,
			     ("Talking to Secure 1.1 server, using version 1.\n"));
		    call_arg.version = 1;
		    goto try_new_version;
	       }

	       PRINTF(("gssapi_create: invalid call_res vers %d\n",
		       call_res.version));
	       goto cleanup;
	  } else if (call_res.gss_major != GSS_S_COMPLETE) {
	       AUTH_GSSAPI_DISPLAY_STATUS(("in response from server",
					   call_res.gss_major,
					   call_res.gss_minor));
	       goto cleanup;
	  }
	  
	  PRINTF(("gssapi_create: GSSAPI_INIT (%d) succeeded\n", init_func));
	  init_func = AUTH_GSSAPI_CONTINUE_INIT;
	  
	  /* check for client_handle */
	  if (AUTH_PRIVATE(auth)->client_handle.length == 0) {
	       if (call_res.client_handle.length == 0) {
		    PRINTF(("gssapi_create: expected client_handle\n"));
		    goto cleanup;
	       } else {
		    PRINTF(("gssapi_create: got client_handle %d\n",
			    *((uint32_t *)call_res.client_handle.value)));
		    
		    GSS_DUP_BUFFER(AUTH_PRIVATE(auth)->client_handle,
				   call_res.client_handle);
		    
		    /* auth_msg is TRUE; there may be more tokens */
		    marshall_new_creds(auth, TRUE,
				       &AUTH_PRIVATE(auth)->client_handle); 
	       }
	  } else if (!GSS_BUFFERS_EQUAL(AUTH_PRIVATE(auth)->client_handle,
					call_res.client_handle)) {
	       PRINTF(("gssapi_create: got different client_handle\n"));
	       goto cleanup;
	  }
	  
	  /* check for token */
	  if (call_res.token.length==0 && *gssstat==GSS_S_CONTINUE_NEEDED) {
	       PRINTF(("gssapi_create: expected token\n"));
	       goto cleanup;
	  } else if (call_res.token.length != 0) {
	       if (*gssstat == GSS_S_COMPLETE) {
		    PRINTF(("gssapi_create: got unexpected token\n"));
		    goto cleanup;
	       } else {
		    /* assumes call_res is safe until init_sec_context */
		    input_token = &call_res.token;
		    PRINTF(("gssapi_create: got new token\n"));
	       }
	  }
     }
     
     /* check for isn */
     if (*gssstat == GSS_S_COMPLETE) {
	  if (call_res.signed_isn.length == 0) {
	       PRINTF(("gssapi_created: expected signed isn\n"));
	       goto cleanup;
	  } else {
	       PRINTF(("gssapi_create: processing signed isn\n"));
	       
	       /* don't check conf (integ only) or qop (accpet default) */
	       *gssstat = gss_unseal(minor_stat,
				     AUTH_PRIVATE(auth)->context,
				     &call_res.signed_isn,
				     &isn_buf, NULL, NULL);
	       
	       if (*gssstat != GSS_S_COMPLETE) {
		    AUTH_GSSAPI_DISPLAY_STATUS(("unsealing isn",
						*gssstat, *minor_stat)); 
		    goto cleanup;
	       } else if (isn_buf.length != sizeof(uint32_t)) {
		    PRINTF(("gssapi_create: gss_unseal gave %d bytes\n",
			    (int) isn_buf.length));
		    goto cleanup;
	       }
	       
	       AUTH_PRIVATE(auth)->seq_num = (uint32_t)
		    ntohl(*((uint32_t*)isn_buf.value)); 
	       *gssstat = gss_release_buffer(minor_stat, &isn_buf);
	       if (*gssstat != GSS_S_COMPLETE) {
		    AUTH_GSSAPI_DISPLAY_STATUS(("releasing unsealed isn",
						*gssstat, *minor_stat));
		    goto cleanup;
	       }
	       
	       PRINTF(("gssapi_create: isn is %d\n",
		       AUTH_PRIVATE(auth)->seq_num));
	       
	       /* we no longer need these results.. */
	       xdr_free(xdr_authgssapi_init_res, &call_res);
	  }
     } else if (call_res.signed_isn.length != 0) {
	  PRINTF(("gssapi_create: got signed isn, can't check yet\n"));
     }
     
     /* results were okay.. continue if necessary */
     if (*gssstat == GSS_S_CONTINUE_NEEDED) {
	  PRINTF(("gssapi_create: not done, continuing\n"));
	  goto next_token;
     }
     
     /*
      * Done!  Context is established, we have client_handle and isn.
      */
     AUTH_PRIVATE(auth)->established = TRUE;
     
     marshall_new_creds(auth, FALSE,
			&AUTH_PRIVATE(auth)->client_handle); 
     
     PRINTF(("gssapi_create: done. client_handle %#x, isn %d\n\n",
	     *((uint32_t *)AUTH_PRIVATE(auth)->client_handle.value),
	     AUTH_PRIVATE(auth)->seq_num));
     
     /* don't assume the caller will want to change clnt->cl_auth */
     clnt->cl_auth = save_auth;
     
     return auth;
     
     /******************************************************************/
     
cleanup:
     PRINTF(("gssapi_create: bailing\n\n"));

     if (auth) {
	 if (AUTH_PRIVATE(auth))
	     auth_gssapi_destroy(auth);
	 else
	     free(auth);
	 auth = NULL;
     }
     
     /* don't assume the caller will want to change clnt->cl_auth */
     clnt->cl_auth = save_auth;
     
     if (rpc_createerr.cf_stat == 0)
	  rpc_createerr.cf_stat = RPC_AUTHERROR;
     
     return auth;
}
Beispiel #7
0
bool_t auth_gssapi_unwrap_data(
     OM_uint32 *major,
     OM_uint32 *minor,
     gss_ctx_id_t context,
     uint32_t seq_num,
     XDR *in_xdrs,
     bool_t (*xdr_func)(),
     caddr_t xdr_ptr)
{
     gss_buffer_desc in_buf, out_buf;
     XDR temp_xdrs;
     uint32_t verf_seq_num;
     int conf, qop;
     unsigned int length;

     PRINTF(("gssapi_unwrap_data: starting\n"));

     *major = GSS_S_COMPLETE;
     *minor = 0; /* assumption */

     in_buf.value = NULL;
     out_buf.value = NULL;
     if (! xdr_bytes(in_xdrs, (char **) &in_buf.value,
		     &length, (unsigned int) -1)) {
	 PRINTF(("gssapi_unwrap_data: deserializing encrypted data failed\n"));
	 temp_xdrs.x_op = XDR_FREE;
	 (void)xdr_bytes(&temp_xdrs, (char **) &in_buf.value, &length,
			 (unsigned int) -1);
	 return FALSE;
     }
     in_buf.length = length;

     *major = gss_unseal(minor, context, &in_buf, &out_buf, &conf,
			 &qop);
     free(in_buf.value);
     if (*major != GSS_S_COMPLETE)
	  return FALSE;

     PRINTF(("gssapi_unwrap_data: %d bytes data, %d bytes sealed\n",
	     out_buf.length, in_buf.length));

     xdrmem_create(&temp_xdrs, out_buf.value, out_buf.length, XDR_DECODE);

     /* deserialize the sequence number */
     if (! xdr_u_int32(&temp_xdrs, &verf_seq_num)) {
	  PRINTF(("gssapi_unwrap_data: deserializing verf_seq_num failed\n"));
	  gss_release_buffer(minor, &out_buf);
	  XDR_DESTROY(&temp_xdrs);
	  return FALSE;
     }
     if (verf_seq_num != seq_num) {
	  PRINTF(("gssapi_unwrap_data: seq %d specified, read %d\n",
		  seq_num, verf_seq_num));
	  gss_release_buffer(minor, &out_buf);
	  XDR_DESTROY(&temp_xdrs);
	  return FALSE;
     }
     PRINTF(("gssapi_unwrap_data: unwrap seq_num %d okay\n", verf_seq_num));

     /* deserialize the arguments into xdr_ptr */
     if (! (*xdr_func)(&temp_xdrs, xdr_ptr)) {
	  PRINTF(("gssapi_unwrap_data: deserializing arguments failed\n"));
	  gss_release_buffer(minor, &out_buf);
	  xdr_free(xdr_func, xdr_ptr);
	  XDR_DESTROY(&temp_xdrs);
	  return FALSE;
     }

     PRINTF(("gssapi_unwrap_data: succeeding\n\n"));

     gss_release_buffer(minor, &out_buf);
     XDR_DESTROY(&temp_xdrs);
     return TRUE;
}