On Tue, Feb 28, 2012 at 8:25 PM, Hallvard B Furuseth <
[email protected]> wrote:

> The essential parts here are creating the LDAP* with
> ldap_initialize() or whatever, and ldap_start_tls_s().
>
> Note that ldap_unbind() is misnamed, it should have been
> called ldap_destroy().  It does send an unbind, but the more important
> part is that it destroys the LDAP*.


Got it. Thanks for your reminding, Hallvard.

Don't know where it says that.  Options with LDAP* NULL are global,
> but global options are copied to newly created LDAP*s.  Changing
> a global option has no effect on an existing LDAP*, unless the
> option itself really is global - if any option is.   I suppose
> some SASL or TLS opts might be, if some SASL/TLS library does
> not support per-connection options.
>
> Try this:
>
> /* Usage: <program> [ serverhost [ 2nd arg prevents unbind/reinit ]] */
>
> #include <assert.h>
> #include <ldap.h>
> #include <stdio.h>
>
> int main(int argc, char **argv) {
>  int i, r, flags[] = { LDAP_OPT_X_TLS_NEVER, LDAP_OPT_X_TLS_DEMAND };
>  LDAP *ld;
>  i = LDAP_VERSION3;
>  r = ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &i);
>  assert(r == LDAP_OPT_SUCCESS);
>  for (i = 0; i < 2; i++) {
>    r = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &flags[i]);
>    assert(r == LDAP_OPT_SUCCESS);
>    if (i < argc-2)
>      continue;
>    r = ldap_initialize(&ld, argv[1]);
>    assert(r == LDAP_SUCCESS);
>    r = ldap_start_tls_s(ld, NULL, NULL);
>    printf("#%d => %s%s", i+1, ldap_err2string(r), i ? "\n" : ", ");
>    ldap_unbind_ext_s(ld, NULL, NULL);
>  }
>  return 0;
> }
>
> ./testprog servername
> ./testprog servername x
>

Thanks a lot for your testing example. Based on your code, I did some minor
customization to test the cert options:

#include <assert.h>
#include <ldap.h>
#include <stdio.h>

int main() {
    int i, r, flags[] = { LDAP_OPT_X_TLS_NEVER, LDAP_OPT_X_TLS_DEMAND };
    LDAP *ld;
    const char *username = "cn=test,cn=Users,dc=my,dc=server,dc=com";
    const char *password = "test";
    struct berval password_ber = { 0, NULL };
    int msgid = 0;
    LDAPMessage *result = NULL;
    LDAPControl **ctrls = NULL;
    int err = 0;
    char *matched = NULL;
    char *info = NULL;
    char **refs = NULL;


    i = LDAP_VERSION3;
    r = ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &i);
    assert(r == LDAP_OPT_SUCCESS);

    for (i = 0; i < 2; i++) {
        r = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &flags[i]);
        assert(r == LDAP_OPT_SUCCESS);

        r = ldap_initialize(&ld, "ldaps://my.server.com:3269");
        assert(r == LDAP_SUCCESS && ld != NULL);

        password_ber.bv_val = ber_strdup(password);
        password_ber.bv_len = strlen(password_ber.bv_val);
        r = ldap_sasl_bind(ld, username, LDAP_SASL_SIMPLE, &password_ber,
NULL, NULL, &msgid);
        printf("ldap_sasl_bind(): #%d => return status is %s\n", i+1,
ldap_err2string(r));
        printf("ldap_sasl_bind(): #%d => msgid is %d\n", i+1, msgid);
        assert(msgid != -1);

        r = ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &result);
        assert(r != -1);

        r = ldap_parse_result(ld, result, &err, &matched, &info, &refs,
&ctrls, 1);
        printf("ldap_parse_result(): #%d => return status is %s\n", i+1,
ldap_err2string(r));
        printf("ldap_parse_result(): #%d => error is %s\n", i+1,
ldap_err2string(err));

        if (ctrls)
            ldap_controls_free(ctrls);

        if (password_ber.bv_val)
            ber_memfree(password_ber.bv_val);
        if (matched)
            ber_memfree(matched);
        if (info)
            ber_memfree(info);

        if (refs)
            ber_memvfree((void **)refs);

        if (ld)
            ldap_unbind_ext(ld, NULL, NULL);
    }

    return 0;
}

The output is:

ldap_sasl_bind(): #1 => return status is Success
ldap_sasl_bind(): #1 => msgid is 1
ldap_parse_result(): #1 => return status is Success
ldap_parse_result(): #1 => error is Success
ldap_sasl_bind(): #2 => return status is Success
ldap_sasl_bind(): #2 => msgid is 1
ldap_parse_result(): #2 => return status is Success
ldap_parse_result(): #2 => error is Success

So, it does seem that the value for the cert option
LDAP_OPT_X_TLS_REQUIRE_CERT has a global effect. It seems to be per
process, instead of per binding.

Is there a way to set this option on a per binding basis, so that different
bindings can have different choices on the cert requirement?

Thanks,
Qiang

Reply via email to