OM_uint32 KRB5_CALLCONV
gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
                                gss_cred_id_t cred,
                                OM_uint32 num_ktypes,
                                krb5_enctype *ktypes)
{
    static const gss_OID_desc req_oid = {
        GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH,
        GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID };
    OM_uint32 major_status;
    struct krb5_gss_set_allowable_enctypes_req req;
    gss_buffer_desc req_buffer;

    req.num_ktypes = num_ktypes;
    req.ktypes = ktypes;

    req_buffer.length = sizeof(req);
    req_buffer.value = &req;

    major_status = gss_set_cred_option(minor_status,
                                       &cred,
                                       (gss_OID)&req_oid,
                                       &req_buffer);

    return major_status;
}
Example #2
0
OM_uint32 gssi_set_cred_option(OM_uint32 *minor_status,
                               gss_cred_id_t *cred_handle,
                               const gss_OID desired_object,
                               const gss_buffer_t value)
{
    struct gpp_cred_handle *cred = NULL;
    OM_uint32 maj, min;

    GSSI_TRACE();

    *minor_status = 0;
    if (*cred_handle == GSS_C_NO_CREDENTIAL) {
        return GSS_S_CALL_INACCESSIBLE_READ;
    }
    cred = (struct gpp_cred_handle *)*cred_handle;

    /* NOTE: For now we can do this only for known objects
     * or local credentials */
    if (cred->remote) {
        return gpp_remote_options(minor_status, cred->remote,
                                  desired_object, value);
    }
    if (!cred->local) {
        return GSS_S_UNAVAILABLE;
    }

    maj = gss_set_cred_option(&min, &cred->local, desired_object, value);

    *minor_status = gpp_map_error(min);
    return maj;
}
OM_uint32 KRB5_CALLCONV
gss_krb5_import_cred(OM_uint32 *minor_status,
                     krb5_ccache id,
                     krb5_principal keytab_principal,
                     krb5_keytab keytab,
                     gss_cred_id_t *cred)
{
    static const gss_OID_desc req_oid = {
        GSS_KRB5_IMPORT_CRED_OID_LENGTH,
        GSS_KRB5_IMPORT_CRED_OID };
    OM_uint32 major_status;
    struct krb5_gss_import_cred_req req;
    gss_buffer_desc req_buffer;

    if (cred == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;

    *cred = GSS_C_NO_CREDENTIAL;

    req.id = id;
    req.keytab_principal = keytab_principal;
    req.keytab = keytab;

    req_buffer.value = &req;
    req_buffer.length = sizeof(req);

    major_status = gss_set_cred_option(minor_status,
                                       cred,
                                       (gss_OID)&req_oid,
                                       &req_buffer);

    return major_status;
}
Example #4
0
OM_uint32 KRB5_CALLCONV
gssspi_set_cred_option(OM_uint32 *minor_status,
	               gss_cred_id_t cred,
	               const gss_OID desired_object,
	               const gss_buffer_t value)
{
    return gss_set_cred_option(minor_status, &cred,
                               desired_object, value);
}
Example #5
0
OM_uint32
gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, 
				gss_cred_id_t cred,
				OM_uint32 num_enctypes,
				int32_t *enctypes)
{
    krb5_error_code ret;
    OM_uint32 maj_status;
    gss_buffer_desc buffer;
    krb5_storage *sp;
    krb5_data data;
    int i;

    sp = krb5_storage_emem();
    if (sp == NULL) {
	*minor_status = ENOMEM;
	maj_status = GSS_S_FAILURE;
	goto out;
    }

    for (i = 0; i < num_enctypes; i++) {
	ret = krb5_store_int32(sp, enctypes[i]);
	if (ret) {
	    *minor_status = ret;
	    maj_status = GSS_S_FAILURE;
	    goto out;
	}
    }

    ret = krb5_storage_to_data(sp, &data);
    if (ret) {
	*minor_status = ret;
	maj_status = GSS_S_FAILURE;
	goto out;
    }

    buffer.value = data.data;
    buffer.length = data.length;

    maj_status = gss_set_cred_option(minor_status,
				     &cred,
				     GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,
				     &buffer);
    krb5_data_free(&data);
out:
    if (sp)
	krb5_storage_free(sp);
    return maj_status;
}
Example #6
0
OM_uint32 GSSAPI_CALLCONV
_gss_spnego_set_cred_option (OM_uint32 *minor_status,
			     gss_cred_id_t *cred_handle,
			     const gss_OID object,
			     const gss_buffer_t value)
{
    if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) {
	*minor_status = 0;
	return GSS_S_NO_CRED;
    }

    return gss_set_cred_option(minor_status,
			      cred_handle,
			      object,
			      value);
}
Example #7
0
OM_uint32
_gss_spnego_set_cred_option (OM_uint32 *minor_status,
			     gss_cred_id_t *cred_handle,
			     const gss_OID object,
			     const gss_buffer_t value)
{
    gssspnego_cred cred;

    if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) {
	*minor_status = 0;
	return GSS_S_NO_CRED;
    }

    cred = (gssspnego_cred)*cred_handle;
    return gss_set_cred_option(minor_status,
			      &cred->negotiated_cred_id,
			      object,
			      value);
}
OM_uint32 KRB5_CALLCONV
gss_krb5_set_cred_rcache(OM_uint32 *minor_status,
                         gss_cred_id_t cred,
                         krb5_rcache rcache)
{
    static const gss_OID_desc req_oid = {
        GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH,
        GSS_KRB5_SET_CRED_RCACHE_OID };
    OM_uint32 major_status;
    gss_buffer_desc req_buffer;

    req_buffer.length = sizeof(rcache);
    req_buffer.value = rcache;

    major_status = gss_set_cred_option(minor_status,
                                       &cred,
                                       (gss_OID)&req_oid,
                                       &req_buffer);

    return major_status;
}
OM_uint32 KRB5_CALLCONV
gss_krb5_copy_ccache(OM_uint32 *minor_status,
                     gss_cred_id_t cred_handle,
                     krb5_ccache out_ccache)
{
    static const gss_OID_desc req_oid = {
        GSS_KRB5_COPY_CCACHE_OID_LENGTH,
        GSS_KRB5_COPY_CCACHE_OID };
    OM_uint32 major_status;
    gss_buffer_desc req_buffer;

    if (out_ccache == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;

    req_buffer.value = out_ccache;
    req_buffer.length = sizeof(out_ccache);

    major_status = gss_set_cred_option(minor_status,
                                       &cred_handle,
                                       (gss_OID)&req_oid,
                                       &req_buffer);

    return major_status;
}
Example #10
0
_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, 
						  struct tevent_context *event_ctx,
						  struct loadparm_context *lp_ctx,
						  struct gssapi_creds_container **_gcc,
						  const char **error_string)
{
	int ret = 0;
	OM_uint32 maj_stat, min_stat;
	struct gssapi_creds_container *gcc;
	struct ccache_container *ccache;
#ifdef SAMBA4_USES_HEIMDAL
	gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
#endif
	krb5_enctype *etypes = NULL;

	if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold && 
	    cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
		bool expired = false;
		OM_uint32 lifetime = 0;
		gss_cred_usage_t usage = 0;
		maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds, 
					    NULL, &lifetime, &usage, NULL);
		if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) {
			DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred)));
			expired = true;
		} else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) {
			DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime));
			expired = true;
		} else if (maj_stat != GSS_S_COMPLETE) {
			*error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
							gssapi_error_string(cred, maj_stat, min_stat, NULL));
			return EINVAL;
		}
		if (expired) {
			cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
		} else {
			DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n", 
				  cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
		
			*_gcc = cred->client_gss_creds;
			return 0;
		}
	}

	ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
					 &ccache, error_string);
	if (ret) {
		if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) {
			DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string));
		} else {
			DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string));
		}
		return ret;
	}

	gcc = talloc(cred, struct gssapi_creds_container);
	if (!gcc) {
		(*error_string) = error_message(ENOMEM);
		return ENOMEM;
	}

	maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, 
					&gcc->creds);
	if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) {
		/* This CCACHE is no good.  Ensure we don't use it again */
		cli_credentials_unconditionally_invalidate_ccache(cred);

		/* Now try again to get a ccache */
		ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
						 &ccache, error_string);
		if (ret) {
			DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
			return ret;
		}

		maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
						&gcc->creds);

	}

	if (maj_stat) {
		talloc_free(gcc);
		if (min_stat) {
			ret = min_stat;
		} else {
			ret = EINVAL;
		}
		(*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret));
		return ret;
	}


	/*
	 * transfer the enctypes from the smb_krb5_context to the gssapi layer
	 *
	 * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
	 * to configure the enctypes via the krb5.conf.
	 *
	 * And the gss_init_sec_context() creates it's own krb5_context and
	 * the TGS-REQ had all enctypes in it and only the ones configured
	 * and used for the AS-REQ, so it wasn't possible to disable the usage
	 * of AES keys.
	 */
	min_stat = get_kerberos_allowed_etypes(ccache->smb_krb5_context->krb5_context,
					       &etypes);
	if (min_stat == 0) {
		OM_uint32 num_ktypes;

		for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);

		maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
							   num_ktypes,
							   (int32_t *) etypes);
		SAFE_FREE(etypes);
		if (maj_stat) {
			talloc_free(gcc);
			if (min_stat) {
				ret = min_stat;
			} else {
				ret = EINVAL;
			}
			(*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret));
			return ret;
		}
	}

#ifdef SAMBA4_USES_HEIMDAL /* MIT lacks GSS_KRB5_CRED_NO_CI_FLAGS_X */

	/* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
	maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
				       GSS_KRB5_CRED_NO_CI_FLAGS_X,
				       &empty_buffer);
	if (maj_stat) {
		talloc_free(gcc);
		if (min_stat) {
			ret = min_stat;
		} else {
			ret = EINVAL;
		}
		(*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret));
		return ret;
	}
#endif
	cred->client_gss_creds_obtained = cred->ccache_obtained;
	talloc_set_destructor(gcc, free_gssapi_creds);
	cred->client_gss_creds = gcc;
	*_gcc = gcc;
	return 0;
}
Example #11
0
OM_uint32
gss_krb5_import_cred(OM_uint32 *minor_status,
		     krb5_ccache id,
		     krb5_principal keytab_principal,
		     krb5_keytab keytab,
		     gss_cred_id_t *cred)
{
    gss_buffer_desc buffer;
    OM_uint32 major_status;
    krb5_context context;
    krb5_error_code ret;
    krb5_storage *sp;
    krb5_data data;
    char *str;

    *cred = GSS_C_NO_CREDENTIAL;

    ret = krb5_init_context(&context);
    if (ret) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }

    sp = krb5_storage_emem();
    if (sp == NULL) {
	*minor_status = ENOMEM;
	major_status = GSS_S_FAILURE;
	goto out;
    }

    if (id) {
	ret = krb5_cc_get_full_name(context, id, &str);
	if (ret == 0) {
	    ret = krb5_store_string(sp, str);
	    free(str);
	}
    } else
	ret = krb5_store_string(sp, "");
    if (ret) {
	*minor_status = ret;
	major_status = GSS_S_FAILURE;
	goto out;
    }

    if (keytab_principal) {
	ret = krb5_unparse_name(context, keytab_principal, &str);
	if (ret == 0) {
	    ret = krb5_store_string(sp, str);
	    free(str);
	}
    } else
	krb5_store_string(sp, "");
    if (ret) {
	*minor_status = ret;
	major_status = GSS_S_FAILURE;
	goto out;
    }


    if (keytab) {
	ret = krb5_kt_get_full_name(context, keytab, &str);
	if (ret == 0) {
	    ret = krb5_store_string(sp, str);
	    free(str);
	}
    } else
	krb5_store_string(sp, "");
    if (ret) {
	*minor_status = ret;
	major_status = GSS_S_FAILURE;
	goto out;
    }

    ret = krb5_storage_to_data(sp, &data);
    if (ret) {
	*minor_status = ret;
	major_status = GSS_S_FAILURE;
	goto out;
    }

    buffer.value = data.data;
    buffer.length = data.length;
    
    major_status = gss_set_cred_option(minor_status,
				       cred,
				       GSS_KRB5_IMPORT_CRED_X,
				       &buffer);
    krb5_data_free(&data);
out:
    if (sp)
	krb5_storage_free(sp);
    krb5_free_context(context);
    return major_status;
}
Example #12
0
DWORD
VMCARpcCreateSrpAuthIdentity(
    PCSTR user,
    PCSTR domain,
    PCSTR password,
    PSTR *retUpn,
    rpc_auth_identity_handle_t *rpc_identity_h
    )
{
    OM_uint32 min = 0;
    OM_uint32 maj = 0;
    const gss_OID_desc gss_srp_password_oid =
        {GSSAPI_SRP_CRED_OPT_PW_LEN, (void *) GSSAPI_SRP_CRED_OPT_PW};
    const gss_OID_desc spnego_mech_oid =
        {SPNEGO_OID_LENGTH, (void *) SPNEGO_OID};
    gss_buffer_desc name_buf = {0};
    gss_name_t gss_name_buf = NULL;
    gss_buffer_desc gss_pwd = {0};
    size_t upn_len = 0;
    char *upn = NULL;
    gss_cred_id_t cred_handle = NULL;
    gss_OID_desc mech_oid_array[1];
    gss_OID_set_desc desired_mech = {0};

    if (domain)
    {
        /* user@DOMAIN\0 */
        upn_len = strlen(user) + 1 + strlen(domain) + 1;
        upn = calloc(upn_len, sizeof(char));
        if (!upn)
        {
            maj = GSS_S_FAILURE;
            min = ENOMEM;
        }
        snprintf(upn, upn_len, "%s@%s", user, domain);
    }
    else
    {
        /* Assume a UPN-like name form when no domain is provided */
        upn = strdup((char *) user);
        if (!upn)
        {
            maj = GSS_S_FAILURE;
            min = ENOMEM;
        }
    }
    name_buf.value = upn;
    name_buf.length = strlen(name_buf.value);
    maj = gss_import_name(
              &min,
              &name_buf,
              GSS_C_NT_USER_NAME,
              &gss_name_buf);
    if (maj)
    {
        goto error;
    }

    /*
     * Hard code desired mech OID to SRP
     */
    desired_mech.count = 1;
    desired_mech.elements = mech_oid_array;
    desired_mech.elements[0] = spnego_mech_oid;
    maj = gss_acquire_cred(
              &min,
              gss_name_buf,
              0,
              &desired_mech,
              GSS_C_INITIATE,
              &cred_handle,
              NULL,
              NULL);
    if (maj)
    {
        goto error;
    }

    gss_pwd.value = (char *) password;
    gss_pwd.length = strlen(gss_pwd.value);
    maj = gss_set_cred_option(
              &min,
              &cred_handle,
              (gss_OID) &gss_srp_password_oid,
              &gss_pwd);
    if (maj)
    {
        goto error;
    }

    *retUpn = upn;
    upn = NULL;
    *rpc_identity_h = (rpc_auth_identity_handle_t) cred_handle;

error:
    if (maj)
    {
        maj = min ? min : maj;
    }

    if (upn)
    {
        free(upn);
    }
    if (gss_name_buf)
    {
        gss_release_name(&min, &gss_name_buf);
    }

    return (DWORD) maj;
}
Example #13
0
static uint32_t NetSecurityNative_AcquireCredSpNego(uint32_t* minorStatus,
                                                    GssName* desiredName,
                                                    gss_cred_usage_t credUsage,
                                                    GssCredId** outputCredHandle)
{
    assert(minorStatus != NULL);
    assert(desiredName != NULL);
    assert(outputCredHandle != NULL);
    assert(*outputCredHandle == NULL);

#if HAVE_GSS_SPNEGO_MECHANISM
    gss_OID_set_desc gss_mech_spnego_OID_set_desc = {.count = 1, .elements = GSS_SPNEGO_MECHANISM};
#else
    gss_OID_set_desc gss_mech_spnego_OID_set_desc = {.count = 1, .elements = &gss_mech_spnego_OID_desc};
#endif
    uint32_t majorStatus = gss_acquire_cred(
        minorStatus, desiredName, 0, &gss_mech_spnego_OID_set_desc, credUsage, outputCredHandle, NULL, NULL);

    // call gss_set_cred_option with GSS_KRB5_CRED_NO_CI_FLAGS_X to support Kerberos Sign Only option from *nix client against a windows server
#if HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
    if (majorStatus == GSS_S_COMPLETE)
    {
        GssBuffer emptyBuffer = GSS_C_EMPTY_BUFFER;
        majorStatus = gss_set_cred_option(minorStatus, outputCredHandle, GSS_KRB5_CRED_NO_CI_FLAGS_X, &emptyBuffer);
    }
#endif

    return majorStatus;
}

uint32_t
NetSecurityNative_InitiateCredSpNego(uint32_t* minorStatus, GssName* desiredName, GssCredId** outputCredHandle)
{
    return NetSecurityNative_AcquireCredSpNego(minorStatus, desiredName, GSS_C_INITIATE, outputCredHandle);
}

uint32_t NetSecurityNative_DeleteSecContext(uint32_t* minorStatus, GssCtxId** contextHandle)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);

    return gss_delete_sec_context(minorStatus, contextHandle, GSS_C_NO_BUFFER);
}

static uint32_t NetSecurityNative_DisplayStatus(uint32_t* minorStatus,
                                                uint32_t statusValue,
                                                int statusType,
                                                PAL_GssBuffer* outBuffer)
{
    assert(minorStatus != NULL);
    assert(outBuffer != NULL);

    uint32_t messageContext = 0; // Must initialize to 0 before calling gss_display_status.
    GssBuffer gssBuffer = {.length = 0, .value = NULL};
    uint32_t majorStatus =
        gss_display_status(minorStatus, statusValue, statusType, GSS_C_NO_OID, &messageContext, &gssBuffer);

    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

uint32_t
NetSecurityNative_DisplayMinorStatus(uint32_t* minorStatus, uint32_t statusValue, PAL_GssBuffer* outBuffer)
{
    return NetSecurityNative_DisplayStatus(minorStatus, statusValue, GSS_C_MECH_CODE, outBuffer);
}

uint32_t
NetSecurityNative_DisplayMajorStatus(uint32_t* minorStatus, uint32_t statusValue, PAL_GssBuffer* outBuffer)
{
    return NetSecurityNative_DisplayStatus(minorStatus, statusValue, GSS_C_GSS_CODE, outBuffer);
}

uint32_t
NetSecurityNative_ImportUserName(uint32_t* minorStatus, char* inputName, uint32_t inputNameLen, GssName** outputName)
{
    assert(minorStatus != NULL);
    assert(inputName != NULL);
    assert(outputName != NULL);
    assert(*outputName == NULL);

    GssBuffer inputNameBuffer = {.length = inputNameLen, .value = inputName};
    return gss_import_name(minorStatus, &inputNameBuffer, GSS_C_NT_USER_NAME, outputName);
}
Example #14
0
uint32_t NetSecurityNative_Wrap(uint32_t* minorStatus,
                                GssCtxId* contextHandle,
                                int32_t isEncrypt,
                                uint8_t* inputBytes,
                                int32_t offset,
                                int32_t count,
                                PAL_GssBuffer* outBuffer)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);
    assert(isEncrypt == 1 || isEncrypt == 0);
    assert(inputBytes != NULL);
    assert(offset >= 0);
    assert(count >= 0);
    assert(outBuffer != NULL);
    // count refers to the length of the input message. That is, number of bytes of inputBytes
    // starting at offset that need to be wrapped.

    int confState;
    GssBuffer inputMessageBuffer = {.length = (size_t)count, .value = inputBytes + offset};
    GssBuffer gssBuffer;
    uint32_t majorStatus =
        gss_wrap(minorStatus, contextHandle, isEncrypt, GSS_C_QOP_DEFAULT, &inputMessageBuffer, &confState, &gssBuffer);

    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

uint32_t NetSecurityNative_Unwrap(uint32_t* minorStatus,
                                  GssCtxId* contextHandle,
                                  uint8_t* inputBytes,
                                  int32_t offset,
                                  int32_t count,
                                  PAL_GssBuffer* outBuffer)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);
    assert(inputBytes != NULL);
    assert(offset >= 0);
    assert(count >= 0);
    assert(outBuffer != NULL);

    // count refers to the length of the input message. That is, the number of bytes of inputBytes
    // starting at offset that need to be wrapped.
    GssBuffer inputMessageBuffer = {.length = (size_t)count, .value = inputBytes + offset};
    GssBuffer gssBuffer = {.length = 0, .value = NULL};
    uint32_t majorStatus = gss_unwrap(minorStatus, contextHandle, &inputMessageBuffer, &gssBuffer, NULL, NULL);
    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

static uint32_t NetSecurityNative_AcquireCredWithPassword(uint32_t* minorStatus,
                                                          int32_t isNtlm,
                                                          GssName* desiredName,
                                                          char* password,
                                                          uint32_t passwdLen,
                                                          gss_cred_usage_t credUsage,
                                                          GssCredId** outputCredHandle)
{
    assert(minorStatus != NULL);
    assert(isNtlm == 1 || isNtlm == 0);
    assert(desiredName != NULL);
    assert(password != NULL);
    assert(outputCredHandle != NULL);
    assert(*outputCredHandle == NULL);

#if HAVE_GSS_SPNEGO_MECHANISM
    (void)isNtlm; // unused
    // Specifying GSS_SPNEGO_MECHANISM as a desiredMech on OSX fails.
    gss_OID_set desiredMech = GSS_C_NO_OID_SET;
#else
    gss_OID_desc gss_mech_OID_desc;
    if (isNtlm)
    {
        gss_mech_OID_desc = gss_mech_ntlm_OID_desc;
    }
    else
    {
        gss_mech_OID_desc = gss_mech_spnego_OID_desc;
    }

    gss_OID_set_desc gss_mech_OID_set_desc = {.count = 1, .elements = &gss_mech_OID_desc};
    gss_OID_set desiredMech = &gss_mech_OID_set_desc;
#endif

    GssBuffer passwordBuffer = {.length = passwdLen, .value = password};
    uint32_t majorStatus = gss_acquire_cred_with_password(
        minorStatus, desiredName, &passwordBuffer, 0, desiredMech, credUsage, outputCredHandle, NULL, NULL);

    // call gss_set_cred_option with GSS_KRB5_CRED_NO_CI_FLAGS_X to support Kerberos Sign Only option from *nix client against a windows server
#if HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
    if (majorStatus == GSS_S_COMPLETE)
    {
        GssBuffer emptyBuffer = GSS_C_EMPTY_BUFFER;
        majorStatus = gss_set_cred_option(minorStatus, outputCredHandle, GSS_KRB5_CRED_NO_CI_FLAGS_X, &emptyBuffer);
    }
#endif

    return majorStatus;
}

uint32_t NetSecurityNative_InitiateCredWithPassword(uint32_t* minorStatus,
                                                    int32_t isNtlm,
                                                    GssName* desiredName,
                                                    char* password,
                                                    uint32_t passwdLen,
                                                    GssCredId** outputCredHandle)
{
    return NetSecurityNative_AcquireCredWithPassword(
        minorStatus, isNtlm, desiredName, password, passwdLen, GSS_C_INITIATE, outputCredHandle);
}

uint32_t NetSecurityNative_IsNtlmInstalled()
{
#if HAVE_GSS_SPNEGO_MECHANISM
    gss_OID ntlmOid = GSS_NTLM_MECHANISM;
#else
    gss_OID ntlmOid = &gss_mech_ntlm_OID_desc;
#endif

    uint32_t majorStatus;
    uint32_t minorStatus;
    gss_OID_set mechSet;
    gss_OID_desc oid;
    uint32_t foundNtlm = 0;

    majorStatus = gss_indicate_mechs(&minorStatus, &mechSet);
    if (majorStatus == GSS_S_COMPLETE)
    {
        for (size_t i = 0; i < mechSet->count; i++)
        {
            oid = mechSet->elements[i];
            if ((oid.length == ntlmOid->length) && (memcmp(oid.elements, ntlmOid->elements, oid.length) == 0))
            {
                foundNtlm = 1;
                break;
            }
        }

        gss_release_oid_set(&minorStatus, &mechSet);
    }

    return foundNtlm;
}
Example #15
0
INTERNAL void rpc__ntlmauth_bnd_set_auth
(
	unsigned_char_p_t server_name,
	rpc_authn_level_t level,
	rpc_authn_flags_t flags,
	rpc_auth_identity_handle_t auth_ident,
	rpc_authz_protocol_id_t authz_prot,
	rpc_binding_handle_t binding_h,
	rpc_auth_info_p_t *infop,
	unsigned32 *stp
)
{
	unsigned32 st = rpc_s_ok;
	rpc_ntlmssp_auth_ident_t_p auth_info = NULL;
	rpc_ntlmauth_info_p_t ntlmauth_info = NULL;
	gss_name_t gss_server_name = {0};
	unsigned char *str_server_name = NULL;
	gss_buffer_desc username_buf = {0};
	gss_name_t gss_user_name = NULL;
	int gss_rc = 0;
	OM_uint32 minor_status = 0;
	gss_OID_set_desc desired_mech;
	gss_OID_set ret_mech;
	gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL;
	OM_uint32 time_rec = 0;
	gss_OID_desc gss_ntlm_oid_desc = {0};
	gss_OID_desc gss_cred_opt_password_oid_desc = {0};
	gss_buffer_desc auth_buffer = {0};

	RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
		("(rpc__gssauth_bnd_set_auth)\n"));

	rpc_g_ntlmauth_alloc_count++;
	RPC_MEM_ALLOC(ntlmauth_info,
		      rpc_ntlmauth_info_p_t,
		      sizeof (*ntlmauth_info),
		      RPC_C_MEM_NTLMAUTH_INFO,
		      RPC_C_MEM_WAITOK);
	memset(ntlmauth_info, 0, sizeof(*ntlmauth_info));

	if (authz_prot != rpc_c_authz_name)
	{
		st = rpc_s_authn_authz_mismatch;
		goto poison;
	}

	if ((level != rpc_c_authn_level_connect) &&
	    (level != rpc_c_authn_level_pkt_integrity) &&
	    (level != rpc_c_authn_level_pkt_privacy))
	{
		st = rpc_s_unsupported_authn_level;
		goto poison;
	}

	if (flags & (~rpc_c_protect_flags_header_sign))
	{
		st = rpc_s_unsupported_protect_level;
		goto poison;
	}

	// Header signing extension has to be enabled in ntlmssp
	flags |= rpc_c_protect_flags_header_sign;

	if (server_name == NULL ||
	    auth_ident == NULL)
	{
		st = rpc_s_invalid_arg;
		goto poison;
	}

	auth_info = (rpc_ntlmssp_auth_ident_t_p)auth_ident;

	if (authz_prot == rpc_c_authz_name)
	{
		gss_buffer_desc input_name;
		/* GSS_KRB5_NT_PRINCIPAL_NAME */
		gss_OID_desc nt_principal =
		{10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
		int gss_rc = 0;
		OM_uint32 minor_status = 0;

		if (server_name == NULL)
		{
			rpc_mgmt_inq_server_princ_name(binding_h,
						       rpc_c_authn_winnt,
						       &str_server_name,
						       &st);
			if (st != rpc_s_ok)
			{
				goto poison;
			}
		}
		else
		{
			str_server_name = rpc_stralloc(server_name);
		}

		input_name.value = (void *)str_server_name;
		input_name.length = strlen((char *)str_server_name);

		gss_rc = gss_import_name(&minor_status,
					 &input_name,
					 &nt_principal,
					 &gss_server_name);
		if (gss_rc != GSS_S_COMPLETE)
		{
			char msg[256] = {0};
			rpc__ntlmauth_error_map(gss_rc, minor_status, GSS_C_NO_OID,
						msg, sizeof(msg), &st);
			RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
				       ("(rpc__gssauth_bnd_set_auth): import: %s\n", msg));
			goto poison;
		}
	}

	gss_ntlm_oid_desc.length                = GSS_MECH_NTLM_LEN;
	gss_ntlm_oid_desc.elements              = GSS_MECH_NTLM;
	gss_cred_opt_password_oid_desc.length   = GSS_CRED_OPT_PW_LEN;
	gss_cred_opt_password_oid_desc.elements = GSS_CRED_OPT_PW;

	username_buf.value  = auth_info->User;
	username_buf.length = auth_info->UserLength;

	gss_rc = gss_import_name(&minor_status,
				 &username_buf,
				 GSS_C_NT_USER_NAME,
				 &gss_user_name);
	if (gss_rc != GSS_S_COMPLETE)
	{
		char msg[256] = {0};
		rpc__ntlmauth_error_map(gss_rc, minor_status, GSS_C_NO_OID,
				        msg, sizeof(msg), &st);
		RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
			("(rpc__ntlmauth_bnd_set_auth): import: %s\n", msg));
		goto poison;
	}

	desired_mech.elements = (gss_OID)&gss_ntlm_oid_desc;
	desired_mech.count    = 1;

	gss_rc = gss_acquire_cred(&minor_status,
				  gss_user_name,
				  0,
				  &desired_mech,
				  GSS_C_INITIATE,
				  &cred_handle,
				  &ret_mech,
				  &time_rec);
	if (gss_rc != GSS_S_COMPLETE)
	{
		char msg[256] = {0};
		rpc__ntlmauth_error_map(gss_rc, minor_status, GSS_C_NO_OID,
				        msg, sizeof(msg), &st);
		RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
			("(rpc__ntlmauth_bnd_set_auth): import: %s\n", msg));
		goto poison;
	}

	auth_buffer.value  = auth_info;
	auth_buffer.length = sizeof(*auth_info);

	gss_rc = gss_set_cred_option(&minor_status,
					&cred_handle,
					(gss_OID)&gss_cred_opt_password_oid_desc,
					&auth_buffer);
	if (gss_rc != GSS_S_COMPLETE)
	{
		char msg[256] = {0};
		rpc__ntlmauth_error_map(gss_rc, minor_status, GSS_C_NO_OID,
				        msg, sizeof(msg), &st);
		RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
			("(rpc__ntlmauth_bnd_set_auth): import: %s\n", msg));
		goto poison;
	}

	ntlmauth_info->auth_info.server_princ_name = str_server_name;
	ntlmauth_info->auth_info.authn_level       = level;
	ntlmauth_info->auth_info.authn_flags       = flags;
	ntlmauth_info->auth_info.authn_protocol    = rpc_c_authn_winnt;
	ntlmauth_info->auth_info.authz_protocol    = authz_prot;
	ntlmauth_info->auth_info.is_server         = 0;
	ntlmauth_info->auth_info.u.auth_identity   = auth_ident;

	ntlmauth_info->auth_info.refcount          = 1;

	ntlmauth_info->gss_server_name             = gss_server_name;
	ntlmauth_info->gss_creds                   = cred_handle;

	if (gss_user_name)
	{
		gss_release_name(&minor_status, &gss_user_name);
	}

	*infop = &ntlmauth_info->auth_info;
	*stp = st;
	return;
poison:
	*infop = NULL;
	*stp = st;
	return;
}