LCOV - code coverage report
Current view: top level - source3/libads - sasl.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 272 431 63.1 %
Date: 2024-02-28 12:06:22 Functions: 10 10 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             : #include "lib/util/asn1.h"
      31             : 
      32             : #ifdef HAVE_LDAP
      33             : 
      34        1606 : static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
      35             :                                        uint8_t *buf, uint32_t len)
      36             : {
      37           0 :         struct gensec_security *gensec_security =
      38        1606 :                 talloc_get_type_abort(wrap->wrap_private_data,
      39             :                 struct gensec_security);
      40           0 :         NTSTATUS nt_status;
      41           0 :         DATA_BLOB unwrapped, wrapped;
      42        1606 :         TALLOC_CTX *frame = talloc_stackframe();
      43             : 
      44        1606 :         unwrapped = data_blob_const(buf, len);
      45             : 
      46        1606 :         nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
      47        1606 :         if (!NT_STATUS_IS_OK(nt_status)) {
      48           0 :                 TALLOC_FREE(frame);
      49           0 :                 return ADS_ERROR_NT(nt_status);
      50             :         }
      51             : 
      52        1606 :         if ((wrap->out.size - 4) < wrapped.length) {
      53           0 :                 TALLOC_FREE(frame);
      54           0 :                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
      55             :         }
      56             : 
      57             :         /* copy the wrapped blob to the right location */
      58        1606 :         memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
      59             : 
      60             :         /* set how many bytes must be written to the underlying socket */
      61        1606 :         wrap->out.left = 4 + wrapped.length;
      62             : 
      63        1606 :         TALLOC_FREE(frame);
      64             : 
      65        1606 :         return ADS_SUCCESS;
      66             : }
      67             : 
      68        1299 : static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
      69             : {
      70           0 :         struct gensec_security *gensec_security =
      71        1299 :                 talloc_get_type_abort(wrap->wrap_private_data,
      72             :                 struct gensec_security);
      73           0 :         NTSTATUS nt_status;
      74           0 :         DATA_BLOB unwrapped, wrapped;
      75        1299 :         TALLOC_CTX *frame = talloc_stackframe();
      76             : 
      77        1299 :         wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
      78             : 
      79        1299 :         nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
      80        1299 :         if (!NT_STATUS_IS_OK(nt_status)) {
      81           0 :                 TALLOC_FREE(frame);
      82           0 :                 return ADS_ERROR_NT(nt_status);
      83             :         }
      84             : 
      85        1299 :         if (wrapped.length < unwrapped.length) {
      86           0 :                 TALLOC_FREE(frame);
      87           0 :                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
      88             :         }
      89             : 
      90             :         /* copy the wrapped blob to the right location */
      91        1299 :         memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
      92             : 
      93             :         /* set how many bytes must be written to the underlying socket */
      94        1299 :         wrap->in.left        = unwrapped.length;
      95        1299 :         wrap->in.ofs = 4;
      96             : 
      97        1299 :         TALLOC_FREE(frame);
      98             : 
      99        1299 :         return ADS_SUCCESS;
     100             : }
     101             : 
     102         307 : static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
     103             : {
     104           0 :         struct gensec_security *gensec_security =
     105         307 :                 talloc_get_type_abort(wrap->wrap_private_data,
     106             :                 struct gensec_security);
     107             : 
     108         307 :         TALLOC_FREE(gensec_security);
     109             : 
     110         307 :         wrap->wrap_ops = NULL;
     111         307 :         wrap->wrap_private_data = NULL;
     112         307 : }
     113             : 
     114             : static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
     115             :         .name           = "gensec",
     116             :         .wrap           = ads_sasl_gensec_wrap,
     117             :         .unwrap         = ads_sasl_gensec_unwrap,
     118             :         .disconnect     = ads_sasl_gensec_disconnect
     119             : };
     120             : 
     121             : /*
     122             :    perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
     123             :    we fit on one socket??)
     124             : */
     125         311 : static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
     126             :                                 const char *sasl,
     127             :                                 enum credentials_use_kerberos krb5_state,
     128             :                                 const char *target_service,
     129             :                                 const char *target_hostname,
     130             :                                 const DATA_BLOB server_blob)
     131             : {
     132         311 :         DATA_BLOB blob_in = data_blob_null;
     133         311 :         DATA_BLOB blob_out = data_blob_null;
     134           0 :         int rc;
     135           0 :         NTSTATUS nt_status;
     136           0 :         ADS_STATUS status;
     137           0 :         struct auth_generic_state *auth_generic_state;
     138         311 :         bool use_spnego_principal = lp_client_use_spnego_principal();
     139         311 :         const char *sasl_list[] = { sasl, NULL };
     140           0 :         NTTIME end_nt_time;
     141         311 :         struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
     142             : 
     143         311 :         nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
     144         311 :         if (!NT_STATUS_IS_OK(nt_status)) {
     145           0 :                 return ADS_ERROR_NT(nt_status);
     146             :         }
     147             : 
     148         311 :         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
     149           0 :                 return ADS_ERROR_NT(nt_status);
     150             :         }
     151         311 :         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
     152           0 :                 return ADS_ERROR_NT(nt_status);
     153             :         }
     154         311 :         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
     155           0 :                 return ADS_ERROR_NT(nt_status);
     156             :         }
     157             : 
     158         311 :         if (server_blob.length == 0) {
     159           1 :                 use_spnego_principal = false;
     160             :         }
     161             : 
     162         311 :         if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
     163           1 :                 use_spnego_principal = false;
     164             :         }
     165             : 
     166         311 :         cli_credentials_set_kerberos_state(auth_generic_state->credentials,
     167             :                                            krb5_state,
     168             :                                            CRED_SPECIFIED);
     169             : 
     170         311 :         if (target_service != NULL) {
     171         311 :                 nt_status = gensec_set_target_service(
     172         311 :                                         auth_generic_state->gensec_security,
     173             :                                         target_service);
     174         311 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     175           0 :                         return ADS_ERROR_NT(nt_status);
     176             :                 }
     177             :         }
     178             : 
     179         311 :         if (target_hostname != NULL) {
     180         311 :                 nt_status = gensec_set_target_hostname(
     181         311 :                                         auth_generic_state->gensec_security,
     182             :                                         target_hostname);
     183         311 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     184           0 :                         return ADS_ERROR_NT(nt_status);
     185             :                 }
     186             :         }
     187             : 
     188         311 :         if (target_service != NULL && target_hostname != NULL) {
     189         311 :                 use_spnego_principal = false;
     190             :         }
     191             : 
     192         311 :         switch (wrap->wrap_type) {
     193         311 :         case ADS_SASLWRAP_TYPE_SEAL:
     194         311 :                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
     195         311 :                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
     196         311 :                 break;
     197           0 :         case ADS_SASLWRAP_TYPE_SIGN:
     198           0 :                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
     199           0 :                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
     200             :                 } else {
     201             :                         /*
     202             :                          * windows servers are broken with sign only,
     203             :                          * so we let the NTLMSSP backend to seal here,
     204             :                          * via GENSEC_FEATURE_LDAP_STYLE.
     205             :                          */
     206           0 :                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
     207           0 :                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
     208             :                 }
     209           0 :                 break;
     210           0 :         case ADS_SASLWRAP_TYPE_PLAIN:
     211           0 :                 break;
     212             :         }
     213             : 
     214         311 :         nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
     215             :                                                       sasl_list);
     216         311 :         if (!NT_STATUS_IS_OK(nt_status)) {
     217           0 :                 return ADS_ERROR_NT(nt_status);
     218             :         }
     219             : 
     220         311 :         rc = LDAP_SASL_BIND_IN_PROGRESS;
     221         311 :         if (use_spnego_principal) {
     222           0 :                 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
     223           0 :                 if (blob_in.length == 0) {
     224           0 :                         TALLOC_FREE(auth_generic_state);
     225           0 :                         return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
     226             :                 }
     227             :         } else {
     228         311 :                 blob_in = data_blob_null;
     229             :         }
     230         311 :         blob_out = data_blob_null;
     231             : 
     232         308 :         while (true) {
     233         619 :                 struct berval cred, *scred = NULL;
     234             : 
     235         619 :                 nt_status = gensec_update(auth_generic_state->gensec_security,
     236             :                                           talloc_tos(), blob_in, &blob_out);
     237         619 :                 data_blob_free(&blob_in);
     238         619 :                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
     239         311 :                     && !NT_STATUS_IS_OK(nt_status))
     240             :                 {
     241           4 :                         TALLOC_FREE(auth_generic_state);
     242           4 :                         data_blob_free(&blob_out);
     243           4 :                         return ADS_ERROR_NT(nt_status);
     244             :                 }
     245             : 
     246         615 :                 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
     247         307 :                         break;
     248             :                 }
     249             : 
     250         308 :                 cred.bv_val = (char *)blob_out.data;
     251         308 :                 cred.bv_len = blob_out.length;
     252         308 :                 scred = NULL;
     253         308 :                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
     254         308 :                 data_blob_free(&blob_out);
     255         308 :                 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
     256           0 :                         if (scred) {
     257           0 :                                 ber_bvfree(scred);
     258             :                         }
     259             : 
     260           0 :                         TALLOC_FREE(auth_generic_state);
     261           0 :                         return ADS_ERROR(rc);
     262             :                 }
     263         308 :                 if (scred) {
     264         308 :                         blob_in = data_blob_talloc(talloc_tos(),
     265             :                                                    scred->bv_val,
     266             :                                                    scred->bv_len);
     267         308 :                         if (blob_in.length != scred->bv_len) {
     268           0 :                                 ber_bvfree(scred);
     269           0 :                                 TALLOC_FREE(auth_generic_state);
     270           0 :                                 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
     271             :                         }
     272         308 :                         ber_bvfree(scred);
     273             :                 } else {
     274           0 :                         blob_in = data_blob_null;
     275             :                 }
     276         308 :                 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
     277           0 :                         break;
     278             :                 }
     279             :         }
     280             : 
     281         307 :         data_blob_free(&blob_in);
     282         307 :         data_blob_free(&blob_out);
     283             : 
     284         307 :         if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
     285           0 :                 bool ok;
     286             : 
     287         307 :                 ok = gensec_have_feature(auth_generic_state->gensec_security,
     288             :                                          GENSEC_FEATURE_SEAL);
     289         307 :                 if (!ok) {
     290           0 :                         DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
     291           0 :                         TALLOC_FREE(auth_generic_state);
     292           0 :                         return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
     293             :                 }
     294             : 
     295         307 :                 ok = gensec_have_feature(auth_generic_state->gensec_security,
     296             :                                          GENSEC_FEATURE_SIGN);
     297         307 :                 if (!ok) {
     298           0 :                         DEBUG(0,("The gensec feature signing request, but unavailable\n"));
     299           0 :                         TALLOC_FREE(auth_generic_state);
     300           0 :                         return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
     301             :                 }
     302             : 
     303           0 :         } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
     304           0 :                 bool ok;
     305             : 
     306           0 :                 ok = gensec_have_feature(auth_generic_state->gensec_security,
     307             :                                          GENSEC_FEATURE_SIGN);
     308           0 :                 if (!ok) {
     309           0 :                         DEBUG(0,("The gensec feature signing request, but unavailable\n"));
     310           0 :                         TALLOC_FREE(auth_generic_state);
     311           0 :                         return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
     312             :                 }
     313             :         }
     314             : 
     315         307 :         ads->auth.tgs_expire = LONG_MAX;
     316         307 :         end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
     317         307 :         if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
     318           0 :                 struct timeval tv;
     319         306 :                 nttime_to_timeval(&tv, end_nt_time);
     320         306 :                 ads->auth.tgs_expire = tv.tv_sec;
     321             :         }
     322             : 
     323         307 :         if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
     324           0 :                 size_t max_wrapped =
     325         307 :                         gensec_max_wrapped_size(auth_generic_state->gensec_security);
     326         307 :                 wrap->out.max_unwrapped =
     327         307 :                         gensec_max_input_size(auth_generic_state->gensec_security);
     328             : 
     329         307 :                 wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
     330             :                 /*
     331             :                  * Note that we have to truncate this to 0x2C
     332             :                  * (taken from a capture with LDAP unbind), as the
     333             :                  * signature size is not constant for Kerberos with
     334             :                  * arcfour-hmac-md5.
     335             :                  */
     336         307 :                 wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
     337         307 :                 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
     338         307 :                 status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
     339             :                                                  &ads_sasl_gensec_ops,
     340         307 :                                                  auth_generic_state->gensec_security);
     341         307 :                 if (!ADS_ERR_OK(status)) {
     342           0 :                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
     343             :                                 ads_errstr(status)));
     344           0 :                         TALLOC_FREE(auth_generic_state);
     345           0 :                         return status;
     346             :                 }
     347             :                 /* Only keep the gensec_security element around long-term */
     348         307 :                 talloc_steal(NULL, auth_generic_state->gensec_security);
     349             :         }
     350         307 :         TALLOC_FREE(auth_generic_state);
     351             : 
     352         307 :         return ADS_ERROR(rc);
     353             : }
     354             : 
     355             : #ifdef HAVE_KRB5
     356             : struct ads_service_principal {
     357             :         char *service;
     358             :         char *hostname;
     359             :         char *string;
     360             : };
     361             : 
     362         312 : static void ads_free_service_principal(struct ads_service_principal *p)
     363             : {
     364         312 :         SAFE_FREE(p->service);
     365         312 :         SAFE_FREE(p->hostname);
     366         312 :         SAFE_FREE(p->string);
     367         312 :         ZERO_STRUCTP(p);
     368         312 : }
     369             : 
     370         312 : static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
     371             :                                    char **service,
     372             :                                    char **hostname,
     373             :                                    char **principal)
     374             : {
     375         312 :         ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
     376         312 :         char *princ = NULL;
     377           0 :         TALLOC_CTX *frame;
     378         312 :         char *server = NULL;
     379         312 :         char *realm = NULL;
     380           0 :         int rc;
     381             : 
     382         312 :         frame = talloc_stackframe();
     383         312 :         if (frame == NULL) {
     384           0 :                 return ADS_ERROR(LDAP_NO_MEMORY);
     385             :         }
     386             : 
     387         312 :         if (ads->server.realm && ads->server.ldap_server) {
     388         150 :                 server = strlower_talloc(frame, ads->server.ldap_server);
     389         150 :                 if (server == NULL) {
     390           0 :                         goto out;
     391             :                 }
     392             : 
     393         150 :                 realm = strupper_talloc(frame, ads->server.realm);
     394         150 :                 if (realm == NULL) {
     395           0 :                         goto out;
     396             :                 }
     397             : 
     398             :                 /*
     399             :                  * If we got a name which is bigger than a NetBIOS name,
     400             :                  * but isn't a FQDN, create one.
     401             :                  */
     402         150 :                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
     403           0 :                         char *dnsdomain;
     404             : 
     405           0 :                         dnsdomain = strlower_talloc(frame, ads->server.realm);
     406           0 :                         if (dnsdomain == NULL) {
     407           0 :                                 goto out;
     408             :                         }
     409             : 
     410           0 :                         server = talloc_asprintf(frame,
     411             :                                                  "%s.%s",
     412             :                                                  server, dnsdomain);
     413           0 :                         if (server == NULL) {
     414           0 :                                 goto out;
     415             :                         }
     416             :                 }
     417         162 :         } else if (ads->config.realm && ads->config.ldap_server_name) {
     418         162 :                 server = strlower_talloc(frame, ads->config.ldap_server_name);
     419         162 :                 if (server == NULL) {
     420           0 :                         goto out;
     421             :                 }
     422             : 
     423         162 :                 realm = strupper_talloc(frame, ads->config.realm);
     424         162 :                 if (realm == NULL) {
     425           0 :                         goto out;
     426             :                 }
     427             : 
     428             :                 /*
     429             :                  * If we got a name which is bigger than a NetBIOS name,
     430             :                  * but isn't a FQDN, create one.
     431             :                  */
     432         162 :                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
     433           0 :                         char *dnsdomain;
     434             : 
     435           0 :                         dnsdomain = strlower_talloc(frame, ads->server.realm);
     436           0 :                         if (dnsdomain == NULL) {
     437           0 :                                 goto out;
     438             :                         }
     439             : 
     440           0 :                         server = talloc_asprintf(frame,
     441             :                                                  "%s.%s",
     442             :                                                  server, dnsdomain);
     443           0 :                         if (server == NULL) {
     444           0 :                                 goto out;
     445             :                         }
     446             :                 }
     447             :         }
     448             : 
     449         312 :         if (server == NULL || realm == NULL) {
     450           0 :                 goto out;
     451             :         }
     452             : 
     453         312 :         *service = SMB_STRDUP("ldap");
     454         312 :         if (*service == NULL) {
     455           0 :                 status = ADS_ERROR(LDAP_PARAM_ERROR);
     456           0 :                 goto out;
     457             :         }
     458         312 :         *hostname = SMB_STRDUP(server);
     459         312 :         if (*hostname == NULL) {
     460           0 :                 SAFE_FREE(*service);
     461           0 :                 status = ADS_ERROR(LDAP_PARAM_ERROR);
     462           0 :                 goto out;
     463             :         }
     464         312 :         rc = asprintf(&princ, "ldap/%s@%s", server, realm);
     465         312 :         if (rc == -1 || princ == NULL) {
     466           0 :                 SAFE_FREE(*service);
     467           0 :                 SAFE_FREE(*hostname);
     468           0 :                 status = ADS_ERROR(LDAP_PARAM_ERROR);
     469           0 :                 goto out;
     470             :         }
     471             : 
     472         312 :         *principal = princ;
     473             : 
     474         312 :         status = ADS_SUCCESS;
     475         312 : out:
     476         312 :         TALLOC_FREE(frame);
     477         312 :         return status;
     478             : }
     479             : 
     480         312 : static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
     481             :                                                  struct ads_service_principal *p)
     482             : {
     483           0 :         ADS_STATUS status;
     484             : 
     485         312 :         ZERO_STRUCTP(p);
     486             : 
     487         312 :         status = ads_guess_target(ads,
     488             :                                   &p->service,
     489             :                                   &p->hostname,
     490             :                                   &p->string);
     491         312 :         if (!ADS_ERR_OK(status)) {
     492           0 :                 return status;
     493             :         }
     494             : 
     495         312 :         return ADS_SUCCESS;
     496             : }
     497             : 
     498             : #endif /* HAVE_KRB5 */
     499             : 
     500             : /*
     501             :   parse a negTokenInit packet giving a GUID, a list of supported
     502             :   OIDs (the mechanisms) and a principal name string
     503             : */
     504         312 : static bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
     505             :                                       DATA_BLOB blob,
     506             :                                       char *OIDs[ASN1_MAX_OIDS],
     507             :                                       char **principal,
     508             :                                       DATA_BLOB *secblob)
     509             : {
     510           0 :         int i;
     511         312 :         bool ret = false;
     512           0 :         ASN1_DATA *data;
     513             : 
     514        6552 :         for (i = 0; i < ASN1_MAX_OIDS; i++) {
     515        6240 :                 OIDs[i] = NULL;
     516             :         }
     517             : 
     518         312 :         if (principal) {
     519         312 :                 *principal = NULL;
     520             :         }
     521         312 :         if (secblob) {
     522           0 :                 *secblob = data_blob_null;
     523             :         }
     524             : 
     525         312 :         data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
     526         312 :         if (data == NULL) {
     527           0 :                 return false;
     528             :         }
     529             : 
     530         312 :         if (!asn1_load(data, blob)) goto err;
     531             : 
     532         312 :         if (!asn1_start_tag(data,ASN1_APPLICATION(0))) goto err;
     533             : 
     534         312 :         if (!asn1_check_OID(data,OID_SPNEGO)) goto err;
     535             : 
     536             :         /* negTokenInit  [0]  NegTokenInit */
     537         312 :         if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err;
     538         312 :         if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err;
     539             : 
     540             :         /* mechTypes [0] MechTypeList  OPTIONAL */
     541             : 
     542             :         /* Not really optional, we depend on this to decide
     543             :          * what mechanisms we have to work with. */
     544             : 
     545         312 :         if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err;
     546         312 :         if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err;
     547        1248 :         for (i=0; asn1_tag_remaining(data) > 0 && i < ASN1_MAX_OIDS-1; i++) {
     548         936 :                 if (!asn1_read_OID(data,ctx, &OIDs[i])) {
     549           0 :                         goto err;
     550             :                 }
     551         936 :                 if (asn1_has_error(data)) {
     552           0 :                         goto err;
     553             :                 }
     554             :         }
     555         312 :         OIDs[i] = NULL;
     556         312 :         if (!asn1_end_tag(data)) goto err;
     557         312 :         if (!asn1_end_tag(data)) goto err;
     558             : 
     559             :         /*
     560             :           Win7 + Live Sign-in Assistant attaches a mechToken
     561             :           ASN1_CONTEXT(2) to the negTokenInit packet
     562             :           which breaks our negotiation if we just assume
     563             :           the next tag is ASN1_CONTEXT(3).
     564             :         */
     565             : 
     566         312 :         if (asn1_peek_tag(data, ASN1_CONTEXT(1))) {
     567           0 :                 uint8_t flags;
     568             : 
     569             :                 /* reqFlags [1] ContextFlags  OPTIONAL */
     570           0 :                 if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err;
     571           0 :                 if (!asn1_start_tag(data, ASN1_BIT_STRING)) goto err;
     572           0 :                 while (asn1_tag_remaining(data) > 0) {
     573           0 :                         if (!asn1_read_uint8(data, &flags)) goto err;
     574             :                 }
     575           0 :                 if (!asn1_end_tag(data)) goto err;
     576           0 :                 if (!asn1_end_tag(data)) goto err;
     577             :         }
     578             : 
     579         312 :         if (asn1_peek_tag(data, ASN1_CONTEXT(2))) {
     580           0 :                 DATA_BLOB sblob = data_blob_null;
     581             :                 /* mechToken [2] OCTET STRING  OPTIONAL */
     582           0 :                 if (!asn1_start_tag(data, ASN1_CONTEXT(2))) goto err;
     583           0 :                 if (!asn1_read_OctetString(data, ctx, &sblob)) goto err;
     584           0 :                 if (!asn1_end_tag(data)) {
     585           0 :                         data_blob_free(&sblob);
     586           0 :                         goto err;
     587             :                 }
     588           0 :                 if (secblob) {
     589           0 :                         *secblob = sblob;
     590             :                 } else {
     591           0 :                         data_blob_free(&sblob);
     592             :                 }
     593             :         }
     594             : 
     595         312 :         if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
     596         312 :                 char *princ = NULL;
     597             :                 /* mechListMIC [3] OCTET STRING  OPTIONAL */
     598         312 :                 if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto err;
     599         312 :                 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err;
     600         312 :                 if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto err;
     601         312 :                 if (!asn1_read_GeneralString(data, ctx, &princ)) goto err;
     602         312 :                 if (!asn1_end_tag(data)) goto err;
     603         312 :                 if (!asn1_end_tag(data)) goto err;
     604         312 :                 if (!asn1_end_tag(data)) goto err;
     605         312 :                 if (principal) {
     606         312 :                         *principal = princ;
     607             :                 } else {
     608           0 :                         TALLOC_FREE(princ);
     609             :                 }
     610             :         }
     611             : 
     612         312 :         if (!asn1_end_tag(data)) goto err;
     613         312 :         if (!asn1_end_tag(data)) goto err;
     614             : 
     615         312 :         if (!asn1_end_tag(data)) goto err;
     616             : 
     617         312 :         ret = !asn1_has_error(data);
     618             : 
     619         312 :   err:
     620             : 
     621         312 :         if (asn1_has_error(data)) {
     622           0 :                 int j;
     623           0 :                 if (principal) {
     624           0 :                         TALLOC_FREE(*principal);
     625             :                 }
     626           0 :                 if (secblob) {
     627           0 :                         data_blob_free(secblob);
     628             :                 }
     629           0 :                 for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) {
     630           0 :                         TALLOC_FREE(OIDs[j]);
     631             :                 }
     632             :         }
     633             : 
     634         312 :         asn1_free(data);
     635         312 :         return ret;
     636             : }
     637             : 
     638             : /*
     639             :    this performs a SASL/SPNEGO bind
     640             : */
     641         312 : static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
     642             : {
     643         312 :         TALLOC_CTX *frame = talloc_stackframe();
     644         312 :         struct ads_service_principal p = {0};
     645         312 :         struct berval *scred=NULL;
     646           0 :         int rc, i;
     647           0 :         ADS_STATUS status;
     648         312 :         DATA_BLOB blob = data_blob_null;
     649         312 :         char *given_principal = NULL;
     650           0 :         char *OIDs[ASN1_MAX_OIDS];
     651             : #ifdef HAVE_KRB5
     652         312 :         bool got_kerberos_mechanism = False;
     653             : #endif
     654         312 :         const char *mech = NULL;
     655             : 
     656         312 :         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
     657             : 
     658         312 :         if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
     659           0 :                 status = ADS_ERROR(rc);
     660           0 :                 goto done;
     661             :         }
     662             : 
     663         312 :         blob = data_blob(scred->bv_val, scred->bv_len);
     664             : 
     665         312 :         ber_bvfree(scred);
     666             : 
     667             : #if 0
     668             :         file_save("sasl_spnego.dat", blob.data, blob.length);
     669             : #endif
     670             : 
     671             :         /* the server sent us the first part of the SPNEGO exchange in the negprot
     672             :            reply */
     673         312 :         if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
     674         312 :                         OIDs[0] == NULL) {
     675           0 :                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
     676           0 :                 goto done;
     677             :         }
     678         312 :         TALLOC_FREE(given_principal);
     679             : 
     680             :         /* make sure the server understands kerberos */
     681        1248 :         for (i=0;OIDs[i];i++) {
     682         936 :                 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
     683             : #ifdef HAVE_KRB5
     684         936 :                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
     685         624 :                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
     686         624 :                         got_kerberos_mechanism = True;
     687             :                 }
     688             : #endif
     689         936 :                 talloc_free(OIDs[i]);
     690             :         }
     691             : 
     692         312 :         status = ads_generate_service_principal(ads, &p);
     693         312 :         if (!ADS_ERR_OK(status)) {
     694           0 :                 goto done;
     695             :         }
     696             : 
     697             : #ifdef HAVE_KRB5
     698         312 :         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
     699             :             got_kerberos_mechanism)
     700             :         {
     701         310 :                 mech = "KRB5";
     702             : 
     703         310 :                 if (ads->auth.password == NULL ||
     704         306 :                     ads->auth.password[0] == '\0')
     705             :                 {
     706             : 
     707           4 :                         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
     708             :                                                              CRED_USE_KERBEROS_REQUIRED,
     709           4 :                                                              p.service, p.hostname,
     710             :                                                              blob);
     711           4 :                         if (ADS_ERR_OK(status)) {
     712           0 :                                 ads_free_service_principal(&p);
     713           0 :                                 goto done;
     714             :                         }
     715             : 
     716           4 :                         DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
     717             :                                   "calling kinit\n", ads_errstr(status)));
     718             :                 }
     719             : 
     720         310 :                 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
     721             : 
     722         310 :                 if (ADS_ERR_OK(status)) {
     723         306 :                         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
     724             :                                                         CRED_USE_KERBEROS_REQUIRED,
     725         306 :                                                         p.service, p.hostname,
     726             :                                                         blob);
     727         306 :                         if (!ADS_ERR_OK(status)) {
     728           0 :                                 DBG_ERR("kinit succeeded but "
     729             :                                         "SPNEGO bind with Kerberos failed "
     730             :                                         "for %s/%s - user[%s], realm[%s]: %s\n",
     731             :                                         p.service, p.hostname,
     732             :                                         ads->auth.user_name,
     733             :                                         ads->auth.realm,
     734             :                                         ads_errstr(status));
     735             :                         }
     736             :                 }
     737             : 
     738             :                 /* only fallback to NTLMSSP if allowed */
     739         310 :                 if (ADS_ERR_OK(status) ||
     740           4 :                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
     741         310 :                         goto done;
     742             :                 }
     743             : 
     744           0 :                 DBG_WARNING("SASL bind with Kerberos failed "
     745             :                             "for %s/%s - user[%s], realm[%s]: %s, "
     746             :                             "try to fallback to NTLMSSP\n",
     747             :                             p.service, p.hostname,
     748             :                             ads->auth.user_name,
     749             :                             ads->auth.realm,
     750             :                             ads_errstr(status));
     751             :         }
     752             : #endif
     753             : 
     754             :         /* lets do NTLMSSP ... this has the big advantage that we don't need
     755             :            to sync clocks, and we don't rely on special versions of the krb5
     756             :            library for HMAC_MD4 encryption */
     757           2 :         mech = "NTLMSSP";
     758             : 
     759           2 :         if (!(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
     760           0 :                 DBG_WARNING("We can't use NTLMSSP, it is not allowed.\n");
     761           0 :                 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
     762           0 :                 goto done;
     763             :         }
     764             : 
     765           2 :         if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED) {
     766           1 :                 DBG_WARNING("We can't fallback to NTLMSSP, weak crypto is"
     767             :                             " disallowed.\n");
     768           1 :                 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
     769           1 :                 goto done;
     770             :         }
     771             : 
     772           1 :         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
     773             :                                              CRED_USE_KERBEROS_DISABLED,
     774           1 :                                              p.service, p.hostname,
     775             :                                              data_blob_null);
     776         312 : done:
     777         312 :         if (!ADS_ERR_OK(status)) {
     778           5 :                 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
     779             :                          "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
     780             :                           p.service, p.hostname,
     781             :                           ads->auth.user_name,
     782             :                           ads->auth.realm,
     783             :                           ads_errstr(status)));
     784             :         }
     785         312 :         ads_free_service_principal(&p);
     786         312 :         TALLOC_FREE(frame);
     787         312 :         if (blob.data != NULL) {
     788         312 :                 data_blob_free(&blob);
     789             :         }
     790         312 :         return status;
     791             : }
     792             : 
     793             : /* mapping between SASL mechanisms and functions */
     794             : static struct {
     795             :         const char *name;
     796             :         ADS_STATUS (*fn)(ADS_STRUCT *);
     797             : } sasl_mechanisms[] = {
     798             :         {"GSS-SPNEGO", ads_sasl_spnego_bind},
     799             :         {NULL, NULL}
     800             : };
     801             : 
     802         312 : ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
     803             : {
     804         312 :         const char *attrs[] = {"supportedSASLMechanisms", NULL};
     805           0 :         char **values;
     806           0 :         ADS_STATUS status;
     807           0 :         int i, j;
     808           0 :         LDAPMessage *res;
     809         312 :         struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
     810             : 
     811             :         /* get a list of supported SASL mechanisms */
     812         312 :         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
     813         312 :         if (!ADS_ERR_OK(status)) return status;
     814             : 
     815         312 :         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
     816             : 
     817         312 :         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
     818         312 :                 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
     819           0 :         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
     820           0 :                 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
     821             :         } else {
     822           0 :                 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
     823             :         }
     824             : 
     825             :         /* try our supported mechanisms in order */
     826         312 :         for (i=0;sasl_mechanisms[i].name;i++) {
     827             :                 /* see if the server supports it */
     828         312 :                 for (j=0;values && values[j];j++) {
     829         312 :                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
     830         312 :                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
     831         312 : retry:
     832         312 :                                 status = sasl_mechanisms[i].fn(ads);
     833         312 :                                 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
     834         307 :                                     status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
     835           0 :                                     wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
     836             :                                 {
     837           0 :                                         DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
     838             :                                                  "retrying with signing enabled\n"));
     839           0 :                                         wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
     840           0 :                                         goto retry;
     841             :                                 }
     842         312 :                                 ldap_value_free(values);
     843         312 :                                 ldap_msgfree(res);
     844         312 :                                 return status;
     845             :                         }
     846             :                 }
     847             :         }
     848             : 
     849           0 :         ldap_value_free(values);
     850           0 :         ldap_msgfree(res);
     851           0 :         return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
     852             : }
     853             : 
     854             : #endif /* HAVE_LDAP */
     855             : 

Generated by: LCOV version 1.14