r25026: Move param/param.h out of includes.h
[jelmer/samba4-debian.git] / source / cldap_server / cldap_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    CLDAP server task
5
6    Copyright (C) Andrew Tridgell        2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "libcli/ldap/ldap.h"
24 #include "lib/socket/socket.h"
25 #include "lib/messaging/irpc.h"
26 #include "smbd/service_task.h"
27 #include "smbd/service.h"
28 #include "cldap_server/cldap_server.h"
29 #include "system/network.h"
30 #include "lib/socket/netif.h"
31 #include "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "db_wrap.h"
35 #include "auth/auth.h"
36 #include "param/param.h"
37
38 /*
39   handle incoming cldap requests
40 */
41 static void cldapd_request_handler(struct cldap_socket *cldap, 
42                                    struct ldap_message *ldap_msg, 
43                                    struct socket_address *src)
44 {
45         struct ldap_SearchRequest *search;
46         if (ldap_msg->type != LDAP_TAG_SearchRequest) {
47                 DEBUG(0,("Invalid CLDAP request type %d from %s:%d\n", 
48                          ldap_msg->type, src->addr, src->port));
49                 cldap_error_reply(cldap, ldap_msg->messageid, src,
50                                   LDAP_OPERATIONS_ERROR, "Invalid CLDAP request");
51                 return;
52         }
53
54         search = &ldap_msg->r.SearchRequest;
55
56         if (strcmp("", search->basedn) != 0) {
57                 DEBUG(0,("Invalid CLDAP basedn '%s' from %s:%d\n", 
58                          search->basedn, src->addr, src->port));
59                 cldap_error_reply(cldap, ldap_msg->messageid, src,
60                                   LDAP_OPERATIONS_ERROR, "Invalid CLDAP basedn");
61                 return;
62         }
63
64         if (search->scope != LDAP_SEARCH_SCOPE_BASE) {
65                 DEBUG(0,("Invalid CLDAP scope %d from %s:%d\n", 
66                          search->scope, src->addr, src->port));
67                 cldap_error_reply(cldap, ldap_msg->messageid, src,
68                                   LDAP_OPERATIONS_ERROR, "Invalid CLDAP scope");
69                 return;
70         }
71
72         if (search->num_attributes == 1 &&
73             strcasecmp(search->attributes[0], "netlogon") == 0) {
74                 cldapd_netlogon_request(cldap, ldap_msg->messageid,
75                                         search->tree, src);
76                 return;
77         }
78
79         cldapd_rootdse_request(cldap, ldap_msg->messageid,
80                                search, src);
81 }
82
83
84 /*
85   start listening on the given address
86 */
87 static NTSTATUS cldapd_add_socket(struct cldapd_server *cldapd, const char *address)
88 {
89         struct cldap_socket *cldapsock;
90         struct socket_address *socket_address;
91         NTSTATUS status;
92
93         /* listen for unicasts on the CLDAP port (389) */
94         cldapsock = cldap_socket_init(cldapd, cldapd->task->event_ctx);
95         NT_STATUS_HAVE_NO_MEMORY(cldapsock);
96
97         socket_address = socket_address_from_strings(cldapsock, cldapsock->sock->backend_name, 
98                                                      address, lp_cldap_port());
99         if (!socket_address) {
100                 talloc_free(cldapsock);
101                 return NT_STATUS_NO_MEMORY;
102         }
103
104         status = socket_listen(cldapsock->sock, socket_address, 0, 0);
105         if (!NT_STATUS_IS_OK(status)) {
106                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
107                          address, lp_cldap_port(), nt_errstr(status)));
108                 talloc_free(cldapsock);
109                 return status;
110         }
111
112         talloc_free(socket_address);
113
114         cldap_set_incoming_handler(cldapsock, cldapd_request_handler, cldapd);
115
116         return NT_STATUS_OK;
117 }
118
119
120 /*
121   setup our listening sockets on the configured network interfaces
122 */
123 static NTSTATUS cldapd_startup_interfaces(struct cldapd_server *cldapd)
124 {
125         int num_interfaces = iface_count();
126         TALLOC_CTX *tmp_ctx = talloc_new(cldapd);
127         NTSTATUS status;
128
129         /* if we are allowing incoming packets from any address, then
130            we need to bind to the wildcard address */
131         if (!lp_bind_interfaces_only()) {
132                 status = cldapd_add_socket(cldapd, "0.0.0.0");
133                 NT_STATUS_NOT_OK_RETURN(status);
134         } else {
135                 int i;
136
137                 for (i=0; i<num_interfaces; i++) {
138                         const char *address = talloc_strdup(tmp_ctx, iface_n_ip(i));
139                         status = cldapd_add_socket(cldapd, address);
140                         NT_STATUS_NOT_OK_RETURN(status);
141                 }
142         }
143
144         talloc_free(tmp_ctx);
145
146         return NT_STATUS_OK;
147 }
148
149 /*
150   startup the cldapd task
151 */
152 static void cldapd_task_init(struct task_server *task)
153 {
154         struct cldapd_server *cldapd;
155         NTSTATUS status;
156
157         if (iface_count() == 0) {
158                 task_server_terminate(task, "cldapd: no network interfaces configured");
159                 return;
160         }
161
162         task_server_set_title(task, "task[cldapd]");
163
164         cldapd = talloc(task, struct cldapd_server);
165         if (cldapd == NULL) {
166                 task_server_terminate(task, "cldapd: out of memory");
167                 return;
168         }
169
170         cldapd->task = task;
171         cldapd->samctx = samdb_connect(cldapd, anonymous_session(cldapd));
172         if (cldapd->samctx == NULL) {
173                 task_server_terminate(task, "cldapd failed to open samdb");
174                 return;
175         }
176
177         /* start listening on the configured network interfaces */
178         status = cldapd_startup_interfaces(cldapd);
179         if (!NT_STATUS_IS_OK(status)) {
180                 task_server_terminate(task, "cldapd failed to setup interfaces");
181                 return;
182         }
183
184         irpc_add_name(task->msg_ctx, "cldap_server");
185 }
186
187
188 /*
189   initialise the cldapd server
190  */
191 static NTSTATUS cldapd_init(struct event_context *event_ctx, const struct model_ops *model_ops)
192 {
193         return task_server_startup(event_ctx, model_ops, cldapd_task_init);
194 }
195
196
197 /*
198   register ourselves as a available server
199 */
200 NTSTATUS server_service_cldapd_init(void)
201 {
202         return register_server_service("cldap", cldapd_init);
203 }