Exemple #1
0
static NTSTATUS tcp_ldap_rootdse(void *data,
				 TALLOC_CTX *mem_ctx,
				 struct cldap_search *io)
{
	struct ldap_connection *conn = talloc_get_type(data,
						       struct ldap_connection);
	struct ldap_message *msg, *result;
	struct ldap_request *req;
	int i;
	NTSTATUS status;

	msg = new_ldap_message(mem_ctx);
	if (!msg) {
		return NT_STATUS_NO_MEMORY;
	}

	msg->type = LDAP_TAG_SearchRequest;
	msg->r.SearchRequest.basedn = "";
	msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
	msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
	msg->r.SearchRequest.timelimit = 0;
	msg->r.SearchRequest.sizelimit = 0;
	msg->r.SearchRequest.attributesonly = false;
	msg->r.SearchRequest.tree = ldb_parse_tree(msg, io->in.filter);
	msg->r.SearchRequest.num_attributes = str_list_length(io->in.attributes);
	msg->r.SearchRequest.attributes = io->in.attributes;

	req = ldap_request_send(conn, msg);
	if (req == NULL) {
		printf("Could not setup ldap search\n");
		return NT_STATUS_UNSUCCESSFUL;
	}

	ZERO_STRUCT(io->out);
	for (i = 0; i < 2; ++i) {
		status = ldap_result_n(req, i, &result);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		switch (result->type) {
		case LDAP_TAG_SearchResultEntry:
			if (i != 0) {
				return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
			}
			io->out.response = &result->r.SearchResultEntry;
			break;
		case LDAP_TAG_SearchResultDone:
			io->out.result = &result->r.SearchResultDone;
			if (io->out.result->resultcode != LDAP_SUCCESS) {
				return NT_STATUS_LDAP(io->out.result->resultcode);
			}

			return NT_STATUS_OK;
		default:
			return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
		}
	}

	return NT_STATUS_OK;
}
Exemple #2
0
static bool test_search_auth_empty_substring(struct ldap_connection *conn, const char *basedn)
{
	bool ret = true;
	struct ldap_message *msg, *result;
	struct ldap_request *req;
	NTSTATUS status;
	struct ldap_Result *r;

	printf("Testing authenticated base Search with objectclass= substring filter\n");

	msg = new_ldap_message(conn);
	if (!msg) {
		return false;
	}

	msg->type = LDAP_TAG_SearchRequest;
	msg->r.SearchRequest.basedn = basedn;
	msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
	msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
	msg->r.SearchRequest.timelimit = 0;
	msg->r.SearchRequest.sizelimit = 0;
	msg->r.SearchRequest.attributesonly = false;
	msg->r.SearchRequest.tree = ldb_parse_tree(msg, "(objectclass=*)");
	msg->r.SearchRequest.tree->operation = LDB_OP_SUBSTRING;
	msg->r.SearchRequest.tree->u.substring.attr = "objectclass";
	msg->r.SearchRequest.tree->u.substring.start_with_wildcard = 1;
	msg->r.SearchRequest.tree->u.substring.end_with_wildcard = 1;
	msg->r.SearchRequest.tree->u.substring.chunks = NULL;
	msg->r.SearchRequest.num_attributes = 0;
	msg->r.SearchRequest.attributes = NULL;

	req = ldap_request_send(conn, msg);
	if (req == NULL) {
		printf("Could not setup ldap search\n");
		return false;
	}

	status = ldap_result_one(req, &result, LDAP_TAG_SearchResultDone);
	if (!NT_STATUS_IS_OK(status)) {
		printf("looking for search result done failed - %s\n", nt_errstr(status));
		return false;
	}

	printf("received %d replies\n", req->num_replies);

	r = &result->r.SearchResultDone;

	if (r->resultcode != LDAP_SUCCESS) {
		printf("search result done gave error - %s\n", ldb_strerror(r->resultcode));
		return false;
	}

	return ret;
}
Exemple #3
0
static bool test_compare_sasl(struct ldap_connection *conn, const char *basedn)
{
	struct ldap_message *msg, *rep;
	struct ldap_request *req;
	const char *val;
	NTSTATUS status;

	printf("Testing SASL Compare: %s\n", basedn);

	if (!basedn) {
		return false;
	}

	msg = new_ldap_message(conn);
	if (!msg) {
		return false;
	}

	msg->type = LDAP_TAG_CompareRequest;
	msg->r.CompareRequest.dn = basedn;
	msg->r.CompareRequest.attribute = talloc_strdup(msg, "objectClass");
	val = "domain";
	msg->r.CompareRequest.value = data_blob_talloc(msg, val, strlen(val));

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_CompareResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap compare request - %s\n", nt_errstr(status));
		return false;
	}

	DEBUG(5,("Code: %d DN: [%s] ERROR:[%s] REFERRAL:[%s]\n",
		rep->r.CompareResponse.resultcode,
		rep->r.CompareResponse.dn,
		rep->r.CompareResponse.errormessage,
		rep->r.CompareResponse.referral));

	return true;
}
Exemple #4
0
static bool test_abandon_request(struct torture_context *tctx,
	struct ldap_connection *conn, const char *basedn)
{
	struct ldap_message *msg;
	struct ldap_request *req;
	NTSTATUS status;

	printf("Testing the AbandonRequest with an old message id!\n");

	if (!basedn) {
		return false;
	}

	msg = new_ldap_message(conn);
	if (!msg) {
		return false;
	}

	printf(" Try a AbandonRequest for an old message id\n");

	msg->type = LDAP_TAG_AbandonRequest;
	msg->r.AbandonRequest.messageid = 1;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_request_wait(req);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap abandon request - %s\n", nt_errstr(status));
		return false;
	}

	return true;
}
Exemple #5
0
/*
  perform a simple username/password bind
*/
_PUBLIC_ NTSTATUS ldap_bind_simple(struct ldap_connection *conn, 
			  const char *userdn, const char *password)
{
	struct ldap_request *req;
	struct ldap_message *msg;
	const char *dn, *pw;
	NTSTATUS status;

	if (conn == NULL) {
		return NT_STATUS_INVALID_CONNECTION;
	}

	if (userdn) {
		dn = userdn;
	} else {
		if (conn->auth_dn) {
			dn = conn->auth_dn;
		} else {
			dn = "";
		}
	}

	if (password) {
		pw = password;
	} else {
		if (conn->simple_pw) {
			pw = conn->simple_pw;
		} else {
			pw = "";
		}
	}

	msg = new_ldap_simple_bind_msg(conn, dn, pw);
	NT_STATUS_HAVE_NO_MEMORY(msg);

	/* send the request */
	req = ldap_request_send(conn, msg);
	talloc_free(msg);
	NT_STATUS_HAVE_NO_MEMORY(req);

	/* wait for replies */
	status = ldap_request_wait(req);
	if (!NT_STATUS_IS_OK(status)) {
		talloc_free(req);
		return status;
	}

	/* check its a valid reply */
	msg = req->replies[0];
	if (msg->type != LDAP_TAG_BindResponse) {
		talloc_free(req);
		return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
	}

	status = ldap_check_response(conn, &msg->r.BindResponse.response);

	talloc_free(req);

	if (NT_STATUS_IS_OK(status)) {
		struct ldap_simple_creds *creds = talloc(conn, struct ldap_simple_creds);
		if (creds == NULL) {
			return NT_STATUS_NO_MEMORY;
		}
		creds->dn = talloc_strdup(creds, dn);
		creds->pw = talloc_strdup(creds, pw);
		if (creds->dn == NULL || creds->pw == NULL) {
			return NT_STATUS_NO_MEMORY;
		}
		conn->bind.type = LDAP_BIND_SIMPLE;
		conn->bind.creds = creds;
	}

	return status;
}
Exemple #6
0
/*
  perform a sasl bind using the given credentials
*/
_PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
			struct cli_credentials *creds,
			struct loadparm_context *lp_ctx)
{
	NTSTATUS status;
	TALLOC_CTX *tmp_ctx = NULL;

	DATA_BLOB input = data_blob(NULL, 0);
	DATA_BLOB output = data_blob(NULL, 0);

	struct ldap_message **sasl_mechs_msgs;
	struct ldap_SearchResEntry *search;
	int count, i;

	const char **sasl_names;
	uint32_t old_gensec_features;
	static const char *supported_sasl_mech_attrs[] = {
		"supportedSASLMechanisms", 
		NULL 
	};
	unsigned int logon_retries = 0;

	status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs,
			      false, NULL, NULL, &sasl_mechs_msgs);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n",
			  nt_errstr(status)));
		goto failed;
	}

	count = ildap_count_entries(conn, sasl_mechs_msgs);
	if (count != 1) {
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n",
			  count));
		goto failed;
	}

	tmp_ctx = talloc_new(conn);
	if (tmp_ctx == NULL) goto failed;

	search = &sasl_mechs_msgs[0]->r.SearchResultEntry;
	if (search->num_attributes != 1) {
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d != 1\n",
			  search->num_attributes));
		goto failed;
	}

	sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1);
	if (!sasl_names) {
		DEBUG(1, ("talloc_arry(char *, %d) failed\n",
			  count));
		goto failed;
	}

	for (i=0; i<search->attributes[0].num_values; i++) {
		sasl_names[i] = (const char *)search->attributes[0].values[i].data;
	}
	sasl_names[i] = NULL;

	gensec_init();

try_logon_again:
	/*
	  we loop back here on a logon failure, and re-create the
	  gensec session. The logon_retries counter ensures we don't
	  loop forever.
	 */

	status = gensec_client_start(conn, &conn->gensec,
				     lpcfg_gensec_settings(conn, lp_ctx));
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
		goto failed;
	}

	/* require Kerberos SIGN/SEAL only if we don't use SSL
	 * Windows seem not to like double encryption */
	old_gensec_features = cli_credentials_get_gensec_features(creds);
	if (tls_enabled(conn->sock)) {
		cli_credentials_set_gensec_features(creds, old_gensec_features & ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL));
	}

	/* this call also sets the gensec_want_features */
	status = gensec_set_credentials(conn->gensec, creds);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to set GENSEC creds: %s\n", 
			  nt_errstr(status)));
		goto failed;
	}

	/* reset the original gensec_features (on the credentials
	 * context, so we don't tatoo it ) */
	cli_credentials_set_gensec_features(creds, old_gensec_features);

	if (conn->host) {
		status = gensec_set_target_hostname(conn->gensec, conn->host);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to set GENSEC target hostname: %s\n", 
				  nt_errstr(status)));
			goto failed;
		}
	}

	status = gensec_set_target_service(conn->gensec, "ldap");
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to set GENSEC target service: %s\n", 
			  nt_errstr(status)));
		goto failed;
	}

	status = gensec_start_mech_by_sasl_list(conn->gensec, sasl_names);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("None of the %d proposed SASL mechs were acceptable: %s\n",
			  count, nt_errstr(status)));
		goto failed;
	}

	while (1) {
		NTSTATUS gensec_status;
		struct ldap_message *response;
		struct ldap_message *msg;
		struct ldap_request *req;
		int result = LDAP_OTHER;
	
		status = gensec_update(conn->gensec, tmp_ctx,
				       conn->event.event_ctx,
				       input,
				       &output);
		/* The status value here, from GENSEC is vital to the security
		 * of the system.  Even if the other end accepts, if GENSEC
		 * claims 'MORE_PROCESSING_REQUIRED' then you must keep
		 * feeding it blobs, or else the remote host/attacker might
		 * avoid mutal authentication requirements.
		 *
		 * Likewise, you must not feed GENSEC too much (after the OK),
		 * it doesn't like that either
		 */

		gensec_status = status;

		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
		    !NT_STATUS_IS_OK(status)) {
			break;
		}
		if (NT_STATUS_IS_OK(status) && output.length == 0) {
			break;
		}

		/* Perhaps we should make gensec_start_mech_by_sasl_list() return the name we got? */
		msg = new_ldap_sasl_bind_msg(tmp_ctx, conn->gensec->ops->sasl_name, (output.data?&output:NULL));
		if (msg == NULL) {
			status = NT_STATUS_NO_MEMORY;
			goto failed;
		}

		req = ldap_request_send(conn, msg);
		if (req == NULL) {
			status = NT_STATUS_NO_MEMORY;
			goto failed;
		}
		talloc_reparent(conn, tmp_ctx, req);

		status = ldap_result_n(req, 0, &response);
		if (!NT_STATUS_IS_OK(status)) {
			goto failed;
		}
		
		if (response->type != LDAP_TAG_BindResponse) {
			status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
			goto failed;
		}

		result = response->r.BindResponse.response.resultcode;

		if (result == LDAP_INVALID_CREDENTIALS) {
			/*
			  try a second time on invalid credentials, to
			  give the user a chance to re-enter the
			  password and to handle the case where our
			  kerberos ticket is invalid as the server
			  password has changed
			*/
			const char *principal;

			principal = gensec_get_target_principal(conn->gensec);
			if (principal == NULL) {
				const char *hostname = gensec_get_target_hostname(conn->gensec);
				const char *service  = gensec_get_target_service(conn->gensec);
				if (hostname != NULL && service != NULL) {
					principal = talloc_asprintf(tmp_ctx, "%s/%s", service, hostname);
				}
			}

			if (cli_credentials_failed_kerberos_login(creds, principal, &logon_retries) ||
			    cli_credentials_wrong_password(creds)) {
				/*
				  destroy our gensec session and loop
				  back up to the top to retry,
				  offering the user a chance to enter
				  new credentials, or get a new ticket
				  if using kerberos
				 */
				talloc_free(conn->gensec);
				conn->gensec = NULL;
				goto try_logon_again;
			}
		}

		if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
			status = ldap_check_response(conn, 
						     &response->r.BindResponse.response);
			break;
		}

		/* This is where we check if GENSEC wanted to be fed more data */
		if (!NT_STATUS_EQUAL(gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
			break;
		}
		if (response->r.BindResponse.SASL.secblob) {
			input = *response->r.BindResponse.SASL.secblob;
		} else {
			input = data_blob(NULL, 0);
		}
	}

	talloc_free(tmp_ctx);

	if (NT_STATUS_IS_OK(status)) {
		struct socket_context *sasl_socket;
		status = gensec_socket_init(conn->gensec, 
					    conn,
					    conn->sock,
					    conn->event.event_ctx, 
					    ldap_read_io_handler,
					    conn,
					    &sasl_socket);
		if (!NT_STATUS_IS_OK(status)) goto failed;

		conn->sock = sasl_socket;
		packet_set_socket(conn->packet, conn->sock);

		conn->bind.type = LDAP_BIND_SASL;
		conn->bind.creds = creds;
	}

	return status;

failed:
	talloc_free(tmp_ctx);
	talloc_free(conn->gensec);
	conn->gensec = NULL;
	return status;
}
Exemple #7
0
static bool test_search_rootDSE(struct ldap_connection *conn, const char **basedn,
	const char ***partitions)
{
	bool ret = true;
	struct ldap_message *msg, *result;
	struct ldap_request *req;
	int i;
	struct ldap_SearchResEntry *r;
	NTSTATUS status;

	printf("Testing RootDSE Search\n");

	*basedn = NULL;

	if (partitions != NULL) {
		*partitions = const_str_list(str_list_make_empty(conn));
	}

	msg = new_ldap_message(conn);
	if (!msg) {
		return false;
	}

	msg->type = LDAP_TAG_SearchRequest;
	msg->r.SearchRequest.basedn = "";
	msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
	msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
	msg->r.SearchRequest.timelimit = 0;
	msg->r.SearchRequest.sizelimit = 0;
	msg->r.SearchRequest.attributesonly = false;
	msg->r.SearchRequest.tree = ldb_parse_tree(msg, "(objectclass=*)");
	msg->r.SearchRequest.num_attributes = 0;
	msg->r.SearchRequest.attributes = NULL;

	req = ldap_request_send(conn, msg);
	if (req == NULL) {
		printf("Could not setup ldap search\n");
		return false;
	}

	status = ldap_result_one(req, &result, LDAP_TAG_SearchResultEntry);
	if (!NT_STATUS_IS_OK(status)) {
		printf("search failed - %s\n", nt_errstr(status));
		return false;
	}

	printf("received %d replies\n", req->num_replies);

	r = &result->r.SearchResultEntry;
		
	DEBUG(1,("\tdn: %s\n", r->dn));
	for (i=0; i<r->num_attributes; i++) {
		int j;
		for (j=0; j<r->attributes[i].num_values; j++) {
			DEBUG(1,("\t%s: %d %.*s\n", r->attributes[i].name,
				 (int)r->attributes[i].values[j].length,
				 (int)r->attributes[i].values[j].length,
				 (char *)r->attributes[i].values[j].data));
			if (!(*basedn) && 
			    strcasecmp("defaultNamingContext",r->attributes[i].name)==0) {
				*basedn = talloc_asprintf(conn, "%.*s",
							  (int)r->attributes[i].values[j].length,
							  (char *)r->attributes[i].values[j].data);
			}
			if ((partitions != NULL) &&
			    (strcasecmp("namingContexts", r->attributes[i].name) == 0)) {
				char *entry = talloc_asprintf(conn, "%.*s",
							      (int)r->attributes[i].values[j].length,
							      (char *)r->attributes[i].values[j].data);
				*partitions = str_list_add(*partitions, entry);
			}
		}
	}

	return ret;
}
Exemple #8
0
/* This has to be done using the LDAP API since the LDB API does only transmit
 * the error code and not the error message. */
static bool test_error_codes(struct torture_context *tctx,
	struct ldap_connection *conn, const char *basedn)
{
	struct ldap_message *msg, *rep;
	struct ldap_request *req;
	const char *err_code_str;
	char *endptr;
	WERROR err;
	NTSTATUS status;

	printf("Testing the most important error code -> error message conversions!\n");

	if (!basedn) {
		return false;
	}

	msg = new_ldap_message(conn);
	if (!msg) {
		return false;
	}

	printf(" Try a wrong addition\n");

	msg->type = LDAP_TAG_AddRequest;
	msg->r.AddRequest.dn = basedn;
	msg->r.AddRequest.num_attributes = 0;
	msg->r.AddRequest.attributes = NULL;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_AddResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap add request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.AddResponse.resultcode == 0)
		|| (rep->r.AddResponse.errormessage == NULL)
		|| (strtol(rep->r.AddResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}

	err = ad_error(rep->r.AddResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_DS_REFERRAL))
			|| (rep->r.AddResponse.resultcode != LDAP_REFERRAL)) {
			return false;
	}
	if ((rep->r.AddResponse.referral == NULL)
			|| (strstr(rep->r.AddResponse.referral, basedn) == NULL)) {
			return false;
	}

	printf(" Try another wrong addition\n");

	msg->type = LDAP_TAG_AddRequest;
	msg->r.AddRequest.dn = "";
	msg->r.AddRequest.num_attributes = 0;
	msg->r.AddRequest.attributes = NULL;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_AddResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap add request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.AddResponse.resultcode == 0)
		|| (rep->r.AddResponse.errormessage == NULL)
		|| (strtol(rep->r.AddResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}

	err = ad_error(rep->r.AddResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_DS_ROOT_MUST_BE_NC) &&
	     !W_ERROR_EQUAL(err, WERR_DS_NAMING_VIOLATION))
		|| (rep->r.AddResponse.resultcode != LDAP_NAMING_VIOLATION)) {
		return false;
	}

	printf(" Try a wrong modification\n");

	msg->type = LDAP_TAG_ModifyRequest;
	msg->r.ModifyRequest.dn = basedn;
	msg->r.ModifyRequest.num_mods = 0;
	msg->r.ModifyRequest.mods = NULL;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_ModifyResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap modifification request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.ModifyResponse.resultcode == 0)
		|| (rep->r.ModifyResponse.errormessage == NULL)
		|| (strtol(rep->r.ModifyResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}

	err = ad_error(rep->r.ModifyResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
	     !W_ERROR_EQUAL(err, WERR_DS_UNWILLING_TO_PERFORM))
		|| (rep->r.ModifyResponse.resultcode != LDAP_UNWILLING_TO_PERFORM)) {
		return false;
	}

	printf(" Try another wrong modification\n");

	msg->type = LDAP_TAG_ModifyRequest;
	msg->r.ModifyRequest.dn = "";
	msg->r.ModifyRequest.num_mods = 0;
	msg->r.ModifyRequest.mods = NULL;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_ModifyResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap modifification request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.ModifyResponse.resultcode == 0)
		|| (rep->r.ModifyResponse.errormessage == NULL)
		|| (strtol(rep->r.ModifyResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}

	err = ad_error(rep->r.ModifyResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
	     !W_ERROR_EQUAL(err, WERR_DS_UNWILLING_TO_PERFORM))
		|| (rep->r.ModifyResponse.resultcode != LDAP_UNWILLING_TO_PERFORM)) {
		return false;
	}

	printf(" Try a wrong removal\n");

	msg->type = LDAP_TAG_DelRequest;
	msg->r.DelRequest.dn = basedn;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_DelResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap removal request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.DelResponse.resultcode == 0)
		|| (rep->r.DelResponse.errormessage == NULL)
		|| (strtol(rep->r.DelResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}

	err = ad_error(rep->r.DelResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_DS_CANT_DELETE) &&
	     !W_ERROR_EQUAL(err, WERR_DS_UNWILLING_TO_PERFORM))
		|| (rep->r.DelResponse.resultcode != LDAP_UNWILLING_TO_PERFORM)) {
		return false;
	}

	printf(" Try another wrong removal\n");

	msg->type = LDAP_TAG_DelRequest;
	msg->r.DelRequest.dn = "";

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_DelResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap removal request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.DelResponse.resultcode == 0)
		|| (rep->r.DelResponse.errormessage == NULL)
		|| (strtol(rep->r.DelResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}
	
	err = ad_error(rep->r.DelResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_DS_OBJ_NOT_FOUND) &&
	     !W_ERROR_EQUAL(err, WERR_DS_NO_SUCH_OBJECT))
		|| (rep->r.DelResponse.resultcode != LDAP_NO_SUCH_OBJECT)) {
		return false;
	}

	printf(" Try a wrong rename\n");

	msg->type = LDAP_TAG_ModifyDNRequest;
	msg->r.ModifyDNRequest.dn = basedn;
	msg->r.ModifyDNRequest.newrdn = "dc=test";
	msg->r.ModifyDNRequest.deleteolddn = true;
	msg->r.ModifyDNRequest.newsuperior = NULL;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap rename request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.ModifyDNResponse.resultcode == 0)
		|| (rep->r.ModifyDNResponse.errormessage == NULL)
		|| (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}

	err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_DS_NO_PARENT_OBJECT) &&
	     !W_ERROR_EQUAL(err, WERR_DS_GENERIC_ERROR))
		|| (rep->r.ModifyDNResponse.resultcode != LDAP_OTHER)) {
		return false;
	}

	printf(" Try another wrong rename\n");

	msg->type = LDAP_TAG_ModifyDNRequest;
	msg->r.ModifyDNRequest.dn = basedn;
	msg->r.ModifyDNRequest.newrdn = basedn;
	msg->r.ModifyDNRequest.deleteolddn = true;
	msg->r.ModifyDNRequest.newsuperior = NULL;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap rename request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.ModifyDNResponse.resultcode == 0)
		|| (rep->r.ModifyDNResponse.errormessage == NULL)
		|| (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}

	err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
	     !W_ERROR_EQUAL(err, WERR_DS_NAMING_VIOLATION))
		|| (rep->r.ModifyDNResponse.resultcode != LDAP_NAMING_VIOLATION)) {
		return false;
	}

	printf(" Try another wrong rename\n");

	msg->type = LDAP_TAG_ModifyDNRequest;
	msg->r.ModifyDNRequest.dn = basedn;
	msg->r.ModifyDNRequest.newrdn = "";
	msg->r.ModifyDNRequest.deleteolddn = true;
	msg->r.ModifyDNRequest.newsuperior = NULL;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap rename request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.ModifyDNResponse.resultcode == 0)
		|| (rep->r.ModifyDNResponse.errormessage == NULL)
		|| (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}

	err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
	     !W_ERROR_EQUAL(err, WERR_DS_PROTOCOL_ERROR))
		|| (rep->r.ModifyDNResponse.resultcode != LDAP_PROTOCOL_ERROR)) {
		return false;
	}

	printf(" Try another wrong rename\n");

	msg->type = LDAP_TAG_ModifyDNRequest;
	msg->r.ModifyDNRequest.dn = "";
	msg->r.ModifyDNRequest.newrdn = "cn=temp";
	msg->r.ModifyDNRequest.deleteolddn = true;
	msg->r.ModifyDNRequest.newsuperior = NULL;

	req = ldap_request_send(conn, msg);
	if (!req) {
		return false;
	}

	status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
	if (!NT_STATUS_IS_OK(status)) {
		printf("error in ldap rename request - %s\n", nt_errstr(status));
		return false;
	}

	if ((rep->r.ModifyDNResponse.resultcode == 0)
		|| (rep->r.ModifyDNResponse.errormessage == NULL)
		|| (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
		|| (*endptr != ':')) {
		printf("Invalid error message!\n");
		return false;
	}

	err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
	err_code_str = win_errstr(err);
	printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
	if ((!W_ERROR_EQUAL(err, WERR_DS_OBJ_NOT_FOUND) &&
	     !W_ERROR_EQUAL(err, WERR_DS_NO_SUCH_OBJECT))
		|| (rep->r.ModifyDNResponse.resultcode != LDAP_NO_SUCH_OBJECT)) {
		return false;
	}

	return true;
}
Exemple #9
0
/*
  perform a sasl bind using the given credentials
*/
_PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
			struct cli_credentials *creds,
			struct loadparm_context *lp_ctx)
{
	NTSTATUS status;
	TALLOC_CTX *tmp_ctx = NULL;

	DATA_BLOB input = data_blob(NULL, 0);
	DATA_BLOB output = data_blob(NULL, 0);

	struct ldap_message **sasl_mechs_msgs;
	struct ldap_SearchResEntry *search;
	int count, i;
	bool first = true;
	int wrap_flags = 0;
	const char **sasl_names;
	uint32_t old_gensec_features;
	static const char *supported_sasl_mech_attrs[] = {
		"supportedSASLMechanisms", 
		NULL 
	};
	unsigned int logon_retries = 0;
	size_t queue_length;

	if (conn->sockets.active == NULL) {
		status = NT_STATUS_CONNECTION_DISCONNECTED;
		goto failed;
	}

	queue_length = tevent_queue_length(conn->sockets.send_queue);
	if (queue_length != 0) {
		status = NT_STATUS_INVALID_PARAMETER_MIX;
		DEBUG(1, ("SASL bind triggered with non empty send_queue[%zu]: %s\n",
			  queue_length, nt_errstr(status)));
		goto failed;
	}

	if (conn->pending != NULL) {
		status = NT_STATUS_INVALID_PARAMETER_MIX;
		DEBUG(1, ("SASL bind triggered with pending requests: %s\n",
			  nt_errstr(status)));
		goto failed;
	}

	status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs,
			      false, NULL, NULL, &sasl_mechs_msgs);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n",
			  nt_errstr(status)));
		goto failed;
	}

	count = ildap_count_entries(conn, sasl_mechs_msgs);
	if (count != 1) {
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n",
			  count));
		goto failed;
	}

	tmp_ctx = talloc_new(conn);
	if (tmp_ctx == NULL) goto failed;

	search = &sasl_mechs_msgs[0]->r.SearchResultEntry;
	if (search->num_attributes != 1) {
		DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d != 1\n",
			  search->num_attributes));
		goto failed;
	}

	sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1);
	if (!sasl_names) {
		DEBUG(1, ("talloc_arry(char *, %d) failed\n",
			  count));
		goto failed;
	}

	for (i=0; i<search->attributes[0].num_values; i++) {
		sasl_names[i] = (const char *)search->attributes[0].values[i].data;
	}
	sasl_names[i] = NULL;

	gensec_init();

	if (conn->sockets.active == conn->sockets.tls) {
		/*
		 * require Kerberos SIGN/SEAL only if we don't use SSL
		 * Windows seem not to like double encryption
		 */
		wrap_flags = 0;
	} else if (cli_credentials_is_anonymous(creds)) {
		/*
		 * anonymous isn't protected
		 */
		wrap_flags = 0;
	} else {
		wrap_flags = lpcfg_client_ldap_sasl_wrapping(lp_ctx);
	}

try_logon_again:
	/*
	  we loop back here on a logon failure, and re-create the
	  gensec session. The logon_retries counter ensures we don't
	  loop forever.
	 */
	data_blob_free(&input);
	TALLOC_FREE(conn->gensec);

	status = gensec_client_start(conn, &conn->gensec,
				     lpcfg_gensec_settings(conn, lp_ctx));
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
		goto failed;
	}

	old_gensec_features = cli_credentials_get_gensec_features(creds);
	if (wrap_flags == 0) {
		cli_credentials_set_gensec_features(creds, old_gensec_features & ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL));
	}

	/* this call also sets the gensec_want_features */
	status = gensec_set_credentials(conn->gensec, creds);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to set GENSEC creds: %s\n", 
			  nt_errstr(status)));
		goto failed;
	}

	/* reset the original gensec_features (on the credentials
	 * context, so we don't tatoo it ) */
	cli_credentials_set_gensec_features(creds, old_gensec_features);

	if (wrap_flags & ADS_AUTH_SASL_SEAL) {
		gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
		gensec_want_feature(conn->gensec, GENSEC_FEATURE_SEAL);
	}
	if (wrap_flags & ADS_AUTH_SASL_SIGN) {
		gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
	}

	/*
	 * This is an indication for the NTLMSSP backend to
	 * also encrypt when only GENSEC_FEATURE_SIGN is requested
	 * in gensec_[un]wrap().
	 */
	gensec_want_feature(conn->gensec, GENSEC_FEATURE_LDAP_STYLE);

	if (conn->host) {
		status = gensec_set_target_hostname(conn->gensec, conn->host);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to set GENSEC target hostname: %s\n", 
				  nt_errstr(status)));
			goto failed;
		}
	}

	status = gensec_set_target_service(conn->gensec, "ldap");
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to set GENSEC target service: %s\n", 
			  nt_errstr(status)));
		goto failed;
	}

	status = gensec_start_mech_by_sasl_list(conn->gensec, sasl_names);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("None of the %d proposed SASL mechs were acceptable: %s\n",
			  count, nt_errstr(status)));
		goto failed;
	}

	while (1) {
		NTSTATUS gensec_status;
		struct ldap_message *response;
		struct ldap_message *msg;
		struct ldap_request *req;
		int result = LDAP_OTHER;
	
		status = gensec_update_ev(conn->gensec, tmp_ctx,
				       conn->event.event_ctx,
				       input,
				       &output);
		/* The status value here, from GENSEC is vital to the security
		 * of the system.  Even if the other end accepts, if GENSEC
		 * claims 'MORE_PROCESSING_REQUIRED' then you must keep
		 * feeding it blobs, or else the remote host/attacker might
		 * avoid mutal authentication requirements.
		 *
		 * Likewise, you must not feed GENSEC too much (after the OK),
		 * it doesn't like that either.
		 *
		 * For SASL/EXTERNAL, there is no data to send, but we still
		 * must send the actual Bind request the first time around.
		 * Otherwise, a result of NT_STATUS_OK with 0 output means the
		 * end of a multi-step authentication, and no message must be
		 * sent.
		 */

		gensec_status = status;

		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
		    !NT_STATUS_IS_OK(status)) {
			break;
		}
		if (NT_STATUS_IS_OK(status) && output.length == 0) {
			if (!first)
				break;
		}
		first = false;

		/* Perhaps we should make gensec_start_mech_by_sasl_list() return the name we got? */
		msg = new_ldap_sasl_bind_msg(tmp_ctx, conn->gensec->ops->sasl_name, (output.data?&output:NULL));
		if (msg == NULL) {
			status = NT_STATUS_NO_MEMORY;
			goto failed;
		}

		req = ldap_request_send(conn, msg);
		if (req == NULL) {
			status = NT_STATUS_NO_MEMORY;
			goto failed;
		}
		talloc_reparent(conn, tmp_ctx, req);

		status = ldap_result_n(req, 0, &response);
		if (!NT_STATUS_IS_OK(status)) {
			goto failed;
		}
		
		if (response->type != LDAP_TAG_BindResponse) {
			status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
			goto failed;
		}

		result = response->r.BindResponse.response.resultcode;

		if (result == LDAP_STRONG_AUTH_REQUIRED) {
			if (wrap_flags == 0) {
				wrap_flags = ADS_AUTH_SASL_SIGN;
				goto try_logon_again;
			}
		}

		if (result == LDAP_INVALID_CREDENTIALS) {
			/*
			  try a second time on invalid credentials, to
			  give the user a chance to re-enter the
			  password and to handle the case where our
			  kerberos ticket is invalid as the server
			  password has changed
			*/
			const char *principal;

			principal = gensec_get_target_principal(conn->gensec);
			if (principal == NULL) {
				const char *hostname = gensec_get_target_hostname(conn->gensec);
				const char *service  = gensec_get_target_service(conn->gensec);
				if (hostname != NULL && service != NULL) {
					principal = talloc_asprintf(tmp_ctx, "%s/%s", service, hostname);
				}
			}

			if (cli_credentials_failed_kerberos_login(creds, principal, &logon_retries) ||
			    cli_credentials_wrong_password(creds)) {
				/*
				  destroy our gensec session and loop
				  back up to the top to retry,
				  offering the user a chance to enter
				  new credentials, or get a new ticket
				  if using kerberos
				 */
				goto try_logon_again;
			}
		}

		if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
			status = ldap_check_response(conn, 
						     &response->r.BindResponse.response);
			break;
		}

		/* This is where we check if GENSEC wanted to be fed more data */
		if (!NT_STATUS_EQUAL(gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
			break;
		}
		if (response->r.BindResponse.SASL.secblob) {
			input = *response->r.BindResponse.SASL.secblob;
		} else {
			input = data_blob(NULL, 0);
		}
	}

	TALLOC_FREE(tmp_ctx);

	if (!NT_STATUS_IS_OK(status)) {
		goto failed;
	}

	conn->bind.type = LDAP_BIND_SASL;
	conn->bind.creds = creds;

	if (wrap_flags & ADS_AUTH_SASL_SEAL) {
		if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN)) {
			return NT_STATUS_INVALID_NETWORK_RESPONSE;
		}

		if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) {
			return NT_STATUS_INVALID_NETWORK_RESPONSE;
		}
	} else if (wrap_flags & ADS_AUTH_SASL_SIGN) {
		if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN)) {
			return NT_STATUS_INVALID_NETWORK_RESPONSE;
		}
	}

	if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) &&
	    !gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) {
		return NT_STATUS_OK;
	}

	status = gensec_create_tstream(conn->sockets.raw,
				       conn->gensec,
				       conn->sockets.raw,
				       &conn->sockets.sasl);
	if (!NT_STATUS_IS_OK(status)) {
		goto failed;
	}

	conn->sockets.active = conn->sockets.sasl;

	return NT_STATUS_OK;

failed:
	talloc_free(tmp_ctx);
	talloc_free(conn->gensec);
	conn->gensec = NULL;
	return status;
}