ldap_client.c

来自「samba最新软件」· C语言 代码 · 共 820 行 · 第 1/2 页

C
820
字号
		}		talloc_unlink(conn, conn->sock);		conn->sock = tls_socket;		talloc_steal(conn, conn->sock);	}	conn->packet = packet_init(conn);	if (conn->packet == NULL) {		talloc_free(conn->sock);		return;	}	packet_set_private(conn->packet, conn);	packet_set_socket(conn->packet, conn->sock);	packet_set_callback(conn->packet, ldap_recv_handler);	packet_set_full_request(conn->packet, ldap_full_packet);	packet_set_error_handler(conn->packet, ldap_error_handler);	packet_set_event_context(conn->packet, conn->event.event_ctx);	packet_set_fde(conn->packet, conn->event.fde);	packet_set_serialise(conn->packet);	composite_done(ctx);}static void ldap_connect_recv_tcp_conn(struct composite_context *ctx){	struct ldap_connect_state *state =		talloc_get_type(ctx->async.private_data,				struct ldap_connect_state);	struct ldap_connection *conn = state->conn;	uint16_t port;	NTSTATUS status = socket_connect_multi_recv(ctx, state, &conn->sock,						       &port);	if (!NT_STATUS_IS_OK(status)) {		composite_error(state->ctx, status);		return;	}	ldap_connect_got_sock(state->ctx, conn);}static void ldap_connect_recv_unix_conn(struct composite_context *ctx){	struct ldap_connect_state *state =		talloc_get_type(ctx->async.private_data,				struct ldap_connect_state);	struct ldap_connection *conn = state->conn;	NTSTATUS status = socket_connect_recv(ctx);	if (!NT_STATUS_IS_OK(state->ctx->status)) {		composite_error(state->ctx, status);		return;	}	ldap_connect_got_sock(state->ctx, conn);}_PUBLIC_ NTSTATUS ldap_connect_recv(struct composite_context *ctx){	NTSTATUS status = composite_wait(ctx);	talloc_free(ctx);	return status;}_PUBLIC_ NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url){	struct composite_context *ctx = ldap_connect_send(conn, url);	return ldap_connect_recv(ctx);}/* set reconnect parameters */_PUBLIC_ void ldap_set_reconn_params(struct ldap_connection *conn, int max_retries){	if (conn) {		conn->reconnect.max_retries = max_retries;		conn->reconnect.retries = 0;		conn->reconnect.previous = time(NULL);	}}/* Actually this function is NOT ASYNC safe, FIXME? */static void ldap_reconnect(struct ldap_connection *conn){	NTSTATUS status;	time_t now = time(NULL);	/* do we have set up reconnect ? */	if (conn->reconnect.max_retries == 0) return;	/* is the retry time expired ? */	if (now > conn->reconnect.previous + 30) {		conn->reconnect.retries = 0;		conn->reconnect.previous = now;	}	/* are we reconnectind too often and too fast? */	if (conn->reconnect.retries > conn->reconnect.max_retries) return;	/* keep track of the number of reconnections */	conn->reconnect.retries++;	/* reconnect */	status = ldap_connect(conn, conn->reconnect.url);	if ( ! NT_STATUS_IS_OK(status)) {		return;	}	/* rebind */	status = ldap_rebind(conn);	if ( ! NT_STATUS_IS_OK(status)) {		ldap_connection_dead(conn);	}}/* destroy an open ldap request */static int ldap_request_destructor(struct ldap_request *req){	if (req->state == LDAP_REQUEST_PENDING) {		DLIST_REMOVE(req->conn->pending, req);	}	return 0;}/*  called on timeout of a ldap request*/static void ldap_request_timeout(struct event_context *ev, struct timed_event *te, 				      struct timeval t, void *private_data){	struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);	req->status = NT_STATUS_IO_TIMEOUT;	if (req->state == LDAP_REQUEST_PENDING) {		DLIST_REMOVE(req->conn->pending, req);	}	req->state = LDAP_REQUEST_DONE;	if (req->async.fn) {		req->async.fn(req);	}}/*  called on completion of a one-way ldap request*/static void ldap_request_complete(struct event_context *ev, struct timed_event *te, 				  struct timeval t, void *private_data){	struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);	if (req->async.fn) {		req->async.fn(req);	}}/*  send a ldap message - async interface*/_PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,				       struct ldap_message *msg){	struct ldap_request *req;	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;	req = talloc_zero(conn, struct ldap_request);	if (req == NULL) return NULL;	if (conn->sock == NULL) {		status = NT_STATUS_INVALID_CONNECTION;		goto failed;	}	req->state       = LDAP_REQUEST_SEND;	req->conn        = conn;	req->messageid   = conn->next_messageid++;	if (conn->next_messageid == 0) {		conn->next_messageid = 1;	}	req->type        = msg->type;	if (req->messageid == -1) {		goto failed;	}	talloc_set_destructor(req, ldap_request_destructor);	msg->messageid = req->messageid;	if (!ldap_encode(msg, &req->data, req)) {		status = NT_STATUS_INTERNAL_ERROR;		goto failed;			}	status = packet_send(conn->packet, req->data);	if (!NT_STATUS_IS_OK(status)) {		goto failed;	}	/* some requests don't expect a reply, so don't add those to the	   pending queue */	if (req->type == LDAP_TAG_AbandonRequest ||	    req->type == LDAP_TAG_UnbindRequest) {		req->status = NT_STATUS_OK;		req->state = LDAP_REQUEST_DONE;		/* we can't call the async callback now, as it isn't setup, so		   call it as next event */		event_add_timed(conn->event.event_ctx, req, timeval_zero(),				ldap_request_complete, req);		return req;	}	req->state = LDAP_REQUEST_PENDING;	DLIST_ADD(conn->pending, req);	/* put a timeout on the request */	req->time_event = event_add_timed(conn->event.event_ctx, req, 					  timeval_current_ofs(conn->timeout, 0),					  ldap_request_timeout, req);	return req;failed:	req->status = status;	req->state = LDAP_REQUEST_ERROR;	event_add_timed(conn->event.event_ctx, req, timeval_zero(),			ldap_request_complete, req);	return req;}/*  wait for a request to complete  note that this does not destroy the request*/_PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req){	while (req->state < LDAP_REQUEST_DONE) {		if (event_loop_once(req->conn->event.event_ctx) != 0) {			req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;			break;		}	}	return req->status;}/*  a mapping of ldap response code to strings*/static const struct {	enum ldap_result_code code;	const char *str;} ldap_code_map[] = {#define _LDAP_MAP_CODE(c) { c, #c }	_LDAP_MAP_CODE(LDAP_SUCCESS),	_LDAP_MAP_CODE(LDAP_OPERATIONS_ERROR),	_LDAP_MAP_CODE(LDAP_PROTOCOL_ERROR),	_LDAP_MAP_CODE(LDAP_TIME_LIMIT_EXCEEDED),	_LDAP_MAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED),	_LDAP_MAP_CODE(LDAP_COMPARE_FALSE),	_LDAP_MAP_CODE(LDAP_COMPARE_TRUE),	_LDAP_MAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED),	_LDAP_MAP_CODE(LDAP_STRONG_AUTH_REQUIRED),	_LDAP_MAP_CODE(LDAP_REFERRAL),	_LDAP_MAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED),	_LDAP_MAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION),	_LDAP_MAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED),	_LDAP_MAP_CODE(LDAP_SASL_BIND_IN_PROGRESS),	_LDAP_MAP_CODE(LDAP_NO_SUCH_ATTRIBUTE),	_LDAP_MAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE),	_LDAP_MAP_CODE(LDAP_INAPPROPRIATE_MATCHING),	_LDAP_MAP_CODE(LDAP_CONSTRAINT_VIOLATION),	_LDAP_MAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS),	_LDAP_MAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX),	_LDAP_MAP_CODE(LDAP_NO_SUCH_OBJECT),	_LDAP_MAP_CODE(LDAP_ALIAS_PROBLEM),	_LDAP_MAP_CODE(LDAP_INVALID_DN_SYNTAX),	_LDAP_MAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM),	_LDAP_MAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION),	_LDAP_MAP_CODE(LDAP_INVALID_CREDENTIALS),	_LDAP_MAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTS),	_LDAP_MAP_CODE(LDAP_BUSY),	_LDAP_MAP_CODE(LDAP_UNAVAILABLE),	_LDAP_MAP_CODE(LDAP_UNWILLING_TO_PERFORM),	_LDAP_MAP_CODE(LDAP_LOOP_DETECT),	_LDAP_MAP_CODE(LDAP_NAMING_VIOLATION),	_LDAP_MAP_CODE(LDAP_OBJECT_CLASS_VIOLATION),	_LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF),	_LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_RDN),	_LDAP_MAP_CODE(LDAP_ENTRY_ALREADY_EXISTS),	_LDAP_MAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED),	_LDAP_MAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS),	_LDAP_MAP_CODE(LDAP_OTHER)};/*  used to setup the status code from a ldap response*/_PUBLIC_ NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r){	int i;	const char *codename = "unknown";	if (r->resultcode == LDAP_SUCCESS) {		return NT_STATUS_OK;	}	if (conn->last_error) {		talloc_free(conn->last_error);	}	for (i=0;i<ARRAY_SIZE(ldap_code_map);i++) {		if (r->resultcode == ldap_code_map[i].code) {			codename = ldap_code_map[i].str;			break;		}	}	conn->last_error = talloc_asprintf(conn, "LDAP error %u %s - %s <%s> <%s>", 					   r->resultcode,					   codename,					   r->dn?r->dn:"(NULL)", 					   r->errormessage?r->errormessage:"", 					   r->referral?r->referral:"");		return NT_STATUS_LDAP(r->resultcode);}/*  return error string representing the last error*/_PUBLIC_ const char *ldap_errstr(struct ldap_connection *conn, 			TALLOC_CTX *mem_ctx, 			NTSTATUS status){	if (NT_STATUS_IS_LDAP(status) && conn->last_error != NULL) {		return talloc_strdup(mem_ctx, conn->last_error);	}	return talloc_asprintf(mem_ctx, "LDAP client internal error: %s", nt_errstr(status));}/*  return the Nth result message, waiting if necessary*/_PUBLIC_ NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg){	*msg = NULL;	NT_STATUS_HAVE_NO_MEMORY(req);	while (req->state < LDAP_REQUEST_DONE && n >= req->num_replies) {		if (event_loop_once(req->conn->event.event_ctx) != 0) {			return NT_STATUS_UNEXPECTED_NETWORK_ERROR;		}	}	if (n < req->num_replies) {		*msg = req->replies[n];		return NT_STATUS_OK;	}	if (!NT_STATUS_IS_OK(req->status)) {		return req->status;	}	return NT_STATUS_NO_MORE_ENTRIES;}/*  return a single result message, checking if it is of the expected LDAP type*/_PUBLIC_ NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type){	NTSTATUS status;	status = ldap_result_n(req, 0, msg);	if (!NT_STATUS_IS_OK(status)) {		return status;	}	if ((*msg)->type != type) {		*msg = NULL;		return NT_STATUS_UNEXPECTED_NETWORK_ERROR;	}	return status;}/*  a simple ldap transaction, for single result requests that only need a status code  this relies on single valued requests having the response type == request type + 1*/_PUBLIC_ NTSTATUS ldap_transaction(struct ldap_connection *conn, struct ldap_message *msg){	struct ldap_request *req = ldap_request_send(conn, msg);	struct ldap_message *res;	NTSTATUS status;	status = ldap_result_n(req, 0, &res);	if (!NT_STATUS_IS_OK(status)) {		talloc_free(req);		return status;	}	if (res->type != msg->type + 1) {		talloc_free(req);		return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);	}	status = ldap_check_response(conn, &res->r.GeneralResult);	talloc_free(req);	return status;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?