LCOV - code coverage report
Current view: top level - source3/libads - sasl.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 233 326 71.5 %
Date: 2021-09-23 10:06:22 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    ads sasl code
       4             :    Copyright (C) Andrew Tridgell 2001
       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 "../libcli/auth/spnego.h"
      22             : #include "auth/credentials/credentials.h"
      23             : #include "auth/gensec/gensec.h"
      24             : #include "auth_generic.h"
      25             : #include "ads.h"
      26             : #include "smb_krb5.h"
      27             : #include "system/gssapi.h"
      28             : #include "lib/param/loadparm.h"
      29             : #include "krb5_env.h"
      30             : 
      31             : #ifdef HAVE_LDAP
      32             : 
      33        1758 : static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
      34             :                                        uint8_t *buf, uint32_t len)
      35             : {
      36         909 :         struct gensec_security *gensec_security =
      37        1758 :                 talloc_get_type_abort(wrap->wrap_private_data,
      38             :                 struct gensec_security);
      39             :         NTSTATUS nt_status;
      40             :         DATA_BLOB unwrapped, wrapped;
      41        1758 :         TALLOC_CTX *frame = talloc_stackframe();
      42             : 
      43        1758 :         unwrapped = data_blob_const(buf, len);
      44             : 
      45        1758 :         nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
      46        1758 :         if (!NT_STATUS_IS_OK(nt_status)) {
      47           0 :                 TALLOC_FREE(frame);
      48           0 :                 return ADS_ERROR_NT(nt_status);
      49             :         }
      50             : 
      51        1758 :         if ((wrap->out.size - 4) < wrapped.length) {
      52           0 :                 TALLOC_FREE(frame);
      53           0 :                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
      54             :         }
      55             : 
      56             :         /* copy the wrapped blob to the right location */
      57        1758 :         memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
      58             : 
      59             :         /* set how many bytes must be written to the underlying socket */
      60        1758 :         wrap->out.left = 4 + wrapped.length;
      61             : 
      62        1758 :         TALLOC_FREE(frame);
      63             : 
      64        1758 :         return ADS_SUCCESS;
      65             : }
      66             : 
      67        1488 : static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
      68             : {
      69         768 :         struct gensec_security *gensec_security =
      70        1488 :                 talloc_get_type_abort(wrap->wrap_private_data,
      71             :                 struct gensec_security);
      72             :         NTSTATUS nt_status;
      73             :         DATA_BLOB unwrapped, wrapped;
      74        1488 :         TALLOC_CTX *frame = talloc_stackframe();
      75             : 
      76        1488 :         wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
      77             : 
      78        1488 :         nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
      79        1488 :         if (!NT_STATUS_IS_OK(nt_status)) {
      80           0 :                 TALLOC_FREE(frame);
      81           0 :                 return ADS_ERROR_NT(nt_status);
      82             :         }
      83             : 
      84        1488 :         if (wrapped.length < unwrapped.length) {
      85           0 :                 TALLOC_FREE(frame);
      86           0 :                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
      87             :         }
      88             : 
      89             :         /* copy the wrapped blob to the right location */
      90        1488 :         memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
      91             : 
      92             :         /* set how many bytes must be written to the underlying socket */
      93        1488 :         wrap->in.left        = unwrapped.length;
      94        1488 :         wrap->in.ofs = 4;
      95             : 
      96        1488 :         TALLOC_FREE(frame);
      97             : 
      98        1488 :         return ADS_SUCCESS;
      99             : }
     100             : 
     101         270 : static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
     102             : {
     103         141 :         struct gensec_security *gensec_security =
     104         270 :                 talloc_get_type_abort(wrap->wrap_private_data,
     105             :                 struct gensec_security);
     106             : 
     107         270 :         TALLOC_FREE(gensec_security);
     108             : 
     109         270 :         wrap->wrap_ops = NULL;
     110         270 :         wrap->wrap_private_data = NULL;
     111         270 : }
     112             : 
     113             : static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
     114             :         .name           = "gensec",
     115             :         .wrap           = ads_sasl_gensec_wrap,
     116             :         .unwrap         = ads_sasl_gensec_unwrap,
     117             :         .disconnect     = ads_sasl_gensec_disconnect
     118             : };
     119             : 
     120             : /* 
     121             :    perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
     122             :    we fit on one socket??)
     123             : */
     124         342 : static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
     125             :                                 const char *sasl,
     126             :                                 enum credentials_use_kerberos krb5_state,
     127             :                                 const char *target_service,
     128             :                                 const char *target_hostname,
     129             :                                 const DATA_BLOB server_blob)
     130             : {
     131         342 :         DATA_BLOB blob_in = data_blob_null;
     132         342 :         DATA_BLOB blob_out = data_blob_null;
     133             :         int rc;
     134             :         NTSTATUS nt_status;
     135             :         ADS_STATUS status;
     136             :         struct auth_generic_state *auth_generic_state;
     137         342 :         bool use_spnego_principal = lp_client_use_spnego_principal();
     138         342 :         const char *sasl_list[] = { sasl, NULL };
     139             :         NTTIME end_nt_time;
     140         342 :         struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
     141             : 
     142         342 :         nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
     143         342 :         if (!NT_STATUS_IS_OK(nt_status)) {
     144           0 :                 return ADS_ERROR_NT(nt_status);
     145             :         }
     146             : 
     147         342 :         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
     148           0 :                 return ADS_ERROR_NT(nt_status);
     149             :         }
     150         342 :         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
     151           0 :                 return ADS_ERROR_NT(nt_status);
     152             :         }
     153         342 :         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
     154           0 :                 return ADS_ERROR_NT(nt_status);
     155             :         }
     156             : 
     157         342 :         if (server_blob.length == 0) {
     158           0 :                 use_spnego_principal = false;
     159             :         }
     160             : 
     161         342 :         if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
     162           0 :                 use_spnego_principal = false;
     163             :         }
     164             : 
     165         342 :         cli_credentials_set_kerberos_state(auth_generic_state->credentials,
     166             :                                            krb5_state,
     167             :                                            CRED_SPECIFIED);
     168             : 
     169         342 :         if (target_service != NULL) {
     170         342 :                 nt_status = gensec_set_target_service(
     171         342 :                                         auth_generic_state->gensec_security,
     172             :                                         target_service);
     173         342 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     174           0 :                         return ADS_ERROR_NT(nt_status);
     175             :                 }
     176             :         }
     177             : 
     178         342 :         if (target_hostname != NULL) {
     179         342 :                 nt_status = gensec_set_target_hostname(
     180         342 :                                         auth_generic_state->gensec_security,
     181             :                                         target_hostname);
     182         342 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     183           0 :                         return ADS_ERROR_NT(nt_status);
     184             :                 }
     185             :         }
     186             : 
     187         342 :         if (target_service != NULL && target_hostname != NULL) {
     188         342 :                 use_spnego_principal = false;
     189             :         }
     190             : 
     191         342 :         switch (wrap->wrap_type) {
     192         104 :         case ADS_SASLWRAP_TYPE_SEAL:
     193         104 :                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
     194         104 :                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
     195         104 :                 break;
     196         238 :         case ADS_SASLWRAP_TYPE_SIGN:
     197         238 :                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
     198           0 :                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
     199             :                 } else {
     200             :                         /*
     201             :                          * windows servers are broken with sign only,
     202             :                          * so we let the NTLMSSP backend to seal here,
     203             :                          * via GENSEC_FEATURE_LDAP_STYLE.
     204             :                          */
     205         238 :                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
     206         238 :                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
     207             :                 }
     208         238 :                 break;
     209           0 :         case ADS_SASLWRAP_TYPE_PLAIN:
     210           0 :                 break;
     211             :         }
     212             : 
     213         342 :         nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
     214             :                                                       sasl_list);
     215         342 :         if (!NT_STATUS_IS_OK(nt_status)) {
     216           0 :                 return ADS_ERROR_NT(nt_status);
     217             :         }
     218             : 
     219         342 :         rc = LDAP_SASL_BIND_IN_PROGRESS;
     220         342 :         if (use_spnego_principal) {
     221           0 :                 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
     222           0 :                 if (blob_in.length == 0) {
     223           0 :                         TALLOC_FREE(auth_generic_state);
     224           0 :                         return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
     225             :                 }
     226             :         } else {
     227         342 :                 blob_in = data_blob_null;
     228             :         }
     229         342 :         blob_out = data_blob_null;
     230             : 
     231         340 :         while (true) {
     232         682 :                 struct berval cred, *scred = NULL;
     233             : 
     234         682 :                 nt_status = gensec_update(auth_generic_state->gensec_security,
     235             :                                           talloc_tos(), blob_in, &blob_out);
     236         682 :                 data_blob_free(&blob_in);
     237         682 :                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
     238         342 :                     && !NT_STATUS_IS_OK(nt_status))
     239             :                 {
     240           2 :                         TALLOC_FREE(auth_generic_state);
     241           2 :                         data_blob_free(&blob_out);
     242           4 :                         return ADS_ERROR_NT(nt_status);
     243             :                 }
     244             : 
     245         680 :                 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
     246         516 :                         break;
     247             :                 }
     248             : 
     249         340 :                 cred.bv_val = (char *)blob_out.data;
     250         340 :                 cred.bv_len = blob_out.length;
     251         340 :                 scred = NULL;
     252         340 :                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
     253         340 :                 data_blob_free(&blob_out);
     254         340 :                 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
     255           0 :                         if (scred) {
     256           0 :                                 ber_bvfree(scred);
     257             :                         }
     258             : 
     259           0 :                         TALLOC_FREE(auth_generic_state);
     260           0 :                         return ADS_ERROR(rc);
     261             :                 }
     262         340 :                 if (scred) {
     263         340 :                         blob_in = data_blob_talloc(talloc_tos(),
     264             :                                                    scred->bv_val,
     265             :                                                    scred->bv_len);
     266         340 :                         if (blob_in.length != scred->bv_len) {
     267           0 :                                 ber_bvfree(scred);
     268           0 :                                 TALLOC_FREE(auth_generic_state);
     269           0 :                                 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
     270             :                         }
     271         340 :                         ber_bvfree(scred);
     272             :                 } else {
     273           0 :                         blob_in = data_blob_null;
     274             :                 }
     275         340 :                 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
     276           0 :                         break;
     277             :                 }
     278             :         }
     279             : 
     280         340 :         data_blob_free(&blob_in);
     281         340 :         data_blob_free(&blob_out);
     282             : 
     283         340 :         if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
     284             :                 bool ok;
     285             : 
     286         104 :                 ok = gensec_have_feature(auth_generic_state->gensec_security,
     287             :                                          GENSEC_FEATURE_SEAL);
     288         104 :                 if (!ok) {
     289           0 :                         DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
     290           0 :                         TALLOC_FREE(auth_generic_state);
     291           0 :                         return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
     292             :                 }
     293             : 
     294         104 :                 ok = gensec_have_feature(auth_generic_state->gensec_security,
     295             :                                          GENSEC_FEATURE_SIGN);
     296         104 :                 if (!ok) {
     297           0 :                         DEBUG(0,("The gensec feature signing request, but unavailable\n"));
     298           0 :                         TALLOC_FREE(auth_generic_state);
     299           0 :                         return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
     300             :                 }
     301             : 
     302         236 :         } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
     303             :                 bool ok;
     304             : 
     305         236 :                 ok = gensec_have_feature(auth_generic_state->gensec_security,
     306             :                                          GENSEC_FEATURE_SIGN);
     307         236 :                 if (!ok) {
     308           0 :                         DEBUG(0,("The gensec feature signing request, but unavailable\n"));
     309           0 :                         TALLOC_FREE(auth_generic_state);
     310           0 :                         return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
     311             :                 }
     312             :         }
     313             : 
     314         340 :         ads->auth.tgs_expire = LONG_MAX;
     315         340 :         end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
     316         340 :         if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
     317             :                 struct timeval tv;
     318         340 :                 nttime_to_timeval(&tv, end_nt_time);
     319         340 :                 ads->auth.tgs_expire = tv.tv_sec;
     320             :         }
     321             : 
     322         340 :         if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
     323         176 :                 size_t max_wrapped =
     324         340 :                         gensec_max_wrapped_size(auth_generic_state->gensec_security);
     325         340 :                 wrap->out.max_unwrapped =
     326         340 :                         gensec_max_input_size(auth_generic_state->gensec_security);
     327             : 
     328         340 :                 wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
     329             :                 /*
     330             :                  * Note that we have to truncate this to 0x2C
     331             :                  * (taken from a capture with LDAP unbind), as the
     332             :                  * signature size is not constant for Kerberos with
     333             :                  * arcfour-hmac-md5.
     334             :                  */
     335         340 :                 wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
     336         340 :                 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
     337         340 :                 status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
     338             :                                                  &ads_sasl_gensec_ops,
     339         340 :                                                  auth_generic_state->gensec_security);
     340         340 :                 if (!ADS_ERR_OK(status)) {
     341           0 :                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
     342             :                                 ads_errstr(status)));
     343           0 :                         TALLOC_FREE(auth_generic_state);
     344           0 :                         return status;
     345             :                 }
     346             :                 /* Only keep the gensec_security element around long-term */
     347         340 :                 talloc_steal(NULL, auth_generic_state->gensec_security);
     348             :         }
     349         340 :         TALLOC_FREE(auth_generic_state);
     350             : 
     351         340 :         return ADS_ERROR(rc);
     352             : }
     353             : 
     354             : #ifdef HAVE_KRB5
     355             : struct ads_service_principal {
     356             :         char *service;
     357             :         char *hostname;
     358             :         char *string;
     359             : };
     360             : 
     361         342 : static void ads_free_service_principal(struct ads_service_principal *p)
     362             : {
     363         342 :         SAFE_FREE(p->service);
     364         342 :         SAFE_FREE(p->hostname);
     365         342 :         SAFE_FREE(p->string);
     366         342 :         ZERO_STRUCTP(p);
     367         342 : }
     368             : 
     369         342 : static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
     370             :                                    char **service,
     371             :                                    char **hostname,
     372             :                                    char **principal)
     373             : {
     374         342 :         ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
     375         342 :         char *princ = NULL;
     376             :         TALLOC_CTX *frame;
     377         342 :         char *server = NULL;
     378         342 :         char *realm = NULL;
     379             :         int rc;
     380             : 
     381         342 :         frame = talloc_stackframe();
     382         342 :         if (frame == NULL) {
     383           0 :                 return ADS_ERROR(LDAP_NO_MEMORY);
     384             :         }
     385             : 
     386         342 :         if (ads->server.realm && ads->server.ldap_server) {
     387         166 :                 server = strlower_talloc(frame, ads->server.ldap_server);
     388         166 :                 if (server == NULL) {
     389           0 :                         goto out;
     390             :                 }
     391             : 
     392         166 :                 realm = strupper_talloc(frame, ads->server.realm);
     393         166 :                 if (realm == NULL) {
     394           0 :                         goto out;
     395             :                 }
     396             : 
     397             :                 /*
     398             :                  * If we got a name which is bigger than a NetBIOS name,
     399             :                  * but isn't a FQDN, create one.
     400             :                  */
     401         253 :                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
     402             :                         char *dnsdomain;
     403             : 
     404           0 :                         dnsdomain = strlower_talloc(frame, ads->server.realm);
     405           0 :                         if (dnsdomain == NULL) {
     406           0 :                                 goto out;
     407             :                         }
     408             : 
     409           0 :                         server = talloc_asprintf(frame,
     410             :                                                  "%s.%s",
     411             :                                                  server, dnsdomain);
     412           0 :                         if (server == NULL) {
     413           0 :                                 goto out;
     414             :                         }
     415             :                 }
     416         176 :         } else if (ads->config.realm && ads->config.ldap_server_name) {
     417         176 :                 server = strlower_talloc(frame, ads->config.ldap_server_name);
     418         176 :                 if (server == NULL) {
     419           0 :                         goto out;
     420             :                 }
     421             : 
     422         176 :                 realm = strupper_talloc(frame, ads->config.realm);
     423         176 :                 if (realm == NULL) {
     424           0 :                         goto out;
     425             :                 }
     426             : 
     427             :                 /*
     428             :                  * If we got a name which is bigger than a NetBIOS name,
     429             :                  * but isn't a FQDN, create one.
     430             :                  */
     431         176 :                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
     432             :                         char *dnsdomain;
     433             : 
     434           0 :                         dnsdomain = strlower_talloc(frame, ads->server.realm);
     435           0 :                         if (dnsdomain == NULL) {
     436           0 :                                 goto out;
     437             :                         }
     438             : 
     439           0 :                         server = talloc_asprintf(frame,
     440             :                                                  "%s.%s",
     441             :                                                  server, dnsdomain);
     442           0 :                         if (server == NULL) {
     443           0 :                                 goto out;
     444             :                         }
     445             :                 }
     446             :         }
     447             : 
     448         520 :         if (server == NULL || realm == NULL) {
     449           0 :                 goto out;
     450             :         }
     451             : 
     452         342 :         *service = SMB_STRDUP("ldap");
     453         342 :         if (*service == NULL) {
     454           0 :                 status = ADS_ERROR(LDAP_PARAM_ERROR);
     455           0 :                 goto out;
     456             :         }
     457         342 :         *hostname = SMB_STRDUP(server);
     458         342 :         if (*hostname == NULL) {
     459           0 :                 SAFE_FREE(*service);
     460           0 :                 status = ADS_ERROR(LDAP_PARAM_ERROR);
     461           0 :                 goto out;
     462             :         }
     463         342 :         rc = asprintf(&princ, "ldap/%s@%s", server, realm);
     464         342 :         if (rc == -1 || princ == NULL) {
     465           0 :                 SAFE_FREE(*service);
     466           0 :                 SAFE_FREE(*hostname);
     467           0 :                 status = ADS_ERROR(LDAP_PARAM_ERROR);
     468           0 :                 goto out;
     469             :         }
     470             : 
     471         342 :         *principal = princ;
     472             : 
     473         342 :         status = ADS_SUCCESS;
     474         342 : out:
     475         342 :         TALLOC_FREE(frame);
     476         342 :         return status;
     477             : }
     478             : 
     479         342 : static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
     480             :                                                  struct ads_service_principal *p)
     481             : {
     482             :         ADS_STATUS status;
     483             : 
     484         342 :         ZERO_STRUCTP(p);
     485             : 
     486         342 :         status = ads_guess_target(ads,
     487             :                                   &p->service,
     488             :                                   &p->hostname,
     489             :                                   &p->string);
     490         342 :         if (!ADS_ERR_OK(status)) {
     491           0 :                 return status;
     492             :         }
     493             : 
     494         342 :         return ADS_SUCCESS;
     495             : }
     496             : 
     497             : #endif /* HAVE_KRB5 */
     498             : 
     499             : /* 
     500             :    this performs a SASL/SPNEGO bind
     501             : */
     502         342 : static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
     503             : {
     504         342 :         TALLOC_CTX *frame = talloc_stackframe();
     505         342 :         struct ads_service_principal p = {0};
     506         342 :         struct berval *scred=NULL;
     507             :         int rc, i;
     508             :         ADS_STATUS status;
     509         342 :         DATA_BLOB blob = data_blob_null;
     510         342 :         char *given_principal = NULL;
     511             :         char *OIDs[ASN1_MAX_OIDS];
     512             : #ifdef HAVE_KRB5
     513         342 :         bool got_kerberos_mechanism = False;
     514             : #endif
     515         342 :         const char *mech = NULL;
     516             : 
     517         342 :         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
     518             : 
     519         342 :         if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
     520           0 :                 status = ADS_ERROR(rc);
     521           0 :                 goto done;
     522             :         }
     523             : 
     524         342 :         blob = data_blob(scred->bv_val, scred->bv_len);
     525             : 
     526         342 :         ber_bvfree(scred);
     527             : 
     528             : #if 0
     529             :         file_save("sasl_spnego.dat", blob.data, blob.length);
     530             : #endif
     531             : 
     532             :         /* the server sent us the first part of the SPNEGO exchange in the negprot 
     533             :            reply */
     534         520 :         if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
     535         342 :                         OIDs[0] == NULL) {
     536           0 :                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
     537           0 :                 goto done;
     538             :         }
     539         342 :         TALLOC_FREE(given_principal);
     540             : 
     541             :         /* make sure the server understands kerberos */
     542        1368 :         for (i=0;OIDs[i];i++) {
     543        1026 :                 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
     544             : #ifdef HAVE_KRB5
     545        1382 :                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
     546         684 :                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
     547         684 :                         got_kerberos_mechanism = True;
     548             :                 }
     549             : #endif
     550        1026 :                 talloc_free(OIDs[i]);
     551             :         }
     552             : 
     553         342 :         status = ads_generate_service_principal(ads, &p);
     554         342 :         if (!ADS_ERR_OK(status)) {
     555           0 :                 goto done;
     556             :         }
     557             : 
     558             : #ifdef HAVE_KRB5
     559         342 :         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
     560             :             got_kerberos_mechanism) 
     561             :         {
     562         342 :                 mech = "KRB5";
     563             : 
     564         518 :                 if (ads->auth.password == NULL ||
     565         340 :                     ads->auth.password[0] == '\0')
     566             :                 {
     567             : 
     568           2 :                         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
     569             :                                                              CRED_USE_KERBEROS_REQUIRED,
     570           2 :                                                              p.service, p.hostname,
     571             :                                                              blob);
     572           2 :                         if (ADS_ERR_OK(status)) {
     573           0 :                                 ads_free_service_principal(&p);
     574           0 :                                 goto done;
     575             :                         }
     576             : 
     577           2 :                         DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
     578             :                                   "calling kinit\n", ads_errstr(status)));
     579             :                 }
     580             : 
     581         342 :                 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
     582             : 
     583         342 :                 if (ADS_ERR_OK(status)) {
     584         340 :                         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
     585             :                                                         CRED_USE_KERBEROS_REQUIRED,
     586         340 :                                                         p.service, p.hostname,
     587             :                                                         blob);
     588         340 :                         if (!ADS_ERR_OK(status)) {
     589           0 :                                 DEBUG(0,("kinit succeeded but "
     590             :                                         "ads_sasl_spnego_gensec_bind(KRB5) failed "
     591             :                                         "for %s/%s with user[%s] realm[%s]: %s\n",
     592             :                                         p.service, p.hostname,
     593             :                                         ads->auth.user_name,
     594             :                                         ads->auth.realm,
     595             :                                         ads_errstr(status)));
     596             :                         }
     597             :                 }
     598             : 
     599             :                 /* only fallback to NTLMSSP if allowed */
     600         522 :                 if (ADS_ERR_OK(status) || 
     601           2 :                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
     602         164 :                         goto done;
     603             :                 }
     604             : 
     605           0 :                 DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
     606             :                          "for %s/%s with user[%s] realm[%s]: %s, "
     607             :                          "fallback to NTLMSSP\n",
     608             :                          p.service, p.hostname,
     609             :                          ads->auth.user_name,
     610             :                          ads->auth.realm,
     611             :                          ads_errstr(status)));
     612             :         }
     613             : #endif
     614             : 
     615             :         /* lets do NTLMSSP ... this has the big advantage that we don't need
     616             :            to sync clocks, and we don't rely on special versions of the krb5 
     617             :            library for HMAC_MD4 encryption */
     618           0 :         mech = "NTLMSSP";
     619           0 :         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
     620             :                                              CRED_USE_KERBEROS_DISABLED,
     621           0 :                                              p.service, p.hostname,
     622             :                                              data_blob_null);
     623         520 : done:
     624         342 :         if (!ADS_ERR_OK(status)) {
     625           2 :                 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
     626             :                          "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
     627             :                           p.service, p.hostname,
     628             :                           ads->auth.user_name,
     629             :                           ads->auth.realm,
     630             :                           ads_errstr(status)));
     631             :         }
     632         342 :         ads_free_service_principal(&p);
     633         342 :         TALLOC_FREE(frame);
     634         342 :         if (blob.data != NULL) {
     635         342 :                 data_blob_free(&blob);
     636             :         }
     637         342 :         return status;
     638             : }
     639             : 
     640             : /* mapping between SASL mechanisms and functions */
     641             : static struct {
     642             :         const char *name;
     643             :         ADS_STATUS (*fn)(ADS_STRUCT *);
     644             : } sasl_mechanisms[] = {
     645             :         {"GSS-SPNEGO", ads_sasl_spnego_bind},
     646             :         {NULL, NULL}
     647             : };
     648             : 
     649         342 : ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
     650             : {
     651         342 :         const char *attrs[] = {"supportedSASLMechanisms", NULL};
     652             :         char **values;
     653             :         ADS_STATUS status;
     654             :         int i, j;
     655             :         LDAPMessage *res;
     656         342 :         struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
     657             : 
     658             :         /* get a list of supported SASL mechanisms */
     659         342 :         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
     660         342 :         if (!ADS_ERR_OK(status)) return status;
     661             : 
     662         342 :         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
     663             : 
     664         342 :         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
     665         104 :                 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
     666         238 :         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
     667         238 :                 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
     668             :         } else {
     669           0 :                 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
     670             :         }
     671             : 
     672             :         /* try our supported mechanisms in order */
     673         342 :         for (i=0;sasl_mechanisms[i].name;i++) {
     674             :                 /* see if the server supports it */
     675         342 :                 for (j=0;values && values[j];j++) {
     676         342 :                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
     677         342 :                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
     678         342 : retry:
     679         342 :                                 status = sasl_mechanisms[i].fn(ads);
     680         518 :                                 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
     681         340 :                                     status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
     682           0 :                                     wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
     683             :                                 {
     684           0 :                                         DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
     685             :                                                  "retrying with signing enabled\n"));
     686           0 :                                         wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
     687           0 :                                         goto retry;
     688             :                                 }
     689         342 :                                 ldap_value_free(values);
     690         342 :                                 ldap_msgfree(res);
     691         342 :                                 return status;
     692             :                         }
     693             :                 }
     694             :         }
     695             : 
     696           0 :         ldap_value_free(values);
     697           0 :         ldap_msgfree(res);
     698           0 :         return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
     699             : }
     700             : 
     701             : #endif /* HAVE_LDAP */
     702             : 

Generated by: LCOV version 1.13