Example #1
0
/** Create and return a new connection
 *
 * libkrb5(s) can talk to the KDC over TCP. Were assuming something sane is implemented
 * by libkrb5 and that it does connection caching associated with contexts, so it's
 * worth using a connection pool to preserve connections when workers die.
 *
 * @param instance rlm_krb5 instance instance.
 * @return A new context or NULL on error.
 */
void *mod_conn_create(void *instance)
{
	rlm_krb5_t *inst = instance;
	rlm_krb5_handle_t *conn;
	krb5_error_code ret;

	MEM(conn = talloc_zero(instance, rlm_krb5_handle_t));
	ret = krb5_init_context(&conn->context);
	if (ret) {
		ERROR("rlm_krb5 (%s): Context initialisation failed: %s", inst->xlat_name,
		       rlm_krb5_error(NULL, ret));

		return NULL;
	}
	talloc_set_destructor(conn, _free_handle);

	ret = inst->keytabname ?
		krb5_kt_resolve(conn->context, inst->keytabname, &conn->keytab) :
		krb5_kt_default(conn->context, &conn->keytab);
	if (ret) {
		ERROR("Resolving keytab failed: %s", rlm_krb5_error(conn->context, ret));

		goto cleanup;
	}

#ifdef HEIMDAL_KRB5
	ret = krb5_cc_new_unique(conn->context, "MEMORY", NULL, &conn->ccache);
	if (ret) {
		ERROR("rlm_krb5 (%s): Credential cache creation failed: %s", inst->xlat_name,
		      rlm_krb5_error(conn->context, ret));

		return NULL;
	}

	krb5_verify_opt_init(&conn->options);
	krb5_verify_opt_set_ccache(&conn->options, conn->ccache);

	krb5_verify_opt_set_keytab(&conn->options, conn->keytab);
	krb5_verify_opt_set_secure(&conn->options, true);

	if (inst->service) {
		krb5_verify_opt_set_service(&conn->options, inst->service);
	}
#else
	krb5_verify_init_creds_opt_set_ap_req_nofail(inst->vic_options, true);
#endif
	return conn;

cleanup:
	talloc_free(conn);
	return NULL;
}
Example #2
0
char *					/* R: allocated response string */
auth_krb5 (
  /* PARAMETERS */
  const char *user,			/* I: plaintext authenticator */
  const char *password,			/* I: plaintext password */
  const char *service,                  /* I: service authenticating to */
  const char *realm                     /* I: user's realm */
  /* END PARAMETERS */
  )
{
    /* VARIABLES */
    krb5_context context;
    krb5_ccache ccache = NULL;
    krb5_keytab kt = NULL;
    krb5_principal auth_user;
    krb5_verify_opt opt;
    char * result;
    char tfname[2048];
    char principalbuf[2048];
    /* END VARIABLES */

    if (!user || !password) {
	syslog(LOG_ERR, "auth_krb5: NULL password or username?");
	return strdup("NO saslauthd internal NULL password or username");
    }

    if (krb5_init_context(&context)) {
	syslog(LOG_ERR, "auth_krb5: krb5_init_context");
	return strdup("NO saslauthd internal krb5_init_context error");
    }

    if (form_principal_name(user, service, realm, principalbuf, sizeof (principalbuf))) {
	syslog(LOG_ERR, "auth_krb5: form_principal_name");
	return strdup("NO saslauthd principal name error");
    }

    if (krb5_parse_name (context, principalbuf, &auth_user)) {
	krb5_free_context(context);
	syslog(LOG_ERR, "auth_krb5: krb5_parse_name");
	return strdup("NO saslauthd internal krb5_parse_name error");
    }

    if (krbtf_name(tfname, sizeof (tfname)) != 0) {
	syslog(LOG_ERR, "auth_krb5: could not generate ccache name");
	return strdup("NO saslauthd internal error");
    }

    if (krb5_cc_resolve(context, tfname, &ccache)) {
	krb5_free_principal(context, auth_user);
	krb5_free_context(context);
	syslog(LOG_ERR, "auth_krb5: krb5_cc_resolve");
	return strdup("NO saslauthd internal error");
    }

    if (keytabname) {
	if (krb5_kt_resolve(context, keytabname, &kt)) {
	    krb5_free_principal(context, auth_user);
	    krb5_cc_destroy(context, ccache);
	    krb5_free_context(context);
	    syslog(LOG_ERR, "auth_krb5: krb5_kt_resolve");
	    return strdup("NO saslauthd internal error");
	}
    }
    
    krb5_verify_opt_init(&opt);
    krb5_verify_opt_set_secure(&opt, 1);
    krb5_verify_opt_set_ccache(&opt, ccache);
    if (kt)
	krb5_verify_opt_set_keytab(&opt,  kt);
    krb5_verify_opt_set_service(&opt, verify_principal);
    
    if (krb5_verify_user_opt(context, auth_user, password, &opt)) {
	result = strdup("NO krb5_verify_user_opt failed");
    } else {
        result = strdup("OK");
    }
    
    krb5_free_principal(context, auth_user);
    krb5_cc_destroy(context, ccache);
    if (kt)
	krb5_kt_close(context, kt);
    krb5_free_context(context);

    return result;
}
Example #3
0
/*
 *  validate user/pass (Heimdal)
 */
static int krb5_auth(void *instance, REQUEST *request)
{
	rlm_krb5_t *inst = instance;

	krb5_error_code ret;
	krb5_ccache id;
	krb5_principal userP;

	krb5_context context = *(inst->context); /* copy data */
	const char *user, *pass;

	char service[SERVICE_NAME_LEN] = "host";
	char *server_name = NULL;
	char *princ_name;

	krb5_verify_opt krb_verify_options;
	krb5_keytab keytab;

	if (inst->service_princ != NULL) {
		server_name = strchr(inst->service_princ, '/');
		if (server_name != NULL) {
			*server_name = '\0';
		}

		strlcpy(service, inst->service_princ, sizeof(service));
		if (server_name != NULL) {
			*server_name = '/';
			server_name++;
		}
	}

	/*
	 *  We can only authenticate user requests which HAVE
	 *  a User-Name attribute.
	 */
	if (!request->username) {
		radlog(L_AUTH, "rlm_krb5: Attribute \"User-Name\" is required for authentication.");
		
		return RLM_MODULE_INVALID;
	}

	/*
	 *  We can only authenticate user requests which HAVE
	 *  a User-Password attribute.
	 */
	if (!request->password) {
		radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication.");
		
		return RLM_MODULE_INVALID;
	}

	/*
	 *  Ensure that we're being passed a plain-text password,
	 *  and not anything else.
	 */
	if (request->password->attribute != PW_USER_PASSWORD) {
		radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication.  Cannot use \"%s\".", request->password->name);
		
		return RLM_MODULE_INVALID;
	}

	user = request->username->vp_strvalue;
	pass = request->password->vp_strvalue;

	ret = krb5_parse_name(context, user, &userP);
	if (ret) {
		radlog(L_AUTH, "rlm_krb5: [%s] krb5_parse_name failed: %s",
		       user, error_message(ret));
		       
		return RLM_MODULE_REJECT;
	}

	/*
	 *  Heimdal krb5 verification.
	 */
	 
	/*
	 *  The following bit allows us to also log user/instance@REALM if someone
	 *  logs in using an instance.
	 */
	ret = krb5_unparse_name(context, userP, &princ_name);
	if (ret != 0) {
		radlog(L_AUTH, "rlm_krb5: Unparsable name");
	} else {
		radlog(L_AUTH, "rlm_krb5: Parsed name is: %s", princ_name);
		free(princ_name);
	}

	krb5_cc_default(context, &id);

	/*
	 *  Set up krb5_verify_user options.
	 */
	krb5_verify_opt_init(&krb_verify_options);
	krb5_verify_opt_set_ccache(&krb_verify_options, id);

	/*
	 *  Resolve keytab name. This allows us to use something other than
	 *  the default system keytab
	 */
	if (inst->keytab != NULL) {
		ret = krb5_kt_resolve(context, inst->keytab, &keytab);
		if (ret) {
			radlog(L_AUTH, "rlm_krb5: unable to resolve keytab %s: %s",
			       inst->keytab, error_message(ret));
			krb5_kt_close(context, keytab);
			
			return RLM_MODULE_REJECT;
		}
		
		krb5_verify_opt_set_keytab(&krb_verify_options, keytab);
	}

	/*
	 *  Verify aquired credentials against the keytab.
	 */
	krb5_verify_opt_set_secure(&krb_verify_options, 1);

	/*
	 *  Allow us to use an arbitrary service name.
	 */
	krb5_verify_opt_set_service(&krb_verify_options, service);

	/* 
	 *  Verify the user, using the above set options.
	 */
	ret = krb5_verify_user_opt(context, userP, pass, &krb_verify_options);

	/*
	 *  We are done with the keytab, close it.
	 */
	krb5_kt_close(context, keytab);

	if (ret == 0)
		return RLM_MODULE_OK;

	radlog(L_AUTH, "rlm_krb5: failed verify_user: %s (%s@%s)",
	       error_message(ret),
	       *userP->name.name_string.val,
	       userP->realm);

	return RLM_MODULE_REJECT;
}
Example #4
0
/*
 *	Validate user/pass (Heimdal)
 */
static rlm_rcode_t krb5_auth(void *instance, REQUEST *request)
{
	rlm_krb5_t *inst = instance;
	rlm_rcode_t rcode;
	
	krb5_error_code ret;
	
	krb5_principal client;
	krb5_ccache ccache;
	krb5_keytab keytab;
	krb5_verify_opt options;
	krb5_context *context = NULL;
	
	/*
	 *	See above in MIT krb5_auth
	 */
	ret = krb5_copy_context(*(inst->context), context);
	if (ret) {
		radlog(L_ERR, "rlm_krb5 (%s): Error cloning krb5 context: %s",
		       inst->xlat_name, error_message(ret));
		
		return RLM_MODULE_FAIL;
	}
	
	/*
	 *	Setup krb5_verify_user options
	 *
	 *	Not entirely sure this is necessary, but as we use context 
	 *	to get the cache handle, we probably do have to do this with
	 *	the cloned context.
	 */
	krb5_cc_default(*context, &ccache);
	
	krb5_verify_opt_init(&options);
	krb5_verify_opt_set_ccache(&options, ccache);
	
	memset(&keytab, 0, sizeof(keytab));
	ret = inst->keytabname ? 
		krb5_kt_resolve(*context, inst->keytabname, &keytab) :
		krb5_kt_default(*context, &keytab);
	if (ret) {
		radlog(L_ERR, "rlm_krb5 (%s): Resolving keytab failed: %s",
		       inst->xlat_name, error_message(ret));
		
		goto cleanup;
	}
	
	krb5_verify_opt_set_keytab(&options, keytab);
	krb5_verify_opt_set_secure(&options, TRUE);

	if (inst->service) {
		krb5_verify_opt_set_service(&options, inst->service);
	}
	
	rcode = krb5_parse_user(inst, request, &client);
	if (rcode != RLM_MODULE_OK) goto cleanup;

	/* 
	 *	Verify the user, using the options we set in instantiate
	 */
	ret = krb5_verify_user_opt(*context, client,
				   request->password->vp_strvalue,
				   &options);
	if (ret) {
		switch (ret) {
		case KRB5_LIBOS_BADPWDMATCH:
		case KRB5KRB_AP_ERR_BAD_INTEGRITY:
			RDEBUG("Provided password was incorrect: %s",
			       error_message(ret));
			rcode = RLM_MODULE_REJECT;
		
			break;
		case KRB5KDC_ERR_KEY_EXP:
		case KRB5KDC_ERR_CLIENT_REVOKED:
		case KRB5KDC_ERR_SERVICE_REVOKED:
			RDEBUG("Account has been locked out: %s",
			       error_message(ret));
			rcode = RLM_MODULE_USERLOCK;
		
			break;
		case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
			RDEBUG("User not found: %s", error_message(ret));
			rcode = RLM_MODULE_NOTFOUND;
					
		default:
			radlog(L_ERR, "rlm_krb5 (%s): Verifying user failed: "
			       "%s", inst->xlat_name, error_message(ret));
			rcode = RLM_MODULE_FAIL;
		
			break;
		}

		goto cleanup;
	}
	
	cleanup:
	
	krb5_free_context(*context);
	krb5_kt_close(*context, keytab);
	
	return rcode;
}