Beispiel #1
0
static int
input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh)
{
	Authctxt *authctxt = ssh->authctxt;
	Gssctxt *gssctxt;
	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
	gss_buffer_desc recv_tok;
	OM_uint32 maj_status, min_status, flags;
	u_char *p;
	size_t len;
	int r;

	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
		fatal("No authentication or GSSAPI context");

	gssctxt = authctxt->methoddata;
	if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 ||
	    (r = sshpkt_get_end(ssh)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));

	recv_tok.value = p;
	recv_tok.length = len;
	maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
	    &send_tok, &flags));

	xfree(p);

	if (GSS_ERROR(maj_status)) {
		if (send_tok.length != 0) {
			if ((r = sshpkt_start(ssh,
			    SSH2_MSG_USERAUTH_GSSAPI_ERRTOK)) != 0 ||
			    (r = sshpkt_put_string(ssh, send_tok.value,
			    send_tok.length)) != 0 ||
			    (r = sshpkt_send(ssh)) != 0)
				fatal("%s: %s", __func__, ssh_err(r));
		}
		authctxt->postponed = 0;
		ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
		userauth_finish(ssh, 0, "gssapi-with-mic", NULL);
	} else {
		if (send_tok.length != 0) {
			if ((r = sshpkt_start(ssh,
			    SSH2_MSG_USERAUTH_GSSAPI_TOKEN)) != 0 ||
			    (r = sshpkt_put_string(ssh, send_tok.value,
			    send_tok.length)) != 0 ||
			    (r = sshpkt_send(ssh)) != 0)
				fatal("%s: %s", __func__, ssh_err(r));
		}
		if (maj_status == GSS_S_COMPLETE) {
			ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
			if (flags & GSS_C_INTEG_FLAG)
				ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC,
				    &input_gssapi_mic);
			else
				ssh_dispatch_set(ssh, 
				    SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
				    &input_gssapi_exchange_complete);
		}
	}

	gss_release_buffer(&min_status, &send_tok);
	return 0;
}
static OM_uint32
spnego_initial
           (OM_uint32 * minor_status,
	    gssspnego_cred cred,
            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
    )
{
    NegTokenInit ni;
    int ret;
    OM_uint32 sub, minor;
    gss_buffer_desc mech_token;
    u_char *buf;
    size_t buf_size, buf_len;
    gss_buffer_desc data;
    size_t ni_len;
    gss_ctx_id_t context;
    gssspnego_ctx ctx;

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

    *context_handle = GSS_C_NO_CONTEXT;

    *minor_status = 0;

    sub = _gss_spnego_alloc_sec_context(&minor, &context);
    if (GSS_ERROR(sub)) {
	*minor_status = minor;
	return sub;
    }
    ctx = (gssspnego_ctx)context;

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    ctx->local = 1;

    sub = _gss_spnego_indicate_mechtypelist(&minor, 0,
					    cred,
					    &ni.mechTypes,
					    &ctx->preferred_mech_type);
    if (GSS_ERROR(sub)) {
	*minor_status = minor;
	_gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
	return sub;
    }

    ni.reqFlags = NULL;

    /*
     * If we have a credential handle, use it to select the mechanism
     * that we will use
     */

    /* generate optimistic token */
    sub = gss_init_sec_context(&minor,
			       (cred != NULL) ? cred->negotiated_cred_id :
			          GSS_C_NO_CREDENTIAL,
			       &ctx->negotiated_ctx_id,
			       target_name,
			       GSS_C_NO_OID,
			       req_flags,
			       time_req,
			       input_chan_bindings,
			       input_token,
			       &ctx->negotiated_mech_type,
			       &mech_token,
			       &ctx->mech_flags,
			       &ctx->mech_time_rec);
    if (GSS_ERROR(sub)) {
	free_NegTokenInit(&ni);
	*minor_status = minor;
	_gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
	return sub;
    }

    if (mech_token.length != 0) {
	ALLOC(ni.mechToken, 1);
	if (ni.mechToken == NULL) {
	    free_NegTokenInit(&ni);
	    gss_release_buffer(&minor, &mech_token);
	    _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
	    *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	}
	ni.mechToken->length = mech_token.length;
	ni.mechToken->data = malloc(mech_token.length);
	if (ni.mechToken->data == NULL && mech_token.length != 0) {
	    free_NegTokenInit(&ni);
	    gss_release_buffer(&minor, &mech_token);
	    *minor_status = ENOMEM;
	    _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
	    return GSS_S_FAILURE;
	}
	memcpy(ni.mechToken->data, mech_token.value, mech_token.length);
	gss_release_buffer(&minor, &mech_token);
    } else
	ni.mechToken = NULL;

    ni.mechListMIC = NULL;

    ni_len = length_NegTokenInit(&ni);
    buf_size = 1 + der_length_len(ni_len) + ni_len;

    buf = malloc(buf_size);
    if (buf == NULL) {
	free_NegTokenInit(&ni);
	*minor_status = ENOMEM;
	_gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
	return GSS_S_FAILURE;
    }

    ret = encode_NegTokenInit(buf + buf_size - 1,
			      ni_len,
			      &ni, &buf_len);
    if (ret == 0 && ni_len != buf_len)
	abort();

    if (ret == 0) {
	size_t tmp;

	ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
				     buf_size - buf_len,
				     buf_len,
				     ASN1_C_CONTEXT,
				     CONS,
				     0,
				     &tmp);
	if (ret == 0 && tmp + buf_len != buf_size)
	    abort();
    }
    if (ret) {
	*minor_status = ret;
	free(buf);
	free_NegTokenInit(&ni);
	_gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
	return GSS_S_FAILURE;
    }

    data.value  = buf;
    data.length = buf_size;

    ctx->initiator_mech_types.len = ni.mechTypes.len;
    ctx->initiator_mech_types.val = ni.mechTypes.val;
    ni.mechTypes.len = 0;
    ni.mechTypes.val = NULL;
 
    free_NegTokenInit(&ni);

    sub = gss_encapsulate_token(&data,
				GSS_SPNEGO_MECHANISM,
				output_token);
    free (buf);

    if (sub) {
	_gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
	return sub;
    }

    if (actual_mech_type)
	*actual_mech_type = ctx->negotiated_mech_type;
    if (ret_flags)
	*ret_flags = ctx->mech_flags;
    if (time_rec)
	*time_rec = ctx->mech_time_rec;

    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);

    *context_handle = context;

    return GSS_S_CONTINUE_NEEDED;
}
Beispiel #3
0
/*
 * We only support those mechanisms that we know about (ie ones that we know
 * how to check local user kuserok and the like)
 */
static int
userauth_gssapi(Authctxt *authctxt)
{
	gss_OID_desc goid = {0, NULL};
	Gssctxt *ctxt = NULL;
	int mechs;
	int present;
	OM_uint32 ms;
	u_int len;
	u_char *doid = NULL;

	if (!authctxt->valid || authctxt->user == NULL)
		return (0);

	mechs = packet_get_int();
	if (mechs == 0) {
		debug("Mechanism negotiation is not supported");
		return (0);
	}

	do {
		mechs--;

		free(doid);

		present = 0;
		doid = packet_get_string(&len);

		if (len > 2 && doid[0] == SSH_GSS_OIDTYPE &&
		    doid[1] == len - 2) {
			goid.elements = doid + 2;
			goid.length   = len - 2;
			ssh_gssapi_test_oid_supported(&ms, &goid, &present);
		} else {
			logit("Badly formed OID received");
		}
	} while (mechs > 0 && !present);

	if (!present) {
		free(doid);
		authctxt->server_caused_failure = 1;
		return (0);
	}

	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
		if (ctxt != NULL)
			ssh_gssapi_delete_ctx(&ctxt);
		free(doid);
		authctxt->server_caused_failure = 1;
		return (0);
	}

	authctxt->methoddata = (void *)ctxt;

	packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);

	/* Return the OID that we received */
	packet_put_string(doid, len);

	packet_send();
	free(doid);

	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
	authctxt->postponed = 1;

	return (0);
}
Beispiel #4
0
int
gfarmGssInitiateSecurityContext(int fd, const gss_name_t acceptorName,
    gss_cred_id_t cred, OM_uint32 reqFlag, gss_ctx_id_t *scPtr,
    OM_uint32 *majStatPtr, OM_uint32 *minStatPtr, gss_name_t *remoteNamePtr)
{
    OM_uint32 majStat;
    OM_uint32 minStat, minStat2;
    OM_uint32 retFlag = 0;

    gss_buffer_desc inputToken = GSS_C_EMPTY_BUFFER;
    gss_buffer_t itPtr = &inputToken;
    
    gss_buffer_desc outputToken = GSS_C_EMPTY_BUFFER;
    gss_buffer_t otPtr = &outputToken;

    gss_OID *actualMechType = NULL;
    OM_uint32 timeRet;

    int tknStat;

    static const char diag[] = "gfarmGssInitiateSecurityContext()";

    *scPtr = GSS_C_NO_CONTEXT;

    /*
     * Implementation specification:
     * In gfarm, an initiator must reveal own identity to an acceptor.
     */
    if ((reqFlag & GSS_C_ANON_FLAG) == GSS_C_ANON_FLAG) {
	/* It is a bit safer to deny the request than to silently ignore it */
	gflog_auth_error(GFARM_MSG_1000618,
	    "gfarmGssInitiateSecurityContext(): "
	    "GSS_C_ANON_FLAG is not allowed");
	majStat = GSS_S_UNAVAILABLE;
	minStat = GFSL_DEFAULT_MINOR_ERROR;
	goto Done;
    }

    while (1) {
	gfarm_mutex_lock(&gss_mutex, diag, gssDiag);
	majStat = gss_init_sec_context(&minStat,
				       cred,
				       scPtr,
				       acceptorName,
				       GSS_C_NO_OID,
				       reqFlag,
				       0,
				       GSS_C_NO_CHANNEL_BINDINGS,
				       itPtr,
				       actualMechType,
				       otPtr,
				       &retFlag,
				       &timeRet);
	gfarm_mutex_unlock(&gss_mutex, diag, gssDiag);
	
	if (itPtr->length > 0)
	    gss_release_buffer(&minStat2, itPtr);

	if (otPtr->length > 0) {
	    tknStat = gfarmGssSendToken(fd, otPtr);
	    gss_release_buffer(&minStat2, otPtr);
	    if (tknStat <= 0) {
		gflog_auth_error(GFARM_MSG_1000619,
		    "gfarmGssInitiateSecurityContext(): "
				 "failed to send response");
		majStat = GSS_S_DEFECTIVE_TOKEN|GSS_S_CALL_INACCESSIBLE_WRITE;
		minStat = GFSL_DEFAULT_MINOR_ERROR;
	    }
	}

	if (GSS_ERROR(majStat)) {
	    break;
	}
    
	if (majStat & GSS_S_CONTINUE_NEEDED) {
	    tknStat = gfarmGssReceiveToken(fd, itPtr,
					   GFARM_GSS_TIMEOUT_INFINITE);
	    if (tknStat <= 0) {
		gflog_auth_error(GFARM_MSG_1000620,
		    "gfarmGssInitiateSecurityContext(): "
				 "failed to receive response");
		majStat = GSS_S_DEFECTIVE_TOKEN|GSS_S_CALL_INACCESSIBLE_READ;
		minStat = GFSL_DEFAULT_MINOR_ERROR;
		break;
	    }
	} else {
	    break;
	}
    }

    if (itPtr->length > 0)
	gss_release_buffer(&minStat2, itPtr);

    if (majStat == GSS_S_COMPLETE && remoteNamePtr != NULL) {
	majStat = gss_inquire_context(&minStat,
				      *scPtr,
				      NULL,
				      remoteNamePtr,
				      NULL,
				      NULL,
				      NULL,
				      NULL,
				      NULL);
    }

    Done:
    if (majStatPtr != NULL)
	*majStatPtr = majStat;
    if (minStatPtr != NULL)
	*minStatPtr = minStat;

    if (majStat != GSS_S_COMPLETE && *scPtr != GSS_C_NO_CONTEXT)
	gss_delete_sec_context(&minStat2, scPtr, GSS_C_NO_BUFFER);

    return majStat == GSS_S_COMPLETE ? 1 : -1;
}
Beispiel #5
0
gss_cred_id_t read_globus_credentials(const std::string& filename) {
  Arc::Credential cred(filename, "", "", "", "", true);
  X509* cert = cred.GetCert();
  STACK_OF(X509)* cchain = cred.GetCertChain();
  EVP_PKEY* key = cred.GetPrivKey();
  globus_gsi_cred_handle_t chandle;
  globus_gsi_cred_handle_init(&chandle, NULL);
  if(cert) globus_gsi_cred_set_cert(chandle, cert);
  if(key) globus_gsi_cred_set_key(chandle, key);
  if(cchain) globus_gsi_cred_set_cert_chain(chandle, cchain);

  gss_cred_id_desc* ccred = (gss_cred_id_desc*)::malloc(sizeof(gss_cred_id_desc));
  if(ccred) {
    ::memset(ccred,0,sizeof(gss_cred_id_desc));
    ccred->cred_handle = chandle; chandle = NULL;
    // cred_usage
    // ssl_context
    X509* identity_cert = NULL;
    if(cert) {
      globus_gsi_cert_utils_cert_type_t ctype = GLOBUS_GSI_CERT_UTILS_TYPE_DEFAULT;
      globus_gsi_cert_utils_get_cert_type(cert,&ctype);
      if(ctype == GLOBUS_GSI_CERT_UTILS_TYPE_EEC) {
        identity_cert = cert;
      };
    };
    if(!identity_cert && cchain) {
      // For compatibility with older globus not using
      //globus_gsi_cert_utils_get_identity_cert(cchain,&identity_cert);
      for(int n = 0; n < sk_X509_num(cchain); ++n) {
        X509* tmp_cert = sk_X509_value(cchain, n);
        if(tmp_cert) {
          globus_gsi_cert_utils_cert_type_t ctype = GLOBUS_GSI_CERT_UTILS_TYPE_DEFAULT;
          globus_gsi_cert_utils_get_cert_type(tmp_cert,&ctype);
          if(ctype == GLOBUS_GSI_CERT_UTILS_TYPE_EEC) {
            identity_cert = tmp_cert;
            break;
          };
        };
      };
    };
    gss_buffer_desc peer_buffer;
    peer_buffer.value = identity_cert;
    peer_buffer.length = identity_cert?sizeof(X509):0;
    OM_uint32 majstat, minstat;
    majstat = gss_import_name(&minstat, &peer_buffer,
                              identity_cert?GLOBUS_GSS_C_NT_X509:GSS_C_NT_ANONYMOUS,
                              &ccred->globusid);
    if (GSS_ERROR(majstat)) {
      logger.msg(Arc::ERROR, "Failed to convert GSI credential to "
         "GSS credential (major: %d, minor: %d)", majstat, minstat);
      majstat = gss_release_cred(&minstat, &ccred);
    };
  } else {
    ccred = GSS_C_NO_CREDENTIAL;
  };
  if(cert) X509_free(cert);
  if(key) EVP_PKEY_free(key);
  if(cchain) sk_X509_pop_free(cchain, X509_free);
  if(chandle) globus_gsi_cred_handle_destroy(chandle);
  return ccred;
}
Beispiel #6
0
/* returning zero (0) means success, everything else is treated as "failure"
   with no care exactly what the failure was */
int Curl_input_negotiate(struct connectdata *conn, bool proxy,
                         const char *header)
{
  struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
    &conn->data->state.negotiate;
  OM_uint32 major_status, minor_status, minor_status2;
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  int ret;
  size_t len, rawlen;
  bool gss;
  const char* protocol;

  while(*header && ISSPACE(*header))
    header++;
  if(checkprefix("GSS-Negotiate", header)) {
    protocol = "GSS-Negotiate";
    gss = TRUE;
  }
  else if(checkprefix("Negotiate", header)) {
    protocol = "Negotiate";
    gss = FALSE;
  }
  else
    return -1;

  if(neg_ctx->context) {
    if(neg_ctx->gss != gss) {
      return -1;
    }
  }
  else {
    neg_ctx->protocol = protocol;
    neg_ctx->gss = gss;
  }

  if(neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) {
    /* We finished successfully our part of authentication, but server
     * rejected it (since we're again here). Exit with an error since we
     * can't invent anything better */
    Curl_cleanup_negotiate(conn->data);
    return -1;
  }

  if(neg_ctx->server_name == NULL &&
      (ret = get_gss_name(conn, proxy, &neg_ctx->server_name)))
    return ret;

  header += strlen(neg_ctx->protocol);
  while(*header && ISSPACE(*header))
    header++;

  len = strlen(header);
  if(len > 0) {
    rawlen = Curl_base64_decode(header,
                                (unsigned char **)&input_token.value);
    if(rawlen == 0)
      return -1;
    input_token.length = rawlen;

#ifdef HAVE_SPNEGO /* Handle SPNEGO */
    if(checkprefix("Negotiate", header)) {
      ASN1_OBJECT *   object            = NULL;
      int             rc                = 1;
      unsigned char * spnegoToken       = NULL;
      size_t          spnegoTokenLength = 0;
      unsigned char * mechToken         = NULL;
      size_t          mechTokenLength   = 0;

      if(input_token.value == NULL)
        return CURLE_OUT_OF_MEMORY;

      spnegoToken = malloc(input_token.length);
      if(spnegoToken == NULL)
        return CURLE_OUT_OF_MEMORY;

      spnegoTokenLength = input_token.length;

      object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1);
      if(!parseSpnegoTargetToken(spnegoToken,
                                 spnegoTokenLength,
                                 NULL,
                                 NULL,
                                 &mechToken,
                                 &mechTokenLength,
                                 NULL,
                                 NULL)) {
        free(spnegoToken);
        spnegoToken = NULL;
        infof(conn->data, "Parse SPNEGO Target Token failed\n");
      }
      else {
        free(input_token.value);
        input_token.value = malloc(mechTokenLength);
        if(input_token.value == NULL)
          return CURLE_OUT_OF_MEMORY;

        memcpy(input_token.value, mechToken,mechTokenLength);
        input_token.length = mechTokenLength;
        free(mechToken);
        mechToken = NULL;
        infof(conn->data, "Parse SPNEGO Target Token succeeded\n");
      }
    }
#endif
  }

  major_status = Curl_gss_init_sec_context(&minor_status,
                                           &neg_ctx->context,
                                           neg_ctx->server_name,
                                           GSS_C_NO_CHANNEL_BINDINGS,
                                           &input_token,
                                           &output_token,
                                           NULL);
  if(input_token.length > 0)
    gss_release_buffer(&minor_status2, &input_token);
  neg_ctx->status = major_status;
  if(GSS_ERROR(major_status)) {
    /* Curl_cleanup_negotiate(conn->data) ??? */
    log_gss_error(conn, minor_status,
                  "gss_init_sec_context() failed: ");
    return -1;
  }

  if(output_token.length == 0) {
    return -1;
  }

  neg_ctx->output_token = output_token;
  /* conn->bits.close = FALSE; */

  return 0;
}
Beispiel #7
0
struct gfarmGssInitiateSecurityContextState *
gfarmGssInitiateSecurityContextRequest(struct gfarm_eventqueue *q, int fd,
    const gss_name_t acceptorName, gss_cred_id_t cred, OM_uint32 reqFlag,
    void (*continuation) (void *), void *closure, OM_uint32 *majStatPtr,
    OM_uint32 *minStatPtr)
{
    OM_uint32 majStat;
    OM_uint32 minStat;
    struct gfarmGssInitiateSecurityContextState *state;

    /*
     * Implementation specification:
     * In gfarm, an initiator must reveal own identity to an acceptor.
     */
    if ((reqFlag & GSS_C_ANON_FLAG) == GSS_C_ANON_FLAG) {
	/* It is a bit safer to deny the request than to silently ignore it */
	gflog_auth_error(GFARM_MSG_1000625,
	    "gfarmGssInitiateSecurityContextRequest(): "
	    "GSS_C_ANON_FLAG is not allowed");
	majStat = GSS_S_UNAVAILABLE;
	minStat = GFSL_DEFAULT_MINOR_ERROR;
	goto ReturnStat;
    }

    GFARM_MALLOC(state);
    if (state == NULL) {
	gflog_auth_error(GFARM_MSG_1000626,
	    "gfarmGssInitiateSecurityContextRequest(): "
			 "no memory");
	majStat = GSS_S_FAILURE;
	minStat = GFSL_DEFAULT_MINOR_ERROR;
	goto ReturnStat;
    }

    state->completed = 0;
    state->majStat = GSS_S_COMPLETE;
    state->minStat = GFSL_DEFAULT_MINOR_ERROR;

    state->writable =
	gfarm_fd_event_alloc(GFARM_EVENT_WRITE, fd,
			     gfarmGssInitiateSecurityContextSendToken,
			     state);
    if (state->writable == NULL) {
	gflog_auth_error(GFARM_MSG_1000627,
	    "gfarmGssInitiateSecurityContextRequest(): "
			 "no memory");
	state->majStat = GSS_S_FAILURE;
	goto FreeState;
    }
    /*
     * We cannot use two independent events (i.e. a fd_event with
     * GFARM_EVENT_READ flag and a timer_event) here, because
     * it's possible that both event handlers are called at once.
     */
    state->readable =
	gfarm_fd_event_alloc(GFARM_EVENT_READ|GFARM_EVENT_TIMEOUT, fd,
			     gfarmGssInitiateSecurityContextReceiveToken,
			     state);
    if (state->readable == NULL) {
	gflog_auth_error(GFARM_MSG_1000628,
	    "gfarmGssInitiateSecurityContextRequest(): "
			 "no memory");
	state->majStat = GSS_S_FAILURE;
	goto FreeWritable;
    }

    state->q = q;
    state->fd = fd;
    state->acceptorName = acceptorName;
    state->cred = cred;
    state->reqFlag = reqFlag;
    state->continuation = continuation;
    state->closure = closure;

    state->retFlag = 0;

    /* GSS_C_EMPTY_BUFFER */
    state->inputToken.length = 0; state->inputToken.value = NULL;
    state->itPtr = &state->inputToken;

    /* GSS_C_EMPTY_BUFFER */
    state->outputToken.length = 0; state->outputToken.value = NULL;
    state->otPtr = &state->outputToken;

    state->actualMechType = NULL;

    state->sc = GSS_C_NO_CONTEXT;

    gssInitiateSecurityContextNext(state);
    assert(!state->completed);
    if (!GSS_ERROR(state->majStat)) {
	if (majStatPtr != NULL) {
	    *majStatPtr = GSS_S_COMPLETE;
	}
	if (minStatPtr != NULL) {
	    *minStatPtr = GFSL_DEFAULT_MINOR_ERROR;
	}
	return (state);
    }

    gfarm_event_free(state->readable);

    FreeWritable:
    gfarm_event_free(state->writable);

    FreeState:
    majStat = state->majStat;
    minStat = state->minStat;
    free(state);

    ReturnStat:
    if (majStatPtr != NULL)
	*majStatPtr = majStat;
    if (minStatPtr != NULL)
	*minStatPtr = minStat;

    if (GSS_ERROR(majStat)) {
	gflog_debug(GFARM_MSG_1000801,
		"failed to request initiate security context (%u)(%u)",
		 majStat, minStat);
    }

    return (NULL);
}
Beispiel #8
0
OM_uint32
kg_compose_deleg_cred(OM_uint32 *minor_status,
                      krb5_gss_cred_id_t impersonator_cred,
                      krb5_creds *subject_creds,
                      OM_uint32 time_req,
                      krb5_gss_cred_id_t *output_cred,
                      OM_uint32 *time_rec,
                      krb5_context context)
{
    OM_uint32 major_status;
    krb5_error_code code;
    krb5_gss_cred_id_t cred = NULL;

    *output_cred = NULL;
    k5_mutex_assert_locked(&impersonator_cred->lock);

    if (!kg_is_initiator_cred(impersonator_cred) ||
        impersonator_cred->name == NULL ||
        impersonator_cred->impersonator != NULL) {
        code = G_BAD_USAGE;
        goto cleanup;
    }

    assert(impersonator_cred->name->princ != NULL);

    assert(subject_creds != NULL);
    assert(subject_creds->client != NULL);

    cred = xmalloc(sizeof(*cred));
    if (cred == NULL) {
        code = ENOMEM;
        goto cleanup;
    }
    memset(cred, 0, sizeof(*cred));

    code = k5_mutex_init(&cred->lock);
    if (code != 0)
        goto cleanup;

    cred->usage = GSS_C_INITIATE;

    cred->expire = subject_creds->times.endtime;

    code = kg_init_name(context, subject_creds->client, NULL, NULL, NULL, 0,
                        &cred->name);
    if (code != 0)
        goto cleanup;

    code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache);
    if (code != 0)
        goto cleanup;
    cred->destroy_ccache = 1;

    code = krb5_cc_initialize(context, cred->ccache, subject_creds->client);
    if (code != 0)
        goto cleanup;

    /*
     * Only return a "proxy" credential for use with constrained
     * delegation if the subject credentials are forwardable.
     * Submitting non-forwardable credentials to the KDC for use
     * with constrained delegation will only return an error.
     */
    if (subject_creds->ticket_flags & TKT_FLG_FORWARDABLE) {
        code = make_proxy_cred(context, cred, impersonator_cred);
        if (code != 0)
            goto cleanup;
    }

    code = krb5_cc_store_cred(context, cred->ccache, subject_creds);
    if (code != 0)
        goto cleanup;

    if (time_rec != NULL) {
        krb5_timestamp now;

        code = krb5_timeofday(context, &now);
        if (code != 0)
            goto cleanup;

        *time_rec = cred->expire - now;
    }

    major_status = GSS_S_COMPLETE;
    *minor_status = 0;
    *output_cred = cred;

cleanup:
    if (code != 0) {
        *minor_status = code;
        major_status = GSS_S_FAILURE;
    }

    if (GSS_ERROR(major_status) && cred != NULL) {
        k5_mutex_destroy(&cred->lock);
        krb5_cc_destroy(context, cred->ccache);
        kg_release_name(context, &cred->name);
        xfree(cred);
    }

    return major_status;
}
Beispiel #9
0
/*
 * Curl_auth_create_gssapi_security_message()
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) security
 * token message ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg64  [in]     - Pointer to the optional base64 encoded challenge message.
 * krb5    [in/out] - The Kerberos 5 data struct being used and modified.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_gssapi_security_message(struct SessionHandle *data,
                                                  const char *chlg64,
                                                  struct kerberos5data *krb5,
                                                  char **outptr,
                                                  size_t *outlen)
{
  CURLcode result = CURLE_OK;
  size_t chlglen = 0;
  size_t messagelen = 0;
  unsigned char *chlg = NULL;
  unsigned char *message = NULL;
  OM_uint32 gss_status;
  OM_uint32 gss_major_status;
  OM_uint32 gss_minor_status;
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  unsigned int indata = 0;
  unsigned int outdata = 0;
  gss_qop_t qop = GSS_C_QOP_DEFAULT;
  unsigned int sec_layer = 0;
  unsigned int max_size = 0;
  gss_name_t username = GSS_C_NO_NAME;
  gss_buffer_desc username_token;

  /* Decode the base-64 encoded input message */
  if(strlen(chlg64) && *chlg64 != '=') {
    result = Curl_base64_decode(chlg64, &chlg, &chlglen);
    if(result)
      return result;
  }

  /* Ensure we have a valid challenge message */
  if(!chlg) {
    infof(data, "GSSAPI handshake failure (empty security message)\n");

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Get the fully qualified username back from the context */
  gss_major_status = gss_inquire_context(&gss_minor_status, krb5->context,
                                         &username, NULL, NULL, NULL, NULL,
                                         NULL, NULL);
  if(GSS_ERROR(gss_major_status)) {
    Curl_gss_log_error(data, "gss_inquire_context() failed: ",
                       gss_major_status, gss_minor_status);

    free(chlg);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Convert the username from internal format to a displayable token */
  gss_major_status = gss_display_name(&gss_minor_status, username,
                                      &username_token, NULL);
  if(GSS_ERROR(gss_major_status)) {
    Curl_gss_log_error(data, "gss_display_name() failed: ",
                       gss_major_status, gss_minor_status);

    free(chlg);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Setup the challenge "input" security buffer */
  input_token.value = chlg;
  input_token.length = chlglen;

  /* Decrypt the inbound challenge and obtain the qop */
  gss_major_status = gss_unwrap(&gss_minor_status, krb5->context, &input_token,
                                &output_token, NULL, &qop);
  if(GSS_ERROR(gss_major_status)) {
    Curl_gss_log_error(data, "gss_unwrap() failed: ",
                       gss_major_status, gss_minor_status);

    gss_release_buffer(&gss_status, &username_token);
    free(chlg);

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
  if(output_token.length != 4) {
    infof(data, "GSSAPI handshake failure (invalid security data)\n");

    gss_release_buffer(&gss_status, &username_token);
    free(chlg);

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Copy the data out and free the challenge as it is not required anymore */
  memcpy(&indata, output_token.value, 4);
  gss_release_buffer(&gss_status, &output_token);
  free(chlg);

  /* Extract the security layer */
  sec_layer = indata & 0x000000FF;
  if(!(sec_layer & GSSAUTH_P_NONE)) {
    infof(data, "GSSAPI handshake failure (invalid security layer)\n");

    gss_release_buffer(&gss_status, &username_token);

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Extract the maximum message size the server can receive */
  max_size = ntohl(indata & 0xFFFFFF00);
  if(max_size > 0) {
    /* The server has told us it supports a maximum receive buffer, however, as
       we don't require one unless we are encrypting data, we tell the server
       our receive buffer is zero. */
    max_size = 0;
  }

  /* Allocate our message */
  messagelen = sizeof(outdata) + username_token.length + 1;
  message = malloc(messagelen);
  if(!message) {
    gss_release_buffer(&gss_status, &username_token);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Populate the message with the security layer, client supported receive
     message size and authorization identity including the 0x00 based
     terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization
     identity is not terminated with the zero-valued (%x00) octet." it seems
     necessary to include it. */
  outdata = htonl(max_size) | sec_layer;
  memcpy(message, &outdata, sizeof(outdata));
  memcpy(message + sizeof(outdata), username_token.value,
         username_token.length);
  message[messagelen - 1] = '\0';

  /* Free the username token as it is not required anymore */
  gss_release_buffer(&gss_status, &username_token);

  /* Setup the "authentication data" security buffer */
  input_token.value = message;
  input_token.length = messagelen;

  /* Encrypt the data */
  gss_major_status = gss_wrap(&gss_minor_status, krb5->context, 0,
                              GSS_C_QOP_DEFAULT, &input_token, NULL,
                              &output_token);
  if(GSS_ERROR(gss_major_status)) {
    Curl_gss_log_error(data, "gss_wrap() failed: ",
                       gss_major_status, gss_minor_status);

    free(message);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Base64 encode the response */
  result = Curl_base64_encode(data, (char *) output_token.value,
                              output_token.length, outptr, outlen);

  /* Free the output buffer */
  gss_release_buffer(&gss_status, &output_token);

  /* Free the message buffer */
  free(message);

  return result;
}
Beispiel #10
0
int gsscon_passive_authenticate (int	            inSocket, 
				 gss_buffer_desc    inNameBuffer,
				 gss_ctx_id_t      *outGSSContext,
				 client_cb_fn       clientCb,
				 void              *clientCbData)
{
    int err = 0;
    OM_uint32 majorStatus;
    OM_uint32 minorStatus = 0, minorStatusToo = 0;
    gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
    gss_name_t clientName = GSS_C_NO_NAME, serviceName = GSS_C_NO_NAME;
    gss_cred_id_t acceptorCredentials = NULL;
    gss_buffer_desc clientDisplayName = {0, NULL};
    char *inputTokenBuffer = NULL;
    size_t inputTokenBufferLength = 0;
    gss_buffer_desc inputToken;  /* buffer received from the server */
    
    printf("In gsscon_passive_authenticate(), inNameBuffer = %s\n", inNameBuffer.value);

    if (inSocket <  0 ) { err = EINVAL; }
    if (!outGSSContext) { err = EINVAL; }

    if (!err)
      majorStatus = gss_import_name (&minorStatus, &inNameBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &serviceName); 
    if (majorStatus != GSS_S_COMPLETE) {
	gsscon_print_gss_errors ("gss_import_name(serviceName)", majorStatus, minorStatus);
	err = minorStatus ? minorStatus : majorStatus; 
      }

    if (!err) {
      majorStatus = gss_acquire_cred ( &minorStatus, serviceName,
				       GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
				       GSS_C_ACCEPT, &acceptorCredentials,
				       NULL /*mechs out*/, NULL /*time out*/);
      if (majorStatus != GSS_S_COMPLETE) { 
	gsscon_print_gss_errors ("gss_acquire_cred", majorStatus, minorStatus);
	err = minorStatus ? minorStatus : majorStatus; 
      }
    }

    /* 
     * The main authentication loop:
     *
     * GSS is a multimechanism API.  The number of packet exchanges required to  
     * authenticatevaries between mechanisms.  As a result, we need to loop reading 
     * input tokens from the client, calling gss_accept_sec_context on the input 
     * tokens and send the resulting output tokens back to the client until we 
     * get GSS_S_COMPLETE or an error.
     *
     * When we are done, save the client principal so we can make authorization 
     * checks.
     */
    
    majorStatus = GSS_S_CONTINUE_NEEDED;
    while (!err && (majorStatus != GSS_S_COMPLETE)) {
        /* Clean up old input buffer */
        if (inputTokenBuffer != NULL) {
            free (inputTokenBuffer);
            inputTokenBuffer = NULL;  /* don't double-free */
        }
        
        err = gsscon_read_token (inSocket, &inputTokenBuffer, &inputTokenBufferLength);
        
        if (!err) {
            /* Set up input buffers for the next run through the loop */
            inputToken.value = inputTokenBuffer;
            inputToken.length = inputTokenBufferLength;
        }
        
        if (!err) {
            /* buffer to send to the server */
            gss_buffer_desc outputToken = { 0, NULL }; 
            
            /*
             * accept_sec_context does the actual work of taking the client's 
             * request and generating an appropriate reply.              */
            majorStatus = gss_accept_sec_context (&minorStatus, 
                                                  &gssContext, 
						  acceptorCredentials,
                                                  &inputToken, 
                                                  GSS_C_NO_CHANNEL_BINDINGS, 
                                                  &clientName,
                                                  NULL /* actual_mech_type */,
                                                  &outputToken, 
                                                  NULL /* req_flags */, 
                                                  NULL /* time_rec */, 
                                                  NULL /* delegated_cred_handle */);
            
            if ((outputToken.length > 0) && (outputToken.value != NULL)) {
                /* Send the output token to the client (even on error) */
                err = gsscon_write_token (inSocket, outputToken.value, outputToken.length);
                
                /* free the output token */
                gss_release_buffer (&minorStatusToo, &outputToken);
            }
        }
        
        if ((majorStatus != GSS_S_COMPLETE) && (majorStatus != GSS_S_CONTINUE_NEEDED)) {
            gsscon_print_gss_errors ("gss_accept_sec_context", majorStatus, minorStatus);
            err = minorStatus ? minorStatus : majorStatus; 
        }            
    }

    if (!err) {
      majorStatus = gss_display_name(&minorStatus, clientName, &clientDisplayName, NULL);
      if (GSS_ERROR(majorStatus)) {
	gsscon_print_gss_errors("gss_display_name", majorStatus, minorStatus);
	err = EINVAL;
      }
      if (!err)
	err = clientCb(clientName, &clientDisplayName, clientCbData);
    }

    if (!err) { 
        *outGSSContext = gssContext;
        gssContext = NULL;
    } else {
        gsscon_print_error (err, "Authenticate failed");
    }
    
    if (inputTokenBuffer) { free (inputTokenBuffer); }
    if (gssContext != GSS_C_NO_CONTEXT) { 
        gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
if (clientName != GSS_C_NO_NAME)
  gss_release_name(&minorStatus, &clientName);
if (clientDisplayName.value != NULL)
  gss_release_buffer(&minorStatus, &clientDisplayName);
 gss_release_name( &minorStatus, &serviceName);
 gss_release_cred( &minorStatus, &acceptorCredentials);
        
    return err;
}
Beispiel #11
0
/* The mechglue always passes null desired_mechs and actual_mechs. */
OM_uint32 KRB5_CALLCONV
krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
                                       const gss_cred_id_t impersonator_cred_handle,
                                       const gss_name_t desired_name,
                                       OM_uint32 time_req,
                                       const gss_OID_set desired_mechs,
                                       gss_cred_usage_t cred_usage,
                                       gss_cred_id_t *output_cred_handle,
                                       gss_OID_set *actual_mechs,
                                       OM_uint32 *time_rec)
{
    OM_uint32 major_status;
    krb5_error_code code;
    krb5_gss_cred_id_t cred;
    krb5_context context;

    if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
        return GSS_S_CALL_INACCESSIBLE_READ;

    if (desired_name == GSS_C_NO_NAME)
        return GSS_S_CALL_INACCESSIBLE_READ;

    if (output_cred_handle == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;

    if (cred_usage != GSS_C_INITIATE) {
        *minor_status = (OM_uint32)G_BAD_USAGE;
        return GSS_S_FAILURE;
    }

    *output_cred_handle = GSS_C_NO_CREDENTIAL;
    if (time_rec != NULL)
        *time_rec = 0;

    code = krb5_gss_init_context(&context);
    if (code != 0) {
        *minor_status = code;
        return GSS_S_FAILURE;
    }

    major_status = kg_cred_resolve(minor_status, context,
                                   impersonator_cred_handle, NULL);
    if (GSS_ERROR(major_status)) {
        krb5_free_context(context);
        return major_status;
    }

    major_status = kg_impersonate_name(minor_status,
                                       (krb5_gss_cred_id_t)impersonator_cred_handle,
                                       (krb5_gss_name_t)desired_name,
                                       time_req,
                                       &cred,
                                       time_rec,
                                       context);

    if (!GSS_ERROR(major_status))
        *output_cred_handle = (gss_cred_id_t)cred;

    k5_mutex_unlock(&((krb5_gss_cred_id_t)impersonator_cred_handle)->lock);
    krb5_free_context(context);

    return major_status;

}
static OM_uint32
inquireNegoExKey(OM_uint32 *minor,
                  const gss_ctx_id_t ctx,
                  const gss_OID desired_object,
                  gss_buffer_set_t *dataSet)
{
    OM_uint32 major, tmpMinor;
    int bInitiatorKey;
    gss_buffer_desc salt;
    gss_buffer_desc key = GSS_C_EMPTY_BUFFER;
    size_t keySize;

    bInitiatorKey = CTX_IS_INITIATOR(ctx);

    if (ctx->encryptionType == ENCTYPE_NULL) {
        major = GSS_S_UNAVAILABLE;
        *minor = GSSEAP_KEY_UNAVAILABLE;
        goto cleanup;
    }

    /*
     * If the caller supplied the verify key OID, then we need the acceptor
     * key if we are the initiator, and vice versa.
     */
    if (desired_object->length == 11 &&
        memcmp(desired_object->elements,
               "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07", 11) == 0)
        bInitiatorKey ^= 1;

    if (bInitiatorKey) {
        salt.length = NEGOEX_INITIATOR_SALT_LEN;
        salt.value  = NEGOEX_INITIATOR_SALT;
    } else {
        salt.length = NEGOEX_ACCEPTOR_SALT_LEN;
        salt.value  = NEGOEX_ACCEPTOR_SALT;
    }

    keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key);

    major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt,
                               keySize, &key);
    if (GSS_ERROR(major))
        goto cleanup;

    major = gss_add_buffer_set_member(minor, &key, dataSet);
    if (GSS_ERROR(major))
        goto cleanup;

    major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
    if (GSS_ERROR(major))
        goto cleanup;

    major = GSS_S_COMPLETE;
    *minor = 0;

cleanup:
    if (key.value != NULL) {
        memset(key.value, 0, key.length);
        gss_release_buffer(&tmpMinor, &key);
    }
    if (GSS_ERROR(major))
        zeroAndReleaseBufferSet(dataSet);

    return major;
}
/*
 * Export GSI credentials to disk.
 */
static void
ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client)
{
	OM_uint32	major_status;
	OM_uint32	minor_status;
	gss_buffer_desc	export_cred = GSS_C_EMPTY_BUFFER;
	char *		p;
	
	if (!client || !client->creds) {
	    return;
	}

	major_status = gss_export_cred(&minor_status,
				       client->creds,
				       GSS_C_NO_OID,
				       1,
				       &export_cred);
	if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) {
	    Gssctxt *ctx;
	    ssh_gssapi_build_ctx(&ctx);
	    ctx->major = major_status;
	    ctx->minor = minor_status;
	    ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid);
	    ssh_gssapi_error(ctx);
	    ssh_gssapi_delete_ctx(&ctx);
	    return;
	}
	
	p = strchr((char *) export_cred.value, '=');
	if (p == NULL) {
	    logit("Failed to parse exported credentials string '%.100s'",
		(char *)export_cred.value);
	    gss_release_buffer(&minor_status, &export_cred);
	    return;
	}
	*p++ = '\0';
	if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) {
	    client->store.envvar = strdup("X509_USER_PROXY");
	} else {
	    client->store.envvar = strdup((char *)export_cred.value);
	}
	if (access(p, R_OK) == 0) {
        if (client->store.filename) {
            if (rename(p, client->store.filename) < 0) {
                logit("Failed to rename %s to %s: %s", p,
                      client->store.filename, strerror(errno));
                free(client->store.filename);
                client->store.filename = strdup(p);
            } else {
                p = client->store.filename;
            }
        } else {
            client->store.filename = strdup(p);
        }
	}
	client->store.envval = strdup(p);
#ifdef USE_PAM
	if (options.use_pam)
	    do_pam_putenv(client->store.envvar, client->store.envval);
#endif
	gss_release_buffer(&minor_status, &export_cred);
}
Beispiel #14
0
/*
 * We only support those mechanisms that we know about (ie ones that we know
 * how to check local user kuserok and the like)
 */
static int
userauth_gssapi(struct ssh *ssh)
{
	Authctxt *authctxt = ssh->authctxt;
	gss_OID_desc goid = {0, NULL};
	Gssctxt *ctxt = NULL;
	int r, mechs, present;
	gss_OID_set supported;
	OM_uint32 ms;
	size_t len;
	u_char *doid = NULL;

	if (!authctxt->valid || authctxt->user == NULL)
		return (0);

	if ((r = sshpkt_get_u32(ssh, &mechs)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));

	if (mechs == 0) {
		debug("Mechanism negotiation is not supported");
		return (0);
	}

	ssh_gssapi_supported_oids(&supported);
	do {
		mechs--;

		if (doid)
			xfree(doid);

		present = 0;
		if ((r = sshpkt_get_string(ssh, &doid, &len)) != 0)
			fatal("%s: %s", __func__, ssh_err(r));

		if (len > 2 && doid[0] == SSH_GSS_OIDTYPE &&
		    doid[1] == len - 2) {
			goid.elements = doid + 2;
			goid.length   = len - 2;
			gss_test_oid_set_member(&ms, &goid, supported,
			    &present);
		} else {
			logit("Badly formed OID received");
		}
	} while (mechs > 0 && !present);

	gss_release_oid_set(&ms, &supported);

	if (!present) {
		xfree(doid);
		authctxt->server_caused_failure = 1;
		return (0);
	}

	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
		if (ctxt != NULL)
			ssh_gssapi_delete_ctx(&ctxt);
		xfree(doid);
		authctxt->server_caused_failure = 1;
		return (0);
	}

	authctxt->methoddata = (void *)ctxt;

	/* Return the OID that we received */
	if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE)) != 0 ||
	    (r = sshpkt_put_string(ssh, doid, len)) != 0 ||
	    (r = sshpkt_send(ssh)) != 0)
		fatal("%s: %s", __func__, ssh_err(r));

	xfree(doid);

	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
	authctxt->postponed = 1;

	return (0);
}
Beispiel #15
0
static OM_uint32
gssEapDuplicateCred(OM_uint32 *minor,
                    const gss_cred_id_t src,
                    gss_cred_id_t *pDst)
{
    OM_uint32 major, tmpMinor;
    gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;

    *pDst = GSS_C_NO_CREDENTIAL;

    major = gssEapAllocCred(minor, &dst);
    if (GSS_ERROR(major))
        goto cleanup;

    dst->flags = src->flags;

    if (src->name != GSS_C_NO_NAME) {
        major = gssEapDuplicateName(minor, src->name, &dst->name);
        if (GSS_ERROR(major))
            goto cleanup;
    }

    if (src->target != GSS_C_NO_NAME) {
        major = gssEapDuplicateName(minor, src->target, &dst->target);
        if (GSS_ERROR(major))
            goto cleanup;
    }

    if (src->password.value != NULL) {
        major = duplicateBuffer(minor, &src->password, &dst->password);
        if (GSS_ERROR(major))
            goto cleanup;
    }

#ifndef MECH_EAP
    if (src->deleg_assertions.value != NULL) {
        major = duplicateBuffer(minor, &src->deleg_assertions, &dst->deleg_assertions);
        if (GSS_ERROR(major))
            goto cleanup;
    }
#endif

    major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
    if (GSS_ERROR(major))
        goto cleanup;

    dst->expiryTime = src->expiryTime;

    if (src->radiusConfigFile.value != NULL)
        duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
    if (src->radiusConfigStanza.value != NULL)
        duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
    if (src->caCertificate.value != NULL)
        duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
    if (src->subjectNameConstraint.value != NULL)
        duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
    if (src->subjectAltNameConstraint.value != NULL)
        duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);

    *pDst = dst;
    dst = GSS_C_NO_CREDENTIAL;

    major = GSS_S_COMPLETE;
    *minor = 0;

cleanup:
    gssEapReleaseCred(&tmpMinor, &dst);

    return major;
}
Beispiel #16
0
/*
 * Curl_auth_create_gssapi_user_message()
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
 * message ready for sending to the recipient.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * userp       [in]     - The user name.
 * passdwp     [in]     - The user's password.
 * service     [in]     - The service type such as www, smtp, pop or imap.
 * mutual_auth [in]     - Flag specifing whether or not mutual authentication
 *                        is enabled.
 * chlg64      [in]     - Pointer to the optional base64 encoded challenge
 *                        message.
 * krb5        [in/out] - The Kerberos 5 data struct being used and modified.
 * outptr      [in/out] - The address where a pointer to newly allocated memory
 *                        holding the result will be stored upon completion.
 * outlen      [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data,
                                              const char *userp,
                                              const char *passwdp,
                                              const char *service,
                                              const bool mutual_auth,
                                              const char *chlg64,
                                              struct kerberos5data *krb5,
                                              char **outptr, size_t *outlen)
{
  CURLcode result = CURLE_OK;
  size_t chlglen = 0;
  unsigned char *chlg = NULL;
  OM_uint32 gss_status;
  OM_uint32 gss_major_status;
  OM_uint32 gss_minor_status;
  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;

  (void) userp;
  (void) passwdp;

  if(krb5->context == GSS_C_NO_CONTEXT) {
    /* Generate our SPN */
    char *spn = Curl_auth_build_gssapi_spn(service,
                                           data->easy_conn->host.name);
    if(!spn)
      return CURLE_OUT_OF_MEMORY;

    /* Populate the SPN structure */
    spn_token.value = spn;
    spn_token.length = strlen(spn);

    /* Import the SPN */
    gss_major_status = gss_import_name(&gss_minor_status, &spn_token,
                                       GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn);
    if(GSS_ERROR(gss_major_status)) {
      Curl_gss_log_error(data, "gss_import_name() failed: ",
                         gss_major_status, gss_minor_status);

      free(spn);

      return CURLE_OUT_OF_MEMORY;
    }

    free(spn);
  }
  else {
    /* Decode the base-64 encoded challenge message */
    if(strlen(chlg64) && *chlg64 != '=') {
      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
      if(result)
        return result;
    }

    /* Ensure we have a valid challenge message */
    if(!chlg) {
      infof(data, "GSSAPI handshake failure (empty challenge message)\n");

      return CURLE_BAD_CONTENT_ENCODING;
    }

    /* Setup the challenge "input" security buffer */
    input_token.value = chlg;
    input_token.length = chlglen;
  }

  gss_major_status = Curl_gss_init_sec_context(data,
                                               &gss_minor_status,
                                               &krb5->context,
                                               krb5->spn,
                                               &Curl_krb5_mech_oid,
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               &input_token,
                                               &output_token,
                                               mutual_auth,
                                               NULL);

  free(input_token.value);

  if(GSS_ERROR(gss_major_status)) {
    if(output_token.value)
      gss_release_buffer(&gss_status, &output_token);

    Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
                       gss_major_status, gss_minor_status);

    return CURLE_RECV_ERROR;
  }

  if(output_token.value && output_token.length) {
    /* Base64 encode the response */
    result = Curl_base64_encode(data, (char *) output_token.value,
                                output_token.length, outptr, outlen);

    gss_release_buffer(&gss_status, &output_token);
  }

  return result;
}
Beispiel #17
0
OM_uint32
gssEapResolveInitiatorCred(OM_uint32 *minor,
                           const gss_cred_id_t cred,
                           const gss_name_t targetName
#ifndef HAVE_MOONSHOT_GET_IDENTITY
                                                       GSSEAP_UNUSED
#endif
                           ,
                           gss_cred_id_t *pResolvedCred)
{
    OM_uint32 major, tmpMinor;
    gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;

    if (cred == GSS_C_NO_CREDENTIAL) {
        major = gssEapAcquireCred(minor,
                                  GSS_C_NO_NAME,
                                  GSS_C_INDEFINITE,
                                  GSS_C_NO_OID_SET,
                                  GSS_C_INITIATE,
                                  &resolvedCred,
                                  NULL,
                                  NULL);
        if (GSS_ERROR(major))
            goto cleanup;
    } else {
        if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
            major = GSS_S_NO_CRED;
            *minor = GSSEAP_CRED_USAGE_MISMATCH;
            goto cleanup;
        }

        major = gssEapDuplicateCred(minor, cred, &resolvedCred);
        if (GSS_ERROR(major))
            goto cleanup;
    }

    if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
#ifdef HAVE_MOONSHOT_GET_IDENTITY
        major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
        if (major == GSS_S_CRED_UNAVAIL)
#endif
            major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
        if (GSS_ERROR(major) && major != GSS_S_CRED_UNAVAIL)
            goto cleanup;

        /* If we have a caller-supplied password, the credential is resolved. */
        if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) {
            major = GSS_S_CRED_UNAVAIL;
            *minor = GSSEAP_NO_DEFAULT_CRED;
            goto cleanup;
        }

        resolvedCred->flags |= CRED_FLAG_RESOLVED;
    }

    *pResolvedCred = resolvedCred;
    resolvedCred = GSS_C_NO_CREDENTIAL;

    major = GSS_S_COMPLETE;
    *minor = 0;

cleanup:
    gssEapReleaseCred(&tmpMinor, &resolvedCred);

    return major;
}
Beispiel #18
0
/*
 * Establish a secure context using the GSS-API.  A handshake is attempted in
 * order to detect a non-authenticating server.  The server IP address is obtained
 * from the socket and is used to perform an fqdn lookup in case a DNS alias is
 * used as a host spec, this ensures we authenticate against the correct server.
 * We attempt to extract the server principal name, a service, from the
 * environment, if it is not specified we use "host/" as a default.
 *
 * @pram to_net_sd.	Socket to write to.
 *
 * @pram from_net_sd.	Socket to read from.
 *
 * @param req_flags.	A representation of the security services to
 *			be requested.
 *
 * @param ret_flags.    A representation of the security services
 *			provided/supported by the underlying mechanism
 *			to be returned to the invoking function.
 *
 * Returns 0 on success, otherwise error.
 */
static int dcc_gssapi_establish_secure_context(int to_net_sd,
					       int from_net_sd,
					       OM_uint32 req_flags,
					       OM_uint32 *ret_flags) {
    char *ext_princ_name = NULL;
    char *full_name = NULL;
    char *princ_env_val = NULL;
    gss_buffer_desc input_tok = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc name_buffer = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output_tok = GSS_C_EMPTY_BUFFER;
    gss_name_t int_serv_name;
    gss_OID name_type;
    int ret;
    OM_uint32 major_status, minor_status, return_status;
    socklen_t addr_len;
    struct hostent *hp;
    struct sockaddr_in addr;

    addr_len = sizeof(addr);

    if ((ret = getpeername(to_net_sd, &addr, &addr_len)) != 0) {
        rs_log_error("Failed to look up peer address using socket \"%d\": %s.",
                     to_net_sd,
                     hstrerror(h_errno));
        return EXIT_CONNECT_FAILED;
    }

    rs_log_info("Successfully looked up IP address %s using socket %d.",
                                                inet_ntoa(addr.sin_addr),
                                                to_net_sd);

    if ((hp = gethostbyaddr((char *) &addr.sin_addr,
                            sizeof(addr.sin_addr),
                            AF_INET)) == NULL) {
        rs_log_error("Failed to look up host by address \"%s\": %s.",
                     inet_ntoa(addr.sin_addr),
                     hstrerror(h_errno));
        return EXIT_CONNECT_FAILED;
    }

    rs_log_info("Successfully looked up host %s using IP address %s.",
                                                hp->h_name,
                                                inet_ntoa(addr.sin_addr));

    if ((full_name = malloc(strlen(hp->h_name) + 1)) == NULL) {
        rs_log_error("malloc failed : %ld bytes: out of memory.",
                                        (long) (strlen(hp->h_name) + 1));
        return EXIT_OUT_OF_MEMORY;
    }

    strcpy(full_name, hp->h_name);

    if ((princ_env_val = getenv("DISTCC_PRINCIPAL"))) {
        if (asprintf(&ext_princ_name, "%s@%s", princ_env_val, full_name) < 0) {
            rs_log_error("Failed to allocate memory for asprintf.");
            return EXIT_OUT_OF_MEMORY;
        }

        name_type = GSS_C_NT_HOSTBASED_SERVICE;
    } else {
        if (asprintf(&ext_princ_name, "host/%s", full_name) < 0) {
            rs_log_error("Failed to allocate memory for asprintf.");
            return EXIT_OUT_OF_MEMORY;
        }

        name_type = GSS_C_NT_USER_NAME;
    }

    free(full_name);
    name_buffer.value = ext_princ_name;
    name_buffer.length = strlen(ext_princ_name);

    if ((major_status = gss_import_name(&minor_status,
				       &name_buffer,
				       name_type,
				       &int_serv_name)) != GSS_S_COMPLETE) {
	rs_log_error("Failed to import service name to internal GSS-API format.");
        return EXIT_GSSAPI_FAILED;
    }

    input_tok.value = NULL;
    input_tok.length = 0;
    output_tok.value = NULL;
    output_tok.length = 0;

    if ((ret = dcc_gssapi_send_handshake(to_net_sd, from_net_sd)) != 0) {
        return ret;
    }

    do
    {
        major_status = gss_init_sec_context(&minor_status,
					    GSS_C_NO_CREDENTIAL,
					    &distcc_ctx_handle,
					    int_serv_name,
					    GSS_C_NO_OID,
					    req_flags,
					    0,
					    GSS_C_NO_CHANNEL_BINDINGS,
					    &input_tok,
					    NULL,
					    &output_tok,
					    ret_flags,
					    NULL);

	if (GSS_ERROR(major_status)) {
	    rs_log_crit("Failed to initiate a secure context.");
	    dcc_gssapi_status_to_log(major_status, GSS_C_GSS_CODE);
	    dcc_gssapi_status_to_log(minor_status, GSS_C_MECH_CODE);
	    return EXIT_GSSAPI_FAILED;
	}

	if (output_tok.length > 0) {
	    if ((ret = send_token(to_net_sd, &output_tok)) != 0) {
		dcc_gssapi_cleanup(&input_tok, &output_tok, &int_serv_name);
		return ret;
	    } else {
		if ((return_status = gss_release_buffer(&minor_status,
						 &output_tok)) != GSS_S_COMPLETE) {
		    rs_log_error("Failed to release buffer.");
		}
	    }
	}

	if (input_tok.length > 0) {
	    if ((return_status = gss_release_buffer(&minor_status,
						   &input_tok)) != GSS_S_COMPLETE) {
		rs_log_error("Failed to release buffer.");
	    }
	}

	if (major_status == GSS_S_CONTINUE_NEEDED) {
	    if ((ret = recv_token(from_net_sd, &input_tok)) != 0) {
		dcc_gssapi_cleanup(&input_tok, &output_tok, &int_serv_name);
		return ret;
	    }
	}

    } while (major_status != GSS_S_COMPLETE);

    rs_log_info("Successfully authenticated %s.", ext_princ_name);
    dcc_gssapi_cleanup(&input_tok, &output_tok, &int_serv_name);

    if ((major_status = gss_release_buffer(&minor_status,
					  &name_buffer)) != GSS_S_COMPLETE) {
	rs_log_error("Failed to release buffer.");
    }

    return 0;
}
/**
 *
 * GSSAPI routine to initiate the sending of a security context
 * See: <draft-ietf-cat-gssv2-cbind-04.txt>
 *
 * @param minor_status
 * @param context_handle
 * @param option
 * @param value
 *
 * @return
 */
OM_uint32
GSS_CALLCONV gss_set_sec_context_option(
    OM_uint32 *                         minor_status,
    gss_ctx_id_t *                      context_handle,
    const gss_OID                       option,
    const gss_buffer_t                  value)
{
    gss_ctx_id_desc *                   context = NULL;
    OM_uint32                           major_status = GSS_S_COMPLETE;
    OM_uint32                           local_minor_status;
    globus_result_t                     local_result = GLOBUS_SUCCESS;
    int                                 index;
    static char *                       _function_name_ =
        "gss_set_sec_context_option";
    GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER;
    
    if(minor_status == NULL)
    {
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    *minor_status = (OM_uint32) GLOBUS_SUCCESS;
    
    if(context_handle == NULL)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Invalid context_handle passed to function - cannot be NULL")));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    context = *context_handle;

    if(option == GSS_C_NO_OID)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
            (_GGSL("Invalid option passed to function with value: GSS_C_NO_OID")));
        major_status = GSS_S_FAILURE;
        goto exit;
    }
    
    if ((*context_handle == (gss_ctx_id_t) GSS_C_NO_CONTEXT))
    {
        /* for now just malloc and zero the context */
        context = (gss_ctx_id_desc *) malloc(sizeof(gss_ctx_id_desc));
        if (context == NULL)
        {
            GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
            major_status = GSS_S_FAILURE;
            goto exit;
        }

        *context_handle = context;
        memset(context, 0, sizeof(gss_ctx_id_desc));
        context->ctx_flags = 0;

        major_status = gss_create_empty_oid_set(
            &local_minor_status,
            (gss_OID_set *) &context->extension_oids);

        /* initialize the callback_data in the context.  This needs
         * to be done so the verify_callback func can be set later.
         */
        local_result = globus_gsi_callback_data_init(
            &context->callback_data);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_RESULT(
                minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT,
                (_GGSL("The callback data in the context "
                 "could not be initialized.")));
            major_status = GSS_S_FAILURE;
            goto exit;
        }
    }
    else if(context->ctx_flags & GSS_I_CTX_INITIALIZED)
    {
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT,
            (_GGSL("The context has already been initialized!  %s should be "
             "called on a context before initialization"), _function_name_));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    if(g_OID_equal(option, GSS_DISALLOW_ENCRYPTION))
    {
        context->ctx_flags |= GSS_I_DISALLOW_ENCRYPTION;
    }
    else if(g_OID_equal(option, GSS_PROTECTION_FAIL_ON_CONTEXT_EXPIRATION))
    {
        context->ctx_flags |= GSS_I_PROTECTION_FAIL_ON_CONTEXT_EXPIRATION;
    }
    else if(g_OID_equal(option, GSS_APPLICATION_WILL_HANDLE_EXTENSIONS))
    {
        if(value == GSS_C_NO_BUFFER)
        {
            GLOBUS_GSI_GSSAPI_ERROR_RESULT(
                minor_status,
                GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
                (_GGSL("Invalid buffer passed to function")));
            major_status = GSS_S_FAILURE;
            goto exit;
        }

        for(index = 0; 
            index < ((gss_OID_set_desc *) value->value)->count; 
            index++)
        {
            major_status = gss_add_oid_set_member(
                &local_minor_status,
                (gss_OID) 
                &((gss_OID_set_desc *) value->value)->elements[index],
                (gss_OID_set *) &context->extension_oids);

            if(GSS_ERROR(major_status))
            {
                GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                    minor_status, local_minor_status,
                    GLOBUS_GSI_GSSAPI_ERROR_WITH_OID);
                goto exit;
            }
        }

        local_result = globus_gsi_callback_set_extension_cb(
            context->callback_data,
            globus_i_gsi_gss_verify_extensions_callback);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_CALLBACK_DATA);
            major_status = GSS_S_FAILURE;
            goto exit;
        }

        /* if the extension_oids are set, 
         * then we set them in the callback data */
        local_result = globus_gsi_callback_set_extension_oids(
            context->callback_data,
            (void *) context->extension_oids);
        if(local_result != GLOBUS_SUCCESS)
        {
            GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
                minor_status, local_result,
                GLOBUS_GSI_GSSAPI_ERROR_WITH_CALLBACK_DATA);
            major_status = GSS_S_FAILURE;
            goto exit;
        }

        context->ctx_flags |= GSS_I_APPLICATION_WILL_HANDLE_EXTENSIONS;
    }
    else
    {
        /* unknown option */
        GLOBUS_GSI_GSSAPI_ERROR_RESULT(
            minor_status,
            GLOBUS_GSI_GSSAPI_ERROR_UNKNOWN_OPTION,
            (NULL));
        major_status = GSS_S_FAILURE;
        goto exit;
    }

    *context_handle = context;

 exit:

    GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT;
    return major_status;
}
Beispiel #20
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;
}
Beispiel #21
0
int
gfarmGssAcceptSecurityContext(int fd, gss_cred_id_t cred, gss_ctx_id_t *scPtr,
    OM_uint32 *majStatPtr, OM_uint32 *minStatPtr, gss_name_t *remoteNamePtr,
    gss_cred_id_t *remoteCredPtr)
{
    OM_uint32 majStat;
    OM_uint32 minStat, minStat2;
    OM_uint32 retFlag = GFARM_GSS_DEFAULT_SECURITY_ACCEPT_FLAG;
    gss_name_t initiatorName = GSS_C_NO_NAME;
    gss_cred_id_t remCred = GSS_C_NO_CREDENTIAL;

    gss_buffer_desc inputToken = GSS_C_EMPTY_BUFFER;
    gss_buffer_t itPtr = &inputToken;
    
    gss_buffer_desc outputToken = GSS_C_EMPTY_BUFFER;
    gss_buffer_t otPtr = &outputToken;

    gss_OID mechType = GSS_C_NO_OID;
    OM_uint32 timeRet;

    int tknStat;

    static const char diag[] = "gfarmGssAcceptSecurityContext()";

    *scPtr = GSS_C_NO_CONTEXT;

    do {
	tknStat = gfarmGssReceiveToken(fd, itPtr, GFARM_GSS_TIMEOUT_INFINITE);
	if (tknStat <= 0) {
	    gflog_auth_info(GFARM_MSG_1000616,
		"gfarmGssAcceptSecurityContext(): failed to receive response");
	    majStat = GSS_S_DEFECTIVE_TOKEN|GSS_S_CALL_INACCESSIBLE_READ;
	    minStat = GFSL_DEFAULT_MINOR_ERROR;
	    break;
	}

	gfarm_mutex_lock(&gss_mutex, diag, gssDiag);
	majStat = gss_accept_sec_context(&minStat,
					 scPtr,
					 cred,
					 itPtr,
					 GSS_C_NO_CHANNEL_BINDINGS,
					 &initiatorName,
					 &mechType,
					 otPtr,
					 &retFlag,
					 &timeRet,
					 &remCred);

	gfarm_mutex_unlock(&gss_mutex, diag, gssDiag);
	if (itPtr->length > 0)
	    gss_release_buffer(&minStat2, itPtr);

	if (otPtr->length > 0) {
	    tknStat = gfarmGssSendToken(fd, otPtr);
	    gss_release_buffer(&minStat2, otPtr);
	    if (tknStat <= 0) {
		gflog_auth_info(GFARM_MSG_1000617,
		    "gfarmGssAcceptSecurityContext(): failed to send response");
		majStat = GSS_S_DEFECTIVE_TOKEN|GSS_S_CALL_INACCESSIBLE_WRITE;
		minStat = GFSL_DEFAULT_MINOR_ERROR;
	    }
	}

	if (GSS_ERROR(majStat)) {
	    break;
	}

    } while (majStat & GSS_S_CONTINUE_NEEDED);

    if (majStatPtr != NULL)
	*majStatPtr = majStat;
    if (minStatPtr != NULL)
	*minStatPtr = minStat;

    if (majStat == GSS_S_COMPLETE && remoteNamePtr != NULL)
	*remoteNamePtr = initiatorName;
    else if (initiatorName != GSS_C_NO_NAME)
	gss_release_name(&minStat2, &initiatorName);

    if (majStat == GSS_S_COMPLETE && remoteCredPtr != NULL)
	*remoteCredPtr = remCred;
    else if (remCred != GSS_C_NO_CREDENTIAL)
	gss_release_cred(&minStat2, &remCred);
    
    if (majStat != GSS_S_COMPLETE && *scPtr != GSS_C_NO_CONTEXT)
	gss_delete_sec_context(&minStat2, scPtr, GSS_C_NO_BUFFER);

    return majStat == GSS_S_COMPLETE ? 1 : -1;
}
Beispiel #22
0
/* Derived from util_cred.c:readStaticIdentityFile() */
OM_uint32
readChannelBindingsType(OM_uint32 *minor, char **cb_type)
{
    OM_uint32 major, tmpMinor;
    FILE *fp = NULL;
    char buf[BUFSIZ];
    char *ccacheName;
    int i = 0;
#ifndef WIN32
    struct passwd *pw = NULL, pwd;
    char pwbuf[BUFSIZ];
#endif

    *cb_type = NULL;

    ccacheName = getenv("GSS_SAML_EC_CB_TYPE_FILE");
    if (ccacheName == NULL) {
#ifdef WIN32
        TCHAR szPath[MAX_PATH];

        if (!SUCCEEDED(SHGetFolderPath(NULL,
                                       CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
                                       NULL, /* User access token */
                                       0,    /* SHGFP_TYPE_CURRENT */
                                       szPath))) {
            major = GSS_S_CRED_UNAVAIL;
            *minor = GSSEAP_GET_LAST_ERROR(); /* XXX */
            goto cleanup;
        }

        snprintf(buf, sizeof(buf), "%s/.gss_saml_ec_cb_type", szPath);
#else
        if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
            pw == NULL || pw->pw_dir == NULL) {
            major = GSS_S_CRED_UNAVAIL;
            *minor = GSSEAP_GET_LAST_ERROR();
            goto cleanup;
        }

        snprintf(buf, sizeof(buf), "%s/.gss_saml_ec_cb_type", pw->pw_dir);
#endif /* WIN32 */
        ccacheName = buf;
    }

    if (MECH_SAML_EC_DEBUG)
        printf("Looking for Channel Bindings Type in (%s)\n", ccacheName);

    fp = fopen(ccacheName, "r");
    if (fp == NULL) {
        fprintf(stderr, "ERROR: Channel Bindings Type not specified in (%s) nor"
                  " in a file pointed to by the environment variable: "
                  " GSS_SAML_EC_CB_TYPE_FILE\n", ccacheName);
        major = GSS_S_BAD_BINDINGS;
        *minor = GSSEAP_SAML_BINDING_FAILURE;
        goto cleanup;
    }

    if (fgets(buf, sizeof(buf), fp) != NULL) {

        if (strlen(buf) && buf[strlen(buf) - 1] == '\n') {
            buf[strlen(buf) - 1] = '\0';
        }
        *cb_type = strdup(buf);
    }

    if (*cb_type == NULL || strlen(*cb_type) == 0) {
        fprintf(stderr, "ERROR: Channel Bindings Type not specified\n");
        major = GSS_S_BAD_BINDINGS;
        *minor = GSSEAP_SAML_BINDING_FAILURE;
        goto cleanup;
    }

    major = GSS_S_COMPLETE;
    *minor = 0;

cleanup:
    if (fp != NULL)
        fclose(fp);

    if (GSS_ERROR(major)) {
        if (*cb_type)
            free(*cb_type); *cb_type = NULL;
    }

    memset(buf, 0, sizeof(buf));

    return major;
}
Beispiel #23
0
gfarmExportedCredential *
gfarmGssExportCredential(gss_cred_id_t cred, OM_uint32 *statPtr)
{
    gfarmExportedCredential *exportedCred = NULL;
    OM_uint32 majStat = 0;
    OM_uint32 minStat = 0;
    gss_buffer_desc buf = GSS_C_EMPTY_BUFFER;
    char *exported, *filename, *env;
    static char exported_name[] = "X509_USER_DELEG_PROXY=";
    static char env_name[] = "X509_USER_PROXY=";
    static char file_prefix[] = "FILE:";

    majStat = gss_export_cred(&minStat, cred, GSS_C_NO_OID, 1, &buf);
    if (GSS_ERROR(majStat))
	goto Done;

    exported = buf.value;
    for (filename = exported; *filename != '\0'; filename++)
	if (!isalnum(*(unsigned char *)filename) && *filename != '_')
	    break;
    if (*filename != '=') { /* not an environment variable */
	majStat = GSS_S_UNAVAILABLE;
	goto Done;
    }
    filename++;
    if (memcmp(exported, exported_name, sizeof(exported_name) - 1) == 0) {
	GFARM_MALLOC_ARRAY(env, sizeof(env_name) + strlen(filename));
	if (env == NULL) {
	    majStat = GSS_S_FAILURE;
	    goto Done;
	}
	memcpy(env, env_name, sizeof(env_name) - 1);
	strcpy(env + sizeof(env_name) - 1, filename);
	filename = env + sizeof(env_name) - 1;
    } else {
	env = strdup(exported);
	if (env == NULL) {
	    majStat = GSS_S_FAILURE;
	    goto Done;
	}
	filename = env + (filename - exported);
    }
    if (memcmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0)
	filename += sizeof(file_prefix) - 1;

    GFARM_MALLOC(exportedCred);
    if (exportedCred == NULL) {
	free(env);
	majStat = GSS_S_FAILURE;
	goto Done;
    }
    exportedCred->env = env;
    exportedCred->filename = access(filename, R_OK) == 0 ? filename : NULL;

    Done:
    gss_release_buffer(&minStat, &buf);
    if (statPtr != NULL)
	*statPtr = majStat;

    if (GSS_ERROR(majStat)) {
	gflog_debug(GFARM_MSG_1000800,
		"failed to export credential (%u)(%u)",
		 majStat, minStat);
    }

    return exportedCred;
}
Beispiel #24
0
static OM_uint32
readStaticIdentityFile(OM_uint32 *minor,
                       gss_buffer_t defaultIdentity,
                       gss_buffer_t defaultPassword)
{
    OM_uint32 major, tmpMinor;
    FILE *fp = NULL;
    char buf[BUFSIZ];
    char *ccacheName;
    int i = 0;
#ifndef WIN32
    struct passwd *pw = NULL, pwd;
    char pwbuf[BUFSIZ];
#endif

    defaultIdentity->length = 0;
    defaultIdentity->value = NULL;

    if (defaultPassword != GSS_C_NO_BUFFER) {
        defaultPassword->length = 0;
        defaultPassword->value = NULL;
    }

    ccacheName = getenv("GSSEAP_IDENTITY");
    if (ccacheName == NULL) {
#ifdef WIN32
        TCHAR szPath[MAX_PATH];

        if (!SUCCEEDED(SHGetFolderPath(NULL,
                                       CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
                                       NULL, /* User access token */
                                       0,    /* SHGFP_TYPE_CURRENT */
                                       szPath))) {
            major = GSS_S_CRED_UNAVAIL;
            *minor = GSSEAP_GET_LAST_ERROR(); /* XXX */
            goto cleanup;
        }

        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath);
#else
        if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
            pw == NULL || pw->pw_dir == NULL) {
            major = GSS_S_CRED_UNAVAIL;
            *minor = GSSEAP_GET_LAST_ERROR();
            goto cleanup;
        }

        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
#endif /* WIN32 */
        ccacheName = buf;
    }

    fp = fopen(ccacheName, "r");
    if (fp == NULL) {
        major = GSS_S_CRED_UNAVAIL;
        *minor = GSSEAP_NO_DEFAULT_CRED;
        goto cleanup;
    }

    while (fgets(buf, sizeof(buf), fp) != NULL) {
        gss_buffer_desc src, *dst;

        src.length = strlen(buf);
        src.value = buf;

        if (src.length == 0)
            break;

        if (buf[src.length - 1] == '\n') {
            buf[src.length - 1] = '\0';
            if (--src.length == 0)
                break;
        }

        if (i == 0)
            dst = defaultIdentity;
        else if (i == 1)
            dst = defaultPassword;
        else
            break;

        if (dst != GSS_C_NO_BUFFER) {
            major = duplicateBuffer(minor, &src, dst);
            if (GSS_ERROR(major))
                goto cleanup;
        }

        i++;
    }

    if (defaultIdentity->length == 0) {
        major = GSS_S_CRED_UNAVAIL;
        *minor = GSSEAP_NO_DEFAULT_CRED;
        goto cleanup;
    }

    major = GSS_S_COMPLETE;
    *minor = 0;

cleanup:
    if (fp != NULL)
        fclose(fp);

    if (GSS_ERROR(major)) {
        gss_release_buffer(&tmpMinor, defaultIdentity);
        zeroAndReleasePassword(defaultPassword);
    }

    memset(buf, 0, sizeof(buf));

    return major;
}
Beispiel #25
0
static char *
gss_mk_err(OM_uint32 maj_stat, OM_uint32 min_stat, const char *preamble)
{
	gss_buffer_desc	 status;
	OM_uint32	 new_stat;
	OM_uint32	 cur_stat;
	OM_uint32	 msg_ctx = 0;
	OM_uint32	 ret;
	int		 type;
	size_t		 newlen;
	char		*str = NULL;
	char		*tmp = NULL;

	cur_stat = maj_stat;
	type = GSS_C_GSS_CODE;

	for (;;) {

		/*
		 * GSS_S_FAILURE produces a rather unhelpful message, so
		 * we skip straight to the mech specific error in this case.
		 */

		if (type == GSS_C_GSS_CODE && cur_stat == GSS_S_FAILURE) {
			type = GSS_C_MECH_CODE;
			cur_stat = min_stat;
		}

		ret = gss_display_status(&new_stat, cur_stat, type,
		    GSS_C_NO_OID, &msg_ctx, &status);

		if (GSS_ERROR(ret))
			return str;	/* XXXrcd: hmmm, not quite?? */

		if (str)
			newlen = strlen(str);
		else
			newlen = strlen(preamble);

		newlen += status.length + 3;

		tmp = str;
		str = malloc(newlen);

		if (!str) {
			gss_release_buffer(&new_stat, &status);
			return tmp;	/* XXXrcd: hmmm, not quite?? */
		}

		snprintf(str, newlen, "%s%s%.*s", tmp?tmp:preamble,
		    tmp?", ":": ", (int)status.length, (char *)status.value);

		gss_release_buffer(&new_stat, &status);
		free(tmp);

		/*
		 * If we are finished processing for maj_stat, then
		 * move onto min_stat.
		 */

		if (msg_ctx == 0 && type == GSS_C_GSS_CODE && min_stat != 0) {
			type = GSS_C_MECH_CODE;
			cur_stat = min_stat;
			continue;
		}

		if (msg_ctx == 0)
			break;
	}

	return str;
}
Beispiel #26
0
OM_uint32
gssEapAcquireCred(OM_uint32 *minor,
                  const gss_name_t desiredName,
                  OM_uint32 timeReq GSSEAP_UNUSED,
                  const gss_OID_set desiredMechs,
                  int credUsage,
                  gss_cred_id_t *pCred,
                  gss_OID_set *pActualMechs,
                  OM_uint32 *timeRec)
{
    OM_uint32 major, tmpMinor;
    gss_cred_id_t cred;

    /* XXX TODO validate with changed set_cred_option API */
    *pCred = GSS_C_NO_CREDENTIAL;

    major = gssEapAllocCred(minor, &cred);
    if (GSS_ERROR(major))
        goto cleanup;

    switch (credUsage) {
    case GSS_C_BOTH:
        cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
        break;
    case GSS_C_INITIATE:
        cred->flags |= CRED_FLAG_INITIATE;
        break;
    case GSS_C_ACCEPT:
        cred->flags |= CRED_FLAG_ACCEPT;
        break;
    default:
        major = GSS_S_FAILURE;
        *minor = GSSEAP_BAD_USAGE;
        goto cleanup;
        break;
    }

    major = gssEapValidateMechs(minor, desiredMechs);
    if (GSS_ERROR(major))
        goto cleanup;

    major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
    if (GSS_ERROR(major))
        goto cleanup;

    if (desiredName != GSS_C_NO_NAME) {
        GSSEAP_MUTEX_LOCK(&desiredName->mutex);

        major = gssEapDuplicateName(minor, desiredName, &cred->name);
        if (GSS_ERROR(major)) {
            GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
            goto cleanup;
        }

        GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
    }

#ifdef GSSEAP_ENABLE_ACCEPTOR
    if (cred->flags & CRED_FLAG_ACCEPT) {
#ifdef MECH_EAP
        struct rs_context *radContext;

        major = gssEapCreateRadiusContext(minor, cred, &radContext);
        if (GSS_ERROR(major))
            goto cleanup;

        rs_context_destroy(radContext);
#endif
    }
#endif

    if (pActualMechs != NULL) {
        major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
        if (GSS_ERROR(major))
            goto cleanup;
    }

    if (timeRec != NULL)
        *timeRec = GSS_C_INDEFINITE;

    *pCred = cred;

    major = GSS_S_COMPLETE;
    *minor = 0;

cleanup:
    if (GSS_ERROR(major))
        gssEapReleaseCred(&tmpMinor, &cred);

    return major;
}
static OM_uint32
spnego_reply
           (OM_uint32 * minor_status,
	    const gssspnego_cred cred,
            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
    )
{
    OM_uint32 ret, minor;
    NegTokenResp resp;
    u_char oidbuf[17];
    size_t oidlen;
    size_t len, taglen;
    gss_OID_desc mech;
    int require_mic;
    size_t buf_len;
    gss_buffer_desc mic_buf, mech_buf;
    gss_buffer_desc mech_output_token;
    gssspnego_ctx ctx;

    *minor_status = 0;

    ctx = (gssspnego_ctx)*context_handle;

    output_token->length = 0;
    output_token->value  = NULL;

    mech_output_token.length = 0;
    mech_output_token.value = NULL;

    mech_buf.value = NULL;
    mech_buf.length = 0;

    ret = der_match_tag_and_length(input_token->value, input_token->length,
				   ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
    if (ret)
	return ret;

    if (len > input_token->length - taglen)
	return ASN1_OVERRUN;

    ret = decode_NegTokenResp((const unsigned char *)input_token->value+taglen,
			      len, &resp, NULL);
    if (ret) {
	*minor_status = ENOMEM;
	return GSS_S_FAILURE;
    }

    if (resp.negResult == NULL
	|| *(resp.negResult) == reject
	|| resp.supportedMech == NULL) {
	free_NegTokenResp(&resp);
	return GSS_S_BAD_MECH;
    }

    ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
		      sizeof(oidbuf),
		      resp.supportedMech,
		      &oidlen);
    if (ret || (oidlen == GSS_SPNEGO_MECHANISM->length &&
		memcmp(oidbuf + sizeof(oidbuf) - oidlen,
		       GSS_SPNEGO_MECHANISM->elements,
		       oidlen) == 0)) {
	/* Avoid recursively embedded SPNEGO */
	free_NegTokenResp(&resp);
	return GSS_S_BAD_MECH;
    }

    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);

    if (resp.responseToken != NULL) {
	gss_buffer_desc mech_input_token;

	mech_input_token.length = resp.responseToken->length;
	mech_input_token.value  = resp.responseToken->data;

	mech.length = oidlen;
	mech.elements = oidbuf + sizeof(oidbuf) - oidlen;

	/* Fall through as if the negotiated mechanism
	   was requested explicitly */
	ret = gss_init_sec_context(&minor,
				   (cred != NULL) ? cred->negotiated_cred_id :
				       GSS_C_NO_CREDENTIAL,
				   &ctx->negotiated_ctx_id,
				   target_name,
				   &mech,
				   req_flags,
				   time_req,
				   input_chan_bindings,
				   &mech_input_token,
				   &ctx->negotiated_mech_type,
				   &mech_output_token,
				   &ctx->mech_flags,
				   &ctx->mech_time_rec);
	if (GSS_ERROR(ret)) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free_NegTokenResp(&resp);
	    *minor_status = minor;
	    return ret;
	}
	if (ret == GSS_S_COMPLETE) {
	    ctx->open = 1;
	}
    }

    if (*(resp.negResult) == request_mic) {
	ctx->require_mic = 1;
    }

    if (ctx->open) {
	/*
	 * Verify the mechListMIC if one was provided or CFX was
	 * used and a non-preferred mechanism was selected
	 */
	if (resp.mechListMIC != NULL) {
	    require_mic = 1;
	} else {
	    ret = _gss_spnego_require_mechlist_mic(minor_status, ctx,
						   &require_mic);
	    if (ret) {
		HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
		free_NegTokenResp(&resp);
		gss_release_buffer(&minor, &mech_output_token);
		return ret;
	    }
	}
    } else {
	require_mic = 0;
    }

    if (require_mic) {
	ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
			   &ctx->initiator_mech_types, &buf_len, ret);
	if (ret) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free_NegTokenResp(&resp);
	    gss_release_buffer(&minor, &mech_output_token);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	if (mech_buf.length != buf_len)
	    abort();

	if (resp.mechListMIC == NULL) {
	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
	    free(mech_buf.value);
	    free_NegTokenResp(&resp);
	    *minor_status = 0;
	    return GSS_S_DEFECTIVE_TOKEN;
	}
	mic_buf.length = resp.mechListMIC->length;
	mic_buf.value  = resp.mechListMIC->data;

	if (mech_output_token.length == 0) {
	    ret = gss_verify_mic(minor_status,
				 ctx->negotiated_ctx_id,
				 &mech_buf,
				 &mic_buf,
				 NULL);
	   if (ret) {
		HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
		free(mech_buf.value);
		gss_release_buffer(&minor, &mech_output_token);
		free_NegTokenResp(&resp);
		return GSS_S_DEFECTIVE_TOKEN;
	    }
	    ctx->verified_mic = 1;
	}
    }

    ret = spnego_reply_internal(minor_status, ctx,
				require_mic ? &mech_buf : NULL,
				&mech_output_token,
				output_token);

    if (mech_buf.value != NULL)
	free(mech_buf.value);

    free_NegTokenResp(&resp);
    gss_release_buffer(&minor, &mech_output_token);

    if (actual_mech_type)
	*actual_mech_type = ctx->negotiated_mech_type;
    if (ret_flags)
	*ret_flags = ctx->mech_flags;
    if (time_rec)
	*time_rec = ctx->mech_time_rec;

    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
    return ret;
}
Beispiel #28
0
OM_uint32
gssEapInquireCred(OM_uint32 *minor,
                  gss_cred_id_t cred,
                  gss_name_t *name,
                  OM_uint32 *pLifetime,
                  gss_cred_usage_t *cred_usage,
                  gss_OID_set *mechanisms)
{
    OM_uint32 major;
    time_t now, lifetime;

    if (name != NULL) {
        major = gssEapResolveCredIdentity(minor, cred);
        if (GSS_ERROR(major))
            goto cleanup;

        if (cred->name != GSS_C_NO_NAME) {
            major = gssEapDuplicateName(minor, cred->name, name);
            if (GSS_ERROR(major))
                goto cleanup;
        } else
            *name = GSS_C_NO_NAME;
    }

    if (cred_usage != NULL) {
        OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));

        switch (flags) {
        case CRED_FLAG_INITIATE:
            *cred_usage = GSS_C_INITIATE;
            break;
        case CRED_FLAG_ACCEPT:
            *cred_usage = GSS_C_ACCEPT;
            break;
        default:
            *cred_usage = GSS_C_BOTH;
            break;
        }
    }

    if (mechanisms != NULL) {
        if (cred->mechanisms != GSS_C_NO_OID_SET)
            major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
        else
            major = gssEapIndicateMechs(minor, mechanisms);
        if (GSS_ERROR(major))
            goto cleanup;
    }

    if (cred->expiryTime == 0) {
        lifetime = GSS_C_INDEFINITE;
    } else  {
        now = time(NULL);
        lifetime = now - cred->expiryTime;
        if (lifetime < 0)
            lifetime = 0;
    }

    if (pLifetime != NULL) {
        *pLifetime = lifetime;
    }

    if (lifetime == 0) {
        major = GSS_S_CREDENTIALS_EXPIRED;
        *minor = GSSEAP_CRED_EXPIRED;
        goto cleanup;
    }

    major = GSS_S_COMPLETE;
    *minor = 0;

cleanup:
    return major;
}
Beispiel #29
0
int
_gsasl_gs2_server_step (Gsasl_session * sctx,
			void *mech_data,
			const char *input, size_t input_len,
			char **output, size_t * output_len)
{
  _Gsasl_gs2_server_state *state = mech_data;
  gss_buffer_desc bufdesc1, bufdesc2;
  OM_uint32 maj_stat, min_stat;
  gss_buffer_desc client_name;
  gss_OID mech_type;
  char tmp[4];
  int res;
  OM_uint32 ret_flags;
  struct gs2_token tok;

  *output = NULL;
  *output_len = 0;

  switch (state->step)
    {
    case 0:
      if (input_len == 0)
	{
	  res = GSASL_NEEDS_MORE;
	  break;
	}
      state->step++;
      /* fall through */

    case 1:
      res = gs2_parser (input, input_len, &tok);
      if (res < 0)
	return GSASL_MECHANISM_PARSE_ERROR;

      bufdesc1.value = tok.context_token;
      bufdesc1.length = tok.context_length;
      if (state->client)
	{
	  gss_release_name (&min_stat, &state->client);
	  state->client = GSS_C_NO_NAME;
	}

      maj_stat = gss_accept_sec_context (&min_stat,
					 &state->context,
					 state->cred,
					 &bufdesc1,
					 GSS_C_NO_CHANNEL_BINDINGS,
					 &state->client,
					 &mech_type,
					 &bufdesc2, &ret_flags, NULL, NULL);
      if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
	return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR;

      /* XXX check wrap token */

      if (ret_flags & GSS_C_PROT_READY_FLAG)
	{
	  puts ("prot_ready");
	  /* XXX gss_wrap token */
	}

      res = gs2_encode (bufdesc2.value, bufdesc2.length,
			NULL, 0, output, output_len);
      if (res < 0)
	return GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR;

      maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;

      if (maj_stat == GSS_S_COMPLETE)
	state->step++;

      res = GSASL_NEEDS_MORE;
      break;

    case 2:
      memset (tmp, 0xFF, 4);
      tmp[0] = GSASL_QOP_AUTH;
      bufdesc1.length = 4;
      bufdesc1.value = tmp;
      maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
			   &bufdesc1, NULL, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_WRAP_ERROR;

      *output = malloc (bufdesc2.length);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      memcpy (*output, bufdesc2.value, bufdesc2.length);
      *output_len = bufdesc2.length;

      maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;

      state->step++;
      res = GSASL_NEEDS_MORE;
      break;

    case 3:
      bufdesc1.value = (void *) input;
      bufdesc1.length = input_len;
      maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc1,
			     &bufdesc2, NULL, NULL);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_UNWRAP_ERROR;

      /* [RFC 2222 section 7.2.1]:
         The client passes this token to GSS_Unwrap and interprets the
         first octet of resulting cleartext as a bit-mask specifying
         the security layers supported by the server and the second
         through fourth octets as the maximum size output_message to
         send to the server.  The client then constructs data, with
         the first octet containing the bit-mask specifying the
         selected security layer, the second through fourth octets
         containing in network byte order the maximum size
         output_message the client is able to receive, and the
         remaining octets containing the authorization identity.  The
         client passes the data to GSS_Wrap with conf_flag set to
         FALSE, and responds with the generated output_message.  The
         client can then consider the server authenticated. */

      if ((((char *) bufdesc2.value)[0] & GSASL_QOP_AUTH) == 0)
	{
	  /* Integrity or privacy unsupported */
	  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
	  return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
	}

      gsasl_property_set_raw (sctx, GSASL_AUTHZID,
			      (char *) bufdesc2.value + 4,
			      bufdesc2.length - 4);

      maj_stat = gss_display_name (&min_stat, state->client,
				   &client_name, &mech_type);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_DISPLAY_NAME_ERROR;

      gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME,
			      client_name.value, client_name.length);

      maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;

      res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);

      state->step++;
      break;

    default:
      res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
      break;
    }

  return res;
}
Beispiel #30
0
gss_client_response *authenticate_gss_server_step(gss_server_state *state, const char *auth_data)
{
    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;
    gss_client_response *response = NULL;

    // Always clear out the old response
    if (state->response != NULL)
    {
        free(state->response);
        state->response = NULL;
    }

    // we don't need to check the authentication token if S4U2Self protocol
    // transition was done, because we already have the client credentials.
    if (state->client_creds == GSS_C_NO_CREDENTIAL)
    {
	if (auth_data && *auth_data)
	{
	    int len;
	    input_token.value = base64_decode(auth_data, &len);
	    input_token.length = len;
	}
	else
	{
	    response = calloc(1, sizeof(gss_client_response));
	    if(response == NULL) die1("Memory allocation failed");
	    response->message = strdup("No auth_data value in request from client");
	    response->return_code = AUTH_GSS_ERROR;
	    goto end;
	}

	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,
					  NULL,
					  NULL,
					  &state->client_creds);

	if (GSS_ERROR(maj_stat))
	{
	    response = gss_error(__func__, "gss_accept_sec_context", maj_stat, min_stat);
	    response->return_code = 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))
    {
	response = gss_error(__func__, "gss_display_name", maj_stat, min_stat);
	response->return_code = 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))
	{
	    response = gss_error(__func__, "gss_inquire_context", maj_stat, min_stat);
	    response->return_code = AUTH_GSS_ERROR;
	    goto end;
	}
	maj_stat = gss_display_name(&min_stat, target_name, &output_token, NULL);
	if (GSS_ERROR(maj_stat))
	{
	    response = gss_error(__func__, "gss_display_name", maj_stat, min_stat);
	    response->return_code = 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;
    }

    if (state->constrained_delegation && state->client_creds != GSS_C_NO_CREDENTIAL)
    {
	if ((response = store_gss_creds(state)) != NULL)
	{
	    goto end;
	}
    }

    ret = AUTH_GSS_COMPLETE;

end:
    if (output_token.length)
        gss_release_buffer(&min_stat, &output_token);
    if (input_token.value)
        free(input_token.value);

    if(response == NULL) {
      response = calloc(1, sizeof(gss_client_response));
      if(response == NULL) die1("Memory allocation failed");
      response->return_code = ret;
    }

    // Return the response
    return response;
}