/* * Callers should have already allocated *gerstr to hold at least * "entryLevelRights: adnvxxx\n". */ unsigned long _ger_get_entry_rights ( Slapi_PBlock *gerpb, Slapi_Entry *e, const char *subjectndn, char **gerstr, size_t *gerstrsize, size_t *gerstrcap, char **errbuf ) { unsigned long entryrights = 0; Slapi_RDN *rdn = NULL; char *rdntype = NULL; char *rdnvalue = NULL; _append_gerstr(gerstr, gerstrsize, gerstrcap, "entryLevelRights: ", NULL); slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_get_entry_rights: SLAPI_ACL_READ\n" ); if (acl_access_allowed(gerpb, e, "*", NULL, SLAPI_ACL_READ) == LDAP_SUCCESS) { /* v - view e */ entryrights |= SLAPI_ACL_READ; _append_gerstr(gerstr, gerstrsize, gerstrcap, "v", NULL); } slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_get_entry_rights: SLAPI_ACL_ADD\n" ); if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_ADD) == LDAP_SUCCESS) { /* a - add child entry below e */ entryrights |= SLAPI_ACL_ADD; _append_gerstr(gerstr, gerstrsize, gerstrcap, "a", NULL); } slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_get_entry_rights: SLAPI_ACL_DELETE\n" ); if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_DELETE) == LDAP_SUCCESS) { /* d - delete e */ entryrights |= SLAPI_ACL_DELETE; _append_gerstr(gerstr, gerstrsize, gerstrcap, "d", NULL); } /* * Some limitation/simplification applied here: * - The modrdn right requires the rights to delete the old rdn and * the new one. However we have no knowledge of what the new rdn * is going to be. * - In multi-valued RDN case, we check the right on * the first rdn type only for now. */ rdn = slapi_rdn_new_dn ( slapi_entry_get_ndn (e) ); slapi_rdn_get_first(rdn, &rdntype, &rdnvalue); if ( NULL != rdntype ) { slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_get_entry_rights: SLAPI_ACL_WRITE_DEL & _ADD %s\n", rdntype ); if (acl_access_allowed(gerpb, e, rdntype, NULL, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS && acl_access_allowed(gerpb, e, rdntype, NULL, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS) { /* n - rename e */ entryrights |= SLAPI_ACL_WRITE; _append_gerstr(gerstr, gerstrsize, gerstrcap, "n", NULL); } } slapi_rdn_free ( &rdn ); if ( entryrights == 0 ) { _append_gerstr(gerstr, gerstrsize, gerstrcap, "none", NULL); } _append_gerstr(gerstr, gerstrsize, gerstrcap, "\n", NULL); return entryrights; }
/* * *gerstr should point to a heap buffer since it may need * to expand dynamically. */ unsigned long _ger_get_attr_rights ( Slapi_PBlock *gerpb, Slapi_Entry *e, const char *subjectndn, char *type, char **gerstr, size_t *gerstrsize, size_t *gerstrcap, int isfirstattr, char **errbuf ) { unsigned long attrrights = 0; if (!isfirstattr) { _append_gerstr(gerstr, gerstrsize, gerstrcap, ", ", NULL); } _append_gerstr(gerstr, gerstrsize, gerstrcap, type, ":"); slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_get_attr_rights: SLAPI_ACL_READ %s\n", type ); if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_READ) == LDAP_SUCCESS) { /* r - read the values of type */ attrrights |= SLAPI_ACL_READ; _append_gerstr(gerstr, gerstrsize, gerstrcap, "r", NULL); } slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_get_attr_rights: SLAPI_ACL_SEARCH %s\n", type ); if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_SEARCH) == LDAP_SUCCESS) { /* s - search the values of type */ attrrights |= SLAPI_ACL_SEARCH; _append_gerstr(gerstr, gerstrsize, gerstrcap, "s", NULL); } slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_get_attr_rights: SLAPI_ACL_COMPARE %s\n", type ); if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_COMPARE) == LDAP_SUCCESS) { /* c - compare the values of type */ attrrights |= SLAPI_ACL_COMPARE; _append_gerstr(gerstr, gerstrsize, gerstrcap, "c", NULL); } slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_get_attr_rights: SLAPI_ACL_WRITE_ADD %s\n", type ); if (acl_access_allowed(gerpb, e, type, NULL, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS) { /* w - add the values of type */ attrrights |= ACLPB_SLAPI_ACL_WRITE_ADD; _append_gerstr(gerstr, gerstrsize, gerstrcap, "w", NULL); } slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_get_attr_rights: SLAPI_ACL_WRITE_DEL %s\n", type ); if (acl_access_allowed(gerpb, e, type, NULL, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS) { /* o - delete the values of type */ attrrights |= ACLPB_SLAPI_ACL_WRITE_DEL; _append_gerstr(gerstr, gerstrsize, gerstrcap, "o", NULL); } /* If subjectdn has no general write right, check for self write */ if ( 0 == (attrrights & (ACLPB_SLAPI_ACL_WRITE_DEL | ACLPB_SLAPI_ACL_WRITE_ADD)) ) { struct berval val; val.bv_val = (char *)subjectndn; val.bv_len = strlen (subjectndn); if (acl_access_allowed(gerpb, e, type, &val, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS) { /* W - add self to the attribute */ attrrights |= ACLPB_SLAPI_ACL_WRITE_ADD; _append_gerstr(gerstr, gerstrsize, gerstrcap, "W", NULL); } if (acl_access_allowed(gerpb, e, type, &val, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS) { /* O - delete self from the attribute */ attrrights |= ACLPB_SLAPI_ACL_WRITE_DEL; _append_gerstr(gerstr, gerstrsize, gerstrcap, "O", NULL); } } if ( attrrights == 0 ) { _append_gerstr(gerstr, gerstrsize, gerstrcap, "none", NULL); } return attrrights; }
/* * Get an annotated value from the BerElement. Returns 0 on * success, -1 on failure. */ static int my_ber_scanf_value(BerElement *ber, Slapi_Value **value, PRBool *deleted) { struct berval *attrval = NULL; ber_len_t len = -1; ber_tag_t tag; CSN *csn = NULL; char csnstring[CSN_STRSIZE + 1]; CSNType csntype; char *lasti; PR_ASSERT(ber && value && deleted); if (NULL == ber && NULL == value) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 1\n"); goto loser; } *value = NULL; /* Each value is a sequence */ if (ber_scanf(ber, "{O", &attrval) == LBER_ERROR) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 2\n"); goto loser; } /* Allocate and fill in the attribute value */ if ((*value = slapi_value_new_berval(attrval)) == NULL) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 3\n"); goto loser; } /* check if this is a deleted value */ if (ber_peek_tag(ber, &len) == LBER_BOOLEAN) { if (ber_scanf(ber, "b", deleted) == LBER_ERROR) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 4\n"); goto loser; } } else /* default is present value */ { *deleted = PR_FALSE; } /* Read the sequence of CSNs */ for (tag = ber_first_element(ber, &len, &lasti); tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET; tag = ber_next_element(ber, &len, lasti)) { ber_int_t csntype_tmp; /* Each CSN is in a sequence that includes a csntype and CSN */ len = CSN_STRSIZE; if (ber_scanf(ber, "{es}", &csntype_tmp, csnstring, &len) == LBER_ERROR) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 7 - bval is %s\n", attrval->bv_val); goto loser; } switch (csntype_tmp) { case CSN_TYPE_VALUE_UPDATED_ON_WIRE: csntype = CSN_TYPE_VALUE_UPDATED; break; case CSN_TYPE_VALUE_DELETED_ON_WIRE: csntype = CSN_TYPE_VALUE_DELETED; break; case CSN_TYPE_VALUE_DISTINGUISHED_ON_WIRE: csntype = CSN_TYPE_VALUE_DISTINGUISHED; break; default: slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Error: preposterous CSN type " "%d received during total update.\n", csntype_tmp); goto loser; } csn = csn_new_by_string(csnstring); if (csn == NULL) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 8\n"); goto loser; } value_add_csn(*value, csntype, csn); csn_free (&csn); } if (ber_scanf(ber, "}") == LBER_ERROR) /* End of annotated attribute value seq */ { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 10\n"); goto loser; } if (attrval) ber_bvfree(attrval); return 0; loser: /* Free any stuff we allocated */ if (csn) csn_free (&csn); if (attrval) ber_bvfree(attrval); if (value) { slapi_value_free (value); } return -1; }
static int _ger_parse_control ( Slapi_PBlock *pb, char **subjectndn, int *iscritical, char **errbuf ) { LDAPControl **requestcontrols; struct berval *subjectber; BerElement *ber; size_t subjectndnlen = 0; char *orig = NULL; char *normed = NULL; if (NULL == subjectndn) { return LDAP_OPERATIONS_ERROR; } *subjectndn = NULL; /* * Get the control */ slapi_pblock_get ( pb, SLAPI_REQCONTROLS, (void *) &requestcontrols ); slapi_control_present ( requestcontrols, LDAP_CONTROL_GET_EFFECTIVE_RIGHTS, &subjectber, iscritical ); if ( subjectber == NULL || subjectber->bv_val == NULL || subjectber->bv_len == 0 ) { aclutil_str_append ( errbuf, "get-effective-rights: missing subject" ); slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf ); return LDAP_INVALID_SYNTAX; } if ( strncasecmp ( "dn:", subjectber->bv_val, 3 ) == 0 ) { /* * This is a non-standard support to allow the subject being a plain * or base64 encoding string. Hence users using -J option in * ldapsearch don't have to do BER encoding for the subject. */ orig = slapi_ch_malloc ( subjectber->bv_len + 1 ); strncpy ( orig, subjectber->bv_val, subjectber->bv_len ); *(orig + subjectber->bv_len) = '\0'; } else { ber = ber_init (subjectber); if ( ber == NULL ) { aclutil_str_append ( errbuf, "get-effective-rights: ber_init failed for the subject" ); slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf ); return LDAP_OPERATIONS_ERROR; } /* "a" means to allocate storage as needed for octet string */ if ( ber_scanf (ber, "a", &orig) == LBER_ERROR ) { aclutil_str_append ( errbuf, "get-effective-rights: invalid ber tag in the subject" ); slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf ); ber_free ( ber, 1 ); return LDAP_INVALID_SYNTAX; } ber_free ( ber, 1 ); } /* * The current implementation limits the subject to authorization ID * (see section 9 of RFC 2829) only. It also only supports the "dnAuthzId" * flavor, which looks like "dn:<DN>" where null <DN> is for anonymous. */ subjectndnlen = orig ? strlen(orig) : 0; if ( NULL == orig || subjectndnlen < 3 || strncasecmp ( "dn:", orig, 3 ) != 0 ) { aclutil_str_append ( errbuf, "get-effective-rights: subject is not dnAuthzId" ); slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf ); slapi_ch_free_string(&orig); return LDAP_INVALID_SYNTAX; } /* memmove is safe for overlapping copy */ normed = slapi_create_dn_string("%s", orig + 3); if (NULL == normed) { aclutil_str_append (errbuf, "get-effective-rights: failed to normalize dn: "); aclutil_str_append (errbuf, orig); slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf); slapi_ch_free_string(&orig); return LDAP_INVALID_SYNTAX; } slapi_ch_free_string(&orig); *subjectndn = normed; slapi_dn_ignore_case(*subjectndn); return LDAP_SUCCESS; }
void aclg_init_userGroup ( struct acl_pblock *aclpb, const char *n_dn , int got_lock ) { aclUserGroup *u_group = NULL; aclUserGroup *next_ugroup = NULL; aclUserGroup *p_group, *n_group; int found = 0; /* Check for Anonymous user */ if ( n_dn && *n_dn == '\0') return; if ( !got_lock ) ACLG_LOCK_GROUPCACHE_WRITE (); u_group = aclUserGroups->aclg_first; aclpb->aclpb_groupinfo = NULL; while ( u_group != NULL ) { next_ugroup = u_group->aclug_next; if ( aclUserGroups->aclg_signature != u_group->aclug_signature) { /* * This means that this usergroup is no longer valid and * this operation so delete this one if no one is using it. */ if ( !u_group->aclug_refcnt ) { slapi_log_error( SLAPI_LOG_ACL, plugin_name, "In traversal group deallocation\n" ); __aclg__delete_userGroup (u_group); } } else { /* * Here, u_group is valid--if it matches then take it. */ if ( slapi_utf8casecmp((ACLUCHP)u_group->aclug_ndn, (ACLUCHP)n_dn ) == 0 ) { u_group->aclug_refcnt++; aclpb->aclpb_groupinfo = u_group; found = 1; break; } } u_group = next_ugroup; } /* Move the new one to the top of the queue */ if ( found ) { p_group = u_group->aclug_prev; n_group = u_group->aclug_next; if ( p_group ) { aclUserGroup *t_group = NULL; p_group->aclug_next = n_group; if ( n_group ) n_group->aclug_prev = p_group; t_group = aclUserGroups->aclg_first; if ( t_group ) t_group->aclug_prev = u_group; u_group->aclug_prev = NULL; u_group->aclug_next = t_group; aclUserGroups->aclg_first = u_group; if ( u_group == aclUserGroups->aclg_last ) aclUserGroups->aclg_last = p_group; } slapi_log_error(SLAPI_LOG_ACL, plugin_name, "acl_init_userGroup: found in cache for dn:%s\n", n_dn); } if (!got_lock ) ACLG_ULOCK_GROUPCACHE_WRITE (); }
static int agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *e, int *returncode, char *returntext, void *arg) { int i; Slapi_DN *sdn = NULL; int start_initialize = 0, stop_initialize = 0, cancel_initialize = 0; int update_the_schedule = 0; /* do we need to update the repl sched? */ Repl_Agmt *agmt = NULL; LDAPMod **mods; char buff [SLAPI_DSE_RETURNTEXT_SIZE]; char *errortext = returntext ? returntext : buff; int rc = SLAPI_DSE_CALLBACK_OK; Slapi_Operation *op; void *identity; *returncode = LDAP_SUCCESS; /* just let internal operations originated from replication plugin to go through */ slapi_pblock_get (pb, SLAPI_OPERATION, &op); slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity); if (operation_is_flag_set(op, OP_FLAG_INTERNAL) && (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION))) { goto done; } slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); if (NULL == sdn) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmtlist_modify_callback: NULL target dn\n"); goto done; } agmt = agmtlist_get_by_agmt_name(sdn); if (NULL == agmt) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmtlist_modify_callback: received " "a modification for unknown replication agreement \"%s\"\n", slapi_sdn_get_dn(sdn)); goto done; } slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); for (i = 0; NULL != mods && NULL != mods[i]; i++) { if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaInitialize)) { /* we don't allow delete attribute operations unless it was issued by the replication plugin - handled above */ if (mods[i]->mod_op & LDAP_MOD_DELETE) { if(strcasecmp (mods[i]->mod_type, type_nsds5ReplicaCleanRUVnotified) == 0){ /* allow the deletion of cleanallruv agmt attr */ continue; } slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "deletion of %s attribute is not allowed\n", type_nsds5ReplicaInitialize); *returncode = LDAP_UNWILLING_TO_PERFORM; rc = SLAPI_DSE_CALLBACK_ERROR; break; } else { char *val; if (mods[i]->mod_bvalues && mods[i]->mod_bvalues[0]) val = slapi_berval_get_string_copy (mods[i]->mod_bvalues[0]); else { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "no value provided for %s attribute\n", type_nsds5ReplicaInitialize); *returncode = LDAP_UNWILLING_TO_PERFORM; rc = SLAPI_DSE_CALLBACK_ERROR; break; } /* Start replica initialization */ if (val == NULL) { PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "No value supplied for attr (%s)", mods[i]->mod_type); slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: %s\n", errortext); *returncode = LDAP_UNWILLING_TO_PERFORM; rc = SLAPI_DSE_CALLBACK_ERROR; break; } if (strcasecmp (val, "start") == 0) { start_initialize = 1; } else if (strcasecmp (val, "stop") == 0) { stop_initialize = 1; } else if (strcasecmp (val, "cancel") == 0) { cancel_initialize = 1; } else { PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid value (%s) value supplied for attr (%s)", val, mods[i]->mod_type); slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: %s\n", errortext); } slapi_ch_free ((void**)&val); } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaUpdateSchedule)) { /* * Request to update the replication schedule. Set a flag so * we know to update the schedule later. */ update_the_schedule = 1; } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaCredentials)) { /* New replica credentials */ if (agmt_set_credentials_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update credentials for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaTimeout)) { /* New replica timeout */ if (agmt_set_timeout_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update timeout for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaBusyWaitTime)) { /* New replica busywaittime */ if (agmt_set_busywaittime_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update busy wait time for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaSessionPauseTime)) { /* New replica pausetime */ if (agmt_set_pausetime_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update session pause time for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaBindDN)) { /* New replica Bind DN */ if (agmt_set_binddn_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update bind DN for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaPort)) { /* New replica port */ if (agmt_set_port_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update port for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5TransportInfo)) { /* New Transport info */ if (agmt_set_transportinfo_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update transport info for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaBindMethod)) { if (agmt_set_bind_method_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update bind method for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicatedAttributeList)) { char **denied_attrs = NULL; /* New set of excluded attributes */ if (agmt_set_replicated_attributes_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update replicated attributes for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } /* Check that there are no verboten attributes in the exclude list */ denied_attrs = agmt_validate_replicated_attributes(agmt, 0 /* incremental */); if (denied_attrs) { /* Report the error to the client */ PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "attempt to exclude an illegal attribute in a fractional agreement"); slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "attempt to exclude an illegal attribute in a fractional agreement\n"); *returncode = LDAP_UNWILLING_TO_PERFORM; rc = SLAPI_DSE_CALLBACK_ERROR; /* Free the deny list if we got one */ slapi_ch_array_free(denied_attrs); break; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicatedAttributeListTotal)) { char **denied_attrs = NULL; /* New set of excluded attributes */ if (agmt_set_replicated_attributes_total_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update total update replicated attributes for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } /* Check that there are no verboten attributes in the exclude list */ denied_attrs = agmt_validate_replicated_attributes(agmt, 1 /* total */); if (denied_attrs) { /* Report the error to the client */ PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "attempt to exclude an illegal total update " "attribute in a fractional agreement"); slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "attempt to exclude an illegal total update attribute in a fractional agreement\n"); *returncode = LDAP_UNWILLING_TO_PERFORM; rc = SLAPI_DSE_CALLBACK_ERROR; /* Free the deny list if we got one */ slapi_ch_array_free(denied_attrs); break; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, "nsds5debugreplicatimeout")) { char *val = slapi_entry_attr_get_charptr(e, "nsds5debugreplicatimeout"); repl5_set_debug_timeout(val); slapi_ch_free_string(&val); } else if (strcasecmp (mods[i]->mod_type, "modifytimestamp") == 0 || strcasecmp (mods[i]->mod_type, "modifiersname") == 0 || strcasecmp (mods[i]->mod_type, "description") == 0) { /* ignore modifier's name and timestamp attributes and the description. */ continue; } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaEnabled)) { if(agmt_set_enabled_from_entry(agmt, e, returntext) != 0){ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to set replica agmt state \"enabled/disabled\" for %s\n",agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaStripAttrs)) { if(agmt_set_attrs_to_strip(agmt, e) != 0){ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to set replica agmt attributes to strip for %s\n",agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e)) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "modification of %s attribute is not allowed\n", mods[i]->mod_type); *returncode = LDAP_UNWILLING_TO_PERFORM; rc = SLAPI_DSE_CALLBACK_ERROR; break; } } if (stop_initialize) { agmt_stop (agmt); } else if (start_initialize) { if (agmt_initialize_replica(agmt) != 0) { /* The suffix/repl agmt is disabled */ agmt_set_last_init_status(agmt, 0, NSDS50_REPL_DISABLED, NULL); if(agmt_is_enabled(agmt)){ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Suffix is disabled"); } else { PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Replication agreement is disabled"); } *returncode = LDAP_UNWILLING_TO_PERFORM; rc = SLAPI_DSE_CALLBACK_ERROR; } } else if (cancel_initialize) { agmt_replica_init_done(agmt); } if (update_the_schedule) { if (agmt_set_schedule_from_entry(agmt, e) != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " "failed to update replication schedule for agreement %s\n", agmt_get_long_name(agmt)); *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } } done: if (NULL != agmt) { agmtlist_release_agmt(agmt); } return rc; }
/* * Function Implementations */ int linked_attrs_fixup_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg) { PRThread *thread = NULL; int rv = SLAPI_DSE_CALLBACK_OK; task_data *mytaskdata = NULL; Slapi_Task *task = NULL; const char *linkdn = NULL; char *bind_dn; *returncode = LDAP_SUCCESS; /* make sure the plugin is not closed */ if(!linked_attrs_is_started()){ *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } /* get arg(s) */ linkdn = fetch_attr(e, "linkdn", 0); /* setup our task data */ slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &bind_dn); mytaskdata = (task_data*)slapi_ch_calloc(1, sizeof(task_data)); if (mytaskdata == NULL) { *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } if (linkdn) { mytaskdata->linkdn = slapi_dn_normalize(slapi_ch_strdup(linkdn)); } mytaskdata->bind_dn = slapi_ch_strdup(bind_dn); /* allocate new task now */ task = slapi_new_task(slapi_entry_get_ndn(e)); /* register our destructor for cleaning up our private data */ slapi_task_set_destructor_fn(task, linked_attrs_fixup_task_destructor); /* Stash a pointer to our data in the task */ slapi_task_set_data(task, mytaskdata); /* start the sample task as a separate thread */ thread = PR_CreateThread(PR_USER_THREAD, linked_attrs_fixup_task_thread, (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE); if (thread == NULL) { slapi_log_error( SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "unable to create task thread!\n"); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; slapi_task_finish(task, *returncode); } else { rv = SLAPI_DSE_CALLBACK_OK; } out: return rv; }
/* * Function: retrocl_create_config * * Returns: LDAP_ * * Arguments: none * * Description: * This function is called if there was no mapping tree node or backend for * cn=changelog. */ int retrocl_create_config(void) { Slapi_PBlock *pb = NULL; Slapi_Entry *e; struct berval *vals[2]; struct berval val; int rc; char *mappingtree_dn = NULL; vals[0] = &val; vals[1] = NULL; /* Assume the mapping tree node is missing. It doesn't hurt to * attempt to add it if it already exists. You will see a warning * in the errors file when the referenced backend does not exist. */ e = slapi_entry_alloc(); /* This function converts the old DN style to the new one. */ mappingtree_dn = slapi_create_dn_string("%s", RETROCL_MAPPINGTREE_DN); if (NULL == mappingtree_dn) { slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "retrocl_create_config: failed to normalize " "mappingtree dn %s\n", RETROCL_MAPPINGTREE_DN); return LDAP_PARAM_ERROR; } slapi_entry_set_dn(e, mappingtree_dn); /* mappingtree_dn is consumed */ /* Set the objectclass attribute */ val.bv_val = "top"; val.bv_len = 3; slapi_entry_add_values( e, "objectclass", vals ); /* Set the objectclass attribute */ val.bv_val = "extensibleObject"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "objectclass", vals ); /* Set the objectclass attribute */ val.bv_val = "nsMappingTree"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "objectclass", vals ); val.bv_val = "backend"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nsslapd-state", vals ); val.bv_val = RETROCL_CHANGELOG_DN; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "cn", vals ); val.bv_val = "changelog"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nsslapd-backend", vals ); pb = slapi_pblock_new (); slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */, g_plg_identity[PLUGIN_RETROCL], 0 /* actions */ ); slapi_add_internal_pb (pb); slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc ); slapi_pblock_destroy(pb); if (rc == 0) { slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "created changelog mapping tree node\n"); } else if (rc == LDAP_ALREADY_EXISTS) { slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "changelog mapping tree node already existed\n"); } else { slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "cn=\"cn=changelog\",cn=mapping tree,cn=config could not be created (%d)\n", rc); return rc; } retrocl_be_changelog = slapi_be_select_by_instance_name("changelog"); if (retrocl_be_changelog == NULL) { /* This is not the nsslapd-changelogdir from cn=changelog4,cn=config */ char *bedir; bedir = retrocl_get_config_str(CONFIG_CHANGELOG_DIRECTORY_ATTRIBUTE); if (bedir == NULL) { /* none specified */ } rc = retrocl_create_be(bedir); slapi_ch_free ((void **)&bedir); if (rc != LDAP_SUCCESS && rc != LDAP_ALREADY_EXISTS) { return rc; } retrocl_be_changelog = slapi_be_select_by_instance_name("changelog"); } return LDAP_SUCCESS; }
static void linked_attrs_fixup_task_thread(void *arg) { int rc = 0; Slapi_Task *task = (Slapi_Task *)arg; task_data *td = NULL; PRCList *main_config = NULL; int found_config = 0; /* Fetch our task data from the task */ td = (task_data *)slapi_task_get_data(task); /* init and set the bind dn in the thread data */ slapi_td_set_dn(slapi_ch_strdup(td->bind_dn)); /* Log started message. */ slapi_task_begin(task, 1); slapi_task_log_notice(task, "Linked attributes fixup task starting (link dn: \"%s\") ...\n", td->linkdn ? td->linkdn : ""); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Syntax validate task starting (link dn: \"%s\") ...\n", td->linkdn ? td->linkdn : ""); linked_attrs_read_lock(); main_config = linked_attrs_get_config(); if (!PR_CLIST_IS_EMPTY(main_config)) { struct configEntry *config_entry = NULL; PRCList *list = PR_LIST_HEAD(main_config); while (list != main_config) { config_entry = (struct configEntry *) list; /* See if this is the requested config and fix up if so. */ if (td->linkdn) { if (strcasecmp(td->linkdn, config_entry->dn) == 0) { found_config = 1; slapi_task_log_notice(task, "Fixing up linked attribute pair (%s)\n", config_entry->dn); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Fixing up linked attribute pair (%s)\n", config_entry->dn); linked_attrs_fixup_links(config_entry); break; } } else { /* No config DN was supplied, so fix up all configured links. */ slapi_task_log_notice(task, "Fixing up linked attribute pair (%s)\n", config_entry->dn); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Fixing up linked attribute pair (%s)\n", config_entry->dn); linked_attrs_fixup_links(config_entry); } list = PR_NEXT_LINK(list); } } /* Log a message if we didn't find the requested attribute pair. */ if (td->linkdn && !found_config) { slapi_task_log_notice(task, "Requested link config DN not found (%s)\n", td->linkdn); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Requested link config DN not found (%s)\n", td->linkdn); } linked_attrs_unlock(); /* Log finished message. */ slapi_task_log_notice(task, "Linked attributes fixup task complete.\n"); slapi_task_log_status(task, "Linked attributes fixup task complete.\n"); slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "Linked attributes fixup task complete.\n"); slapi_task_inc_progress(task); /* this will queue the destruction of the task */ slapi_task_finish(task, rc); }
static int linked_attrs_add_backlinks_callback(Slapi_Entry *e, void *callback_data) { int rc = 0; char *linkdn = slapi_entry_get_dn(e); struct configEntry *config = (struct configEntry *)callback_data; Slapi_PBlock *pb = slapi_pblock_new(); int i = 0; char **targets = NULL; char *val[2]; LDAPMod mod; LDAPMod *mods[2]; /* Setup the modify operation. Only the target will * change, so we only need to do this once. */ val[0] = linkdn; val[1] = 0; mod.mod_op = LDAP_MOD_ADD; mod.mod_type = config->managedtype; mod.mod_values = val; mods[0] = &mod; mods[1] = 0; targets = slapi_entry_attr_get_charray(e, config->linktype); for (i = 0; targets && targets[i]; ++i) { char *targetdn = (char *)targets[i]; int perform_update = 0; Slapi_DN *targetsdn = NULL; if (slapi_is_shutting_down()) { rc = -1; goto done; } targetsdn = slapi_sdn_new_normdn_byref(targetdn); if (config->scope) { /* Check if the target is within the scope. */ perform_update = slapi_dn_issuffix(targetdn, config->scope); } else { /* Find out the root suffix that the linkdn is in * and see if the target is in the same backend. */ Slapi_Backend *be = NULL; Slapi_DN *linksdn = slapi_sdn_new_normdn_byref(linkdn); if ((be = slapi_be_select(linksdn))) { perform_update = slapi_sdn_issuffix(targetsdn, slapi_be_getsuffix(be, 0)); } slapi_sdn_free(&linksdn); } if (perform_update) { slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM, "Adding backpointer (%s) in entry (%s)\n", linkdn, targetdn); /* Perform the modify operation. */ slapi_modify_internal_set_pb_ext(pb, targetsdn, mods, 0, 0, linked_attrs_get_plugin_id(), 0); slapi_modify_internal_pb(pb); /* Initialize the pblock so we can reuse it. */ slapi_pblock_init(pb); } slapi_sdn_free(&targetsdn); } done: slapi_ch_array_free(targets); slapi_pblock_destroy(pb); return rc; }
static int windows_parse_config_entry(Repl_Agmt *ra, const char *type, Slapi_Entry *e) { char *tmpstr = NULL; int retval = 0; if (type == NULL || slapi_attr_types_equivalent(type,type_nsds7WindowsReplicaArea)) { tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7WindowsReplicaArea); if (NULL != tmpstr) { windows_private_set_windows_subtree(ra, slapi_sdn_new_dn_passin(tmpstr) ); } retval = 1; } if (type == NULL || slapi_attr_types_equivalent(type,type_nsds7DirectoryReplicaArea)) { tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7DirectoryReplicaArea); if (NULL != tmpstr) { windows_private_set_directory_subtree(ra, slapi_sdn_new_dn_passin(tmpstr) ); } retval = 1; } if (type == NULL || slapi_attr_types_equivalent(type,type_nsds7CreateNewUsers)) { tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7CreateNewUsers); if (NULL != tmpstr && true_value_from_string(tmpstr)) { windows_private_set_create_users(ra, PR_TRUE); } else { windows_private_set_create_users(ra, PR_FALSE); } retval = 1; slapi_ch_free((void**)&tmpstr); } if (type == NULL || slapi_attr_types_equivalent(type,type_nsds7CreateNewGroups)) { tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7CreateNewGroups); if (NULL != tmpstr && true_value_from_string(tmpstr)) { windows_private_set_create_groups(ra, PR_TRUE); } else { windows_private_set_create_groups(ra, PR_FALSE); } retval = 1; slapi_ch_free((void**)&tmpstr); } if (type == NULL || slapi_attr_types_equivalent(type,type_nsds7WindowsDomain)) { tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7WindowsDomain); if (NULL != tmpstr) { windows_private_set_windows_domain(ra,tmpstr); } /* No need to free tmpstr because it was aliased by the call above */ tmpstr = NULL; retval = 1; } if (type == NULL || slapi_attr_types_equivalent(type,type_winSyncInterval)) { tmpstr = slapi_entry_attr_get_charptr(e, type_winSyncInterval); if (NULL != tmpstr) { windows_private_set_sync_interval(ra,tmpstr); } slapi_ch_free_string(&tmpstr); retval = 1; } if (type == NULL || slapi_attr_types_equivalent(type,type_oneWaySync)) { tmpstr = slapi_entry_attr_get_charptr(e, type_oneWaySync); if (NULL != tmpstr) { if (strcasecmp(tmpstr, "fromWindows") == 0) { windows_private_set_one_way(ra, ONE_WAY_SYNC_FROM_AD); } else if (strcasecmp(tmpstr, "toWindows") == 0) { windows_private_set_one_way(ra, ONE_WAY_SYNC_TO_AD); } else { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Ignoring illegal setting for %s attribute in replication " "agreement \"%s\". Valid values are \"toWindows\" or " "\"fromWindows\".\n", type_oneWaySync, slapi_entry_get_dn(e)); windows_private_set_one_way(ra, ONE_WAY_SYNC_DISABLED); } } else { windows_private_set_one_way(ra, ONE_WAY_SYNC_DISABLED); } slapi_ch_free((void**)&tmpstr); retval = 1; } return retval; }
/* * This plugin entry point is called whenever an NSDS50ReplicationEntry * extended operation is received. */ int multimaster_extop_NSDS50ReplicationEntry(Slapi_PBlock *pb) { int rc; Slapi_Entry *e = NULL; Slapi_Connection *conn = NULL; PRUint64 connid = 0; int opid = 0; slapi_pblock_get(pb, SLAPI_CONN_ID, &connid); slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opid); /* Decode the extended operation */ rc = decode_total_update_extop(pb, &e); if (0 == rc) { #ifdef notdef /* * Just spew LDIF so we're sure we got it right. Later we'll firehose * this into the database import code */ int len; char *str = slapi_entry2str_with_options(e, &len,SLAPI_DUMP_UNIQUEID); puts(str); free(str); #endif rc = slapi_import_entry (pb, e); /* slapi_import_entry returns an LDAP error in case of a * problem. If there's a problem, it's our responsibility * to free the slapi_entry that we're trying to import. */ if (rc != LDAP_SUCCESS) { const char *dn = slapi_entry_get_dn_const(e); slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "Error %d: could not import entry dn %s " "for total update operation conn=%" NSPRIu64 " op=%d\n", rc, dn, connid, opid); rc = -1; } } else { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "Error %d: could not decode the total update extop " "for total update operation conn=%" NSPRIu64 " op=%d\n", rc, connid, opid); } if (rc != 0) { /* just disconnect from the supplier. bulk import is stopped when connection object is destroyed */ slapi_pblock_get (pb, SLAPI_CONNECTION, &conn); if (conn) { slapi_disconnect_server(conn); } /* cleanup */ if (e) { slapi_entry_free (e); } } return rc; }
/* * Extract the payload from a total update extended operation, * decode it, and produce a Slapi_Entry structure representing a new * entry to be added to the local database. */ static int decode_total_update_extop(Slapi_PBlock *pb, Slapi_Entry **ep) { BerElement *tmp_bere = NULL; Slapi_Entry *e = NULL; Slapi_Attr *attr = NULL; char *str = NULL; struct berval *extop_value = NULL; char *extop_oid = NULL; ber_len_t len; char *lasto; ber_tag_t tag; int rc; PRBool deleted; PR_ASSERT(NULL != pb); PR_ASSERT(NULL != ep); slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid); slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value); if ((NULL == extop_oid) || ((strcmp(extop_oid, REPL_NSDS50_REPLICATION_ENTRY_REQUEST_OID) != 0) && (strcmp(extop_oid, REPL_NSDS71_REPLICATION_ENTRY_REQUEST_OID) != 0)) || !BV_HAS_DATA(extop_value)) { /* Bogus */ goto loser; } if ((tmp_bere = ber_init(extop_value)) == NULL) { goto loser; } if ((e = slapi_entry_alloc()) == NULL) { goto loser; } if (ber_scanf(tmp_bere, "{") == LBER_ERROR) /* Begin outer sequence */ { goto loser; } /* The entry's uniqueid is first */ if (ber_scanf(tmp_bere, "a", &str) == LBER_ERROR) { goto loser; } slapi_entry_set_uniqueid(e, str); str = NULL; /* Slapi_Entry now owns the uniqueid */ /* The entry's DN is next */ if (ber_scanf(tmp_bere, "a", &str) == LBER_ERROR) { goto loser; } slapi_entry_set_dn(e, str); str = NULL; /* Slapi_Entry now owns the dn */ /* Get the attributes */ for ( tag = ber_first_element( tmp_bere, &len, &lasto ); tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET; tag = ber_next_element( tmp_bere, &len, lasto ) ) { if (my_ber_scanf_attr (tmp_bere, &attr, &deleted) != 0) { goto loser; } /* Add the attribute to the entry */ if (deleted) entry_add_deleted_attribute_wsi(e, attr); /* entry now owns attr */ else entry_add_present_attribute_wsi(e, attr); /* entry now owns attr */ attr = NULL; } if (ber_scanf(tmp_bere, "}") == LBER_ERROR) /* End sequence for this entry */ { goto loser; } /* Check for ldapsubentries and tombstone entries to set flags properly */ slapi_entry_attr_find(e, "objectclass", &attr); if (attr != NULL) { struct berval bv; bv.bv_val = "ldapsubentry"; bv.bv_len = strlen(bv.bv_val); if (slapi_attr_value_find(attr, &bv) == 0) { slapi_entry_set_flag(e, SLAPI_ENTRY_LDAPSUBENTRY); } bv.bv_val = SLAPI_ATTR_VALUE_TOMBSTONE; bv.bv_len = strlen(bv.bv_val); if (slapi_attr_value_find(attr, &bv) == 0) { slapi_entry_set_flag(e, SLAPI_ENTRY_FLAG_TOMBSTONE); } } /* If we get here, the entry is properly constructed. Return it. */ rc = 0; *ep = e; goto free_and_return; loser: rc = -1; /* slapi_ch_free accepts NULL pointer */ slapi_ch_free((void **)&str); if (attr != NULL) { slapi_attr_free (&attr); } if (NULL != e) { slapi_entry_free (e); } *ep = NULL; slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Error: could not decode extended " "operation containing entry for total update.\n"); free_and_return: if (NULL != tmp_bere) { ber_free(tmp_bere, 1); tmp_bere = NULL; } return rc; }
int _ger_generate_template_entry ( Slapi_PBlock *pb ) { Slapi_Entry *e = NULL; char **gerattrs = NULL; char **attrs = NULL; char **allowedattrs = NULL; char *templateentry = NULL; char *object = NULL; char *superior = NULL; char *p = NULL; const char *dn = NULL; Slapi_DN *sdn = NULL; char *dntype = NULL; int siz = 0; int len = 0; int i = 0; int notfirst = 0; int rc = LDAP_SUCCESS; slapi_pblock_get( pb, SLAPI_SEARCH_GERATTRS, &gerattrs ); if (NULL == gerattrs) { slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "Objectclass info is expected " "in the attr list, e.g., \"*@person\"\n"); rc = LDAP_SUCCESS; goto bailout; } for (i = 0; gerattrs && gerattrs[i]; i++) { object = strchr(gerattrs[i], '@'); if (NULL != object && '\0' != *(++object)) { break; } } if (NULL == object) { rc = LDAP_SUCCESS; /* no objectclass info; ok to return */ goto bailout; } /* * Either @objectclass or @objectclass:dntype is accepted. * If @objectclass, the first MUST attributetype (or the first MAY * attributetype if MUST does not exist) is used for the attribute * type in the leaf RDN. * If @objectclass:dntype, dntype is used for the attribute type in the * leaf RDN. */ dntype = strchr(object, ':'); if (dntype) { /* @objectclasse:dntype */ *dntype++ = '\0'; } attrs = slapi_schema_list_objectclass_attributes( (const char *)object, SLAPI_OC_FLAG_REQUIRED); allowedattrs = slapi_schema_list_objectclass_attributes( (const char *)object, SLAPI_OC_FLAG_ALLOWED); charray_merge(&attrs, allowedattrs, 0 /* no copy */); slapi_ch_free((void **)&allowedattrs); /* free just allowedattrs */ if (NULL == attrs) { rc = LDAP_SUCCESS; /* bogus objectclass info; ok to return */ goto bailout; } for (i = 0; attrs[i]; i++) { if (0 == strcasecmp(attrs[i], "objectclass")) { /* <*attrp>: <object>\n\0 */ siz += strlen(attrs[i]) + 4 + strlen(object); } else { /* <*attrp>: (template_attribute)\n\0 */ siz += strlen(attrs[i]) + 4 + 20; } } /* get the target dn where the template entry is located */ slapi_pblock_get( pb, SLAPI_TARGET_SDN, &sdn ); dn = slapi_sdn_get_dn(sdn); if (dn) { /* dn: <attr>=<template_name>,<dn>\n\0 */ if (dntype) { siz += strlen(dntype) + 30 + strlen(object) + strlen(dn); } else { siz += strlen(attrs[0]) + 30 + strlen(object) + strlen(dn); } } else { /* dn: <attr>=<template_name>\n\0 */ if (dntype) { siz += strlen(dntype) + 30 + strlen(object); } else { siz += strlen(attrs[0]) + 30 + strlen(object); } } templateentry = (char *)slapi_ch_malloc(siz); if (NULL != dn && strlen(dn) > 0) { PR_snprintf(templateentry, siz, "dn: %s=template_%s_objectclass,%s\n", dntype?dntype:attrs[0], object, dn); } else { PR_snprintf(templateentry, siz, "dn: %s=template_%s_objectclass\n", dntype?dntype:attrs[0], object); } for (--i; i >= 0; i--) { len = strlen(templateentry); p = templateentry + len; if (0 == strcasecmp(attrs[i], "objectclass")) { PR_snprintf(p, siz - len, "%s: %s\n", attrs[i], object); } else { PR_snprintf(p, siz - len, "%s: (template_attribute)\n", attrs[i]); } } charray_free(attrs); while ((superior = slapi_schema_get_superior_name(object)) && (0 != strcasecmp(superior, "top"))) { if (notfirst) { slapi_ch_free_string(&object); } notfirst = 1; object = superior; attrs = slapi_schema_list_objectclass_attributes( (const char *)superior, SLAPI_OC_FLAG_REQUIRED); for (i = 0; attrs && attrs[i]; i++) { if (0 == strcasecmp(attrs[i], "objectclass")) { /* <*attrp>: <object>\n\0 */ siz += strlen(attrs[i]) + 4 + strlen(object); } } templateentry = (char *)slapi_ch_realloc(templateentry, siz); for (--i; i >= 0; i--) { len = strlen(templateentry); p = templateentry + len; if (0 == strcasecmp(attrs[i], "objectclass")) { PR_snprintf(p, siz - len, "%s: %s\n", attrs[i], object); } } charray_free(attrs); } if (notfirst) { slapi_ch_free_string(&object); } slapi_ch_free_string(&superior); siz += 18; /* objectclass: top\n\0 */ len = strlen(templateentry); templateentry = (char *)slapi_ch_realloc(templateentry, siz); p = templateentry + len; PR_snprintf(p, siz - len, "objectclass: top\n"); e = slapi_str2entry(templateentry, SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF); /* set the template entry to send the result to clients */ slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, e); bailout: slapi_ch_free_string(&templateentry); return rc; }
int ipa_topo_init(Slapi_PBlock *pb) { int rc = 0; void *ipa_topo_plugin_identity = NULL; slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM, "--> ipa_topo_init\n"); /** * Store the plugin identity for later use. * Used for internal operations */ slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &ipa_topo_plugin_identity); ipa_topo_set_plugin_id(ipa_topo_plugin_identity); if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) != 0 || slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *)ipa_topo_start) != 0 || slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *)ipa_topo_close) != 0 || slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &pdesc) != 0) { slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM, "ipa_topo_init: failed to register plugin\n"); rc = 1; } if (rc == 0) { char *plugin_type = "bepreoperation"; if (slapi_register_plugin(plugin_type, 1, "ipa_topo_init", ipa_topo_preop_init, IPA_TOPO_PREOP_DESC, NULL, ipa_topo_get_plugin_id())) { slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM, "ipa_topo_init: failed to register preop plugin\n"); rc = 1; } } if (rc == 0) { char *plugin_type = "postoperation"; if (slapi_register_plugin(plugin_type, 1, "ipa_topo_init", ipa_topo_postop_init, IPA_TOPO_POSTOP_DESC, NULL, ipa_topo_get_plugin_id())) { slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM, "ipa_topo_init: failed to register postop plugin\n"); rc = 1; } } if (rc == 0) { char *plugin_type = "internalpostoperation"; if (slapi_register_plugin(plugin_type, 1, "ipa_topo_internal_init", ipa_topo_internal_postop_init, IPA_TOPO_INTERNAL_POSTOP_DESC, NULL, ipa_topo_get_plugin_id())) { slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM, "ipa_topo_init: failed to register internal postop plugin\n"); rc = 1; } } slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM, "<-- ipa_topo_init\n"); return(rc); }
static int _ger_g_permission_granted ( Slapi_PBlock *pb, Slapi_Entry *e, const char *subjectdn, char **errbuf ) { char *proxydn = NULL; Slapi_DN *requestor_sdn, *entry_sdn; char *errtext = NULL; int isroot; int rc; /* * Theorically, we should check if the entry has "g" * permission granted to the requestor. If granted, * allows the effective rights on that entry and its * attributes within the entry to be returned for * ANY subject. * * "G" permission granting has not been implemented yet, * the current release assumes that "g" permission be * granted to root and owner of any entry. */ /* * The requestor may be either the bind dn or a proxy dn */ if ((proxyauth_get_dn( pb, &proxydn, &errtext ) == LDAP_SUCCESS) && ( proxydn != NULL )) { requestor_sdn = slapi_sdn_new_dn_passin ( proxydn ); } else { requestor_sdn = &(pb->pb_op->o_sdn); } if ( slapi_sdn_get_dn (requestor_sdn) == NULL ) { slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_g_permission_granted: anonymous has no g permission\n" ); rc = LDAP_INSUFFICIENT_ACCESS; goto bailout; } isroot = slapi_dn_isroot ( slapi_sdn_get_dn (requestor_sdn) ); if ( isroot ) { /* Root has "g" permission on any entry */ rc = LDAP_SUCCESS; goto bailout; } entry_sdn = slapi_entry_get_sdn ( e ); if ( entry_sdn == NULL || slapi_sdn_get_dn (entry_sdn) == NULL ) { rc = LDAP_SUCCESS; goto bailout; } if ( slapi_sdn_compare ( requestor_sdn, entry_sdn ) == 0 ) { /* Owner has "g" permission on his own entry */ rc = LDAP_SUCCESS; goto bailout; } /* if the requestor and the subject user are identical, let's grant it */ if ( strcasecmp ( slapi_sdn_get_ndn(requestor_sdn), subjectdn ) == 0) { /* Requestor should see his own permission rights on any entry */ rc = LDAP_SUCCESS; goto bailout; } aclutil_str_append ( errbuf, "get-effective-rights: requestor has no g permission on the entry" ); slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_g_permission_granted: %s\n", *errbuf); rc = LDAP_INSUFFICIENT_ACCESS; bailout: if ( proxydn ) { /* The ownership of proxydn has passed to requestor_sdn */ slapi_sdn_free ( &requestor_sdn ); } return rc; }
/* * Thread routine for sending search results to a client * which is persistently waiting for them. * * This routine will terminate when either (a) the ps_complete * flag is set, or (b) the associated operation is abandoned. * In any case, the thread won't notice until it wakes from * sleeping on the ps_list condition variable, so it needs * to be awakened. */ static void ps_send_results( void *arg ) { PSearch *ps = (PSearch *)arg; PSEQNode *peq, *peqnext; struct slapi_filter *filter = 0; char *base = NULL; Slapi_DN *sdn = NULL; char *fstr = NULL; char **pbattrs = NULL; int conn_acq_flag = 0; g_incr_active_threadcnt(); /* need to acquire a reference to this connection so that it will not be released or cleaned up out from under us */ PR_Lock( ps->ps_pblock->pb_conn->c_mutex ); conn_acq_flag = connection_acquire_nolock(ps->ps_pblock->pb_conn); PR_Unlock( ps->ps_pblock->pb_conn->c_mutex ); if (conn_acq_flag) { slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search", "conn=%" NSPRIu64 " op=%d Could not acquire the connection - psearch aborted\n", ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid); } PR_Lock( psearch_list->pl_cvarlock ); while ( (conn_acq_flag == 0) && !ps->ps_complete ) { /* Check for an abandoned operation */ if ( ps->ps_pblock->pb_op == NULL || slapi_op_abandoned( ps->ps_pblock ) ) { slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search", "conn=%" NSPRIu64 " op=%d The operation has been abandoned\n", ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid); break; } if ( NULL == ps->ps_eq_head ) { /* Nothing to do */ PR_WaitCondVar( psearch_list->pl_cvar, PR_INTERVAL_NO_TIMEOUT ); } else { /* dequeue the item */ int attrsonly; char **attrs; LDAPControl **ectrls; Slapi_Entry *ec; Slapi_Filter *f = NULL; PR_Lock( ps->ps_lock ); peq = ps->ps_eq_head; ps->ps_eq_head = peq->pe_next; if ( NULL == ps->ps_eq_head ) { ps->ps_eq_tail = NULL; } PR_Unlock( ps->ps_lock ); /* Get all the information we need to send the result */ ec = peq->pe_entry; slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_ATTRS, &attrs ); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_ATTRSONLY, &attrsonly ); if ( !ps->ps_send_entchg_controls || peq->pe_ctrls[0] == NULL ) { ectrls = NULL; } else { ectrls = peq->pe_ctrls; } /* * Send the result. Since send_ldap_search_entry can block for * up to 30 minutes, we relinquish all locks before calling it. */ PR_Unlock(psearch_list->pl_cvarlock); /* * The entry is in the right scope and matches the filter * but we need to redo the filter test here to check access * controls. See the comments at the slapi_filter_test() * call in ps_service_persistent_searches(). */ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_FILTER, &f ); /* See if the entry meets the filter and ACL criteria */ if ( slapi_vattr_filter_test( ps->ps_pblock, ec, f, 1 /* verify_access */ ) == 0 ) { int rc = 0; slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_RESULT_ENTRY, ec ); rc = send_ldap_search_entry( ps->ps_pblock, ec, ectrls, attrs, attrsonly ); if (rc) { slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search", "conn=%" NSPRIu64 " op=%d Error %d sending entry %s with op status %d\n", ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid, rc, slapi_entry_get_dn_const(ec), ps->ps_pblock->pb_op->o_status); } } PR_Lock(psearch_list->pl_cvarlock); /* Deallocate our wrapper for this entry */ pe_ch_free( &peq ); } } PR_Unlock( psearch_list->pl_cvarlock ); ps_remove( ps ); /* indicate the end of search */ plugin_call_plugins( ps->ps_pblock , SLAPI_PLUGIN_POST_SEARCH_FN ); /* free things from the pblock that were not free'd in do_search() */ /* we strdup'd this in search.c - need to free */ slapi_pblock_get( ps->ps_pblock, SLAPI_ORIGINAL_TARGET_DN, &base ); slapi_pblock_set( ps->ps_pblock, SLAPI_ORIGINAL_TARGET_DN, NULL ); slapi_ch_free_string(&base); /* Free SLAPI_SEARCH_* before deleting op since those are held by op */ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, &sdn ); slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, NULL ); slapi_sdn_free(&sdn); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_STRFILTER, &fstr ); slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_STRFILTER, NULL ); slapi_ch_free_string(&fstr); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_ATTRS, &pbattrs ); slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_ATTRS, NULL ); if ( pbattrs != NULL ) { charray_free( pbattrs ); } slapi_pblock_get(ps->ps_pblock, SLAPI_SEARCH_FILTER, &filter ); slapi_pblock_set(ps->ps_pblock, SLAPI_SEARCH_FILTER, NULL ); slapi_filter_free(filter, 1); /* Clean up the connection structure */ PR_Lock( ps->ps_pblock->pb_conn->c_mutex ); slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search", "conn=%" NSPRIu64 " op=%d Releasing the connection and operation\n", ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid); /* Delete this op from the connection's list */ connection_remove_operation( ps->ps_pblock->pb_conn, ps->ps_pblock->pb_op ); operation_free(&(ps->ps_pblock->pb_op),ps->ps_pblock->pb_conn); ps->ps_pblock->pb_op=NULL; /* Decrement the connection refcnt */ if (conn_acq_flag == 0) { /* we acquired it, so release it */ connection_release_nolock (ps->ps_pblock->pb_conn); } PR_Unlock( ps->ps_pblock->pb_conn->c_mutex ); PR_DestroyLock ( ps->ps_lock ); ps->ps_lock = NULL; slapi_ch_free((void **) &ps->ps_pblock ); for ( peq = ps->ps_eq_head; peq; peq = peqnext) { peqnext = peq->pe_next; pe_ch_free( &peq ); } slapi_ch_free((void **) &ps ); g_decr_active_threadcnt(); }
static int retrocl_create_be(const char *bedir) { Slapi_PBlock *pb = NULL; Slapi_Entry *e; struct berval *vals[2]; struct berval val; int rc; vals[0] = &val; vals[1] = NULL; e = slapi_entry_alloc(); /* RETROCL_LDBM_DN is no need to be normalized. */ slapi_entry_set_dn(e,slapi_ch_strdup(RETROCL_LDBM_DN)); /* Set the objectclass attribute */ val.bv_val = "top"; val.bv_len = 3; slapi_entry_add_values( e, "objectclass", vals ); /* Set the objectclass attribute */ val.bv_val = "extensibleObject"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "objectclass", vals ); /* Set the objectclass attribute */ val.bv_val = "nsBackendInstance"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "objectclass", vals ); val.bv_val = "changelog"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "cn", vals ); val.bv_val = RETROCL_BE_CACHESIZE; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nsslapd-cachesize", vals ); val.bv_val = RETROCL_CHANGELOG_DN; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nsslapd-suffix", vals ); val.bv_val = RETROCL_BE_CACHEMEMSIZE; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nsslapd-cachememsize", vals ); val.bv_val = "off"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nsslapd-readonly", vals ); if (bedir) { val.bv_val = (char *)bedir; /* cast const */ val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nsslapd-directory", vals ); } pb = slapi_pblock_new (); slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */, g_plg_identity[PLUGIN_RETROCL], 0 /* actions */ ); slapi_add_internal_pb (pb); slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc ); slapi_pblock_destroy(pb); if (rc == 0) { slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "created changelog database node\n"); } else if (rc == LDAP_ALREADY_EXISTS) { slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "changelog database node already existed\n"); } else { slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "Changelog LDBM backend could not be created (%d)\n", rc); return rc; } /* we need the changenumber indexed */ e = slapi_entry_alloc(); /* RETROCL_INDEX_DN is no need to be normalized. */ slapi_entry_set_dn(e,slapi_ch_strdup(RETROCL_INDEX_DN)); /* Set the objectclass attribute */ val.bv_val = "top"; val.bv_len = 3; slapi_entry_add_values( e, "objectclass", vals ); /* Set the objectclass attribute */ val.bv_val = "nsIndex"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "objectclass", vals ); val.bv_val = "changenumber"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "cn", vals ); val.bv_val = "false"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nssystemindex", vals ); val.bv_val = "eq"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nsindextype", vals ); val.bv_val = "integerOrderingMatch"; val.bv_len = strlen(val.bv_val); slapi_entry_add_values( e, "nsMatchingRule", vals ); pb = slapi_pblock_new (); slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */, g_plg_identity[PLUGIN_RETROCL], 0 /* actions */ ); slapi_add_internal_pb (pb); slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc ); slapi_pblock_destroy(pb); if (rc == 0) { slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "created changenumber index node\n"); } else if (rc == LDAP_ALREADY_EXISTS) { slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "changelog index node already existed\n"); } else { slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "Changelog LDBM backend changenumber index could not be created (%d)\n", rc); return rc; } return rc; }
/* * Check if there are any persistent searches. If so, * the check to see if the chgtype is one of those the * client is interested in. If so, then check to see if * the entry matches any of the filters the searches. * If so, then enqueue the entry on that persistent search's * ps_entryqueue and signal it to wake up and send the entry. * * Note that if eprev is NULL we assume that the entry's DN * was not changed by the op. that called this function. If * chgnum is 0 it is unknown so we won't ever send it to a * client in the EntryChangeNotification control. */ void ps_service_persistent_searches( Slapi_Entry *e, Slapi_Entry *eprev, ber_int_t chgtype, ber_int_t chgnum ) { LDAPControl *ctrl = NULL; PSearch *ps = NULL; PSEQNode *pe = NULL; int matched = 0; const char *edn; if ( !PS_IS_INITIALIZED()) { return; } if ( NULL == e ) { /* For now, some backends such as the chaining backend do not provide a post-op entry */ return; } PSL_LOCK_READ(); edn = slapi_entry_get_dn_const(e); for ( ps = psearch_list ? psearch_list->pl_head : NULL; NULL != ps; ps = ps->ps_next ) { char *origbase = NULL; Slapi_DN *base = NULL; Slapi_Filter *f; int scope; /* Skip the node that doesn't meet the changetype, * or is unable to use the change in ps_send_results() */ if (( ps->ps_changetypes & chgtype ) == 0 || ps->ps_pblock->pb_op == NULL || slapi_op_abandoned( ps->ps_pblock ) ) { continue; } slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search", "conn=%" NSPRIu64 " op=%d entry %s with chgtype %d " "matches the ps changetype %d\n", ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid, edn, chgtype, ps->ps_changetypes); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_FILTER, &f ); slapi_pblock_get( ps->ps_pblock, SLAPI_ORIGINAL_TARGET_DN, &origbase ); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, &base ); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_SCOPE, &scope ); if (NULL == base) { base = slapi_sdn_new_dn_byref(origbase); slapi_pblock_set(ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, base); } /* * See if the entry meets the scope and filter criteria. * We cannot do the acl check here as this thread * would then potentially clash with the ps_send_results() * thread on the aclpb in ps->ps_pblock. * By avoiding the acl check in this thread, and leaving all the acl * checking to the ps_send_results() thread we avoid * the ps_pblock contention problem. * The lesson here is "Do not give multiple threads arbitary access * to the same pblock" this kind of muti-threaded access * to the same pblock must be done carefully--there is currently no * generic satisfactory way to do this. */ if ( slapi_sdn_scope_test( slapi_entry_get_sdn_const(e), base, scope ) && slapi_vattr_filter_test( ps->ps_pblock, e, f, 0 /* verify_access */ ) == 0 ) { PSEQNode *pOldtail; /* The scope and the filter match - enqueue it */ matched++; pe = (PSEQNode *)slapi_ch_calloc( 1, sizeof( PSEQNode )); pe->pe_entry = slapi_entry_dup( e ); if ( ps->ps_send_entchg_controls ) { /* create_entrychange_control() is more * expensive than slapi_dup_control() */ if ( ctrl == NULL ) { int rc; rc = create_entrychange_control( chgtype, chgnum, eprev ? slapi_entry_get_dn_const(eprev) : NULL, &ctrl ); if ( rc != LDAP_SUCCESS ) { LDAPDebug( LDAP_DEBUG_ANY, "ps_service_persistent_searches:" " unable to create EntryChangeNotification control for" " entry \"%s\" -- control won't be sent.\n", slapi_entry_get_dn_const(e), 0, 0 ); } } if ( ctrl ) { pe->pe_ctrls[0] = slapi_dup_control( ctrl ); } } /* Put it on the end of the list for this pers search */ PR_Lock( ps->ps_lock ); pOldtail = ps->ps_eq_tail; ps->ps_eq_tail = pe; if ( NULL == ps->ps_eq_head ) { ps->ps_eq_head = ps->ps_eq_tail; } else { pOldtail->pe_next = ps->ps_eq_tail; } PR_Unlock( ps->ps_lock ); } } PSL_UNLOCK_READ(); /* Were there any matches? */ if ( matched ) { ldap_control_free( ctrl ); /* Turn 'em loose */ ps_wakeup_all(); LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: enqueued entry " "\"%s\" on %d persistent search lists\n", slapi_entry_get_dn_const(e), matched, 0 ); } else { LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: entry " "\"%s\" not enqueued on any persistent search lists\n", slapi_entry_get_dn_const(e), 0, 0 ); } }
/* * * aclg_get_usersGroup * * If we already have a the group info then we are done. If we * don't, then allocate a new one and attach it. * * Inputs: * struct acl_pblock -- The acl private block. * char *n_dn - normalized client's DN * * Returns: * aclUserGroup - The Group info block. * */ aclUserGroup * aclg_get_usersGroup ( struct acl_pblock *aclpb , char *n_dn) { aclUserGroup *u_group, *f_group; if ( !aclpb ) { slapi_log_error( SLAPI_LOG_ACL, plugin_name, "NULL acl pblock\n" ); return NULL; } if ( aclpb->aclpb_groupinfo ) return aclpb->aclpb_groupinfo; ACLG_LOCK_GROUPCACHE_WRITE(); /* try it one more time. We might have one in the meantime */ aclg_init_userGroup (aclpb, n_dn , 1 /* got the lock */); if ( aclpb->aclpb_groupinfo ) { ACLG_ULOCK_GROUPCACHE_WRITE(); return aclpb->aclpb_groupinfo; } /* * It is possible at this point that we already have a group cache for the user * but is is invalid. We can't use it anayway. So, we march along and allocate a new one. * That's fine as the invalid one will be deallocated when done. */ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "ALLOCATING GROUP FOR:%s\n", n_dn ); u_group = ( aclUserGroup * ) slapi_ch_calloc ( 1, sizeof ( aclUserGroup ) ); u_group->aclug_refcnt = 1; if ( (u_group->aclug_refcnt_mutex = PR_NewLock()) == NULL ) { slapi_ch_free((void **)&u_group); ACLG_ULOCK_GROUPCACHE_WRITE(); return(NULL); } u_group->aclug_member_groups = (char **) slapi_ch_calloc ( 1, (ACLUG_INCR_GROUPS_LIST * sizeof (char *))); u_group->aclug_member_group_size = ACLUG_INCR_GROUPS_LIST; u_group->aclug_numof_member_group = 0; u_group->aclug_notmember_groups = (char **) slapi_ch_calloc ( 1, (ACLUG_INCR_GROUPS_LIST * sizeof (char *))); u_group->aclug_notmember_group_size = ACLUG_INCR_GROUPS_LIST; u_group->aclug_numof_notmember_group = 0; u_group->aclug_ndn = slapi_ch_strdup ( n_dn ) ; u_group->aclug_signature = aclUserGroups->aclg_signature; /* Do we have alreday the max number. If we have then delete the last one */ if ( aclUserGroups->aclg_num_userGroups >= ACL_MAXCACHE_USERGROUPS - 5 ) { aclUserGroup *d_group; /* We need to traverse thru backwards and delete the one with a refcnt = 0 */ d_group = aclUserGroups->aclg_last; while ( d_group ) { if ( !d_group->aclug_refcnt ) { __aclg__delete_userGroup ( d_group ); break; } else { d_group = d_group->aclug_prev; } } /* If we didn't find any, which should be never, ** we have 5 more tries to do it. */ } f_group = aclUserGroups->aclg_first; u_group->aclug_next = f_group; if ( f_group ) f_group->aclug_prev = u_group; aclUserGroups->aclg_first = u_group; if ( aclUserGroups->aclg_last == NULL ) aclUserGroups->aclg_last = u_group; aclUserGroups->aclg_num_userGroups++; /* Put it in the queue */ ACLG_ULOCK_GROUPCACHE_WRITE(); /* Now hang on to it */ aclpb->aclpb_groupinfo = u_group; return u_group; }
int acl_get_effective_rights ( Slapi_PBlock *pb, Slapi_Entry *e, /* target entry */ char **attrs, /* Attribute of the entry */ struct berval *val, /* value of attr. NOT USED */ int access, /* requested access rights */ char **errbuf ) { Slapi_PBlock *gerpb = NULL; void *aclcb = NULL; char *subjectndn = NULL; char *gerstr = NULL; size_t gerstrsize = 0; size_t gerstrcap = 0; int iscritical = 1; int rc = LDAP_SUCCESS; *errbuf = '\0'; if (NULL == e) /* create a template entry from SLAPI_SEARCH_GERATTRS */ { rc = _ger_generate_template_entry ( pb ); slapi_pblock_get ( pb, SLAPI_SEARCH_RESULT_ENTRY, &e ); if ( rc != LDAP_SUCCESS || NULL == e ) { goto bailout; } } /* * Get the subject */ rc = _ger_parse_control (pb, &subjectndn, &iscritical, errbuf ); if ( rc != LDAP_SUCCESS ) { goto bailout; } /* * The requestor should have g permission on the entry * to get the effective rights. */ rc = _ger_g_permission_granted (pb, e, subjectndn, errbuf); if ( rc != LDAP_SUCCESS ) { goto bailout; } /* * Construct a new pb */ rc = _ger_new_gerpb ( pb, e, subjectndn, &gerpb, &aclcb, errbuf ); if ( rc != LDAP_SUCCESS ) { goto bailout; } /* Get entry level effective rights */ _ger_get_entry_rights ( gerpb, e, subjectndn, &gerstr, &gerstrsize, &gerstrcap, errbuf ); /* * Attribute level effective rights may not be NULL * even if entry level's is. */ _ger_get_attrs_rights ( gerpb, e, subjectndn, attrs, &gerstr, &gerstrsize, &gerstrcap, errbuf ); bailout: /* * Now construct the response control */ _ger_set_response_control ( pb, iscritical, rc ); if ( rc != LDAP_SUCCESS ) { gerstr = slapi_ch_smprintf("entryLevelRights: %d\nattributeLevelRights: *:%d", rc, rc ); } slapi_log_error (SLAPI_LOG_ACLSUMMARY, plugin_name, "###### Effective Rights on Entry (%s) for Subject (%s) ######\n", e?slapi_entry_get_ndn(e):"null", subjectndn?subjectndn:"null"); slapi_log_error (SLAPI_LOG_ACLSUMMARY, plugin_name, "%s\n", gerstr); /* Restore pb */ _ger_release_gerpb ( &gerpb, &aclcb, pb ); /* * General plugin uses SLAPI_RESULT_TEXT for error text. Here * SLAPI_PB_RESULT_TEXT is exclusively shared with add, dse and schema. * slapi_pblock_set() will free any previous data, and * pblock_done() will free SLAPI_PB_RESULT_TEXT. */ slapi_pblock_set (pb, SLAPI_PB_RESULT_TEXT, gerstr); if ( !iscritical ) { /* * If return code is not LDAP_SUCCESS, the server would * abort sending the data of the entry to the client. */ rc = LDAP_SUCCESS; } slapi_ch_free ( (void **) &subjectndn ); slapi_ch_free ( (void **) &gerstr ); return rc; }
static Slapi_PBlock * plugin_pblock_new( int type, int argc, char *argv[] ) { Slapi_PBlock *pPlugin = NULL; Slapi_PluginDesc *pPluginDesc = NULL; lt_dlhandle hdLoadHandle; int rc; char **av2 = NULL, **ppPluginArgv; char *path = argv[2]; char *initfunc = argv[3]; pPlugin = slapi_pblock_new(); if ( pPlugin == NULL ) { rc = LDAP_NO_MEMORY; goto done; } slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)&type ); slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)&argc ); av2 = ldap_charray_dup( argv ); if ( av2 == NULL ) { rc = LDAP_NO_MEMORY; goto done; } if ( argc > 0 ) { ppPluginArgv = &av2[4]; } else { ppPluginArgv = NULL; } slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)ppPluginArgv ); slapi_pblock_set( pPlugin, SLAPI_X_CONFIG_ARGV, (void *)av2 ); rc = slapi_int_load_plugin( pPlugin, path, initfunc, 1, NULL, &hdLoadHandle ); if ( rc != 0 ) { goto done; } if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 && pPluginDesc != NULL ) { slapi_log_error(SLAPI_LOG_TRACE, "plugin_pblock_new", "Registered plugin %s %s [%s] (%s)\n", pPluginDesc->spd_id, pPluginDesc->spd_version, pPluginDesc->spd_vendor, pPluginDesc->spd_description); } done: if ( rc != 0 && pPlugin != NULL ) { slapi_pblock_destroy( pPlugin ); pPlugin = NULL; if ( av2 != NULL ) { ldap_charray_free( av2 ); } } return pPlugin; }
/* * Do the actual work of authenticating with PAM. First, get the PAM identity * based on the method used to convert the BIND identity to the PAM identity. * Set up the structures that pam_start needs and call pam_start(). After * that, call pam_authenticate and pam_acct_mgmt. Check the various return * values from these functions and map them to their corresponding LDAP BIND * return values. Return the appropriate LDAP error code. * This function will also set the appropriate LDAP response controls in * the given pblock. * Since this function can be called multiple times, we only want to return * the errors and controls to the user if this is the final call, so the * final_method parameter tells us if this is the last one. Coupled with * the fallback argument, we can tell if we are able to send the response * back to the client. */ static int do_one_pam_auth( Slapi_PBlock *pb, int method, /* get pam identity from ENTRY, RDN, or DN */ PRBool final_method, /* which method is the last one to try */ char *pam_service, /* name of service for pam_start() */ char *map_ident_attr, /* for ENTRY method, name of attribute holding pam identity */ PRBool fallback, /* if true, failure here should fallback to regular bind */ int pw_response_requested /* do we need to send pwd policy resp control */ ) { MyStrBuf pam_id; const char *binddn = NULL; Slapi_DN *bindsdn = NULL; int rc; int retcode = LDAP_SUCCESS; pam_handle_t *pam_handle; struct my_pam_conv_str my_data; struct pam_conv my_pam_conv = {pam_conv_func, NULL}; char *errmsg = NULL; /* free with PR_smprintf_free */ int locked = 0; slapi_pblock_get( pb, SLAPI_BIND_TARGET_SDN, &bindsdn ); if (NULL == bindsdn) { errmsg = PR_smprintf("Null bind dn"); retcode = LDAP_OPERATIONS_ERROR; pam_id.str = NULL; /* initialize pam_id.str */ goto done; /* skip the pam stuff */ } binddn = slapi_sdn_get_dn(bindsdn); if (method == PAMPT_MAP_METHOD_RDN) { derive_from_bind_dn(pb, bindsdn, &pam_id); } else if (method == PAMPT_MAP_METHOD_ENTRY) { derive_from_bind_entry(pb, bindsdn, &pam_id, map_ident_attr, &locked); } else { init_my_str_buf(&pam_id, binddn); } if (locked) { errmsg = PR_smprintf("Account inactivated. Contact system administrator."); retcode = LDAP_UNWILLING_TO_PERFORM; /* user inactivated */ goto done; /* skip the pam stuff */ } if (!pam_id.str) { errmsg = PR_smprintf("Bind DN [%s] is invalid or not found", binddn); retcode = LDAP_NO_SUCH_OBJECT; /* user unknown */ goto done; /* skip the pam stuff */ } /* do the pam stuff */ my_data.pb = pb; my_data.pam_identity = pam_id.str; my_pam_conv.appdata_ptr = &my_data; slapi_lock_mutex(PAMLock); /* from this point on we are in the critical section */ rc = pam_start(pam_service, pam_id.str, &my_pam_conv, &pam_handle); report_pam_error("during pam_start", rc, pam_handle); if (rc == PAM_SUCCESS) { /* use PAM_SILENT - there is no user interaction at this point */ rc = pam_authenticate(pam_handle, 0); report_pam_error("during pam_authenticate", rc, pam_handle); /* check different types of errors here */ if (rc == PAM_USER_UNKNOWN) { errmsg = PR_smprintf("User id [%s] for bind DN [%s] does not exist in PAM", pam_id.str, binddn); retcode = LDAP_NO_SUCH_OBJECT; /* user unknown */ } else if (rc == PAM_AUTH_ERR) { errmsg = PR_smprintf("Invalid PAM password for user id [%s], bind DN [%s]", pam_id.str, binddn); retcode = LDAP_INVALID_CREDENTIALS; /* invalid creds */ } else if (rc == PAM_MAXTRIES) { errmsg = PR_smprintf("Authentication retry limit exceeded in PAM for " "user id [%s], bind DN [%s]", pam_id.str, binddn); if (pw_response_requested) { slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_ACCTLOCKED); } retcode = LDAP_CONSTRAINT_VIOLATION; /* max retries */ } else if (rc != PAM_SUCCESS) { errmsg = PR_smprintf("Unknown PAM error [%s] for user id [%s], bind DN [%s]", pam_strerror(pam_handle, rc), pam_id.str, binddn); retcode = LDAP_OPERATIONS_ERROR; /* pam config or network problem */ } } /* if user authenticated successfully, see if there is anything we need to report back w.r.t. password or account lockout */ if (rc == PAM_SUCCESS) { rc = pam_acct_mgmt(pam_handle, 0); report_pam_error("during pam_acct_mgmt", rc, pam_handle); /* check different types of errors here */ if (rc == PAM_USER_UNKNOWN) { errmsg = PR_smprintf("User id [%s] for bind DN [%s] does not exist in PAM", pam_id.str, binddn); retcode = LDAP_NO_SUCH_OBJECT; /* user unknown */ } else if (rc == PAM_AUTH_ERR) { errmsg = PR_smprintf("Invalid PAM password for user id [%s], bind DN [%s]", pam_id.str, binddn); retcode = LDAP_INVALID_CREDENTIALS; /* invalid creds */ } else if (rc == PAM_PERM_DENIED) { errmsg = PR_smprintf("Access denied for PAM user id [%s], bind DN [%s]" " - see administrator", pam_id.str, binddn); if (pw_response_requested) { slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_ACCTLOCKED); } retcode = LDAP_UNWILLING_TO_PERFORM; } else if (rc == PAM_ACCT_EXPIRED) { errmsg = PR_smprintf("Expired PAM password for user id [%s], bind DN [%s]: " "reset required", pam_id.str, binddn); slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0); if (pw_response_requested) { slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED); } retcode = LDAP_INVALID_CREDENTIALS; } else if (rc == PAM_NEW_AUTHTOK_REQD) { /* handled same way as ACCT_EXPIRED */ errmsg = PR_smprintf("Expired PAM password for user id [%s], bind DN [%s]: " "reset required", pam_id.str, binddn); slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0); if (pw_response_requested) { slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED); } retcode = LDAP_INVALID_CREDENTIALS; } else if (rc != PAM_SUCCESS) { errmsg = PR_smprintf("Unknown PAM error [%s] for user id [%s], bind DN [%s]", pam_strerror(pam_handle, rc), pam_id.str, binddn); retcode = LDAP_OPERATIONS_ERROR; /* unknown */ } } rc = pam_end(pam_handle, rc); report_pam_error("during pam_end", rc, pam_handle); slapi_unlock_mutex(PAMLock); /* not in critical section any more */ done: delete_my_str_buf(&pam_id); if ((retcode == LDAP_SUCCESS) && (rc != PAM_SUCCESS)) { errmsg = PR_smprintf("Unknown PAM error [%d] for user id [%s], bind DN [%s]", rc, pam_id.str, binddn); retcode = LDAP_OPERATIONS_ERROR; } if (retcode != LDAP_SUCCESS) { slapi_log_error(SLAPI_LOG_FATAL, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "%s\n", errmsg); if (final_method && !fallback) { slapi_send_ldap_result(pb, retcode, NULL, errmsg, 0, NULL); } } if (errmsg) { PR_smprintf_free(errmsg); } return retcode; }