static int default_mr_filter_match(void *obj, Slapi_Entry *e, Slapi_Attr *attr) { /* returns: 0 filter matched * -1 filter did not match * >0 an LDAP error code */ int rc = -1; struct mr_private* mrpriv = (struct mr_private*)obj; /* In case SLAPI_PLUGIN_OBJECT is not set, mrpriv may be NULL */ if (mrpriv == NULL) return rc; for (; (rc == -1) && (attr != NULL); slapi_entry_next_attr(e, attr, &attr)) { char* type = NULL; if (!slapi_attr_get_type (attr, &type) && type != NULL && !slapi_attr_type_cmp ((const char *)mrpriv->type, type, 2/*match subtypes*/)) { Slapi_Value **vals = attr_get_present_values(attr); #ifdef SUPPORT_MR_SUBSTRING_MATCHING if (mrpriv->ftype == LDAP_FILTER_SUBSTRINGS) { rc = (*mrpriv->match_fn)(pb, mrpriv->initial, mrpriv->any, mrpriv->final, vals); } #endif rc = (*mrpriv->match_fn)(NULL, mrpriv->value, vals, mrpriv->ftype, NULL); }
/* Handles the parsing of the config entry for an ldbm instance. Returns 0 * on success. */ static int parse_ldbm_instance_config_entry(ldbm_instance *inst, Slapi_Entry *e, config_info *config_array) { Slapi_Attr *attr = NULL; for (slapi_entry_first_attr(e, &attr); attr; slapi_entry_next_attr(e, attr, &attr)) { char *attr_name = NULL; Slapi_Value *sval = NULL; struct berval *bval; char err_buf[BUFSIZ]; slapi_attr_get_type(attr, &attr_name); /* There are some attributes that we don't care about, * like objectclass. */ if (ldbm_config_ignored_attr(attr_name)) { continue; } /* We have to handle suffix attributes a little differently */ if (strcasecmp(attr_name, CONFIG_INSTANCE_SUFFIX) == 0) { Slapi_DN suffix; slapi_attr_first_value(attr, &sval); bval = (struct berval *) slapi_value_get_berval(sval); slapi_sdn_init_dn_byref(&suffix, bval->bv_val); if (!slapi_be_issuffix(inst->inst_be, &suffix)) { be_addsuffix(inst->inst_be, &suffix); } slapi_sdn_done(&suffix); continue; } /* We are assuming that each of these attributes are to have * only one value. If they have more than one value, like * the nsslapd-suffix attribute, then they need to be * handled differently. */ slapi_attr_first_value(attr, &sval); bval = (struct berval *) slapi_value_get_berval(sval); if (ldbm_config_set((void *) inst, attr_name, config_array, bval, err_buf, CONFIG_PHASE_STARTUP, 1 /* apply */, LDAP_MOD_REPLACE) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "Error with config attribute %s : %s\n", attr_name, err_buf, 0); return 1; } } /* Read the index entries */ read_instance_index_entries(inst); /* Read the attribute encryption entries */ read_instance_attrcrypt_entries(inst); return 0; }
Slapi_ValueSet * replica_updatedn_list_get_members(Slapi_DN *dn) { static char* const filter_groups = "(|(objectclass=groupOfNames)(objectclass=groupOfUniqueNames)(objectclass=groupOfURLs))"; static char* const type_member = "member"; static char* const type_uniquemember = "uniquemember"; static char* const type_memberURL = "memberURL"; int rval; char *attrs[4]; Slapi_PBlock *mpb = slapi_pblock_new (); Slapi_ValueSet *members = slapi_valueset_new(); attrs[0] = type_member; attrs[1] = type_uniquemember; attrs[2] = type_memberURL; attrs[3] = NULL; slapi_search_internal_set_pb ( mpb, slapi_sdn_get_ndn(dn), LDAP_SCOPE_BASE, filter_groups, &attrs[0], 0, NULL /* controls */, NULL /* uniqueid */, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0); slapi_search_internal_pb(mpb); slapi_pblock_get(mpb, SLAPI_PLUGIN_INTOP_RESULT, &rval); if (rval == LDAP_SUCCESS) { Slapi_Entry **ep; slapi_pblock_get(mpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &ep); if ((ep != NULL) && (ep[0] != NULL)) { Slapi_Attr *attr = NULL; Slapi_Attr *nextAttr = NULL; Slapi_ValueSet *vs = NULL; char *attrType; slapi_entry_first_attr ( ep[0], &attr); while (attr) { slapi_attr_get_type ( attr, &attrType ); if ((strcasecmp (attrType, type_member) == 0) || (strcasecmp (attrType, type_uniquemember) == 0 )) { slapi_attr_get_valueset(attr, &vs); slapi_valueset_join_attr_valueset(attr, members, vs); slapi_valueset_free(vs); } else if (strcasecmp (attrType, type_memberURL) == 0) { /* not yet supported */ } slapi_entry_next_attr ( ep[0], attr, &nextAttr ); attr = nextAttr; } } } slapi_free_search_results_internal(mpb); slapi_pblock_destroy (mpb); return(members); }
static int parse_ldbm_instance_entry(Slapi_Entry *e, char **instance_name) { Slapi_Attr *attr = NULL; for (slapi_entry_first_attr(e, &attr); attr; slapi_entry_next_attr(e, attr, &attr)) { char *attr_name = NULL; slapi_attr_get_type(attr, &attr_name); if (strcasecmp(attr_name, "cn") == 0) { Slapi_Value *sval = NULL; struct berval *bval; slapi_attr_first_value(attr, &sval); bval = (struct berval *) slapi_value_get_berval(sval); *instance_name = slapi_ch_strdup((char *)bval->bv_val); } } return 0; }
static int or_filter_match (void* obj, Slapi_Entry* entry, Slapi_Attr* attr) /* returns: 0 filter matched * -1 filter did not match * >0 an LDAP error code */ { auto int rc = -1; /* no match */ auto or_filter_t* or = (or_filter_t*)obj; for (; attr != NULL; slapi_entry_next_attr (entry, attr, &attr)) { auto char* type = NULL; auto struct berval** vals = NULL; /* * XXXmcs 1-March-2001: This code would perform better if it did not make * a copy of the values here, but that would require re-writing the code * in this file to use Slapi_ValueSet's instead of struct berval **'s * (and that is not a small project). */ if (!slapi_attr_get_type (attr, &type) && type != NULL && !slapi_attr_type_cmp (or->or_type, type, 2/*match subtypes*/) && !slapi_attr_get_bervals_copy(attr, &vals) && vals != NULL) { if (or->or_op == SLAPI_OP_SUBSTRING) { rc = ss_filter_match (or, vals); } else { rc = op_filter_match (or, vals); } ber_bvecfree( vals ); vals = NULL; if (rc >= 0) break; } } return rc; }
void _ger_get_attrs_rights ( Slapi_PBlock *gerpb, Slapi_Entry *e, const char *subjectndn, char **attrs, char **gerstr, size_t *gerstrsize, size_t *gerstrcap, char **errbuf ) { int isfirstattr = 1; /* gerstr was initially allocated with enough space for one more line */ _append_gerstr(gerstr, gerstrsize, gerstrcap, "attributeLevelRights: ", NULL); /* * If it's stated attribute list is given, * the first attr in the list should not be empty. * Otherwise, it's considered the list is not given. */ if (attrs && *attrs && (strlen(*attrs) > 0)) { int i = 0; char **allattrs = NULL; char **opattrs = NULL; char **noexpattrs = NULL; /* attrs not to expose */ char **myattrs = NULL; char **thisattr = NULL; int hasstar = charray_inlist(attrs, "*"); int hasplus = charray_inlist(attrs, "+"); Slapi_Attr *objclasses = NULL; Slapi_ValueSet *objclassvals = NULL; int isextensibleobj = 0; /* get all attrs available for the entry */ slapi_entry_attr_find(e, "objectclass", &objclasses); if (NULL != objclasses) { Slapi_Value *v; slapi_attr_get_valueset(objclasses, &objclassvals); i = slapi_valueset_first_value(objclassvals, &v); if (-1 != i) { const char *ocname = NULL; allattrs = slapi_schema_list_objectclass_attributes( (const char *)v->bv.bv_val, SLAPI_OC_FLAG_REQUIRED|SLAPI_OC_FLAG_ALLOWED); /* check if this entry is an extensble object or not */ ocname = slapi_value_get_string(v); if ( strcasecmp( ocname, "extensibleobject" ) == 0 ) { isextensibleobj = 1; } /* add "aci" to the allattrs to adjust to do_search */ charray_add(&allattrs, slapi_attr_syntax_normalize("aci")); while (-1 != i) { i = slapi_valueset_next_value(objclassvals, i, &v); if (-1 != i) { myattrs = slapi_schema_list_objectclass_attributes( (const char *)v->bv.bv_val, SLAPI_OC_FLAG_REQUIRED|SLAPI_OC_FLAG_ALLOWED); /* check if this entry is an extensble object or not */ ocname = slapi_value_get_string(v); if ( strcasecmp( ocname, "extensibleobject" ) == 0 ) { isextensibleobj = 1; } charray_merge_nodup(&allattrs, myattrs, 1/*copy_strs*/); charray_free(myattrs); } } } slapi_valueset_free(objclassvals); } /* get operational attrs */ opattrs = slapi_schema_list_attribute_names(SLAPI_ATTR_FLAG_OPATTR); noexpattrs = slapi_schema_list_attribute_names(SLAPI_ATTR_FLAG_NOEXPOSE); /* subtract no expose attrs from opattrs (e.g., unhashed pw) */ charray_subtract(opattrs, noexpattrs, NULL); if (isextensibleobj) { for ( i = 0; attrs[i]; i++ ) { if ('\0' == *attrs[i]) { continue; /* skip an empty attr */ } _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i], gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf ); isfirstattr = 0; } } else { if (hasstar && hasplus) { GER_GET_ATTR_RIGHTS(allattrs); GER_GET_ATTR_RIGHTS(opattrs); } else if (hasstar) { GER_GET_ATTR_RIGHTS(allattrs); GER_GET_ATTR_RIGHTA_EXT('*', opattrs, allattrs); } else if (hasplus) { GER_GET_ATTR_RIGHTS(opattrs); GER_GET_ATTR_RIGHTA_EXT('+', allattrs, opattrs); } else { for ( i = 0; attrs[i]; i++ ) { if ('\0' == *attrs[i]) { continue; /* skip an empty attr */ } if (charray_inlist(noexpattrs, attrs[i])) { continue; } else if (charray_inlist(allattrs, attrs[i]) || charray_inlist(opattrs, attrs[i]) || (0 == strcasecmp(attrs[i], "dn")) || (0 == strcasecmp(attrs[i], "distinguishedName"))) { _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i], gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf ); isfirstattr = 0; } else { /* if the attr does not belong to the entry, "<attr>:none" is returned */ if (!isfirstattr) { _append_gerstr(gerstr, gerstrsize, gerstrcap, ", ", NULL); } _append_gerstr(gerstr, gerstrsize, gerstrcap, attrs[i], ":"); _append_gerstr(gerstr, gerstrsize, gerstrcap, "none", NULL); isfirstattr = 0; } } } } charray_free(allattrs); charray_free(opattrs); } else { Slapi_Attr *prevattr = NULL, *attr; char *type; while ( slapi_entry_next_attr ( e, prevattr, &attr ) == 0 ) { if ( ! slapi_attr_flag_is_set (attr, SLAPI_ATTR_FLAG_OPATTR) ) { slapi_attr_get_type ( attr, &type ); _ger_get_attr_rights ( gerpb, e, subjectndn, type, gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf ); isfirstattr = 0; } prevattr = attr; } } if ( isfirstattr ) { /* not a single attribute was retrived or specified */ _append_gerstr(gerstr, gerstrsize, gerstrcap, "*:none", NULL); } return; }
/* Given an entry, provide the account policy in effect for that entry. Returns non-0 if function fails. If account policy comes back NULL, it's not an error; the entry is simply not covered by a policy. */ int get_acctpolicy( Slapi_PBlock *pb, Slapi_Entry *target_entry, void *plugin_id, acctPolicy **policy ) { Slapi_DN *sdn = NULL; Slapi_Entry *policy_entry = NULL; Slapi_Attr *attr; Slapi_Value *sval = NULL; int ldrc; char *attr_name; char *policy_dn = NULL; acctPluginCfg *cfg; int rc = 0; if( policy == NULL ) { /* Bad parameter */ return( -1 ); } *policy = NULL; config_rd_lock(); cfg = get_config(); /* Return success and NULL policy */ policy_dn = get_attr_string_val( target_entry, cfg->spec_attr_name ); if( policy_dn == NULL ) { slapi_log_err(SLAPI_LOG_PLUGIN, PLUGIN_NAME, "get_acctpolicy - \"%s\" is not governed by an account inactivity " "policy subentry\n", slapi_entry_get_ndn( target_entry ) ); if (cfg->inactivitylimit != ULONG_MAX) { goto dopolicy; } slapi_log_err(SLAPI_LOG_PLUGIN, PLUGIN_NAME, "get_acctpolicy - \"%s\" is not governed by an account inactivity " "global policy\n", slapi_entry_get_ndn( target_entry ) ); config_unlock(); return rc; } sdn = slapi_sdn_new_dn_byref( policy_dn ); ldrc = slapi_search_internal_get_entry( sdn, NULL, &policy_entry, plugin_id ); slapi_sdn_free( &sdn ); /* There should be a policy but it can't be retrieved; fatal error */ if( policy_entry == NULL ) { if( ldrc != LDAP_NO_SUCH_OBJECT ) { slapi_log_err(SLAPI_LOG_ERR, PLUGIN_NAME, "get_acctpolicy - Error retrieving policy entry \"%s\": %d\n", policy_dn, ldrc ); } else { slapi_log_err(SLAPI_LOG_PLUGIN, PLUGIN_NAME, "get_acctpolicy - Policy entry \"%s\" is missing: %d\n", policy_dn, ldrc ); } rc = -1; goto done; } dopolicy: *policy = (acctPolicy *)slapi_ch_calloc( 1, sizeof( acctPolicy ) ); if ( !policy_entry ) { /* global policy */ (*policy)->inactivitylimit = cfg->inactivitylimit; goto done; } for( slapi_entry_first_attr( policy_entry, &attr ); attr != NULL; slapi_entry_next_attr( policy_entry, attr, &attr ) ) { slapi_attr_get_type(attr, &attr_name); if( !strcasecmp( attr_name, cfg->limit_attr_name ) ) { if( slapi_attr_first_value( attr, &sval ) == 0 ) { (*policy)->inactivitylimit = slapi_value_get_ulong( sval ); } } } done: config_unlock(); slapi_ch_free_string( &policy_dn ); slapi_entry_free( policy_entry ); return( rc ); }
int update_integrity(char **argv, Slapi_DN *origSDN, char *newrDN, Slapi_DN *newsuperior, int logChanges) { Slapi_PBlock *search_result_pb = NULL; Slapi_PBlock *mod_pb = slapi_pblock_new(); Slapi_Entry **search_entries = NULL; Slapi_DN *sdn = NULL; Slapi_Attr *attr = NULL; void *node = NULL; const char *origDN = slapi_sdn_get_dn(origSDN); const char *search_base = NULL; char *attrName = NULL; char *filter = NULL; char *attrs[2]; int search_result; int nval = 0; int i, j; int rc; if ( argv == NULL ){ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop required config file arguments missing\n" ); rc = -1; goto free_and_return; } /* * For now, just putting attributes to keep integrity on in conf file, * until resolve the other timing mode issue */ search_result_pb = slapi_pblock_new(); /* Search each namingContext in turn */ for ( sdn = slapi_get_first_suffix( &node, 0 ); sdn != NULL; sdn = slapi_get_next_suffix( &node, 0 )) { Slapi_Backend *be = slapi_be_select(sdn); search_base = slapi_sdn_get_dn( sdn ); for(i = 3; argv[i] != NULL; i++){ filter = slapi_filter_sprintf("(%s=*%s%s)", argv[i], ESC_NEXT_VAL, origDN); if ( filter ) { /* Need only the current attribute and its subtypes */ attrs[0] = argv[i]; attrs[1] = NULL; /* Use new search API */ slapi_pblock_init(search_result_pb); slapi_pblock_set(search_result_pb, SLAPI_BACKEND, be); slapi_search_internal_set_pb(search_result_pb, search_base, LDAP_SCOPE_SUBTREE, filter, attrs, 0 /* attrs only */, NULL, NULL, referint_plugin_identity, 0); slapi_search_internal_pb(search_result_pb); slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result); /* if search successfull then do integrity update */ if(search_result == LDAP_SUCCESS) { slapi_pblock_get(search_result_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &search_entries); for(j = 0; search_entries[j] != NULL; j++){ attr = NULL; attrName = NULL; /* * Loop over all the attributes of the entry and search * for the integrity attribute and its subtypes */ for (slapi_entry_first_attr(search_entries[j], &attr); attr; slapi_entry_next_attr(search_entries[j], attr, &attr)) { /* * Take into account only the subtypes of the attribute * in argv[i] having the necessary value - origDN */ slapi_attr_get_type(attr, &attrName); if (slapi_attr_type_cmp(argv[i], attrName, SLAPI_TYPE_CMP_SUBTYPE) == 0) { nval = 0; slapi_attr_get_numvalues(attr, &nval); /* * We want to reduce the "modify" call as much as * possible. But if an entry contains 1000s of * attributes which need to be updated by the * referint plugin (e.g., a group containing 1000s * of members), we want to avoid to allocate too * many mods * in one "modify" call. * This is a compromise: If an attribute type has * more than 128 values, we update the attribute * value one by one. Otherwise, update all values * in one "modify" call. */ if (nval > 128) { rc = _update_one_per_mod( slapi_entry_get_sdn(search_entries[j]), attr, attrName, origSDN, newrDN, slapi_sdn_get_dn(newsuperior), mod_pb); } else { rc = _update_all_per_mod( slapi_entry_get_sdn(search_entries[j]), attr, attrName, origSDN, newrDN, slapi_sdn_get_dn(newsuperior), mod_pb); } /* Should we stop if one modify returns an error? */ } } } } else { if (isFatalSearchError(search_result)){ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "update_integrity search (base=%s filter=%s) returned " "error %d\n", search_base, filter, search_result); rc = -1; goto free_and_return; } } slapi_ch_free_string(&filter); } slapi_free_search_results_internal(search_result_pb); } } /* if got here, then everything good rc = 0 */ rc = 0; free_and_return: /* free filter and search_results_pb */ slapi_ch_free_string(&filter); slapi_pblock_destroy(mod_pb); if (search_result_pb) { slapi_free_search_results_internal(search_result_pb); slapi_pblock_destroy(search_result_pb); } return(rc); }
/* send a single attribute */ static int my_ber_printf_attr (BerElement *ber, Slapi_Attr *attr, PRBool deleted) { Slapi_Value *value; char *type; int i; const CSN *csn; /* First, send the type */ slapi_attr_get_type(attr, &type); BER_DEBUG("{s(type "); BER_DEBUG(type); BER_DEBUG(")"); if (ber_printf(ber, "{s", type) == -1) /* Begin sequence for this type */ { goto loser; } /* Send the attribute deletion CSN if present */ csn = attr_get_deletion_csn(attr); if (csn) { if (my_ber_printf_csn(ber, csn, CSN_TYPE_ATTRIBUTE_DELETED) == -1) { goto loser; } } /* only send "is deleted" flag for deleted attributes since it defaults to false */ if (deleted) { BER_DEBUG("b(del flag)"); if (ber_printf (ber, "b", PR_TRUE) == -1) { goto loser; } } /* * Iterate through all the values. */ BER_DEBUG("["); if (ber_printf(ber, "[") == -1) /* Begin set */ { goto loser; } /* * Process the non-deleted values first. */ i = slapi_attr_first_value(attr, &value); while (i != -1) { if (my_ber_printf_value(ber, type, value, PR_FALSE) == -1) { goto loser; } i= slapi_attr_next_value(attr, i, &value); } /* * Now iterate over all of the deleted values. */ i= attr_first_deleted_value(attr, &value); while (i != -1) { if (my_ber_printf_value(ber, type, value, PR_TRUE) == -1) { goto loser; } i= attr_next_deleted_value(attr, i, &value); } BER_DEBUG("]"); if (ber_printf(ber, "]") == -1) /* End set */ { goto loser; } BER_DEBUG("}"); if (ber_printf(ber, "}") == -1) /* End sequence for this type */ { goto loser; } return 0; loser: return -1; }
/* * Get a Slapi_Entry ready to send over the wire as part of * a total update protocol stream. Convert the entry and all * of its state information to a BerElement which will be the * payload of an extended LDAP operation. * * Entries consist of: * - An entry DN * - A uniqueID * - A set of present attributes, each of which consists of: * - A set of present values, each of which consists of: * - A value * - A set of CSNs * - A set of deleted values, each of which consists of: * - A value * - A set of CSNs * - A set of deleted attibutes, each of which consists of: * - An attribute type * - A set of CSNs. Note that this list of CSNs will always contain exactly one CSN. * * This all gets mashed into one BerElement, ready to be blasted over the wire to * a replica. * */ BerElement * entry2bere(const Slapi_Entry *e, char **excluded_attrs) { BerElement *ber = NULL; const char *str = NULL; const char *dnstr = NULL; char *type; Slapi_DN *sdn = NULL; Slapi_Attr *attr = NULL, *prev_attr; int rc; PR_ASSERT(NULL != e); if ((ber = ber_alloc()) == NULL) { goto loser; } BER_DEBUG("{"); if (ber_printf(ber, "{") == -1) /* Begin outer sequence */ { goto loser; } /* Get the entry's uniqueid */ if ((str = slapi_entry_get_uniqueid(e)) == NULL) { goto loser; } BER_DEBUG("s(uniqueid)"); if (ber_printf(ber, "s", str) == -1) { goto loser; } /* Get the entry's DN */ if ((sdn = slapi_entry_get_sdn((Slapi_Entry *)e)) == NULL) /* XXXggood had to cast away const */ { goto loser; } if ((dnstr = slapi_sdn_get_dn(sdn)) == NULL) { goto loser; } BER_DEBUG("s(dn)"); if (ber_printf(ber, "s", dnstr) == -1) { goto loser; } /* Next comes the annoted list of the entry's attributes */ BER_DEBUG("["); if (ber_printf(ber, "[") == -1) /* Begin set of attributes */ { goto loser; } /* * We iterate over all of the non-deleted attributes first. */ slapi_entry_first_attr(e, &attr); while (NULL != attr) { /* ONREPL - skip uniqueid attribute since we already sent uniqueid This is a hack; need to figure a better way of storing uniqueid in an entry */ slapi_attr_get_type (attr, &type); if (strcasecmp (type, SLAPI_ATTR_UNIQUEID) != 0) { /* Check to see if this attribute is excluded by the fractional list */ if ( (NULL == excluded_attrs) || !charray_inlist(excluded_attrs,type)) { /* Process this attribute */ rc = my_ber_printf_attr (ber, attr, PR_FALSE); if (rc != 0) { goto loser; } } } prev_attr = attr; slapi_entry_next_attr(e, prev_attr, &attr); } /* * Now iterate over the deleted attributes. */ entry_first_deleted_attribute(e, &attr); while (attr != NULL) { slapi_attr_get_type (attr, &type); /* Check to see if this attribute is excluded by the fractional list */ if ( (NULL == excluded_attrs) || !charray_inlist(excluded_attrs,type)) { /* Process this attribute */ rc = my_ber_printf_attr (ber, attr, PR_TRUE); if (rc != 0) { goto loser; } } entry_next_deleted_attribute(e, &attr); } BER_DEBUG("]"); if (ber_printf(ber, "]") == -1) /* End set for attributes */ { goto loser; } BER_DEBUG("}"); if (ber_printf(ber, "}") == -1) /* End sequence for this entry */ { goto loser; } /* If we get here, everything went ok */ BER_DEBUG("\n"); goto free_and_return; loser: if (NULL != ber) { ber_free(ber, 1); ber = NULL; } free_and_return: return ber; }