static WERROR dns_domain_from_principal(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, 
					const char *name, 
					struct drsuapi_DsNameInfo1 *info1) 
{
	krb5_error_code ret;
	krb5_principal principal;
	/* perhaps it's a principal with a realm, so return the right 'domain only' response */
	char *realm;
	ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
				    KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
	if (ret) {
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
		return WERR_OK;
	}

	realm = smb_krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);

	info1->dns_domain_name	= talloc_strdup(mem_ctx, realm);
	krb5_free_principal(smb_krb5_context->krb5_context, principal);
	free(realm);

	W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);

	info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
	return WERR_OK;
}		
Example #2
0
static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
					const char *principal,
					const char *oldpw, 
					const char *newpw, 
					int time_offset)
{
    ADS_STATUS aret;
    krb5_error_code ret;
    krb5_context context = NULL;
    krb5_principal princ;
    krb5_get_init_creds_opt opts;
    krb5_creds creds;
    char *chpw_princ = NULL, *password;
    const char *realm = NULL;

    initialize_krb5_error_table();
    ret = krb5_init_context(&context);
    if (ret) {
	DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    if ((ret = smb_krb5_parse_name(context, principal,
                                    &princ))) {
	krb5_free_context(context);
	DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    krb5_get_init_creds_opt_init(&opts);
    krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
    krb5_get_init_creds_opt_set_renew_life(&opts, 0);
    krb5_get_init_creds_opt_set_forwardable(&opts, 0);
    krb5_get_init_creds_opt_set_proxiable(&opts, 0);

    realm = smb_krb5_principal_get_realm(context, princ);

    /* We have to obtain an INITIAL changepw ticket for changing password */
    if (asprintf(&chpw_princ, "kadmin/changepw@%s", realm) == -1) {
	krb5_free_context(context);
	DEBUG(1,("ads_krb5_chg_password: asprintf fail\n"));
	return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
    }

    password = SMB_STRDUP(oldpw);
    ret = krb5_get_init_creds_password(context, &creds, princ, password,
					   kerb_prompter, NULL, 
					   0, chpw_princ, &opts);
    SAFE_FREE(chpw_princ);
    SAFE_FREE(password);

    if (ret) {
      if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
	DEBUG(1,("Password incorrect while getting initial ticket"));
      else
	DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret)));

	krb5_free_principal(context, princ);
	krb5_free_context(context);
	return ADS_ERROR_KRB5(ret);
    }

    aret = do_krb5_kpasswd_request(context, kdc_host,
				   KRB5_KPASSWD_VERS_CHANGEPW,
				   &creds, principal, newpw);

    krb5_free_principal(context, princ);
    krb5_free_context(context);

    return aret;
}
Example #3
0
ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ, 
				 const char *newpw, int time_offset)
{

	ADS_STATUS aret;
	krb5_error_code ret = 0;
	krb5_context context = NULL;
	const char *realm = NULL;
	unsigned int realm_len = 0;
	krb5_creds creds, *credsp = NULL;
	krb5_ccache ccache = NULL;

	ZERO_STRUCT(creds);
	
	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	ret = krb5_cc_default(context, &ccache);
	if (ret) {
	        krb5_free_context(context);
		DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	ret = krb5_cc_get_principal(context, ccache, &creds.client);
	if (ret) {
		krb5_cc_close(context, ccache);
                krb5_free_context(context);
		DEBUG(1,("Failed to get principal from ccache (%s)\n",
			 error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	realm = smb_krb5_principal_get_realm(context, creds.client);
	realm_len = strlen(realm);
	ret = krb5_build_principal(context,
				   &creds.server,
				   realm_len,
				   realm, "kadmin", "changepw", NULL);

	ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
	if (ret) {
		krb5_cc_close(context, ccache);
	        krb5_free_principal(context, creds.client);
	        krb5_free_principal(context, creds.server);
	        krb5_free_context(context);
		DEBUG(1,("krb5_build_prinipal_ext (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp); 
	if (ret) {
		krb5_cc_close(context, ccache);
	        krb5_free_principal(context, creds.client);
	        krb5_free_principal(context, creds.server);
	        krb5_free_context(context);
		DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}
	
	/* we might have to call krb5_free_creds(...) from now on ... */

	aret = do_krb5_kpasswd_request(context, kdc_host,
				       KRB5_KPASSWD_VERS_SETPW,
				       credsp, princ, newpw);

	krb5_free_creds(context, credsp);
	krb5_free_principal(context, creds.client);
        krb5_free_principal(context, creds.server);
	krb5_cc_close(context, ccache);
	krb5_free_context(context);

	return aret;
}
Example #4
0
static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
					const char *principal,
					const char *oldpw, 
					const char *newpw, 
					int time_offset)
{
    ADS_STATUS aret;
    krb5_error_code ret;
    krb5_context context = NULL;
    krb5_principal princ;
    krb5_get_init_creds_opt opts;
    krb5_creds creds;
    char *chpw_princ = NULL, *password;
    char *realm = NULL;
    int result_code;
    krb5_data result_code_string = { 0 };
    krb5_data result_string = { 0 };
    smb_krb5_addresses *addr = NULL;

    initialize_krb5_error_table();
    ret = krb5_init_context(&context);
    if (ret) {
	DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    if ((ret = smb_krb5_parse_name(context, principal,
                                    &princ))) {
	krb5_free_context(context);
	DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret)));
	return ADS_ERROR_KRB5(ret);
    }

    krb5_get_init_creds_opt_init(&opts);

    krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
    krb5_get_init_creds_opt_set_renew_life(&opts, 0);
    krb5_get_init_creds_opt_set_forwardable(&opts, 0);
    krb5_get_init_creds_opt_set_proxiable(&opts, 0);

    /* note that heimdal will fill in the local addresses if the addresses
     * in the creds_init_opt are all empty and then later fail with invalid
     * address, sending our local netbios krb5 address - just like windows
     * - avoids this - gd */
    ret = smb_krb5_gen_netbios_krb5_address(&addr, lp_netbios_name());
    if (ret) {
        krb5_free_principal(context, princ);
        krb5_free_context(context);
        return ADS_ERROR_KRB5(ret);
    }
    krb5_get_init_creds_opt_set_address_list(&opts, addr->addrs);

    realm = smb_krb5_principal_get_realm(context, princ);

    /* We have to obtain an INITIAL changepw ticket for changing password */
    if (asprintf(&chpw_princ, "kadmin/changepw@%s", realm) == -1) {
	krb5_free_context(context);
	free(realm);
	DEBUG(1,("ads_krb5_chg_password: asprintf fail\n"));
	return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
    }

    free(realm);
    password = SMB_STRDUP(oldpw);
    ret = krb5_get_init_creds_password(context, &creds, princ, password,
					   kerb_prompter, NULL, 
					   0, chpw_princ, &opts);
    SAFE_FREE(chpw_princ);
    SAFE_FREE(password);

    if (ret) {
      if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
	DEBUG(1,("Password incorrect while getting initial ticket"));
      else
	DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret)));

	krb5_free_principal(context, princ);
	krb5_free_context(context);
	return ADS_ERROR_KRB5(ret);
    }

    ret = krb5_change_password(context,
			       &creds,
			       discard_const_p(char, newpw),
			       &result_code,
			       &result_code_string,
			       &result_string);
    if (ret) {
	DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret)));
	aret = ADS_ERROR_KRB5(ret);
	goto done;
    }

    if (result_code != KRB5_KPASSWD_SUCCESS) {
	ret = kpasswd_err_to_krb5_err(result_code);
	DEBUG(1, ("krb5_change_password failed (%s)\n", error_message(ret)));
	aret = ADS_ERROR_KRB5(ret);
	goto done;
    }

    aret = ADS_SUCCESS;

done:
    kerberos_free_data_contents(context, &result_code_string);
    kerberos_free_data_contents(context, &result_string);
    krb5_free_principal(context, princ);
    krb5_free_context(context);

    return aret;
}
static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
			     struct smb_krb5_context *smb_krb5_context,
			     uint32_t format_flags, enum drsuapi_DsNameFormat format_offered,
			     enum drsuapi_DsNameFormat format_desired,
			     const char *name, struct drsuapi_DsNameInfo1 *info1)
{
	int ldb_ret;
	WERROR status;
	const char *domain_filter = NULL;
	const char *result_filter = NULL;
	krb5_error_code ret;
	krb5_principal principal;
	char *realm;
	char *unparsed_name_short;
	const char *domain_attrs[] = { NULL };
	struct ldb_result *domain_res = NULL;

	/* Prevent recursion */
	if (!name) {
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
		return WERR_OK;
	}

	ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, 
				    KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
	if (ret) {
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
		return WERR_OK;
	}

	realm = smb_krb5_principal_get_realm(smb_krb5_context->krb5_context,
					     principal);

	ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
			     samdb_partitions_dn(sam_ctx, mem_ctx),
			     LDB_SCOPE_ONELEVEL,
			     domain_attrs,
			     "(&(objectClass=crossRef)(|(dnsRoot=%s)(netbiosName=%s))(systemFlags:%s:=%u))",
			     ldb_binary_encode_string(mem_ctx, realm),
			     ldb_binary_encode_string(mem_ctx, realm),
			     LDB_OID_COMPARATOR_AND,
			     SYSTEM_FLAG_CR_NTDS_DOMAIN);
	free(realm);

	if (ldb_ret != LDB_SUCCESS) {
		DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
		krb5_free_principal(smb_krb5_context->krb5_context, principal);
		return WERR_OK;
	}

	switch (domain_res->count) {
	case 1:
		break;
	case 0:
		krb5_free_principal(smb_krb5_context->krb5_context, principal);
		return dns_domain_from_principal(mem_ctx, smb_krb5_context, 
						 name, info1);
	default:
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
		krb5_free_principal(smb_krb5_context->krb5_context, principal);
		return WERR_OK;
	}

	ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, 
				      KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
	krb5_free_principal(smb_krb5_context->krb5_context, principal);

	if (ret) {
		free(unparsed_name_short);
		return WERR_NOMEM;
	}

	/* This may need to be extended for more userPrincipalName variations */
	result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))", 
					ldb_binary_encode_string(mem_ctx, unparsed_name_short));

	domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));

	if (!result_filter || !domain_filter) {
		free(unparsed_name_short);
		return WERR_NOMEM;
	}
	status = DsCrackNameOneFilter(sam_ctx, mem_ctx, 
				      smb_krb5_context, 
				      format_flags, format_offered, format_desired, 
				      NULL, unparsed_name_short, domain_filter, result_filter, 
				      info1, LDB_SCOPE_SUBTREE, NULL);
	free(unparsed_name_short);

	return status;
}
Example #6
0
static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
					    TALLOC_CTX *mem_ctx,
					    struct auth_session_info *session_info,
					    DATA_BLOB *decoded_data,
					    DATA_BLOB *kpasswd_reply,
					    const char **error_string)
{
	krb5_context context = kdc->smb_krb5_context->krb5_context;
	krb5_data k_dec_data;
	krb5_data *k_clear_data;
	krb5_principal target_principal;
	krb5_error_code code;
	DATA_BLOB password;
	char *target_realm = NULL;
	char *target_name = NULL;
	char *target_principal_string = NULL;
	bool is_service_principal = false;
	bool ok;
	size_t num_components;
	enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR;
	struct samr_DomInfo1 *dominfo = NULL;
	NTSTATUS status;

	k_dec_data.length = decoded_data->length;
	k_dec_data.data   = (char *)decoded_data->data;

	code = decode_krb5_setpw_req(&k_dec_data,
				     &k_clear_data,
				     &target_principal);
	if (code != 0) {
		DBG_WARNING("decode_krb5_setpw_req failed: %s\n",
			    error_message(code));
		ok = kpasswd_make_error_reply(mem_ctx,
					      KRB5_KPASSWD_MALFORMED,
					      "Failed to decode packet",
					      kpasswd_reply);
		if (!ok) {
			*error_string = "Failed to create reply";
			return KRB5_KPASSWD_HARDERROR;
		}
		return 0;
	}

	ok = convert_string_talloc_handle(mem_ctx,
					  lpcfg_iconv_handle(kdc->task->lp_ctx),
					  CH_UTF8,
					  CH_UTF16,
					  (const char *)k_clear_data->data,
					  k_clear_data->length,
					  (void **)&password.data,
					  &password.length);
	krb5_free_data(context, k_clear_data);
	if (!ok) {
		DBG_WARNING("String conversion failed\n");
		*error_string = "String conversion failed";
		return KRB5_KPASSWD_HARDERROR;
	}

	target_realm = smb_krb5_principal_get_realm(context, target_principal);
	code = krb5_unparse_name_flags(context,
				       target_principal,
				       KRB5_PRINCIPAL_UNPARSE_NO_REALM,
				       &target_name);
	if (code != 0) {
		DBG_WARNING("Failed to parse principal\n");
		*error_string = "String conversion failed";
		return KRB5_KPASSWD_HARDERROR;
	}

	if ((target_name != NULL && target_realm == NULL) ||
	    (target_name == NULL && target_realm != NULL)) {
		krb5_free_principal(context, target_principal);
		SAFE_FREE(target_realm);
		SAFE_FREE(target_name);

		ok = kpasswd_make_error_reply(mem_ctx,
					      KRB5_KPASSWD_MALFORMED,
					      "Realm and principal must be "
					      "both present, or neither "
					      "present",
					      kpasswd_reply);
		if (!ok) {
			*error_string = "Failed to create reply";
			return KRB5_KPASSWD_HARDERROR;
		}
		return 0;
	}

	if (target_name != NULL && target_realm != NULL) {
		SAFE_FREE(target_realm);
		SAFE_FREE(target_name);
	} else {
		krb5_free_principal(context, target_principal);
		SAFE_FREE(target_realm);
		SAFE_FREE(target_name);

		return kpasswd_change_password(kdc,
					       mem_ctx,
					       session_info,
					       &password,
					       kpasswd_reply,
					       error_string);
	}

	num_components = krb5_princ_size(context, target_principal);
	if (num_components >= 2) {
		is_service_principal = true;
		code = krb5_unparse_name_flags(context,
					       target_principal,
					       KRB5_PRINCIPAL_UNPARSE_SHORT,
					       &target_principal_string);
	} else {
		code = krb5_unparse_name(context,
					 target_principal,
					 &target_principal_string);
	}
	krb5_free_principal(context, target_principal);
	if (code != 0) {
		ok = kpasswd_make_error_reply(mem_ctx,
					      KRB5_KPASSWD_MALFORMED,
					      "Failed to parse principal",
					      kpasswd_reply);
		if (!ok) {
			*error_string = "Failed to create reply";
			return KRB5_KPASSWD_HARDERROR;
		}
	}

	status = kpasswd_samdb_set_password(mem_ctx,
					    kdc->task->event_ctx,
					    kdc->task->lp_ctx,
					    session_info,
					    is_service_principal,
					    target_principal_string,
					    &password,
					    &reject_reason,
					    &dominfo);
	if (!NT_STATUS_IS_OK(status)) {
		DBG_ERR("kpasswd_samdb_set_password failed - %s\n",
			nt_errstr(status));
	}

	ok = kpasswd_make_pwchange_reply(mem_ctx,
					 status,
					 reject_reason,
					 dominfo,
					 kpasswd_reply);
	if (!ok) {
		*error_string = "Failed to create reply";
		return KRB5_KPASSWD_HARDERROR;
	}

	return 0;
}
Example #7
0
/* does the ccache have a valid TGT? */
static time_t
get_tgt_time(const char *ccname) {
	krb5_context context;
	krb5_ccache ccache;
	krb5_cc_cursor cur;
	krb5_creds creds;
	krb5_principal principal;
	time_t credtime = 0;
	char *realm = NULL;
	TALLOC_CTX *mem_ctx;

	if (krb5_init_context(&context)) {
		syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__);
		return 0;
	}

	if (krb5_cc_resolve(context, ccname, &ccache)) {
		syslog(LOG_DEBUG, "%s: unable to resolve krb5 cache", __func__);
		goto err_cache;
	}

	if (krb5_cc_set_flags(context, ccache, 0)) {
		syslog(LOG_DEBUG, "%s: unable to set flags", __func__);
		goto err_cache;
	}

	if (krb5_cc_get_principal(context, ccache, &principal)) {
		syslog(LOG_DEBUG, "%s: unable to get principal", __func__);
		goto err_princ;
	}

	if (krb5_cc_start_seq_get(context, ccache, &cur)) {
		syslog(LOG_DEBUG, "%s: unable to seq start", __func__);
		goto err_ccstart;
	}

	if ((realm = smb_krb5_principal_get_realm(context, principal)) == NULL) {
		syslog(LOG_DEBUG, "%s: unable to get realm", __func__);
		goto err_ccstart;
	}

	mem_ctx = talloc_init("cifs.upcall");
	while (!credtime && !krb5_cc_next_cred(context, ccache, &cur, &creds)) {
		char *name;
		if (smb_krb5_unparse_name(mem_ctx, context, creds.server, &name)) {
			syslog(LOG_DEBUG, "%s: unable to unparse name", __func__);
			goto err_endseq;
		}
		if (krb5_realm_compare(context, creds.server, principal) &&
		    strnequal(name, KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE) &&
		    strnequal(name+KRB5_TGS_NAME_SIZE+1, realm, strlen(realm)) &&
		    creds.times.endtime > time(NULL))
			credtime = creds.times.endtime;
                krb5_free_cred_contents(context, &creds);
		TALLOC_FREE(name);
        }
err_endseq:
	TALLOC_FREE(mem_ctx);
        krb5_cc_end_seq_get(context, ccache, &cur);
err_ccstart:
	krb5_free_principal(context, principal);
err_princ:
#if defined(KRB5_TC_OPENCLOSE)
	krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
#endif
	krb5_cc_close(context, ccache);
err_cache:
	krb5_free_context(context);
	return credtime;
}