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 <talloc.h> 24#include "libcli/ldap/ldap.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 "ldb_wrap.h" 35#include "auth/auth.h" 36#include "param/param.h" 37#include "../lib/tsocket/tsocket.h" 38 39/* 40 handle incoming cldap requests 41*/ 42static void cldapd_request_handler(struct cldap_socket *cldap, 43 void *private_data, 44 struct cldap_incoming *in) 45{ 46 struct cldapd_server *cldapd = talloc_get_type(private_data, 47 struct cldapd_server); 48 struct ldap_SearchRequest *search; 49 50 if (in->ldap_msg->type != LDAP_TAG_SearchRequest) { 51 DEBUG(0,("Invalid CLDAP request type %d from %s\n", 52 in->ldap_msg->type, 53 tsocket_address_string(in->src, in))); 54 cldap_error_reply(cldap, in->ldap_msg->messageid, in->src, 55 LDAP_OPERATIONS_ERROR, "Invalid CLDAP request"); 56 talloc_free(in); 57 return; 58 } 59 60 search = &in->ldap_msg->r.SearchRequest; 61 62 if (strcmp("", search->basedn) != 0) { 63 DEBUG(0,("Invalid CLDAP basedn '%s' from %s\n", 64 search->basedn, 65 tsocket_address_string(in->src, in))); 66 cldap_error_reply(cldap, in->ldap_msg->messageid, in->src, 67 LDAP_OPERATIONS_ERROR, "Invalid CLDAP basedn"); 68 talloc_free(in); 69 return; 70 } 71 72 if (search->scope != LDAP_SEARCH_SCOPE_BASE) { 73 DEBUG(0,("Invalid CLDAP scope %d from %s\n", 74 search->scope, 75 tsocket_address_string(in->src, in))); 76 cldap_error_reply(cldap, in->ldap_msg->messageid, in->src, 77 LDAP_OPERATIONS_ERROR, "Invalid CLDAP scope"); 78 talloc_free(in); 79 return; 80 } 81 82 if (search->num_attributes == 1 && 83 strcasecmp(search->attributes[0], "netlogon") == 0) { 84 cldapd_netlogon_request(cldap, 85 cldapd, 86 in, 87 in->ldap_msg->messageid, 88 search->tree, 89 in->src); 90 talloc_free(in); 91 return; 92 } 93 94 cldapd_rootdse_request(cldap, cldapd, in, 95 in->ldap_msg->messageid, 96 search, in->src); 97 talloc_free(in); 98} 99 100 101/* 102 start listening on the given address 103*/ 104static NTSTATUS cldapd_add_socket(struct cldapd_server *cldapd, struct loadparm_context *lp_ctx, 105 const char *address) 106{ 107 struct cldap_socket *cldapsock; 108 struct tsocket_address *socket_address; 109 NTSTATUS status; 110 int ret; 111 112 ret = tsocket_address_inet_from_strings(cldapd, 113 "ip", 114 address, 115 lp_cldap_port(lp_ctx), 116 &socket_address); 117 if (ret != 0) { 118 status = map_nt_error_from_unix(errno); 119 DEBUG(0,("invalid address %s:%d - %s:%s\n", 120 address, lp_cldap_port(lp_ctx), 121 gai_strerror(ret), nt_errstr(status))); 122 return status; 123 } 124 125 /* listen for unicasts on the CLDAP port (389) */ 126 status = cldap_socket_init(cldapd, 127 cldapd->task->event_ctx, 128 socket_address, 129 NULL, 130 &cldapsock); 131 if (!NT_STATUS_IS_OK(status)) { 132 DEBUG(0,("Failed to bind to %s - %s\n", 133 tsocket_address_string(socket_address, socket_address), 134 nt_errstr(status))); 135 talloc_free(socket_address); 136 return status; 137 } 138 talloc_free(socket_address); 139 140 cldap_set_incoming_handler(cldapsock, cldapd_request_handler, cldapd); 141 142 return NT_STATUS_OK; 143} 144 145/* 146 setup our listening sockets on the configured network interfaces 147*/ 148static NTSTATUS cldapd_startup_interfaces(struct cldapd_server *cldapd, struct loadparm_context *lp_ctx, 149 struct interface *ifaces) 150{ 151 int num_interfaces; 152 TALLOC_CTX *tmp_ctx = talloc_new(cldapd); 153 NTSTATUS status; 154 int i; 155 156 num_interfaces = iface_count(ifaces); 157 158 /* if we are allowing incoming packets from any address, then 159 we need to bind to the wildcard address */ 160 if (!lp_bind_interfaces_only(lp_ctx)) { 161 status = cldapd_add_socket(cldapd, lp_ctx, "0.0.0.0"); 162 NT_STATUS_NOT_OK_RETURN(status); 163 } 164 165 /* now we have to also listen on the specific interfaces, 166 so that replies always come from the right IP */ 167 for (i=0; i<num_interfaces; i++) { 168 const char *address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i)); 169 status = cldapd_add_socket(cldapd, lp_ctx, address); 170 NT_STATUS_NOT_OK_RETURN(status); 171 } 172 173 talloc_free(tmp_ctx); 174 175 return NT_STATUS_OK; 176} 177 178/* 179 startup the cldapd task 180*/ 181static void cldapd_task_init(struct task_server *task) 182{ 183 struct cldapd_server *cldapd; 184 NTSTATUS status; 185 struct interface *ifaces; 186 187 load_interfaces(task, lp_interfaces(task->lp_ctx), &ifaces); 188 189 if (iface_count(ifaces) == 0) { 190 task_server_terminate(task, "cldapd: no network interfaces configured", false); 191 return; 192 } 193 194 switch (lp_server_role(task->lp_ctx)) { 195 case ROLE_STANDALONE: 196 task_server_terminate(task, "cldap_server: no CLDAP server required in standalone configuration", 197 false); 198 return; 199 case ROLE_DOMAIN_MEMBER: 200 task_server_terminate(task, "cldap_server: no CLDAP server required in member server configuration", 201 false); 202 return; 203 case ROLE_DOMAIN_CONTROLLER: 204 /* Yes, we want an CLDAP server */ 205 break; 206 } 207 208 task_server_set_title(task, "task[cldapd]"); 209 210 cldapd = talloc(task, struct cldapd_server); 211 if (cldapd == NULL) { 212 task_server_terminate(task, "cldapd: out of memory", true); 213 return; 214 } 215 216 cldapd->task = task; 217 cldapd->samctx = samdb_connect(cldapd, task->event_ctx, task->lp_ctx, system_session(cldapd, task->lp_ctx)); 218 if (cldapd->samctx == NULL) { 219 task_server_terminate(task, "cldapd failed to open samdb", true); 220 return; 221 } 222 223 /* start listening on the configured network interfaces */ 224 status = cldapd_startup_interfaces(cldapd, task->lp_ctx, ifaces); 225 if (!NT_STATUS_IS_OK(status)) { 226 task_server_terminate(task, "cldapd failed to setup interfaces", true); 227 return; 228 } 229 230 irpc_add_name(task->msg_ctx, "cldap_server"); 231} 232 233 234/* 235 register ourselves as a available server 236*/ 237NTSTATUS server_service_cldapd_init(void) 238{ 239 return register_server_service("cldap", cldapd_task_init); 240} 241