Ejemplo n.º 1
0
int
main(int argc, char *argv[])
{
    OM_uint32 minor, major, flags;
    gss_OID mech = &mech_krb5;
    gss_name_t tname;
    gss_buffer_desc itok, atok;
    gss_ctx_id_t ictx = GSS_C_NO_CONTEXT, actx = GSS_C_NO_CONTEXT;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s targetname\n", argv[0]);
        return 1;
    }
    tname = import_name(argv[1]);

    /* Get the initial context token. */
    flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_MUTUAL_FLAG;
    major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ictx, tname,
                                 mech, flags, GSS_C_INDEFINITE,
                                 GSS_C_NO_CHANNEL_BINDINGS, GSS_C_NO_BUFFER,
                                 NULL, &itok, NULL, NULL);
    check_gsserr("gss_init_sec_context(1)", major, minor);
    assert(major == GSS_S_CONTINUE_NEEDED);

    /* Process this token into an acceptor context, then discard it. */
    major = gss_accept_sec_context(&minor, &actx, GSS_C_NO_CREDENTIAL, &itok,
                                   GSS_C_NO_CHANNEL_BINDINGS, NULL,
                                   NULL, &atok, NULL, NULL, NULL);
    check_gsserr("gss_accept_sec_context(1)", major, minor);
    (void)gss_release_buffer(&minor, &atok);
    (void)gss_delete_sec_context(&minor, &actx, NULL);

    /* Process the same token again, producing a replay error. */
    major = gss_accept_sec_context(&minor, &actx, GSS_C_NO_CREDENTIAL, &itok,
                                   GSS_C_NO_CHANNEL_BINDINGS, NULL,
                                   NULL, &atok, NULL, NULL, NULL);
    check_replay_error("gss_accept_sec_context(2)", major, minor);
    assert(atok.length != 0);

    /* Send the error token back the initiator. */
    (void)gss_release_buffer(&minor, &itok);
    major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ictx, tname,
                                 mech, flags, GSS_C_INDEFINITE,
                                 GSS_C_NO_CHANNEL_BINDINGS, &atok,
                                 NULL, &itok, NULL, NULL);
    check_replay_error("gss_init_sec_context(2)", major, minor);

    (void)gss_release_name(&minor, &tname);
    (void)gss_release_buffer(&minor, &itok);
    (void)gss_release_buffer(&minor, &atok);
    (void)gss_delete_sec_context(&minor, &ictx, NULL);
    (void)gss_delete_sec_context(&minor, &actx, NULL);
    return 0;
}
Ejemplo n.º 2
0
uint32_t
sapgss_accept_sec_context(
    uint32_t *minor_status,
    gss_ctx_id_t *context_handle,
    gss_cred_id_t acceptor_cred_handle,
    gss_buffer_t input_token_buffer,
    sapgss_channel_bindings_t input_chan_bindings,
    gss_name_t *src_name,
    sapgss_OID *mech_type,
    gss_buffer_t output_token,
    uint32_t *ret_flags,
    uint32_t *time_rec,
    gss_cred_id_t *delegated_cred_handle)
{
    gss_OID mech_type_loc;
    uint32_t major_status;
    int ret;

    memset(&mech_type_loc, 0, sizeof(mech_type_loc));
    if (input_chan_bindings != NULL)
	return GSS_S_FAILURE;
    major_status = gss_accept_sec_context(minor_status, context_handle,
					  acceptor_cred_handle,
					  input_token_buffer,
					  NULL, src_name, &mech_type_loc,
					  output_token, ret_flags, time_rec,
					  delegated_cred_handle);
    ret = gss_OID_loc_to_sap(mech_type_loc, mech_type);
    if (ret != 0) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }
    return major_status;
}
Ejemplo n.º 3
0
/*-------------*/
static int accept_sec_context (gss_ctx_id_t *context, gss_cred_id_t server_creds,
                               gss_buffer_desc *ticket_buffer, gss_name_t *client_name,
                               gss_buffer_desc *authenticator_buff)
{
    OM_uint32 major_status = 0, minor_status = 0, ret_flags;

    /* Initialize autheticator buffer. */
    authenticator_buff->length = 0;
    authenticator_buff->value = NULL;

    LOG(log_debug, logtype_uams, "accept_context: accepting context (ticketlen: %u)",
        ticket_buffer->length);

    /*
     * Try to accept the secondary context using the tocken in ticket_buffer.
     * We don't care about the mechanisms used, nor for the time.
     * We don't act as a proxy either.
     */
    major_status = gss_accept_sec_context( &minor_status, context,
                                           server_creds, ticket_buffer, GSS_C_NO_CHANNEL_BINDINGS,
                                           client_name, NULL, authenticator_buff,
                                           &ret_flags, NULL, NULL );

    if (major_status != GSS_S_COMPLETE) {
        log_status( "accept_sec_context", major_status, minor_status );
        return 1;
    }
    log_ctx_flags( ret_flags );
    return 0;
}
Ejemplo n.º 4
0
/* Privileged */
OM_uint32
ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok,
    gss_buffer_desc *send_tok, OM_uint32 *flags)
{
	OM_uint32 status;
	gss_OID mech;

	ctx->major = gss_accept_sec_context(&ctx->minor,
	    &ctx->context, ctx->creds, recv_tok,
	    GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech,
	    send_tok, flags, NULL, &ctx->client_creds);

	if (GSS_ERROR(ctx->major))
		ssh_gssapi_error(ctx);

	if (ctx->client_creds)
		debug("Received some client credentials");
	else
		debug("Got no client credentials");

	status = ctx->major;

	/* Now, if we're complete and we have the right flags, then
	 * we flag the user as also having been authenticated
	 */

	if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
	    (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
		if (ssh_gssapi_getclient(ctx, &gssapi_client))
			fatal("Couldn't convert client name");
	}

	return (status);
}
Ejemplo n.º 5
0
/*
 * Call gss_accept_context, with token just read from the wire.
 */
int
gssapi_get_rtoken(struct ph1handle *iph1, int *lenp)
{
	struct gssapi_ph1_state *gps;
	gss_buffer_desc name_token;
	gss_buffer_t itoken, rtoken;
	OM_uint32 min_stat, maj_stat;
	gss_name_t client_name;

	if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0)
		return -1;

	gps = gssapi_get_state(iph1);

	rtoken = &gps->gss_p[gps->gsscnt_p - 1];
	itoken = &gps->gss[gps->gsscnt];

	gps->gss_status = gss_accept_sec_context(&min_stat, &gps->gss_context,
	    gps->gss_cred, rtoken, GSS_C_NO_CHANNEL_BINDINGS, &client_name,
	    NULL, itoken, NULL, NULL, NULL);

	if (GSS_ERROR(gps->gss_status)) {
		gssapi_error(min_stat, LOCATION, "accept_sec_context\n");
		return -1;
	}

	maj_stat = gss_display_name(&min_stat, client_name, &name_token, NULL);
	if (GSS_ERROR(maj_stat)) {
		gssapi_error(min_stat, LOCATION, "gss_display_name\n");
		maj_stat = gss_release_name(&min_stat, &client_name);
		if (GSS_ERROR(maj_stat))
			gssapi_error(min_stat, LOCATION,
			    "release client_name\n");
		return -1;
	}
	maj_stat = gss_release_name(&min_stat, &client_name);
	if (GSS_ERROR(maj_stat))
		gssapi_error(min_stat, LOCATION, "release client_name\n");

	plog(LLV_DEBUG, LOCATION, NULL,
		"gss_accept_sec_context: other side is %s\n",
		(char *)name_token.value);
	maj_stat = gss_release_buffer(&min_stat, &name_token);
	if (GSS_ERROR(maj_stat))
		gssapi_error(min_stat, LOCATION, "release name buffer\n");

	if (itoken->length != 0)
		gps->gsscnt++;

	if (lenp)
		*lenp = itoken->length;

	return 0;
}
Ejemplo n.º 6
0
void zmq::gssapi_server_t::accept_context ()
{
    maj_stat = gss_accept_sec_context(&init_sec_min_stat, &context, cred,
                                      &recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
                                      &target_name, &doid, &send_tok,
                                      &ret_flags, NULL, NULL);

    if (recv_tok.value) {
        free (recv_tok.value);
        recv_tok.value = NULL;
    }
}
Ejemplo n.º 7
0
static int accept_sec_context(gss_ctx_id_t *context,
                              gss_buffer_desc *ticket_buffer,
                              gss_name_t *client_name,
                              gss_buffer_desc *authenticator_buff)
{
    OM_uint32 major_status = 0, minor_status = 0, flags = 0;

    /* Initialize autheticator buffer. */
    authenticator_buff->length = 0;
    authenticator_buff->value = NULL;

    LOG_LOGINCONT(log_debug,
                  "accepting context (ticketlen: %u)",
                  ticket_buffer->length);

    /*
     * Try to accept the secondary context using the token in ticket_buffer.
     * We don't care about the principals or mechanisms used, nor for the time.
     * We don't act as a proxy either.
     */
    major_status = gss_accept_sec_context(&minor_status,
                                          context,
                                          GSS_C_NO_CREDENTIAL,
                                          ticket_buffer,
                                          GSS_C_NO_CHANNEL_BINDINGS,
                                          client_name,
                                          NULL,
                                          authenticator_buff,
                                          &flags,
                                          NULL,
                                          NULL);

    if (major_status != GSS_S_COMPLETE) {
        log_status("gss_accept_sec_context", major_status, minor_status);
        return 1;
    }

    log_ctx_flags(flags);
    return 0;
}
Ejemplo n.º 8
0
Archivo: common.c Proyecto: PADL/krb5
void
establish_contexts(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
                   gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ictx,
                   gss_ctx_id_t *actx, gss_name_t *src_name, gss_OID *amech,
                   gss_cred_id_t *deleg_cred)
{
    OM_uint32 minor, imaj, amaj;
    gss_buffer_desc itok, atok;

    *ictx = *actx = GSS_C_NO_CONTEXT;
    imaj = amaj = GSS_S_CONTINUE_NEEDED;
    itok.value = atok.value = NULL;
    itok.length = atok.length = 0;
    for (;;) {
        (void)gss_release_buffer(&minor, &itok);
        imaj = gss_init_sec_context(&minor, icred, ictx, tname, imech, flags,
                                    GSS_C_INDEFINITE,
                                    GSS_C_NO_CHANNEL_BINDINGS, &atok, NULL,
                                    &itok, NULL, NULL);
        check_gsserr("gss_init_sec_context", imaj, minor);
        if (amaj == GSS_S_COMPLETE)
            break;

        (void)gss_release_buffer(&minor, &atok);
        amaj = gss_accept_sec_context(&minor, actx, acred, &itok,
                                      GSS_C_NO_CHANNEL_BINDINGS, src_name,
                                      amech, &atok, NULL, NULL, deleg_cred);
        check_gsserr("gss_accept_sec_context", amaj, minor);
        (void)gss_release_buffer(&minor, &itok);
        if (imaj == GSS_S_COMPLETE)
            break;
    }

    if (imaj != GSS_S_COMPLETE || amaj != GSS_S_COMPLETE)
        errout("One side wants to continue after the other is done");

    (void)gss_release_buffer(&minor, &itok);
    (void)gss_release_buffer(&minor, &atok);
}
Ejemplo n.º 9
0
static pam_handle_t *
perform_gssapi (void)
{
  struct pam_conv conv = { pam_conv_func, };
  OM_uint32 major, minor;
  gss_cred_id_t server = GSS_C_NO_CREDENTIAL;
  gss_cred_id_t client = GSS_C_NO_CREDENTIAL;
  gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc local = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc display = GSS_C_EMPTY_BUFFER;
  gss_name_t name = GSS_C_NO_NAME;
  gss_ctx_id_t context = GSS_C_NO_CONTEXT;
  gss_OID mech_type = GSS_C_NO_OID;
  pam_handle_t *pamh = NULL;
  OM_uint32 flags = 0;
  char *str = NULL;
  OM_uint32 caps = 0;
  int res;

  server = GSS_C_NO_CREDENTIAL;
  res = PAM_AUTH_ERR;

  /* We shouldn't be writing to kerberos caches here */
  setenv ("KRB5CCNAME", "FILE:/dev/null", 1);

  debug ("reading kerberos auth from cockpit-ws");
  input.value = read_auth_until_eof (&input.length);

  major = gss_accept_sec_context (&minor, &context, server, &input,
                                  GSS_C_NO_CHANNEL_BINDINGS, &name, &mech_type,
                                  &output, &flags, &caps, &client);

  if (GSS_ERROR (major))
    {
      warnx ("gssapi auth failed: %s", gssapi_strerror (major, minor));
      goto out;
    }

  /*
   * In general gssapi mechanisms can require multiple challenge response
   * iterations keeping &context between each, however Kerberos doesn't
   * require this, so we don't care :O
   *
   * If we ever want this to work with something other than Kerberos, then
   * we'll have to have some sorta session that holds the context.
   */
  if (major & GSS_S_CONTINUE_NEEDED)
    goto out;

  major = gss_localname (&minor, name, mech_type, &local);
  if (major == GSS_S_COMPLETE)
    {
      minor = 0;
      str = dup_string (local.value, local.length);
      debug ("mapped gssapi name to local user '%s'", str);

      if (getpwnam (str))
        {
          res = pam_start ("cockpit", str, &conv, &pamh);
        }
      else
        {
          /* If the local user doesn't exist, pretend gss_localname() failed */
          free (str);
          str = NULL;
          major = GSS_S_FAILURE;
          minor = KRB5_NO_LOCALNAME;
        }
    }

  if (major != GSS_S_COMPLETE)
    {
      if (minor == (OM_uint32)KRB5_NO_LOCALNAME || minor == (OM_uint32)KRB5_LNAME_NOTRANS)
        {
          major = gss_display_name (&minor, name, &display, NULL);
          if (GSS_ERROR (major))
            {
              warnx ("couldn't get gssapi display name: %s", gssapi_strerror (major, minor));
              goto out;
            }

          str = dup_string (display.value, display.length);
          debug ("no local user mapping for gssapi name '%s'", str);

          res = pam_start ("cockpit", str, &conv, &pamh);
        }
      else
        {
          warnx ("couldn't map gssapi name to local user: %s", gssapi_strerror (major, minor));
          goto out;
        }
    }

  if (res != PAM_SUCCESS)
    errx (EX, "couldn't start pam: %s", pam_strerror (NULL, res));

  if (pam_set_item (pamh, PAM_RHOST, rhost) != PAM_SUCCESS ||
      pam_get_item (pamh, PAM_USER, (const void **)&user) != PAM_SUCCESS)
    errx (EX, "couldn't setup pam");

  assert (user != NULL);

  res = open_session (pamh, user);

out:
  write_auth_begin (res);
  if (user)
    write_auth_string ("user", user);
  if (output.value)
    write_auth_hex ("gssapi-output", output.value, output.length);

  if (output.value)
    gss_release_buffer (&minor, &output);
  output.value = NULL;
  output.length = 0;

  if (caps & GSS_C_DELEG_FLAG && client != GSS_C_NO_CREDENTIAL)
    {
#ifdef HAVE_GSS_IMPORT_CRED
      major = gss_export_cred (&minor, client, &output);
      if (GSS_ERROR (major))
        warnx ("couldn't export gssapi credentials: %s", gssapi_strerror (major, minor));
      else if (output.value)
        write_auth_hex ("gssapi-creds", output.value, output.length);
#else
      /* cockpit-ws will complain for us, if they're ever used */
      write_auth_hex ("gssapi-creds", (void *)"", 0);
#endif
    }

  write_auth_end ();

  if (display.value)
    gss_release_buffer (&minor, &display);
  if (output.value)
    gss_release_buffer (&minor, &output);
  if (local.value)
    gss_release_buffer (&minor, &local);
  if (client != GSS_C_NO_CREDENTIAL)
    gss_release_cred (&minor, &client);
  if (server != GSS_C_NO_CREDENTIAL)
    gss_release_cred (&minor, &server);
  if (name != GSS_C_NO_NAME)
     gss_release_name (&minor, &name);
  if (context != GSS_C_NO_CONTEXT)
     gss_delete_sec_context (&minor, &context, GSS_C_NO_BUFFER);
  free (input.value);
  free (str);

  unsetenv ("KRB5CCNAME");

  if (res != PAM_SUCCESS)
    exit (5);

  return pamh;
}
Ejemplo n.º 10
0
static bool
svcauth_gss_accept_sec_context(struct svc_req *req,
			       struct svc_rpc_gss_data *gd,
			       struct rpc_gss_init_res *gr)
{
	struct rpc_gss_cred *gc;
	gss_buffer_desc recv_tok, seqbuf, checksum;
	gss_OID mech;
	OM_uint32 maj_stat = 0, min_stat = 0, ret_flags, seq;
#define INDEF_EXPIRE 60*60*24	/* from mit k5 src/lib/rpc/svc_auth_gssapi.c */
	OM_uint32 time_rec;

	gc = (struct rpc_gss_cred *)req->rq_clntcred;
	memset(gr, 0, sizeof(*gr));

	/* Deserialize arguments. */
	memset(&recv_tok, 0, sizeof(recv_tok));

	if (!svc_getargs
	    (req->rq_xprt, req, (xdrproc_t) xdr_rpc_gss_init_args,
	     (caddr_t) &recv_tok, NULL /* u_data */))
		return (false);

	gr->gr_major =
	    gss_accept_sec_context(&gr->gr_minor, &gd->ctx, svcauth_gss_creds,
				   &recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
				   &gd->client_name, &mech, &gr->gr_token,
				   &ret_flags, &time_rec, NULL);

	svc_freeargs(req->rq_xprt, req, (xdrproc_t) xdr_rpc_gss_init_args,
		     (caddr_t) &recv_tok);

	if ((gr->gr_major != GSS_S_COMPLETE)
	    && (gr->gr_major != GSS_S_CONTINUE_NEEDED)) {
		__warnx(TIRPC_DEBUG_FLAG_AUTH,
			"%s: auth failed major=%u minor=%u", __func__,
			gr->gr_major, gr->gr_minor);
		gd->ctx = GSS_C_NO_CONTEXT;
		gss_release_buffer(&min_stat, &gr->gr_token);
		return (false);
	}
	/* ANDROS: krb5 mechglue returns ctx of size 8 - two pointers,
	 * one to the mechanism oid, one to the internal_ctx_id */
	gr->gr_ctx.value = mem_alloc(sizeof(gss_union_ctx_id_desc));
	memcpy(gr->gr_ctx.value, gd->ctx, sizeof(gss_union_ctx_id_desc));
	gr->gr_ctx.length = sizeof(gss_union_ctx_id_desc);

	/* ANDROS: change for debugging linux kernel version...
	   gr->gr_win = 0x00000005;
	 */
	gr->gr_win = sizeof(gd->seqmask) * 8;

	/* Save client info. */
	gd->sec.mech = mech;
	gd->sec.qop = GSS_C_QOP_DEFAULT;
	gd->sec.svc = gc->gc_svc;
	gd->win = gr->gr_win;

	if (time_rec == GSS_C_INDEFINITE) time_rec = INDEF_EXPIRE;
	if (time_rec > 10) time_rec -= 5;
	gd->endtime = time_rec + get_time_fast();

	if (gr->gr_major == GSS_S_COMPLETE) {
		maj_stat =
		    gss_display_name(&min_stat, gd->client_name, &gd->cname,
				     &gd->sec.mech);
		if (maj_stat != GSS_S_COMPLETE) {
			__warnx(TIRPC_DEBUG_FLAG_AUTH,
				"%s: display_name major=%u minor=%u", __func__,
				maj_stat, min_stat);
			gss_release_buffer(&min_stat, &gr->gr_token);
			return (false);
		}
#ifdef DEBUG
#ifdef HAVE_KRB5
		{
			gss_buffer_desc mechname;
			gss_oid_to_str(&min_stat, mech, &mechname);
			__warnx(TIRPC_DEBUG_FLAG_AUTH,
				"%s: accepted context for %.*s with "
				"<mech %.*s, qop %d, svc %d>", __func__,
				gd->cname.length, (char *)gd->cname.value,
				mechname.length, (char *)mechname.value,
				gd->sec.qop, gd->sec.svc);
			gss_release_buffer(&min_stat, &mechname);
		}
#elif HAVE_HEIMDAL
		__warnx(TIRPC_DEBUG_FLAG_AUTH,
			"%s: accepted context for %.*s with "
			"<mech {}, qop %d, svc %d>", __func__, gd->cname.length,
			(char *)gd->cname.value, gd->sec.qop, gd->sec.svc);
#endif
#endif				/* DEBUG */
		seq = htonl(gr->gr_win);
		seqbuf.value = &seq;
		seqbuf.length = sizeof(seq);

		gss_release_buffer(&min_stat, &gd->checksum);

		maj_stat =
		    gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT, &seqbuf,
			     &checksum);

		if (maj_stat != GSS_S_COMPLETE) {
			gss_release_buffer(&min_stat, &gr->gr_token);
			return (false);
		}

		/* XXX ref? (assert gd->locked?) */
		req->rq_verf.oa_flavor = RPCSEC_GSS;
		req->rq_verf.oa_base = checksum.value;
		req->rq_verf.oa_length = checksum.length;
	}
	return (true);
}
int main()
{
    OM_uint32                           init_maj_stat;
    OM_uint32                           accept_maj_stat;
    OM_uint32                           maj_stat;
    OM_uint32                           min_stat;
    OM_uint32                           ret_flags;
    OM_uint32                           req_flags = 0;
    OM_uint32                           time_rec;
    gss_buffer_desc                     send_tok;
    gss_buffer_desc                     recv_tok;
    gss_buffer_desc *                   token_ptr;
    gss_OID                             mech_type;
    gss_name_t                          target_name;
    gss_ctx_id_t                        init_context;
    gss_ctx_id_t                        accept_context;
    gss_ctx_id_t                        del_init_context;
    gss_ctx_id_t                        del_accept_context;
    gss_cred_id_t                       delegated_cred;
    gss_cred_id_t                       imported_cred;
    gss_cred_id_t                       cred_handle;
    char *                              error_str;
    globus_result_t                     result;
    globus_gsi_cert_utils_cert_type_t   cert_type;
    int                                 rc = EXIT_SUCCESS;

    printf("1..1\n");
    /* Activate Modules */
    globus_module_activate(GLOBUS_GSI_GSSAPI_MODULE);

    /* Initialize variables */
    
    token_ptr = GSS_C_NO_BUFFER;
    init_context = GSS_C_NO_CONTEXT;
    accept_context = GSS_C_NO_CONTEXT;
    del_init_context = GSS_C_NO_CONTEXT;
    del_accept_context = GSS_C_NO_CONTEXT;
    delegated_cred = GSS_C_NO_CREDENTIAL;
    accept_maj_stat = GSS_S_CONTINUE_NEEDED;
    ret_flags = 0;
    req_flags |= GSS_C_GLOBUS_LIMITED_DELEG_PROXY_FLAG;


    /* acquire the credential */

    maj_stat = gss_acquire_cred(&min_stat,
                                NULL,
                                GSS_C_INDEFINITE,
                                GSS_C_NO_OID_SET,
                                GSS_C_BOTH,
                                &cred_handle,
                                NULL,
                                NULL);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gsi_gssapi_test_print_error(stderr, maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    
    /* get the subject name */
    
    maj_stat = gss_inquire_cred(&min_stat, 
                                cred_handle,
                                &target_name,
                                NULL,
                                NULL,
                                NULL);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gsi_gssapi_test_print_error(stderr, maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }


    /* set up the first security context */
    
    init_maj_stat = gss_init_sec_context(&min_stat,
                                         cred_handle,
                                         &init_context,
                                         target_name,
                                         GSS_C_NULL_OID,
                                         0,
                                         0,
                                         GSS_C_NO_CHANNEL_BINDINGS,
                                         token_ptr,
                                         NULL,
                                         &send_tok,
                                         NULL,
                                         NULL);


    if(init_maj_stat != GSS_S_CONTINUE_NEEDED)
    {
        globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    while(1)
    {
        
        accept_maj_stat=gss_accept_sec_context(&min_stat,
                                               &accept_context,
                                               GSS_C_NO_CREDENTIAL,
                                               &send_tok, 
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               NULL,
                                               &mech_type,
                                               &recv_tok,
                                               &ret_flags,
                                               /* ignore time_rec */
                                               NULL, 
                                               NULL);

        if(accept_maj_stat != GSS_S_COMPLETE &&
           accept_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, accept_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
        else if(accept_maj_stat == GSS_S_COMPLETE)
        {
            break;
        }

        init_maj_stat = gss_init_sec_context(&min_stat,
                                             GSS_C_NO_CREDENTIAL,
                                             &init_context,
                                             target_name,
                                             GSS_C_NULL_OID,
                                             0,
                                             0,
                                             GSS_C_NO_CHANNEL_BINDINGS,
                                             &recv_tok,
                                             NULL,
                                             &send_tok,
                                             NULL,
                                             NULL);
        
        
        if(init_maj_stat != GSS_S_COMPLETE &&
           init_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
    }

    printf("# %s:%d: Successfully established initial security context\n",
           __FILE__,
           __LINE__);


    /* delegate our credential over the initial security context and
     * insert a restriction extension into the delegated credential.
     * This is a post GT 2.0 feature.
     */


    init_maj_stat = gss_init_delegation(&min_stat,
                                        init_context,
                                        cred_handle,
                                        GSS_C_NO_OID,
                                        GSS_C_NO_OID_SET,
                                        GSS_C_NO_BUFFER_SET,
                                        token_ptr,
                                        req_flags,
                                        0,
                                        &send_tok);
    

    if(init_maj_stat != GSS_S_COMPLETE &&
       init_maj_stat != GSS_S_CONTINUE_NEEDED)
    {
        globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    while(1)
    {
        accept_maj_stat=gss_accept_delegation(&min_stat,
                                              accept_context,
                                              GSS_C_NO_OID_SET,
                                              GSS_C_NO_BUFFER_SET,
                                              &send_tok,
                                              req_flags,
                                              0,
                                              &time_rec,
                                              &delegated_cred,
                                              &mech_type,
                                              &recv_tok);
        
        if(accept_maj_stat != GSS_S_COMPLETE &&
           accept_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, accept_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
        else if(accept_maj_stat == GSS_S_COMPLETE)
        {
            break;
        }

        init_maj_stat = gss_init_delegation(&min_stat,
                                            init_context,
                                            cred_handle,
                                            GSS_C_NO_OID,
                                            GSS_C_NO_OID_SET,
                                            GSS_C_NO_BUFFER_SET,
                                            &recv_tok,
                                            req_flags,
                                            0,
                                            &send_tok);


        if(init_maj_stat != GSS_S_COMPLETE &&
           init_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
    }
    
    printf("# %s:%d: Successfully delegated credential\n",
           __FILE__,
           __LINE__);

    /* export and import the delegated credential */
    /* this can be done both to a buffer and to a file */
    /* New in GT 2.0 */

    maj_stat = gss_export_cred(&min_stat,
                               delegated_cred,
                               GSS_C_NO_OID,
                               0,
                               &send_tok);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gsi_gssapi_test_print_error(stderr, maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    
    maj_stat = gss_import_cred(&min_stat,
                               &imported_cred,
                               GSS_C_NO_OID,
                               0,
                               &send_tok,
                               0,
                               &time_rec);


    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gsi_gssapi_test_print_error(stderr, maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    printf("# %s:%d: Successfully exported/imported the delegated credential\n",
           __FILE__,
           __LINE__);

    /* set up another security context using the delegated credential */
    
    init_maj_stat = gss_init_sec_context(&min_stat,
                                         imported_cred,
                                         &del_init_context,
                                         target_name,
                                         GSS_C_NULL_OID,
                                         0,
                                         0,
                                         GSS_C_NO_CHANNEL_BINDINGS,
                                         token_ptr,
                                         NULL,
                                         &send_tok,
                                         NULL,
                                         NULL);


    if(init_maj_stat != GSS_S_COMPLETE &&
       init_maj_stat != GSS_S_CONTINUE_NEEDED)
    {
        globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }


    
    while(1)
    {
        accept_maj_stat=gss_accept_sec_context(&min_stat,
                                               &del_accept_context,
                                               imported_cred,
                                               &send_tok, 
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               NULL,
                                               &mech_type,
                                               &recv_tok,
                                               &ret_flags,
                                               /* ignore time_rec */
                                               NULL, 
                                               NULL);

        if(accept_maj_stat != GSS_S_COMPLETE &&
           accept_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, accept_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
        else if(accept_maj_stat == GSS_S_COMPLETE)
        {
            break;
        }
        
        init_maj_stat = gss_init_sec_context(&min_stat,
                                             imported_cred,
                                             &del_init_context,
                                             target_name,
                                             GSS_C_NULL_OID,
                                             0,
                                             0,
                                             GSS_C_NO_CHANNEL_BINDINGS,
                                             &recv_tok,
                                             NULL,
                                             &send_tok,
                                             NULL,
                                             NULL);
        
        
        if(init_maj_stat != GSS_S_COMPLETE &&
           init_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
    }

    /* got sec context based on delegated cred now */
    printf("# %s:%d: Successfully established security context with delegated credential\n",
           __FILE__,
           __LINE__);

    /* Verify that the delegated credential is a limited proxy */
    result = globus_gsi_cred_get_cert_type(
        ((gss_cred_id_desc *)imported_cred)->cred_handle,
        &cert_type);
    if(result != GLOBUS_SUCCESS)
    {
        char *                          error_str;
        globus_object_t *               error_obj;

        error_obj = globus_error_get(result);
        error_str = globus_error_print_chain(error_obj);
        fprintf(stderr, "%s", error_str);
        globus_libc_free(error_str);
        globus_object_free(error_obj);
        rc = EXIT_FAILURE;
        goto fail;
    }

    if (! GLOBUS_GSI_CERT_UTILS_IS_LIMITED_PROXY(cert_type))
    {
        fprintf(stderr,
                "Invalid certificate type. Expected a limited proxy, got %d\n",
                (int) cert_type);
        rc = EXIT_FAILURE;
        goto fail;
    }

fail:
    printf("%s gssapi_limited_delegation_test\n",
            (rc==EXIT_SUCCESS) ? "ok" : "not ok");
    globus_module_deactivate_all();
    
    exit(rc);    
}
OM_uint32 gssi_accept_sec_context(OM_uint32 *minor_status,
                                  gss_ctx_id_t *context_handle,
                                  gss_cred_id_t acceptor_cred_handle,
                                  gss_buffer_t input_token_buffer,
                                  gss_channel_bindings_t input_chan_bindings,
                                  gss_name_t *src_name,
                                  gss_OID *mech_type,
                                  gss_buffer_t output_token,
                                  OM_uint32 *ret_flags,
                                  OM_uint32 *time_rec,
                                  gss_cred_id_t *delegated_cred_handle)
{
    enum gpp_behavior behavior;
    struct gpp_context_handle *ctx_handle = NULL;
    struct gpp_cred_handle *cred_handle = NULL;
    struct gpp_cred_handle *deleg_cred = NULL;
    struct gpp_name_handle *name = NULL;
    OM_uint32 maj, min;

    GSSI_TRACE();

    behavior = gpp_get_behavior();

    if (*context_handle) {
        ctx_handle = (struct gpp_context_handle *)*context_handle;
        if (ctx_handle->local) {
            /* if we already have a local context it means this is
             * a continuation, force local only behavior, nothing else
             * makes sense */
            behavior = GPP_LOCAL_ONLY;
        } else if (ctx_handle->remote) {
            behavior = GPP_REMOTE_ONLY;
        }
    } else {
        ctx_handle = calloc(1, sizeof(struct gpp_context_handle));
        if (!ctx_handle) {
            maj = GSS_S_FAILURE;
            min = ENOMEM;
            goto done;
        }
    }

    if (acceptor_cred_handle != GSS_C_NO_CREDENTIAL) {
        cred_handle = (struct gpp_cred_handle *)acceptor_cred_handle;
    } else {
        maj = gppint_get_def_creds(&min, behavior, NULL,
                                   GSS_C_ACCEPT, &cred_handle);
        if (maj != GSS_S_COMPLETE) {
            goto done;
        }
    }
    if (cred_handle->local) {
        if (behavior == GPP_REMOTE_ONLY) {
            min = 0;
            maj = GSS_S_DEFECTIVE_CREDENTIAL;
            goto done;
        }
        behavior = GPP_LOCAL_ONLY;
    } else if (cred_handle->remote) {
        if (behavior == GPP_LOCAL_ONLY) {
            min = 0;
            maj = GSS_S_DEFECTIVE_CREDENTIAL;
            goto done;
        }
        behavior = GPP_REMOTE_ONLY;
    }

    if (src_name) {
        name = calloc(1, sizeof(struct gpp_name_handle));
        if (!name) {
            maj = GSS_S_FAILURE;
            min = ENOMEM;
            goto done;
        }
    }

    if (delegated_cred_handle) {
        deleg_cred = calloc(1, sizeof(struct gpp_cred_handle));
        if (!deleg_cred) {
            maj = GSS_S_FAILURE;
            min = ENOMEM;
            goto done;
        }
    }

    /* behavior has been set to local only or remote only by context or
     * credential handler inspection, so we only have those 2 cases,
     * anything else is an error at this point. */
    if (behavior == GPP_LOCAL_ONLY) {

        maj = gss_accept_sec_context(&min, &ctx_handle->local,
                                     cred_handle->local, input_token_buffer,
                                     input_chan_bindings,
                                     name ? &name->local : NULL, mech_type,
                                     output_token, ret_flags, time_rec,
                                     deleg_cred ? &deleg_cred->local : NULL);
    } else if (behavior == GPP_REMOTE_ONLY) {

        maj = gpm_accept_sec_context(&min, &ctx_handle->remote,
                                     cred_handle->remote, input_token_buffer,
                                     input_chan_bindings,
                                     name ? &name->remote : NULL, mech_type,
                                     output_token, ret_flags, time_rec,
                                     deleg_cred ? &deleg_cred->remote : NULL);
    } else {

        min = 0;
        maj = GSS_S_FAILURE;
    }

done:
    *minor_status = gpp_map_error(min);
    if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
        if (ctx_handle &&
            ctx_handle->local == GSS_C_NO_CONTEXT &&
            ctx_handle->remote == NULL) {
            free(ctx_handle);
            ctx_handle = NULL;
        }
        free(deleg_cred);
        free(name);
    } else {
        if (src_name) {
            *src_name = (gss_name_t)name;
        }
        if (delegated_cred_handle) {
            *delegated_cred_handle = (gss_cred_id_t)deleg_cred;
        }
    }
    /* always replace the provided context handle to avoid
     * dangling pointers when a context has been passed in */
    *context_handle = (gss_ctx_id_t)ctx_handle;

    if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
        (void)gssi_release_cred(&min, (gss_cred_id_t *)&cred_handle);
    }
    return maj;
}
Ejemplo n.º 13
0
static bool_t
svcauth_gss_accept_sec_context(struct svc_req *rqst,
			       struct rpc_gss_init_res *gr)
{
	struct svc_rpc_gss_data	*gd;
	struct rpc_gss_cred	*gc;
	gss_buffer_desc		 recv_tok, seqbuf, checksum;
	gss_OID			 mech;
	OM_uint32		 maj_stat = 0, min_stat = 0, ret_flags, seq;

	log_debug("in svcauth_gss_accept_context()");

	gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
	gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
	memset(gr, 0, sizeof(*gr));

	/* Deserialize arguments. */
	memset(&recv_tok, 0, sizeof(recv_tok));

	if (!svc_getargs(rqst->rq_xprt, (xdrproc_t)xdr_rpc_gss_init_args,
			 (caddr_t)&recv_tok))
		return (FALSE);

	gr->gr_major = gss_accept_sec_context(&gr->gr_minor,
					      &gd->ctx,
					      _svcauth_gss_creds,
					      &recv_tok,
					      GSS_C_NO_CHANNEL_BINDINGS,
					      &gd->client_name,
					      &mech,
					      &gr->gr_token,
					      &ret_flags,
					      NULL,
					      NULL);

	if (gr->gr_major != GSS_S_COMPLETE &&
	    gr->gr_major != GSS_S_CONTINUE_NEEDED) {
		log_status("accept_sec_context", gr->gr_major, gr->gr_minor);
		gd->ctx = GSS_C_NO_CONTEXT;
		gss_release_buffer(&min_stat, &gr->gr_token);
		return (FALSE);
	}
	/* ANDROS: krb5 mechglue returns ctx of size 8 - two pointers,
	 * one to the mechanism oid, one to the internal_ctx_id */
	if ((gr->gr_ctx.value = mem_alloc(sizeof(gss_union_ctx_id_desc))) == NULL) {
		fprintf(stderr, "svcauth_gss_accept_context: out of memory\n");
		return (FALSE);
	}
	memcpy(gr->gr_ctx.value, gd->ctx, sizeof(gss_union_ctx_id_desc));
	gr->gr_ctx.length = sizeof(gss_union_ctx_id_desc);

	/* ANDROS: change for debugging linux kernel version...
	gr->gr_win = sizeof(gd->seqmask) * 8;
	*/
	gr->gr_win = 0x00000005;

	/* Save client info. */
	gd->sec.mech = mech;
	gd->sec.qop = GSS_C_QOP_DEFAULT;
	gd->sec.svc = gc->gc_svc;
	gd->seq = gc->gc_seq;
	gd->win = gr->gr_win;

	if (gr->gr_major == GSS_S_COMPLETE) {
		maj_stat = gss_display_name(&min_stat, gd->client_name,
					    &gd->cname, &gd->sec.mech);
		if (maj_stat != GSS_S_COMPLETE) {
			log_status("display_name", maj_stat, min_stat);
			return (FALSE);
		}
#ifdef DEBUG
#ifdef HAVE_KRB5
		{
			gss_buffer_desc mechname;

			gss_oid_to_str(&min_stat, mech, &mechname);

			log_debug("accepted context for %.*s with "
				  "<mech %.*s, qop %d, svc %d>",
				  gd->cname.length, (char *)gd->cname.value,
				  mechname.length, (char *)mechname.value,
				  gd->sec.qop, gd->sec.svc);

			gss_release_buffer(&min_stat, &mechname);
		}
#elif HAVE_HEIMDAL
		log_debug("accepted context for %.*s with "
			  "<mech {}, qop %d, svc %d>",
			  gd->cname.length, (char *)gd->cname.value,
			  gd->sec.qop, gd->sec.svc);
#endif
#endif /* DEBUG */
		seq = htonl(gr->gr_win);
		seqbuf.value = &seq;
		seqbuf.length = sizeof(seq);

		maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT,
				    &seqbuf, &checksum);

		if (maj_stat != GSS_S_COMPLETE)
			return (FALSE);

		rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
		rqst->rq_xprt->xp_verf.oa_base = checksum.value;
		rqst->rq_xprt->xp_verf.oa_length = checksum.length;
	}
	return (TRUE);
}
Ejemplo n.º 14
0
DWORD
VMCARESTVerifyKrbAuth(
    PVMCA_AUTHORIZATION_PARAM pAuthorization,
    PVMCA_ACCESS_TOKEN* ppAccessToken
    )
{
    DWORD dwError = 0;
    PSTR pszNegotiate = NULL;
    PSTR pszDecode = NULL;
    PSTR pszUser = NULL;
    char *pszToken = NULL;
    int nLength = 0;
    OM_uint32 major_status;
    OM_uint32 minor_status;
    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc display_name = GSS_C_EMPTY_BUFFER;
    gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
    gss_name_t client_name = GSS_C_NO_NAME;
    static gss_OID_desc gss_spnego_mech_oid_desc =
                                 {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
    static gss_OID gss_spnego_mech_oid = &gss_spnego_mech_oid_desc;
    gss_cred_id_t server_creds;

    pszNegotiate = pAuthorization->pszAuthorizationToken;
    if ( IsNullOrEmptyString(pszNegotiate) )
    {
        dwError = EACCES;
        BAIL_ON_VMREST_ERROR(dwError);
    }

    if (!strcmp(pszNegotiate,"testing"))
    // TODO: REMOVE
    // TODO: DO NOT CHECK IN
    {// Kerberos backdoor for testing
        dwError = VMCARESTMakeKrbAccessToken(ppAccessToken);
        BAIL_ON_VMREST_ERROR(dwError);
        goto cleanup;
    }
    dwError = base64_decode(
                        pszNegotiate,
                        &pszDecode,
                        &nLength
                        );
    BAIL_ON_VMREST_ERROR(dwError);

    dwError = server_acquire_creds(
                            "HTTP",
                            &gss_spnego_mech_oid_desc,
                            &server_creds
                            );
    BAIL_ON_VMREST_ERROR(dwError);

    input_token.length = nLength;
    input_token.value = pszDecode;

    major_status = gss_accept_sec_context(
                                    &minor_status,
                                    &gss_context,
                                    server_creds,
                                    &input_token,
                                    GSS_C_NO_CHANNEL_BINDINGS,
                                    &client_name,
                                    &gss_spnego_mech_oid,
                                    &output_token,
                                    NULL,
                                    NULL,
                                    NULL
                                    );

    if (GSS_ERROR(major_status) )
    {
        //TODO: insert show error
        dwError = EACCES;
        BAIL_ON_VMREST_ERROR(dwError);
    }

    if (output_token.length)
    {
        dwError = make_negotiate_token(&output_token, &pszToken);
        BAIL_ON_VMREST_ERROR(dwError);
    }

    if (major_status == GSS_S_CONTINUE_NEEDED)
    {
        OM_uint32 min2;
        gss_buffer_desc mech_msg = GSS_C_EMPTY_BUFFER;
        gss_buffer_desc gss_msg = GSS_C_EMPTY_BUFFER;
        gss_buffer_desc minor_msg = GSS_C_EMPTY_BUFFER;
        OM_uint32 msg_ctx = 0;
        PSTR pszError = NULL;

        gss_oid_to_str(&min2, gss_spnego_mech_oid, &mech_msg);
        gss_display_status(&min2, major_status, GSS_C_GSS_CODE, gss_spnego_mech_oid, &msg_ctx, &gss_msg);
        gss_display_status(&min2, minor_status, GSS_C_MECH_CODE, gss_spnego_mech_oid, &msg_ctx, &minor_msg);

        VMCAAllocateStringPrintfA(&pszError, "gss_rc[%d:%*s] mech[%*s] minor[%u:%*s]",
            major_status, (int)gss_msg.length,
            (const char *)(gss_msg.value?gss_msg.value:""),
            (int)mech_msg.length,
            (const char *)(mech_msg.value?mech_msg.value:""),
            minor_status, (int)minor_msg.length,
            (const char *)(minor_msg.value?minor_msg.value:""));

        gss_release_buffer(&min2, &mech_msg);
        gss_release_buffer(&min2, &gss_msg);
        gss_release_buffer(&min2, &minor_msg);
    }
    if (major_status == GSS_S_COMPLETE)
    {
        gss_display_name(&minor_status, client_name, &display_name, NULL);

        dwError = VMCAAllocateStringA(display_name.value, &pszUser);
        BAIL_ON_VMREST_ERROR(dwError);
    }

    dwError = VMCARESTMakeKrbAccessToken(ppAccessToken);
    BAIL_ON_VMREST_ERROR(dwError);

cleanup:
    if (pszUser)
    {
        VMCA_SAFE_FREE_MEMORY(pszUser);
    }
    return dwError;

error:
    goto cleanup;
}
Ejemplo n.º 15
0
static int mag_auth(request_rec *req)
{
    const char *type;
    struct mag_config *cfg;
    const char *auth_header;
    char *auth_header_type;
    char *auth_header_value;
    int ret = HTTP_UNAUTHORIZED;
    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
    gss_ctx_id_t *pctx;
    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc name = GSS_C_EMPTY_BUFFER;
    gss_name_t client = GSS_C_NO_NAME;
    gss_cred_id_t acquired_cred = GSS_C_NO_CREDENTIAL;
    gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
    uint32_t flags;
    uint32_t vtime;
    uint32_t maj, min;
    char *reply;
    size_t replen;
    char *clientname;
    gss_OID mech_type = GSS_C_NO_OID;
    gss_buffer_desc lname = GSS_C_EMPTY_BUFFER;
    struct mag_conn *mc = NULL;

    type = ap_auth_type(req);
    if ((type == NULL) || (strcasecmp(type, "GSSAPI") != 0)) {
        return DECLINED;
    }

    /* ignore auth for subrequests */
    if (!ap_is_initial_req(req)) {
        return OK;
    }

    cfg = ap_get_module_config(req->per_dir_config, &auth_gssapi_module);

    if (cfg->ssl_only) {
        if (!mag_conn_is_https(req->connection)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
                          "Not a TLS connection, refusing to authenticate!");
            goto done;
        }
    }

    if (cfg->gss_conn_ctx) {
        mc = (struct mag_conn *)ap_get_module_config(
                                                req->connection->conn_config,
                                                &auth_gssapi_module);
        if (!mc) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
                          "Failed to retrieve connection context!");
            goto done;
        }
    }

    /* if available, session always supersedes connection bound data */
    mag_check_session(req, cfg, &mc);

    if (mc) {
        /* register the context in the memory pool, so it can be freed
         * when the connection/request is terminated */
        apr_pool_userdata_set(mc, "mag_conn_ptr",
                              mag_conn_destroy, mc->parent);

        if (mc->established) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
                          "Already established context found!");
            apr_table_set(req->subprocess_env, "GSS_NAME", mc->gss_name);
            req->ap_auth_type = apr_pstrdup(req->pool, "Negotiate");
            req->user = apr_pstrdup(req->pool, mc->user_name);
            ret = OK;
            goto done;
        }
        pctx = &mc->ctx;
    } else {
        pctx = &ctx;
    }

    auth_header = apr_table_get(req->headers_in, "Authorization");
    if (!auth_header) goto done;

    auth_header_type = ap_getword_white(req->pool, &auth_header);
    if (!auth_header_type) goto done;

    if (strcasecmp(auth_header_type, "Negotiate") != 0) goto done;

    auth_header_value = ap_getword_white(req->pool, &auth_header);
    if (!auth_header_value) goto done;
    input.length = apr_base64_decode_len(auth_header_value) + 1;
    input.value = apr_pcalloc(req->pool, input.length);
    if (!input.value) goto done;
    input.length = apr_base64_decode(input.value, auth_header_value);

#ifdef HAVE_GSS_ACQUIRE_CRED_FROM
    if (cfg->use_s4u2proxy) {
        maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, 0,
                                    GSS_C_NO_OID_SET, GSS_C_BOTH,
                                    cfg->cred_store, &acquired_cred,
                                    NULL, NULL);
        if (GSS_ERROR(maj)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
                          mag_error(req, "gss_acquire_cred_from() failed",
                                    maj, min));
            goto done;
        }
    }
#endif

    maj = gss_accept_sec_context(&min, pctx, acquired_cred,
                                 &input, GSS_C_NO_CHANNEL_BINDINGS,
                                 &client, &mech_type, &output, &flags, &vtime,
                                 &delegated_cred);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
                      mag_error(req, "gss_accept_sec_context() failed",
                                maj, min));
        goto done;
    }

    if (maj == GSS_S_CONTINUE_NEEDED) {
        if (!mc) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
                          "Mechanism needs continuation but neither "
                          "GssapiConnectionBound nor "
                          "GssapiUseSessions are available");
            gss_delete_sec_context(&min, pctx, GSS_C_NO_BUFFER);
            gss_release_buffer(&min, &output);
            output.length = 0;
        }
        /* auth not complete send token and wait next packet */
        goto done;
    }

    req->ap_auth_type = apr_pstrdup(req->pool, "Negotiate");

    /* Always set the GSS name in an env var */
    maj = gss_display_name(&min, client, &name, NULL);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
                      mag_error(req, "gss_accept_sec_context() failed",
                                maj, min));
        goto done;
    }
    clientname = apr_pstrndup(req->pool, name.value, name.length);
    apr_table_set(req->subprocess_env, "GSS_NAME", clientname);

#ifdef HAVE_GSS_STORE_CRED_INTO
    if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
        char *ccachefile = NULL;

        mag_store_deleg_creds(req, cfg->deleg_ccache_dir, clientname,
                              delegated_cred, &ccachefile);

        if (ccachefile) {
            apr_table_set(req->subprocess_env, "KRB5CCNAME", ccachefile);
        }
    }
#endif

    if (cfg->map_to_local) {
        maj = gss_localname(&min, client, mech_type, &lname);
        if (maj != GSS_S_COMPLETE) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
                          mag_error(req, "gss_localname() failed", maj, min));
            goto done;
        }
        req->user = apr_pstrndup(req->pool, lname.value, lname.length);
    } else {
        req->user = clientname;
    }

    if (mc) {
        mc->user_name = apr_pstrdup(mc->parent, req->user);
        mc->gss_name = apr_pstrdup(mc->parent, clientname);
        mc->established = true;
        if (vtime == GSS_C_INDEFINITE || vtime < MIN_SESS_EXP_TIME) {
            vtime = MIN_SESS_EXP_TIME;
        }
        mc->expiration = time(NULL) + vtime;
        mag_attempt_session(req, cfg, mc);
    }

    ret = OK;

done:
    if (ret == HTTP_UNAUTHORIZED) {
        if (output.length != 0) {
            replen = apr_base64_encode_len(output.length) + 1;
            reply = apr_pcalloc(req->pool, 10 + replen);
            if (reply) {
                memcpy(reply, "Negotiate ", 10);
                apr_base64_encode(&reply[10], output.value, output.length);
                apr_table_add(req->err_headers_out,
                              "WWW-Authenticate", reply);
            }
        } else {
            apr_table_add(req->err_headers_out,
                          "WWW-Authenticate", "Negotiate");
        }
    }
    gss_release_cred(&min, &delegated_cred);
    gss_release_buffer(&min, &output);
    gss_release_name(&min, &client);
    gss_release_buffer(&min, &name);
    gss_release_buffer(&min, &lname);
    return ret;
}
Ejemplo n.º 16
0
enum auth_stat gssrpc__svcauth_gssapi(
     register struct svc_req *rqst,
     register struct rpc_msg *msg,
     bool_t *no_dispatch)
{
     XDR xdrs;
     auth_gssapi_creds creds;
     auth_gssapi_init_arg call_arg;
     auth_gssapi_init_res call_res;
     gss_buffer_desc output_token, in_buf, out_buf;
     gss_cred_id_t server_creds;
     struct gss_channel_bindings_struct bindings, *bindp;
     OM_uint32 gssstat, minor_stat, time_rec;
     struct opaque_auth *cred, *verf;
     svc_auth_gssapi_data *client_data;
     int i;
     enum auth_stat ret;
     OM_uint32 ret_flags;
     uint32_t seq_num;

     PRINTF(("svcauth_gssapi: starting\n"));
     
     /* clean up expired entries */
     clean_client();

     /* use AUTH_NONE until there is a client_handle */
     rqst->rq_xprt->xp_auth = &svc_auth_none;
     
     memset((char *) &call_res, 0, sizeof(call_res));
     creds.client_handle.length = 0;
     creds.client_handle.value = NULL;
     
     cred = &msg->rm_call.cb_cred;
     verf = &msg->rm_call.cb_verf;
     
     if (cred->oa_length == 0) {
	  PRINTF(("svcauth_gssapi: empty creds, failing\n"));
	  LOG_MISCERR("empty client credentials");
	  ret = AUTH_BADCRED;
	  goto error;
     }

     PRINTF(("svcauth_gssapi: decoding credentials\n"));
     xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); 
     memset((char *) &creds, 0, sizeof(creds));
     if (! xdr_authgssapi_creds(&xdrs, &creds)) {
	  PRINTF(("svcauth_gssapi: failed decoding creds\n"));
	  LOG_MISCERR("protocol error in client credentials");
	  xdr_free(xdr_authgssapi_creds, &creds);
	  XDR_DESTROY(&xdrs);
	  ret = AUTH_BADCRED;
	  goto error;
     }
     XDR_DESTROY(&xdrs);

     PRINTF(("svcauth_gssapi: got credentials, version %d, client_handle len %d\n",
	     creds.version, (int) creds.client_handle.length));

     if (creds.version != 2) {
 	  PRINTF(("svcauth_gssapi: bad credential version\n"));
 	  LOG_MISCERR("unsupported client credentials version");
 	  ret = AUTH_BADCRED;
 	  goto error;
     }

#ifdef DEBUG_GSSAPI
     if (svc_debug_gssapi) {
	  if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_EXIT) {
	       PRINTF(("svcauth_gssapi: GSSAPI_EXIT, cleaning up\n"));
	       svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
	       xdr_free(xdr_authgssapi_creds, &creds);
	       cleanup();
	       exit(0);
	  }
     }
#endif
	  
     /*
      * If this is an auth_msg and proc is GSSAPI_INIT, then create a
      * client handle for this client.  Otherwise, look up the
      * existing handle.
      */
     if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_INIT) {
	  if (creds.client_handle.length != 0) {
	       PRINTF(("svcauth_gssapi: non-empty handle on GSSAPI_INIT\n"));
	       LOG_MISCERR("protocol error in client handle");
	       ret = AUTH_FAILED;
	       goto error;
	  }
	       
	  PRINTF(("svcauth_gssapi: GSSAPI_INIT, creating client.\n"));
	  
	  client_data = create_client();
	  if (client_data == NULL) {
	       PRINTF(("svcauth_gssapi: create_client failed\n"));
	       LOG_MISCERR("internal error creating client record");
	       ret = AUTH_FAILED;
	       goto error;
	  }
     } else {
	  if (creds.client_handle.length == 0) {
	       PRINTF(("svcauth_gssapi: expected non-empty creds\n"));
	       LOG_MISCERR("protocol error in client credentials");
	       ret = AUTH_FAILED;
	       goto error;
	  }
	  
	  PRINTF(("svcauth_gssapi: incoming client_handle %d, len %d\n", 
		  *((uint32_t *) creds.client_handle.value),
		  (int) creds.client_handle.length));

	  client_data = get_client(&creds.client_handle);
	  if (client_data == NULL) {
	       PRINTF(("svcauth_gssapi: client_handle lookup failed\n"));
	       LOG_MISCERR("invalid client handle received");
	       ret = AUTH_BADCRED;
	       goto error;
	  }
	  PRINTF(("svcauth_gssapi: client_handle lookup succeeded\n"));
     }

     /* any response we send will use client_handle, so set it now */
     call_res.client_handle.length = sizeof(client_data->key);
     call_res.client_handle.value = (char *) &client_data->key;
     
     /* mark this call as using AUTH_GSSAPI via client_data's SVCAUTH */
     rqst->rq_xprt->xp_auth = &client_data->svcauth;

     if (client_data->established == FALSE) {
	  PRINTF(("svcauth_gssapi: context is not established\n"));

	  if (creds.auth_msg == FALSE) {
	       PRINTF(("svcauth_gssapi: expected auth_msg TRUE\n"));
	       LOG_MISCERR("protocol error on incomplete connection");
	       ret = AUTH_REJECTEDCRED;
	       goto error;
	  }

	  /*
	   * If the context is not established, then only GSSAPI_INIT
	   * and _CONTINUE requests are valid.
	   */
	  if (rqst->rq_proc != AUTH_GSSAPI_INIT && rqst->rq_proc !=
	      AUTH_GSSAPI_CONTINUE_INIT) {
	       PRINTF(("svcauth_gssapi: unacceptable procedure %d\n",
		       rqst->rq_proc));
	       LOG_MISCERR("protocol error on incomplete connection");
	       ret = AUTH_FAILED;
	       goto error;
	  }

	  /* call is for us, deserialize arguments */
	  memset(&call_arg, 0, sizeof(call_arg));
	  if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg,
			    &call_arg)) {
	       PRINTF(("svcauth_gssapi: cannot decode args\n"));
	       LOG_MISCERR("protocol error in procedure arguments");
	       ret = AUTH_BADCRED;
	       goto error;
	  }

	  /*
	   * Process the call arg version number.
	   * 
	   * Set the krb5_gss backwards-compatibility mode based on client
	   * version.  This controls whether the AP_REP message is
	   * encrypted with the session key (version 2+, correct) or the
	   * session subkey (version 1, incorrect).  This function can
	   * never fail, so we don't bother checking its return value.
	   */
	  switch (call_arg.version) {
	  case 1:
	  case 2:
	       LOG_MISCERR("Warning: Accepted old RPC protocol request");
	       call_res.version = 1;
	       break;
	  case 3:
	  case 4:
	       /* 3 and 4 are essentially the same, don't bother warning */
	       call_res.version = call_arg.version;
	       break;
	  default:
	       PRINTF(("svcauth_gssapi: bad GSSAPI_INIT version\n"));
	       LOG_MISCERR("unsupported GSSAPI_INIT version");
	       ret = AUTH_BADCRED;
	       goto error;
	  }

#ifdef GSS_BACKWARD_HACK
	  krb5_gss_set_backward_mode(&minor_stat, call_arg.version == 1);
#endif

	  if (call_arg.version >= 3) {
	       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 =
		    &svc_getcaller(rqst->rq_xprt)->sin_addr.s_addr;

	       if (rqst->rq_xprt->xp_laddrlen > 0) {
		    bindings.acceptor_addrtype = GSS_C_AF_INET;
		    bindings.acceptor_address.length = 4;
		    bindings.acceptor_address.value =
			 &rqst->rq_xprt->xp_laddr.sin_addr.s_addr;
	       } else {
		    LOG_MISCERR("cannot get local address");
		    ret = AUTH_FAILED;
		    goto error;
	       }


	       bindp = &bindings;
	  } else {
	       bindp = GSS_C_NO_CHANNEL_BINDINGS;
	  }

	  /*
	   * If the client's server_creds is already set, use it.
	   * Otherwise, try each credential in server_creds_list until
	   * one of them succeedes, then set the client server_creds
	   * to that.  If all fail, the client's server_creds isn't
	   * set (which is fine, because the client will be gc'ed
	   * anyway).
	   *
	   * If accept_sec_context returns something other than
	   * success and GSS_S_FAILURE, then assume different
	   * credentials won't help and stop looping.
	   * 
	   * Note that there are really two cases here: (1) the client
	   * has a server_creds already, and (2) it does not.  They
	   * are both written in the same loop so that there is only
	   * one textual call to gss_accept_sec_context; in fact, in
	   * case (1), the loop is executed exactly once.
	   */
	  for (i = 0; i < server_creds_count; i++) {
	       if (client_data->server_creds != NULL) {
		    PRINTF(("svcauth_gssapi: using's clients server_creds\n"));
		    server_creds = client_data->server_creds;
	       } else {
		    PRINTF(("svcauth_gssapi: trying creds %d\n", i));
		    server_creds = server_creds_list[i];
	       }
	       
	       /* Free previous output_token from loop */
	       if(i != 0) gss_release_buffer(&minor_stat, &output_token);

	       call_res.gss_major =
		    gss_accept_sec_context(&call_res.gss_minor,
					   &client_data->context,
					   server_creds,
					   &call_arg.token,
					   bindp,
					   &client_data->client_name,
					   NULL,
					   &output_token,
					   &ret_flags,
					   &time_rec,
					   NULL);

	       if (server_creds == client_data->server_creds)
		    break;

	       PRINTF(("accept_sec_context returned 0x%x 0x%x wrong-princ=%#x\n",
		       call_res.gss_major, call_res.gss_minor, (int) KRB5KRB_AP_WRONG_PRINC));
	       if (call_res.gss_major == GSS_S_COMPLETE ||
		   call_res.gss_major == GSS_S_CONTINUE_NEEDED) {
		    /* server_creds was right, set it! */
		    PRINTF(("svcauth_gssapi: creds are correct, storing\n"));
		    client_data->server_creds = server_creds;
		    client_data->server_name = server_name_list[i];
		    break;
	       } else if (call_res.gss_major != GSS_S_FAILURE
#ifdef GSSAPI_KRB5
			  /*
			   * hard-coded because there is no other way
			   * to prevent all GSS_S_FAILURES from
			   * returning a "wrong principal in request"
			   * error
			   */
			  || ((krb5_error_code) call_res.gss_minor !=
			      (krb5_error_code) KRB5KRB_AP_WRONG_PRINC)
#endif
			  ) {
		    break;
	       }
	  }
	  
	  gssstat = call_res.gss_major;
	  minor_stat = call_res.gss_minor;

	  /* done with call args */
	  xdr_free(xdr_authgssapi_init_arg, &call_arg);

	  PRINTF(("svcauth_gssapi: accept_sec_context returned %#x %#x\n",
		  call_res.gss_major, call_res.gss_minor));
	  if (call_res.gss_major != GSS_S_COMPLETE &&
	      call_res.gss_major != GSS_S_CONTINUE_NEEDED) {
	       AUTH_GSSAPI_DISPLAY_STATUS(("accepting context",
					   call_res.gss_major,
					   call_res.gss_minor));

	       if (log_badauth != NULL)
		    (*log_badauth)(call_res.gss_major,
				   call_res.gss_minor,
				   &rqst->rq_xprt->xp_raddr,
				   log_badauth_data);
	       
	       gss_release_buffer(&minor_stat, &output_token);
	       svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res,
			     (caddr_t) &call_res);
	       *no_dispatch = TRUE;
	       ret = AUTH_OK;
	       goto error;
	  }
	      
	  if (output_token.length != 0) {
	       PRINTF(("svcauth_gssapi: got new output token\n"));
	       GSS_COPY_BUFFER(call_res.token, output_token);
	  }

	  if (gssstat == GSS_S_COMPLETE) {
	       client_data->seq_num = rand();
	       client_expire(client_data,
			     (time_rec == GSS_C_INDEFINITE ?
			      INDEF_EXPIRE : time_rec) + time(0));

	       PRINTF(("svcauth_gssapi: context established, isn %d\n", 
		       client_data->seq_num));

	       if (auth_gssapi_seal_seq(client_data->context,
					client_data->seq_num,
					&call_res.signed_isn) ==
		   FALSE) {
		    ret = AUTH_FAILED;
		    LOG_MISCERR("internal error sealing sequence number");
		    gss_release_buffer(&minor_stat, &output_token);
		    goto error;
	       }
	  }

	  PRINTF(("svcauth_gssapi: sending reply\n"));
	  svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res,
			(caddr_t) &call_res);
	  *no_dispatch = TRUE;

	  /*
	   * If appropriate, set established to TRUE *after* sending
	   * response (otherwise, the client will receive the final
	   * token encrypted)
	   */
	  if (gssstat == GSS_S_COMPLETE) {
	       gss_release_buffer(&minor_stat, &call_res.signed_isn);
	       client_data->established = TRUE;
	  }
	  gss_release_buffer(&minor_stat, &output_token);
     } else {
	  PRINTF(("svcauth_gssapi: context is established\n"));

	  /* check the verifier */
	  PRINTF(("svcauth_gssapi: checking verifier, len %d\n",
		  verf->oa_length));
	  
	  in_buf.length = verf->oa_length;
	  in_buf.value = verf->oa_base;
	  
	  if (auth_gssapi_unseal_seq(client_data->context, &in_buf,
				     &seq_num) == FALSE) {
	       ret = AUTH_BADVERF;
	       LOG_MISCERR("internal error unsealing sequence number");
	       goto error;
	  }
	  
	  if (seq_num != client_data->seq_num + 1) {
	       PRINTF(("svcauth_gssapi: expected isn %d, got %d\n",
		       client_data->seq_num + 1, seq_num));
	       if (log_badverf != NULL)
		    (*log_badverf)(client_data->client_name,
				   client_data->server_name,
				   rqst, msg, log_badverf_data);
	       
	       ret = AUTH_REJECTEDVERF;
	       goto error;
	  }
	  client_data->seq_num++;
	  
	  PRINTF(("svcauth_gssapi: seq_num %d okay\n", seq_num));

	  /* free previous response verifier, if any */
	  if (client_data->prev_verf.length != 0) {
	       gss_release_buffer(&minor_stat, &client_data->prev_verf);
	       client_data->prev_verf.length = 0;
	  }
	  
	  /* prepare response verifier */
	  seq_num = client_data->seq_num + 1;
	  if (auth_gssapi_seal_seq(client_data->context, seq_num,
				   &out_buf) == FALSE) {
	       ret = AUTH_FAILED;
	       LOG_MISCERR("internal error sealing sequence number");
	       goto error;
	  }
	  
	  client_data->seq_num++;
	  
	  PRINTF(("svcauth_gssapi; response seq_num %d\n", seq_num));
	  
	  rqst->rq_xprt->xp_verf.oa_flavor = AUTH_GSSAPI;
	  rqst->rq_xprt->xp_verf.oa_base = out_buf.value; 
	  rqst->rq_xprt->xp_verf.oa_length = out_buf.length;

	  /* save verifier so it can be freed next time */
	  client_data->prev_verf.value = out_buf.value; 
	  client_data->prev_verf.length = out_buf.length;

	  /*
	   * Message is authentic.  If auth_msg if true, process the
	   * call; otherwise, return AUTH_OK so it will be dispatched
	   * to the application server.
	   */

	  if (creds.auth_msg == TRUE) {
	       /*
		* If process_token fails, then the token probably came
		* from an attacker.  No response (error or otherwise)
		* should be returned to the client, since it won't be
		* accepting one.
		*/

	       switch (rqst->rq_proc) {
	       case AUTH_GSSAPI_MSG:
		    PRINTF(("svcauth_gssapi: GSSAPI_MSG, getting args\n"));
		    memset(&call_arg, 0, sizeof(call_arg));
		    if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg,
				      &call_arg)) {
			 PRINTF(("svcauth_gssapi: cannot decode args\n"));
			 LOG_MISCERR("protocol error in call arguments");
			 xdr_free(xdr_authgssapi_init_arg, &call_arg);
			 ret = AUTH_BADCRED;
			 goto error;
		    }

		    PRINTF(("svcauth_gssapi: processing token\n"));
		    gssstat = gss_process_context_token(&minor_stat,
							client_data->context,
							&call_arg.token);

		    /* done with call args */
		    xdr_free(xdr_authgssapi_init_arg, &call_arg);
		    
		    if (gssstat != GSS_S_COMPLETE) {
			 AUTH_GSSAPI_DISPLAY_STATUS(("processing token",
						     gssstat, minor_stat));
			 ret = AUTH_FAILED;
			 goto error;
		    }

		    svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
		    *no_dispatch = TRUE;
		    break;

	       case AUTH_GSSAPI_DESTROY:
		    PRINTF(("svcauth_gssapi: GSSAPI_DESTROY\n"));
		    
		    PRINTF(("svcauth_gssapi: sending reply\n"));
		    svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
		    *no_dispatch = TRUE;

		    destroy_client(client_data);
		    rqst->rq_xprt->xp_auth = NULL;
		    break;

	       default:
		    PRINTF(("svcauth_gssapi: unacceptable procedure %d\n",
			    rqst->rq_proc));
		    LOG_MISCERR("invalid call procedure number");
		    ret = AUTH_FAILED;
		    goto error;
	       }
	  } else {
	       /* set credentials for app server; comment in svc.c */
	       /* seems to imply this is incorrect, but I don't see */
	       /* any problem with it... */
	       rqst->rq_clntcred = (char *)client_data->client_name;
	       rqst->rq_svccred = (char *)client_data->context;
	  }
     }

     if (creds.client_handle.length != 0) {
	  PRINTF(("svcauth_gssapi: freeing client_handle len %d\n",
		  (int) creds.client_handle.length));
	  xdr_free(xdr_authgssapi_creds, &creds);
     }
     
     PRINTF(("\n"));
     return AUTH_OK;

error:
     if (creds.client_handle.length != 0) {
	  PRINTF(("svcauth_gssapi: freeing client_handle len %d\n",
		  (int) creds.client_handle.length));
	  xdr_free(xdr_authgssapi_creds, &creds);
     }
     
     PRINTF(("\n"));
     return ret;
}
Ejemplo n.º 17
0
int authenticate_gss_server_step(gss_server_state *state, const char *challenge)
{
    OM_uint32 maj_stat;
    OM_uint32 min_stat;
    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
    int ret = AUTH_GSS_CONTINUE;
    
    // Always clear out the old response
    if (state->response != NULL)
    {
        free(state->response);
        state->response = NULL;
    }
    
    // If there is a challenge (data from the server) we need to give it to GSS
    if (challenge && *challenge)
    {
        size_t len;
        input_token.value = base64_decode(challenge, &len);
        input_token.length = len;
    }
    else
    {
        PyErr_SetString(KrbException_class, "No challenge parameter in request from client");
        ret = AUTH_GSS_ERROR;
        goto end;
    }
    
    Py_BEGIN_ALLOW_THREADS
    maj_stat = gss_accept_sec_context(&min_stat,
                                      &state->context,
                                      state->server_creds,
                                      &input_token,
                                      GSS_C_NO_CHANNEL_BINDINGS,
                                      &state->client_name,
                                      NULL,
                                      &output_token,
                                      (OM_uint32 *)&state->gss_flags,
                                      NULL,
                                      &state->client_creds);
    Py_END_ALLOW_THREADS
    
    if (GSS_ERROR(maj_stat))
    {
        set_gss_error(maj_stat, min_stat);
        ret = AUTH_GSS_ERROR;
        goto end;
    }
    
    // Grab the server response to send back to the client
    if (output_token.length)
    {
        state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);;
        maj_stat = gss_release_buffer(&min_stat, &output_token);
    }
    
    // Get the user name
    maj_stat = gss_display_name(&min_stat, state->client_name, &output_token, NULL);
    if (GSS_ERROR(maj_stat))
    {
        set_gss_error(maj_stat, min_stat);
        ret = AUTH_GSS_ERROR;
        goto end;
    }
    state->username = (char *)malloc(output_token.length + 1);
    strncpy(state->username, (char*) output_token.value, output_token.length);
    state->username[output_token.length] = 0;
    
    // Get the target name if no server creds were supplied
    if (state->server_creds == GSS_C_NO_CREDENTIAL)
    {
        gss_name_t target_name = GSS_C_NO_NAME;
        maj_stat = gss_inquire_context(&min_stat, state->context, NULL, &target_name, NULL, NULL, NULL, NULL, NULL);
        if (GSS_ERROR(maj_stat))
        {
            set_gss_error(maj_stat, min_stat);
            ret = AUTH_GSS_ERROR;
            goto end;
        }
        maj_stat = gss_display_name(&min_stat, target_name, &output_token, NULL);
        if (GSS_ERROR(maj_stat))
        {
            set_gss_error(maj_stat, min_stat);
            ret = AUTH_GSS_ERROR;
            goto end;
        }
        state->targetname = (char *)malloc(output_token.length + 1);
        strncpy(state->targetname, (char*) output_token.value, output_token.length);
        state->targetname[output_token.length] = 0;
    }

    ret = AUTH_GSS_COMPLETE;
    
end:
    if (output_token.length)
        gss_release_buffer(&min_stat, &output_token);
    if (input_token.value)
        free(input_token.value);
    return ret;
}
Ejemplo n.º 18
0
static int 
accept_user(gss_ctx_id_t *ctx,
	    gss_buffer_desc *in,
	    gss_buffer_desc *out,
	    gss_buffer_desc *name,
	    char **pccname)
{
    OM_uint32 maj_stat, min_stat;
    gss_name_t src_name = GSS_C_NO_NAME;
    gss_OID oid = GSS_C_NO_OID;
    int ret = -1;
    gss_cred_id_t delegated_cred_handle = NULL;

    *pccname = NULL;
    maj_stat = gss_accept_sec_context(&min_stat,
				      ctx,
				      GSS_C_NO_CREDENTIAL,
				      in,
				      GSS_C_NO_CHANNEL_BINDINGS,
				      &src_name,
				      &oid,
				      out,
				      NULL,
				      NULL,
				      &delegated_cred_handle);

    if ((maj_stat & GSS_S_CONTINUE_NEEDED) || maj_stat != GSS_S_COMPLETE) {
	fprintf(stderr, "gss_accept_sec_context: %08x %d %d ",
		maj_stat, maj_stat & GSS_S_CONTINUE_NEEDED, maj_stat != GSS_S_COMPLETE);
	gss_print_errors(min_stat);
	ret = HTTP_UNAUTHORIZED;
	goto out;
    }
				      
    if (name) {
	/* Use display name */
	maj_stat = gss_display_name(&min_stat, src_name, name, NULL);
	if (maj_stat != GSS_S_COMPLETE) {
	    ret = HTTP_UNAUTHORIZED;
	    goto out;
	}
    }

    ret = OK;

    if (delegated_cred_handle) {
	const struct mech_specific *m;

	m = find_mech(oid);
	if (m && m->save_cred)
	    (*m->save_cred)(name->value, delegated_cred_handle, pccname);
    } else {
/* 	fprintf(stderr, "Not delegated\r\n"); */
    }

 out:
    if (src_name != GSS_C_NO_NAME)
	gss_release_name(&min_stat, &src_name);

    return ret;
}
Ejemplo n.º 19
0
int
main (int argc, char *argv[])
{
  gss_uint32 maj_stat, min_stat, ret_flags, time_rec;
  gss_buffer_desc bufdesc, bufdesc2;
  gss_name_t servername = GSS_C_NO_NAME, name;
  gss_ctx_id_t cctx = GSS_C_NO_CONTEXT;
  gss_ctx_id_t sctx = GSS_C_NO_CONTEXT;
  gss_cred_id_t server_creds;
  Shishi *handle;
  size_t i;
  struct gss_channel_bindings_struct cb;

  memset (&cb, 0, sizeof (cb));
  cb.application_data.length = 3;
  cb.application_data.value = (char *) "hej";

  do
    if (strcmp (argv[argc - 1], "-v") == 0 ||
	strcmp (argv[argc - 1], "--verbose") == 0)
      debug = 1;
    else if (strcmp (argv[argc - 1], "-b") == 0 ||
	     strcmp (argv[argc - 1], "--break-on-error") == 0)
      break_on_error = 1;
    else if (strcmp (argv[argc - 1], "-h") == 0 ||
	     strcmp (argv[argc - 1], "-?") == 0 ||
	     strcmp (argv[argc - 1], "--help") == 0)
      {
	printf ("Usage: %s [-vbh?] [--verbose] [--break-on-error] [--help]\n",
		argv[0]);
	return 1;
      }
  while (argc-- > 1);

  handle = shishi ();

  /* Name of service. */

  bufdesc.value = (char *) "*****@*****.**";
  bufdesc.length = strlen (bufdesc.value);

  maj_stat = gss_import_name (&min_stat, &bufdesc,
			      GSS_C_NT_HOSTBASED_SERVICE, &servername);
  if (GSS_ERROR (maj_stat))
    fail ("gss_import_name (host/server)\n");

  /* Get credential, for server. */

  maj_stat = gss_acquire_cred (&min_stat, servername, 0,
			       GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
			       &server_creds, NULL, NULL);
  if (GSS_ERROR (maj_stat))
    {
      fail ("gss_acquire_cred");
      display_status ("acquire credentials", maj_stat, min_stat);
    }

  for (i = 0; i < 3; i++)
    {
      /* Start client. */

      switch (i)
	{
	case 0:
	  maj_stat = gss_init_sec_context (&min_stat,
					   GSS_C_NO_CREDENTIAL,
					   &cctx,
					   servername,
					   GSS_KRB5,
					   GSS_C_MUTUAL_FLAG |
					   GSS_C_REPLAY_FLAG |
					   GSS_C_SEQUENCE_FLAG,
					   0,
					   GSS_C_NO_CHANNEL_BINDINGS,
					   GSS_C_NO_BUFFER, NULL,
					   &bufdesc2, NULL, NULL);
	  if (maj_stat != GSS_S_CONTINUE_NEEDED)
	    fail ("loop 0 init failure\n");
	  break;

	case 1:
	  /* Default OID, channel bindings. */
	  maj_stat = gss_init_sec_context (&min_stat,
					   GSS_C_NO_CREDENTIAL,
					   &cctx,
					   servername,
					   GSS_C_NO_OID,
					   GSS_C_MUTUAL_FLAG |
					   GSS_C_REPLAY_FLAG |
					   GSS_C_SEQUENCE_FLAG,
					   0,
					   &cb,
					   GSS_C_NO_BUFFER, NULL,
					   &bufdesc2, NULL, NULL);
	  if (maj_stat != GSS_S_CONTINUE_NEEDED)
	    fail ("loop 0 init failure\n");
	  break;

	case 2:
	  /* No mutual authentication. */
	  maj_stat = gss_init_sec_context (&min_stat,
					   GSS_C_NO_CREDENTIAL,
					   &cctx,
					   servername,
					   GSS_KRB5,
					   GSS_C_REPLAY_FLAG |
					   GSS_C_CONF_FLAG |
					   GSS_C_SEQUENCE_FLAG,
					   0,
					   GSS_C_NO_CHANNEL_BINDINGS,
					   GSS_C_NO_BUFFER, NULL,
					   &bufdesc2, &ret_flags, NULL);
	  if (ret_flags != (GSS_C_REPLAY_FLAG |
			    GSS_C_CONF_FLAG |
			    GSS_C_SEQUENCE_FLAG | GSS_C_PROT_READY_FLAG))
	    fail ("loop 2 ret_flags failure (%d)\n", ret_flags);
	  if (maj_stat != GSS_S_COMPLETE)
	    fail ("loop 1 init failure\n");
	  break;

	default:
	  fail ("default?!\n");
	  break;
	}
      if (GSS_ERROR (maj_stat))
	{
	  fail ("gss_accept_sec_context failure\n");
	  display_status ("accept_sec_context", maj_stat, min_stat);
	}

      if (debug)
	{
	  char *p = bufdesc2.value;
	  Shishi_asn1 apreq = shishi_der2asn1_apreq (handle,
						     p + 17,
						     bufdesc2.length - 17);
	  printf ("\nClient AP-REQ:\n\n");
	  shishi_apreq_print (handle, stdout, apreq);
	}

      /* Start server. */

      switch (i)
	{
	case 0:
	  maj_stat = gss_accept_sec_context (&min_stat,
					     &sctx,
					     server_creds,
					     &bufdesc2,
					     GSS_C_NO_CHANNEL_BINDINGS,
					     &name,
					     NULL,
					     &bufdesc,
					     &ret_flags, &time_rec, NULL);
	  if (ret_flags != (GSS_C_MUTUAL_FLAG |
			    /* XXX GSS_C_REPLAY_FLAG |
			       GSS_C_SEQUENCE_FLAG | */
			    GSS_C_PROT_READY_FLAG))
	    fail ("loop 0 accept flag failure (%d)\n", ret_flags);
	  break;

	case 1:
	  maj_stat = gss_accept_sec_context (&min_stat,
					     &sctx,
					     server_creds,
					     &bufdesc2,
					     &cb,
					     &name,
					     NULL,
					     &bufdesc,
					     &ret_flags, &time_rec, NULL);
	  break;

	case 2:
	  maj_stat = gss_accept_sec_context (&min_stat,
					     &sctx,
					     server_creds,
					     &bufdesc2,
					     GSS_C_NO_CHANNEL_BINDINGS,
					     &name,
					     NULL,
					     &bufdesc,
					     &ret_flags, &time_rec, NULL);
	  break;
	default:
	  fail ("default?!\n");
	  break;
	}
      if (GSS_ERROR (maj_stat))
	{
	  fail ("gss_accept_sec_context failure\n");
	  display_status ("accept_sec_context", maj_stat, min_stat);
	}

      if (debug)
	{
	  char *p = bufdesc2.value;
	  Shishi_asn1 aprep =
	    shishi_der2asn1_aprep (handle, p + 15, bufdesc.length - 15);
	  printf ("\nServer AP-REP:\n\n");
	  shishi_aprep_print (handle, stdout, aprep);
	}

      switch (i)
	{
	case 0:
	  maj_stat = gss_init_sec_context (&min_stat,
					   GSS_C_NO_CREDENTIAL,
					   &cctx,
					   servername,
					   GSS_KRB5,
					   GSS_C_MUTUAL_FLAG |
					   GSS_C_REPLAY_FLAG |
					   GSS_C_SEQUENCE_FLAG,
					   0,
					   GSS_C_NO_CHANNEL_BINDINGS,
					   &bufdesc, NULL,
					   &bufdesc2, NULL, NULL);
	  break;

	case 1:
	  /* Check ret_flags. */
	  maj_stat = gss_init_sec_context (&min_stat,
					   GSS_C_NO_CREDENTIAL,
					   &cctx,
					   servername,
					   GSS_KRB5,
					   GSS_C_MUTUAL_FLAG |
					   GSS_C_REPLAY_FLAG |
					   GSS_C_SEQUENCE_FLAG,
					   0,
					   GSS_C_NO_CHANNEL_BINDINGS,
					   &bufdesc, NULL,
					   &bufdesc2, &ret_flags, &time_rec);
	  if (ret_flags != (GSS_C_MUTUAL_FLAG |
			    GSS_C_REPLAY_FLAG |
			    GSS_C_SEQUENCE_FLAG | GSS_C_PROT_READY_FLAG))
	    fail ("loop 1 ret_flags failure (%d)\n", ret_flags);
	  break;

	  /* No case 2. */

	default:
	  break;
	}
      if (GSS_ERROR (maj_stat))
	{
	  fail ("gss_init_sec_context failure (2)\n");
	  display_status ("init_sec_context", maj_stat, min_stat);
	}

      {
	gss_buffer_desc pt, pt2, ct;
	int conf_state;
	gss_qop_t qop_state;

	pt.value = (char *) "foo";
	pt.length = strlen (pt.value) + 1;
	maj_stat = gss_wrap (&min_stat, cctx, 0, 0, &pt, &conf_state, &ct);
	if (GSS_ERROR (maj_stat))
	  {
	    fail ("client gss_wrap failure\n");
	    display_status ("client wrap", maj_stat, min_stat);
	  }

	maj_stat = gss_unwrap (&min_stat, sctx,
			       &ct, &pt2, &conf_state, &qop_state);
	if (GSS_ERROR (maj_stat))
	  {
	    fail ("server gss_unwrap failure\n");
	    display_status ("client wrap", maj_stat, min_stat);
	  }

	if (pt.length != pt2.length
	    || memcmp (pt2.value, pt.value, pt.length) != 0)
	  fail ("wrap+unwrap failed (%d, %d, %.*s)\n",
		(int) pt.length, (int) pt2.length, (int) pt2.length,
		(char *) pt2.value);

	gss_release_buffer (&min_stat, &ct);
	gss_release_buffer (&min_stat, &pt2);
      }

      maj_stat = gss_delete_sec_context (&min_stat, &cctx, GSS_C_NO_BUFFER);
      if (GSS_ERROR (maj_stat))
	{
	  fail ("client gss_delete_sec_context failure\n");
	  display_status ("client delete_sec_context", maj_stat, min_stat);
	}

      maj_stat = gss_delete_sec_context (&min_stat, &sctx, GSS_C_NO_BUFFER);
      if (GSS_ERROR (maj_stat))
	{
	  fail ("server gss_delete_sec_context failure\n");
	  display_status ("server delete_sec_context", maj_stat, min_stat);
	}

      success ("loop %d ok\n", (int) i);
    }

  /* Clean up. */

  maj_stat = gss_release_cred (&min_stat, &server_creds);
  if (GSS_ERROR (maj_stat))
    {
      fail ("gss_release_cred");
      display_status ("release credentials", maj_stat, min_stat);
    }

  maj_stat = gss_release_name (&min_stat, &servername);
  if (GSS_ERROR (maj_stat))
    {
      fail ("gss_release_name failure\n");
      display_status ("gss_release_name", maj_stat, min_stat);
    }

  shishi_done (handle);

  /* We're done. */

  if (debug)
    printf ("Kerberos 5 security context self tests done with %d errors\n",
	    error_count);

  return error_count ? 1 : 0;
}
Ejemplo n.º 20
0
void *
example_gss_accept(
    int                                 socket,
    struct sockaddr                    *addr,
    socklen_t                          *addr_len,
    int                                *sock_out)
{
    example_gss_state_t                 *state;
    int                                 rc;
    gss_buffer_desc                     inbuf, token;
    OM_uint32                           maj_stat, min_stat;

    state = malloc(sizeof(example_gss_state_t));

    state->socket = accept(socket, addr, addr_len);

    if (state->socket < 0)
    {
        rc = -1;
        goto err;
    }
    *sock_out = state->socket;

    state->ctx = GSS_C_NO_CONTEXT;
    state->buffer.value = NULL;
    state->buffer.length = 0;

    inbuf.value = malloc(1024);
    do
    {
        inbuf.length = 1024;
        /* Read token */
        rc = recv(state->socket, inbuf.value, inbuf.length, 0);
        if (rc < 0)
        {
            break;
        }
        inbuf.length = rc;

        /* Pass to accept sec context */
        maj_stat = gss_accept_sec_context(
                &min_stat,
                &state->ctx,
                GSS_C_NO_CREDENTIAL,
                &inbuf,
                GSS_C_NO_CHANNEL_BINDINGS,
                NULL,
                NULL,
                &token,
                NULL,
                NULL,
                NULL);
        if (GSS_ERROR(maj_stat))
        {
            break;
        }
        /* Send output token if available */
        if (token.length > 0)
        {
            int sent;

            for (sent = 0; sent < token.length; )
            {
                rc = send(state->socket, ((char *) token.value)+sent,
                          token.length-sent, 0);

                if (rc < 0)
                {
                    break;
                }
                else
                {
                    sent += rc;
                }
            }
            gss_release_buffer(&min_stat, &token);
            token.value = NULL;
            token.length = 0;
        }
    }
    while (maj_stat == GSS_S_CONTINUE_NEEDED);

    if (inbuf.value)
    {
        free(inbuf.value);
    }
    if (GSS_ERROR(maj_stat))
    {
        rc = -1;
    }

err:
    if (rc < 0)
    {
        free(state);
        state = NULL;
    }
    return state;
}
Ejemplo n.º 21
0
static int
pamGssInitAcceptSecContext(pam_handle_t *pamh,
                           int confFlags,
                           gss_cred_id_t cred,
                           gss_cred_id_t acceptorCred,
                           gss_name_t hostName,
                           gss_OID mech)
{
    int status;
    OM_uint32 major, minor;
    gss_buffer_desc initiatorToken = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc acceptorToken = GSS_C_EMPTY_BUFFER;
    gss_ctx_id_t initiatorContext = GSS_C_NO_CONTEXT;
    gss_ctx_id_t acceptorContext = GSS_C_NO_CONTEXT;
    gss_buffer_desc canonUserNameBuf = GSS_C_EMPTY_BUFFER;
    gss_name_t canonUserName = GSS_C_NO_NAME;
    gss_OID canonMech = GSS_C_NO_OID;
    OM_uint32 gssFlags;

    do {
        major = gss_init_sec_context(&minor, cred, &initiatorContext,
                                     hostName, mech, GSS_C_MUTUAL_FLAG,
                                     GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
                                     &acceptorToken, NULL, &initiatorToken, &gssFlags, NULL);
        gss_release_buffer(&minor, &acceptorToken);

#ifdef GSS_S_PROMPTING_NEEDED
        if (major == GSS_S_PROMPTING_NEEDED) {
            status = PAM_CRED_INSUFFICIENT;
            goto cleanup;
        }
#endif

        BAIL_ON_GSS_ERROR(major, minor);

        if (initiatorToken.length != 0) {
            major = gss_accept_sec_context(&minor, &acceptorContext, acceptorCred,
                                           &initiatorToken, GSS_C_NO_CHANNEL_BINDINGS,
                                           &canonUserName, &canonMech, &acceptorToken,
                                           NULL, NULL, NULL);
            gss_release_buffer(&minor, &initiatorToken);
        }

        BAIL_ON_GSS_ERROR(major, minor);
    } while (major == GSS_S_CONTINUE_NEEDED);

    BAIL_ON_GSS_ERROR(major, minor);

    if ((gssFlags & GSS_C_MUTUAL_FLAG) == 0) {
        status = PAM_PERM_DENIED;
        goto cleanup;
    }

#ifndef __APPLE__
    major = gss_localname(&minor, canonUserName, GSS_C_NO_OID, &canonUserNameBuf);
    if (major == GSS_S_COMPLETE) {
        status = pam_set_item(pamh, PAM_USER, canonUserNameBuf.value);
        BAIL_ON_PAM_ERROR(status);
    } else if (major != GSS_S_UNAVAILABLE)
        goto cleanup;
#endif

    status = pam_set_data(pamh, GSS_NAME_DATA, canonUserName, pamGssCleanupName);
    BAIL_ON_PAM_ERROR(status);

    canonUserName = GSS_C_NO_NAME;

    status = pam_set_data(pamh, GSS_MECH_DATA, canonMech, pamGssCleanupMech);
    BAIL_ON_PAM_ERROR(status);

    canonMech = GSS_C_NO_OID;

    status = PAM_SUCCESS;

cleanup:
    gss_release_name(&minor, &canonUserName);
    gss_release_buffer(&minor, &initiatorToken);
    gss_release_buffer(&minor, &acceptorToken);
    gss_delete_sec_context(&minor, &initiatorContext, NULL);
    gss_delete_sec_context(&minor, &acceptorContext, NULL);
    gss_release_buffer(&minor, &canonUserNameBuf);

    if (IGNORE_ERR_P(status, confFlags))
        status = PAM_IGNORE;

    return status;
}
Ejemplo n.º 22
0
int main(int argc, char * const argv[])
{
  char buf[MAX_AUTHTOKEN_LEN];
  char *c;
  char *user=NULL;
  int length=0;
  static int err=0;
  int opt, rc, debug=0, loging=0;
  OM_uint32 ret_flags=0, spnego_flag=0;
  char *service_name=(char *)"HTTP",*host_name=NULL;
  char *token = NULL;
  char *service_principal = NULL;
  OM_uint32 major_status, minor_status;
  gss_ctx_id_t 		gss_context = GSS_C_NO_CONTEXT;
  gss_name_t 		client_name = GSS_C_NO_NAME;
  gss_name_t 		server_name = GSS_C_NO_NAME;
  gss_cred_id_t 	server_creds = GSS_C_NO_CREDENTIAL;
  gss_cred_id_t 	delegated_cred = GSS_C_NO_CREDENTIAL;
  gss_buffer_desc 	service = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc 	input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc 	output_token = GSS_C_EMPTY_BUFFER;
  const unsigned char	*kerberosToken       = NULL;
  size_t		kerberosTokenLength = 0;
  const unsigned char	*spnegoToken         = NULL ;
  size_t		spnegoTokenLength   = 0;

  setbuf(stdout,NULL);
  setbuf(stdin,NULL);

  while (-1 != (opt = getopt(argc, argv, "dis:h"))) {
    switch (opt) {
    case 'd':
      debug = 1;
      break;              
    case 'i':
      loging = 1;
      break;              
    case 's':
      service_principal = strdup(optarg);
      break;
    case 'h':
      fprintf(stdout, "Usage: \n");
      fprintf(stdout, "squid_kerb_auth -d [-s SPN]\n");
      fprintf(stdout, "SPN = service principal name\n");
      fprintf(stdout, "Can be set to GSS_C_NO_NAME to allow any entry from keytab\n");
      fprintf(stdout, "default SPN is HTTP/fqdn@DEFAULT_REALM\n");
      break;
    default:
      fprintf(stderr, "%s| %s: unknown option: -%c.\n", LogTime(), PROGRAM, opt);
    }
  }

  if (service_principal && strcasecmp(service_principal,"GSS_C_NO_NAME") ) {
    service.value = service_principal;
    service.length = strlen((char *)service.value);
  } else {
    host_name=gethost_name();
    if ( !host_name ) {
      fprintf(stderr, "%s| %s: Local hostname could not be determined. Please specify the service principal\n", LogTime(), PROGRAM);
      exit(-1);
    }
    service.value = malloc(strlen(service_name)+strlen(host_name)+2);
    snprintf(service.value,strlen(service_name)+strlen(host_name)+2,"%s@%s",service_name,host_name);
    service.length = strlen((char *)service.value);
  }

  while (1) {
    if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
      if (ferror(stdin)) {
	if (debug)
	  fprintf(stderr, "%s| %s: fgets() failed! dying..... errno=%d (%s)\n", LogTime(), PROGRAM, ferror(stdin),
		 strerror(ferror(stdin)));

	exit(1);    /* BIIG buffer */
      }
      exit(0);
    }

    c=memchr(buf,'\n',sizeof(buf)-1);
    if (c) {
      *c = '\0';
      length = c-buf;
    } else {
      err = 1;
    }
    if (err) {
      if (debug)
	fprintf(stderr, "%s| %s: Oversized message\n", LogTime(), PROGRAM);
      fprintf(stdout, "NA Oversized message\n");
      err = 0;
      continue;
    }

    if (debug)
      fprintf(stderr, "%s| %s: Got '%s' from squid (length: %d).\n", LogTime(), PROGRAM, buf ,length);

    if (buf[0] == '\0') {
      if (debug)
	fprintf(stderr, "%s| %s: Invalid request\n", LogTime(), PROGRAM);
      fprintf(stdout, "NA Invalid request\n");
      continue;
    }

    if (strlen(buf) < 2) {
      if (debug)
	fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
      fprintf(stdout, "NA Invalid request\n");
      continue;
    }

    if ( !strncmp(buf, "QQ", 2) ) {
      gss_release_buffer(&minor_status, &input_token);
      gss_release_buffer(&minor_status, &output_token);
      gss_release_buffer(&minor_status, &service);
      gss_release_cred(&minor_status, &server_creds);
      gss_release_cred(&minor_status, &delegated_cred);
      gss_release_name(&minor_status, &server_name);
      gss_release_name(&minor_status, &client_name);
      gss_delete_sec_context(&minor_status, &gss_context, NULL);
      if (kerberosToken) {
	/* Allocated by parseNegTokenInit, but no matching free function exists.. */
        if (!spnego_flag)
          free((char *)kerberosToken);
        kerberosToken=NULL;
      }
      if (spnego_flag) {
	/* Allocated by makeNegTokenTarg, but no matching free function exists.. */
        if (spnegoToken) 
	  free((char *)spnegoToken);
      	spnegoToken=NULL;
      }
      if (token) {
        free(token);
        token=NULL;
      }
      if (host_name) {
        free(host_name);
        host_name=NULL;
      }
      exit(0);
    }

    if ( !strncmp(buf, "YR", 2) && !strncmp(buf, "KK", 2) ) {
      if (debug)
	fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
      fprintf(stdout, "NA Invalid request\n");
      continue;
    }
    if ( !strncmp(buf, "YR", 2) ){
      if (gss_context != GSS_C_NO_CONTEXT )
        gss_delete_sec_context(&minor_status, &gss_context, NULL);
      gss_context = GSS_C_NO_CONTEXT;
    }

    if (strlen(buf) <= 3) {
      if (debug)
	fprintf(stderr, "%s| %s: Invalid negotiate request [%s]\n", LogTime(), PROGRAM, buf);
      fprintf(stdout, "NA Invalid negotiate request\n");
      continue;
    }
        
    input_token.length = base64_decode_len(buf+3);
    input_token.value = malloc(input_token.length);

    base64_decode(input_token.value,buf+3,input_token.length);

 
#ifndef HAVE_SPNEGO
    if (( rc=parseNegTokenInit (input_token.value,
				input_token.length,
				&kerberosToken,
				&kerberosTokenLength))!=0 ){
      if (debug)
	fprintf(stderr, "%s| %s: parseNegTokenInit failed with rc=%d\n", LogTime(), PROGRAM, rc);
        
      /* if between 100 and 200 it might be a GSSAPI token and not a SPNEGO token */    
      if ( rc < 100 || rc > 199 ) {
	if (debug)
	  fprintf(stderr, "%s| %s: Invalid GSS-SPNEGO query [%s]\n", LogTime(), PROGRAM, buf);
	fprintf(stdout, "NA Invalid GSS-SPNEGO query\n");
	goto cleanup;
      } 
      if ((input_token.length >= sizeof ntlmProtocol + 1) &&
	  (!memcmp (input_token.value, ntlmProtocol, sizeof ntlmProtocol))) {
	if (debug)
	  fprintf(stderr, "%s| %s: received type %d NTLM token\n", LogTime(), PROGRAM, (int) *((unsigned char *)input_token.value + sizeof ntlmProtocol));
	fprintf(stdout, "NA received type %d NTLM token\n",(int) *((unsigned char *)input_token.value + sizeof ntlmProtocol));
	goto cleanup;
      } 
      spnego_flag=0;
    } else {
      gss_release_buffer(&minor_status, &input_token);
      input_token.length=kerberosTokenLength;
      input_token.value=(void *)kerberosToken;
      spnego_flag=1;
    }
#else
    if ((input_token.length >= sizeof ntlmProtocol + 1) &&
	(!memcmp (input_token.value, ntlmProtocol, sizeof ntlmProtocol))) {
      if (debug)
	fprintf(stderr, "%s| %s: received type %d NTLM token\n", LogTime(), PROGRAM, (int) *((unsigned char *)input_token.value + sizeof ntlmProtocol));
      fprintf(stdout, "NA received type %d NTLM token\n",(int) *((unsigned char *)input_token.value + sizeof ntlmProtocol));
      goto cleanup;
    } 
#endif
     
    if ( service_principal ) {
      if ( strcasecmp(service_principal,"GSS_C_NO_NAME") ){
        major_status = gss_import_name(&minor_status, &service,
  				       (gss_OID) GSS_C_NULL_OID, &server_name);
       
      } else {
        server_name = GSS_C_NO_NAME;
        major_status = GSS_S_COMPLETE;
      }
    } else {
      major_status = gss_import_name(&minor_status, &service,
  				     gss_nt_service_name, &server_name);
    }

    if ( check_gss_err(major_status,minor_status,"gss_import_name()",debug,loging) )
      goto cleanup;

    major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
				    GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_creds,
				    NULL, NULL);
    if (check_gss_err(major_status,minor_status,"gss_acquire_cred()",debug,loging) )
      goto cleanup;

    major_status = gss_accept_sec_context(&minor_status,
					  &gss_context,
					  server_creds,
					  &input_token,
					  GSS_C_NO_CHANNEL_BINDINGS,
					  &client_name,
					  NULL,
					  &output_token,
					  &ret_flags,
					  NULL,
					  &delegated_cred);


    if (output_token.length) {
#ifndef HAVE_SPNEGO
      if (spnego_flag) {
	if ((rc=makeNegTokenTarg (output_token.value,
				  output_token.length,
				  &spnegoToken,
				  &spnegoTokenLength))!=0 ) {
	  if (debug)
	    fprintf(stderr, "%s| %s: makeNegTokenTarg failed with rc=%d\n", LogTime(), PROGRAM, rc);
	  fprintf(stdout, "NA makeNegTokenTarg failed with rc=%d\n",rc);
	  goto cleanup;
	}
      } else {
	spnegoToken = output_token.value;
	spnegoTokenLength = output_token.length;
      }
#else
      spnegoToken = output_token.value;
      spnegoTokenLength = output_token.length;
#endif
      token = malloc(base64_encode_len(spnegoTokenLength));
      if (token == NULL) {
	if (debug)
	  fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(), PROGRAM);
	fprintf(stdout, "NA Not enough memory\n");
        goto cleanup;
      }

      base64_encode(token,(const char *)spnegoToken,base64_encode_len(spnegoTokenLength),spnegoTokenLength);

      if (check_gss_err(major_status,minor_status,"gss_accept_sec_context()",debug,loging) )
	goto cleanup;
      if (major_status & GSS_S_CONTINUE_NEEDED) {
	if (debug)
	  fprintf(stderr, "%s| %s: continuation needed\n", LogTime(), PROGRAM);
	fprintf(stdout, "TT %s\n",token);
        goto cleanup;
      }
      gss_release_buffer(&minor_status, &output_token);
      major_status = gss_display_name(&minor_status, client_name, &output_token,
				      NULL);

      if (check_gss_err(major_status,minor_status,"gss_display_name()",debug,loging) )
	goto cleanup;
      
      user=malloc(output_token.length+1);
      if (user == NULL) {
        if (debug)
          fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(), PROGRAM);
        fprintf(stdout, "BH Not enough memory\n");
        goto cleanup;
      }
      memcpy(user,output_token.value,output_token.length);
      user[output_token.length]='\0';
      fprintf(stdout, "AF %s %s\n",token,user);
      if (debug)
	fprintf(stderr, "%s| %s: AF %s %s\n", LogTime(), PROGRAM, token,user); 
      if (loging)
	fprintf(stderr, "%s| %s: User %s authenticated\n", LogTime(), PROGRAM, user);
      goto cleanup;
    } else {
      if (check_gss_err(major_status,minor_status,"gss_accept_sec_context()",debug,loging) )
	goto cleanup;
      if (major_status & GSS_S_CONTINUE_NEEDED) {
	if (debug)
	  fprintf(stderr, "%s| %s: continuation needed\n", LogTime(), PROGRAM);
	fprintf(stdout, "NA No token to return to continue\n");
	goto cleanup;
      }
      gss_release_buffer(&minor_status, &output_token);
      major_status = gss_display_name(&minor_status, client_name, &output_token,
				      NULL);

      if (check_gss_err(major_status,minor_status,"gss_display_name()",debug,loging) )
	goto cleanup;
      /* 
       *  Return dummy token AA. May need an extra return tag then AF
       */
      user=malloc(output_token.length+1);
      if (user == NULL) { 
        if (debug)
          fprintf(stderr, "%s| %s: Not enough memory\n", LogTime(), PROGRAM);
        fprintf(stdout, "BH Not enough memory\n");
        goto cleanup; 
      }
      memcpy(user,output_token.value,output_token.length);
      user[output_token.length]='\0';      
      fprintf(stdout, "AF %s %s\n","AA==",user);
      if (debug)
	fprintf(stderr, "%s| %s: AF %s %s\n", LogTime(), PROGRAM, "AA==", user);
      if (loging)
	fprintf(stderr, "%s| %s: User %s authenticated\n", LogTime(), PROGRAM, user);

cleanup:
      gss_release_buffer(&minor_status, &input_token);
      gss_release_buffer(&minor_status, &output_token);
      gss_release_cred(&minor_status, &server_creds);
      gss_release_cred(&minor_status, &delegated_cred);
      gss_release_name(&minor_status, &server_name);
      gss_release_name(&minor_status, &client_name);
      if (kerberosToken) {
	/* Allocated by parseNegTokenInit, but no matching free function exists.. */
	if (!spnego_flag)
           free((char *)kerberosToken);
      	kerberosToken=NULL;
      }
      if (spnego_flag) {
	/* Allocated by makeNegTokenTarg, but no matching free function exists.. */
        if (spnegoToken)
	  free((char *)spnegoToken);
      	spnegoToken=NULL;
      }
      if (token) {
        free(token);
      	token=NULL;
      }
      if( user) {
         free(user);
         user=NULL;
      }
      continue;            
    }
  }
}
Ejemplo n.º 23
0
static int tunnel(struct gt_service *svc, int fd, struct sockaddr *cliaddr)
{
    AUTOCLEAN(char *tmbuf, autofreestr) = NULL;
    AUTOCLEAN(struct addrinfo *addr, autofreeaddrinfo) = NULL;
    AUTOCLEAN(int sd, autofreesocket) = -1;
    AUTOCLEAN(int efd, autofreesocket) = -1;
    AUTOCLEAN(gss_name_t name, autofreegssname) = GSS_C_NO_NAME;
    AUTOCLEAN(gss_name_t srcname, autofreegssname) = GSS_C_NO_NAME;
    AUTOCLEAN(gss_cred_id_t cred, autofreegsscred) = GSS_C_NO_CREDENTIAL;
    AUTOCLEAN(gss_ctx_id_t ctx, autofreegssctx) = GSS_C_NO_CONTEXT;
    AUTOCLEAN(gss_buffer_desc output, autofreegssbuf) = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc  namebuf;
    OM_uint32 maj, min;
    OM_uint32 ignore;
    struct epoll_event events[MAX_EVENTS];
    size_t tmlen;
    int pfd; /* plain text fd */
    int cfd; /* cipher text fd */
    int ret;

    /* We allocate a 1 MiB buffer for messages, that's also the maximum msg
     * size */
    tmbuf = malloc(MAX_MSG_SIZE);
    if (!tmbuf) return ENOMEM;

    if (svc->exec) {
        fprintf(stderr, "[%s] EXEC option not supported yet, sorry!\n",
                        svc->name);
        return ENOTSUP;
    }

    ret = string_to_addrinfo(svc->connect, &addr);
    if (ret) return ret;

    errno = 0;
    sd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    if (sd == -1) return errno;

    ret = connect(sd, addr->ai_addr, addr->ai_addrlen);
    if (ret != 0) {
        ret = errno;
        fprintf(stderr, "[%s] Failed to connect to server '%s': %s\n",
                        svc->name, svc->connect, strerror(ret));
        return ret;
    }

    if (svc->target_name) {
        namebuf.length = strlen(svc->target_name);
        namebuf.value = svc->target_name;
        maj = gss_import_name(&min, &namebuf,
                              GSS_C_NT_HOSTBASED_SERVICE, &name);
        if (maj != GSS_S_COMPLETE) {
            fprintf(stderr, "[%s] Failed to import name: '%s' (%d/%d)\n",
                            svc->name, svc->target_name,
                            (int)maj, (int)min);
            return EINVAL;
        }
    }

    if (svc->client) {
        pfd = fd;
        cfd = sd;

        do {
            maj = gss_init_sec_context(&min, cred, &ctx, name, GSS_C_NO_OID,
                                       GSS_C_MUTUAL_FLAG
                                        | GSS_C_REPLAY_FLAG
                                        | GSS_C_SEQUENCE_FLAG
                                        | GSS_C_CONF_FLAG
                                        | GSS_C_INTEG_FLAG, 0,
                                       GSS_C_NO_CHANNEL_BINDINGS,
                                       &input, NULL, &output, NULL, NULL);

            if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
                gt_gss_error(svc->name, GSS_C_NO_OID, maj, min);
                return EBADE;
            }

            if (output.length > MAX_MSG_SIZE) return ENOSPC;
            if (output.length > 0) {
                memcpy(tmbuf, output.value, output.length);
                tmlen = output.length;
                (void)gss_release_buffer(&ignore, &output);

                ret = send_msg(cfd, tmbuf, tmlen, true);
                if (ret) return ret;
            }

            if (maj == GSS_S_CONTINUE_NEEDED) {
                tmlen = MAX_MSG_SIZE;
                ret = recv_msg(cfd, tmbuf, &tmlen, true);
                if (ret) return ret;

                input.value = tmbuf;
                input.length = tmlen;
            }

        } while (maj == GSS_S_CONTINUE_NEEDED);

    } else {
        pfd = sd;
        cfd = fd;

        if (name != GSS_C_NO_NAME) {
            maj = gss_acquire_cred(&min, name, GSS_C_INDEFINITE,
                                   GSS_C_NO_OID_SET, GSS_C_ACCEPT,
                                   &cred, NULL, NULL);
            if (maj != GSS_S_COMPLETE) {
                fprintf(stderr,
                        "[%s] Failed to acquire creds for '%s' (%d/%d)\n",
                        svc->name, svc->target_name?svc->target_name:"",
                        (int)maj, (int)min);
                return EIO;
            }
        }

        do {
            tmlen = MAX_MSG_SIZE;
            ret = recv_msg(cfd, tmbuf, &tmlen, true);
            if (ret) return ret;

            input.value = tmbuf;
            input.length = tmlen;

            maj = gss_accept_sec_context(&min, &ctx, cred, &input,
                                         GSS_C_NO_CHANNEL_BINDINGS, &srcname,
                                         NULL, &output, NULL, NULL, NULL);

            if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
                gt_gss_error(svc->name, GSS_C_NO_OID, maj, min);
                return EBADE;
            }

            if (output.length > MAX_MSG_SIZE) return ENOSPC;
            if (output.length > 0) {
                memcpy(tmbuf, output.value, output.length);
                tmlen = output.length;
                (void)gss_release_buffer(&ignore, &output);

                ret = send_msg(cfd, tmbuf, tmlen, true);
                if (ret) return ret;
            }

        } while (maj == GSS_S_CONTINUE_NEEDED);
    }

    /* negotiation completed, now handle traffic */

    ret = init_epoll(cfd, pfd, &efd);
    if (ret) return ret;

    while (efd != -1) {
        struct epoll_event *ev;
        int n;
        n = epoll_wait(efd, events, MAX_EVENTS, -1);
        if (n == -1) {
            ret = errno;
            if (ret == EINTR) continue;
            return ret;
        }
        for (int i = 0; i < n; i++) {
            ev = &events[i];
            if (ev->events & (EPOLLERR|EPOLLHUP)) {
                /* one of the peers gave up */
                return ENOLINK;
            }

            /* RECEIVE */

            tmlen = MAX_MSG_SIZE;
            ret = recv_msg(ev->data.fd, tmbuf, &tmlen, (ev->data.fd == cfd));
            if (ret) return ret;

            if (ev->data.fd == cfd) {
                /* sender encrypts */
                input.value = tmbuf;
                input.length = tmlen;
                maj = gss_unwrap(&min, ctx, &input, &output, NULL, NULL);
                if (maj != GSS_S_COMPLETE) {
                    gt_gss_error(svc->name, GSS_C_NO_OID, maj, min);
                    return EIO;
                }
                if (output.length > MAX_MSG_SIZE) return ENOSPC;
                memcpy(tmbuf, output.value, output.length);
                tmlen = output.length;
                (void)gss_release_buffer(&ignore, &output);
            }

            /* RESEND */
            if (ev->data.fd == pfd) {
                /* receiver encrypts */
                input.value = tmbuf;
                input.length = tmlen;
                maj = gss_wrap(&min, ctx, 1, 0, &input, NULL, &output);
                if (maj != GSS_S_COMPLETE) {
                    gt_gss_error(svc->name, GSS_C_NO_OID, maj, min);
                    return EIO;
                }
                if (output.length > MAX_MSG_SIZE) return ENOSPC;
                memcpy(tmbuf, output.value, output.length);
                tmlen = output.length;
                (void)gss_release_buffer(&ignore, &output);
            }

            /* send to the other fd, add header only if we encrypted */
            ret = send_msg((ev->data.fd == pfd)?cfd:pfd,
                           tmbuf, tmlen, (ev->data.fd == pfd));
            if (ret) return ret;
        }
    }

    return 0;
}
Ejemplo n.º 24
0
static int
HandleOP(AcceptContext)
{
    OM_uint32 maj_stat, min_stat, ret_flags;
    int32_t hContext, deleg_hcred, flags;
    krb5_data in_token;
    int32_t new_context_id = 0, gsm_error = 0;
    krb5_data out_token = { 0 , NULL };

    gss_ctx_id_t ctx;
    gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
    gss_buffer_desc input_token, output_token;

    ret32(c, hContext);
    ret32(c, flags);
    retdata(c, in_token);

    ctx = find_handle(c->handles, hContext, handle_context);
    if (ctx == NULL)
	hContext = 0;

    if (in_token.length) {
	input_token.length = in_token.length;
	input_token.value = in_token.data;
    } else {
	input_token.length = 0;
	input_token.value = NULL;
    }

    maj_stat = gss_accept_sec_context(&min_stat,
				      &ctx,
				      GSS_C_NO_CREDENTIAL,
				      &input_token,
				      GSS_C_NO_CHANNEL_BINDINGS,
				      NULL,
				      NULL,
				      &output_token,
				      &ret_flags,
				      NULL,
				      &deleg_cred);
    if (GSS_ERROR(maj_stat)) {
	if (hContext != 0)
	    del_handle(&c->handles, hContext);
	logmessage(c, __FILE__, __LINE__, 0,
		   "gss_accept_sec_context returns code: %d/%d",
		   maj_stat, min_stat);
	new_context_id = 0;
    } else {
	if (hContext == 0)
	    new_context_id = add_handle(c, handle_context, ctx);
	else
	    new_context_id = hContext;
    }
    if (output_token.length) {
	out_token.data = output_token.value;
	out_token.length = output_token.length;
    }
    if ((ret_flags & GSS_C_DCE_STYLE) != 0)
	logmessage(c, __FILE__, __LINE__, 0, "accept_sec_context dce-style");
    if ((ret_flags & GSS_C_DELEG_FLAG) != 0) {
	deleg_hcred = add_handle(c, handle_cred, deleg_cred);
	logmessage(c, __FILE__, __LINE__, 0,
		   "accept_context delegated handle: %d", deleg_hcred);
    } else {
	gss_release_cred(&min_stat, &deleg_cred);
	deleg_hcred = 0;
    }


    gsm_error = convert_gss_to_gsm(maj_stat);

    put32(c, new_context_id);
    put32(c, gsm_error);
    putdata(c, out_token);
    put32(c, deleg_hcred);

    if (output_token.length)
	gss_release_buffer(&min_stat, &output_token);
    krb5_data_free(&in_token);

    return 0;
}
Ejemplo n.º 25
0
static int
test_libntlm_v1(int flags)
{
    const char *user = "******",
	*domain = "mydomain",
	*password = "******";
    OM_uint32 maj_stat, min_stat;
    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
    gss_buffer_desc input, output;
    struct ntlm_type1 type1;
    struct ntlm_type2 type2;
    struct ntlm_type3 type3;
    struct ntlm_buf data;
    krb5_error_code ret;
    gss_name_t src_name = GSS_C_NO_NAME;

    memset(&type1, 0, sizeof(type1));
    memset(&type2, 0, sizeof(type2));
    memset(&type3, 0, sizeof(type3));

    type1.flags = NTLM_NEG_UNICODE|NTLM_NEG_TARGET|NTLM_NEG_NTLM|flags;
    type1.domain = strdup(domain);
    type1.hostname = NULL;
    type1.os[0] = 0;
    type1.os[1] = 0;

    ret = heim_ntlm_encode_type1(&type1, &data);
    if (ret)
	errx(1, "heim_ntlm_encode_type1");

    input.value = data.data;
    input.length = data.length;

    output.length = 0;
    output.value = NULL;

    maj_stat = gss_accept_sec_context(&min_stat,
				      &ctx,
				      GSS_C_NO_CREDENTIAL,
				      &input,
				      GSS_C_NO_CHANNEL_BINDINGS,
				      NULL,
				      NULL,
				      &output,
				      NULL,
				      NULL,
				      NULL);
    free(data.data);
    if (GSS_ERROR(maj_stat))
	errx(1, "accept_sec_context v1: %s",
	     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));

    if (output.length == 0)
	errx(1, "output.length == 0");

    data.data = output.value;
    data.length = output.length;

    ret = heim_ntlm_decode_type2(&data, &type2);
    if (ret)
	errx(1, "heim_ntlm_decode_type2");

    gss_release_buffer(&min_stat, &output);

    type3.flags = type2.flags;
    type3.username = rk_UNCONST(user);
    type3.targetname = type2.targetname;
    type3.ws = rk_UNCONST("workstation");

    {
	struct ntlm_buf key;

	heim_ntlm_nt_key(password, &key);

	heim_ntlm_calculate_ntlm1(key.data, key.length,
				  type2.challenge,
				  &type3.ntlm);

	if (flags & NTLM_NEG_KEYEX) {
	    struct ntlm_buf sessionkey;
	    heim_ntlm_build_ntlm1_master(key.data, key.length,
					 &sessionkey,
				     &type3.sessionkey);
	    free(sessionkey.data);
	}
	free(key.data);
    }

    ret = heim_ntlm_encode_type3(&type3, &data);
    if (ret)
	errx(1, "heim_ntlm_encode_type3");

    input.length = data.length;
    input.value = data.data;

    maj_stat = gss_accept_sec_context(&min_stat,
				      &ctx,
				      GSS_C_NO_CREDENTIAL,
				      &input,
				      GSS_C_NO_CHANNEL_BINDINGS,
				      &src_name,
				      NULL,
				      &output,
				      NULL,
				      NULL,
				      NULL);
    free(input.value);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "accept_sec_context v1 2 %s",
	     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));

    gss_release_buffer(&min_stat, &output);
    gss_delete_sec_context(&min_stat, &ctx, NULL);

    if (src_name == GSS_C_NO_NAME)
	errx(1, "no source name!");

    gss_display_name(&min_stat, src_name, &output, NULL);

    printf("src_name: %.*s\n", (int)output.length, (char*)output.value);

    gss_release_name(&min_stat, &src_name);
    gss_release_buffer(&min_stat, &output);

    return 0;
}
Ejemplo n.º 26
0
int
main(int argc, char *argv[])
{
    OM_uint32 minor, major;
    gss_cred_id_t initiator_cred = GSS_C_NO_CREDENTIAL;
    gss_name_t target_name, initiator_name = GSS_C_NO_NAME;
    gss_name_t real_initiator_name;
    gss_buffer_desc token, tmp, namebuf;
    gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
    gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT;

    if (argc < 2 || argc > 3) {
        fprintf(stderr, "Usage: %s targetname [initiatorname|-]\n", argv[0]);
        return 1;
    }

    target_name = import_name(argv[1]);

    if (argc >= 3) {
        /* Get initiator cred. */
        if (strcmp(argv[2], "-") != 0)
            initiator_name = import_name(argv[2]);
        major = gss_acquire_cred(&minor, initiator_name, GSS_C_INDEFINITE,
                                 GSS_C_NO_OID_SET, GSS_C_INITIATE,
                                 &initiator_cred, NULL, NULL);
        check_gsserr("gss_acquire_cred", major, minor);
    }


    /* Create krb5 initiator context and get the first token. */
    token.value = NULL;
    token.length = 0;
    major = gss_init_sec_context(&minor, initiator_cred, &initiator_context,
                                 target_name, (gss_OID)gss_mech_krb5,
                                 GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
                                 GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
                                 GSS_C_NO_BUFFER, NULL, &token, NULL, NULL);
    check_gsserr("gss_init_sec_context", major, minor);

    /* Pass the token to gss_accept_sec_context. */
    tmp.value = NULL;
    tmp.length = 0;
    major = gss_accept_sec_context(&minor, &acceptor_context,
                                   GSS_C_NO_CREDENTIAL, &token,
                                   GSS_C_NO_CHANNEL_BINDINGS,
                                   &real_initiator_name, NULL, &tmp,
                                   NULL, NULL, NULL);
    check_gsserr("gss_accept_sec_context", major, minor);

    namebuf.value = NULL;
    namebuf.length = 0;
    major = gss_display_name(&minor, real_initiator_name, &namebuf, NULL);
    check_gsserr("gss_display_name(initiator)", major, minor);
    printf("%.*s\n", (int)namebuf.length, (char *)namebuf.value);

    (void)gss_release_name(&minor, &target_name);
    (void)gss_release_name(&minor, &initiator_name);
    (void)gss_release_name(&minor, &real_initiator_name);
    (void)gss_release_cred(&minor, &initiator_cred);
    (void)gss_delete_sec_context(&minor, &initiator_context, NULL);
    (void)gss_delete_sec_context(&minor, &acceptor_context, NULL);
    (void)gss_release_buffer(&minor, &token);
    (void)gss_release_buffer(&minor, &tmp);
    (void)gss_release_buffer(&minor, &namebuf);
    return 0;
}
Ejemplo n.º 27
0
/*
 * Negotiate a krb5 gss context from the server end.
 */
static int
gss_server(
    struct tcp_conn *rc)
{
    OM_uint32 maj_stat, min_stat, ret_flags;
    gss_buffer_desc send_tok, recv_tok, AA;
    gss_OID doid;
    gss_name_t gss_name;
    gss_cred_id_t gss_creds;
    char *p, *realm, *msg;
    int rval = -1;
    int rvalue;
    char errbuf[256];
    char *errmsg = NULL;

    auth_debug(1, "gss_server\n");

    assert(rc != NULL);

    /*
     * We need to be root while in gss_acquire_cred() to read the host key
     * out of the default keytab.  We also need to be root in
     * gss_accept_context() thanks to the replay cache code.
     */
    if (!set_root_privs(0)) {
	g_snprintf(errbuf, SIZEOF(errbuf),
	    _("can't take root privileges to read krb5 host key: %s"), strerror(errno));
	goto out;
    }

    rc->gss_context = GSS_C_NO_CONTEXT;
    send_tok.value = vstralloc("host/", myhostname, NULL);
    send_tok.length = strlen(send_tok.value) + 1;
    for (p = send_tok.value; *p != '\0'; p++) {
	if (isupper((int)*p))
	    *p = tolower(*p);
    }
    maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NULL_OID,
	&gss_name);
    if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
	set_root_privs(0);
	g_snprintf(errbuf, SIZEOF(errbuf),
	    _("can't import name %s: %s"), (char *)send_tok.value,
	    gss_error(maj_stat, min_stat));
	amfree(send_tok.value);
	goto out;
    }
    amfree(send_tok.value);

    maj_stat = gss_display_name(&min_stat, gss_name, &AA, &doid);
    dbprintf(_("gss_name %s\n"), (char *)AA.value);
    maj_stat = gss_acquire_cred(&min_stat, gss_name, 0,
	GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &gss_creds, NULL, NULL);
    if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
	g_snprintf(errbuf, SIZEOF(errbuf),
	    _("can't acquire creds for host key host/%s: %s"), myhostname,
	    gss_error(maj_stat, min_stat));
	gss_release_name(&min_stat, &gss_name);
	set_root_privs(0);
	goto out;
    }
    gss_release_name(&min_stat, &gss_name);

    for (recv_tok.length = 0;;) {
	recv_tok.value = NULL;
        rvalue = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg,
				 /* (void *) is to avoid type-punning warning */
				 (char **)(void *)&recv_tok.value,
				 (ssize_t *)&recv_tok.length, 60);
	if (rvalue <= 0) {
	    if (rvalue < 0) {
		g_snprintf(errbuf, SIZEOF(errbuf),
		    _("recv error in gss loop: %s"), rc->errmsg);
		amfree(rc->errmsg);
	    } else
		g_snprintf(errbuf, SIZEOF(errbuf), _("EOF in gss loop"));
	    goto out;
	}

	maj_stat = gss_accept_sec_context(&min_stat, &rc->gss_context,
	    gss_creds, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
	    &gss_name, &doid, &send_tok, &ret_flags, NULL, NULL);

	if (maj_stat != (OM_uint32)GSS_S_COMPLETE &&
	    maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) {
	    g_snprintf(errbuf, SIZEOF(errbuf),
		_("error accepting context: %s"), gss_error(maj_stat, min_stat));
	    amfree(recv_tok.value);
	    goto out;
	}
	amfree(recv_tok.value);

	if (send_tok.length != 0 && tcpm_send_token(rc, rc->write, 0, &errmsg, send_tok.value, send_tok.length) < 0) {
	    strncpy(errbuf, rc->errmsg, SIZEOF(errbuf) - 1);
	    errbuf[SIZEOF(errbuf) - 1] = '\0';
	    amfree(rc->errmsg);
	    gss_release_buffer(&min_stat, &send_tok);
	    goto out;
	}
	gss_release_buffer(&min_stat, &send_tok);


	/*
	 * If we need to get more from the client, then register for
	 * more packets.
	 */
	if (maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED)
	    break;
    }

    maj_stat = gss_display_name(&min_stat, gss_name, &send_tok, &doid);
    if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
	g_snprintf(errbuf, SIZEOF(errbuf),
	    _("can't display gss name: %s"), gss_error(maj_stat, min_stat));
	gss_release_name(&min_stat, &gss_name);
	goto out;
    }
    gss_release_name(&min_stat, &gss_name);

    /* get rid of the realm */
    if ((p = strchr(send_tok.value, '@')) == NULL) {
	g_snprintf(errbuf, SIZEOF(errbuf),
	    _("malformed gss name: %s"), (char *)send_tok.value);
	amfree(send_tok.value);
	goto out;
    }
    *p = '\0';
    realm = ++p;

    /* 
     * If the principal doesn't match, complain
     */
    if ((msg = krb5_checkuser(rc->hostname, send_tok.value, realm)) != NULL) {
	g_snprintf(errbuf, SIZEOF(errbuf),
	    _("access not allowed from %s: %s"), (char *)send_tok.value, msg);
	amfree(send_tok.value);
	goto out;
    }
    amfree(send_tok.value);

    rval = 0;
out:
    set_root_privs(0);
    if (rval != 0) {
	rc->errmsg = stralloc(errbuf);
    } else {
	rc->auth = 1;
    }
    auth_debug(1, _("gss_server returning %d\n"), rval);
    return (rval);
}
Ejemplo n.º 28
0
int
gsslib_put_credentials(gss_cred_id_t server_creds,
                       gss_buffer_desc *cred,
                       char *username)
{
   gss_ctx_id_t context = GSS_C_NO_CONTEXT;
   gss_buffer_desc client_name;
   OM_uint32 maj_stat, min_stat;
   GSSAPI_INT ret_flags;
   gss_buffer_desc send_tok;
   gss_name_t client = NULL;
   gss_OID doid;
   int cc=0;
   gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;

   gsslib_reset_error();

   send_tok.length = 0;
   client_name.length = 0;

   if (cred->length <= 0) {
      gsslib_print_error(MSG_GSS_PRINTERROR_CREDENTIALBUFFERLENGTHISZERO );
      cc = -1;
      goto error;
   }

   /*
    * establish and forward client credentials
    */

   maj_stat = gss_accept_sec_context(&min_stat,
                                     &context,
                                     server_creds,
                                     cred,
                                     GSS_C_NO_CHANNEL_BINDINGS,
                                     &client,
                                     &doid,
                                     &send_tok,
                                     &ret_flags,
                                     NULL,     /* ignore time_rec */
                                     &delegated_cred);    /* ignore del_cred_handle */

   if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
      gsslib_display_status(MSG_GSS_DISPLAYSTATUS_ACCEPTINGCONTEXT, maj_stat, min_stat);
      cc = -1;
      goto error;
   }

   if (send_tok.length != 0) {
      fprintf(stderr, "%s\n", MSG_GSS_ACCEPTSECCONTEXTREQUIRESTOKENTOBESENTBACK );
      /* cc = -1;
      goto error; */
   }

   maj_stat = gss_display_name(&min_stat, client, &client_name, &doid);
   if (maj_stat != GSS_S_COMPLETE) {
      gsslib_display_status(MSG_GSS_DISPLAYSTATUS_DISPLAYINGNAME, maj_stat, min_stat);
      cc = -1;
      goto error;
   }

#ifdef KRBGSS
#ifdef KRB5_EXPORTVAR /* this is required for later Kerberos versions */

   /* check for delegated credential */
   if (delegated_cred == GSS_C_NO_CREDENTIAL) {
      fprintf(stderr, "WARNING: Credentials were not forwarded\n");
#ifdef REQUIRE_FORWARDED_CREDENTIALS
      cc = 3;
      goto error;
#endif
   }

   if (username && (ret_flags & GSS_C_DELEG_FLAG)) {
      char *principal = malloc(client_name.length + 1);
      strncpy(principal, client_name.value, client_name.length);
      principal[client_name.length] = 0;
      put_creds_in_ccache(principal, delegated_cred);
      free(principal);
   }

#endif
#endif

   /* display the flags */
   if (verbose)
      gsslib_display_ctx_flags(ret_flags);

   if (verbose)
      printf("client: \"%.*s\"\n",
             (int) client_name.length, (char *) client_name.value);

   if (username) {
      gss_buffer_desc tok;
      gss_name_t user_name;
      int str_equal;

      tok.value = username;
      tok.length = strlen(tok.value)+1;
      maj_stat = gss_import_name(&min_stat, &tok, GSS_C_NULL_OID, &user_name);
      if (maj_stat != GSS_S_COMPLETE) {
	 gsslib_display_status(MSG_GSS_DISPLAYSTATUS_PARSINGNAME, maj_stat, min_stat);
         cc = -1;
         goto error;
      }
      maj_stat = gss_compare_name(&min_stat, client, user_name, &str_equal);
      if (maj_stat != GSS_S_COMPLETE) {
	 gsslib_display_status( MSG_GSS_DISPLAYSTATUS_DISPLAYINGNAME, maj_stat, min_stat);
         cc = 6;
         goto error;
      }

#ifdef KRBGSS

      if (!str_equal) {
         krb5_context context;

         maj_stat = krb5_init_context(&context);
         if (maj_stat != GSS_S_COMPLETE) {
            gsslib_display_status(MSG_GSS_DISPLAYSTATUS_GETTINGKRB5CONTEXT,
                                  maj_stat, GSS_S_COMPLETE);
            cc = -1;
            goto error;
         }

         /* see if this user is authorized by the krb5 client */
         if (krb5_kuserok(context, (krb5_principal)client, username))
            str_equal = 1;
      }

      /* Users from Kerberos cross-authenticated realms will not match,
         so we manually compare the user names */
      if (!str_equal) {
         char *s;
         if ((s=strchr((char *)client_name.value, '@')))
            str_equal = !strncmp(username, (char *)client_name.value, 
                                 s-(char *)client_name.value);
      }

#endif
      if (!str_equal) {
         char buf[1024];
         snprintf(buf, sizeof(buf), MSG_GSS_CLIENTNAMEXDOESNOTMATCHUNAMEY_SS,
                  (int)client_name.length, (char *)client_name.value, username);
         gsslib_print_error(buf);
         cc = 5;
         goto error;
      }
   }

#ifdef DCE

   while (delegated_cred) {
      sec_login_handle_t login_context;
      error_status_t st;
      dce_error_string_t err_string;
      int lst;
      sec_login_auth_src_t auth_src=NULL;
      boolean32 reset_passwd=0;
      char errbuf[1024];
      unsigned32 num_groups=0;
      signed32 *groups=NULL;
      unsigned32 flags;

      maj_stat = gssdce_set_cred_context_ownership(&min_stat, delegated_cred, GSSDCE_C_OWNERSHIP_APPLICATION);
      if (maj_stat != GSS_S_COMPLETE) {
	 gsslib_display_status(MSG_GSS_DISPLAYSTATUS_GSSDCESETCREDCONTEXTOWNERSHIP, maj_stat, min_stat);
	 break;
      }

#if 0
      gsslib_print_error(MSG_GSS_PRINTERROR_CREDENTIALDUMP);
      gsslib_print_error(dump_cred(delegated_cred));
#endif

      maj_stat = gssdce_cred_to_login_context(&min_stat, delegated_cred,
					      &login_context);
      if (maj_stat != GSS_S_COMPLETE) {
	 gsslib_display_status(MSG_GSS_DISPLAYSTATUS_GSSDCECREDTOLOGINCONTEXT, maj_stat,
			       min_stat);
	 break;
      }

#ifdef TURN_OFF_DELEGATION
      {
         sec_login_handle_t *new_login_context;

         new_login_context = sec_login_disable_delegation(login_context, &st);
         if (st != error_status_ok) {
            dce_error_inq_text(st, err_string, &lst);
            snprintf(errbuf, sizeof errbuf,
                     MSG_GSS_PRINTERROR_COULDNOTDISABLEDELEGATIONX_S, err_string);
            gsslib_print_error(errbuf);
         } else {
            login_context = *new_login_context;
         }
      }
#endif

      flags = sec_login_get_context_flags(login_context, &st);
      sec_login_set_context_flags(login_context,
				  flags & ~sec_login_credentials_private,
				  &st);


      if (!sec_login_certify_identity(login_context, &st)) {
	 dce_error_inq_text(st, err_string, &lst);
	 snprintf(errbuf, sizeof errbuf,
                  MSG_GSS_PRINTERROR_COULDNOTCERTIFYIDENTITYX_S, err_string);
         gsslib_print_error(errbuf);
	 break;
      }

      sec_login_set_context(login_context, &st);
      if (st != error_status_ok) {
         dce_error_inq_text(st, err_string, &lst);
	 snprintf(errbuf, sizeof errbuf,
                  MSG_GSS_PRINTERROR_COULDNOTSETUPLOGINCONTEXTX_S, err_string);
         gsslib_print_error(errbuf);
	 break;
      }

      {
	 char *cp;
	 cp = getenv("KRB5CCNAME");
	 if (cp) {
            snprintf(errbuf, sizeof errbuf, MSG_GSS_PRINTERROR_NEWKRB5CCNAMEISX_S , cp);
	    gsslib_print_error(errbuf);
	 } else {
	    gsslib_print_error(MSG_GSS_PRINTERROR_KRB5CCNAMENOTFOUND );
	 }
      }

      break;
   }

#endif /* DCE */

 error:

   if (client) {
      maj_stat = gss_release_name(&min_stat, &client);
      if (maj_stat != GSS_S_COMPLETE) {
         gsslib_display_status(MSG_GSS_DISPLAYSTATUS_RELEASINGNAME, maj_stat, min_stat);
         cc = -1;
      }
   }

   if (send_tok.length)
      (void) gss_release_buffer(&min_stat, &send_tok);

   if (client_name.length)
      (void) gss_release_buffer(&min_stat, &client_name);

   return cc;
}
Ejemplo n.º 29
0
isc_result_t
dst_gssapi_acceptctx(gss_cred_id_t cred,
		     const char *gssapi_keytab,
		     isc_region_t *intoken, isc_buffer_t **outtoken,
		     gss_ctx_id_t *ctxout, dns_name_t *principal,
		     isc_mem_t *mctx)
{
#ifdef GSSAPI
	isc_region_t r;
	isc_buffer_t namebuf;
	gss_buffer_desc gnamebuf = GSS_C_EMPTY_BUFFER, gintoken,
			gouttoken = GSS_C_EMPTY_BUFFER;
	OM_uint32 gret, minor;
	gss_ctx_id_t context = GSS_C_NO_CONTEXT;
	gss_name_t gname = NULL;
	isc_result_t result;
	char buf[1024];

	REQUIRE(outtoken != NULL && *outtoken == NULL);

	log_cred(cred);

	REGION_TO_GBUFFER(*intoken, gintoken);

	if (*ctxout == NULL)
		context = GSS_C_NO_CONTEXT;
	else
		context = *ctxout;

	if (gssapi_keytab != NULL) {
#ifdef ISC_PLATFORM_GSSAPI_KRB5_HEADER
		gret = gsskrb5_register_acceptor_identity(gssapi_keytab);
		if (gret != GSS_S_COMPLETE) {
			gss_log(3, "failed "
				"gsskrb5_register_acceptor_identity(%s): %s",
				gssapi_keytab,
				gss_error_tostring(gret, minor,
						   buf, sizeof(buf)));
			return (DNS_R_INVALIDTKEY);
		}
#else
		/*
		 * Minimize memory leakage by only setting KRB5_KTNAME
		 * if it needs to change.
		 */
		const char *old = getenv("KRB5_KTNAME");
		if (old == NULL || strcmp(old, gssapi_keytab) != 0) {
			char *kt = malloc(strlen(gssapi_keytab) + 13);
			if (kt == NULL)
				return (ISC_R_NOMEMORY);
			sprintf(kt, "KRB5_KTNAME=%s", gssapi_keytab);
			if (putenv(kt) != 0)
				return (ISC_R_NOMEMORY);
		}
#endif
	}

	gret = gss_accept_sec_context(&minor, &context, cred, &gintoken,
				      GSS_C_NO_CHANNEL_BINDINGS, &gname,
				      NULL, &gouttoken, NULL, NULL, NULL);

	result = ISC_R_FAILURE;

	switch (gret) {
	case GSS_S_COMPLETE:
		result = ISC_R_SUCCESS;
		break;
	case GSS_S_CONTINUE_NEEDED:
		result = DNS_R_CONTINUE;
		break;
	case GSS_S_DEFECTIVE_TOKEN:
	case GSS_S_DEFECTIVE_CREDENTIAL:
	case GSS_S_BAD_SIG:
	case GSS_S_DUPLICATE_TOKEN:
	case GSS_S_OLD_TOKEN:
	case GSS_S_NO_CRED:
	case GSS_S_CREDENTIALS_EXPIRED:
	case GSS_S_BAD_BINDINGS:
	case GSS_S_NO_CONTEXT:
	case GSS_S_BAD_MECH:
	case GSS_S_FAILURE:
		result = DNS_R_INVALIDTKEY;
		/* fall through */
	default:
		gss_log(3, "failed gss_accept_sec_context: %s",
			gss_error_tostring(gret, minor, buf, sizeof(buf)));
		return (result);
	}

	if (gouttoken.length > 0) {
		RETERR(isc_buffer_allocate(mctx, outtoken, gouttoken.length));
		GBUFFER_TO_REGION(gouttoken, r);
		RETERR(isc_buffer_copyregion(*outtoken, &r));
		(void)gss_release_buffer(&minor, &gouttoken);
	}

	if (gret == GSS_S_COMPLETE) {
		gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
		if (gret != GSS_S_COMPLETE) {
			gss_log(3, "failed gss_display_name: %s",
				gss_error_tostring(gret, minor,
						   buf, sizeof(buf)));
			RETERR(ISC_R_FAILURE);
		}

		/*
		 * Compensate for a bug in Solaris8's implementation
		 * of gss_display_name().  Should be harmless in any
		 * case, since principal names really should not
		 * contain null characters.
		 */
		if (gnamebuf.length > 0 &&
		    ((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
			gnamebuf.length--;

		gss_log(3, "gss-api source name (accept) is %.*s",
			(int)gnamebuf.length, (char *)gnamebuf.value);

		GBUFFER_TO_REGION(gnamebuf, r);
		isc_buffer_init(&namebuf, r.base, r.length);
		isc_buffer_add(&namebuf, r.length);

		RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname,
					 0, NULL));

		if (gnamebuf.length != 0) {
			gret = gss_release_buffer(&minor, &gnamebuf);
			if (gret != GSS_S_COMPLETE)
				gss_log(3, "failed gss_release_buffer: %s",
					gss_error_tostring(gret, minor, buf,
							   sizeof(buf)));
		}
	}

	*ctxout = context;

 out:
	if (gname != NULL) {
		gret = gss_release_name(&minor, &gname);
		if (gret != GSS_S_COMPLETE)
			gss_log(3, "failed gss_release_name: %s",
				gss_error_tostring(gret, minor, buf,
						   sizeof(buf)));
	}

	return (result);
#else
	UNUSED(cred);
	UNUSED(gssapi_keytab);
	UNUSED(intoken);
	UNUSED(outtoken);
	UNUSED(ctxout);
	UNUSED(principal);
	UNUSED(mctx);

	return (ISC_R_NOTIMPLEMENTED);
#endif
}
Ejemplo n.º 30
0
static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
				     TALLOC_CTX *out_mem_ctx,
				     struct tevent_context *ev,
				     const DATA_BLOB in, DATA_BLOB *out)
{
	struct gensec_gssapi_state *gensec_gssapi_state
		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
	NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
	OM_uint32 maj_stat, min_stat;
	OM_uint32 min_stat2;
	gss_buffer_desc input_token = { 0, NULL };
	gss_buffer_desc output_token = { 0, NULL };

	gss_OID gss_oid_p = NULL;
	OM_uint32 time_req = 0;
	OM_uint32 time_rec = 0;
	struct timeval tv;

	time_req = gensec_setting_int(gensec_security->settings,
				      "gensec_gssapi", "requested_life_time",
				      time_req);

	input_token.length = in.length;
	input_token.value = in.data;

	switch (gensec_gssapi_state->sasl_state) {
	case STAGE_GSS_NEG:
	{
		switch (gensec_security->gensec_role) {
		case GENSEC_CLIENT:
		{
#ifdef SAMBA4_USES_HEIMDAL
			struct gsskrb5_send_to_kdc send_to_kdc;
			krb5_error_code ret;
#endif

			nt_status = gensec_gssapi_client_creds(gensec_security, ev);
			if (!NT_STATUS_IS_OK(nt_status)) {
				return nt_status;
			}

#ifdef SAMBA4_USES_HEIMDAL
			send_to_kdc.func = smb_krb5_send_and_recv_func;
			send_to_kdc.ptr = ev;

			min_stat = gsskrb5_set_send_to_kdc(&send_to_kdc);
			if (min_stat) {
				DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
				return NT_STATUS_INTERNAL_ERROR;
			}
#endif
			maj_stat = gss_init_sec_context(&min_stat, 
							gensec_gssapi_state->client_cred->creds,
							&gensec_gssapi_state->gssapi_context, 
							gensec_gssapi_state->server_name, 
							gensec_gssapi_state->gss_oid,
							gensec_gssapi_state->gss_want_flags, 
							time_req,
							gensec_gssapi_state->input_chan_bindings,
							&input_token, 
							&gss_oid_p,
							&output_token, 
							&gensec_gssapi_state->gss_got_flags, /* ret flags */
							&time_rec);
			if (gss_oid_p) {
				gensec_gssapi_state->gss_oid = gss_oid_p;
			}

#ifdef SAMBA4_USES_HEIMDAL
			send_to_kdc.func = smb_krb5_send_and_recv_func;
			send_to_kdc.ptr = NULL;

			ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
			if (ret) {
				DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
				return NT_STATUS_INTERNAL_ERROR;
			}
#endif
			break;
		}
		case GENSEC_SERVER:
		{
			maj_stat = gss_accept_sec_context(&min_stat, 
							  &gensec_gssapi_state->gssapi_context, 
							  gensec_gssapi_state->server_cred->creds,
							  &input_token, 
							  gensec_gssapi_state->input_chan_bindings,
							  &gensec_gssapi_state->client_name, 
							  &gss_oid_p,
							  &output_token, 
							  &gensec_gssapi_state->gss_got_flags, 
							  &time_rec,
							  &gensec_gssapi_state->delegated_cred_handle);
			if (gss_oid_p) {
				gensec_gssapi_state->gss_oid = gss_oid_p;
			}
			break;
		}
		default:
			return NT_STATUS_INVALID_PARAMETER;
			
		}

		gensec_gssapi_state->gss_exchange_count++;

		if (maj_stat == GSS_S_COMPLETE) {
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat2, &output_token);
			
			if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
			    gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
				DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
			} else {
				DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
			}

			tv = timeval_current_ofs(time_rec, 0);
			gensec_gssapi_state->expire_time = timeval_to_nttime(&tv);

			/* We may have been invoked as SASL, so there
			 * is more work to do */
			if (gensec_gssapi_state->sasl) {
				gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
				return NT_STATUS_MORE_PROCESSING_REQUIRED;
			} else {
				gensec_gssapi_state->sasl_state = STAGE_DONE;

				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
					DEBUG(5, ("GSSAPI Connection will be cryptographically sealed\n"));
				} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
					DEBUG(5, ("GSSAPI Connection will be cryptographically signed\n"));
				} else {
					DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
				}

				return NT_STATUS_OK;
			}
		} else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat2, &output_token);
			
			return NT_STATUS_MORE_PROCESSING_REQUIRED;
		} else if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
			gss_cred_id_t creds = NULL;
			gss_name_t name;
			gss_buffer_desc buffer;
			OM_uint32 lifetime = 0;
			gss_cred_usage_t usage;
			const char *role = NULL;
			DEBUG(0, ("GSS %s Update(krb5)(%d) Update failed, credentials expired during GSSAPI handshake!\n",
				  role,
				  gensec_gssapi_state->gss_exchange_count));

			
			switch (gensec_security->gensec_role) {
			case GENSEC_CLIENT:
				creds = gensec_gssapi_state->client_cred->creds;
				role = "client";
				break;
			case GENSEC_SERVER:
				creds = gensec_gssapi_state->server_cred->creds;
				role = "server";
				break;
			}

			maj_stat = gss_inquire_cred(&min_stat, 
						    creds,
						    &name, &lifetime, &usage, NULL);

			if (maj_stat == GSS_S_COMPLETE) {
				const char *usage_string = NULL;
				switch (usage) {
				case GSS_C_BOTH:
					usage_string = "GSS_C_BOTH";
					break;
				case GSS_C_ACCEPT:
					usage_string = "GSS_C_ACCEPT";
					break;
				case GSS_C_INITIATE:
					usage_string = "GSS_C_INITIATE";
					break;
				}
				maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
				if (maj_stat) {
					buffer.value = NULL;
					buffer.length = 0;
				}
				if (lifetime > 0) {
					DEBUG(0, ("GSSAPI gss_inquire_cred indicates expiry of %*.*s in %u sec for %s\n", 
						  (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
						  lifetime, usage_string));
				} else {
					DEBUG(0, ("GSSAPI gss_inquire_cred indicates %*.*s has already expired for %s\n", 
						  (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
						  usage_string));
				}
				gss_release_buffer(&min_stat, &buffer);
				gss_release_name(&min_stat, &name);
			} else if (maj_stat != GSS_S_COMPLETE) {
				DEBUG(0, ("inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			}
			return NT_STATUS_INVALID_PARAMETER;
		} else if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
					     gss_mech_krb5)) {
			switch (min_stat) {
			case KRB5KRB_AP_ERR_TKT_NYV:
				DEBUG(1, ("Error with ticket to contact %s: possible clock skew between us and the KDC or target server: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_TIME_DIFFERENCE_AT_DC; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KRB_AP_ERR_TKT_EXPIRED:
				DEBUG(1, ("Error with ticket to contact %s: ticket is expired, possible clock skew between us and the KDC or target server: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5_KDC_UNREACH:
				DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticket to %s: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_NO_LOGON_SERVERS; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
				DEBUG(3, ("Server %s is not registered with our KDC: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KRB_AP_ERR_MSG_TYPE:
				/* garbage input, possibly from the auto-mech detection */
				return NT_STATUS_INVALID_PARAMETER;
			default:
				DEBUG(1, ("GSS %s Update(krb5)(%d) Update failed: %s\n",
					  gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
					  gensec_gssapi_state->gss_exchange_count,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_LOGON_FAILURE;
			}
		} else {
			DEBUG(1, ("GSS %s Update(%d) failed: %s\n",
				  gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
				  gensec_gssapi_state->gss_exchange_count,
				  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			return NT_STATUS_LOGON_FAILURE;
		}
		break;
	}

	/* These last two stages are only done if we were invoked as SASL */
	case STAGE_SASL_SSF_NEG:
	{
		switch (gensec_security->gensec_role) {
		case GENSEC_CLIENT:
		{
			uint8_t maxlength_proposed[4]; 
			uint8_t maxlength_accepted[4]; 
			uint8_t security_supported;
			int conf_state;
			gss_qop_t qop_state;
			input_token.length = in.length;
			input_token.value = in.data;

			/* As a client, we have just send a
			 * zero-length blob to the server (after the
			 * normal GSSAPI exchange), and it has replied
			 * with it's SASL negotiation */
			
			maj_stat = gss_unwrap(&min_stat, 
					      gensec_gssapi_state->gssapi_context, 
					      &input_token,
					      &output_token, 
					      &conf_state,
					      &qop_state);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			if (output_token.length < 4) {
				return NT_STATUS_INVALID_PARAMETER;
			}

			memcpy(maxlength_proposed, output_token.value, 4);
			gss_release_buffer(&min_stat, &output_token);

			/* first byte is the proposed security */
			security_supported = maxlength_proposed[0];
			maxlength_proposed[0] = '\0';
			
			/* Rest is the proposed max wrap length */
			gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0), 
								     gensec_gssapi_state->max_wrap_buf_size);
			gensec_gssapi_state->sasl_protection = 0;
			if (security_supported & NEG_SEAL) {
				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
					gensec_gssapi_state->sasl_protection |= NEG_SEAL;
				}
			}
			if (security_supported & NEG_SIGN) {
				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
					gensec_gssapi_state->sasl_protection |= NEG_SIGN;
				}
			}
			if (security_supported & NEG_NONE) {
				gensec_gssapi_state->sasl_protection |= NEG_NONE;
			}
			if (gensec_gssapi_state->sasl_protection == 0) {
				DEBUG(1, ("Remote server does not support unprotected connections\n"));
				return NT_STATUS_ACCESS_DENIED;
			}

			/* Send back the negotiated max length */

			RSIVAL(maxlength_accepted, 0, gensec_gssapi_state->max_wrap_buf_size);

			maxlength_accepted[0] = gensec_gssapi_state->sasl_protection;
			
			input_token.value = maxlength_accepted;
			input_token.length = sizeof(maxlength_accepted);

			maj_stat = gss_wrap(&min_stat, 
					    gensec_gssapi_state->gssapi_context, 
					    false,
					    GSS_C_QOP_DEFAULT,
					    &input_token,
					    &conf_state,
					    &output_token);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat, &output_token);

			/* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
			gensec_gssapi_state->sasl_state = STAGE_DONE;

			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically sealed\n"));
			} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically signed\n"));
			} else {
				DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographically protection\n"));
			}

			return NT_STATUS_OK;
		}
		case GENSEC_SERVER:
		{
			uint8_t maxlength_proposed[4]; 
			uint8_t security_supported = 0x0;
			int conf_state;

			/* As a server, we have just been sent a zero-length blob (note this, but it isn't fatal) */
			if (in.length != 0) {
				DEBUG(1, ("SASL/GSSAPI: client sent non-zero length starting SASL negotiation!\n"));
			}
			
			/* Give the client some idea what we will support */
			  
			RSIVAL(maxlength_proposed, 0, gensec_gssapi_state->max_wrap_buf_size);
			/* first byte is the proposed security */
			maxlength_proposed[0] = '\0';
			
			gensec_gssapi_state->sasl_protection = 0;
			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				security_supported |= NEG_SEAL;
			} 
			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				security_supported |= NEG_SIGN;
			}
			if (security_supported == 0) {
				/* If we don't support anything, this must be 0 */
				RSIVAL(maxlength_proposed, 0, 0x0);
			}

			/* TODO:  We may not wish to support this */
			security_supported |= NEG_NONE;
			maxlength_proposed[0] = security_supported;
			
			input_token.value = maxlength_proposed;
			input_token.length = sizeof(maxlength_proposed);

			maj_stat = gss_wrap(&min_stat, 
					    gensec_gssapi_state->gssapi_context, 
					    false,
					    GSS_C_QOP_DEFAULT,
					    &input_token,
					    &conf_state,
					    &output_token);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat, &output_token);

			gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
			return NT_STATUS_MORE_PROCESSING_REQUIRED;
		}
		default:
  			return NT_STATUS_INVALID_PARAMETER;
			
		}
	}
	/* This is s server-only stage */
	case STAGE_SASL_SSF_ACCEPT:
	{
		uint8_t maxlength_accepted[4]; 
		uint8_t security_accepted;
		int conf_state;
		gss_qop_t qop_state;
		input_token.length = in.length;
		input_token.value = in.data;
			
		maj_stat = gss_unwrap(&min_stat, 
				      gensec_gssapi_state->gssapi_context, 
				      &input_token,
				      &output_token, 
				      &conf_state,
				      &qop_state);
		if (GSS_ERROR(maj_stat)) {
			DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
				  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			return NT_STATUS_ACCESS_DENIED;
		}
			
		if (output_token.length < 4) {
			return NT_STATUS_INVALID_PARAMETER;
		}

		memcpy(maxlength_accepted, output_token.value, 4);
		gss_release_buffer(&min_stat, &output_token);
		
		/* first byte is the proposed security */
		security_accepted = maxlength_accepted[0];
		maxlength_accepted[0] = '\0';

		/* Rest is the proposed max wrap length */
		gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0), 
							     gensec_gssapi_state->max_wrap_buf_size);

		gensec_gssapi_state->sasl_protection = 0;
		if (security_accepted & NEG_SEAL) {
			if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				DEBUG(1, ("Remote client wanted seal, but gensec refused\n"));
				return NT_STATUS_ACCESS_DENIED;
			}
			gensec_gssapi_state->sasl_protection |= NEG_SEAL;
		}
		if (security_accepted & NEG_SIGN) {
			if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				DEBUG(1, ("Remote client wanted sign, but gensec refused\n"));
				return NT_STATUS_ACCESS_DENIED;
			}
			gensec_gssapi_state->sasl_protection |= NEG_SIGN;
		}
		if (security_accepted & NEG_NONE) {
			gensec_gssapi_state->sasl_protection |= NEG_NONE;
		}

		/* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
		gensec_gssapi_state->sasl_state = STAGE_DONE;
		if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
			DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically sealed\n"));
		} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
			DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically signed\n"));
		} else {
			DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
		}

		*out = data_blob(NULL, 0);
		return NT_STATUS_OK;	
	}
	default:
		return NT_STATUS_INVALID_PARAMETER;
	}
}