Esempio n. 1
0
/*
  add or modify a rdataset
 */
_PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, void *dbdata, void *version)
{
	struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
	struct dnsp_DnssrvRpcRecord *rec;
	struct ldb_dn *dn;
	isc_result_t result;
	struct ldb_result *res;
	const char *attrs[] = { "dnsRecord", NULL };
	int ret, i;
	struct ldb_message_element *el;
	enum ndr_err_code ndr_err;
	NTTIME t;

	if (state->transaction_token != (void*)version) {
		state->log(ISC_LOG_INFO, "samba_dlz: bad transaction version");
		return ISC_R_FAILURE;
	}

	rec = talloc_zero(state, struct dnsp_DnssrvRpcRecord);
	if (rec == NULL) {
		return ISC_R_NOMEMORY;
	}

	unix_to_nt_time(&t, time(NULL));
	t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
	t /= 3600;         /* convert to hours */

	rec->rank        = DNS_RANK_ZONE;
	rec->dwSerial    = state->soa_serial;
	rec->dwTimeStamp = (uint32_t)t;

	if (!b9_parse(state, rdatastr, rec)) {
		state->log(ISC_LOG_INFO, "samba_dlz: failed to parse rdataset '%s'", rdatastr);
		talloc_free(rec);
		return ISC_R_FAILURE;
	}

	/* find the DN of the record */
	result = b9_find_name_dn(state, name, rec, &dn);
	if (result != ISC_R_SUCCESS) {
		talloc_free(rec);
		return result;
	}

	/* get any existing records */
	ret = ldb_search(state->samdb, rec, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode");
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		result = b9_add_record(state, name, dn, rec);
		talloc_free(rec);
		if (result == ISC_R_SUCCESS) {
			state->log(ISC_LOG_ERROR, "samba_dlz: added %s %s", name, rdatastr);
		}
		return result;
	}

	/* there are existing records. We need to see if this will
	 * replace a record or add to it
	 */
	el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
	if (el == NULL) {
		state->log(ISC_LOG_ERROR, "samba_dlz: no dnsRecord attribute for %s",
			   ldb_dn_get_linearized(dn));
		talloc_free(rec);
		return ISC_R_FAILURE;
	}

	for (i=0; i<el->num_values; i++) {
		struct dnsp_DnssrvRpcRecord rec2;

		ndr_err = ndr_pull_struct_blob(&el->values[i], rec, &rec2,
					       (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s",
				   ldb_dn_get_linearized(dn));
			talloc_free(rec);
			return ISC_R_FAILURE;
		}

		if (b9_record_match(state, rec, &rec2)) {
			break;
		}
	}
	if (i == el->num_values) {
		/* adding a new value */
		el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
		if (el->values == NULL) {
			talloc_free(rec);
			return ISC_R_NOMEMORY;
		}
		el->num_values++;
	}
Esempio n. 2
0
/*
  authorize a zone update
 */
_PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
				    const char *type, const char *key, uint32_t keydatalen, uint8_t *keydata,
				    void *dbdata)
{
	struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
	TALLOC_CTX *tmp_ctx;
	DATA_BLOB ap_req;
	struct cli_credentials *server_credentials;
	char *keytab_name;
	int ret;
	int ldb_ret;
	NTSTATUS nt_status;
	struct gensec_security *gensec_ctx;
	struct auth_session_info *session_info;
	struct ldb_dn *dn;
	isc_result_t result;
	struct ldb_result *res;
	const char * attrs[] = { NULL };
	uint32_t access_mask;

	/* Remove cached credentials, if any */
	if (state->session_info) {
		talloc_free(state->session_info);
		state->session_info = NULL;
	}
	if (state->update_name) {
		talloc_free(state->update_name);
		state->update_name = NULL;
	}

	tmp_ctx = talloc_new(NULL);
	if (tmp_ctx == NULL) {
		state->log(ISC_LOG_ERROR, "samba_dlz: no memory");
		return ISC_FALSE;
	}

	ap_req = data_blob_const(keydata, keydatalen);
	server_credentials = cli_credentials_init(tmp_ctx);
	if (!server_credentials) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to init server credentials");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	cli_credentials_set_krb5_context(server_credentials, state->smb_krb5_ctx);
	cli_credentials_set_conf(server_credentials, state->lp);

	keytab_name = talloc_asprintf(tmp_ctx, "file:%s/dns.keytab",
					lpcfg_private_dir(state->lp));
	ret = cli_credentials_set_keytab_name(server_credentials, state->lp, keytab_name,
						CRED_SPECIFIED);
	if (ret != 0) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to obtain server credentials from %s",
			   keytab_name);
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}
	talloc_free(keytab_name);

	nt_status = gensec_server_start(tmp_ctx,
					lpcfg_gensec_settings(tmp_ctx, state->lp),
					state->auth_context, &gensec_ctx);
	if (!NT_STATUS_IS_OK(nt_status)) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to start gensec server");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	gensec_set_credentials(gensec_ctx, server_credentials);

	nt_status = gensec_start_mech_by_name(gensec_ctx, "spnego");
	if (!NT_STATUS_IS_OK(nt_status)) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to start spnego");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	nt_status = gensec_update(gensec_ctx, tmp_ctx, state->ev_ctx, ap_req, &ap_req);
	if (!NT_STATUS_IS_OK(nt_status)) {
		state->log(ISC_LOG_ERROR, "samba_dlz: spnego update failed");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	nt_status = gensec_session_info(gensec_ctx, tmp_ctx, &session_info);
	if (!NT_STATUS_IS_OK(nt_status)) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to create session info");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	/* Get the DN from name */
	result = b9_find_name_dn(state, name, tmp_ctx, &dn);
	if (result != ISC_R_SUCCESS) {
		state->log(ISC_LOG_ERROR, "samba_dlz: failed to find name %s", name);
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	/* make sure the dn exists, or find parent dn in case new object is being added */
	ldb_ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
				attrs, "objectClass=dnsNode");
	if (ldb_ret == LDB_ERR_NO_SUCH_OBJECT) {
		ldb_dn_remove_child_components(dn, 1);
		access_mask = SEC_ADS_CREATE_CHILD;
		talloc_free(res);
	} else if (ldb_ret == LDB_SUCCESS) {
		access_mask = SEC_STD_REQUIRED | SEC_ADS_SELF_WRITE;
		talloc_free(res);
	} else {
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	/* Do ACL check */
	ldb_ret = dsdb_check_access_on_dn(state->samdb, tmp_ctx, dn,
						session_info->security_token,
						access_mask, NULL);
	if (ldb_ret != LDB_SUCCESS) {
		state->log(ISC_LOG_INFO,
			"samba_dlz: disallowing update of signer=%s name=%s type=%s error=%s",
			signer, name, type, ldb_strerror(ldb_ret));
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}

	/* Cache session_info, so it can be used in the actual add/delete operation */
	state->update_name = talloc_strdup(state, name);
	if (state->update_name == NULL) {
		state->log(ISC_LOG_ERROR, "samba_dlz: memory allocation error");
		talloc_free(tmp_ctx);
		return ISC_FALSE;
	}
	state->session_info = talloc_steal(state, session_info);

	state->log(ISC_LOG_INFO, "samba_dlz: allowing update of signer=%s name=%s tcpaddr=%s type=%s key=%s",
		   signer, name, tcpaddr, type, key);

	talloc_free(tmp_ctx);
	return ISC_TRUE;
}