root/source4/ldap_server/ldap_bind.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ldapsrv_BindSimple
  2. ldapsrv_set_sasl
  3. ldapsrv_BindSASL
  4. ldapsrv_BindRequest
  5. ldapsrv_UnbindRequest

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    LDAP server
   4    Copyright (C) Stefan Metzmacher 2004
   5    
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10    
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15    
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #include "includes.h"
  21 #include "ldap_server/ldap_server.h"
  22 #include "auth/auth.h"
  23 #include "libcli/ldap/ldap.h"
  24 #include "smbd/service.h"
  25 #include "lib/ldb/include/ldb.h"
  26 #include "lib/ldb/include/ldb_errors.h"
  27 #include "dsdb/samdb/samdb.h"
  28 #include "auth/gensec/gensec.h"
  29 #include "param/param.h"
  30 
  31 static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
     /* [<][>][^][v][top][bottom][index][help] */
  32 {
  33         struct ldap_BindRequest *req = &call->request->r.BindRequest;
  34         struct ldapsrv_reply *reply;
  35         struct ldap_BindResponse *resp;
  36 
  37         int result;
  38         const char *errstr;
  39         const char *nt4_domain, *nt4_account;
  40 
  41         struct auth_session_info *session_info;
  42 
  43         NTSTATUS status;
  44 
  45         DEBUG(10, ("BindSimple dn: %s\n",req->dn));
  46 
  47         status = crack_auto_name_to_nt4_name(call, call->conn->connection->event.ctx, call->conn->lp_ctx, req->dn, &nt4_domain, &nt4_account);
  48         if (NT_STATUS_IS_OK(status)) {
  49                 status = authenticate_username_pw(call,
  50                                                   call->conn->connection->event.ctx,
  51                                                   call->conn->connection->msg_ctx,
  52                                                   call->conn->lp_ctx,
  53                                                   nt4_domain, nt4_account, 
  54                                                   req->creds.password,
  55                                                   &session_info);
  56         }
  57 
  58         reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse);
  59         if (!reply) {
  60                 return NT_STATUS_NO_MEMORY;
  61         }
  62 
  63         if (NT_STATUS_IS_OK(status)) {
  64                 result = LDAP_SUCCESS;
  65                 errstr = NULL;
  66 
  67                 talloc_free(call->conn->session_info);
  68                 call->conn->session_info = session_info;
  69                 talloc_steal(call->conn, session_info);
  70 
  71                 /* don't leak the old LDB */
  72                 talloc_free(call->conn->ldb);
  73 
  74                 status = ldapsrv_backend_Init(call->conn);              
  75                 
  76                 if (!NT_STATUS_IS_OK(status)) {
  77                         result = LDAP_OPERATIONS_ERROR;
  78                         errstr = talloc_asprintf(reply, "Simple Bind: Failed to advise ldb new credentials: %s", nt_errstr(status));
  79                 }
  80         } else {
  81                 status = auth_nt_status_squash(status);
  82 
  83                 result = LDAP_INVALID_CREDENTIALS;
  84                 errstr = talloc_asprintf(reply, "Simple Bind Failed: %s", nt_errstr(status));
  85         }
  86 
  87         resp = &reply->msg->r.BindResponse;
  88         resp->response.resultcode = result;
  89         resp->response.errormessage = errstr;
  90         resp->response.dn = NULL;
  91         resp->response.referral = NULL;
  92         resp->SASL.secblob = NULL;
  93 
  94         ldapsrv_queue_reply(call, reply);
  95         return NT_STATUS_OK;
  96 }
  97 
  98 struct ldapsrv_sasl_context {
  99         struct ldapsrv_connection *conn;
 100         struct socket_context *sasl_socket;
 101 };
 102 
 103 static void ldapsrv_set_sasl(void *private_data)
     /* [<][>][^][v][top][bottom][index][help] */
 104 {
 105         struct ldapsrv_sasl_context *ctx = talloc_get_type(private_data, struct ldapsrv_sasl_context);
 106         talloc_steal(ctx->conn->connection, ctx->sasl_socket);
 107         talloc_unlink(ctx->conn->connection, ctx->conn->connection->socket);
 108 
 109         ctx->conn->sockets.sasl = ctx->sasl_socket;
 110         ctx->conn->connection->socket = ctx->sasl_socket;
 111         packet_set_socket(ctx->conn->packet, ctx->conn->connection->socket);
 112 }
 113 
 114 static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
     /* [<][>][^][v][top][bottom][index][help] */
 115 {
 116         struct ldap_BindRequest *req = &call->request->r.BindRequest;
 117         struct ldapsrv_reply *reply;
 118         struct ldap_BindResponse *resp;
 119         struct ldapsrv_connection *conn;
 120         int result = 0;
 121         const char *errstr=NULL;
 122         NTSTATUS status = NT_STATUS_OK;
 123 
 124         DEBUG(10, ("BindSASL dn: %s\n",req->dn));
 125 
 126         reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse);
 127         if (!reply) {
 128                 return NT_STATUS_NO_MEMORY;
 129         }
 130         resp = &reply->msg->r.BindResponse;
 131         
 132         conn = call->conn;
 133 
 134         /* 
 135          * TODO: a SASL bind with a different mechanism
 136          *       should cancel an inprogress SASL bind.
 137          *       (see RFC 4513)
 138          */
 139 
 140         if (!conn->gensec) {
 141                 conn->session_info = NULL;
 142 
 143                 status = samba_server_gensec_start(conn,
 144                                                    conn->connection->event.ctx,
 145                                                    conn->connection->msg_ctx,
 146                                                    conn->lp_ctx,
 147                                                    conn->server_credentials,
 148                                                    "ldap",
 149                                                    &conn->gensec);
 150                 if (!NT_STATUS_IS_OK(status)) {
 151                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
 152                         result = LDAP_OPERATIONS_ERROR;
 153                         errstr = talloc_asprintf(reply, "SASL: Failed to start authentication system: %s", 
 154                                                  nt_errstr(status));
 155                 } else {
 156                 
 157                         gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
 158                         gensec_want_feature(conn->gensec, GENSEC_FEATURE_SEAL);
 159                         gensec_want_feature(conn->gensec, GENSEC_FEATURE_ASYNC_REPLIES);
 160                         
 161                         status = gensec_start_mech_by_sasl_name(conn->gensec, req->creds.SASL.mechanism);
 162                         
 163                         if (!NT_STATUS_IS_OK(status)) {
 164                                 DEBUG(1, ("Failed to start GENSEC SASL[%s] server code: %s\n", 
 165                                           req->creds.SASL.mechanism, nt_errstr(status)));
 166                                 result = LDAP_OPERATIONS_ERROR;
 167                                 errstr = talloc_asprintf(reply, "SASL:[%s]: Failed to start authentication backend: %s", 
 168                                                          req->creds.SASL.mechanism, nt_errstr(status));
 169                         }
 170                 }
 171         }
 172 
 173         if (NT_STATUS_IS_OK(status)) {
 174                 DATA_BLOB input = data_blob(NULL, 0);
 175                 DATA_BLOB output = data_blob(NULL, 0);
 176 
 177                 if (req->creds.SASL.secblob) {
 178                         input = *req->creds.SASL.secblob;
 179                 }
 180 
 181                 status = gensec_update(conn->gensec, reply,
 182                                        input, &output);
 183 
 184                 /* Windows 2000 mmc doesn't like secblob == NULL and reports a decoding error */
 185                 resp->SASL.secblob = talloc(reply, DATA_BLOB);
 186                 NT_STATUS_HAVE_NO_MEMORY(resp->SASL.secblob);
 187                 *resp->SASL.secblob = output;
 188         } else {
 189                 resp->SASL.secblob = NULL;
 190         }
 191 
 192         if (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) {
 193                 result = LDAP_SASL_BIND_IN_PROGRESS;
 194                 errstr = NULL;
 195         } else if (NT_STATUS_IS_OK(status)) {
 196                 struct auth_session_info *old_session_info=NULL;
 197                 struct ldapsrv_sasl_context *ctx;
 198 
 199                 result = LDAP_SUCCESS;
 200                 errstr = NULL;
 201 
 202                 ctx = talloc(call, struct ldapsrv_sasl_context); 
 203 
 204                 if (!ctx) {
 205                         status = NT_STATUS_NO_MEMORY;
 206                 } else {
 207                         ctx->conn = conn;
 208                         status = gensec_socket_init(conn->gensec, 
 209                                                     conn->connection,
 210                                                     conn->connection->socket,
 211                                                     conn->connection->event.ctx, 
 212                                                     stream_io_handler_callback,
 213                                                     conn->connection,
 214                                                     &ctx->sasl_socket);
 215                 } 
 216 
 217                 if (!ctx || !NT_STATUS_IS_OK(status)) {
 218                         conn->session_info = old_session_info;
 219                         result = LDAP_OPERATIONS_ERROR;
 220                         errstr = talloc_asprintf(reply, 
 221                                                  "SASL:[%s]: Failed to setup SASL socket: %s", 
 222                                                  req->creds.SASL.mechanism, nt_errstr(status));
 223                 } else {
 224 
 225                         call->send_callback = ldapsrv_set_sasl;
 226                         call->send_private = ctx;
 227                 
 228                         old_session_info = conn->session_info;
 229                         conn->session_info = NULL;
 230                         status = gensec_session_info(conn->gensec, &conn->session_info);
 231                         if (!NT_STATUS_IS_OK(status)) {
 232                                 conn->session_info = old_session_info;
 233                                 result = LDAP_OPERATIONS_ERROR;
 234                                 errstr = talloc_asprintf(reply, 
 235                                                          "SASL:[%s]: Failed to get session info: %s", 
 236                                                          req->creds.SASL.mechanism, nt_errstr(status));
 237                         } else {
 238                                 talloc_free(old_session_info);
 239                                 talloc_steal(conn, conn->session_info);
 240                                 
 241                                 /* don't leak the old LDB */
 242                                 talloc_free(conn->ldb);
 243                                 
 244                                 status = ldapsrv_backend_Init(conn);            
 245                                 
 246                                 if (!NT_STATUS_IS_OK(status)) {
 247                                         result = LDAP_OPERATIONS_ERROR;
 248                                         errstr = talloc_asprintf(reply, 
 249                                                                  "SASL:[%s]: Failed to advise samdb of new credentials: %s", 
 250                                                                  req->creds.SASL.mechanism, 
 251                                                                  nt_errstr(status));
 252                                 }
 253                         }
 254                 }
 255         } else {
 256                 status = auth_nt_status_squash(status);
 257                 if (result == 0) {
 258                         result = LDAP_INVALID_CREDENTIALS;
 259                         errstr = talloc_asprintf(reply, "SASL:[%s]: %s", req->creds.SASL.mechanism, nt_errstr(status));
 260                 }
 261         }
 262 
 263         resp->response.resultcode = result;
 264         resp->response.dn = NULL;
 265         resp->response.errormessage = errstr;
 266         resp->response.referral = NULL;
 267 
 268         ldapsrv_queue_reply(call, reply);
 269         return NT_STATUS_OK;
 270 }
 271 
 272 NTSTATUS ldapsrv_BindRequest(struct ldapsrv_call *call)
     /* [<][>][^][v][top][bottom][index][help] */
 273 {
 274         struct ldap_BindRequest *req = &call->request->r.BindRequest;
 275         struct ldapsrv_reply *reply;
 276         struct ldap_BindResponse *resp;
 277 
 278         /* 
 279          * TODO: we should fail the bind request
 280          *       if there're any pending requests.
 281          *
 282          *       also a simple bind should cancel an
 283          *       inprogress SASL bind.
 284          *       (see RFC 4513)
 285          */
 286         switch (req->mechanism) {
 287                 case LDAP_AUTH_MECH_SIMPLE:
 288                         return ldapsrv_BindSimple(call);
 289                 case LDAP_AUTH_MECH_SASL:
 290                         return ldapsrv_BindSASL(call);
 291         }
 292 
 293         reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse);
 294         if (!reply) {
 295                 return NT_STATUS_NO_MEMORY;
 296         }
 297 
 298         resp = &reply->msg->r.BindResponse;
 299         resp->response.resultcode = 7;
 300         resp->response.dn = NULL;
 301         resp->response.errormessage = talloc_asprintf(reply, "Bad AuthenticationChoice [%d]", req->mechanism);
 302         resp->response.referral = NULL;
 303         resp->SASL.secblob = NULL;
 304 
 305         ldapsrv_queue_reply(call, reply);
 306         return NT_STATUS_OK;
 307 }
 308 
 309 NTSTATUS ldapsrv_UnbindRequest(struct ldapsrv_call *call)
     /* [<][>][^][v][top][bottom][index][help] */
 310 {
 311         DEBUG(10, ("UnbindRequest\n"));
 312         return NT_STATUS_OK;
 313 }

/* [<][>][^][v][top][bottom][index][help] */