winbindd_ldap.c

来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 647 行

C
647
字号
/*    Unix SMB/CIFS implementation.   winbind ldap proxy code   Copyright (C) Volker Lendecke      This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "includes.h"#include "winbindd.h"/* This rw-buf api is made to avoid memcpy. For now do that like mad...  The   idea is to write into a circular list of buffers where the ideal case is   that a read(2) holds a complete request that is then thrown away   completely. */struct ldap_message_queue {	struct ldap_message_queue *prev, *next;	struct ldap_message *msg;};struct rw_buffer {	uint8 *data;	size_t ofs, length;};struct winbind_ldap_client {	struct winbind_ldap_client *next, *prev;	int sock;	BOOL finished;	struct rw_buffer in_buffer, out_buffer;};static struct winbind_ldap_client *ldap_clients;struct winbind_ldap_server {	struct winbind_ldap_server *next, *prev;	int sock;	BOOL ready;		/* Bind successful? */	BOOL finished;	struct rw_buffer in_buffer, out_buffer;	int messageid;};	static struct winbind_ldap_server *ldap_servers;struct pending_ldap_message {	struct pending_ldap_message *next, *prev;	struct ldap_message *msg; /* The message the client sent us */	int our_msgid;		/* The messageid we used */	struct winbind_ldap_client *client;};struct pending_ldap_message *pending_messages;static BOOL append_to_buf(struct rw_buffer *buf, uint8 *data, size_t length){	buf->data = SMB_REALLOC(buf->data, buf->length+length);	if (buf->data == NULL)		return False;	memcpy(buf->data+buf->length, data, length);	buf->length += length;	return True;}static BOOL read_into_buf(int fd, struct rw_buffer *buf){	char tmp_buf[1024];	int len;	len = read(fd, tmp_buf, sizeof(tmp_buf));	if (len == 0)		return False;	return append_to_buf(buf, tmp_buf, len);}static void peek_into_buf(struct rw_buffer *buf, uint8 **out,			  size_t *out_length){	*out = buf->data;	*out_length = buf->length;}static void consumed_from_buf(struct rw_buffer *buf, size_t length){	uint8 *new = memdup(buf->data+length, buf->length-length);	free(buf->data);	buf->data = new;	buf->length -= length;}static BOOL write_out_of_buf(int fd, struct rw_buffer *buf){	uint8 *tmp;	size_t tmp_length, written;	peek_into_buf(buf, &tmp, &tmp_length);	if (tmp_length == 0)		return True;	written = write(fd, tmp, tmp_length);	if (written < 0)		return False;	consumed_from_buf(buf, written);	return True;}static BOOL ldap_append_to_buf(struct ldap_message *msg, struct rw_buffer *buf){	DATA_BLOB blob;	BOOL res;	if (!ldap_encode(msg, &blob))		return False;	res = append_to_buf(buf, blob.data, blob.length);	data_blob_free(&blob);	return res;}static void new_ldap_client(int listen_sock){	struct sockaddr_un sunaddr;	struct winbind_ldap_client *client;	socklen_t len;	int sock;		/* Accept connection */		len = sizeof(sunaddr);	do {		sock = accept(listen_sock, (struct sockaddr *)&sunaddr, &len);	} while (sock == -1 && errno == EINTR);	if (sock == -1)		return;		DEBUG(6,("accepted socket %d\n", sock));		/* Create new connection structure */	client = SMB_MALLOC_P(struct winbind_ldap_client);	if (client == NULL)		return;	ZERO_STRUCTP(client);		client->sock = sock;	client->finished = False;		DLIST_ADD(ldap_clients, client);}static struct ldap_message *get_msg_from_buf(struct rw_buffer *buffer,					     BOOL *error){	uint8 *buf;	int buf_length, msg_length;	DATA_BLOB blob;	ASN1_DATA data;	struct ldap_message *msg;	DEBUG(10,("ldapsrv_recv\n"));	*error = False;	peek_into_buf(buffer, &buf, &buf_length);	if (buf_length < 8) {		/* Arbitrary heuristics: ldap messages are longer than eight		 * bytes, and their tag length fits into the eight bytes */		return NULL;	}	/* LDAP Messages are always SEQUENCES */	if (!asn1_object_length(buf, buf_length, ASN1_SEQUENCE(0),				&msg_length))		goto disconnect;	if (buf_length < msg_length) {		/* Not enough yet */		return NULL;	}	/* We've got a complete LDAP request in the in-buffer */	blob.data = buf;	blob.length = msg_length;	if (!asn1_load(&data, blob))		goto disconnect;	msg = new_ldap_message();	if ((msg == NULL) || !ldap_decode(&data, msg)) {		asn1_free(&data);		goto disconnect;	}	asn1_free(&data);	consumed_from_buf(buffer, msg_length);	return msg; disconnect:	*error = True;	return NULL;}static int send_msg_to_server(struct ldap_message *msg,			      struct winbind_ldap_server *server){	int cli_messageid;	cli_messageid = msg->messageid;	msg->messageid = ldap_servers->messageid;	if (!ldap_append_to_buf(msg, &ldap_servers->out_buffer))		return -1;	msg->messageid = cli_messageid;	return ldap_servers->messageid++;}static int send_msg(struct ldap_message *msg){	/* This is the scheduling routine that should decide where to send	 * stuff. The first attempt is easy: We only have one server. This	 * will change once we handle referrals etc. */	SMB_ASSERT(ldap_servers != NULL);	if (!ldap_servers->ready)		return -1;	return send_msg_to_server(msg, ldap_servers);}static void fake_bind_response(struct winbind_ldap_client *client,			       int messageid){	struct ldap_message *msg = new_ldap_message();	if (msg == NULL) {		client->finished = True;		return;	}	msg->messageid = messageid;	msg->type = LDAP_TAG_BindResponse;	msg->r.BindResponse.response.resultcode = 0;	msg->r.BindResponse.response.dn = "";	msg->r.BindResponse.response.dn = "";	msg->r.BindResponse.response.errormessage = "";	msg->r.BindResponse.response.referral = "";	ldap_append_to_buf(msg, &client->out_buffer);	destroy_ldap_message(msg);}static int open_ldap_socket(void){	static int fd = -1;	if (fd >= 0)		return fd;	fd = create_pipe_sock(get_winbind_priv_pipe_dir(), "ldapi", 0750);	return fd;}static BOOL do_sigterm = False;static void ldap_termination_handler(int signum){	do_sigterm = True;	sys_select_signal();}static BOOL handled_locally(struct ldap_message *msg,			    struct winbind_ldap_server *server){	struct ldap_Result *r = &msg->r.BindResponse.response;	if (msg->type != LDAP_TAG_BindResponse)		return False;	if (r->resultcode != 0) {		destroy_ldap_message(msg);		server->finished = True;	}	destroy_ldap_message(msg);	server->ready = True;	return True;}static void client_has_data(struct winbind_ldap_client *client){				struct ldap_message *msg;	if (!read_into_buf(client->sock, &client->in_buffer)) {		client->finished = True;		return;	}	while ((msg = get_msg_from_buf(&client->in_buffer,				       &client->finished))) {		struct pending_ldap_message *pending;		if (msg->type == LDAP_TAG_BindRequest) {			fake_bind_response(client, msg->messageid);			destroy_ldap_message(msg);			continue;		}		if (msg->type == LDAP_TAG_UnbindRequest) {			destroy_ldap_message(msg);			client->finished = True;			break;		}		pending = SMB_MALLOC_P(struct pending_ldap_message);		if (pending == NULL)			continue;		pending->msg = msg;		pending->client = client;		pending->our_msgid = send_msg(msg);		if (pending->our_msgid < 0) {			/* could not send */			client->finished = True;			free(pending);		}		DLIST_ADD(pending_messages, pending);	}}static struct ldap_Result *ldap_msg2result(struct ldap_message *msg){	switch(msg->type) {	case LDAP_TAG_BindResponse:		return &msg->r.BindResponse.response;	case LDAP_TAG_SearchResultDone:		return &msg->r.SearchResultDone;	case LDAP_TAG_ModifyResponse:		return &msg->r.ModifyResponse;	case LDAP_TAG_AddResponse:		return &msg->r.AddResponse;	case LDAP_TAG_DelResponse:		return &msg->r.DelResponse;	case LDAP_TAG_ModifyDNResponse:		return &msg->r.ModifyDNResponse;	case LDAP_TAG_CompareResponse:		return &msg->r.CompareResponse;	case LDAP_TAG_ExtendedResponse:		return &msg->r.ExtendedResponse.response;	}	return NULL;}static void server_has_data(struct winbind_ldap_server *server){	struct ldap_message *msg;	if (!read_into_buf(server->sock, &server->in_buffer)) {		server->finished = True;		return;	}	while ((msg = get_msg_from_buf(&server->in_buffer,				       &server->finished))) {		struct pending_ldap_message *pending;		struct rw_buffer *buf;		struct ldap_Result *res;		if (handled_locally(msg, server))			continue;		res = ldap_msg2result(msg);		if ( (res != NULL) && (res->resultcode == 10) )			DEBUG(5, ("Got Referral %s\n", res->referral));		for (pending = pending_messages;		     pending != NULL;		     pending = pending->next) {			if (pending->our_msgid == msg->messageid)				break;		}		if (pending == NULL) {			talloc_destroy(msg->mem_ctx);			continue;		}		msg->messageid = pending->msg->messageid;		buf = &pending->client->out_buffer;		ldap_append_to_buf(msg, buf);		if ( (msg->type != LDAP_TAG_SearchResultEntry) &&		     (msg->type != LDAP_TAG_SearchResultReference) ) {			destroy_ldap_message(pending->msg);			DLIST_REMOVE(pending_messages,				     pending);			SAFE_FREE(pending);		}		destroy_ldap_message(msg);	}}static void process_ldap_loop(void){	struct winbind_ldap_client *client;	struct winbind_ldap_server *server;	fd_set r_fds, w_fds;	int maxfd, listen_sock, selret;	struct timeval timeout;	/* Free up temporary memory */	lp_talloc_free();	main_loop_talloc_free();	if (do_sigterm) {#if 0		TALLOC_CTX *mem_ctx = talloc_init("describe");		DEBUG(0, ("%s\n", talloc_describe_all(mem_ctx)));		talloc_destroy(mem_ctx);#endif		exit(0);	}	/* Initialise fd lists for select() */	listen_sock = open_ldap_socket();	if (listen_sock == -1) {		perror("open_ldap_socket");		exit(1);	}	maxfd = listen_sock;	FD_ZERO(&r_fds);	FD_ZERO(&w_fds);	FD_SET(listen_sock, &r_fds);	timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;	timeout.tv_usec = 0;	/* Set up client readers and writers */		client = ldap_clients;	while (client != NULL) {		if (client->finished) {			struct winbind_ldap_client *next = client->next;			DLIST_REMOVE(ldap_clients, client);			close(client->sock);			SAFE_FREE(client->in_buffer.data);			SAFE_FREE(client->out_buffer.data);			SAFE_FREE(client);			client = next;			continue;		}		if (client->sock > maxfd)			maxfd = client->sock;		FD_SET(client->sock, &r_fds);		if (client->out_buffer.length > 0)			FD_SET(client->sock, &w_fds);		client = client->next;	}	/* And now the servers */	server = ldap_servers;	while (server != NULL) {		if (server->finished) {			struct winbind_ldap_server *next = server->next;			DLIST_REMOVE(ldap_servers, server);			close(server->sock);			SAFE_FREE(server);			server = next;			continue;		}		if (server->sock > maxfd)			maxfd = server->sock;		FD_SET(server->sock, &r_fds);		if (server->out_buffer.length > 0)			FD_SET(server->sock, &w_fds);		server = server->next;	}	selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);	if (selret == 0)		return;	if (selret == -1 && errno != EINTR) {		perror("select");		exit(1);	}	if (FD_ISSET(listen_sock, &r_fds))		new_ldap_client(listen_sock);	for (client = ldap_clients; client != NULL; client = client->next) {		if (FD_ISSET(client->sock, &r_fds))			client_has_data(client);		if ((!client->finished) && FD_ISSET(client->sock, &w_fds))			write_out_of_buf(client->sock, &client->out_buffer);	}	for (server = ldap_servers; server != NULL; server = server->next) {		if (FD_ISSET(server->sock, &r_fds))			server_has_data(server);		if (!server->finished && FD_ISSET(server->sock, &w_fds))			write_out_of_buf(server->sock, &server->out_buffer);	}}static BOOL setup_ldap_serverconn(void){	char *host;	uint16 port;	BOOL ldaps;	struct hostent *hp;	struct in_addr ip;	TALLOC_CTX *mem_ctx = talloc_init("server");	struct ldap_message *msg;	char *dn, *pw;	ldap_servers = SMB_MALLOC_P(struct winbind_ldap_server);	if ((ldap_servers == NULL) || (mem_ctx == NULL))		return False;	if (!ldap_parse_basic_url(mem_ctx, "ldap://192.168.234.1:3899/",				  &host, &port, &ldaps))		return False;		hp = sys_gethostbyname(host);	if ((hp == NULL) || (hp->h_addr == NULL))		return False;	putip((char *)&ip, (char *)hp->h_addr);	ZERO_STRUCTP(ldap_servers);	ldap_servers->sock = open_socket_out(SOCK_STREAM, &ip, port, 10000);	ldap_servers->messageid = 1;	if (!fetch_ldap_pw(&dn, &pw))		return False;	msg = new_ldap_simple_bind_msg(dn, pw);	SAFE_FREE(dn);	SAFE_FREE(pw);	if (msg == NULL)		return False;	msg->messageid = ldap_servers->messageid++;	ldap_append_to_buf(msg, &ldap_servers->out_buffer);	destroy_ldap_message(msg);	return (ldap_servers->sock >= 0);}void do_ldap_proxy(void){	int ldap_child;	ldap_child = sys_fork();	if (ldap_child != 0)		return;	/* tdb needs special fork handling */	if (tdb_reopen_all() == -1) {		DEBUG(0,("tdb_reopen_all failed.\n"));		_exit(0);	}	if (!message_init()) {		DEBUG(0, ("message_init failed\n"));		_exit(0);	}	CatchSignal(SIGINT, ldap_termination_handler);	CatchSignal(SIGQUIT, ldap_termination_handler);	CatchSignal(SIGTERM, ldap_termination_handler);	if (!setup_ldap_serverconn())		return;	while (1)		process_ldap_loop();	return;}

⌨️ 快捷键说明

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