Ignore:
Timestamp:
Sep 30, 2007, 1:42:50 AM (13 years ago)
Author:
Paul Smedley
Message:

Update trunk to 3.2.0pre1

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/samba/source/libads/sasl.c

    r26 r77  
    66   This program is free software; you can redistribute it and/or modify
    77   it under the terms of the GNU General Public License as published by
    8    the Free Software Foundation; either version 2 of the License, or
     8   the Free Software Foundation; either version 3 of the License, or
    99   (at your option) any later version.
    1010   
     
    1515   
    1616   You should have received a copy of the GNU General Public License
    17    along with this program; if not, write to the Free Software
    18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    1918*/
    2019
     
    2221
    2322#ifdef HAVE_LDAP
     23
     24static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
     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
     63static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
     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
     98static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
     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
     109static 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};
    24115
    25116/*
     
    29120static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
    30121{
    31         DATA_BLOB msg1 = data_blob(NULL, 0);
    32         DATA_BLOB blob = data_blob(NULL, 0);
    33         DATA_BLOB blob_in = data_blob(NULL, 0);
    34         DATA_BLOB blob_out = data_blob(NULL, 0);
     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;
    35126        struct berval cred, *scred = NULL;
    36127        int rc;
    37128        NTSTATUS nt_status;
     129        ADS_STATUS status;
    38130        int turn = 1;
     131        uint32 features = 0;
    39132
    40133        struct ntlmssp_state *ntlmssp_state;
     
    55148        }
    56149
    57         blob_in = data_blob(NULL, 0);
     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;
    58173
    59174        do {
     
    77192                        cred.bv_len = msg1.length;
    78193                        scred = NULL;
    79                         rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
     194                        rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
    80195                        data_blob_free(&msg1);
    81196                        if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
     
    91206                                ber_bvfree(scred);
    92207                        } else {
    93                                 blob = data_blob(NULL, 0);
     208                                blob = data_blob_null;
    94209                        }
    95210
     
    103218                if ((turn == 1) &&
    104219                    (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
    105                         DATA_BLOB tmp_blob = data_blob(NULL, 0);
     220                        DATA_BLOB tmp_blob = data_blob_null;
    106221                        /* the server might give us back two challenges */
    107222                        if (!spnego_parse_challenge(blob, &blob_in,
     
    115230                        data_blob_free(&tmp_blob);
    116231                } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
    117                         if (!spnego_parse_auth_response(blob, nt_status,
     232                        if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
    118233                                                        &blob_in)) {
    119234
     
    132247           then the state will be kept by the signing engine */
    133248
    134         ntlmssp_end(&ntlmssp_state);
     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        }
    135264
    136265        return ADS_ERROR(rc);
    137266}
    138267
     268#ifdef HAVE_GSSAPI
     269static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
     270{
     271        gss_ctx_id_t context_handle = 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
     310static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
     311{
     312        gss_ctx_id_t context_handle = 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 < wrapped.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
     348static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
     349{
     350        gss_ctx_id_t context_handle = 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
     359static 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*/
     369static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
     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
     600failed:
     601        if (context_handle != GSS_C_NO_CONTEXT)
     602                gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
     603        return status;
     604}
     605
     606#endif /* HAVE_GSSAPI */
     607
    139608#ifdef HAVE_KRB5
     609struct ads_service_principal {
     610         char *string;
     611#ifdef HAVE_GSSAPI
     612         gss_name_t name;
     613#endif
     614};
     615
     616static void ads_free_service_principal(struct ads_service_principal *p)
     617{
     618        SAFE_FREE(p->string);
     619
     620#ifdef HAVE_GSSAPI
     621        if (p->name) {
     622                uint32 minor_status;
     623                gss_release_name(&minor_status, &p->name);
     624        }
     625#endif
     626        ZERO_STRUCTP(p);
     627}
     628
     629static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
     630                                                 const char *given_principal,
     631                                                 struct ads_service_principal *p)
     632{
     633        ADS_STATUS status;
     634#ifdef HAVE_GSSAPI
     635        gss_buffer_desc input_name;
     636        /* GSS_KRB5_NT_PRINCIPAL_NAME */
     637        gss_OID_desc nt_principal =
     638        {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
     639        uint32 minor_status;
     640        int gss_rc;
     641#endif
     642
     643        ZERO_STRUCTP(p);
     644
     645        /* I've seen a child Windows 2000 domain not send
     646           the principal name back in the first round of
     647           the SASL bind reply.  So we guess based on server
     648           name and realm.  --jerry  */
     649        /* Also try best guess when we get the w2k8 ignore
     650           principal back - gd */
     651
     652        if (!given_principal ||
     653            strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
     654
     655                status = ads_guess_service_principal(ads, &p->string);
     656                if (!ADS_ERR_OK(status)) {
     657                        return status;
     658                }
     659        } else {
     660                p->string = SMB_STRDUP(given_principal);
     661                if (!p->string) {
     662                        return ADS_ERROR(LDAP_NO_MEMORY);
     663                }
     664        }
     665
     666#ifdef HAVE_GSSAPI
     667        input_name.value = p->string;
     668        input_name.length = strlen(p->string);
     669
     670        gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
     671        if (gss_rc) {
     672                ads_free_service_principal(p);
     673                return ADS_ERROR_GSS(gss_rc, minor_status);
     674        }
     675#endif
     676
     677        return ADS_SUCCESS;
     678}
     679
    140680/*
    141681   perform a LDAP/SASL/SPNEGO/KRB5 bind
    142682*/
    143 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *principal)
    144 {
    145         DATA_BLOB blob = data_blob(NULL, 0);
     683static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
     684{
     685        DATA_BLOB blob = data_blob_null;
    146686        struct berval cred, *scred = NULL;
    147         DATA_BLOB session_key = data_blob(NULL, 0);
     687        DATA_BLOB session_key = data_blob_null;
    148688        int rc;
     689
     690        if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
     691                return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
     692        }
    149693
    150694        rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
     
    159703        cred.bv_len = blob.length;
    160704
    161         rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
     705        rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
    162706
    163707        data_blob_free(&blob);
     
    168712        return ADS_ERROR(rc);
    169713}
     714
     715static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
     716                                            struct ads_service_principal *p)
     717{
     718#ifdef HAVE_GSSAPI
     719        /*
     720         * we only use the gsskrb5 based implementation
     721         * when sasl sign or seal is requested.
     722         *
     723         * This has the following reasons:
     724         * - it's likely that the gssapi krb5 mech implementation
     725         *   doesn't support to negotiate plain connections
     726         * - the ads_sasl_spnego_rawkrb5_bind is more robust
     727         *   against clock skew errors
     728         */
     729        if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
     730                return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
     731        }
    170732#endif
     733        return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
     734}
     735#endif /* HAVE_KRB5 */
    171736
    172737/*
     
    179744        ADS_STATUS status;
    180745        DATA_BLOB blob;
    181         char *principal = NULL;
     746        char *given_principal = NULL;
    182747        char *OIDs[ASN1_MAX_OIDS];
    183748#ifdef HAVE_KRB5
     
    185750#endif
    186751
    187         rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
     752        rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
    188753
    189754        if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
     
    202767        /* the server sent us the first part of the SPNEGO exchange in the negprot
    203768           reply */
    204         if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
     769        if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
    205770                data_blob_free(&blob);
    206771                status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
     
    220785                free(OIDs[i]);
    221786        }
    222         DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", principal));
     787        DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
    223788
    224789#ifdef HAVE_KRB5
     
    226791            got_kerberos_mechanism)
    227792        {
    228                 /* I've seen a child Windows 2000 domain not send
    229                    the principal name back in the first round of
    230                    the SASL bind reply.  So we guess based on server
    231                    name and realm.  --jerry  */
    232                 if ( !principal ) {
    233                         if ( ads->server.realm && ads->server.ldap_server ) {
    234                                 char *server, *server_realm;
    235                                
    236                                 server = SMB_STRDUP( ads->server.ldap_server );
    237                                 server_realm = SMB_STRDUP( ads->server.realm );
    238                                
    239                                 if ( !server || !server_realm )
    240                                         return ADS_ERROR(LDAP_NO_MEMORY);
    241 
    242                                 strlower_m( server );
    243                                 strupper_m( server_realm );                             
    244                                 asprintf( &principal, "ldap/%s@%s", server, server_realm );
    245 
    246                                 SAFE_FREE( server );
    247                                 SAFE_FREE( server_realm );
    248 
    249                                 if ( !principal )
    250                                         return ADS_ERROR(LDAP_NO_MEMORY);                               
    251                         }
    252                        
    253                 }
    254                
    255                 status = ads_sasl_spnego_krb5_bind(ads, principal);
     793                struct ads_service_principal p;
     794
     795                status = ads_generate_service_principal(ads, given_principal, &p);
     796                SAFE_FREE(given_principal);
     797                if (!ADS_ERR_OK(status)) {
     798                        return status;
     799                }
     800
     801                status = ads_sasl_spnego_krb5_bind(ads, &p);
    256802                if (ADS_ERR_OK(status)) {
    257                         SAFE_FREE(principal);
     803                        ads_free_service_principal(&p);
    258804                        return status;
    259805                }
     
    265811
    266812                if (ADS_ERR_OK(status)) {
    267                         status = ads_sasl_spnego_krb5_bind(ads, principal);
    268                 }
     813                        status = ads_sasl_spnego_krb5_bind(ads, &p);
     814                        if (!ADS_ERR_OK(status)) {
     815                                DEBUG(0,("kinit succeeded but "
     816                                        "ads_sasl_spnego_krb5_bind failed: %s\n",
     817                                        ads_errstr(status)));
     818                        }
     819                }
     820
     821                ads_free_service_principal(&p);
    269822
    270823                /* only fallback to NTLMSSP if allowed */
    271824                if (ADS_ERR_OK(status) ||
    272825                    !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
    273                         SAFE_FREE(principal);
    274826                        return status;
    275827                }
    276         }
     828        } else
    277829#endif
    278 
    279         SAFE_FREE(principal);
     830        {
     831                SAFE_FREE(given_principal);
     832        }
    280833
    281834        /* lets do NTLMSSP ... this has the big advantage that we don't need
     
    297850   see RFC2078 and RFC2222 for details
    298851*/
    299 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
     852static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
    300853{
    301854        uint32 minor_status;
    302         gss_name_t serv_name;
    303         gss_buffer_desc input_name;
    304855        gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
    305856        gss_OID mech_type = GSS_C_NULL_OID;
    306857        gss_buffer_desc output_token, input_token;
    307         uint32 ret_flags, conf_state;
     858        uint32 req_flags, ret_flags;
     859        int conf_state;
    308860        struct berval cred;
    309861        struct berval *scred = NULL;
     
    311863        int gss_rc, rc;
    312864        uint8 *p;
    313         uint32 max_msg_size = 0;
    314         char *sname = NULL;
     865        uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
     866        uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
    315867        ADS_STATUS status;
    316         krb5_principal principal = NULL;
    317         krb5_context ctx = NULL;
    318         krb5_enctype enc_types[] = {
    319 #ifdef ENCTYPE_ARCFOUR_HMAC
    320                         ENCTYPE_ARCFOUR_HMAC,
    321 #endif
    322                         ENCTYPE_DES_CBC_MD5,
    323                         ENCTYPE_NULL};
    324         gss_OID_desc nt_principal =
    325         {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
    326 
    327         /* we need to fetch a service ticket as the ldap user in the
    328            servers realm, regardless of our realm */
    329         asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);
    330 
    331         initialize_krb5_error_table();
    332         status = ADS_ERROR_KRB5(krb5_init_context(&ctx));
    333         if (!ADS_ERR_OK(status)) {
    334                 SAFE_FREE(sname);
    335                 return status;
    336         }
    337         status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));
    338         if (!ADS_ERR_OK(status)) {
    339                 SAFE_FREE(sname);
    340                 krb5_free_context(ctx);
    341                 return status;
    342         }
    343         status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));
    344         if (!ADS_ERR_OK(status)) {
    345                 SAFE_FREE(sname);
    346                 krb5_free_context(ctx);
    347                 return status;
    348         }
    349 
    350         input_name.value = &principal;
    351         input_name.length = sizeof(principal);
    352 
    353         gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name);
    354 
    355         /*
    356          * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
    357          * to point to the *address* of the krb5_principal, and the gss libraries
    358          * to a shallow copy of the krb5_principal pointer - so we need to keep
    359          * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
    360          * Just one more way in which MIT engineers screwed me over.... JRA.
    361          */
    362 
    363         SAFE_FREE(sname);
    364 
    365         if (gss_rc) {
    366                 krb5_free_principal(ctx, principal);
    367                 krb5_free_context(ctx);
    368                 return ADS_ERROR_GSS(gss_rc, minor_status);
    369         }
    370868
    371869        input_token.value = NULL;
    372870        input_token.length = 0;
     871
     872        /*
     873         * Note: here we always ask the gssapi for sign and seal
     874         *       as this is negotiated later after the mutal
     875         *       authentication
     876         */
     877        req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
    373878
    374879        for (i=0; i < MAX_GSS_PASSES; i++) {
     
    378883                                          serv_name,
    379884                                          mech_type,
    380                                           GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
     885                                          req_flags,
    381886                                          0,
    382887                                          NULL,
     
    386891                                          &ret_flags,
    387892                                          NULL);
    388 
    389                 if (input_token.value) {
    390                         gss_release_buffer(&minor_status, &input_token);
    391                 }
    392 
     893                if (scred) {
     894                        ber_bvfree(scred);
     895                        scred = NULL;
     896                }
    393897                if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
    394898                        status = ADS_ERROR_GSS(gss_rc, minor_status);
     
    399903                cred.bv_len = output_token.length;
    400904
    401                 rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
     905                rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
    402906                                      &scred);
    403907                if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
     
    422926
    423927        gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
    424                             (int *)&conf_state,NULL);
     928                            &conf_state,NULL);
     929        if (scred) {
     930                ber_bvfree(scred);
     931                scred = NULL;
     932        }
    425933        if (gss_rc) {
    426934                status = ADS_ERROR_GSS(gss_rc, minor_status);
    427935                goto failed;
    428936        }
    429 
    430         gss_release_buffer(&minor_status, &input_token);
    431937
    432938        p = (uint8 *)output_token.value;
     
    437943
    438944        if (p) {
    439                 max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
     945                wrap_type = CVAL(p,0);
     946                SCVAL(p,0,0);
     947                max_msg_size = RIVAL(p,0);
    440948        }
    441949
    442950        gss_release_buffer(&minor_status, &output_token);
    443951
    444         output_token.value = SMB_MALLOC(strlen(ads->config.bind_path) + 8);
     952        if (!(wrap_type & ads->ldap.wrap_type)) {
     953                /*
     954                 * the server doesn't supports the wrap
     955                 * type we want :-(
     956                 */
     957                DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
     958                        ads->ldap.wrap_type, wrap_type));
     959                DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
     960                status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
     961                goto failed;
     962        }
     963
     964        /* 0x58 is the minimum windows accepts */
     965        if (max_msg_size < 0x58) {
     966                max_msg_size = 0x58;
     967        }
     968
     969        output_token.length = 4;
     970        output_token.value = SMB_MALLOC(output_token.length);
    445971        p = (uint8 *)output_token.value;
    446972
    447         *p++ = 1; /* no sign & seal selection */
    448         /* choose the same size as the server gave us */
    449         *p++ = max_msg_size>>16;
    450         *p++ = max_msg_size>>8;
    451         *p++ = max_msg_size;
    452         snprintf((char *)p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path);
    453         p += strlen((const char *)p);
    454 
    455         output_token.length = PTR_DIFF(p, output_token.value);
     973        RSIVAL(p,0,max_msg_size);
     974        SCVAL(p,0,ads->ldap.wrap_type);
     975
     976        /*
     977         * we used to add sprintf("dn:%s", ads->config.bind_path) here.
     978         * but using ads->config.bind_path is the wrong! It should be
     979         * the DN of the user object!
     980         *
     981         * w2k3 gives an error when we send an incorrect DN, but sending nothing
     982         * is ok and matches the information flow used in GSS-SPNEGO.
     983         */
    456984
    457985        gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
    458                           &output_token, (int *)&conf_state,
     986                          &output_token, &conf_state,
    459987                          &input_token);
    460988        if (gss_rc) {
     
    468996        cred.bv_len = input_token.length;
    469997
    470         rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
     998        rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
    471999                              &scred);
     1000        gss_release_buffer(&minor_status, &input_token);
    4721001        status = ADS_ERROR(rc);
    473 
    474         gss_release_buffer(&minor_status, &input_token);
     1002        if (!ADS_ERR_OK(status)) {
     1003                goto failed;
     1004        }
     1005
     1006        if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
     1007                gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
     1008                                             (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
     1009                                             GSS_C_QOP_DEFAULT,
     1010                                             max_msg_size, &ads->ldap.out.max_unwrapped);
     1011                if (gss_rc) {
     1012                        status = ADS_ERROR_GSS(gss_rc, minor_status);
     1013                        goto failed;
     1014                }
     1015
     1016                ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
     1017                ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
     1018                ads->ldap.in.max_wrapped = max_msg_size;
     1019                status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
     1020                if (!ADS_ERR_OK(status)) {
     1021                        DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
     1022                                ads_errstr(status)));
     1023                        goto failed;
     1024                }
     1025                /* make sure we don't free context_handle */
     1026                context_handle = GSS_C_NO_CONTEXT;
     1027        }
    4751028
    4761029failed:
    4771030
    478         gss_release_name(&minor_status, &serv_name);
    4791031        if (context_handle != GSS_C_NO_CONTEXT)
    4801032                gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
    481         krb5_free_principal(ctx, principal);
    482         krb5_free_context(ctx);
    4831033
    4841034        if(scred)
     
    4861036        return status;
    4871037}
    488 #endif /* HAVE_GGSAPI */
     1038
     1039static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
     1040{
     1041        ADS_STATUS status;
     1042        struct ads_service_principal p;
     1043
     1044        status = ads_generate_service_principal(ads, NULL, &p);
     1045        if (!ADS_ERR_OK(status)) {
     1046                return status;
     1047        }
     1048
     1049        status = ads_sasl_gssapi_do_bind(ads, p.name);
     1050        if (ADS_ERR_OK(status)) {
     1051                ads_free_service_principal(&p);
     1052                return status;
     1053        }
     1054
     1055        DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
     1056                  "calling kinit\n", ads_errstr(status)));
     1057
     1058        status = ADS_ERROR_KRB5(ads_kinit_password(ads));
     1059
     1060        if (ADS_ERR_OK(status)) {
     1061                status = ads_sasl_gssapi_do_bind(ads, p.name);
     1062        }
     1063
     1064        ads_free_service_principal(&p);
     1065
     1066        return status;
     1067}
     1068
     1069#endif /* HAVE_GSSAPI */
    4891070
    4901071/* mapping between SASL mechanisms and functions */
     
    5121093        if (!ADS_ERR_OK(status)) return status;
    5131094
    514         values = ldap_get_values(ads->ld, res, "supportedSASLMechanisms");
     1095        values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
     1096
     1097        if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
     1098                ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
     1099        } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
     1100                ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
     1101        } else {
     1102                ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
     1103        }
    5151104
    5161105        /* try our supported mechanisms in order */
Note: See TracChangeset for help on using the changeset viewer.