/* * Validates a distinguishedName as degined in RFC 4514. Returns * 0 if the value from begin to end is a valid distinguishedName. * Returns 1 otherwise. */ int distinguishedname_validate( const char *begin, const char *end ) { int rc = 0; /* Assume value is valid */ const char *p = begin; const char *last = NULL; /* Per RFC 4514: * * distinguishedName = [ relativeDistinguishedName * *( COMMA relativeDistinguishedName ) ] * relativeDistinguishedName = attributeTypeAndValue * *( PLUS attributeTypeAndValue ) * attributeTypeAndValue = attribyteType EQUALS attributeValue * attributeType = descr / numericoid * attributeValue = string / hexstring */ /* Validate one RDN at a time in a loop. */ while (p <= end) { if ((rc = rdn_validate(p, end, &last)) != 0) { goto exit; } p = last + 1; /* p should be pointing at a comma, or one past * the end of the entire dn value. If we have * not reached the end, ensure that the next * character is a comma and that there is at * least another character after the comma. */ if ((p <= end) && ((p == end) || (*p != ','))) { rc = 1; goto exit; } /* Advance the pointer past the comma so it * points at the beginning of the next RDN * (if there is one). */ p++; } exit: return rc; }
static int pblock_set( Slapi_PBlock *pb, int param, void *value ) { int rc = PBLOCK_SUCCESS; pblock_lock( pb ); switch ( param ) { case SLAPI_OPERATION: pb->pb_op = (Operation *)value; break; case SLAPI_OPINITIATED_TIME: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_time = *((long *)value); break; case SLAPI_OPERATION_ID: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_opid = *((long *)value); break; case SLAPI_OPERATION_TYPE: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_tag = *((ber_tag_t *)value); break; case SLAPI_OPERATION_MSGID: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_msgid = *((long *)value); break; case SLAPI_X_OPERATION_DELETE_GLUE_PARENT: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_delete_glue_parent = *((int *)value); break; case SLAPI_X_OPERATION_NO_SCHEMA_CHECK: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_no_schema_check = *((int *)value); break; case SLAPI_X_OPERATION_NO_SUBORDINATE_GLUE: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_no_subordinate_glue = *((int *)value); break; case SLAPI_REQCONTROLS: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_ctrls = (LDAPControl **)value; break; case SLAPI_RESCONTROLS: { LDAPControl **ctrls = NULL; pblock_get_default( pb, param, (void **)&ctrls ); if ( ctrls != NULL ) { /* free old ones first */ ldap_controls_free( ctrls ); } rc = pblock_set_default( pb, param, value ); break; } case SLAPI_ADD_RESCONTROL: PBLOCK_ASSERT_OP( pb, 0 ); rc = pblock_add_control( pb, (LDAPControl *)value ); break; case SLAPI_REQUESTOR_DN: PBLOCK_ASSERT_OP( pb, 0 ); rc = pblock_set_dn( value, &pb->pb_op->o_dn, &pb->pb_op->o_ndn, pb->pb_op->o_tmpmemctx ); break; case SLAPI_MANAGEDSAIT: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_managedsait = *((int *)value); break; case SLAPI_X_RELAX: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_relax = *((int *)value); break; case SLAPI_BACKEND: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_op->o_bd = (BackendDB *)value; break; case SLAPI_CONNECTION: pb->pb_conn = (Connection *)value; break; case SLAPI_X_CONN_SSF: PBLOCK_ASSERT_CONN( pb ); PBLOCK_LOCK_CONN( pb ); pb->pb_conn->c_ssf = (slap_ssf_t)(long)value; PBLOCK_UNLOCK_CONN( pb ); break; case SLAPI_X_CONN_SASL_CONTEXT: PBLOCK_ASSERT_CONN( pb ); PBLOCK_LOCK_CONN( pb ); pb->pb_conn->c_sasl_authctx = value; PBLOCK_UNLOCK_CONN( pb ); break; case SLAPI_TARGET_DN: PBLOCK_ASSERT_OP( pb, 0 ); rc = pblock_set_dn( value, &pb->pb_op->o_req_dn, &pb->pb_op->o_req_ndn, pb->pb_op->o_tmpmemctx ); break; case SLAPI_CONN_ID: PBLOCK_ASSERT_CONN( pb ); PBLOCK_LOCK_CONN( pb ); pb->pb_conn->c_connid = *((long *)value); PBLOCK_UNLOCK_CONN( pb ); break; case SLAPI_CONN_DN: PBLOCK_ASSERT_CONN( pb ); PBLOCK_LOCK_CONN( pb ); rc = pblock_set_dn( value, &pb->pb_conn->c_dn, &pb->pb_conn->c_ndn, NULL ); PBLOCK_UNLOCK_CONN( pb ); break; case SLAPI_RESULT_CODE: case SLAPI_PLUGIN_INTOP_RESULT: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_rs->sr_err = *((int *)value); break; case SLAPI_RESULT_TEXT: PBLOCK_ASSERT_OP( pb, 0 ); snprintf( pb->pb_textbuf, sizeof( pb->pb_textbuf ), "%s", (char *)value ); pb->pb_rs->sr_text = pb->pb_textbuf; break; case SLAPI_RESULT_MATCHED: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_rs->sr_matched = (char *)value; /* XXX should dup? */ break; case SLAPI_ADD_ENTRY: PBLOCK_ASSERT_OP( pb, 0 ); if ( pb->pb_op->o_tag == LDAP_REQ_ADD ) pb->pb_op->ora_e = (Slapi_Entry *)value; else rc = PBLOCK_ERROR; break; case SLAPI_MODIFY_MODS: { Modifications **mlp; Modifications *newmods; PBLOCK_ASSERT_OP( pb, 0 ); rc = pblock_set_default( pb, param, value ); if ( rc != PBLOCK_SUCCESS ) { break; } if ( pb->pb_op->o_tag == LDAP_REQ_MODIFY ) { mlp = &pb->pb_op->orm_modlist; } else if ( pb->pb_op->o_tag == LDAP_REQ_ADD ) { mlp = &pb->pb_op->ora_modlist; } else if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) { mlp = &pb->pb_op->orr_modlist; } else { break; } newmods = slapi_int_ldapmods2modifications( pb->pb_op, (LDAPMod **)value ); if ( newmods != NULL ) { slap_mods_free( *mlp, 1 ); *mlp = newmods; } break; } case SLAPI_MODRDN_NEWRDN: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) { rc = pblock_set_dn( value, &pb->pb_op->orr_newrdn, &pb->pb_op->orr_nnewrdn, pb->pb_op->o_tmpmemctx ); if ( rc == LDAP_SUCCESS ) rc = rdn_validate( &pb->pb_op->orr_nnewrdn ); } else { rc = PBLOCK_ERROR; } break; case SLAPI_MODRDN_NEWSUPERIOR: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) { if ( value == NULL ) { if ( pb->pb_op->orr_newSup != NULL ) { pb->pb_op->o_tmpfree( pb->pb_op->orr_newSup, pb->pb_op->o_tmpmemctx ); BER_BVZERO( pb->pb_op->orr_newSup ); pb->pb_op->orr_newSup = NULL; } if ( pb->pb_op->orr_newSup != NULL ) { pb->pb_op->o_tmpfree( pb->pb_op->orr_nnewSup, pb->pb_op->o_tmpmemctx ); BER_BVZERO( pb->pb_op->orr_nnewSup ); pb->pb_op->orr_nnewSup = NULL; } } else { if ( pb->pb_op->orr_newSup == NULL ) { pb->pb_op->orr_newSup = (struct berval *)pb->pb_op->o_tmpalloc( sizeof(struct berval), pb->pb_op->o_tmpmemctx ); BER_BVZERO( pb->pb_op->orr_newSup ); } if ( pb->pb_op->orr_nnewSup == NULL ) { pb->pb_op->orr_nnewSup = (struct berval *)pb->pb_op->o_tmpalloc( sizeof(struct berval), pb->pb_op->o_tmpmemctx ); BER_BVZERO( pb->pb_op->orr_nnewSup ); } rc = pblock_set_dn( value, pb->pb_op->orr_newSup, pb->pb_op->orr_nnewSup, pb->pb_op->o_tmpmemctx ); } } else { rc = PBLOCK_ERROR; } break; case SLAPI_MODRDN_DELOLDRDN: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN ) pb->pb_op->orr_deleteoldrdn = *((int *)value); else rc = PBLOCK_ERROR; break; case SLAPI_SEARCH_SCOPE: { int scope = *((int *)value); PBLOCK_ASSERT_OP( pb, 0 ); if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) { switch ( *((int *)value) ) { case LDAP_SCOPE_BASE: case LDAP_SCOPE_ONELEVEL: case LDAP_SCOPE_SUBTREE: case LDAP_SCOPE_SUBORDINATE: pb->pb_op->ors_scope = scope; break; default: rc = PBLOCK_ERROR; break; } } else { rc = PBLOCK_ERROR; } break; } case SLAPI_SEARCH_DEREF: PBLOCK_ASSERT_OP( pb, 0 ); if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) pb->pb_op->ors_deref = *((int *)value); else rc = PBLOCK_ERROR; break; case SLAPI_SEARCH_SIZELIMIT: PBLOCK_ASSERT_OP( pb, 0 ); if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) pb->pb_op->ors_slimit = *((int *)value); else rc = PBLOCK_ERROR; break; case SLAPI_SEARCH_TIMELIMIT: PBLOCK_ASSERT_OP( pb, 0 ); if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) pb->pb_op->ors_tlimit = *((int *)value); else rc = PBLOCK_ERROR; break; case SLAPI_SEARCH_FILTER: PBLOCK_ASSERT_OP( pb, 0 ); if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) pb->pb_op->ors_filter = (Slapi_Filter *)value; else rc = PBLOCK_ERROR; break; case SLAPI_SEARCH_STRFILTER: PBLOCK_ASSERT_OP( pb, 0 ); if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) { pb->pb_op->ors_filterstr.bv_val = (char *)value; pb->pb_op->ors_filterstr.bv_len = strlen((char *)value); } else { rc = PBLOCK_ERROR; } break; case SLAPI_SEARCH_ATTRS: { AttributeName *an = NULL; size_t i = 0, j = 0; char **attrs = (char **)value; PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag != LDAP_REQ_SEARCH ) { rc = PBLOCK_ERROR; break; } /* also set mapped attrs */ rc = pblock_set_default( pb, param, value ); if ( rc != PBLOCK_SUCCESS ) { break; } if ( pb->pb_op->ors_attrs != NULL ) { pb->pb_op->o_tmpfree( pb->pb_op->ors_attrs, pb->pb_op->o_tmpmemctx ); pb->pb_op->ors_attrs = NULL; } if ( attrs != NULL ) { for ( i = 0; attrs[i] != NULL; i++ ) ; } if ( i ) { an = (AttributeName *)pb->pb_op->o_tmpcalloc( i + 1, sizeof(AttributeName), pb->pb_op->o_tmpmemctx ); for ( i = 0; attrs[i] != NULL; i++ ) { an[j].an_desc = NULL; an[j].an_oc = NULL; an[j].an_flags = 0; an[j].an_name.bv_val = attrs[i]; an[j].an_name.bv_len = strlen( attrs[i] ); if ( slap_bv2ad( &an[j].an_name, &an[j].an_desc, &pb->pb_rs->sr_text ) == LDAP_SUCCESS ) { j++; } } an[j].an_name.bv_val = NULL; an[j].an_name.bv_len = 0; } pb->pb_op->ors_attrs = an; break; } case SLAPI_SEARCH_ATTRSONLY: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) pb->pb_op->ors_attrsonly = *((int *)value); else rc = PBLOCK_ERROR; break; case SLAPI_SEARCH_RESULT_ENTRY: PBLOCK_ASSERT_OP( pb, 0 ); rs_replace_entry( pb->pb_op, pb->pb_rs, NULL, (Slapi_Entry *)value ); /* TODO: Should REP_ENTRY_MODIFIABLE be set? */ pb->pb_rs->sr_flags |= REP_ENTRY_MUSTBEFREED; break; case SLAPI_BIND_RET_SASLCREDS: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_rs->sr_sasldata = (struct berval *)value; break; case SLAPI_EXT_OP_REQ_OID: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_EXTENDED ) { pb->pb_op->ore_reqoid.bv_val = (char *)value; pb->pb_op->ore_reqoid.bv_len = strlen((char *)value); } else { rc = PBLOCK_ERROR; } break; case SLAPI_EXT_OP_REQ_VALUE: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_EXTENDED ) pb->pb_op->ore_reqdata = (struct berval *)value; else rc = PBLOCK_ERROR; break; case SLAPI_EXT_OP_RET_OID: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_rs->sr_rspoid = (char *)value; break; case SLAPI_EXT_OP_RET_VALUE: PBLOCK_ASSERT_OP( pb, 0 ); pb->pb_rs->sr_rspdata = (struct berval *)value; break; case SLAPI_BIND_METHOD: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_BIND ) pb->pb_op->orb_method = *((int *)value); else rc = PBLOCK_ERROR; break; case SLAPI_BIND_CREDENTIALS: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_BIND ) pb->pb_op->orb_cred = *((struct berval *)value); else rc = PBLOCK_ERROR; break; case SLAPI_COMPARE_TYPE: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_COMPARE ) { const char *text; pb->pb_op->orc_ava->aa_desc = NULL; rc = slap_str2ad( (char *)value, &pb->pb_op->orc_ava->aa_desc, &text ); } else { rc = PBLOCK_ERROR; } break; case SLAPI_COMPARE_VALUE: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_COMPARE ) pb->pb_op->orc_ava->aa_value = *((struct berval *)value); else rc = PBLOCK_ERROR; break; case SLAPI_ABANDON_MSGID: PBLOCK_ASSERT_OP( pb, 0 ); PBLOCK_VALIDATE_IS_INTOP( pb ); if ( pb->pb_op->o_tag == LDAP_REQ_ABANDON) pb->pb_op->orn_msgid = *((int *)value); else rc = PBLOCK_ERROR; break; case SLAPI_REQUESTOR_ISROOT: case SLAPI_IS_REPLICATED_OPERATION: case SLAPI_CONN_AUTHTYPE: case SLAPI_CONN_AUTHMETHOD: case SLAPI_IS_INTERNAL_OPERATION: case SLAPI_X_CONN_IS_UDP: case SLAPI_CONN_CLIENTIP: case SLAPI_X_CONN_CLIENTPATH: case SLAPI_CONN_SERVERIP: case SLAPI_X_CONN_SERVERPATH: case SLAPI_X_ADD_STRUCTURAL_CLASS: /* These parameters cannot be set */ rc = PBLOCK_ERROR; break; default: rc = pblock_set_default( pb, param, value ); break; } pblock_unlock( pb ); return rc; }
int do_modrdn( Operation *op, SlapReply *rs ) { struct berval dn = BER_BVNULL; struct berval newrdn = BER_BVNULL; struct berval newSuperior = BER_BVNULL; ber_int_t deloldrdn; struct berval pnewSuperior = BER_BVNULL; struct berval nnewSuperior = BER_BVNULL; ber_len_t length; Debug( LDAP_DEBUG_TRACE, "%s do_modrdn\n", op->o_log_prefix, 0, 0 ); /* * Parse the modrdn request. It looks like this: * * ModifyRDNRequest := SEQUENCE { * entry DistinguishedName, * newrdn RelativeDistinguishedName * deleteoldrdn BOOLEAN, * newSuperior [0] LDAPDN OPTIONAL (v3 Only!) * } */ if ( ber_scanf( op->o_ber, "{mmb", &dn, &newrdn, &deloldrdn ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n", op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); return SLAPD_DISCONNECT; } /* Check for newSuperior parameter, if present scan it */ if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) { if ( op->o_protocol < LDAP_VERSION3 ) { /* Connection record indicates v2 but field * newSuperior is present: report error. */ Debug( LDAP_DEBUG_ANY, "%s do_modrdn: newSuperior requires LDAPv3\n", op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" ); rs->sr_err = SLAPD_DISCONNECT; goto cleanup; } if ( ber_scanf( op->o_ber, "m", &newSuperior ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf(\"m\") failed\n", op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto cleanup; } op->orr_newSup = &pnewSuperior; op->orr_nnewSup = &nnewSuperior; } Debug( LDAP_DEBUG_ARGS, "do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n", dn.bv_val, newrdn.bv_val, newSuperior.bv_len ? newSuperior.bv_val : "" ); if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n", op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto cleanup; } if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: get_ctrls failed\n", op->o_log_prefix, 0, 0 ); /* get_ctrls has sent results. Now clean up. */ goto cleanup; } rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx ); if( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid dn (%s)\n", op->o_log_prefix, dn.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); goto cleanup; } /* FIXME: should have/use rdnPretty / rdnNormalize routines */ rs->sr_err = dnPrettyNormal( NULL, &newrdn, &op->orr_newrdn, &op->orr_nnewrdn, op->o_tmpmemctx ); if( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid newrdn (%s)\n", op->o_log_prefix, newrdn.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" ); goto cleanup; } if( rdn_validate( &op->orr_newrdn ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid rdn (%s)\n", op->o_log_prefix, op->orr_newrdn.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" ); goto cleanup; } if( op->orr_newSup ) { rs->sr_err = dnPrettyNormal( NULL, &newSuperior, &pnewSuperior, &nnewSuperior, op->o_tmpmemctx ); if( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid newSuperior (%s)\n", op->o_log_prefix, newSuperior.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid newSuperior" ); goto cleanup; } } Statslog( LDAP_DEBUG_STATS, "%s MODRDN dn=\"%s\"\n", op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 ); op->orr_deleteoldrdn = deloldrdn; op->orr_modlist = NULL; /* prepare modlist of modifications from old/new RDN */ rs->sr_err = slap_modrdn2mods( op, rs ); if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } op->o_bd = frontendDB; rs->sr_err = frontendDB->be_modrdn( op, rs ); #ifdef LDAP_X_TXN if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) { /* skip cleanup */ } #endif cleanup: op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx ); op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx ); op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx ); if ( op->orr_modlist != NULL ) slap_mods_free( op->orr_modlist, 1 ); if ( !BER_BVISNULL( &pnewSuperior ) ) { op->o_tmpfree( pnewSuperior.bv_val, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &nnewSuperior ) ) { op->o_tmpfree( nnewSuperior.bv_val, op->o_tmpmemctx ); } return rs->sr_err; }
/* * Helper function for validating a DN. This function will validate * a single RDN. If the RDN is valid, 0 will be returned, otherwise * non-zero will be returned. A pointer to the last character processed * will be set in the "last parameter. This will be the end of the RDN * in the valid case, and the illegal character in the invalid case. */ int rdn_validate( const char *begin, const char *end, const char **last ) { int rc = 0; /* Assume RDN is valid */ int numericform = 0; char *separator = NULL; const char *p = begin; /* Find the '=', then use the helpers for descr and numericoid */ if ((separator = PL_strnchr(p, '=', end - begin + 1)) == NULL) { rc = 1; goto exit; } /* Process an attribute type. The 'descr' * form must start with a 'leadkeychar'. */ if (IS_LEADKEYCHAR(*p)) { if ((rc = keystring_validate(p, separator - 1))) { goto exit; } /* See if the 'numericoid' form is being used */ } else if (isdigit(*p)) { numericform = 1; if ((rc = numericoid_validate(p, separator - 1))) { goto exit; } } else { rc = 1; goto exit; } /* Advance the pointer past the '=' and make sure * we're not past the end of the string. */ p = separator + 1; if (p > end) { rc = 1; goto exit; } /* The value must be a 'hexstring' if the 'numericoid' * form of 'attributeType' is used. Per RFC 4514: * * hexstring = SHARP 1*hexpair * hexpair = HEX HEX */ if (numericform) { if ((p == end) || !IS_SHARP(*p)) { rc = 1; goto exit; } p++; /* The value must be a 'string' when the 'descr' form * of 'attributeType' is used. Per RFC 4514: * * string = [ ( leadchar / pair ) [ *( stringchar / pair ) * ( trailchar / pair ) ] ] * * leadchar = LUTF1 / UTFMB * trailchar = TUTF1 / UTFMB * stringchar = SUTF1 / UTFMB * * pair = ESC (ESC / special / hexpair ) * special = escaped / SPACE / SHARP / EQUALS * escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE * hexpair = HEX HEX */ } else { /* Check the leadchar to see if anything illegal * is there. We need to allow a 'pair' to get * through, so we'll assume that a '\' is the * start of a 'pair' for now. */ if (IS_UTF1(*p) && !IS_ESC(*p) && !IS_LUTF1(*p)) { rc = 1; goto exit; } } /* Loop through string until we find the ',' separator, a '+' * char indicating a multi-value RDN, or we reach the end. */ while ((p <= end) && (*p != ',') && (*p != '+')) { if (numericform) { /* Process a single 'hexpair' */ if ((p == end) || !isxdigit(*p) || !isxdigit(*p + 1)) { rc = 1; goto exit; } p = p + 2; } else { /* Check for a valid 'stringchar'. We handle * multi-byte characters separately. */ if (IS_UTF1(*p)) { /* If we're at the end, check if we have * a valid 'trailchar'. */ if ((p == end) && !IS_TUTF1(*p)) { rc = 1; goto exit; /* Check for a 'pair'. */ } else if (IS_ESC(*p)) { /* We're guaranteed to still have at * least one more character, so lets * take a look at it. */ p++; if (!IS_ESC(*p) && !IS_SPECIAL(*p)) { /* The only thing valid now * is a 'hexpair'. */ if ((p == end) || !isxdigit(*p) ||!isxdigit(*p + 1)) { rc = 1; goto exit; } p++; } /* Only allow 'SUTF1' chars now. */ } else if (!IS_SUTF1(*p)) { rc = 1; goto exit; } p++; } else { /* Validate a single 'UTFMB' (multi-byte) character. */ if (utf8char_validate(p, end, &p ) != 0) { rc = 1; goto exit; } /* Advance the pointer past the multi-byte char. */ p++; } } } /* We'll end up either at the comma, a '+', or one past end. * If we are processing a multi-valued RDN, we recurse to * process the next 'attributeTypeAndValue'. */ if ((p <= end) && (*p == '+')) { /* Make sure that there is something after the '+'. */ if (p == end) { rc = 1; goto exit; } p++; /* Recurse to process the next value. We need to reset p to * ensure that last is set correctly for the original caller. */ rc = rdn_validate( p, end, last ); p = *last + 1; } exit: *last = p - 1; return rc; }