static void do_search( char *uri, char *manager, struct berval *passwd, char *sbase, int scope, char *filter, LDAP **ldp, char **attrs, int noattrs, int nobind, int innerloop, int maxretries, int delay, int force, int chaserefs ) { LDAP *ld = ldp ? *ldp : NULL; int i = 0, do_retry = maxretries; int rc = LDAP_SUCCESS; int version = LDAP_VERSION3; char buf[ BUFSIZ ]; int *msgids = NULL, active = 0; /* make room for msgid */ if ( swamp > 1 ) { msgids = (int *)calloc( sizeof(int), innerloop ); } retry:; if ( ld == NULL ) { ldap_initialize( &ld, uri ); if ( ld == NULL ) { tester_perror( "ldap_initialize", NULL ); exit( EXIT_FAILURE ); } (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); if ( do_retry == maxretries ) { fprintf( stderr, "PID=%ld - Search(%d): " "base=\"%s\" scope=%s filter=\"%s\" " "attrs=%s%s.\n", (long) pid, innerloop, sbase, ldap_pvt_scope2str( scope ), filter, attrs[0], attrs[1] ? " (more...)" : "" ); } if ( nobind == 0 ) { rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { snprintf( buf, sizeof( buf ), "bindDN=\"%s\"", manager ); tester_ldap_error( ld, "ldap_sasl_bind_s", buf ); switch ( rc ) { case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { ldap_unbind_ext( ld, NULL, NULL ); ld = NULL; do_retry--; if ( delay != 0 ) { sleep( delay ); } goto retry; } /* fallthru */ default: break; } exit( EXIT_FAILURE ); } } } if ( swamp > 1 ) { do { LDAPMessage *res = NULL; int j, msgid; if ( i < innerloop ) { rc = ldap_search_ext( ld, sbase, scope, filter, NULL, noattrs, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgids[i] ); active++; #if 0 fprintf( stderr, ">>> PID=%ld - Search maxloop=%d cnt=%d active=%d msgid=%d: " "base=\"%s\" scope=%s filter=\"%s\"\n", (long) pid, innerloop, i, active, msgids[i], sbase, ldap_pvt_scope2str( scope ), filter ); #endif i++; if ( rc ) { int first = tester_ignore_err( rc ); /* if ignore.. */ if ( first ) { /* only log if first occurrence */ if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) { tester_ldap_error( ld, "ldap_search_ext", NULL ); } continue; } /* busy needs special handling */ snprintf( buf, sizeof( buf ), "base=\"%s\" filter=\"%s\"\n", sbase, filter ); tester_ldap_error( ld, "ldap_search_ext", buf ); if ( rc == LDAP_BUSY && do_retry > 0 ) { ldap_unbind_ext( ld, NULL, NULL ); ld = NULL; do_retry--; goto retry; } break; } if ( swamp > 2 ) { continue; } } rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res ); switch ( rc ) { case -1: /* gone really bad */ goto cleanup; case 0: /* timeout (impossible) */ break; case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: /* ignore */ break; case LDAP_RES_SEARCH_RESULT: /* just remove, no error checking (TODO?) */ msgid = ldap_msgid( res ); ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 ); res = NULL; /* linear search, bah */ for ( j = 0; j < i; j++ ) { if ( msgids[ j ] == msgid ) { msgids[ j ] = -1; active--; #if 0 fprintf( stderr, "<<< PID=%ld - SearchDone maxloop=%d cnt=%d active=%d msgid=%d: " "base=\"%s\" scope=%s filter=\"%s\"\n", (long) pid, innerloop, j, active, msgid, sbase, ldap_pvt_scope2str( scope ), filter ); #endif break; } } break; default: /* other messages unexpected */ fprintf( stderr, "### PID=%ld - Search(%d): " "base=\"%s\" scope=%s filter=\"%s\" " "attrs=%s%s. unexpected response tag=%d\n", (long) pid, innerloop, sbase, ldap_pvt_scope2str( scope ), filter, attrs[0], attrs[1] ? " (more...)" : "", rc ); break; } if ( res != NULL ) { ldap_msgfree( res ); } } while ( i < innerloop || active > 0 ); } else { for ( ; i < innerloop; i++ ) { LDAPMessage *res = NULL; if (swamp) { int msgid; rc = ldap_search_ext( ld, sbase, scope, filter, NULL, noattrs, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid ); if ( rc == LDAP_SUCCESS ) continue; else break; } rc = ldap_search_ext_s( ld, sbase, scope, filter, attrs, noattrs, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); if ( res != NULL ) { ldap_msgfree( res ); } if ( rc ) { int first = tester_ignore_err( rc ); /* if ignore.. */ if ( first ) { /* only log if first occurrence */ if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) { tester_ldap_error( ld, "ldap_search_ext_s", NULL ); } continue; } /* busy needs special handling */ snprintf( buf, sizeof( buf ), "base=\"%s\" filter=\"%s\"\n", sbase, filter ); tester_ldap_error( ld, "ldap_search_ext_s", buf ); if ( rc == LDAP_BUSY && do_retry > 0 ) { ldap_unbind_ext( ld, NULL, NULL ); ld = NULL; do_retry--; goto retry; } break; } } } cleanup:; if ( msgids != NULL ) { free( msgids ); } if ( ldp != NULL ) { *ldp = ld; } else { fprintf( stderr, " PID=%ld - Search done (%d).\n", (long) pid, rc ); if ( ld != NULL ) { ldap_unbind_ext( ld, NULL, NULL ); } } }
static void do_modrdn( char *uri, char *manager, struct berval *passwd, char *entry, int maxloop, int maxretries, int delay, int friendly, int chaserefs ) { LDAP *ld = NULL; int i, do_retry = maxretries; char *DNs[2]; char *rdns[2]; int rc = LDAP_SUCCESS; char *p1, *p2; int version = LDAP_VERSION3; DNs[0] = entry; DNs[1] = strdup( entry ); /* reverse the RDN, make new DN */ p1 = strchr( entry, '=' ) + 1; p2 = strchr( p1, ',' ); *p2 = '\0'; rdns[1] = strdup( entry ); *p2-- = ','; for (i = p1 - entry;p2 >= p1;) DNs[1][i++] = *p2--; DNs[1][i] = '\0'; rdns[0] = strdup( DNs[1] ); DNs[1][i] = ','; i = 0; retry:; ldap_initialize( &ld, uri ); if ( ld == NULL ) { tester_perror( "ldap_initialize", NULL ); exit( EXIT_FAILURE ); } (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); if ( do_retry == maxretries ) { fprintf( stderr, "PID=%ld - Modrdn(%d): entry=\"%s\".\n", (long) pid, maxloop, entry ); } rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); switch ( rc ) { case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { do_retry--; if ( delay > 0) { sleep( delay ); } goto retry; } /* fallthru */ default: break; } exit( EXIT_FAILURE ); } for ( ; i < maxloop; i++ ) { rc = ldap_rename_s( ld, DNs[0], rdns[0], NULL, 0, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_rename_s", NULL ); switch ( rc ) { case LDAP_NO_SUCH_OBJECT: /* NOTE: this likely means * the second modrdn failed * during the previous round... */ if ( !friendly ) { goto done; } break; case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { do_retry--; goto retry; } /* fall thru */ default: goto done; } } rc = ldap_rename_s( ld, DNs[1], rdns[1], NULL, 1, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_rename_s", NULL ); switch ( rc ) { case LDAP_NO_SUCH_OBJECT: /* NOTE: this likely means * the first modrdn failed * during the previous round... */ if ( !friendly ) { goto done; } break; case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { do_retry--; goto retry; } /* fall thru */ default: goto done; } } } done:; fprintf( stderr, " PID=%ld - Modrdn done (%d).\n", (long) pid, rc ); ldap_unbind_ext( ld, NULL, NULL ); free( DNs[1] ); free( rdns[0] ); free( rdns[1] ); }
int main(int argc, char* argv[]) { DWORD dwError = 0; const int ldapVer = LDAP_VERSION3; PVMDIR_QUERY_ARGS pArgs = NULL; PSTR pszLdapURL = NULL; LDAP* pLd = NULL; BerValue ldapBindPwd = {0}; LDAPMessage* pResult = NULL; PSTR pszDN = NULL; dwError = VmDirQueryParseArgs(argc, argv, &pArgs); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringAVsnprintf( &pszLdapURL, "ldap://%s", pArgs->pszHostname); BAIL_ON_VMDIR_ERROR(dwError); #if 0 dwError = ldap_initialize(&pLd, pszLdapURL); BAIL_ON_VMDIR_ERROR(dwError); #else pLd = ldap_open(pArgs->pszHostname, 389); if (!pLd) { dwError = VMDIR_ERROR_SERVER_DOWN; BAIL_ON_VMDIR_ERROR(dwError); } #endif dwError = ldap_set_option(pLd, LDAP_OPT_PROTOCOL_VERSION, &ldapVer); BAIL_ON_VMDIR_ERROR(dwError); dwError = ldap_set_option(pLd, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); BAIL_ON_VMDIR_ERROR(dwError); ldapBindPwd.bv_val = pArgs->pszPassword; ldapBindPwd.bv_len = strlen(pArgs->pszPassword); #if 0 dwError = ldap_sasl_bind_s( pLd, pArgs->pszBindDN, LDAP_SASL_SIMPLE, &ldapBindPwd, NULL, NULL, NULL); BAIL_ON_VMDIR_ERROR(dwError); #else dwError = ldap_bind_s( pLd, pArgs->pszBindDN, pArgs->pszPassword, LDAP_AUTH_SIMPLE); BAIL_ON_VMDIR_ERROR(dwError); #endif #if 0 dwError = ldap_search_ext_s( pLd, pArgs->pszBaseDN, LDAP_SCOPE_SUBTREE, pArgs->pszFilter, NULL, TRUE, NULL, // server ctrls NULL, // client ctrls NULL, // timeout -1, // size limit, &pResult); BAIL_ON_VMDIR_ERROR(dwError); #else dwError = ldap_search_s( pLd, pArgs->pszBaseDN, LDAP_SCOPE_SUBTREE, pArgs->pszFilter, NULL, TRUE, &pResult); BAIL_ON_VMDIR_ERROR(dwError); #endif if (ldap_count_entries(pLd, pResult) > 0) { LDAPMessage* pEntry = ldap_first_entry(pLd, pResult); for (; pEntry != NULL; pEntry = ldap_next_entry(pLd, pEntry)) { if (pszDN) { ldap_memfree(pszDN); pszDN = NULL; } pszDN = ldap_get_dn(pLd, pEntry); if (IsNullOrEmptyString(pszDN)) { dwError = VMDIR_ERROR_INVALID_DN; BAIL_ON_VMDIR_ERROR(dwError); } fprintf(stdout, "DN : %s\n", pszDN); } } cleanup: if (pArgs) { VmDirFreeArgs(pArgs); } VMDIR_SAFE_FREE_MEMORY(pszLdapURL); if (pResult) { ldap_msgfree(pResult); } if (pszDN) { ldap_memfree(pszDN); } if (pLd) { ldap_unbind_ext_s(pLd, NULL, NULL); } return dwError; error: goto cleanup; }
static void do_modify( char *uri, char *manager, struct berval *passwd, char *entry, char* attr, char* value, int maxloop, int maxretries, int delay, int friendly, int chaserefs ) { LDAP *ld = NULL; int i = 0, do_retry = maxretries; int rc = LDAP_SUCCESS; struct ldapmod mod; struct ldapmod *mods[2]; char *values[2]; int version = LDAP_VERSION3; values[0] = value; values[1] = NULL; mod.mod_op = LDAP_MOD_ADD; mod.mod_type = attr; mod.mod_values = values; mods[0] = &mod; mods[1] = NULL; retry:; ldap_initialize( &ld, uri ); if ( ld == NULL ) { tester_perror( "ldap_initialize", NULL ); exit( EXIT_FAILURE ); } (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); if ( do_retry == maxretries ) { fprintf( stderr, "PID=%ld - Modify(%d): entry=\"%s\".\n", (long) pid, maxloop, entry ); } rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); switch ( rc ) { case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { do_retry--; if ( delay > 0 ) { sleep( delay ); } goto retry; } /* fallthru */ default: break; } exit( EXIT_FAILURE ); } for ( ; i < maxloop; i++ ) { mod.mod_op = LDAP_MOD_ADD; rc = ldap_modify_ext_s( ld, entry, mods, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_modify_ext_s", NULL ); switch ( rc ) { case LDAP_TYPE_OR_VALUE_EXISTS: /* NOTE: this likely means * the second modify failed * during the previous round... */ if ( !friendly ) { goto done; } break; case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { do_retry--; goto retry; } /* fall thru */ default: goto done; } } mod.mod_op = LDAP_MOD_DELETE; rc = ldap_modify_ext_s( ld, entry, mods, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_modify_ext_s", NULL ); switch ( rc ) { case LDAP_NO_SUCH_ATTRIBUTE: /* NOTE: this likely means * the first modify failed * during the previous round... */ if ( !friendly ) { goto done; } break; case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { do_retry--; goto retry; } /* fall thru */ default: goto done; } } } done:; fprintf( stderr, " PID=%ld - Modify done (%d).\n", (long) pid, rc ); ldap_unbind_ext( ld, NULL, NULL ); }
static void do_random( char *uri, char *manager, struct berval *passwd, char *sbase, int scope, char *filter, char *attr, char **srchattrs, int noattrs, int nobind, int innerloop, int maxretries, int delay, int force, int chaserefs ) { LDAP *ld = NULL; int i = 0, do_retry = maxretries; char *attrs[ 2 ]; int rc = LDAP_SUCCESS; int version = LDAP_VERSION3; int nvalues = 0; char **values = NULL; LDAPMessage *res = NULL, *e = NULL; attrs[ 0 ] = attr; attrs[ 1 ] = NULL; ldap_initialize( &ld, uri ); if ( ld == NULL ) { tester_perror( "ldap_initialize", NULL ); exit( EXIT_FAILURE ); } (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); if ( do_retry == maxretries ) { fprintf( stderr, "PID=%ld - Search(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n", (long) pid, innerloop, sbase, filter, attr ); } if ( nobind == 0 ) { rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); switch ( rc ) { case LDAP_BUSY: case LDAP_UNAVAILABLE: /* fallthru */ default: break; } exit( EXIT_FAILURE ); } } rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); switch ( rc ) { case LDAP_SIZELIMIT_EXCEEDED: case LDAP_TIMELIMIT_EXCEEDED: case LDAP_SUCCESS: if ( ldap_count_entries( ld, res ) == 0 ) { if ( rc ) { tester_ldap_error( ld, "ldap_search_ext_s", NULL ); } break; } for ( e = ldap_first_entry( ld, res ); e != NULL; e = ldap_next_entry( ld, e ) ) { struct berval **v = ldap_get_values_len( ld, e, attr ); if ( v != NULL ) { int n = ldap_count_values_len( v ); int j; values = realloc( values, ( nvalues + n + 1 )*sizeof( char * ) ); for ( j = 0; j < n; j++ ) { values[ nvalues + j ] = strdup( v[ j ]->bv_val ); } values[ nvalues + j ] = NULL; nvalues += n; ldap_value_free_len( v ); } } ldap_msgfree( res ); if ( !values ) { fprintf( stderr, " PID=%ld - Search base=\"%s\" filter=\"%s\" got %d values.\n", (long) pid, sbase, filter, nvalues ); exit(EXIT_FAILURE); } if ( do_retry == maxretries ) { fprintf( stderr, " PID=%ld - Search base=\"%s\" filter=\"%s\" got %d values.\n", (long) pid, sbase, filter, nvalues ); } for ( i = 0; i < innerloop; i++ ) { char buf[ BUFSIZ ]; #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */ int r = rand() % nvalues; #endif int r = ((double)nvalues)*rand()/(RAND_MAX + 1.0); snprintf( buf, sizeof( buf ), "(%s=%s)", attr, values[ r ] ); do_search( uri, manager, passwd, sbase, scope, buf, &ld, srchattrs, noattrs, nobind, 1, maxretries, delay, force, chaserefs ); } break; default: tester_ldap_error( ld, "ldap_search_ext_s", NULL ); break; } fprintf( stderr, " PID=%ld - Search done (%d).\n", (long) pid, rc ); if ( ld != NULL ) { ldap_unbind_ext( ld, NULL, NULL ); } }
/* this performs a SASL/gssapi bind we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl is very dependent on correctly configured DNS whereas this routine is much less fragile see RFC2078 and RFC2222 for details */ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name) { uint32_t minor_status; gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; gss_OID mech_type = GSS_C_NULL_OID; gss_buffer_desc output_token, input_token; uint32_t req_flags, ret_flags; int conf_state; struct berval cred; struct berval *scred = NULL; int i=0; int gss_rc, rc; uint8_t *p; uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED; uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN; ADS_STATUS status; input_token.value = NULL; input_token.length = 0; status = ads_init_gssapi_cred(ads, &gss_cred); if (!ADS_ERR_OK(status)) { goto failed; } /* * Note: here we always ask the gssapi for sign and seal * as this is negotiated later after the mutal * authentication */ req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; for (i=0; i < MAX_GSS_PASSES; i++) { gss_rc = gss_init_sec_context(&minor_status, gss_cred, &context_handle, serv_name, mech_type, req_flags, 0, NULL, &input_token, NULL, &output_token, &ret_flags, NULL); if (scred) { ber_bvfree(scred); scred = NULL; } if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) { status = ADS_ERROR_GSS(gss_rc, minor_status); goto failed; } cred.bv_val = (char *)output_token.value; cred.bv_len = output_token.length; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, &scred); if (rc != LDAP_SASL_BIND_IN_PROGRESS) { status = ADS_ERROR(rc); goto failed; } if (output_token.value) { gss_release_buffer(&minor_status, &output_token); } if (scred) { input_token.value = scred->bv_val; input_token.length = scred->bv_len; } else { input_token.value = NULL; input_token.length = 0; } if (gss_rc == 0) break; } gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token, &conf_state,NULL); if (scred) { ber_bvfree(scred); scred = NULL; } if (gss_rc) { status = ADS_ERROR_GSS(gss_rc, minor_status); goto failed; } p = (uint8_t *)output_token.value; #if 0 file_save("sasl_gssapi.dat", output_token.value, output_token.length); #endif if (p) { wrap_type = CVAL(p,0); SCVAL(p,0,0); max_msg_size = RIVAL(p,0); } gss_release_buffer(&minor_status, &output_token); if (!(wrap_type & ads->ldap.wrap_type)) { /* * the server doesn't supports the wrap * type we want :-( */ DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n", ads->ldap.wrap_type, wrap_type)); DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n")); status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); goto failed; } /* 0x58 is the minimum windows accepts */ if (max_msg_size < 0x58) { max_msg_size = 0x58; } output_token.length = 4; output_token.value = SMB_MALLOC(output_token.length); if (!output_token.value) { output_token.length = 0; status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); goto failed; } p = (uint8_t *)output_token.value; RSIVAL(p,0,max_msg_size); SCVAL(p,0,ads->ldap.wrap_type); /* * we used to add sprintf("dn:%s", ads->config.bind_path) here. * but using ads->config.bind_path is the wrong! It should be * the DN of the user object! * * w2k3 gives an error when we send an incorrect DN, but sending nothing * is ok and matches the information flow used in GSS-SPNEGO. */ gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT, &output_token, /* used as *input* here. */ &conf_state, &input_token); /* Used as *output* here. */ if (gss_rc) { status = ADS_ERROR_GSS(gss_rc, minor_status); output_token.length = 0; SAFE_FREE(output_token.value); goto failed; } /* We've finished with output_token. */ SAFE_FREE(output_token.value); output_token.length = 0; cred.bv_val = (char *)input_token.value; cred.bv_len = input_token.length; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, &scred); gss_release_buffer(&minor_status, &input_token); status = ADS_ERROR(rc); if (!ADS_ERR_OK(status)) { goto failed; } if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { gss_rc = gss_wrap_size_limit(&minor_status, context_handle, (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL), GSS_C_QOP_DEFAULT, max_msg_size, &ads->ldap.out.max_unwrapped); if (gss_rc) { status = ADS_ERROR_GSS(gss_rc, minor_status); goto failed; } ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped; ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */ ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED; status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle); if (!ADS_ERR_OK(status)) { DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", ads_errstr(status))); goto failed; } /* make sure we don't free context_handle */ context_handle = GSS_C_NO_CONTEXT; } failed: if (gss_cred != GSS_C_NO_CREDENTIAL) gss_release_cred(&minor_status, &gss_cred); if (context_handle != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); if(scred) ber_bvfree(scred); return status; }
/* perform a LDAP/SASL/SPNEGO/GSSKRB5 bind */ static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name) { ADS_STATUS status; bool ok; uint32 minor_status; int gss_rc, rc; gss_OID_desc krb5_mech_type = {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }; gss_OID mech_type = &krb5_mech_type; gss_OID actual_mech_type = GSS_C_NULL_OID; const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL}; gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; gss_buffer_desc input_token, output_token; uint32 req_flags, ret_flags; uint32 req_tmp, ret_tmp; DATA_BLOB unwrapped; DATA_BLOB wrapped; struct berval cred, *scred = NULL; input_token.value = NULL; input_token.length = 0; req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; switch (ads->ldap.wrap_type) { case ADS_SASLWRAP_TYPE_SEAL: req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; break; case ADS_SASLWRAP_TYPE_SIGN: req_flags |= GSS_C_INTEG_FLAG; break; case ADS_SASLWRAP_TYPE_PLAIN: break; } /* Note: here we explicit ask for the krb5 mech_type */ gss_rc = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL, &context_handle, serv_name, mech_type, req_flags, 0, NULL, &input_token, &actual_mech_type, &output_token, &ret_flags, NULL); if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) { status = ADS_ERROR_GSS(gss_rc, minor_status); goto failed; } /* * As some gssapi krb5 mech implementations * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG * to req_flags internaly, it's not possible to * use plain or signing only connection via * the gssapi interface. * * Because of this we need to check it the ret_flags * has more flags as req_flags and correct the value * of ads->ldap.wrap_type. * * I ads->auth.flags has ADS_AUTH_SASL_FORCE * we need to give an error. */ req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); if (req_tmp == ret_tmp) { /* everythings fine... */ } else if (req_flags & GSS_C_CONF_FLAG) { /* * here we wanted sealing but didn't got it * from the gssapi library */ status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); goto failed; } else if ((req_flags & GSS_C_INTEG_FLAG) && !(ret_flags & GSS_C_INTEG_FLAG)) { /* * here we wanted siging but didn't got it * from the gssapi library */ status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); goto failed; } else if (ret_flags & GSS_C_CONF_FLAG) { /* * here we didn't want sealing * but the gssapi library forces it * so correct the needed wrap_type if * the caller didn't forced siging only */ if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); goto failed; } ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL; req_flags = ret_flags; } else if (ret_flags & GSS_C_INTEG_FLAG) { /* * here we didn't want signing * but the gssapi library forces it * so correct the needed wrap_type if * the caller didn't forced plain */ if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); goto failed; } ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN; req_flags = ret_flags; } else { /* * This could (should?) not happen */ status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR); goto failed; } /* and wrap that in a shiny SPNEGO wrapper */ unwrapped = data_blob_const(output_token.value, output_token.length); wrapped = spnego_gen_negTokenInit(talloc_tos(), spnego_mechs, &unwrapped, NULL); gss_release_buffer(&minor_status, &output_token); if (unwrapped.length > wrapped.length) { status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); goto failed; } cred.bv_val = (char *)wrapped.data; cred.bv_len = wrapped.length; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); data_blob_free(&wrapped); if (rc != LDAP_SUCCESS) { status = ADS_ERROR(rc); goto failed; } if (scred) { wrapped = data_blob_const(scred->bv_val, scred->bv_len); } else { wrapped = data_blob_null; } ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK, OID_KERBEROS5_OLD, &unwrapped); if (scred) ber_bvfree(scred); if (!ok) { status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); goto failed; } input_token.value = unwrapped.data; input_token.length = unwrapped.length; /* * As we asked for mutal authentication * we need to pass the servers response * to gssapi */ gss_rc = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL, &context_handle, serv_name, mech_type, req_flags, 0, NULL, &input_token, &actual_mech_type, &output_token, &ret_flags, NULL); data_blob_free(&unwrapped); if (gss_rc) { status = ADS_ERROR_GSS(gss_rc, minor_status); goto failed; } gss_release_buffer(&minor_status, &output_token); /* * If we the sign and seal options * doesn't match after getting the response * from the server, we don't want to use the connection */ req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); if (req_tmp != ret_tmp) { /* everythings fine... */ status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); goto failed; } if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED; gss_rc = gss_wrap_size_limit(&minor_status, context_handle, (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL), GSS_C_QOP_DEFAULT, max_msg_size, &ads->ldap.out.max_unwrapped); if (gss_rc) { status = ADS_ERROR_GSS(gss_rc, minor_status); goto failed; } ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped; ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */ ads->ldap.in.max_wrapped = max_msg_size; status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle); if (!ADS_ERR_OK(status)) { DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", ads_errstr(status))); goto failed; } /* make sure we don't free context_handle */ context_handle = GSS_C_NO_CONTEXT; } status = ADS_SUCCESS; failed: if (context_handle != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); return status; }
static char* check_ldap_auth(LD_session *session, char *login, unsigned char *password, char *fullname) { int rc = 0, count = 0; char logbuf[MAXLOGBUF]; LDAPMessage *res, *entry; char *attr, *dn; BerElement * ber; struct berval **list_of_values; struct berval value; char *validgroups; char filter[MAXFILTERSTR]; struct berval cred_user; /* Check authorization */ memset(filter, 0, 100); snprintf(filter, MAXLOGBUF, "(&(objectClass=posixGroup)(memberUid=%s))", login); cred_user.bv_val = (const char *)password; cred_user.bv_len = strlen(cred_user.bv_val); #if LDAP_API_VERSION > 3000 if((rc = ldap_sasl_bind_s(session->sess, fullname, ldap_authorization_type, &cred_user, NULL, NULL, NULL))!=LDAP_SUCCESS) { snprintf(logbuf, MAXLOGBUF, "Ldap server %s authentificate with method %s failed: %s", ldap_authorization_host, ldap_authorization_type, ldap_err2string(rc)); ldap_log(LOG_DEBUG, logbuf); return RETURN_TRUE; }; #else if((rc = ldap_bind_s(session->sess, fullname, password, LDAP_AUTH_SIMPLE))!=LDAP_SUCCESS) { snprintf(logbuf, MAXLOGBUF, "Ldap server %s authentificate failed: %s", ldap_authorization_host, ldap_err2string(rc)); ldap_log(LOG_DEBUG, logbuf); return RETURN_TRUE; } #endif if ((rc = ldap_search_ext_s(session->sess, ldap_authorization_basedn, LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res)) != LDAP_SUCCESS) { #if LDAP_API_VERSION > 3000 ldap_unbind_ext(session->sess, NULL, NULL); #else ldap_unbind(session->sess); #endif return RETURN_TRUE; } for (entry = ldap_first_entry(session->sess,res); entry!=NULL && count<=ldap_count_messages(session->sess, res); entry=ldap_next_entry(session->sess, res)) { count++; for(attr = ldap_first_attribute(session->sess,entry,&ber); attr != NULL ; attr=ldap_next_attribute(session->sess,entry,ber)) { snprintf(logbuf, MAXLOGBUF, "Found attribute %s", attr); ldap_log(LOG_DEBUG, logbuf); if (strcmp(attr, "cn")) continue; if ((list_of_values = ldap_get_values_len(session->sess, entry, attr)) != NULL ) { value = *list_of_values[0]; char temp[MAXGROUPLIST]; memset(temp, 0, MAXGROUPLIST); if (ldap_authorization_validgroups) { strcpy(temp, ldap_authorization_validgroups); validgroups = strtok(temp, ","); while (validgroups != NULL) { snprintf(logbuf, MAXLOGBUF, "Attribute value validgroups ? value.bv_val >> %s ? %s", validgroups, value.bv_val); ldap_log(LOG_DEBUG, logbuf); if (!strcmp(validgroups, value.bv_val)) { ldap_msgfree(res); #if LDAP_API_VERSION > 3000 ldap_unbind_ext(session->sess, NULL, NULL); #else ldap_unbind(session->sess); #endif dn = malloc((int)strlen(value.bv_val)*sizeof(char)); memset(dn, 0, (int)strlen(value.bv_val)*sizeof(char)); strcpy(dn, value.bv_val); return dn; } validgroups = strtok (NULL, ","); } // printf("VAL: %s\n", value.bv_val); ldap_value_free_len( list_of_values ); } } } res = ldap_next_message(session->sess, res); }; ldap_msgfree(res); #if LDAP_API_VERSION > 3000 ldap_unbind_ext(session->sess, NULL, NULL); #else ldap_unbind(session->sess); #endif return RETURN_TRUE; }
static void do_addel( char *uri, char *manager, struct berval *passwd, char *entry, LDAPMod **attrs, int maxloop, int maxretries, int delay, int friendly, int chaserefs ) { LDAP *ld = NULL; int i = 0, do_retry = maxretries; int rc = LDAP_SUCCESS; int version = LDAP_VERSION3; retry:; ldap_initialize( &ld, uri ); if ( ld == NULL ) { tester_perror( "ldap_initialize", NULL ); exit( EXIT_FAILURE ); } (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); if ( do_retry == maxretries ) { fprintf( stderr, "PID=%ld - Add/Delete(%d): entry=\"%s\".\n", (long) pid, maxloop, entry ); } rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); switch ( rc ) { case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { do_retry--; if ( delay != 0 ) { sleep( delay ); } goto retry; } /* fallthru */ default: break; } exit( EXIT_FAILURE ); } for ( ; i < maxloop; i++ ) { /* add the entry */ rc = ldap_add_ext_s( ld, entry, attrs, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_add_ext_s", NULL ); switch ( rc ) { case LDAP_ALREADY_EXISTS: /* NOTE: this likely means * the delete failed * during the previous round... */ if ( !friendly ) { goto done; } break; case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { do_retry--; goto retry; } /* fall thru */ default: goto done; } } #if 0 /* wait a second for the add to really complete */ /* This masks some race conditions though. */ sleep( 1 ); #endif /* now delete the entry again */ rc = ldap_delete_ext_s( ld, entry, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_delete_ext_s", NULL ); switch ( rc ) { case LDAP_NO_SUCH_OBJECT: /* NOTE: this likely means * the add failed * during the previous round... */ if ( !friendly ) { goto done; } break; case LDAP_BUSY: case LDAP_UNAVAILABLE: if ( do_retry > 0 ) { do_retry--; goto retry; } /* fall thru */ default: goto done; } } } done:; fprintf( stderr, " PID=%ld - Add/Delete done (%d).\n", (long) pid, rc ); ldap_unbind_ext( ld, NULL, NULL ); }
/* * Bind to a LDAP server via SSL port. * Require server certificate verification. * * In 5.5. mix mode, replication goes through ldaps port. */ DWORD VmDirSSLBind( LDAP** ppLd, PCSTR pszURI, PCSTR pszDN, PCSTR pszPassword ) { DWORD dwError = 0; int retVal = 0; LDAP* pLd = NULL; BerValue ldapBindPwd = {0}; const int ldapVer = LDAP_VERSION3; int iTLSDEMAND = LDAP_OPT_X_TLS_DEMAND; int iTLSMin = LDAP_OPT_X_TLS_PROTOCOL_TLS1_0; PSTR pszTrustCertFile = NULL; SSL_CTX* pSslCtx = NULL; if ( ppLd == NULL || pszURI == NULL ) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } // only allow ldaps traffic over SSL port if ( VmDirStringNCompareA( pszURI, VMDIR_LDAPS_PROTOCOL, 5, FALSE) != 0 ) { dwError = VMDIR_ERROR_ACCESS_DENIED; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirPrepareOpensslClientCtx( &pSslCtx, &pszTrustCertFile, pszURI ); BAIL_ON_VMDIR_ERROR(dwError); retVal = ldap_set_option( NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &iTLSDEMAND); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_set_option(NULL, LDAP_OPT_X_TLS_PROTOCOL_MIN, &iTLSMin); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_initialize(&pLd, pszURI); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_set_option(pLd, LDAP_OPT_PROTOCOL_VERSION, &ldapVer); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_set_option( pLd, LDAP_OPT_X_TLS_CTX, pSslCtx); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); ldapBindPwd.bv_val = 0; ldapBindPwd.bv_len = 0; if (pszPassword) { ldapBindPwd.bv_val = (PSTR) pszPassword; ldapBindPwd.bv_len = (ULONG) VmDirStringLenA(pszPassword); } retVal = ldap_sasl_bind_s( pLd, pszDN, LDAP_SASL_SIMPLE, &ldapBindPwd, // ldaps with credentials NULL, NULL, NULL); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); *ppLd = pLd; cleanup: if (pSslCtx) { SSL_CTX_free(pSslCtx); } VMDIR_SAFE_FREE_MEMORY(pszTrustCertFile); return dwError; ldaperror: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSSLBind failed for %s %s. (%d)(%s)", pszURI, pszDN, retVal, ldap_err2string(retVal)); dwError = VmDirMapLdapError(retVal); error: if (retVal == 0) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "_VmDirSSLBind failed. (%u)", dwError); } if ( pLd ) { ldap_unbind_ext_s( pLd, NULL, NULL); } goto cleanup; }
/* * There is NO password supplied in anonymous bind. * This is the only place we allow LDAP_SASL_SIMPLE bind over port 389. * * Thus, NO credentials would ever go over clear text channel. */ DWORD VmDirAnonymousLDAPBind( LDAP** ppLd, PCSTR pszLdapURI ) { DWORD dwError = 0; int retVal = 0; const int ldapVer = LDAP_VERSION3; BerValue ldapBindPwd = {0}; LDAP* pLocalLd = NULL; if (ppLd == NULL || pszLdapURI == NULL) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } retVal = ldap_initialize( &pLocalLd, pszLdapURI); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_set_option( pLocalLd, LDAP_OPT_PROTOCOL_VERSION, &ldapVer); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); ldapBindPwd.bv_val = NULL; ldapBindPwd.bv_len = 0; retVal = ldap_sasl_bind_s( pLocalLd, "", LDAP_SASL_SIMPLE, &ldapBindPwd, // no credentials NULL, NULL, NULL); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); *ppLd = pLocalLd; cleanup: return dwError; ldaperror: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirAnonymousLDAPBind to (%s) failed. (%d)(%s)", VDIR_SAFE_STRING(pszLdapURI), retVal, ldap_err2string(retVal) ); dwError = VmDirMapLdapError(retVal); error: if (retVal == 0) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "VmDirAnonymousLDAPBind to (%s) failed. (%u)", VDIR_SAFE_STRING(pszLdapURI), dwError); } if (pLocalLd) { ldap_unbind_ext_s( pLocalLd, NULL, NULL); } goto cleanup; }
/* The caller is responsible for unbinding the connection if ld is not NULL */ static LDAP * connect_ldap(const char *hostname, const char *binddn, const char *bindpw) { LDAP *ld = NULL; int ssl = LDAP_OPT_X_TLS_HARD; int version = LDAP_VERSION3; int ret; int ldapdebug = 0; char *uri; struct berval bindpw_bv; if (debug) { ldapdebug=2; ret = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldapdebug); } if (ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, CAFILE) != LDAP_OPT_SUCCESS) goto fail; ret = asprintf(&uri, "ldaps://%s:636", hostname); if (ret == -1) { fprintf(stderr, _("Out of memory!")); goto fail; } ret = ldap_initialize(&ld, uri); free(uri); if(ret != LDAP_SUCCESS) { fprintf(stderr, _("Unable to initialize connection to ldap server: %s"), ldap_err2string(ret)); goto fail; } if (ldap_set_option(ld, LDAP_OPT_X_TLS, &ssl) != LDAP_OPT_SUCCESS) { fprintf(stderr, _("Unable to enable SSL in LDAP\n")); goto fail; } /* Don't do DNS canonicalization */ ret = ldap_set_option(ld, LDAP_OPT_X_SASL_NOCANON, LDAP_OPT_ON); if (ret != LDAP_SUCCESS) { fprintf(stderr, _("Unable to set LDAP_OPT_X_SASL_NOCANON\n")); goto fail; } ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); if (ret != LDAP_SUCCESS) { fprintf(stderr, _("Unable to set LDAP version\n")); goto fail; } if (bindpw) { bindpw_bv.bv_val = discard_const(bindpw); bindpw_bv.bv_len = strlen(bindpw); } else { bindpw_bv.bv_val = NULL; bindpw_bv.bv_len = 0; } ret = ldap_sasl_bind_s(ld, binddn, LDAP_SASL_SIMPLE, &bindpw_bv, NULL, NULL, NULL); if (ret != LDAP_SUCCESS) { int err; ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &err); if (debug) fprintf(stderr, _("Bind failed: %s\n"), ldap_err2string(err)); goto fail; } return ld; fail: if (ld != NULL) { ldap_unbind_ext(ld, NULL, NULL); } return NULL; }
int ldap_connect(char* _ld_name) { int rc; int ldap_proto_version; struct ld_session* lds; struct berval ldap_cred; struct berval* ldap_credp; /* struct berval* serv_cred = (struct berval*)pkg_malloc(sizeof(struct berval)); if(!serv_cred){ LM_ERR("Out of mem\n"); return -1; } */ /* * get ld session and session config parameters */ if ((lds = get_ld_session(_ld_name)) == NULL) { LM_ERR("ld_session [%s] not found\n", _ld_name); return -1; } /* * ldap_initialize */ rc = ldap_initialize(&lds->handle, lds->host_name); if (rc != LDAP_SUCCESS) { LM_ERR( "[%s]: ldap_initialize (%s) failed: %s\n", _ld_name, lds->host_name, ldap_err2string(rc)); return -1; } /* * set LDAP OPTIONS */ /* LDAP_OPT_PROTOCOL_VERSION */ switch (lds->version) { case 2: ldap_proto_version = LDAP_VERSION2; break; case 3: ldap_proto_version = LDAP_VERSION3; break; default: LM_ERR( "[%s]: Invalid LDAP protocol version [%d]\n", _ld_name, lds->version); return -1; } if (ldap_set_option(lds->handle, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto_version) != LDAP_OPT_SUCCESS) { LM_ERR( "[%s]: Could not set LDAP_OPT_PROTOCOL_VERSION [%d]\n", _ld_name, ldap_proto_version); return -1; } /* LDAP_OPT_RESTART */ if (ldap_set_option(lds->handle, LDAP_OPT_RESTART, LDAP_OPT_ON) != LDAP_OPT_SUCCESS) { LM_ERR("[%s]: Could not set LDAP_OPT_RESTART to ON\n", _ld_name); return -1; } /* LDAP_OPT_TIMELIMIT */ /* if (lds->server_search_timeout > 0) { if (ldap_set_option(lds->handle, LDAP_OPT_TIMELIMIT, &lds->server_search_timeout) != LDAP_OPT_SUCCESS) { LM_ERR("[%s]: Could not set LDAP_OPT_TIMELIMIT to [%d]\n", _ld_name, lds->server_search_timeout); return -1; } } */ /* LDAP_OPT_NETWORK_TIMEOUT */ if ((lds->network_timeout.tv_sec > 0) || (lds->network_timeout.tv_usec > 0)) { if (ldap_set_option(lds->handle, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&lds->network_timeout) != LDAP_OPT_SUCCESS) { LM_ERR( "[%s]: Could not set" " LDAP_NETWORK_TIMEOUT to [%d.%d]\n", _ld_name, (int)lds->network_timeout.tv_sec, (int)lds->network_timeout.tv_usec); } } /* if timeout == 0 then use default */ if ((lds->client_bind_timeout.tv_sec == 0) && (lds->client_bind_timeout.tv_usec == 0)) { lds->client_bind_timeout.tv_sec = CFG_DEF_LDAP_CLIENT_BIND_TIMEOUT / 1000; lds->client_bind_timeout.tv_usec = (CFG_DEF_LDAP_CLIENT_BIND_TIMEOUT % 1000) * 1000; } rc = ldap_set_option(lds->handle, LDAP_OPT_TIMEOUT, &lds->client_bind_timeout); if(rc != LDAP_SUCCESS){ LM_ERR("[%s]: ldap set option LDAP_OPT_TIMEOUT failed\n", _ld_name); return -1; } /* if no "ldap_bind_password" then anonymous */ ldap_cred.bv_val = lds->bind_pwd; ldap_cred.bv_len = strlen(lds->bind_pwd); if(ldap_cred.bv_len == 0 || ldap_cred.bv_val[0]==0){ ldap_credp = NULL; }else{ ldap_credp = &ldap_cred; } /* * ldap_sasl_bind (LDAP_SASL_SIMPLE) */ rc = ldap_sasl_bind_s( lds->handle, lds->bind_dn, LDAP_SASL_SIMPLE, ldap_credp, NULL, NULL, NULL /*&serv_cred */ ); if (rc != LDAP_SUCCESS) { LM_ERR( "[%s]: ldap bind failed: %s\n", _ld_name, ldap_err2string(rc)); return -1; } LM_DBG( "[%s]: LDAP bind successful (ldap_host [%s])\n", _ld_name, lds->host_name); return 0; }
DWORD VMCALdapConnect( PSTR pszHostName, DWORD dwPort, PSTR pszUsername, PSTR pszPassword, PVMCA_LDAP_CONTEXT* ppLotus ) { DWORD dwError = 0; PVMCA_LDAP_CONTEXT pContext = NULL; PSTR pszUrl = NULL; BerValue ldapBindPwd = {0}; //LDAP_SUCCESS is defined as Zero in the Standard // Which plays well with our BAIL_ON_ERROR macro DWORD dwVersion = LDAP_VERSION3; DWORD dwReturns = 20; if(dwPort == 0) { // Let us use the default LDAP_PORT, 389 dwPort = LDAP_PORT; } dwError = VMCAAllocateMemory(sizeof(*pContext), (PVOID*)&pContext); BAIL_ON_ERROR(dwError); if (VMCAIsIPV6AddrFormat(pszHostName)) { dwError = VMCAAllocateStringPrintfA( &pszUrl, "ldap://[%s]:%d", pszHostName, dwPort); } else { dwError = VMCAAllocateStringPrintfA( &pszUrl, "ldap://%s:%d", pszHostName, dwPort); } BAIL_ON_ERROR(dwError); if(IsNullOrEmptyString(pszPassword)) { // no credentials, do anonymous bind. dwError = ldap_initialize(&pContext->pConnection, pszUrl); BAIL_ON_ERROR(dwError); if (pContext->pConnection == NULL) { ldap_get_option(pContext->pConnection, LDAP_OPT_ERROR_NUMBER, &dwError); //dwError = ld_errno; //LdapGetLastError(); BAIL_ON_ERROR(dwError); } dwError = ldap_set_option(pContext->pConnection, LDAP_OPT_PROTOCOL_VERSION, (void*)&dwVersion); BAIL_ON_ERROR(dwError); dwError = ldap_set_option(pContext->pConnection, LDAP_OPT_SIZELIMIT, (void*)& dwReturns); BAIL_ON_ERROR(dwError); dwError = ldap_sasl_bind_s( pContext->pConnection, pszUsername, LDAP_SASL_SIMPLE, &ldapBindPwd, // no credentials NULL, NULL, NULL); } else { dwError = VmCASASLSRPBind( &pContext->pConnection, pszUrl, pszUsername, pszPassword); } #ifdef LDAP_ERROR_MESSAGE if(dwError != 0) { printf("Error :%s\n",ldap_err2string(dwError)); } #endif BAIL_ON_ERROR(dwError); *ppLotus = pContext; cleanup: VMCA_SAFE_FREE_STRINGA(pszUrl); return dwError; error: if ((dwError != 0) && pContext) { VMCALdapClose(pContext); } goto cleanup; }
/* perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can we fit on one socket??) */ static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads, const char *sasl, enum credentials_use_kerberos krb5_state, const char *target_service, const char *target_hostname, const DATA_BLOB server_blob) { DATA_BLOB blob_in = data_blob_null; DATA_BLOB blob_out = data_blob_null; int rc; NTSTATUS nt_status; ADS_STATUS status; struct auth_generic_state *auth_generic_state; bool use_spnego_principal = lp_client_use_spnego_principal(); const char *sasl_list[] = { sasl, NULL }; NTTIME end_nt_time; nt_status = auth_generic_client_prepare(NULL, &auth_generic_state); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) { return ADS_ERROR_NT(nt_status); } if (server_blob.length == 0) { use_spnego_principal = false; } if (krb5_state == CRED_DONT_USE_KERBEROS) { use_spnego_principal = false; } cli_credentials_set_kerberos_state(auth_generic_state->credentials, krb5_state); if (target_service != NULL) { nt_status = gensec_set_target_service( auth_generic_state->gensec_security, target_service); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } } if (target_hostname != NULL) { nt_status = gensec_set_target_hostname( auth_generic_state->gensec_security, target_hostname); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } } if (target_service != NULL && target_hostname != NULL) { use_spnego_principal = false; } switch (ads->ldap.wrap_type) { case ADS_SASLWRAP_TYPE_SEAL: gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL); break; case ADS_SASLWRAP_TYPE_SIGN: if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); } else { /* * windows servers are broken with sign only, * so we let the NTLMSSP backend to seal here, * via GENSEC_FEATURE_LDAP_STYLE. */ gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE); } break; case ADS_SASLWRAP_TYPE_PLAIN: break; } nt_status = auth_generic_client_start_by_sasl(auth_generic_state, sasl_list); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } rc = LDAP_SASL_BIND_IN_PROGRESS; nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; if (use_spnego_principal) { blob_in = data_blob_dup_talloc(talloc_tos(), server_blob); if (blob_in.length == 0) { TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } } else { blob_in = data_blob_null; } blob_out = data_blob_null; while (true) { struct berval cred, *scred = NULL; nt_status = gensec_update(auth_generic_state->gensec_security, talloc_tos(), blob_in, &blob_out); data_blob_free(&blob_in); if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(auth_generic_state); data_blob_free(&blob_out); return ADS_ERROR_NT(nt_status); } if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) { break; } cred.bv_val = (char *)blob_out.data; cred.bv_len = blob_out.length; scred = NULL; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred); data_blob_free(&blob_out); if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) { if (scred) { ber_bvfree(scred); } TALLOC_FREE(auth_generic_state); return ADS_ERROR(rc); } if (scred) { blob_in = data_blob_talloc(talloc_tos(), scred->bv_val, scred->bv_len); if (blob_in.length != scred->bv_len) { ber_bvfree(scred); TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } ber_bvfree(scred); } else { blob_in = data_blob_null; } if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) { break; } } data_blob_free(&blob_in); data_blob_free(&blob_out); if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) { bool ok; ok = gensec_have_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL); if (!ok) { DEBUG(0,("The gensec feature sealing request, but unavailable\n")); TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); } ok = gensec_have_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); if (!ok) { DEBUG(0,("The gensec feature signing request, but unavailable\n")); TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); } } else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) { bool ok; ok = gensec_have_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); if (!ok) { DEBUG(0,("The gensec feature signing request, but unavailable\n")); TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); } } ads->auth.tgs_expire = LONG_MAX; end_nt_time = gensec_expire_time(auth_generic_state->gensec_security); if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) { struct timeval tv; nttime_to_timeval(&tv, end_nt_time); ads->auth.tgs_expire = tv.tv_sec; } if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security); ads->ldap.out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security); ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped; /* * Note that we have to truncate this to 0x2C * (taken from a capture with LDAP unbind), as the * signature size is not constant for Kerberos with * arcfour-hmac-md5. */ ads->ldap.in.min_wrapped = MIN(ads->ldap.out.sig_size, 0x2C); ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED; status = ads_setup_sasl_wrapping(ads, &ads_sasl_gensec_ops, auth_generic_state->gensec_security); if (!ADS_ERR_OK(status)) { DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", ads_errstr(status))); TALLOC_FREE(auth_generic_state); return status; } /* Only keep the gensec_security element around long-term */ talloc_steal(NULL, auth_generic_state->gensec_security); } TALLOC_FREE(auth_generic_state); return ADS_ERROR(rc); }
/* perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can we fit on one socket??) */ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads) { DATA_BLOB msg1 = data_blob_null; DATA_BLOB blob = data_blob_null; DATA_BLOB blob_in = data_blob_null; DATA_BLOB blob_out = data_blob_null; struct berval cred, *scred = NULL; int rc; NTSTATUS nt_status; ADS_STATUS status; int turn = 1; uint32 features = 0; struct ntlmssp_state *ntlmssp_state; nt_status = ntlmssp_client_start(NULL, lp_netbios_name(), lp_workgroup(), lp_client_ntlmv2_auth(), &ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) { return ADS_ERROR_NT(nt_status); } switch (ads->ldap.wrap_type) { case ADS_SASLWRAP_TYPE_SEAL: features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL; break; case ADS_SASLWRAP_TYPE_SIGN: if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { features = NTLMSSP_FEATURE_SIGN; } else { /* * windows servers are broken with sign only, * so we need to use seal here too */ features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL; ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL; } break; case ADS_SASLWRAP_TYPE_PLAIN: break; } ntlmssp_want_feature(ntlmssp_state, features); blob_in = data_blob_null; do { nt_status = ntlmssp_update(ntlmssp_state, blob_in, &blob_out); data_blob_free(&blob_in); if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) && blob_out.length) { if (turn == 1) { const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL}; /* and wrap it in a SPNEGO wrapper */ msg1 = spnego_gen_negTokenInit(talloc_tos(), OIDs_ntlm, &blob_out, NULL); } else { /* wrap it in SPNEGO */ msg1 = spnego_gen_auth(talloc_tos(), blob_out); } data_blob_free(&blob_out); cred.bv_val = (char *)msg1.data; cred.bv_len = msg1.length; scred = NULL; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); data_blob_free(&msg1); if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) { if (scred) { ber_bvfree(scred); } TALLOC_FREE(ntlmssp_state); return ADS_ERROR(rc); } if (scred) { blob = data_blob(scred->bv_val, scred->bv_len); ber_bvfree(scred); } else { blob = data_blob_null; } } else { TALLOC_FREE(ntlmssp_state); data_blob_free(&blob_out); return ADS_ERROR_NT(nt_status); } if ((turn == 1) && (rc == LDAP_SASL_BIND_IN_PROGRESS)) { DATA_BLOB tmp_blob = data_blob_null; /* the server might give us back two challenges */ if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in, &tmp_blob)) { TALLOC_FREE(ntlmssp_state); data_blob_free(&blob); DEBUG(3,("Failed to parse challenges\n")); return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); } data_blob_free(&tmp_blob); } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) { if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP, &blob_in)) { TALLOC_FREE(ntlmssp_state); data_blob_free(&blob); DEBUG(3,("Failed to parse auth response\n")); return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); } } data_blob_free(&blob); data_blob_free(&blob_out); turn++; } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status)); /* we have a reference conter on ntlmssp_state, if we are signing then the state will be kept by the signing engine */ if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE; ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE; ads->ldap.in.min_wrapped = ads->ldap.out.sig_size; ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED; status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state); if (!ADS_ERR_OK(status)) { DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", ads_errstr(status))); TALLOC_FREE(ntlmssp_state); return status; } } else { TALLOC_FREE(ntlmssp_state); } return ADS_ERROR(rc); }
/* this performs a SASL/SPNEGO bind */ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) { TALLOC_CTX *frame = talloc_stackframe(); struct ads_service_principal p = {0}; struct berval *scred=NULL; int rc, i; ADS_STATUS status; DATA_BLOB blob = data_blob_null; char *given_principal = NULL; char *OIDs[ASN1_MAX_OIDS]; #ifdef HAVE_KRB5 bool got_kerberos_mechanism = False; #endif const char *mech = NULL; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred); if (rc != LDAP_SASL_BIND_IN_PROGRESS) { status = ADS_ERROR(rc); goto done; } blob = data_blob(scred->bv_val, scred->bv_len); ber_bvfree(scred); #if 0 file_save("sasl_spnego.dat", blob.data, blob.length); #endif /* the server sent us the first part of the SPNEGO exchange in the negprot reply */ if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) || OIDs[0] == NULL) { status = ADS_ERROR(LDAP_OPERATIONS_ERROR); goto done; } TALLOC_FREE(given_principal); /* make sure the server understands kerberos */ for (i=0;OIDs[i];i++) { DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i])); #ifdef HAVE_KRB5 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || strcmp(OIDs[i], OID_KERBEROS5) == 0) { got_kerberos_mechanism = True; } #endif talloc_free(OIDs[i]); } status = ads_generate_service_principal(ads, &p); if (!ADS_ERR_OK(status)) { goto done; } #ifdef HAVE_KRB5 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) && got_kerberos_mechanism) { mech = "KRB5"; if (ads->auth.password == NULL || ads->auth.password[0] == '\0') { status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", CRED_MUST_USE_KERBEROS, p.service, p.hostname, blob); if (ADS_ERR_OK(status)) { ads_free_service_principal(&p); goto done; } DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, " "calling kinit\n", ads_errstr(status))); } status = ADS_ERROR_KRB5(ads_kinit_password(ads)); if (ADS_ERR_OK(status)) { status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", CRED_MUST_USE_KERBEROS, p.service, p.hostname, blob); if (!ADS_ERR_OK(status)) { DEBUG(0,("kinit succeeded but " "ads_sasl_spnego_gensec_bind(KRB5) failed " "for %s/%s with user[%s] realm[%s]: %s\n", p.service, p.hostname, ads->auth.user_name, ads->auth.realm, ads_errstr(status))); } } /* only fallback to NTLMSSP if allowed */ if (ADS_ERR_OK(status) || !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) { goto done; } DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed " "for %s/%s with user[%s] realm[%s]: %s, " "fallback to NTLMSSP\n", p.service, p.hostname, ads->auth.user_name, ads->auth.realm, ads_errstr(status))); } #endif /* lets do NTLMSSP ... this has the big advantage that we don't need to sync clocks, and we don't rely on special versions of the krb5 library for HMAC_MD4 encryption */ mech = "NTLMSSP"; status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", CRED_DONT_USE_KERBEROS, p.service, p.hostname, data_blob_null); done: if (!ADS_ERR_OK(status)) { DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed " "for %s/%s with user[%s] realm=[%s]: %s\n", mech, p.service, p.hostname, ads->auth.user_name, ads->auth.realm, ads_errstr(status))); } ads_free_service_principal(&p); TALLOC_FREE(frame); if (blob.data != NULL) { data_blob_free(&blob); } return status; }
static int do_bind( char *uri, char *dn, struct berval *pass, int maxloop, int force, int chaserefs, int noinit, LDAP **ldp, int action_type, void *action ) { LDAP *ld = ldp ? *ldp : NULL; int i, rc = -1; /* for internal search */ int timelimit = 0; int sizelimit = 0; switch ( action_type ) { case -1: break; case TESTER_SEARCH: { LDAPURLDesc *ludp = (LDAPURLDesc *)action; assert( action != NULL ); if ( ludp->lud_exts != NULL ) { for ( i = 0; ludp->lud_exts[ i ] != NULL; i++ ) { char *ext = ludp->lud_exts[ i ]; int crit = 0; if (ext[0] == '!') { crit++; ext++; } if ( strncasecmp( ext, "x-timelimit=", STRLENOF( "x-timelimit=" ) ) == 0 ) { if ( lutil_atoi( &timelimit, &ext[ STRLENOF( "x-timelimit=" ) ] ) && crit ) { tester_error( "unable to parse critical extension x-timelimit" ); } } else if ( strncasecmp( ext, "x-sizelimit=", STRLENOF( "x-sizelimit=" ) ) == 0 ) { if ( lutil_atoi( &sizelimit, &ext[ STRLENOF( "x-sizelimit=" ) ] ) && crit ) { tester_error( "unable to parse critical extension x-sizelimit" ); } } else if ( crit ) { tester_error( "unknown critical extension" ); } } } } break; default: /* nothing to do yet */ break; } if ( maxloop > 1 ) { fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n", (long) pid, maxloop, dn ); } for ( i = 0; i < maxloop; i++ ) { if ( !noinit || ld == NULL ) { int version = LDAP_VERSION3; ldap_initialize( &ld, uri ); if ( ld == NULL ) { tester_perror( "ldap_initialize", NULL ); rc = -1; break; } (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF ); } rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL ); if ( rc ) { int first = tester_ignore_err( rc ); /* if ignore.. */ if ( first ) { /* only log if first occurrence */ if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) { tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); } rc = LDAP_SUCCESS; } else { tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); } } switch ( action_type ) { case -1: break; case TESTER_SEARCH: { LDAPURLDesc *ludp = (LDAPURLDesc *)action; LDAPMessage *res = NULL; struct timeval tv = { 0 }, *tvp = NULL; if ( timelimit ) { tv.tv_sec = timelimit; tvp = &tv; } assert( action != NULL ); rc = ldap_search_ext_s( ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, 0, NULL, NULL, tvp, sizelimit, &res ); ldap_msgfree( res ); } break; default: /* nothing to do yet */ break; } if ( !noinit ) { ldap_unbind_ext( ld, NULL, NULL ); ld = NULL; } if ( rc != LDAP_SUCCESS ) { break; } } if ( maxloop > 1 ) { fprintf( stderr, " PID=%ld - Bind done (%d).\n", (long) pid, rc ); } if ( ldp && noinit ) { *ldp = ld; } else if ( ld != NULL ) { ldap_unbind_ext( ld, NULL, NULL ); } return rc; }
/* perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can we fit on one socket??) */ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads) { DATA_BLOB msg1 = data_blob_null; DATA_BLOB blob = data_blob_null; DATA_BLOB blob_in = data_blob_null; DATA_BLOB blob_out = data_blob_null; struct berval cred, *scred = NULL; int rc; NTSTATUS nt_status; ADS_STATUS status; int turn = 1; struct auth_generic_state *auth_generic_state; nt_status = auth_generic_client_prepare(NULL, &auth_generic_state); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) { return ADS_ERROR_NT(nt_status); } switch (ads->ldap.wrap_type) { case ADS_SASLWRAP_TYPE_SEAL: gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL); break; case ADS_SASLWRAP_TYPE_SIGN: if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); } else { /* * windows servers are broken with sign only, * so we need to use seal here too */ gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL); ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL; } break; case ADS_SASLWRAP_TYPE_PLAIN: break; } nt_status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } blob_in = data_blob_null; do { nt_status = gensec_update(auth_generic_state->gensec_security, talloc_tos(), NULL, blob_in, &blob_out); data_blob_free(&blob_in); if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) && blob_out.length) { if (turn == 1) { const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL}; /* and wrap it in a SPNEGO wrapper */ msg1 = spnego_gen_negTokenInit(talloc_tos(), OIDs_ntlm, &blob_out, NULL); } else { /* wrap it in SPNEGO */ msg1 = spnego_gen_auth(talloc_tos(), blob_out); } data_blob_free(&blob_out); cred.bv_val = (char *)msg1.data; cred.bv_len = msg1.length; scred = NULL; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); data_blob_free(&msg1); if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) { if (scred) { ber_bvfree(scred); } TALLOC_FREE(auth_generic_state); return ADS_ERROR(rc); } if (scred) { blob = data_blob(scred->bv_val, scred->bv_len); ber_bvfree(scred); } else { blob = data_blob_null; } } else { TALLOC_FREE(auth_generic_state); data_blob_free(&blob_out); return ADS_ERROR_NT(nt_status); } if ((turn == 1) && (rc == LDAP_SASL_BIND_IN_PROGRESS)) { DATA_BLOB tmp_blob = data_blob_null; /* the server might give us back two challenges */ if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in, &tmp_blob)) { TALLOC_FREE(auth_generic_state); data_blob_free(&blob); DEBUG(3,("Failed to parse challenges\n")); return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); } data_blob_free(&tmp_blob); } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) { if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP, &blob_in)) { TALLOC_FREE(auth_generic_state); data_blob_free(&blob); DEBUG(3,("Failed to parse auth response\n")); return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); } } data_blob_free(&blob); data_blob_free(&blob_out); turn++; } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status)); if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { uint32_t sig_size = gensec_sig_size(auth_generic_state->gensec_security, 0); ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - sig_size; ads->ldap.out.sig_size = sig_size; ads->ldap.in.min_wrapped = ads->ldap.out.sig_size; ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED; status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security); if (!ADS_ERR_OK(status)) { DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", ads_errstr(status))); TALLOC_FREE(auth_generic_state); return status; } /* Only keep the gensec_security element around long-term */ talloc_steal(NULL, auth_generic_state->gensec_security); } TALLOC_FREE(auth_generic_state); return ADS_ERROR(rc); }
static int do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr, int maxloop, int force, int chaserefs, int noinit, int delay, int action_type, void *action ) { LDAP *ld = NULL; int i = 0; int rc = LDAP_SUCCESS; ber_int_t msgid; LDAPMessage *res, *msg; char **dns = NULL; struct berval *creds = NULL; char *attrs[] = { LDAP_NO_ATTRS, NULL }; int ndns = 0; #ifdef _WIN32 DWORD beg, end; #else struct timeval beg, end; #endif int version = LDAP_VERSION3; char *nullstr = ""; ldap_initialize( &ld, uri ); if ( ld == NULL ) { tester_perror( "ldap_initialize", NULL ); exit( EXIT_FAILURE ); } (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF ); rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); exit( EXIT_FAILURE ); } fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n", (long) pid, maxloop, base, filter, pwattr ); if ( pwattr != NULL ) { attrs[ 0 ] = pwattr; } rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, 0, 0, &msgid ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_search_ext", NULL ); exit( EXIT_FAILURE ); } while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 ) { BerElement *ber; struct berval bv; int done = 0; for ( msg = ldap_first_message( ld, res ); msg; msg = ldap_next_message( ld, msg ) ) { switch ( ldap_msgtype( msg ) ) { case LDAP_RES_SEARCH_ENTRY: rc = ldap_get_dn_ber( ld, msg, &ber, &bv ); dns = realloc( dns, (ndns + 1)*sizeof(char *) ); dns[ndns] = ber_strdup( bv.bv_val ); if ( pwattr != NULL ) { struct berval **values = ldap_get_values_len( ld, msg, pwattr ); creds = realloc( creds, (ndns + 1)*sizeof(struct berval) ); if ( values == NULL ) { novals:; creds[ndns].bv_len = 0; creds[ndns].bv_val = nullstr; } else { static struct berval cleartext = BER_BVC( "{CLEARTEXT} " ); struct berval value = *values[ 0 ]; if ( value.bv_val[ 0 ] == '{' ) { char *end = ber_bvchr( &value, '}' ); if ( end ) { if ( ber_bvcmp( &value, &cleartext ) == 0 ) { value.bv_val += cleartext.bv_len; value.bv_len -= cleartext.bv_len; } else { ldap_value_free_len( values ); goto novals; } } } ber_dupbv( &creds[ndns], &value ); ldap_value_free_len( values ); } } ndns++; ber_free( ber, 0 ); break; case LDAP_RES_SEARCH_RESULT: done = 1; break; } if ( done ) break; } ldap_msgfree( res ); if ( done ) break; } #ifdef _WIN32 beg = GetTickCount(); #else gettimeofday( &beg, NULL ); #endif if ( ndns == 0 ) { tester_error( "No DNs" ); return 1; } fprintf( stderr, " PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n", (long) pid, base, filter, ndns ); /* Ok, got list of DNs, now start binding to each */ for ( i = 0; i < maxloop; i++ ) { int j; struct berval cred = { 0, NULL }; #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */ j = rand() % ndns; #endif j = ((double)ndns)*rand()/(RAND_MAX + 1.0); if ( creds && !BER_BVISEMPTY( &creds[j] ) ) { cred = creds[j]; } if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld, action_type, action ) && !force ) { break; } if ( delay ) { sleep( delay ); } } if ( ld != NULL ) { ldap_unbind_ext( ld, NULL, NULL ); ld = NULL; } #ifdef _WIN32 end = GetTickCount(); end -= beg; fprintf( stderr, " PID=%ld - Bind done %d in %d.%03d seconds.\n", (long) pid, i, end / 1000, end % 1000 ); #else gettimeofday( &end, NULL ); end.tv_usec -= beg.tv_usec; if (end.tv_usec < 0 ) { end.tv_usec += 1000000; end.tv_sec -= 1; } end.tv_sec -= beg.tv_sec; fprintf( stderr, " PID=%ld - Bind done %d in %ld.%06ld seconds.\n", (long) pid, i, (long) end.tv_sec, (long) end.tv_usec ); #endif if ( dns ) { for ( i = 0; i < ndns; i++ ) { ber_memfree( dns[i] ); } free( dns ); } if ( creds ) { for ( i = 0; i < ndns; i++ ) { if ( creds[i].bv_val != nullstr ) { ber_memfree( creds[i].bv_val ); } } free( creds ); } return 0; }
/* this performs a SASL/SPNEGO bind */ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) { struct berval *scred=NULL; int rc, i; ADS_STATUS status; DATA_BLOB blob; char *given_principal = NULL; char *OIDs[ASN1_MAX_OIDS]; #ifdef HAVE_KRB5 bool got_kerberos_mechanism = False; #endif rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred); if (rc != LDAP_SASL_BIND_IN_PROGRESS) { status = ADS_ERROR(rc); goto failed; } blob = data_blob(scred->bv_val, scred->bv_len); ber_bvfree(scred); #if 0 file_save("sasl_spnego.dat", blob.data, blob.length); #endif /* the server sent us the first part of the SPNEGO exchange in the negprot reply */ if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) || OIDs[0] == NULL) { data_blob_free(&blob); status = ADS_ERROR(LDAP_OPERATIONS_ERROR); goto failed; } data_blob_free(&blob); /* make sure the server understands kerberos */ for (i=0;OIDs[i];i++) { DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i])); #ifdef HAVE_KRB5 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || strcmp(OIDs[i], OID_KERBEROS5) == 0) { got_kerberos_mechanism = True; } #endif talloc_free(OIDs[i]); } DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal)); #ifdef HAVE_KRB5 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) && got_kerberos_mechanism) { struct ads_service_principal p; status = ads_generate_service_principal(ads, given_principal, &p); TALLOC_FREE(given_principal); if (!ADS_ERR_OK(status)) { return status; } status = ads_sasl_spnego_krb5_bind(ads, &p); if (ADS_ERR_OK(status)) { ads_free_service_principal(&p); return status; } DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, " "calling kinit\n", ads_errstr(status))); status = ADS_ERROR_KRB5(ads_kinit_password(ads)); if (ADS_ERR_OK(status)) { status = ads_sasl_spnego_krb5_bind(ads, &p); if (!ADS_ERR_OK(status)) { DEBUG(0,("kinit succeeded but " "ads_sasl_spnego_krb5_bind failed: %s\n", ads_errstr(status))); } } ads_free_service_principal(&p); /* only fallback to NTLMSSP if allowed */ if (ADS_ERR_OK(status) || !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) { return status; } } else #endif { TALLOC_FREE(given_principal); } /* lets do NTLMSSP ... this has the big advantage that we don't need to sync clocks, and we don't rely on special versions of the krb5 library for HMAC_MD4 encryption */ return ads_sasl_spnego_ntlmssp_bind(ads); failed: return status; }
/// @brief main loop /// @param argc number of arguments passed to program /// @param argv array of arguments passed to program int main(int argc, char * argv[]) { // local variables LDAPConfig config; struct timeval * timeoutp; LDAP * ld; int err; char * errmsg; //int opt; X509 * x; SSL * ssl; void * invalue; char msg[1024]; char * datafile; int skpos; STACK_OF(X509) * skx; BerValue cred; BerValue * servercredp; BIO * mem; int fd; char * fbuff; char rbuff[1024]; int flen; int rlen; void * ptr; // local variables for parsing cli arguments int c; int opt_index; static char short_opt[] = "23H:hT:qVv"; static struct option long_opt[] = { {"help", no_argument, 0, 'h'}, {"silent", no_argument, 0, 'q'}, {"quiet", no_argument, 0, 'q'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {NULL, 0, 0, 0 } }; // reset config data memset(&config, 0, sizeof(LDAPConfig)); memset(&cred, 0, sizeof(BerValue)); strncpy(config.ldap_url, "ldap://localhost/", 1024); config.ldap_version = LDAP_VERSION3; timeoutp = NULL; ssl = NULL; x = NULL; servercredp = NULL; // processes command line arguments while((c = getopt_long(argc, argv, short_opt, long_opt, &opt_index)) != -1) { switch(c) { case -1: /* no more arguments */ case 0: /* long options toggles */ break; case '2': config.ldap_version = LDAP_VERSION2; break; case '3': config.ldap_version = LDAP_VERSION3; break; case 'H': if ((ldap_url_parse(optarg, &config.ludp))) { fprintf(stderr, "ldap_url_parse(): invalid LDAP URL\n"); return(1); }; snprintf(config.ldap_url, 1024, "%s://%s:%i", config.ludp->lud_scheme, config.ludp->lud_host, config.ludp->lud_port); break; case 'h': ldappeerchain_usage(); return(0); case 'q': config.quiet++; break; case 'T': config.tcp_timeout.tv_sec = (int) strtol(optarg, NULL, 0); break; case 'V': ldappeerchain_version(); return(0); case 'v': config.verbose++; break; case '?': fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); return(1); default: fprintf(stderr, "%s: unrecognized option `-%c'\n", PROGRAM_NAME, c); fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); return(1); }; }; // checks for unknown options if (((optind+1) != argc) && (optind != argc)) { fprintf(stderr, "%s: too many arguments\n", PROGRAM_NAME); fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); return(1); }; datafile = NULL; if ((optind+1) == argc) datafile = argv[optind]; // checks for required arguments if (!(config.ludp)) { fprintf(stderr, "%s: missing required option `-H'\n", PROGRAM_NAME); fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); return(1); }; // // initializes LDAP instance // // initialize LDAP handle ldappeerchain_verbose(&config, "ldap_initialize()\n"); if ((err = ldap_initialize(&ld, config.ldap_url)) != LDAP_SUCCESS) { fprintf(stderr, "ldap_initialize(): %s\n", ldap_err2string(err)); return(1); }; // // configure's LDAP instance // // set LDAP protocol version ldappeerchain_verbose(&config, "ldap_set_option(LDAP_OPT_PROTOCOL_VERSION)\n"); err = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &config.ldap_version); if (err != LDAP_SUCCESS) { fprintf(stderr, "ldap_set_option(PROTOCOL_VERSION): %s\n", ldap_err2string(err)); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; // set TLS callback function argument version ldappeerchain_verbose(&config, "ldap_set_option(LDAP_OPT_X_TLS_CONNECT_ARG)\n"); err = ldap_set_option(ld, LDAP_OPT_X_TLS_CONNECT_ARG, &ssl); if (err != LDAP_SUCCESS) { fprintf(stderr, "ldap_set_option(LDAP_OPT_X_TLS_CONNECT_ARG): %s\n", ldap_err2string(err)); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; // set TLS callback function invalue = (void *)ldappeerchain_tls_cb; ldappeerchain_verbose(&config, "ldap_set_option(LDAP_OPT_X_TLS_CONNECT_CB)\n"); err = ldap_set_option(ld, LDAP_OPT_X_TLS_CONNECT_CB, invalue); if (err != LDAP_SUCCESS) { fprintf(stderr, "ldap_set_option(LDAP_OPT_X_TLS_CONNECT_CB): %s\n", ldap_err2string(err)); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; // set network timout if ((config.tcp_timeout.tv_sec)) { ldappeerchain_verbose(&config, "ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT)\n"); err = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &config.tcp_timeout); if (err != LDAP_SUCCESS) { fprintf(stderr, "ldap_set_option(SIZELIMIT): %s\n", ldap_err2string(err)); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; }; // // starts TLS/SSL connections // // starts connection if using TLS if ((strcasecmp(config.ludp->lud_scheme, "ldaps"))) { ldappeerchain_verbose(&config, "ldap_start_tls_s()\n"); err = ldap_start_tls_s(ld, NULL, NULL); switch(err) { case LDAP_SUCCESS: break; case LDAP_CONNECT_ERROR: ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&errmsg); fprintf(stderr, "ldap_start_tls_s(): %s\n", errmsg); ldap_memfree(errmsg); ldap_unbind_ext_s(ld, NULL, NULL); return(1); default: fprintf(stderr, "ldap_start_tls_s(): %s\n", ldap_err2string(err)); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; }; // uses anonymous binds to start SSL connection if (!(strcasecmp(config.ludp->lud_scheme, "ldaps"))) { ldappeerchain_verbose(&config, "ldap_sasl_bind_s()\n"); err = ldap_sasl_bind_s ( ld, // LDAP * ld NULL, // const char * dn LDAP_SASL_SIMPLE, // const char * mechanism &cred, // struct berval * cred NULL, // LDAPControl * sctrls[] NULL, // LDAPControl * cctrls[] &servercredp // struct berval ** servercredp ); if (err != LDAP_SUCCESS) { fprintf(stderr, "ldap_sasl_bind_s(): %s\n", ldap_err2string(err)); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; }; // // writes certificates to file // // retrieves SSL handle if (!(ssl)) { ldappeerchain_verbose(&config, "ldap_get_option(LDAP_OPT_X_TLS_SSL_CTX)\n"); ldap_get_option(ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl); }; if (!(ssl)) { fprintf(stderr, "ldappeerchain: unable to retrieve SSL handle\n"); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; // retrieves stack of certs from peer ldappeerchain_verbose(&config, "SSL_get_peer_cert_chain()\n"); if (!(skx = SSL_get_peer_cert_chain(ssl))) { msg[1023] = '\0'; ERR_error_string_n(ERR_get_error(), msg, 1023); fprintf(stderr, "ldappeerchain: SSL_get_peer_cert_chain(): %s\n", msg); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; if (!(config.quiet)) fprintf(stderr, "%i certificates in peer chain\n", sk_num(skx)); // Creates new BIO ldappeerchain_verbose(&config, "BIO_new()\n"); if (!(mem = BIO_new(BIO_s_mem()))) { ERR_error_string_n(ERR_get_error(), msg, 1023); fprintf(stderr, "ldappeerchain: BIO_new(): %s\n", msg); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; // loops through stack for(skpos = 0; skpos < sk_num(skx); skpos++) { x = (X509 *)sk_value(skx, skpos); ldappeerchain_verbose(&config, "PEM_write_bio_X509()\n"); if ((err = PEM_write_bio_X509(mem, x)) != 1) //if ((err = PEM_write_X509(fp, x)) != 1) { msg[1023] = '\0'; ERR_error_string_n(err, msg, 1023); fprintf(stderr, "ldappeerchain: PEM_write_bio_X509(): %s\n", msg); }; }; // opens file for writing fd = STDOUT_FILENO; if ((datafile)) { ldappeerchain_verbose(&config, "open(%s)\n", datafile); fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, 0644); }; if (fd == -1) { fprintf(stderr, "ldappeerchain: open(%s, w): %s\n", datafile, strerror(errno)); BIO_free(mem); ldap_unbind_ext_s(ld, NULL, NULL); return(1); }; // prints data to file handle flen = 0; fbuff = NULL; while((rlen = BIO_read(mem, rbuff, 1024)) > 0) { if ((ptr = realloc(fbuff, flen+rlen))) { fbuff = ptr; memcpy(&fbuff[flen], rbuff, rlen); flen += rlen; }; }; ldappeerchain_verbose(&config, "write()\n"); write(fd, fbuff, flen); // frees buffer free(fbuff); // closes file if ((datafile)) { ldappeerchain_verbose(&config, "close()\n"); close(fd); }; // frees bio ldappeerchain_verbose(&config, "BIO_free()\n"); BIO_free(mem); // // ends connection and frees resources // // unbind from LDAP server ldappeerchain_verbose(&config, "ldap_unbind_ext_s()\n"); ldap_unbind_ext_s(ld, NULL, NULL); // frees resources ldappeerchain_verbose(&config, "ldap_free_urldesc()\n"); ldap_free_urldesc(config.ludp); return(0); }