LCOV - code coverage report
Current view: top level - source3/lib - tldap_gensec_bind.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 108 163 66.3 %
Date: 2024-05-31 13:13:24 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 "replace.h"
      21             : #include "tldap.h"
      22             : #include "tldap_gensec_bind.h"
      23             : #include "auth/credentials/credentials.h"
      24             : #include "lib/util/tevent_unix.h"
      25             : #include "lib/util/talloc_stack.h"
      26             : #include "lib/util/samba_util.h"
      27             : #include "lib/util/debug.h"
      28             : #include "auth/gensec/gensec.h"
      29             : #include "lib/param/param.h"
      30             : #include "source4/auth/gensec/gensec_tstream.h"
      31             : 
      32             : struct tldap_gensec_bind_state {
      33             :         struct tevent_context *ev;
      34             :         struct tldap_context *ctx;
      35             :         struct cli_credentials *creds;
      36             :         const char *target_service;
      37             :         const char *target_hostname;
      38             :         const char *target_principal;
      39             :         struct loadparm_context *lp_ctx;
      40             :         uint32_t gensec_features;
      41             : 
      42             :         bool first;
      43             :         struct gensec_security *gensec;
      44             :         NTSTATUS gensec_status;
      45             :         DATA_BLOB gensec_input;
      46             :         DATA_BLOB gensec_output;
      47             : };
      48             : 
      49             : static void tldap_gensec_update_next(struct tevent_req *req);
      50             : static void tldap_gensec_update_done(struct tevent_req *subreq);
      51             : static void tldap_gensec_bind_done(struct tevent_req *subreq);
      52             : 
      53           8 : struct tevent_req *tldap_gensec_bind_send(
      54             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
      55             :         struct tldap_context *ctx, struct cli_credentials *creds,
      56             :         const char *target_service, const char *target_hostname,
      57             :         const char *target_principal, struct loadparm_context *lp_ctx,
      58             :         uint32_t gensec_features)
      59             : {
      60           8 :         struct tevent_req *req = NULL;
      61           8 :         struct tldap_gensec_bind_state *state = NULL;
      62           8 :         const DATA_BLOB *tls_cb = NULL;
      63           0 :         NTSTATUS status;
      64             : 
      65           8 :         req = tevent_req_create(mem_ctx, &state,
      66             :                                 struct tldap_gensec_bind_state);
      67           8 :         if (req == NULL) {
      68           0 :                 return NULL;
      69             :         }
      70           8 :         state->ev = ev;
      71           8 :         state->ctx = ctx;
      72           8 :         state->creds = creds;
      73           8 :         state->target_service = target_service;
      74           8 :         state->target_hostname = target_hostname;
      75           8 :         state->target_principal = target_principal;
      76           8 :         state->lp_ctx = lp_ctx;
      77           8 :         state->gensec_features = gensec_features;
      78           8 :         state->first = true;
      79             : 
      80           8 :         gensec_init();
      81             : 
      82          16 :         status = gensec_client_start(
      83           8 :                 state, &state->gensec,
      84           8 :                 lpcfg_gensec_settings(state, state->lp_ctx));
      85           8 :         if (!NT_STATUS_IS_OK(status)) {
      86           0 :                 DBG_DEBUG("gensec_client_start failed: %s\n",
      87             :                           nt_errstr(status));
      88           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
      89           0 :                 return tevent_req_post(req, ev);
      90             :         }
      91             : 
      92           8 :         status = gensec_set_credentials(state->gensec, state->creds);
      93           8 :         if (!NT_STATUS_IS_OK(status)) {
      94           0 :                 DBG_DEBUG("gensec_set_credentials failed: %s\n",
      95             :                           nt_errstr(status));
      96           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
      97           0 :                 return tevent_req_post(req, ev);
      98             :         }
      99             : 
     100           8 :         status = gensec_set_target_service(state->gensec,
     101           8 :                                            state->target_service);
     102           8 :         if (!NT_STATUS_IS_OK(status)) {
     103           0 :                 DBG_DEBUG("gensec_set_target_service failed: %s\n",
     104             :                           nt_errstr(status));
     105           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     106           0 :                 return tevent_req_post(req, ev);
     107             :         }
     108             : 
     109           8 :         if (state->target_hostname != NULL) {
     110           8 :                 status = gensec_set_target_hostname(state->gensec,
     111           8 :                                                     state->target_hostname);
     112           8 :                 if (!NT_STATUS_IS_OK(status)) {
     113           0 :                         DBG_DEBUG("gensec_set_target_hostname failed: %s\n",
     114             :                                   nt_errstr(status));
     115           0 :                         tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     116           0 :                         return tevent_req_post(req, ev);
     117             :                 }
     118             :         }
     119             : 
     120           8 :         if (state->target_principal != NULL) {
     121           0 :                 status = gensec_set_target_principal(state->gensec,
     122           0 :                                                      state->target_principal);
     123           0 :                 if (!NT_STATUS_IS_OK(status)) {
     124           0 :                         DBG_DEBUG("gensec_set_target_principal failed: %s\n",
     125             :                                   nt_errstr(status));
     126           0 :                         tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     127           0 :                         return tevent_req_post(req, ev);
     128             :                 }
     129             :         }
     130             : 
     131           8 :         if (tldap_has_tls_tstream(state->ctx)) {
     132           4 :                 if (gensec_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) {
     133           0 :                         DBG_WARNING("sign or seal not allowed over tls\n");
     134           0 :                         tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     135           0 :                         return tevent_req_post(req, ev);
     136             :                 }
     137             : 
     138           4 :                 tls_cb = tldap_tls_channel_bindings(state->ctx);
     139             :         }
     140             : 
     141           8 :         if (tls_cb != NULL) {
     142           4 :                 uint32_t initiator_addrtype = 0;
     143           4 :                 const DATA_BLOB *initiator_address = NULL;
     144           4 :                 uint32_t acceptor_addrtype = 0;
     145           4 :                 const DATA_BLOB *acceptor_address = NULL;
     146           4 :                 const DATA_BLOB *application_data = tls_cb;
     147             : 
     148           4 :                 status = gensec_set_channel_bindings(state->gensec,
     149             :                                                      initiator_addrtype,
     150             :                                                      initiator_address,
     151             :                                                      acceptor_addrtype,
     152             :                                                      acceptor_address,
     153             :                                                      application_data);
     154           4 :                 if (!NT_STATUS_IS_OK(status)) {
     155           0 :                         DBG_DEBUG("gensec_set_channel_bindings: %s\n",
     156             :                                   nt_errstr(status));
     157           0 :                         tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     158           0 :                         return tevent_req_post(req, ev);
     159             :                 }
     160             :         }
     161             : 
     162           8 :         gensec_want_feature(state->gensec, state->gensec_features);
     163             : 
     164           8 :         status = gensec_start_mech_by_sasl_name(state->gensec, "GSS-SPNEGO");
     165           8 :         if (!NT_STATUS_IS_OK(status)) {
     166           0 :                 DBG_ERR("gensec_start_mech_by_sasl_name(GSS-SPNEGO) failed: %s\n",
     167             :                         nt_errstr(status));
     168           0 :                 tevent_req_ldap_error(req, TLDAP_OPERATIONS_ERROR);
     169           0 :                 return tevent_req_post(req, ev);
     170             :         }
     171             : 
     172           8 :         tldap_gensec_update_next(req);
     173           8 :         if (!tevent_req_is_in_progress(req)) {
     174           0 :                 return tevent_req_post(req, ev);
     175             :         }
     176             : 
     177           8 :         return req;
     178             : }
     179             : 
     180          24 : static void tldap_gensec_update_next(struct tevent_req *req)
     181             : {
     182          24 :         struct tldap_gensec_bind_state *state = tevent_req_data(
     183             :                 req, struct tldap_gensec_bind_state);
     184          24 :         struct tevent_req *subreq = NULL;
     185             : 
     186          24 :         subreq = gensec_update_send(state,
     187             :                                     state->ev,
     188             :                                     state->gensec,
     189             :                                     state->gensec_input);
     190          24 :         if (tevent_req_nomem(subreq, req)) {
     191           0 :                 return;
     192             :         }
     193          24 :         tevent_req_set_callback(subreq,
     194             :                                 tldap_gensec_update_done,
     195             :                                 req);
     196             : }
     197             : 
     198          24 : static void tldap_gensec_update_done(struct tevent_req *subreq)
     199             : {
     200          24 :         struct tevent_req *req = tevent_req_callback_data(
     201             :                 subreq, struct tevent_req);
     202          24 :         struct tldap_gensec_bind_state *state = tevent_req_data(
     203             :                 req, struct tldap_gensec_bind_state);
     204             : 
     205          24 :         state->gensec_status = gensec_update_recv(subreq,
     206             :                                                   state,
     207             :                                                   &state->gensec_output);
     208          24 :         TALLOC_FREE(subreq);
     209          24 :         data_blob_free(&state->gensec_input);
     210          24 :         if (!NT_STATUS_IS_OK(state->gensec_status) &&
     211          16 :             !NT_STATUS_EQUAL(state->gensec_status,
     212             :                              NT_STATUS_MORE_PROCESSING_REQUIRED)) {
     213           0 :                 DBG_DEBUG("gensec_update failed: %s\n",
     214             :                           nt_errstr(state->gensec_status));
     215           0 :                 tevent_req_ldap_error(req, TLDAP_INVALID_CREDENTIALS);
     216           0 :                 return;
     217             :         }
     218             : 
     219          24 :         if (NT_STATUS_IS_OK(state->gensec_status) &&
     220           8 :             (state->gensec_output.length == 0)) {
     221             : 
     222           8 :                 if (state->first) {
     223           0 :                         tevent_req_ldap_error(req, TLDAP_INVALID_CREDENTIALS);
     224             :                 } else {
     225           8 :                         tevent_req_done(req);
     226             :                 }
     227           8 :                 return;
     228             :         }
     229             : 
     230          16 :         state->first = false;
     231             : 
     232          16 :         subreq = tldap_sasl_bind_send(state,
     233             :                                       state->ev,
     234             :                                       state->ctx,
     235             :                                       "",
     236             :                                       "GSS-SPNEGO",
     237             :                                       &state->gensec_output,
     238             :                                       NULL,
     239             :                                       0,
     240             :                                       NULL,
     241             :                                       0);
     242          16 :         if (tevent_req_nomem(subreq, req)) {
     243           0 :                 return;
     244             :         }
     245          16 :         tevent_req_set_callback(subreq, tldap_gensec_bind_done, req);
     246             : }
     247             : 
     248          16 : static void tldap_gensec_bind_done(struct tevent_req *subreq)
     249             : {
     250          16 :         struct tevent_req *req = tevent_req_callback_data(
     251             :                 subreq, struct tevent_req);
     252          16 :         struct tldap_gensec_bind_state *state = tevent_req_data(
     253             :                 req, struct tldap_gensec_bind_state);
     254           0 :         TLDAPRC rc;
     255             : 
     256          16 :         rc = tldap_sasl_bind_recv(subreq, state, &state->gensec_input);
     257          16 :         TALLOC_FREE(subreq);
     258          16 :         data_blob_free(&state->gensec_output);
     259          16 :         if (!TLDAP_RC_IS_SUCCESS(rc) &&
     260           8 :             !TLDAP_RC_EQUAL(rc, TLDAP_SASL_BIND_IN_PROGRESS)) {
     261           0 :                 tevent_req_ldap_error(req, rc);
     262           0 :                 return;
     263             :         }
     264             : 
     265          16 :         if (TLDAP_RC_IS_SUCCESS(rc) && NT_STATUS_IS_OK(state->gensec_status)) {
     266           0 :                 tevent_req_done(req);
     267           0 :                 return;
     268             :         }
     269             : 
     270          16 :         tldap_gensec_update_next(req);
     271             : }
     272             : 
     273           8 : TLDAPRC tldap_gensec_bind_recv(struct tevent_req *req)
     274             : {
     275           8 :         struct tldap_gensec_bind_state *state = tevent_req_data(
     276             :                 req, struct tldap_gensec_bind_state);
     277           0 :         struct tstream_context *plain, *sec;
     278           0 :         NTSTATUS status;
     279           0 :         TLDAPRC rc;
     280             : 
     281           8 :         if (tevent_req_is_ldap_error(req, &rc)) {
     282           0 :                 return rc;
     283             :         }
     284             : 
     285           8 :         if ((state->gensec_features & GENSEC_FEATURE_SIGN) &&
     286           2 :             !gensec_have_feature(state->gensec, GENSEC_FEATURE_SIGN)) {
     287           0 :                 return TLDAP_OPERATIONS_ERROR;
     288             :         }
     289           8 :         if ((state->gensec_features & GENSEC_FEATURE_SEAL) &&
     290           2 :             !gensec_have_feature(state->gensec, GENSEC_FEATURE_SEAL)) {
     291           0 :                 return TLDAP_OPERATIONS_ERROR;
     292             :         }
     293             : 
     294           8 :         if (!gensec_have_feature(state->gensec, GENSEC_FEATURE_SIGN) &&
     295           4 :             !gensec_have_feature(state->gensec, GENSEC_FEATURE_SEAL)) {
     296           4 :                 return TLDAP_SUCCESS;
     297             :         }
     298             : 
     299             :         /*
     300             :          * The gensec ctx needs to survive as long as the ldap context
     301             :          * lives
     302             :          */
     303           4 :         talloc_steal(state->ctx, state->gensec);
     304             : 
     305           4 :         plain = tldap_get_plain_tstream(state->ctx);
     306             : 
     307           4 :         status = gensec_create_tstream(state->ctx, state->gensec,
     308             :                                        plain, &sec);
     309           4 :         if (!NT_STATUS_IS_OK(status)) {
     310           0 :                 DBG_DEBUG("gensec_create_tstream failed: %s\n",
     311             :                           nt_errstr(status));
     312           0 :                 return TLDAP_OPERATIONS_ERROR;
     313             :         }
     314             : 
     315           4 :         tldap_set_gensec_tstream(state->ctx, &sec);
     316             : 
     317           4 :         return TLDAP_SUCCESS;
     318             : }
     319             : 
     320           8 : TLDAPRC tldap_gensec_bind(
     321             :         struct tldap_context *ctx, struct cli_credentials *creds,
     322             :         const char *target_service, const char *target_hostname,
     323             :         const char *target_principal, struct loadparm_context *lp_ctx,
     324             :         uint32_t gensec_features)
     325             : {
     326           8 :         TALLOC_CTX *frame = talloc_stackframe();
     327           0 :         struct tevent_context *ev;
     328           0 :         struct tevent_req *req;
     329           8 :         TLDAPRC rc = TLDAP_NO_MEMORY;
     330             : 
     331           8 :         ev = samba_tevent_context_init(frame);
     332           8 :         if (ev == NULL) {
     333           0 :                 goto fail;
     334             :         }
     335           8 :         req = tldap_gensec_bind_send(frame, ev, ctx, creds, target_service,
     336             :                                      target_hostname, target_principal, lp_ctx,
     337             :                                      gensec_features);
     338           8 :         if (req == NULL) {
     339           0 :                 goto fail;
     340             :         }
     341           8 :         if (!tevent_req_poll(req, ev)) {
     342           0 :                 rc = TLDAP_OPERATIONS_ERROR;
     343           0 :                 goto fail;
     344             :         }
     345           8 :         rc = tldap_gensec_bind_recv(req);
     346           8 :  fail:
     347           8 :         TALLOC_FREE(frame);
     348           8 :         return rc;
     349             : }

Generated by: LCOV version 1.14