Index: /trunk/server/common/patches/389-ds-indirect-cos.patch
===================================================================
--- /trunk/server/common/patches/389-ds-indirect-cos.patch	(revision 2761)
+++ /trunk/server/common/patches/389-ds-indirect-cos.patch	(revision 2761)
@@ -0,0 +1,267 @@
+From a9cd2ffd227c19a458b27415dedaaf4a6b4778ec Mon Sep 17 00:00:00 2001
+From: Mark Reynolds <mreynolds@redhat.com>
+Date: Thu, 11 Jun 2015 12:28:07 -0400
+Subject: [PATCH] Ticket 47921 - indirect cos does not reflect changes in the
+ cos attribute
+
+Bug Description:  Indirect cos results are incorrectly cached, so any changes
+                  to entries that are indirect are not returned to the client.
+
+Fix Description:  Do not cache the vattr result if it came from a indirect cos
+                  definition.
+
+https://fedorahosted.org/389/ticket/47921
+
+Reviewed by: ?
+---
+ dirsrvtests/tickets/ticket47921_test.py | 155 ++++++++++++++++++++++++++++++++
+ ldap/servers/plugins/cos/cos_cache.c    |  26 ++++--
+ 2 files changed, 174 insertions(+), 7 deletions(-)
+ create mode 100644 dirsrvtests/tickets/ticket47921_test.py
+
+diff --git a/dirsrvtests/tickets/ticket47921_test.py b/dirsrvtests/tickets/ticket47921_test.py
+new file mode 100644
+index 0000000..951d33b
+--- /dev/null
++++ b/dirsrvtests/tickets/ticket47921_test.py
+@@ -0,0 +1,155 @@
++import os
++import sys
++import time
++import ldap
++import logging
++import pytest
++from lib389 import DirSrv, Entry, tools, tasks
++from lib389.tools import DirSrvTools
++from lib389._constants import *
++from lib389.properties import *
++from lib389.tasks import *
++from lib389.utils import *
++
++logging.getLogger(__name__).setLevel(logging.DEBUG)
++log = logging.getLogger(__name__)
++
++installation1_prefix = None
++
++
++class TopologyStandalone(object):
++    def __init__(self, standalone):
++        standalone.open()
++        self.standalone = standalone
++
++
++@pytest.fixture(scope="module")
++def topology(request):
++    global installation1_prefix
++    if installation1_prefix:
++        args_instance[SER_DEPLOYED_DIR] = installation1_prefix
++
++    # Creating standalone instance ...
++    standalone = DirSrv(verbose=False)
++    args_instance[SER_HOST] = HOST_STANDALONE
++    args_instance[SER_PORT] = PORT_STANDALONE
++    args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
++    args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
++    args_standalone = args_instance.copy()
++    standalone.allocate(args_standalone)
++    instance_standalone = standalone.exists()
++    if instance_standalone:
++        standalone.delete()
++    standalone.create()
++    standalone.open()
++
++    # Clear out the tmp dir
++    standalone.clearTmpDir(__file__)
++
++    return TopologyStandalone(standalone)
++
++
++def test_ticket47921(topology):
++    '''
++    Test that indirect cos reflects the current value of the indirect entry
++    '''
++
++    INDIRECT_COS_DN = 'cn=cos definition,' + DEFAULT_SUFFIX
++    MANAGER_DN = 'uid=my manager,ou=people,' + DEFAULT_SUFFIX
++    USER_DN = 'uid=user,ou=people,' + DEFAULT_SUFFIX
++
++    # Add COS definition
++    try:
++        topology.standalone.add_s(Entry((INDIRECT_COS_DN,
++            {'objectclass': 'top cosSuperDefinition cosIndirectDefinition ldapSubEntry'.split(),
++             'cosIndirectSpecifier': 'manager',
++             'cosAttribute': 'roomnumber'
++            })))
++    except ldap.LDAPError, e:
++        log.fatal('Failed to add cos defintion, error: ' + e.message['desc'])
++        assert False
++
++    # Add manager entry
++    try:
++        topology.standalone.add_s(Entry((MANAGER_DN,
++            {'objectclass': 'top extensibleObject'.split(),
++             'uid': 'my manager',
++             'roomnumber': '1'
++            })))
++    except ldap.LDAPError, e:
++        log.fatal('Failed to add manager entry, error: ' + e.message['desc'])
++        assert False
++
++    # Add user entry
++    try:
++        topology.standalone.add_s(Entry((USER_DN,
++            {'objectclass': 'top person organizationalPerson inetorgperson'.split(),
++             'sn': 'last',
++             'cn': 'full',
++             'givenname': 'mark',
++             'uid': 'user',
++             'manager': MANAGER_DN
++            })))
++    except ldap.LDAPError, e:
++        log.fatal('Failed to add manager entry, error: ' + e.message['desc'])
++        assert False
++
++    # Test COS is working
++    try:
++        entry = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
++                                             "uid=user",
++                                             ['roomnumber'])
++        if entry:
++            if entry[0].getValue('roomnumber') != '1':
++                log.fatal('COS is not working.')
++                assert False
++        else:
++            log.fatal('Failed to find user entry')
++            assert False
++    except ldap.LDAPError, e:
++        log.error('Failed to search for user entry: ' + e.message['desc'])
++        assert False
++
++    # Modify manager entry
++    try:
++        topology.standalone.modify_s(MANAGER_DN, [(ldap.MOD_REPLACE, 'roomnumber', '2')])
++    except ldap.LDAPError, e:
++        log.error('Failed to modify manager entry: ' + e.message['desc'])
++        assert False
++
++    # Confirm COS is returning the new value
++    try:
++        entry = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
++                                             "uid=user",
++                                             ['roomnumber'])
++        if entry:
++            if entry[0].getValue('roomnumber') != '2':
++                log.fatal('COS is not working after manager update.')
++                assert False
++        else:
++            log.fatal('Failed to find user entry')
++            assert False
++    except ldap.LDAPError, e:
++        log.error('Failed to search for user entry: ' + e.message['desc'])
++        assert False
++
++    log.info('Test complete')
++
++
++def test_ticket47921_final(topology):
++    topology.standalone.delete()
++    log.info('Testcase PASSED')
++
++
++def run_isolated():
++    global installation1_prefix
++    installation1_prefix = None
++
++    topo = topology(True)
++    test_ticket47921(topo)
++    test_ticket47921_final(topo)
++
++
++if __name__ == '__main__':
++    run_isolated()
++
+diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
+index 7d8e877..fa2b6b5 100644
+--- a/ldap/servers/plugins/cos/cos_cache.c
++++ b/ldap/servers/plugins/cos/cos_cache.c
+@@ -284,7 +284,7 @@ void cos_cache_backend_state_change(void *handle, char *be_name,
+ static int cos_cache_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *free_flags, void *hint);
+ static int cos_cache_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result, int flags, void *hint);
+ static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags);
+-static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *ops);
++static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *ops, int *indirect_cos);
+ 
+ /* 
+ 	compares s2 to s1 starting from end of string until the beginning of either
+@@ -2096,8 +2096,9 @@ static int cos_cache_attrval_exists(cosAttrValue *pAttrs, const char *val)
+ 
+ static int cos_cache_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *free_flags, void *hint)
+ {
+-	int ret = -1;
+ 	cos_cache *pCache = 0;
++	int indirect_cos = 0;
++	int ret = -1;
+ 
+ 	LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_vattr_get\n",0,0,0);
+ 	
+@@ -2108,10 +2109,15 @@ static int cos_cache_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_
+ 		goto bail;
+ 	}
+ 
+-	ret = cos_cache_query_attr(pCache, c, e, type, results, NULL, NULL, NULL);
++	ret = cos_cache_query_attr(pCache, c, e, type, results, NULL, NULL, NULL, &indirect_cos);
+ 	if(ret == 0)
+ 	{
+-        *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES | SLAPI_VIRTUALATTRS_VALUES_CACHEABLE;
++		if(indirect_cos){
++			/* we can't cache indirect cos */
++			*free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
++		} else {
++			*free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES | SLAPI_VIRTUALATTRS_VALUES_CACHEABLE;
++		}
+         *actual_type_name = slapi_ch_strdup(type);
+ 		*type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ 	}
+@@ -2138,7 +2144,7 @@ static int cos_cache_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Sl
+ 		goto bail;
+ 	}
+ 
+-	ret = cos_cache_query_attr(pCache, c, e, type, NULL, test_this, result, NULL);
++	ret = cos_cache_query_attr(pCache, c, e, type, NULL, test_this, result, NULL, NULL);
+ 
+ 	cos_cache_release(pCache);
+ 
+@@ -2179,7 +2185,7 @@ static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,
+ 			lastattr = pCache->ppAttrIndex[index]->pAttrName;
+ 
+ 			if(1 == cos_cache_query_attr(pCache, NULL, e, lastattr, NULL, NULL,
+-											 NULL, &props))
++											 NULL, &props, NULL))
+ 			{
+ 				/* entry contains this attr */
+ 				vattr_type_thang thang = {0};
+@@ -2223,7 +2229,10 @@ bail:
+ 	overriding and allow the DS logic to pick it up by denying knowledge
+ 	of attribute
+ */
+-static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *props)
++static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context,
++                                Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr,
++                                Slapi_Value *test_this, int *result, int *props,
++                                int *indirect_cos)
+ {
+ 	int ret = -1;
+ 	cosCache *pCache = (cosCache*)ptheCache;
+@@ -2420,6 +2429,9 @@ static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Sl
+ 								if (cos_cache_follow_pointer( context, (char*)slapi_value_get_string(indirectdn),
+ 									type, &tmp_vals, test_this, result, pointer_flags) == 0)
+ 								{
++									if(indirect_cos){
++										*indirect_cos = 1;
++									}
+ 									hit = 1;
+ 									/* If the caller requested values, set them.  We need
+ 									 * to append values when we follow multiple pointers DNs. */
+-- 
+1.9.3
+
Index: /trunk/server/fedora/Makefile
===================================================================
--- /trunk/server/fedora/Makefile	(revision 2760)
+++ /trunk/server/fedora/Makefile	(revision 2761)
@@ -19,5 +19,5 @@
 # See /COPYRIGHT in this repository for more information.
 
-upstream_yum	= krb5 krb5.i686 httpd openssh libgsasl openssl openssl.i686
+upstream_yum	= krb5 krb5.i686 httpd openssh libgsasl openssl openssl.i686 389-ds-base
 hackage		= cgi-3001.1.8.5 unix-handle-0.0.0
 upstream_hackage = ghc-cgi ghc-unix-handle
@@ -25,5 +25,5 @@
 upstream_gems	= rubygem-pony rubygem-fcgi
 upstream_eggs   = python-authkit
-upstream	= openafs $(upstream_yum) $(upstream_hackage) $(upstream_gems) $(upstream_eggs) moira zephyr zephyr.i686 python-zephyr python-afs python-moira python-hesiod athena-aclocal discuss
+upstream	= openafs $(upstream_yum) $(upstream_hackage) $(upstream_gems) $(upstream_eggs) moira zephyr zephyr.i686 python-zephyr python-afs python-moira python-hesiod athena-aclocal discuss 
 oursrc		= execsys tokensys accountadm httpdmods logview sql-signup nss_nonlocal nss_nonlocal.i686 whoisd athrun php_scripts scripts-wizard scripts-base scripts-static-cat fuse-better-mousetrapfs scripts-munin-plugins
 allsrc		= $(upstream) $(oursrc)
Index: /trunk/server/fedora/specs/389-ds-base.spec.patch
===================================================================
--- /trunk/server/fedora/specs/389-ds-base.spec.patch	(revision 2761)
+++ /trunk/server/fedora/specs/389-ds-base.spec.patch	(revision 2761)
@@ -0,0 +1,39 @@
+--- 389-ds-base.spec.orig	2016-02-27 22:35:25.978791486 -0500
++++ 389-ds-base.spec	2016-02-27 22:39:49.112790989 -0500
+@@ -25,7 +25,7 @@
+ Summary:          389 Directory Server (base)
+ Name:             389-ds-base
+ Version:          1.3.2.23
+-Release:          %{?relprefix}1%{?prerel}%{?dist}
++Release:          %{?relprefix}1%{?prerel}%{?dist}.scripts.%{scriptsversion}
+ License:          GPLv2 with exceptions
+ URL:              http://port389.org/
+ Group:            System Environment/Daemons
+@@ -115,6 +115,8 @@
+ Source1:          %{name}-git.sh
+ Source2:          %{name}-devel.README
+ 
++Patch1000:        389-ds-indirect-cos.patch
++
+ %description
+ 389 Directory Server is an LDAPv3 compliant server.  The base package includes
+ the LDAP server and command line utilities for server administration.
+@@ -165,6 +167,9 @@
+ %setup -q -n %{name}-%{version}%{?prerel}
+ cp %{SOURCE2} README.devel
+ 
++%define _default_patch_fuzz 2
++%patch1000 -p1 -b .cos
++
+ %build
+ %if %{use_openldap}
+ OPENLDAP_FLAG="--with-openldap"
+@@ -176,7 +181,7 @@
+            --with-systemdsystemunitdir=%{_unitdir} \
+            --with-systemdsystemconfdir=%{_sysconfdir}/systemd/system \
+            --with-perldir=/usr/bin \
+-           --with-systemdgroupname=%{groupname} $NSSARGS
++           --with-systemdgroupname=% {groupname} $NSSARGS
+ 
+ # Generate symbolic info for debuggers
+ export XCFLAGS=$RPM_OPT_FLAGS
