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 + -
显示快捷键?