LCOV - code coverage report
Current view: top level - source3/lib - tldap_gensec_bind.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 105 181 58.0 %
Date: 2024-02-28 12:06:22 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  * Gensec based tldap auth
       4             :  * Copyright (C) Volker Lendecke 2015
       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 "tldap_gensec_bind.h"
      21             : #include "tldap_util.h"
      22             : #include "lib/util/tevent_unix.h"
      23             : #include "lib/util/talloc_stack.h"
      24             : #include "lib/util/samba_util.h"
      25             : #include "lib/util/debug.h"
      26             : #include "auth/gensec/gensec.h"
      27             : #include "auth/gensec/gensec_internal.h" /* TODO: remove this */
      28             : #include "lib/param/param.h"
      29             : #include "source4/auth/gensec/gensec_tstream.h"
      30             : 
      31             : struct tldap_gensec_bind_state {
      32             :         struct tevent_context *ev;
      33             :         struct tldap_context *ctx;
      34             :         struct cli_credentials *creds;
      35             :         const char *target_service;
      36             :         const char *target_hostname;
      37             :         const char *target_principal;
      38             :         struct loadparm_context *lp_ctx;
      39             :         uint32_t gensec_features;
      40             : 
      41             :         bool first;
      42             :         struct gensec_security *gensec;
      43             :         NTSTATUS gensec_status;
      44             :         DATA_BLOB gensec_output;
      45             : };
      46             : 
      47             : static void tldap_gensec_bind_got_mechs(struct tevent_req *subreq);
      48             : static void tldap_gensec_update_done(struct tldap_gensec_bind_state *state,
      49             :                                 struct tevent_req *subreq);
      50             : static void tldap_gensec_bind_done(struct tevent_req *subreq);
      51             : 
      52           2 : static struct tevent_req *tldap_gensec_bind_send(
      53             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
      54             :         struct tldap_context *ctx, struct cli_credentials *creds,
      55             :         const char *target_service, const char *target_hostname,
      56             :         const char *target_principal, struct loadparm_context *lp_ctx,
      57             :         uint32_t gensec_features)
      58             : {
      59           0 :         struct tevent_req *req, *subreq;
      60           0 :         struct tldap_gensec_bind_state *state;
      61             : 
      62           2 :         const char *attrs[] = { "supportedSASLMechanisms" };
      63             : 
      64           2 :         req = tevent_req_create(mem_ctx, &state,
      65             :                                 struct tldap_gensec_bind_state);
      66           2 :         if (req == NULL) {
      67           0 :                 return NULL;
      68             :         }
      69           2 :         state->ev = ev;
      70           2 :         state->ctx = ctx;
      71           2 :         state->creds = creds;
      72           2 :         state->target_service = target_service;
      73           2 :         state->target_hostname = target_hostname;
      74           2 :         state->target_principal = target_principal;
      75           2 :         state->lp_ctx = lp_ctx;
      76           2 :         state->gensec_features = gensec_features;
      77           2 :         state->first = true;
      78             : 
      79           2 :         subreq = tldap_search_all_send(
      80           2 :                 state, state->ev, state->ctx, "", TLDAP_SCOPE_BASE,
      81             :                 "(objectclass=*)", attrs, ARRAY_SIZE(attrs),
      82             :                 false, NULL, 0, NULL, 0, 0, 1 /* sizelimit */, 0);
      83           2 :         if (tevent_req_nomem(subreq, req)) {
      84           0 :                 return tevent_req_post(req, ev);
      85             :         }
      86           2 :         tevent_req_set_callback(subreq, tldap_gensec_bind_got_mechs, req);
      87           2 :         return req;
      88             : }
      89             : 
      90           2 : static void tldap_gensec_bind_got_mechs(struct tevent_req *subreq)
      91             : {
      92           2 :         struct tevent_req *req = tevent_req_callback_data(
      93             :                 subreq, struct tevent_req);
      94           2 :         struct tldap_gensec_bind_state *state = tevent_req_data(
      95             :                 req, struct tldap_gensec_bind_state);
      96           0 :         struct tldap_message **msgs, *msg, *result;
      97           0 :         struct tldap_attribute *attribs, *attrib;
      98           0 :         int num_attribs;
      99           0 :         size_t num_msgs;
     100           0 :         TLDAPRC rc;
     101           0 :         int i;
     102           0 :         bool ok;
     103           0 :         const char **sasl_mechs;
     104           0 :         NTSTATUS status;
     105             : 
     106           2 :         rc = tldap_search_all_recv(subreq, state, &msgs, &result);
     107           2 :         TALLOC_FREE(subreq);
     108           2 :         if (tevent_req_ldap_error(req, rc)) {
     109           0 :                 return;
     110             :         }
     111             : 
     112             :         /*
     113             :          * TODO: Inspect "Result"
     114             :          */
     115             : 
     116           2 :         num_msgs = talloc_array_length(msgs);
     117           2 :         if (num_msgs != 1) {
     118           0 :                 DBG_DEBUG("num_msgs = %zu\n", num_msgs);
     119           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     120           0 :                 return;
     121             :         }
     122           2 :         msg = msgs[0];
     123             : 
     124           2 :         ok = tldap_entry_attributes(msg, &attribs, &num_attribs);
     125           2 :         if (!ok) {
     126           0 :                 DBG_DEBUG("tldap_entry_attributes failed\n");
     127           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     128           0 :                 return;
     129             :         }
     130             : 
     131           2 :         if (num_attribs != 1) {
     132           0 :                 DBG_DEBUG("num_attribs = %d\n", num_attribs);
     133           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     134           0 :                 return;
     135             :         }
     136           2 :         attrib = &attribs[0];
     137             : 
     138           2 :         sasl_mechs = talloc_array(state, const char *, attrib->num_values+1);
     139           2 :         if (tevent_req_nomem(sasl_mechs, req)) {
     140           0 :                 return;
     141             :         }
     142             : 
     143           8 :         for (i=0; i<attrib->num_values; i++) {
     144           6 :                 DATA_BLOB *v = &attrib->values[i];
     145           0 :                 size_t len;
     146             : 
     147           6 :                 ok = convert_string_talloc(sasl_mechs, CH_UTF8, CH_UNIX,
     148           6 :                                            v->data, v->length,
     149           6 :                                            &sasl_mechs[i], &len);
     150           6 :                 if (!ok) {
     151           0 :                         DBG_DEBUG("convert_string_talloc failed\n");
     152           0 :                         tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     153           0 :                         return;
     154             :                 }
     155             :         }
     156           2 :         sasl_mechs[attrib->num_values] = NULL;
     157             : 
     158           2 :         gensec_init();
     159             : 
     160           2 :         status = gensec_client_start(
     161             :                 state, &state->gensec,
     162             :                 lpcfg_gensec_settings(state, state->lp_ctx));
     163           2 :         if (!NT_STATUS_IS_OK(status)) {
     164           0 :                 DBG_DEBUG("gensec_client_start failed: %s\n",
     165             :                           nt_errstr(status));
     166           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     167           0 :                 return;
     168             :         }
     169             : 
     170           2 :         status = gensec_set_credentials(state->gensec, state->creds);
     171           2 :         if (!NT_STATUS_IS_OK(status)) {
     172           0 :                 DBG_DEBUG("gensec_set_credentials failed: %s\n",
     173             :                           nt_errstr(status));
     174           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     175           0 :                 return;
     176             :         }
     177             : 
     178           2 :         status = gensec_set_target_service(state->gensec,
     179             :                                            state->target_service);
     180           2 :         if (!NT_STATUS_IS_OK(status)) {
     181           0 :                 DBG_DEBUG("gensec_set_target_service failed: %s\n",
     182             :                           nt_errstr(status));
     183           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     184           0 :                 return;
     185             :         }
     186             : 
     187           2 :         if (state->target_hostname != NULL) {
     188           2 :                 status = gensec_set_target_hostname(state->gensec,
     189             :                                                     state->target_hostname);
     190           2 :                 if (!NT_STATUS_IS_OK(status)) {
     191           0 :                         DBG_DEBUG("gensec_set_target_hostname failed: %s\n",
     192             :                                   nt_errstr(status));
     193           0 :                         tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     194           0 :                         return;
     195             :                 }
     196             :         }
     197             : 
     198           2 :         if (state->target_principal != NULL) {
     199           0 :                 status = gensec_set_target_principal(state->gensec,
     200             :                                                      state->target_principal);
     201           0 :                 if (!NT_STATUS_IS_OK(status)) {
     202           0 :                         DBG_DEBUG("gensec_set_target_principal failed: %s\n",
     203             :                                   nt_errstr(status));
     204           0 :                         tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     205           0 :                         return;
     206             :                 }
     207             :         }
     208             : 
     209           2 :         gensec_want_feature(state->gensec, state->gensec_features);
     210             : 
     211           2 :         status = gensec_start_mech_by_sasl_list(state->gensec, sasl_mechs);
     212           2 :         if (!NT_STATUS_IS_OK(status)) {
     213           0 :                 DBG_DEBUG("gensec_start_mech_by_sasl_list failed: %s\n",
     214             :                           nt_errstr(status));
     215           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     216           0 :                 return;
     217             :         }
     218             : 
     219           2 :         state->gensec_status = gensec_update(state->gensec, state,
     220             :                                                 data_blob_null,
     221             :                                                 &state->gensec_output);
     222           2 :         tldap_gensec_update_done(state, req);
     223             : }
     224             : 
     225           6 : static void tldap_gensec_update_done(struct tldap_gensec_bind_state *state,
     226             :                                         struct tevent_req *req)
     227             : {
     228           0 :         struct tevent_req *subreq;
     229             : 
     230           6 :         if (!NT_STATUS_IS_OK(state->gensec_status) &&
     231           4 :             !NT_STATUS_EQUAL(state->gensec_status,
     232             :                              NT_STATUS_MORE_PROCESSING_REQUIRED)) {
     233           0 :                 DBG_DEBUG("gensec_update failed: %s\n",
     234             :                           nt_errstr(state->gensec_status));
     235           0 :                 tevent_req_ldap_error(req, TLDAP_INVALID_CREDENTIALS);
     236           0 :                 return;
     237             :         }
     238             : 
     239           6 :         if (NT_STATUS_IS_OK(state->gensec_status) &&
     240           2 :             (state->gensec_output.length == 0)) {
     241             : 
     242           2 :                 if (state->first) {
     243           0 :                         tevent_req_ldap_error(req, TLDAP_INVALID_CREDENTIALS);
     244             :                 } else {
     245           2 :                         tevent_req_done(req);
     246             :                 }
     247           2 :                 return;
     248             :         }
     249             : 
     250           4 :         state->first = false;
     251             : 
     252           4 :         subreq = tldap_sasl_bind_send(
     253             :                 state, state->ev, state->ctx, "",
     254           4 :                 state->gensec->ops->sasl_name, &state->gensec_output,
     255             :                 NULL, 0, NULL, 0);
     256           4 :         if (tevent_req_nomem(subreq, req)) {
     257           0 :                 return;
     258             :         }
     259           4 :         tevent_req_set_callback(subreq, tldap_gensec_bind_done, req);
     260             : }
     261             : 
     262           4 : static void tldap_gensec_bind_done(struct tevent_req *subreq)
     263             : {
     264           4 :         struct tevent_req *req = tevent_req_callback_data(
     265             :                 subreq, struct tevent_req);
     266           4 :         struct tldap_gensec_bind_state *state = tevent_req_data(
     267             :                 req, struct tldap_gensec_bind_state);
     268           0 :         DATA_BLOB input;
     269           0 :         TLDAPRC rc;
     270             : 
     271           4 :         rc = tldap_sasl_bind_recv(subreq, state, &input);
     272           4 :         TALLOC_FREE(subreq);
     273           4 :         if (!TLDAP_RC_IS_SUCCESS(rc) &&
     274           2 :             !TLDAP_RC_EQUAL(rc, TLDAP_SASL_BIND_IN_PROGRESS)) {
     275           0 :                 tevent_req_ldap_error(req, rc);
     276           0 :                 return;
     277             :         }
     278             : 
     279           4 :         if (TLDAP_RC_IS_SUCCESS(rc) && NT_STATUS_IS_OK(state->gensec_status)) {
     280           0 :                 tevent_req_done(req);
     281           0 :                 return;
     282             :         }
     283             : 
     284           4 :         state->gensec_status = gensec_update(state->gensec, state,
     285             :                                                 input,
     286             :                                                 &state->gensec_output);
     287           4 :         tldap_gensec_update_done(state, req);
     288             : }
     289             : 
     290           2 : static TLDAPRC tldap_gensec_bind_recv(struct tevent_req *req)
     291             : {
     292           2 :         struct tldap_gensec_bind_state *state = tevent_req_data(
     293             :                 req, struct tldap_gensec_bind_state);
     294           0 :         struct tstream_context *plain, *sec;
     295           0 :         NTSTATUS status;
     296           0 :         TLDAPRC rc;
     297             : 
     298           2 :         if (tevent_req_is_ldap_error(req, &rc)) {
     299           0 :                 return rc;
     300             :         }
     301             : 
     302           2 :         if ((state->gensec_features & GENSEC_FEATURE_SIGN) &&
     303           2 :             !gensec_have_feature(state->gensec, GENSEC_FEATURE_SIGN)) {
     304           0 :                 return TLDAP_OPERATIONS_ERROR;
     305             :         }
     306           2 :         if ((state->gensec_features & GENSEC_FEATURE_SEAL) &&
     307           2 :             !gensec_have_feature(state->gensec, GENSEC_FEATURE_SEAL)) {
     308           0 :                 return TLDAP_OPERATIONS_ERROR;
     309             :         }
     310             : 
     311           2 :         if (!gensec_have_feature(state->gensec, GENSEC_FEATURE_SIGN) &&
     312           0 :             !gensec_have_feature(state->gensec, GENSEC_FEATURE_SEAL)) {
     313           0 :                 return TLDAP_SUCCESS;
     314             :         }
     315             : 
     316             :         /*
     317             :          * The gensec ctx needs to survive as long as the ldap context
     318             :          * lives
     319             :          */
     320           2 :         talloc_steal(state->ctx, state->gensec);
     321             : 
     322           2 :         plain = tldap_get_tstream(state->ctx);
     323             : 
     324           2 :         status = gensec_create_tstream(state->ctx, state->gensec,
     325             :                                        plain, &sec);
     326           2 :         if (!NT_STATUS_IS_OK(status)) {
     327           0 :                 DBG_DEBUG("gensec_create_tstream failed: %s\n",
     328             :                           nt_errstr(status));
     329           0 :                 return TLDAP_OPERATIONS_ERROR;
     330             :         }
     331             : 
     332           2 :         tldap_set_tstream(state->ctx, sec);
     333             : 
     334           2 :         return TLDAP_SUCCESS;
     335             : }
     336             : 
     337           2 : TLDAPRC tldap_gensec_bind(
     338             :         struct tldap_context *ctx, struct cli_credentials *creds,
     339             :         const char *target_service, const char *target_hostname,
     340             :         const char *target_principal, struct loadparm_context *lp_ctx,
     341             :         uint32_t gensec_features)
     342             : {
     343           2 :         TALLOC_CTX *frame = talloc_stackframe();
     344           0 :         struct tevent_context *ev;
     345           0 :         struct tevent_req *req;
     346           2 :         TLDAPRC rc = TLDAP_NO_MEMORY;
     347             : 
     348           2 :         ev = samba_tevent_context_init(frame);
     349           2 :         if (ev == NULL) {
     350           0 :                 goto fail;
     351             :         }
     352           2 :         req = tldap_gensec_bind_send(frame, ev, ctx, creds, target_service,
     353             :                                      target_hostname, target_principal, lp_ctx,
     354             :                                      gensec_features);
     355           2 :         if (req == NULL) {
     356           0 :                 goto fail;
     357             :         }
     358           2 :         if (!tevent_req_poll(req, ev)) {
     359           0 :                 rc = TLDAP_OPERATIONS_ERROR;
     360           0 :                 goto fail;
     361             :         }
     362           2 :         rc = tldap_gensec_bind_recv(req);
     363           2 :  fail:
     364           2 :         TALLOC_FREE(frame);
     365           2 :         return rc;
     366             : }

Generated by: LCOV version 1.14