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_err(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf ); if (iscritical) return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */ else 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_err(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf ); if (iscritical) return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */ else 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_err(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf ); ber_free ( ber, 1 ); if (iscritical) return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */ else 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_err(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf ); slapi_ch_free_string(&orig); if (iscritical) return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */ else 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_err(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf); slapi_ch_free_string(&orig); if (iscritical) return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */ else return LDAP_INVALID_SYNTAX; } slapi_ch_free_string(&orig); *subjectndn = normed; slapi_dn_ignore_case(*subjectndn); return LDAP_SUCCESS; }
/* * update multiple attribute values per _do_modify */ static int _update_all_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */ Slapi_Attr *attr, /* referred attribute */ char *attrName, Slapi_DN *origDN, /* original DN that was modified */ char *newRDN, /* new RDN from modrdn */ const char *newsuperior, /* new superior from modrdn */ Slapi_PBlock *mod_pb) { Slapi_Mods *smods = NULL; char *newDN = NULL; char **dnParts = NULL; char *sval = NULL; char *newvalue = NULL; char *p = NULL; size_t dnlen = 0; int rc = 0; int nval = 0; slapi_attr_get_numvalues(attr, &nval); if (NULL == newRDN && NULL == newsuperior) { /* in delete mode */ LDAPMod *mods[2]; char *values_del[2]; LDAPMod attribute1; /* delete old dn so set that up */ values_del[0] = (char *)slapi_sdn_get_dn(origDN); values_del[1] = NULL; attribute1.mod_type = attrName; attribute1.mod_op = LDAP_MOD_DELETE; attribute1.mod_values = values_del; mods[0] = &attribute1; /* terminate list of mods. */ mods[1] = NULL; rc = _do_modify(mod_pb, entrySDN, mods); if (rc) { slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "_update_all_per_mod: entry %s: deleting \"%s: %s\" failed (%d)" "\n", slapi_sdn_get_dn(entrySDN), attrName, slapi_sdn_get_dn(origDN), rc); } } else { /* in modrdn mode */ const char *superior = NULL; int nval = 0; Slapi_Value *v = NULL; if (NULL == origDN) { slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "_update_all_per_mod: NULL dn was passed\n"); goto bail; } /* need to put together rdn into a dn */ dnParts = slapi_ldap_explode_dn( slapi_sdn_get_dn(origDN), 0 ); if (NULL == dnParts) { slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "_update_all_per_mod: failed to explode dn %s\n", slapi_sdn_get_dn(origDN)); goto bail; } if (NULL == newRDN) { newRDN = dnParts[0]; } if (newsuperior) { superior = newsuperior; } else { /* do not free superior */ superior = slapi_dn_find_parent(slapi_sdn_get_dn(origDN)); } /* newRDN and superior are already normalized. */ newDN = slapi_ch_smprintf("%s,%s", newRDN, superior); slapi_dn_ignore_case(newDN); /* * Compare the modified dn with the value of * the target attribute of referint to find out * the modified dn is the ancestor (case 2) or * the value itself (case 1). * * E.g., * (case 1) * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C * (origDN) (newDN) * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C * (sval) (newDN) * * (case 2) * modrdn: ou=B,o=C --> ou=B',o=C * (origDN) (newDN) * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C * (sval) (sval' + newDN) */ slapi_attr_get_numvalues(attr, &nval); smods = slapi_mods_new(); slapi_mods_init(smods, 2 * nval + 1); for (nval = slapi_attr_first_value(attr, &v); nval != -1; nval = slapi_attr_next_value(attr, nval, &v)) { p = NULL; dnlen = 0; /* DN syntax, which should be a string */ sval = slapi_ch_strdup(slapi_value_get_string(v)); rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen); if (rc == 0) { /* sval is passed in; not terminated */ *(p + dnlen) = '\0'; sval = p; } else if (rc > 0) { slapi_ch_free_string(&sval); sval = p; } /* else: (rc < 0) Ignore the DN normalization error for now. */ p = PL_strstr(sval, slapi_sdn_get_ndn(origDN)); if (p == sval) { /* (case 1) */ slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval); slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newDN); } else if (p) { /* (case 2) */ slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval); *p = '\0'; newvalue = slapi_ch_smprintf("%s%s", sval, newDN); slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newvalue); slapi_ch_free_string(&newvalue); } /* else: value does not include the modified DN. Ignore it. */ slapi_ch_free_string(&sval); } rc = _do_modify(mod_pb, entrySDN, slapi_mods_get_ldapmods_byref(smods)); if (rc) { slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "_update_all_per_mod: entry %s failed (%d)\n", slapi_sdn_get_dn(entrySDN), rc); } /* cleanup memory allocated for dnParts and newDN */ if (dnParts){ slapi_ldap_value_free(dnParts); dnParts = NULL; } slapi_ch_free_string(&newDN); slapi_mods_free(&smods); } bail: return rc; }