root/source3/libads/sasl.c

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

DEFINITIONS

This source file includes following definitions.
  1. ads_sasl_ntlmssp_wrap
  2. ads_sasl_ntlmssp_unwrap
  3. ads_sasl_ntlmssp_disconnect
  4. ads_sasl_spnego_ntlmssp_bind
  5. ads_sasl_gssapi_wrap
  6. ads_sasl_gssapi_unwrap
  7. ads_sasl_gssapi_disconnect
  8. ads_sasl_spnego_gsskrb5_bind
  9. ads_free_service_principal
  10. ads_generate_service_principal
  11. ads_sasl_spnego_rawkrb5_bind
  12. ads_sasl_spnego_krb5_bind
  13. ads_sasl_spnego_bind
  14. ads_sasl_gssapi_do_bind
  15. ads_sasl_gssapi_bind
  16. ads_sasl_bind

   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 
  22 #ifdef HAVE_LDAP
  23 
  24 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
     /* [<][>][^][v][top][bottom][index][help] */
  25 {
  26         struct ntlmssp_state *ntlmssp_state =
  27                 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
  28         ADS_STATUS status;
  29         NTSTATUS nt_status;
  30         DATA_BLOB sig;
  31         uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
  32 
  33         /* copy the data to the right location */
  34         memcpy(dptr, buf, len);
  35 
  36         /* create the signature and may encrypt the data */
  37         if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
  38                 nt_status = ntlmssp_seal_packet(ntlmssp_state,
  39                                                 dptr, len,
  40                                                 dptr, len,
  41                                                 &sig);
  42         } else {
  43                 nt_status = ntlmssp_sign_packet(ntlmssp_state,
  44                                                 dptr, len,
  45                                                 dptr, len,
  46                                                 &sig);
  47         }
  48         status = ADS_ERROR_NT(nt_status);
  49         if (!ADS_ERR_OK(status)) return status;
  50 
  51         /* copy the signature to the right location */
  52         memcpy(ads->ldap.out.buf + 4,
  53                sig.data, NTLMSSP_SIG_SIZE);
  54 
  55         data_blob_free(&sig);
  56 
  57         /* set how many bytes must be written to the underlying socket */
  58         ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
  59 
  60         return ADS_SUCCESS;
  61 }
  62 
  63 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
  64 {
  65         struct ntlmssp_state *ntlmssp_state =
  66                 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
  67         ADS_STATUS status;
  68         NTSTATUS nt_status;
  69         DATA_BLOB sig;
  70         uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
  71         uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
  72 
  73         /* wrap the signature into a DATA_BLOB */
  74         sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
  75 
  76         /* verify the signature and maybe decrypt the data */
  77         if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
  78                 nt_status = ntlmssp_unseal_packet(ntlmssp_state,
  79                                                   dptr, dlen,
  80                                                   dptr, dlen,
  81                                                   &sig);
  82         } else {
  83                 nt_status = ntlmssp_check_packet(ntlmssp_state,
  84                                                  dptr, dlen,
  85                                                  dptr, dlen,
  86                                                  &sig);
  87         }
  88         status = ADS_ERROR_NT(nt_status);
  89         if (!ADS_ERR_OK(status)) return status;
  90 
  91         /* set the amount of bytes for the upper layer and set the ofs to the data */
  92         ads->ldap.in.left       = dlen;
  93         ads->ldap.in.ofs        = 4 + NTLMSSP_SIG_SIZE;
  94 
  95         return ADS_SUCCESS;
  96 }
  97 
  98 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
  99 {
 100         struct ntlmssp_state *ntlmssp_state =
 101                 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
 102 
 103         ntlmssp_end(&ntlmssp_state);
 104 
 105         ads->ldap.wrap_ops = NULL;
 106         ads->ldap.wrap_private_data = NULL;
 107 }
 108 
 109 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
 110         .name           = "ntlmssp",
 111         .wrap           = ads_sasl_ntlmssp_wrap,
 112         .unwrap         = ads_sasl_ntlmssp_unwrap,
 113         .disconnect     = ads_sasl_ntlmssp_disconnect
 114 };
 115 
 116 /* 
 117    perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
 118    we fit on one socket??)
 119 */
 120 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
 121 {
 122         DATA_BLOB msg1 = data_blob_null;
 123         DATA_BLOB blob = data_blob_null;
 124         DATA_BLOB blob_in = data_blob_null;
 125         DATA_BLOB blob_out = data_blob_null;
 126         struct berval cred, *scred = NULL;
 127         int rc;
 128         NTSTATUS nt_status;
 129         ADS_STATUS status;
 130         int turn = 1;
 131         uint32 features = 0;
 132 
 133         struct ntlmssp_state *ntlmssp_state;
 134 
 135         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
 136                 return ADS_ERROR_NT(nt_status);
 137         }
 138         ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
 139 
 140         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
 141                 return ADS_ERROR_NT(nt_status);
 142         }
 143         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
 144                 return ADS_ERROR_NT(nt_status);
 145         }
 146         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
 147                 return ADS_ERROR_NT(nt_status);
 148         }
 149 
 150         switch (ads->ldap.wrap_type) {
 151         case ADS_SASLWRAP_TYPE_SEAL:
 152                 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
 153                 break;
 154         case ADS_SASLWRAP_TYPE_SIGN:
 155                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
 156                         features = NTLMSSP_FEATURE_SIGN;
 157                 } else {
 158                         /*
 159                          * windows servers are broken with sign only,
 160                          * so we need to use seal here too
 161                          */
 162                         features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
 163                         ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
 164                 }
 165                 break;
 166         case ADS_SASLWRAP_TYPE_PLAIN:
 167                 break;
 168         }
 169 
 170         ntlmssp_want_feature(ntlmssp_state, features);
 171 
 172         blob_in = data_blob_null;
 173 
 174         do {
 175                 nt_status = ntlmssp_update(ntlmssp_state, 
 176                                            blob_in, &blob_out);
 177                 data_blob_free(&blob_in);
 178                 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 
 179                      || NT_STATUS_IS_OK(nt_status))
 180                     && blob_out.length) {
 181                         if (turn == 1) {
 182                                 /* and wrap it in a SPNEGO wrapper */
 183                                 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
 184                         } else {
 185                                 /* wrap it in SPNEGO */
 186                                 msg1 = spnego_gen_auth(blob_out);
 187                         }
 188 
 189                         data_blob_free(&blob_out);
 190 
 191                         cred.bv_val = (char *)msg1.data;
 192                         cred.bv_len = msg1.length;
 193                         scred = NULL;
 194                         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
 195                         data_blob_free(&msg1);
 196                         if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
 197                                 if (scred) {
 198                                         ber_bvfree(scred);
 199                                 }
 200 
 201                                 ntlmssp_end(&ntlmssp_state);
 202                                 return ADS_ERROR(rc);
 203                         }
 204                         if (scred) {
 205                                 blob = data_blob(scred->bv_val, scred->bv_len);
 206                                 ber_bvfree(scred);
 207                         } else {
 208                                 blob = data_blob_null;
 209                         }
 210 
 211                 } else {
 212 
 213                         ntlmssp_end(&ntlmssp_state);
 214                         data_blob_free(&blob_out);
 215                         return ADS_ERROR_NT(nt_status);
 216                 }
 217                 
 218                 if ((turn == 1) && 
 219                     (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
 220                         DATA_BLOB tmp_blob = data_blob_null;
 221                         /* the server might give us back two challenges */
 222                         if (!spnego_parse_challenge(blob, &blob_in, 
 223                                                     &tmp_blob)) {
 224 
 225                                 ntlmssp_end(&ntlmssp_state);
 226                                 data_blob_free(&blob);
 227                                 DEBUG(3,("Failed to parse challenges\n"));
 228                                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 229                         }
 230                         data_blob_free(&tmp_blob);
 231                 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
 232                         if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP, 
 233                                                         &blob_in)) {
 234 
 235                                 ntlmssp_end(&ntlmssp_state);
 236                                 data_blob_free(&blob);
 237                                 DEBUG(3,("Failed to parse auth response\n"));
 238                                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 239                         }
 240                 }
 241                 data_blob_free(&blob);
 242                 data_blob_free(&blob_out);
 243                 turn++;
 244         } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
 245         
 246         /* we have a reference conter on ntlmssp_state, if we are signing
 247            then the state will be kept by the signing engine */
 248 
 249         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
 250                 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
 251                 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
 252                 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
 253                 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
 254                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
 255                 if (!ADS_ERR_OK(status)) {
 256                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
 257                                 ads_errstr(status)));
 258                         ntlmssp_end(&ntlmssp_state);
 259                         return status;
 260                 }
 261         } else {
 262                 ntlmssp_end(&ntlmssp_state);
 263         }
 264 
 265         return ADS_ERROR(rc);
 266 }
 267 
 268 #ifdef HAVE_GSSAPI
 269 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
     /* [<][>][^][v][top][bottom][index][help] */
 270 {
 271         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
 272         ADS_STATUS status;
 273         int gss_rc;
 274         uint32 minor_status;
 275         gss_buffer_desc unwrapped, wrapped;
 276         int conf_req_flag, conf_state;
 277 
 278         unwrapped.value         = buf;
 279         unwrapped.length        = len;
 280 
 281         /* for now request sign and seal */
 282         conf_req_flag   = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
 283 
 284         gss_rc = gss_wrap(&minor_status, context_handle,
 285                           conf_req_flag, GSS_C_QOP_DEFAULT,
 286                           &unwrapped, &conf_state,
 287                           &wrapped);
 288         status = ADS_ERROR_GSS(gss_rc, minor_status);
 289         if (!ADS_ERR_OK(status)) return status;
 290 
 291         if (conf_req_flag && conf_state == 0) {
 292                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
 293         }
 294 
 295         if ((ads->ldap.out.size - 4) < wrapped.length) {
 296                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
 297         }
 298 
 299         /* copy the wrapped blob to the right location */
 300         memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
 301 
 302         /* set how many bytes must be written to the underlying socket */
 303         ads->ldap.out.left = 4 + wrapped.length;
 304 
 305         gss_release_buffer(&minor_status, &wrapped);
 306 
 307         return ADS_SUCCESS;
 308 }
 309 
 310 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
 311 {
 312         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
 313         ADS_STATUS status;
 314         int gss_rc;
 315         uint32 minor_status;
 316         gss_buffer_desc unwrapped, wrapped;
 317         int conf_state;
 318 
 319         wrapped.value   = ads->ldap.in.buf + 4;
 320         wrapped.length  = ads->ldap.in.ofs - 4;
 321 
 322         gss_rc = gss_unwrap(&minor_status, context_handle,
 323                             &wrapped, &unwrapped,
 324                             &conf_state, GSS_C_QOP_DEFAULT);
 325         status = ADS_ERROR_GSS(gss_rc, minor_status);
 326         if (!ADS_ERR_OK(status)) return status;
 327 
 328         if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
 329                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
 330         }
 331 
 332         if (wrapped.length < unwrapped.length) {
 333                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
 334         }
 335 
 336         /* copy the wrapped blob to the right location */
 337         memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
 338 
 339         /* set how many bytes must be written to the underlying socket */
 340         ads->ldap.in.left       = unwrapped.length;
 341         ads->ldap.in.ofs        = 4;
 342 
 343         gss_release_buffer(&minor_status, &unwrapped);
 344 
 345         return ADS_SUCCESS;
 346 }
 347 
 348 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
 349 {
 350         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
 351         uint32 minor_status;
 352 
 353         gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
 354 
 355         ads->ldap.wrap_ops = NULL;
 356         ads->ldap.wrap_private_data = NULL;
 357 }
 358 
 359 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
 360         .name           = "gssapi",
 361         .wrap           = ads_sasl_gssapi_wrap,
 362         .unwrap         = ads_sasl_gssapi_unwrap,
 363         .disconnect     = ads_sasl_gssapi_disconnect
 364 };
 365 
 366 /* 
 367    perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
 368 */
 369 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
     /* [<][>][^][v][top][bottom][index][help] */
 370 {
 371         ADS_STATUS status;
 372         bool ok;
 373         uint32 minor_status;
 374         int gss_rc, rc;
 375         gss_OID_desc krb5_mech_type =
 376         {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
 377         gss_OID mech_type = &krb5_mech_type;
 378         gss_OID actual_mech_type = GSS_C_NULL_OID;
 379         const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
 380         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
 381         gss_buffer_desc input_token, output_token;
 382         uint32 req_flags, ret_flags;
 383         uint32 req_tmp, ret_tmp;
 384         DATA_BLOB unwrapped;
 385         DATA_BLOB wrapped;
 386         struct berval cred, *scred = NULL;
 387 
 388         input_token.value = NULL;
 389         input_token.length = 0;
 390 
 391         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
 392         switch (ads->ldap.wrap_type) {
 393         case ADS_SASLWRAP_TYPE_SEAL:
 394                 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
 395                 break;
 396         case ADS_SASLWRAP_TYPE_SIGN:
 397                 req_flags |= GSS_C_INTEG_FLAG;
 398                 break;
 399         case ADS_SASLWRAP_TYPE_PLAIN:
 400                 break;
 401         }
 402 
 403         /* Note: here we explicit ask for the krb5 mech_type */
 404         gss_rc = gss_init_sec_context(&minor_status,
 405                                       GSS_C_NO_CREDENTIAL,
 406                                       &context_handle,
 407                                       serv_name,
 408                                       mech_type,
 409                                       req_flags,
 410                                       0,
 411                                       NULL,
 412                                       &input_token,
 413                                       &actual_mech_type,
 414                                       &output_token,
 415                                       &ret_flags,
 416                                       NULL);
 417         if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
 418                 status = ADS_ERROR_GSS(gss_rc, minor_status);
 419                 goto failed;
 420         }
 421 
 422         /*
 423          * As some gssapi krb5 mech implementations
 424          * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
 425          * to req_flags internaly, it's not possible to
 426          * use plain or signing only connection via
 427          * the gssapi interface.
 428          *
 429          * Because of this we need to check it the ret_flags
 430          * has more flags as req_flags and correct the value
 431          * of ads->ldap.wrap_type.
 432          *
 433          * I ads->auth.flags has ADS_AUTH_SASL_FORCE
 434          * we need to give an error.
 435          */
 436         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
 437         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
 438 
 439         if (req_tmp == ret_tmp) {
 440                 /* everythings fine... */
 441 
 442         } else if (req_flags & GSS_C_CONF_FLAG) {
 443                 /*
 444                  * here we wanted sealing but didn't got it
 445                  * from the gssapi library
 446                  */
 447                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
 448                 goto failed;
 449 
 450         } else if ((req_flags & GSS_C_INTEG_FLAG) &&
 451                    !(ret_flags & GSS_C_INTEG_FLAG)) {
 452                 /*
 453                  * here we wanted siging but didn't got it
 454                  * from the gssapi library
 455                  */
 456                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
 457                 goto failed;
 458 
 459         } else if (ret_flags & GSS_C_CONF_FLAG) {
 460                 /*
 461                  * here we didn't want sealing
 462                  * but the gssapi library forces it
 463                  * so correct the needed wrap_type if
 464                  * the caller didn't forced siging only
 465                  */
 466                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
 467                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
 468                         goto failed;
 469                 }
 470 
 471                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
 472                 req_flags = ret_flags;
 473 
 474         } else if (ret_flags & GSS_C_INTEG_FLAG) {
 475                 /*
 476                  * here we didn't want signing
 477                  * but the gssapi library forces it
 478                  * so correct the needed wrap_type if
 479                  * the caller didn't forced plain
 480                  */
 481                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
 482                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
 483                         goto failed;
 484                 }
 485 
 486                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
 487                 req_flags = ret_flags;
 488         } else {
 489                 /*
 490                  * This could (should?) not happen
 491                  */
 492                 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
 493                 goto failed;
 494         
 495         }
 496 
 497         /* and wrap that in a shiny SPNEGO wrapper */
 498         unwrapped = data_blob_const(output_token.value, output_token.length);
 499         wrapped = gen_negTokenTarg(spnego_mechs, unwrapped);
 500         gss_release_buffer(&minor_status, &output_token);
 501         if (unwrapped.length > wrapped.length) {
 502                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
 503                 goto failed;
 504         }
 505 
 506         cred.bv_val = (char *)wrapped.data;
 507         cred.bv_len = wrapped.length;
 508 
 509         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, 
 510                               &scred);
 511         data_blob_free(&wrapped);
 512         if (rc != LDAP_SUCCESS) {
 513                 status = ADS_ERROR(rc);
 514                 goto failed;
 515         }
 516 
 517         if (scred) {
 518                 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
 519         } else {
 520                 wrapped = data_blob_null;
 521         }
 522 
 523         ok = spnego_parse_auth_response(wrapped, NT_STATUS_OK,
 524                                         OID_KERBEROS5_OLD,
 525                                         &unwrapped);
 526         if (scred) ber_bvfree(scred);
 527         if (!ok) {
 528                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
 529                 goto failed;
 530         }
 531 
 532         input_token.value       = unwrapped.data;
 533         input_token.length      = unwrapped.length;
 534 
 535         /* 
 536          * As we asked for mutal authentication
 537          * we need to pass the servers response
 538          * to gssapi
 539          */
 540         gss_rc = gss_init_sec_context(&minor_status,
 541                                       GSS_C_NO_CREDENTIAL,
 542                                       &context_handle,
 543                                       serv_name,
 544                                       mech_type,
 545                                       req_flags,
 546                                       0,
 547                                       NULL,
 548                                       &input_token,
 549                                       &actual_mech_type,
 550                                       &output_token,
 551                                       &ret_flags,
 552                                       NULL);
 553         data_blob_free(&unwrapped);
 554         if (gss_rc) {
 555                 status = ADS_ERROR_GSS(gss_rc, minor_status);
 556                 goto failed;
 557         }
 558 
 559         gss_release_buffer(&minor_status, &output_token);
 560 
 561         /*
 562          * If we the sign and seal options
 563          * doesn't match after getting the response
 564          * from the server, we don't want to use the connection
 565          */
 566         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
 567         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
 568 
 569         if (req_tmp != ret_tmp) {
 570                 /* everythings fine... */
 571                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
 572                 goto failed;
 573         }
 574 
 575         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
 576                 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
 577 
 578                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
 579                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
 580                                              GSS_C_QOP_DEFAULT,
 581                                              max_msg_size, &ads->ldap.out.max_unwrapped);
 582                 if (gss_rc) {
 583                         status = ADS_ERROR_GSS(gss_rc, minor_status);
 584                         goto failed;
 585                 }
 586 
 587                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
 588                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
 589                 ads->ldap.in.max_wrapped = max_msg_size;
 590                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
 591                 if (!ADS_ERR_OK(status)) {
 592                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
 593                                 ads_errstr(status)));
 594                         goto failed;
 595                 }
 596                 /* make sure we don't free context_handle */
 597                 context_handle = GSS_C_NO_CONTEXT;
 598         }
 599 
 600         status = ADS_SUCCESS;
 601 
 602 failed:
 603         if (context_handle != GSS_C_NO_CONTEXT)
 604                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
 605         return status;
 606 }
 607 
 608 #endif /* HAVE_GSSAPI */
 609 
 610 #ifdef HAVE_KRB5
 611 struct ads_service_principal {
 612          char *string;
 613 #ifdef HAVE_GSSAPI
 614          gss_name_t name;
 615 #endif
 616 };
 617 
 618 static void ads_free_service_principal(struct ads_service_principal *p)
     /* [<][>][^][v][top][bottom][index][help] */
 619 {
 620         SAFE_FREE(p->string);
 621 
 622 #ifdef HAVE_GSSAPI
 623         if (p->name) {
 624                 uint32 minor_status;
 625                 gss_release_name(&minor_status, &p->name);
 626         }
 627 #endif
 628         ZERO_STRUCTP(p);
 629 }
 630 
 631 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
     /* [<][>][^][v][top][bottom][index][help] */
 632                                                  const char *given_principal,
 633                                                  struct ads_service_principal *p)
 634 {
 635         ADS_STATUS status;
 636 #ifdef HAVE_GSSAPI
 637         gss_buffer_desc input_name;
 638         /* GSS_KRB5_NT_PRINCIPAL_NAME */
 639         gss_OID_desc nt_principal =
 640         {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
 641         uint32 minor_status;
 642         int gss_rc;
 643 #endif
 644 
 645         ZERO_STRUCTP(p);
 646 
 647         /* I've seen a child Windows 2000 domain not send
 648            the principal name back in the first round of
 649            the SASL bind reply.  So we guess based on server
 650            name and realm.  --jerry  */
 651         /* Also try best guess when we get the w2k8 ignore
 652            principal back - gd */
 653 
 654         if (!given_principal ||
 655             strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
 656 
 657                 status = ads_guess_service_principal(ads, &p->string);
 658                 if (!ADS_ERR_OK(status)) {
 659                         return status;
 660                 }
 661         } else {
 662                 p->string = SMB_STRDUP(given_principal);
 663                 if (!p->string) {
 664                         return ADS_ERROR(LDAP_NO_MEMORY);
 665                 }
 666         }
 667 
 668 #ifdef HAVE_GSSAPI
 669         input_name.value = p->string;
 670         input_name.length = strlen(p->string);
 671 
 672         gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
 673         if (gss_rc) {
 674                 ads_free_service_principal(p);
 675                 return ADS_ERROR_GSS(gss_rc, minor_status);
 676         }
 677 #endif
 678 
 679         return ADS_SUCCESS;
 680 }
 681 
 682 /* 
 683    perform a LDAP/SASL/SPNEGO/KRB5 bind
 684 */
 685 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
     /* [<][>][^][v][top][bottom][index][help] */
 686 {
 687         DATA_BLOB blob = data_blob_null;
 688         struct berval cred, *scred = NULL;
 689         DATA_BLOB session_key = data_blob_null;
 690         int rc;
 691 
 692         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
 693                 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
 694         }
 695 
 696         rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
 697                                      &ads->auth.tgs_expire);
 698 
 699         if (rc) {
 700                 return ADS_ERROR_KRB5(rc);
 701         }
 702 
 703         /* now send the auth packet and we should be done */
 704         cred.bv_val = (char *)blob.data;
 705         cred.bv_len = blob.length;
 706 
 707         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
 708 
 709         data_blob_free(&blob);
 710         data_blob_free(&session_key);
 711         if(scred)
 712                 ber_bvfree(scred);
 713 
 714         return ADS_ERROR(rc);
 715 }
 716 
 717 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
     /* [<][>][^][v][top][bottom][index][help] */
 718                                             struct ads_service_principal *p)
 719 {
 720 #ifdef HAVE_GSSAPI
 721         /*
 722          * we only use the gsskrb5 based implementation
 723          * when sasl sign or seal is requested.
 724          *
 725          * This has the following reasons:
 726          * - it's likely that the gssapi krb5 mech implementation
 727          *   doesn't support to negotiate plain connections
 728          * - the ads_sasl_spnego_rawkrb5_bind is more robust
 729          *   against clock skew errors
 730          */
 731         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
 732                 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
 733         }
 734 #endif
 735         return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
 736 }
 737 #endif /* HAVE_KRB5 */
 738 
 739 /* 
 740    this performs a SASL/SPNEGO bind
 741 */
 742 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
 743 {
 744         struct berval *scred=NULL;
 745         int rc, i;
 746         ADS_STATUS status;
 747         DATA_BLOB blob;
 748         char *given_principal = NULL;
 749         char *OIDs[ASN1_MAX_OIDS];
 750 #ifdef HAVE_KRB5
 751         bool got_kerberos_mechanism = False;
 752 #endif
 753 
 754         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
 755 
 756         if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
 757                 status = ADS_ERROR(rc);
 758                 goto failed;
 759         }
 760 
 761         blob = data_blob(scred->bv_val, scred->bv_len);
 762 
 763         ber_bvfree(scred);
 764 
 765 #if 0
 766         file_save("sasl_spnego.dat", blob.data, blob.length);
 767 #endif
 768 
 769         /* the server sent us the first part of the SPNEGO exchange in the negprot 
 770            reply */
 771         if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
 772                 data_blob_free(&blob);
 773                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
 774                 goto failed;
 775         }
 776         data_blob_free(&blob);
 777 
 778         /* make sure the server understands kerberos */
 779         for (i=0;OIDs[i];i++) {
 780                 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
 781 #ifdef HAVE_KRB5
 782                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
 783                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
 784                         got_kerberos_mechanism = True;
 785                 }
 786 #endif
 787                 talloc_free(OIDs[i]);
 788         }
 789         DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
 790 
 791 #ifdef HAVE_KRB5
 792         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
 793             got_kerberos_mechanism) 
 794         {
 795                 struct ads_service_principal p;
 796 
 797                 status = ads_generate_service_principal(ads, given_principal, &p);
 798                 TALLOC_FREE(given_principal);
 799                 if (!ADS_ERR_OK(status)) {
 800                         return status;
 801                 }
 802 
 803                 status = ads_sasl_spnego_krb5_bind(ads, &p);
 804                 if (ADS_ERR_OK(status)) {
 805                         ads_free_service_principal(&p);
 806                         return status;
 807                 }
 808 
 809                 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
 810                           "calling kinit\n", ads_errstr(status)));
 811 
 812                 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
 813 
 814                 if (ADS_ERR_OK(status)) {
 815                         status = ads_sasl_spnego_krb5_bind(ads, &p);
 816                         if (!ADS_ERR_OK(status)) {
 817                                 DEBUG(0,("kinit succeeded but "
 818                                         "ads_sasl_spnego_krb5_bind failed: %s\n",
 819                                         ads_errstr(status)));
 820                         }
 821                 }
 822 
 823                 ads_free_service_principal(&p);
 824 
 825                 /* only fallback to NTLMSSP if allowed */
 826                 if (ADS_ERR_OK(status) || 
 827                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
 828                         return status;
 829                 }
 830         } else
 831 #endif
 832         {
 833                 TALLOC_FREE(given_principal);
 834         }
 835 
 836         /* lets do NTLMSSP ... this has the big advantage that we don't need
 837            to sync clocks, and we don't rely on special versions of the krb5 
 838            library for HMAC_MD4 encryption */
 839         return ads_sasl_spnego_ntlmssp_bind(ads);
 840 
 841 failed:
 842         return status;
 843 }
 844 
 845 #ifdef HAVE_GSSAPI
 846 #define MAX_GSS_PASSES 3
 847 
 848 /* this performs a SASL/gssapi bind
 849    we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
 850    is very dependent on correctly configured DNS whereas
 851    this routine is much less fragile
 852    see RFC2078 and RFC2222 for details
 853 */
 854 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
     /* [<][>][^][v][top][bottom][index][help] */
 855 {
 856         uint32 minor_status;
 857         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
 858         gss_OID mech_type = GSS_C_NULL_OID;
 859         gss_buffer_desc output_token, input_token;
 860         uint32 req_flags, ret_flags;
 861         int conf_state;
 862         struct berval cred;
 863         struct berval *scred = NULL;
 864         int i=0;
 865         int gss_rc, rc;
 866         uint8 *p;
 867         uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
 868         uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
 869         ADS_STATUS status;
 870 
 871         input_token.value = NULL;
 872         input_token.length = 0;
 873 
 874         /*
 875          * Note: here we always ask the gssapi for sign and seal
 876          *       as this is negotiated later after the mutal
 877          *       authentication
 878          */
 879         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
 880 
 881         for (i=0; i < MAX_GSS_PASSES; i++) {
 882                 gss_rc = gss_init_sec_context(&minor_status,
 883                                           GSS_C_NO_CREDENTIAL,
 884                                           &context_handle,
 885                                           serv_name,
 886                                           mech_type,
 887                                           req_flags,
 888                                           0,
 889                                           NULL,
 890                                           &input_token,
 891                                           NULL,
 892                                           &output_token,
 893                                           &ret_flags,
 894                                           NULL);
 895                 if (scred) {
 896                         ber_bvfree(scred);
 897                         scred = NULL;
 898                 }
 899                 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
 900                         status = ADS_ERROR_GSS(gss_rc, minor_status);
 901                         goto failed;
 902                 }
 903 
 904                 cred.bv_val = (char *)output_token.value;
 905                 cred.bv_len = output_token.length;
 906 
 907                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
 908                                       &scred);
 909                 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
 910                         status = ADS_ERROR(rc);
 911                         goto failed;
 912                 }
 913 
 914                 if (output_token.value) {
 915                         gss_release_buffer(&minor_status, &output_token);
 916                 }
 917 
 918                 if (scred) {
 919                         input_token.value = scred->bv_val;
 920                         input_token.length = scred->bv_len;
 921                 } else {
 922                         input_token.value = NULL;
 923                         input_token.length = 0;
 924                 }
 925 
 926                 if (gss_rc == 0) break;
 927         }
 928 
 929         gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
 930                             &conf_state,NULL);
 931         if (scred) {
 932                 ber_bvfree(scred);
 933                 scred = NULL;
 934         }
 935         if (gss_rc) {
 936                 status = ADS_ERROR_GSS(gss_rc, minor_status);
 937                 goto failed;
 938         }
 939 
 940         p = (uint8 *)output_token.value;
 941 
 942 #if 0
 943         file_save("sasl_gssapi.dat", output_token.value, output_token.length);
 944 #endif
 945 
 946         if (p) {
 947                 wrap_type = CVAL(p,0);
 948                 SCVAL(p,0,0);
 949                 max_msg_size = RIVAL(p,0);
 950         }
 951 
 952         gss_release_buffer(&minor_status, &output_token);
 953 
 954         if (!(wrap_type & ads->ldap.wrap_type)) {
 955                 /*
 956                  * the server doesn't supports the wrap
 957                  * type we want :-(
 958                  */
 959                 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
 960                         ads->ldap.wrap_type, wrap_type));
 961                 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
 962                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
 963                 goto failed;
 964         }
 965 
 966         /* 0x58 is the minimum windows accepts */
 967         if (max_msg_size < 0x58) {
 968                 max_msg_size = 0x58;
 969         }
 970 
 971         output_token.length = 4;
 972         output_token.value = SMB_MALLOC(output_token.length);
 973         p = (uint8 *)output_token.value;
 974 
 975         RSIVAL(p,0,max_msg_size);
 976         SCVAL(p,0,ads->ldap.wrap_type);
 977 
 978         /*
 979          * we used to add sprintf("dn:%s", ads->config.bind_path) here.
 980          * but using ads->config.bind_path is the wrong! It should be
 981          * the DN of the user object!
 982          *
 983          * w2k3 gives an error when we send an incorrect DN, but sending nothing
 984          * is ok and matches the information flow used in GSS-SPNEGO.
 985          */
 986 
 987         gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
 988                           &output_token, &conf_state,
 989                           &input_token);
 990         if (gss_rc) {
 991                 status = ADS_ERROR_GSS(gss_rc, minor_status);
 992                 goto failed;
 993         }
 994 
 995         free(output_token.value);
 996 
 997         cred.bv_val = (char *)input_token.value;
 998         cred.bv_len = input_token.length;
 999 
1000         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
1001                               &scred);
1002         gss_release_buffer(&minor_status, &input_token);
1003         status = ADS_ERROR(rc);
1004         if (!ADS_ERR_OK(status)) {
1005                 goto failed;
1006         }
1007 
1008         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1009                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1010                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1011                                              GSS_C_QOP_DEFAULT,
1012                                              max_msg_size, &ads->ldap.out.max_unwrapped);
1013                 if (gss_rc) {
1014                         status = ADS_ERROR_GSS(gss_rc, minor_status);
1015                         goto failed;
1016                 }
1017 
1018                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1019                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1020                 ads->ldap.in.max_wrapped = max_msg_size;
1021                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1022                 if (!ADS_ERR_OK(status)) {
1023                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1024                                 ads_errstr(status)));
1025                         goto failed;
1026                 }
1027                 /* make sure we don't free context_handle */
1028                 context_handle = GSS_C_NO_CONTEXT;
1029         }
1030 
1031 failed:
1032 
1033         if (context_handle != GSS_C_NO_CONTEXT)
1034                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1035 
1036         if(scred)
1037                 ber_bvfree(scred);
1038         return status;
1039 }
1040 
1041 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
1042 {
1043         ADS_STATUS status;
1044         struct ads_service_principal p;
1045 
1046         status = ads_generate_service_principal(ads, NULL, &p);
1047         if (!ADS_ERR_OK(status)) {
1048                 return status;
1049         }
1050 
1051         status = ads_sasl_gssapi_do_bind(ads, p.name);
1052         if (ADS_ERR_OK(status)) {
1053                 ads_free_service_principal(&p);
1054                 return status;
1055         }
1056 
1057         DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1058                   "calling kinit\n", ads_errstr(status)));
1059 
1060         status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1061 
1062         if (ADS_ERR_OK(status)) {
1063                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1064         }
1065 
1066         ads_free_service_principal(&p);
1067 
1068         return status;
1069 }
1070 
1071 #endif /* HAVE_GSSAPI */
1072 
1073 /* mapping between SASL mechanisms and functions */
1074 static struct {
1075         const char *name;
1076         ADS_STATUS (*fn)(ADS_STRUCT *);
1077 } sasl_mechanisms[] = {
1078         {"GSS-SPNEGO", ads_sasl_spnego_bind},
1079 #ifdef HAVE_GSSAPI
1080         {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1081 #endif
1082         {NULL, NULL}
1083 };
1084 
1085 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
1086 {
1087         const char *attrs[] = {"supportedSASLMechanisms", NULL};
1088         char **values;
1089         ADS_STATUS status;
1090         int i, j;
1091         LDAPMessage *res;
1092 
1093         /* get a list of supported SASL mechanisms */
1094         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1095         if (!ADS_ERR_OK(status)) return status;
1096 
1097         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1098 
1099         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1100                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1101         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1102                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1103         } else {
1104                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1105         }
1106 
1107         /* try our supported mechanisms in order */
1108         for (i=0;sasl_mechanisms[i].name;i++) {
1109                 /* see if the server supports it */
1110                 for (j=0;values && values[j];j++) {
1111                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1112                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1113                                 status = sasl_mechanisms[i].fn(ads);
1114                                 ldap_value_free(values);
1115                                 ldap_msgfree(res);
1116                                 return status;
1117                         }
1118                 }
1119         }
1120 
1121         ldap_value_free(values);
1122         ldap_msgfree(res);
1123         return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1124 }
1125 
1126 #endif /* HAVE_LDAP */
1127 

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