예제 #1
0
파일: client.c 프로젝트: dezelin/maily
int
_gsasl_kerberos_v5_client_step (Gsasl_session * sctx,
				void *mech_data,
				const char *input,
				size_t input_len,
				char *output, size_t * output_len)
{
  struct _Gsasl_kerberos_v5_client_state *state = mech_data;
  Gsasl_client_callback_authentication_id cb_authentication_id;
  Gsasl_client_callback_authorization_id cb_authorization_id;
  Gsasl_client_callback_qop cb_qop;
  Gsasl_client_callback_realm cb_realm;
  Gsasl_client_callback_password cb_password;
  Gsasl_client_callback_service cb_service;
  Gsasl_client_callback_maxbuf cb_maxbuf;
  Gsasl_ctx *ctx;
  int res;
  int len;

  ctx = gsasl_client_ctx_get (sctx);
  if (ctx == NULL)
    return GSASL_CANNOT_GET_CTX;

  /* These are optional */
  cb_realm = gsasl_client_callback_realm_get (ctx);
  cb_service = gsasl_client_callback_service_get (ctx);
  cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx);
  cb_authorization_id = gsasl_client_callback_authorization_id_get (ctx);
  cb_qop = gsasl_client_callback_qop_get (ctx);
  cb_maxbuf = gsasl_client_callback_maxbuf_get (ctx);

  /* Only optionally needed in infrastructure mode */
  cb_password = gsasl_client_callback_password_get (ctx);
  if (cb_password == NULL)
    return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;

  /* I think we really need this one */
  cb_service = gsasl_client_callback_service_get (ctx);
  if (cb_service == NULL)
    return GSASL_NEED_CLIENT_SERVICE_CALLBACK;

  switch (state->step)
    {
    case STEP_FIRST:
      if (input == NULL)
	{
	  *output_len = 0;
	  return GSASL_NEEDS_MORE;
	}

      if (input_len != SERVER_HELLO_LEN)
	return GSASL_MECHANISM_PARSE_ERROR;

      memcpy (state->serverhello, input, input_len);

      {
	unsigned char serverbitmap;

	memcpy (&serverbitmap, input, BITMAP_LEN);
	state->serverqops = 0;
	if (serverbitmap & GSASL_QOP_AUTH)
	  state->serverqops |= GSASL_QOP_AUTH;
	if (serverbitmap & GSASL_QOP_AUTH_INT)
	  state->serverqops |= GSASL_QOP_AUTH_INT;
	if (serverbitmap & GSASL_QOP_AUTH_CONF)
	  state->serverqops |= GSASL_QOP_AUTH_CONF;
	if (serverbitmap & MUTUAL)
	  state->servermutual = 1;
      }
      memcpy (&state->servermaxbuf, &input[BITMAP_LEN], MAXBUF_LEN);
      state->servermaxbuf = ntohl (state->servermaxbuf);

      if (cb_qop)
	state->clientqop = cb_qop (sctx, state->serverqops);

      if (!(state->serverqops & state->clientqop &
	    (GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF)))
	return GSASL_AUTHENTICATION_ERROR;

      /* XXX for now we require server authentication */
      if (!state->servermutual)
	return GSASL_AUTHENTICATION_ERROR;

      /* Decide policy here: non-infrastructure, infrastructure or proxy.
       *
       * A callback to decide should be added, but without the default
       * should be:
       *
       * IF shishi_tktset_get_for_server() THEN
       *    INFRASTRUCTURE MODE
       * ELSE IF shishi_realm_for_server(server) THEN
       *    PROXY INFRASTRUCTURE (then fallback to NIM?)
       * ELSE
       *    NON-INFRASTRUCTURE MODE
       */
      state->step = STEP_NONINFRA_SEND_APREQ;	/* only NIM for now.. */
      /* fall through */

    case STEP_NONINFRA_SEND_ASREQ:
      res = shishi_as (state->sh, &state->as);
      if (res)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      if (cb_authentication_id)	/* Shishi defaults to one otherwise */
	{
	  len = *output_len - 1;
	  res = cb_authentication_id (sctx, output, &len);
	  if (res != GSASL_OK)
	    return res;
	  output[len] = '\0';

	  res = shishi_kdcreq_set_cname (state->sh, shishi_as_req (state->as),
					 SHISHI_NT_UNKNOWN, output);
	  if (res != GSASL_OK)
	    return res;
	}

      if (cb_realm)
	{
	  len = *output_len - 1;
	  res = cb_realm (sctx, output, &len);
	  if (res != GSASL_OK)
	    return res;
	}
      else
	len = 0;

      output[len] = '\0';
      res = shishi_kdcreq_set_realm (state->sh, shishi_as_req (state->as),
				     output);
      if (res != GSASL_OK)
	return res;

      if (cb_service)
	{
	  char *sname[3];
	  size_t servicelen = 0;
	  size_t hostnamelen = 0;

	  res = cb_service (sctx, NULL, &servicelen, NULL, &hostnamelen,
			    /* XXX support servicename a'la DIGEST-MD5 too? */
			    NULL, NULL);
	  if (res != GSASL_OK)
	    return res;

	  if (*output_len < servicelen + 1 + hostnamelen + 1)
	    return GSASL_TOO_SMALL_BUFFER;

	  sname[0] = &output[0];
	  sname[1] = &output[servicelen + 2];
	  sname[2] = NULL;

	  res = cb_service (sctx, sname[0], &servicelen,
			    sname[1], &hostnamelen, NULL, NULL);
	  if (res != GSASL_OK)
	    return res;

	  sname[0][servicelen] = '\0';
	  sname[1][hostnamelen] = '\0';

	  res = shishi_kdcreq_set_sname (state->sh, shishi_as_req (state->as),
					 SHISHI_NT_UNKNOWN, sname);
	  if (res != GSASL_OK)
	    return res;
	}

      /* XXX query application for encryption types and set the etype
         field?  Already configured by shishi though... */

      res = shishi_a2d (state->sh, shishi_as_req (state->as),
			output, output_len);
      if (res != SHISHI_OK)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      state->step = STEP_NONINFRA_WAIT_ASREP;

      res = GSASL_NEEDS_MORE;
      break;

    case STEP_NONINFRA_WAIT_ASREP:
      if (shishi_as_rep_der_set (state->as, input, input_len) != SHISHI_OK)
	return GSASL_MECHANISM_PARSE_ERROR;

      /* XXX? password stored in callee's output buffer */
      len = *output_len - 1;
      res = cb_password (sctx, output, &len);
      if (res != GSASL_OK && res != GSASL_NEEDS_MORE)
	return res;
      output[len] = '\0';

      res = shishi_as_rep_process (state->as, NULL, output);
      if (res != SHISHI_OK)
	return GSASL_AUTHENTICATION_ERROR;

      state->step = STEP_NONINFRA_SEND_APREQ;
      /* fall through */

    case STEP_NONINFRA_SEND_APREQ:
      if (*output_len <= CLIENT_HELLO_LEN + SERVER_HELLO_LEN)
	return GSASL_TOO_SMALL_BUFFER;

      if (!(state->clientqop & ~GSASL_QOP_AUTH))
	state->clientmaxbuf = 0;
      else if (cb_maxbuf)
	state->clientmaxbuf = cb_maxbuf (sctx, state->servermaxbuf);
      else
	state->clientmaxbuf = MAXBUF_DEFAULT;

      /* XXX for now we require server authentication */
      output[0] = state->clientqop | MUTUAL;
      {
	uint32_t tmp;

	tmp = ntohl (state->clientmaxbuf);
	memcpy (&output[BITMAP_LEN], &tmp, MAXBUF_LEN);
      }
      memcpy (&output[CLIENT_HELLO_LEN], state->serverhello,
	      SERVER_HELLO_LEN);

      if (cb_authorization_id)
	{
	  len = *output_len - CLIENT_HELLO_LEN + SERVER_HELLO_LEN;
	  res = cb_authorization_id (sctx, &output[CLIENT_HELLO_LEN +
						   SERVER_HELLO_LEN], &len);
	}
      else
	len = 0;

      len += CLIENT_HELLO_LEN + SERVER_HELLO_LEN;
      res = shishi_ap_tktoptionsdata (state->sh,
				      &state->ap,
				      shishi_as_tkt (state->as),
				      SHISHI_APOPTIONS_MUTUAL_REQUIRED,
				      output, len);
      if (res != SHISHI_OK)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      res = shishi_authenticator_add_authorizationdata
	(state->sh, shishi_ap_authenticator (state->ap), -1, output, len);
      if (res != SHISHI_OK)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      /* XXX set realm in AP-REQ and Authenticator */

      res = shishi_ap_req_der (state->ap, output, output_len);
      if (res != SHISHI_OK)
	return GSASL_KERBEROS_V5_INTERNAL_ERROR;

      state->step = STEP_NONINFRA_WAIT_APREP;

      res = GSASL_NEEDS_MORE;
      break;

    case STEP_NONINFRA_WAIT_APREP:
      if (shishi_ap_rep_der_set (state->ap, input, input_len) != SHISHI_OK)
	return GSASL_MECHANISM_PARSE_ERROR;

      res = shishi_ap_rep_verify (state->ap);
      if (res != SHISHI_OK)
	return GSASL_AUTHENTICATION_ERROR;

      state->step = STEP_SUCCESS;

      /* XXX support AP session keys */
      state->sessionkey = shishi_tkt_key (shishi_as_tkt (state->as));

      *output_len = 0;
      res = GSASL_OK;
      break;

    default:
      res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
      break;
    }

  return res;
}
예제 #2
0
파일: rsh.c 프로젝트: dmr0605/Kerberos
/* shishi authentication */
int
auth (Shishi * h, int verbose, const char *cname, const char *sname, int sock,
      char *cmd, char *port, Shishi_key ** enckey, Shishi_key * deckey)
{
  Shishi_ap *ap;
  Shishi_tkt *tkt;
  Shishi_tkts_hint hint;

  int rc;
  char *out;
  int outlen;
  int krb5len, msglen;
  char auth;
  /* KERBEROS 5 SENDAUTH MESSAGE */
  char krb5sendauth[] = "KRB5_SENDAUTH_V1.0";
  /* PROTOCOL VERSION */
  char krb5sendclient[] = "KCMDV0.2";
  /* to store error msg sent by server */
  char errormsg[101];
  char cksumdata[101];

  /* size of KRB5 auth message */
  krb5len = strlen (krb5sendauth) + 1;
  msglen = htonl (krb5len);
  safewrite (sock, &msglen, sizeof (int));
  /* KRB5 authentication message */
  safewrite (sock, krb5sendauth, krb5len);
  /* size of client message */
  krb5len = strlen (krb5sendclient) + 1;
  msglen = htonl (krb5len);
  safewrite (sock, &msglen, sizeof (int));
  /* KRB5 client message */
  safewrite (sock, krb5sendclient, krb5len);

  /* get answer from server 0 = ok, 1 = error with message */
  read (sock, &auth, 1);
  if (auth)
    {
      read (sock, errormsg, 100);
      errormsg[100] = '\0';

      printf ("Error during server authentication : %s\n", errormsg);
      return 1;
    }

  if (verbose)
    {
      printf ("Client: %s\n", cname);
      printf ("Server: %s\n", sname);
    }

  /* Get a ticket for the server. */

  memset (&hint, 0, sizeof (hint));

  hint.client = (char *) cname;
  hint.server = (char *) sname;

  tkt = shishi_tkts_get (shishi_tkts_default (h), &hint);
  if (!tkt)
    {
      printf ("cannot find ticket for \"%s\"\n", sname);
      return 1;
    }

  if (verbose)
    shishi_tkt_pretty_print (tkt, stderr);

  /* Create Authentication context */

  rc = shishi_ap_tktoptions (h, &ap, tkt, SHISHI_APOPTIONS_MUTUAL_REQUIRED);
  if (rc != SHISHI_OK)
    {
      printf ("cannot create authentication context\n");
      return 1;
    }


  /* checksum = port: terminal name */

  snprintf (cksumdata, 100, "%s:%s%s", port, cmd, cname);

  /* add checksum to authenticator */

  shishi_ap_authenticator_cksumdata_set (ap, cksumdata, strlen (cksumdata));
  /* To be compatible with MIT rlogind */
  shishi_ap_authenticator_cksumtype_set (ap, SHISHI_RSA_MD5);

  /* create der encoded AP-REQ */

  rc = shishi_ap_req_der (ap, &out, &outlen);
  if (rc != SHISHI_OK)
    {
      printf ("cannot build authentication request: %s\n",
	      shishi_strerror (rc));

      return 1;
    }

  if (verbose)
    shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap));

  /* extract subkey if present from ap exchange for secure connection */

  shishi_authenticator_get_subkey (h, shishi_ap_authenticator (ap), enckey);

  /* send size of AP-REQ to the server */

  msglen = htonl (outlen);
  safewrite (sock, (char *) &msglen, sizeof (int));

  /* send AP-REQ to the server */

  safewrite (sock, out, outlen);

  /* read a respond from server - what ? */

  read (sock, &auth, sizeof (int));

  /* For mutual authentication, wait for server reply. */

  if (shishi_apreq_mutual_required_p (h, shishi_ap_req (ap)))
    {
      if (verbose)
	printf ("Waiting for server to authenticate itself...\n");

      /* read size of the AP-REP */

      read (sock, (char *) &outlen, sizeof (int));

      /* read AP-REP */
      outlen = ntohl (outlen);
      outlen = read (sock, out, outlen);

      rc = shishi_ap_rep_verify_der (ap, out, outlen);
      if (rc == SHISHI_OK)
	{
	  if (verbose)
	    printf ("AP-REP verification OK...\n");
	}
      else
	{
	  if (rc == SHISHI_APREP_VERIFY_FAILED)
	    printf ("AP-REP verification failed...\n");
	  else
	    printf ("AP-REP verification error: %s\n", shishi_strerror (rc));
	  return 1;
	}

      /* The server is authenticated. */
      if (verbose)
	printf ("Server authenticated.\n");
    }

  /* We are now authenticated. */
  if (verbose)
    printf ("User authenticated.\n");

  return AUTH_OK;

}
예제 #3
0
파일: context.c 프로젝트: dezelin/maily
/* Request part of gss_krb5_init_sec_context.  Assumes that
   context_handle is valid, and has krb5 specific structure, and that
   output_token is valid and cleared. */
static OM_uint32
init_request (OM_uint32 * minor_status,
              const gss_cred_id_t initiator_cred_handle,
              gss_ctx_id_t * context_handle,
              const gss_name_t target_name,
              const gss_OID mech_type,
              OM_uint32 req_flags,
              OM_uint32 time_req,
              const gss_channel_bindings_t input_chan_bindings,
              const gss_buffer_t input_token,
              gss_OID * actual_mech_type,
              gss_buffer_t output_token,
              OM_uint32 * ret_flags, OM_uint32 * time_rec)
{
    gss_ctx_id_t ctx = *context_handle;
    _gss_krb5_ctx_t k5 = ctx->krb5;
    char *cksum, *der;
    size_t cksumlen;
    int rc;
    OM_uint32 maj_stat;
    gss_buffer_desc tmp;
    Shishi_tkts_hint hint;

    /* Get service ticket. */
    maj_stat = gss_krb5_canonicalize_name (minor_status, target_name,
                                           GSS_C_NO_OID, &k5->peerptr);
    if (GSS_ERROR (maj_stat))
        return maj_stat;

    memset (&hint, 0, sizeof (hint));
    hint.server = k5->peerptr->value;
    hint.endtime = time_req;

    k5->tkt = shishi_tkts_get (shishi_tkts_default (k5->sh), &hint);
    if (!k5->tkt)
    {
        if (minor_status)
            *minor_status = GSS_KRB5_S_KG_CCACHE_NOMATCH;
        return GSS_S_NO_CRED;
    }

    /* Create Authenticator checksum field. */
    maj_stat = _gss_krb5_checksum_pack (minor_status, initiator_cred_handle,
                                        context_handle,
                                        input_chan_bindings, req_flags,
                                        &cksum, &cksumlen);
    if (GSS_ERROR (maj_stat))
        return maj_stat;

    /* Create AP-REQ in output_token. */
    rc = shishi_ap_tktoptionsraw (k5->sh, &k5->ap, k5->tkt,
                                  SHISHI_APOPTIONS_MUTUAL_REQUIRED,
                                  0x8003, cksum, cksumlen);
    free (cksum);
    if (rc != SHISHI_OK)
        return GSS_S_FAILURE;

    rc = shishi_authenticator_seqnumber_get (k5->sh,
            shishi_ap_authenticator (k5->ap),
            &k5->initseqnr);
    if (rc != SHISHI_OK)
        return GSS_S_FAILURE;

    rc = shishi_ap_req_der (k5->ap, &der, &tmp.length);
    if (rc != SHISHI_OK)
        return GSS_S_FAILURE;

    tmp.value = der;

    rc = gss_encapsulate_token_prefix (&tmp, TOK_AP_REQ, TOK_LEN,
                                       GSS_KRB5, output_token);
    free (der);
    if (!rc)
        return GSS_S_FAILURE;

    if (req_flags & GSS_C_MUTUAL_FLAG)
        return GSS_S_CONTINUE_NEEDED;

    return GSS_S_COMPLETE;
}