From 5011db0720a25dba0a73447649cd4f7c9cfedf4f Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Thu, 10 Oct 2002 03:24:50 +0000 Subject: [PATCH] Referrals and misc other changes --- libraries/libldap/controls.c | 18 +- libraries/libldap/dnssrv.c | 63 +++--- libraries/libldap/error.c | 24 ++- libraries/libldap/getvalues.c | 36 ++++ libraries/libldap/ldap-int.h | 7 + libraries/libldap/options.c | 36 +++- libraries/libldap/schema.c | 354 +++++++++++++++++++++++++++++++++- libraries/libldap/unbind.c | 5 + 8 files changed, 487 insertions(+), 56 deletions(-) diff --git a/libraries/libldap/controls.c b/libraries/libldap/controls.c index f3af141e1e..3d9f3a5ac5 100644 --- a/libraries/libldap/controls.c +++ b/libraries/libldap/controls.c @@ -187,33 +187,27 @@ int ldap_int_get_controls( tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid ); - if( tag != LBER_ERROR ) { - tag = ber_peek_tag( ber, &len ); + if( tag == LBER_ERROR ) { + *ctrls = NULL; + ldap_controls_free( tctrls ); + return LDAP_DECODING_ERROR; } + tag = ber_peek_tag( ber, &len ); + if( tag == LBER_BOOLEAN ) { ber_int_t crit; tag = ber_scanf( ber, "b", &crit ); tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0; - } - - if( tag != LBER_ERROR ) { tag = ber_peek_tag( ber, &len ); } if( tag == LBER_OCTETSTRING ) { tag = ber_scanf( ber, "o", &tctrl->ldctl_value ); - } else { tctrl->ldctl_value.bv_val = NULL; } - if( tag == LBER_ERROR ) { - *ctrls = NULL; - ldap_controls_free( tctrls ); - return LDAP_DECODING_ERROR; - } - *ctrls = tctrls; } diff --git a/libraries/libldap/dnssrv.c b/libraries/libldap/dnssrv.c index 72835f22e8..ef5eb89d3b 100644 --- a/libraries/libldap/dnssrv.c +++ b/libraries/libldap/dnssrv.c @@ -121,46 +121,49 @@ int ldap_domain2dn( LDAP_CONST char *domain_in, char **dnp) { - char *domain, *s, *tok_r, *dn; - size_t loc; + char *domain, *s, *tok_r, *dn, *dntmp; + size_t loc; assert( domain_in != NULL ); assert( dnp != NULL ); - domain = LDAP_STRDUP(domain_in); - if (domain == NULL) { + domain = LDAP_STRDUP(domain_in); + if (domain == NULL) { return LDAP_NO_MEMORY; - } - dn = NULL; - loc = 0; - - for (s = ldap_pvt_strtok(domain, ".", &tok_r); - s != NULL; - s = ldap_pvt_strtok(NULL, ".", &tok_r)) { - size_t len = strlen(s); - - dn = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len ); - if (dn == NULL) { - LDAP_FREE(domain); - return LDAP_NO_MEMORY; - } - if (loc > 0) { - /* not first time. */ - strcpy(dn + loc, ","); - loc++; } - strcpy(dn + loc, "dc="); - loc += sizeof("dc=")-1; + dn = NULL; + loc = 0; + + for (s = ldap_pvt_strtok(domain, ".", &tok_r); + s != NULL; + s = ldap_pvt_strtok(NULL, ".", &tok_r)) + { + size_t len = strlen(s); + + dntmp = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len ); + if (dn == NULL) { + LDAP_FREE(dn); + LDAP_FREE(domain); + return LDAP_NO_MEMORY; + } - strcpy(dn + loc, s); - loc += len; - } + dn = dntmp; - LDAP_FREE(domain); + if (loc > 0) { + /* not first time. */ + strcpy(dn + loc, ","); + loc++; + } + strcpy(dn + loc, "dc="); + loc += sizeof("dc=")-1; - *dnp = dn; + strcpy(dn + loc, s); + loc += len; + } - return LDAP_SUCCESS; + LDAP_FREE(domain); + *dnp = dn; + return LDAP_SUCCESS; } /* diff --git a/libraries/libldap/error.c b/libraries/libldap/error.c index 45f9eec86e..7aa9d46667 100644 --- a/libraries/libldap/error.c +++ b/libraries/libldap/error.c @@ -161,6 +161,7 @@ ldap_err2string( int err ) void ldap_perror( LDAP *ld, LDAP_CONST char *str ) { + int i; const struct ldaperror *e; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ENTRY, "ldap_perror\n", 0,0,0 ); @@ -187,6 +188,13 @@ ldap_perror( LDAP *ld, LDAP_CONST char *str ) fprintf( stderr, "\tadditional info: %s\n", ld->ld_error ); } + if ( ld->ld_referrals != NULL && ld->ld_referrals[0] != NULL) { + fprintf( stderr, "\treferrals:\n" ); + for (i=0; ld->ld_referrals[i]; i++) { + fprintf( stderr, "\t\t%s\n", ld->ld_referrals[i] ); + } + } + fflush( stderr ); } @@ -282,6 +290,10 @@ ldap_parse_result( LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } + if ( ld->ld_referrals ) { + LDAP_VFREE( ld->ld_referrals ); + ld->ld_referrals = NULL; + } /* parse results */ @@ -298,13 +310,7 @@ ldap_parse_result( if( tag != LBER_ERROR ) { /* peek for referrals */ if( ber_peek_tag(ber, &len) == LDAP_TAG_REFERRAL ) { - if( referralsp != NULL ) { - tag = ber_scanf( ber, "v", referralsp ); - - } else { - /* no place to put them so skip 'em */ - tag = ber_scanf( ber, "x" ); - } + tag = ber_scanf( ber, "v", &ld->ld_referrals ); } } @@ -366,6 +372,10 @@ ldap_parse_result( *errmsgp = LDAP_STRDUP( ld->ld_error ); } + if( referralsp != NULL) { + *referralsp = ldap_value_dup( ld->ld_referrals ); + } + /* Find the next result... */ for ( lm = lm->lm_chain; lm != NULL; lm = lm->lm_chain ) { /* skip over entries and references */ diff --git a/libraries/libldap/getvalues.c b/libraries/libldap/getvalues.c index 34ee28da56..43e159f190 100644 --- a/libraries/libldap/getvalues.c +++ b/libraries/libldap/getvalues.c @@ -175,3 +175,39 @@ ldap_value_free_len( struct berval **vals ) { ber_bvecfree( vals ); } + +char ** +ldap_value_dup( char *const *vals ) +{ + char **new; + int i; + + if( vals == NULL ) { + return NULL; + } + + for( i=0; vals[i]; i++ ) { + ; /* Count the number of values */ + } + + if( i == 0 ) { + return NULL; + } + + new = LDAP_MALLOC( (i+1)*sizeof(char *) ); /* Alloc array of pointers */ + if( new == NULL ) { + return NULL; + } + + for( i=0; vals[i]; i++ ) { + new[i] = LDAP_STRDUP( vals[i] ); /* Dup each value */ + if( new[i] == NULL ) { + LDAP_VFREE( new ); + return NULL; + } + } + new[i] = NULL; + + return new; +} + diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index 01fe78bac1..b0c2bd9361 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -295,6 +295,7 @@ struct ldap { ber_int_t ld_errno; char *ld_error; char *ld_matched; + char **ld_referrals; ber_len_t ld_msgid; /* do not mess with these */ @@ -574,6 +575,12 @@ LDAP_F (int) ldap_int_tls_config LDAP_P(( LDAP *ld, LDAP_F (int) ldap_int_tls_start LDAP_P(( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )); +/* + * in getvalues.c + */ +LDAP_F (char **) ldap_value_dup LDAP_P(( + char *const *vals )); + LDAP_END_DECL #endif /* _LDAP_INT_H */ diff --git a/libraries/libldap/options.c b/libraries/libldap/options.c index 45ceae125f..45ec0e5f75 100644 --- a/libraries/libldap/options.c +++ b/libraries/libldap/options.c @@ -250,6 +250,20 @@ ldap_get_option( return LDAP_OPT_SUCCESS; + case LDAP_OPT_REFERRAL_URLS: + if(ld == NULL) { + /* bad param */ + break; + } + + if( ld->ld_referrals == NULL ) { + * (char ***) outvalue = NULL; + } else { + * (char ***) outvalue = ldap_value_dup(ld->ld_referrals); + } + + return LDAP_OPT_SUCCESS; + case LDAP_OPT_API_FEATURE_INFO: { LDAPAPIFeatureInfo *info = (LDAPAPIFeatureInfo *) outvalue; int i; @@ -316,8 +330,9 @@ ldap_set_option( * problem. Thus, we introduce a fix here. */ - if (option == LDAP_OPT_DEBUG_LEVEL) - dbglvl = (int *) invalue; + if (option == LDAP_OPT_DEBUG_LEVEL) { + dbglvl = (int *) invalue; + } if( lo->ldo_valid != LDAP_INITIALIZED ) { ldap_int_initialize(lo, dbglvl); @@ -573,6 +588,21 @@ ldap_set_option( ld->ld_matched = LDAP_STRDUP(err); } return LDAP_OPT_SUCCESS; + case LDAP_OPT_REFERRAL_URLS: { + char *const *referrals = (char *const *) invalue; + + if(ld == NULL) { + /* need a struct ldap */ + break; + } + + if( ld->ld_referrals ) { + LDAP_VFREE(ld->ld_referrals); + } + + ld->ld_referrals = ldap_value_dup(referrals); + } return LDAP_OPT_SUCCESS; + case LDAP_OPT_API_FEATURE_INFO: /* read-only */ break; @@ -584,7 +614,7 @@ ldap_set_option( default: #ifdef HAVE_TLS if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 ) - return LDAP_OPT_SUCCESS; + return LDAP_OPT_SUCCESS; #endif #ifdef HAVE_CYRUS_SASL if ( ldap_int_sasl_set_option( ld, option, (void *)invalue ) == 0 ) diff --git a/libraries/libldap/schema.c b/libraries/libldap/schema.c index 93a1daf381..417b4bdba6 100644 --- a/libraries/libldap/schema.c +++ b/libraries/libldap/schema.c @@ -56,6 +56,11 @@ ldap_objectclass2name( LDAPObjectClass * oc ) return( choose_name( oc->oc_names, oc->oc_oid ) ); } +LDAP_CONST char * +ldap_contentrule2name( LDAPContentRule * cr ) +{ + return( choose_name( cr->cr_names, cr->cr_oid ) ); +} /* * When pretty printing the entities we will be appending to a buffer. @@ -383,7 +388,7 @@ ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv ) print_qdstring(ss,mr->mr_desc); } - if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) { + if ( mr->mr_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } @@ -442,7 +447,7 @@ ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv ) print_qdstring(ss,mru->mru_desc); } - if ( mru->mru_obsolete == LDAP_SCHEMA_YES ) { + if ( mru->mru_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } @@ -501,7 +506,7 @@ ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv ) print_qdstring(ss,oc->oc_desc); } - if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) { + if ( oc->oc_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } @@ -555,6 +560,85 @@ ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv ) return(bv); } +char * +ldap_contentrule2str( LDAPContentRule * cr ) +{ + struct berval bv; + if (ldap_contentrule2bv( cr, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"("/*)*/); + print_whsp(ss); + + print_numericoid(ss, cr->cr_oid); + print_whsp(ss); + + if ( cr->cr_names ) { + print_literal(ss,"NAME"); + print_qdescrs(ss,cr->cr_names); + } + + if ( cr->cr_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,cr->cr_desc); + } + + if ( cr->cr_obsolete ) { + print_literal(ss, "OBSOLETE"); + print_whsp(ss); + } + + if ( cr->cr_oc_oids_aux ) { + print_literal(ss,"AUX"); + print_whsp(ss); + print_oids(ss,cr->cr_oc_oids_aux); + print_whsp(ss); + } + + if ( cr->cr_at_oids_must ) { + print_literal(ss,"MUST"); + print_whsp(ss); + print_oids(ss,cr->cr_at_oids_must); + print_whsp(ss); + } + + if ( cr->cr_at_oids_may ) { + print_literal(ss,"MAY"); + print_whsp(ss); + print_oids(ss,cr->cr_at_oids_may); + print_whsp(ss); + } + + if ( cr->cr_at_oids_not ) { + print_literal(ss,"NOT"); + print_whsp(ss); + print_oids(ss,cr->cr_at_oids_not); + print_whsp(ss); + } + + print_whsp(ss); + print_extensions(ss, cr->cr_extensions); + + print_literal(ss, /*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + char * ldap_attributetype2str( LDAPAttributeType * at ) { @@ -590,7 +674,7 @@ ldap_attributetype2bv( LDAPAttributeType * at, struct berval *bv ) print_qdstring(ss,at->at_desc); } - if ( at->at_obsolete == LDAP_SCHEMA_YES ) { + if ( at->at_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } @@ -2124,6 +2208,7 @@ ldap_str2objectclass( LDAP_CONST char * s, !strcmp(sval, "STRUCTURAL") || !strcmp(sval, "AUXILIARY") || !strcmp(sval, "MUST") || + !strcmp(sval, "MAY") || !strncmp(sval, "X-", 2) ) { /* Missing OID, backtrack */ ss = savepos; @@ -2324,6 +2409,267 @@ ldap_str2objectclass( LDAP_CONST char * s, } } +void +ldap_contentrule_free(LDAPContentRule * cr) +{ + LDAP_FREE(cr->cr_oid); + if (cr->cr_names) LDAP_VFREE(cr->cr_names); + if (cr->cr_desc) LDAP_FREE(cr->cr_desc); + if (cr->cr_oc_oids_aux) LDAP_VFREE(cr->cr_oc_oids_aux); + if (cr->cr_at_oids_must) LDAP_VFREE(cr->cr_at_oids_must); + if (cr->cr_at_oids_may) LDAP_VFREE(cr->cr_at_oids_may); + if (cr->cr_at_oids_not) LDAP_VFREE(cr->cr_at_oids_not); + free_extensions(cr->cr_extensions); + LDAP_FREE(cr); +} + +LDAPContentRule * +ldap_str2contentrule( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST int flags ) +{ + int kind; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_aux = 0; + int seen_must = 0; + int seen_may = 0; + int seen_not = 0; + LDAPContentRule * cr; + char ** ext_vals; + const char * savepos; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + cr = LDAP_CALLOC(1,sizeof(LDAPContentRule)); + + if ( !cr ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + + /* + * Definitions MUST begin with an OID in the numericoid format. + * However, this routine is used by clients to parse the response + * from servers and very well known servers will provide an OID + * in the wrong format or even no OID at all. We do our best to + * extract info from those servers. + */ + parse_whsp(&ss); + savepos = ss; + cr->cr_oid = ldap_int_parse_numericoid(&ss,code,0); + if ( !cr->cr_oid ) { + if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) { + /* Backtracking */ + ss = savepos; + kind = get_token(&ss,&sval); + if ( kind == TK_BAREWORD ) { + if ( !strcmp(sval, "NAME") || + !strcmp(sval, "DESC") || + !strcmp(sval, "OBSOLETE") || + !strcmp(sval, "AUX") || + !strcmp(sval, "MUST") || + !strcmp(sval, "MAY") || + !strcmp(sval, "NOT") || + !strncmp(sval, "X-", 2) ) { + /* Missing OID, backtrack */ + ss = savepos; + } else if ( flags & + LDAP_SCHEMA_ALLOW_OID_MACRO ) { + /* Non-numerical OID, ignore */ + int len = ss-savepos; + cr->cr_oid = LDAP_MALLOC(len+1); + strncpy(cr->cr_oid, savepos, len); + cr->cr_oid[len] = 0; + } + } + LDAP_FREE(sval); + } else { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal an accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + case TK_RIGHTPAREN: + return cr; + case TK_BAREWORD: + if ( !strcmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_name = 1; + cr->cr_names = parse_qdescrs(&ss,code); + if ( !cr->cr_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + } else if ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + cr->cr_desc = sval; + parse_whsp(&ss); + } else if ( !strcmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); + if ( seen_obsolete ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_obsolete = 1; + cr->cr_obsolete = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcmp(sval,"AUX") ) { + LDAP_FREE(sval); + if ( seen_aux ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_aux = 1; + cr->cr_oc_oids_aux = parse_oids(&ss,code,0); + if ( !cr->cr_oc_oids_aux ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + parse_whsp(&ss); + } else if ( !strcmp(sval,"MUST") ) { + LDAP_FREE(sval); + if ( seen_must ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_must = 1; + cr->cr_at_oids_must = parse_oids(&ss,code,0); + if ( !cr->cr_at_oids_must ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + parse_whsp(&ss); + } else if ( !strcmp(sval,"MAY") ) { + LDAP_FREE(sval); + if ( seen_may ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_may = 1; + cr->cr_at_oids_may = parse_oids(&ss,code,0); + if ( !cr->cr_at_oids_may ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + parse_whsp(&ss); + } else if ( !strcmp(sval,"NOT") ) { + LDAP_FREE(sval); + if ( seen_not ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_not = 1; + cr->cr_at_oids_not = parse_oids(&ss,code,0); + if ( !cr->cr_at_oids_not ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + parse_whsp(&ss); + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + if ( add_extension(&cr->cr_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + } +} + static char *const err2text[] = { "Success", "Out of memory", diff --git a/libraries/libldap/unbind.c b/libraries/libldap/unbind.c index 45b77f6528..e09ef637be 100644 --- a/libraries/libldap/unbind.c +++ b/libraries/libldap/unbind.c @@ -110,6 +110,11 @@ ldap_ld_free( ld->ld_matched = NULL; } + if( ld->ld_referrals != NULL) { + LDAP_VFREE(ld->ld_referrals); + ld->ld_referrals = NULL; + } + if ( ld->ld_abandoned != NULL ) { LDAP_FREE( ld->ld_abandoned ); ld->ld_abandoned = NULL; -- 2.39.5