~ubuntu-branches/debian/jessie/389-ds-base/jessie

« back to all changes in this revision

Viewing changes to ldap/servers/slapd/schema.c

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2014-07-08 15:50:11 UTC
  • mfrom: (0.2.2)
  • Revision ID: package-import@ubuntu.com-20140708155011-r66lvtioamqwaype
Tags: 1.3.2.19-1
* New upstream release.
* admin_scripts.diff: Updated to fix more bashisms.
* watch: Update the url.
* Install failedbinds.py and logregex.py scripts.
* init: Use status from init-functions.
* control: Update my email.

Show diffs side-by-side

added added

removed removed

Lines of Context:
61
61
        size_t size;
62
62
} sizedbuffer;
63
63
 
 
64
 
64
65
typedef char *(*schema_strstr_fn_t)( const char *big, const char *little);
65
66
 
66
67
/*
86
87
        NULL
87
88
};
88
89
 
 
90
/* The policies for the replication of the schema are 
 
91
 *  - base policy
 
92
 *  - extended policies
 
93
 * Those policies are enforced when the server is acting as a supplier and
 
94
 * when it is acting as a consumer
 
95
 * 
 
96
 * Base policy:
 
97
 *      Supplier: before pushing the schema, the supplier checks that each objectclass/attribute of
 
98
 *              the consumer schema is a subset of the objectclass/attribute of the supplier schema
 
99
 *      Consumer: before accepting a schema (from replication), the consumer checks that 
 
100
 *              each objectclass/attribute of the consumer schema is a subset of the objectclass/attribute 
 
101
 *              of the supplier schema
 
102
 * Extended policies:
 
103
 *      They are stored in repl_schema_policy_t and specifies an "action" to be taken
 
104
 *      for specific objectclass/attribute.
 
105
 *      Supplier: extended policies are stored in entry "cn=supplierUpdatePolicy,cn=replSchema,cn=config"
 
106
 *              and uploaded in static variable: supplier_policy
 
107
 *              Before pushing the schema, for each objectclass/attribute defined in supplier_policy:
 
108
 *                      if its "action" is REPL_SCHEMA_UPDATE_ACCEPT_VALUE, it is not checked that the 
 
109
 *                      attribute/objectclass of the consumer is a subset of the attribute/objectclass 
 
110
 *                      of the supplier schema.
 
111
 * 
 
112
 *                      if its "action" is REPL_SCHEMA_UPDATE_REJECT_VALUE and the consumer schema contains
 
113
 *                      attribute/objectclass, then schema is not pushed
 
114
 * 
 
115
 *      Consumer: extended policies are stored in entry "cn=consumerUpdatePolicy,cn=replSchema,cn=config"
 
116
 *              and uploaded in static variable: consumer_policy
 
117
 *              before accepting a schema (from replication), for each objectclass/attribute defined in
 
118
 *              consumer_policy:
 
119
 *                      if its "action" is REPL_SCHEMA_UPDATE_ACCEPT_VALUE, it is not checked that the 
 
120
 *                      attribute/objectclass of the consumer is a subset of the attribute/objectclass 
 
121
 *                      of the supplier schema.
 
122
 * 
 
123
 *                      if its "action" is REPL_SCHEMA_UPDATE_REJECT_VALUE and the consumer schema contains
 
124
 *                      attribute/objectclass, then schema is not accepted
 
125
 * 
 
126
 */
 
127
 
 
128
typedef struct schema_item {
 
129
        int action; /* REPL_SCHEMA_UPDATE_ACCEPT_VALUE or REPL_SCHEMA_UPDATE_REJECT_VALUE */
 
130
        char *name_or_oid;
 
131
        struct schema_item *next;
 
132
} schema_item_t;
 
133
 
 
134
typedef struct repl_schema_policy {
 
135
        schema_item_t *objectclasses;
 
136
        schema_item_t *attributes;
 
137
} repl_schema_policy_t;
 
138
 
 
139
struct schema_mods_indexes {
 
140
        int index;
 
141
        char *new_value;
 
142
        struct schema_mods_indexes *next;
 
143
};
 
144
 
89
145
/*
90
146
 * pschemadse is based on the general implementation in dse
91
147
 */
145
201
#else
146
202
        ;
147
203
#endif
 
204
static PRBool check_replicated_schema(LDAPMod **mods, char *replica_role, char **attr_name);
 
205
static void modify_schema_get_new_definitions(Slapi_PBlock *pb, LDAPMod **mods, struct schema_mods_indexes **at_list, struct schema_mods_indexes **oc_list);
 
206
static void modify_schema_apply_new_definitions(char *attr_name, struct schema_mods_indexes *list);
 
207
static void modify_schema_free_new_definitions(struct schema_mods_indexes *def_list);
 
208
static int schema_oc_compare(struct objclass *oc_1, struct objclass *oc_2, const char *description);
 
209
static int schema_at_compare(struct asyntaxinfo *at_1, struct asyntaxinfo *at_2, char *message, int debug_logging);
 
210
static int schema_at_superset_check(struct asyntaxinfo *at_list1, struct asyntaxinfo *at_list2, char *message, int replica_role);
 
211
static int schema_at_superset_check_syntax_oids(char *oid1, char *oid2);
 
212
static int schema_at_superset_check_mr(struct asyntaxinfo *a1, struct asyntaxinfo *a2, char *info);
148
213
static int parse_at_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf, size_t errorbufsize,
149
214
        PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, int is_remote);
150
215
static int extension_is_user_defined( schemaext *extensions );
197
262
static const char *schema_errprefix_at = "attribute type %s: ";
198
263
static const char *schema_errprefix_generic = "%s: ";
199
264
 
 
265
/* Defined the policies for the replication of the schema */
 
266
static repl_schema_policy_t supplier_policy = {0};
 
267
static repl_schema_policy_t consumer_policy = {0};
 
268
static Slapi_RWLock *schema_policy_lock = NULL;
 
269
static int  schema_check_policy(int replica_role, int schema_item, char *name, char *oid);
 
270
static void schema_load_repl_policy(const char *dn, repl_schema_policy_t *replica);
 
271
 
200
272
 
201
273
/*
202
274
 * A "cached" copy of the "ignore trailing spaces" config. setting.
253
325
}
254
326
 
255
327
 
 
328
void
 
329
slapi_schema_get_repl_entries(char **repl_schema_top, char ** repl_schema_supplier, char **repl_schema_consumer, char **default_supplier_policy, char **default_consumer_policy)
 
330
{
 
331
        *repl_schema_top      = ENTRY_REPL_SCHEMA_TOP;
 
332
        *repl_schema_supplier = ENTRY_REPL_SCHEMA_SUPPLIER;
 
333
        *repl_schema_consumer = ENTRY_REPL_SCHEMA_CONSUMER;
 
334
        *default_supplier_policy = DEFAULT_SUPPLIER_POLICY;
 
335
        *default_consumer_policy = DEFAULT_CONSUMER_POLICY;
 
336
}
 
337
 
 
338
/* It gets the attributes (see attrName)values in the entry, and add
 
339
 * the policies in the provided list
 
340
 * 
 
341
 * Entry: Slapi_entry with DN being ENTRY_REPL_SCHEMA_SUPPLIER or ENTRY_REPL_SCHEMA_CONSUMER
 
342
 * attrName: name defining the policy object (objectclass/attribute) and the action
 
343
 *         ATTR_SCHEMA_UPDATE_OBJECTCLASS_ACCEPT
 
344
 *         ATTR_SCHEMA_UPDATE_OBJECTCLASS_REJECT
 
345
 *         ATTR_SCHEMA_UPDATE_ATTRIBUTE_ACCEPT
 
346
 *         ATTR_SCHEMA_UPDATE_ATTRIBUTE_REJECT
 
347
 * *list: is the list of schema_item_t containing the policies (it can be list of objectclasses or attributes)
 
348
 * 
 
349
 */
 
350
static
 
351
void schema_policy_add_action(Slapi_Entry *entry, char *attrName, schema_item_t **list) 
 
352
{
 
353
        Slapi_Attr  *attr  = NULL;
 
354
        schema_item_t *schema_item;
 
355
        char *value;
 
356
        int action;
 
357
        
 
358
        /* Retrieve the expected action from the attribute name */
 
359
        if ((strcasecmp(attrName, ATTR_SCHEMA_UPDATE_OBJECTCLASS_ACCEPT) == 0) ||
 
360
                (strcasecmp(attrName, ATTR_SCHEMA_UPDATE_ATTRIBUTE_ACCEPT) == 0)) {
 
361
                action = REPL_SCHEMA_UPDATE_ACCEPT_VALUE;
 
362
        } else {
 
363
                action = REPL_SCHEMA_UPDATE_REJECT_VALUE;
 
364
        }
 
365
        
 
366
        /* Retrieve the given attribute from the entry */
 
367
        slapi_entry_attr_find(entry, attrName, &attr);
 
368
        if (attr != NULL) {
 
369
                Slapi_Value *sval = NULL;
 
370
                const struct berval *attrVal = NULL;
 
371
                int k = slapi_attr_first_value(attr, &sval);
 
372
                
 
373
                /* For each value adds the policy in the list */
 
374
                while (k != -1) {
 
375
                        attrVal = slapi_value_get_berval(sval);
 
376
                        
 
377
                        schema_item = (schema_item_t *) slapi_ch_calloc(1, sizeof(schema_item_t));
 
378
 
 
379
                        /* Get the schema name_or_oid */
 
380
                        value = (char *) slapi_ch_malloc(attrVal->bv_len + 1);
 
381
                        memcpy(value, attrVal->bv_val, attrVal->bv_len);
 
382
                        value[attrVal->bv_len] = '\0';
 
383
                        schema_item->name_or_oid = value;
 
384
 
 
385
                        /* Set the action on that item */
 
386
                        schema_item->action = action;
 
387
 
 
388
                        /* Add it on the head of the list */
 
389
                        schema_item->next = *list;
 
390
                        *list = schema_item;
 
391
                        
 
392
                        /* Get the next name_or_oid */
 
393
                        k = slapi_attr_next_value(attr, k, &sval);
 
394
                }
 
395
        }
 
396
}
 
397
 
 
398
/* Caller must hold schema_policy_lock in write */
 
399
static void
 
400
schema_load_repl_policy(const char *dn, repl_schema_policy_t *replica)
 
401
{
 
402
        Slapi_DN sdn;
 
403
        Slapi_Entry *entry = NULL;
 
404
        schema_item_t *schema_item, *next;
 
405
        
 
406
        if (replica == NULL) {
 
407
                return;
 
408
        }
 
409
        
 
410
        /* Start to free the previous policy */
 
411
        /* first the objectclasses policies */
 
412
        for (schema_item = replica->objectclasses; schema_item; ) {
 
413
                slapi_ch_free((void **) &schema_item->name_or_oid);
 
414
                next = schema_item->next;
 
415
                slapi_ch_free((void **) &schema_item);
 
416
                schema_item = next;
 
417
        }
 
418
        replica->objectclasses = NULL;
 
419
        /* second the attributes policies */
 
420
        for (schema_item = replica->attributes; schema_item; ) {
 
421
                slapi_ch_free((void **) &schema_item->name_or_oid);
 
422
                next = schema_item->next;
 
423
                slapi_ch_free((void **) &schema_item);
 
424
                schema_item = next;
 
425
        }
 
426
        replica->attributes = NULL;
 
427
 
 
428
        /* Load the replication policy of the schema  */
 
429
        slapi_sdn_init_dn_byref( &sdn, dn );
 
430
        if (slapi_search_internal_get_entry(&sdn, NULL, &entry, plugin_get_default_component_id()) == LDAP_SUCCESS) {
 
431
                
 
432
                /* fill the policies (accept/reject) regarding objectclass */
 
433
                schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_OBJECTCLASS_ACCEPT, &replica->objectclasses);
 
434
                schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_OBJECTCLASS_REJECT, &replica->objectclasses);
 
435
                
 
436
                /* fill the policies (accept/reject) regarding attribute */
 
437
                schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_ATTRIBUTE_ACCEPT, &replica->attributes);
 
438
                schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_ATTRIBUTE_REJECT, &replica->attributes);
 
439
               
 
440
                slapi_entry_free( entry );
 
441
        }
 
442
        slapi_sdn_done(&sdn);
 
443
}
 
444
 
 
445
/* It load the policies (if they are defined) regarding the replication of the schema
 
446
 * depending if the instance behaves as a consumer or a supplier
 
447
 * It returns 0 if success
 
448
 */
 
449
int
 
450
slapi_schema_load_repl_policies() 
 
451
{
 
452
        if (schema_policy_lock == NULL) {
 
453
                if (NULL == (schema_policy_lock = slapi_new_rwlock())) {
 
454
                        slapi_log_error(SLAPI_LOG_FATAL, "slapi_schema_load_repl_policies",
 
455
                                "slapi_new_rwlock() for schema replication policy lock failed\n");
 
456
                        return -1;
 
457
                }
 
458
        }
 
459
        slapi_rwlock_wrlock( schema_policy_lock );
 
460
        
 
461
        schema_load_repl_policy((const char *) ENTRY_REPL_SCHEMA_SUPPLIER, &supplier_policy);
 
462
        schema_load_repl_policy((const char *) ENTRY_REPL_SCHEMA_CONSUMER, &consumer_policy);
 
463
        
 
464
        slapi_rwlock_unlock( schema_policy_lock );
 
465
        
 
466
        return 0;
 
467
}
 
468
 
 
469
/*  
 
470
 * It checks if the name/oid of the provided schema item (objectclass/attribute)  
 
471
 * is defined in the schema replication policy.
 
472
 * If the replica role is a supplier, it takes the policy from supplier_policy else
 
473
 * it takes it from the consumer_policy.
 
474
 * Then depending on the schema_item, it takes the objectclasses or attributes policies
 
475
 *   
 
476
 * If it find the name/oid in the policies, it returns
 
477
 *      REPL_SCHEMA_UPDATE_ACCEPT_VALUE: This schema item is accepted and can not prevent schema update
 
478
 *      REPL_SCHEMA_UPDATE_REJECT_VALUE: This schema item is rejected and prevents the schema update
 
479
 *      REPL_SCHEMA_UPDATE_UNKNOWN_VALUE: This schema item as no defined policy
 
480
 * 
 
481
 * Caller must hold schema_policy_lock in read
 
482
 */  
 
483
static int  
 
484
schema_check_policy(int replica_role, int schema_item, char *name, char *oid)  
 
485
{   
 
486
        repl_schema_policy_t *repl_policy;
 
487
        schema_item_t *policy;
 
488
        
 
489
        /* depending on the role, we take the supplier or the consumer policy */
 
490
        if (replica_role == REPL_SCHEMA_AS_SUPPLIER) {
 
491
                repl_policy = &supplier_policy;
 
492
        } else {
 
493
                repl_policy = &consumer_policy;
 
494
        }
 
495
        
 
496
        /* Now take the correct schema item policy */
 
497
        if (schema_item == REPL_SCHEMA_OBJECTCLASS) {
 
498
                policy = repl_policy->objectclasses;
 
499
        } else {
 
500
                policy = repl_policy->attributes;
 
501
        }
 
502
        
 
503
        /* Try to find the name/oid in the defined policies */
 
504
        while (policy) {
 
505
                if ((strcasecmp( name, policy->name_or_oid) == 0) || (strcasecmp( oid, policy->name_or_oid) == 0)) {
 
506
                        return policy->action;                       
 
507
                }
 
508
                policy = policy->next;
 
509
        }
 
510
        return REPL_SCHEMA_UPDATE_UNKNOWN_VALUE;
 
511
}  
 
512
 
256
513
static void
257
514
schema_dse_lock_read( void )
258
515
{
1417
1674
                if (asip->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD ) {
1418
1675
                        outp += strcpy_count( outp, 1 + schema_nousermod_with_spaces );
1419
1676
                }
1420
 
                if (asip->asi_flags & SLAPI_ATTR_FLAG_OPATTR) {
 
1677
                if (asip->asi_flags & SLAPI_ATTR_FLAG_DISTRIBUTED_OPERATION) {
 
1678
                        outp += strcpy_count(outp, "USAGE distributedOperation ");
 
1679
                } else if (asip->asi_flags & SLAPI_ATTR_FLAG_DSA_OPERATION) {
 
1680
                        outp += strcpy_count(outp, "USAGE dSAOperation ");
 
1681
                } else if (asip->asi_flags & SLAPI_ATTR_FLAG_OPATTR) {
1421
1682
                        outp += strcpy_count(outp, "USAGE directoryOperation ");
1422
1683
                }
1423
1684
 
1815
2076
 
1816
2077
  slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
1817
2078
  slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
 
2079
 
 
2080
  /* In case we receive a schema from a supplier, check if we can accept it
 
2081
   * (it is a superset of our own schema).
 
2082
   * If it is not a superset, pick up what could extend our schema and return
 
2083
   */
 
2084
  if (is_replicated_operation) {
 
2085
          char *attr_name = NULL;
 
2086
          struct schema_mods_indexes *at_list = NULL;
 
2087
          struct schema_mods_indexes *oc_list = NULL;
 
2088
 
 
2089
          if (!check_replicated_schema(mods, OC_CONSUMER, &attr_name)) {
 
2090
 
 
2091
                  /* we will refuse to apply this schema 
 
2092
                   * Try to capture in it what would extends our own schema
 
2093
                   */
 
2094
                  modify_schema_get_new_definitions(pb, mods, &at_list, &oc_list);
 
2095
                  if (at_list) {
 
2096
                          modify_schema_apply_new_definitions("attributetypes", at_list);
 
2097
                  }
 
2098
                  if (oc_list) {
 
2099
                          modify_schema_apply_new_definitions("objectclasses", oc_list);
 
2100
                  }
 
2101
                  
 
2102
                  /* No need to hold the lock for these list that are local */
 
2103
                  modify_schema_free_new_definitions(at_list);
 
2104
                  modify_schema_free_new_definitions(oc_list);
 
2105
                  
 
2106
                  /* now return, we will not apply that schema */
 
2107
                  schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
 
2108
                                          schema_errprefix_generic, attr_name,
 
2109
                                          "Replace is not possible, local consumer schema is a superset of the supplier" );
 
2110
                  slapi_log_error(SLAPI_LOG_FATAL, "schema",
 
2111
                                          "[C] Local %s must not be overwritten (set replication log for additional info)\n",
 
2112
                                          attr_name);
 
2113
                  *returncode = LDAP_UNWILLING_TO_PERFORM;
 
2114
                  return (SLAPI_DSE_CALLBACK_ERROR);
 
2115
          }
 
2116
  }
 
2117
  
 
2118
  
1818
2119
  schema_dse_lock_write();
1819
2120
 
1820
2121
  /*
1825
2126
   * True for DS 4.x as well, although it tried to keep going even after
1826
2127
   * an error was detected (which was very wrong).
1827
2128
   */
1828
 
  for (i = 0; rc == SLAPI_DSE_CALLBACK_OK && mods[i]; i++) {
 
2129
  for (i = 0; rc == SLAPI_DSE_CALLBACK_OK && mods && mods[i]; i++) {
1829
2130
        schema_dse_attr_name  = (char *) mods[i]->mod_type;
1830
2131
        num_mods++; /* incr the number of mods */
1831
2132
 
1888
2189
                                        "Replace is not allowed on the subschema subentry" );
1889
2190
                  rc = SLAPI_DSE_CALLBACK_ERROR;
1890
2191
          } else {
1891
 
                  if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
1892
 
                        /* 
1893
 
                         * Replace all attribute types
1894
 
                         */
1895
 
                        *returncode = schema_replace_attributes( pb, mods[i], returntext,
1896
 
                                        SLAPI_DSE_RETURNTEXT_SIZE );
 
2192
                  if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {                    
 
2193
                              /*
 
2194
                               * Replace all attributetypes
 
2195
                               * It has already been checked that if it was a replicated schema
 
2196
                               * it is a superset of the current schema. That is fine to apply the mods
 
2197
                               */
 
2198
                              *returncode = schema_replace_attributes( pb, mods[i], returntext,
 
2199
                                          SLAPI_DSE_RETURNTEXT_SIZE );
1897
2200
                  } else if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
1898
 
                          
1899
 
                          if (is_replicated_operation) {
1900
 
                                  /* before accepting the schema checks if the local consumer schema is not
1901
 
                                   * a superset of the supplier schema
1902
 
                                   */
1903
 
                                  if (schema_objectclasses_superset_check(mods[i]->mod_bvalues, OC_CONSUMER)) {
1904
 
                                          
1905
 
                                          schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
1906
 
                                                  schema_errprefix_generic, mods[i]->mod_type,
1907
 
                                                  "Replace is not possible, local consumer schema is a superset of the supplier" );
1908
 
                                          slapi_log_error(SLAPI_LOG_FATAL, "schema",
1909
 
                                                  "Local %s must not be overwritten (set replication log for additional info)\n",
1910
 
                                                  mods[i]->mod_type);
1911
 
                                          *returncode = LDAP_UNWILLING_TO_PERFORM;
1912
 
                                  } else {
1913
 
                                          /*
1914
 
                                           * Replace all objectclasses
1915
 
                                           */
1916
 
                                          *returncode = schema_replace_objectclasses(pb, mods[i],
1917
 
                                                  returntext, SLAPI_DSE_RETURNTEXT_SIZE);
1918
 
                                  }                                
1919
 
                         } else {
1920
2201
                                  /*
1921
2202
                                   * Replace all objectclasses
 
2203
                                   * It has already been checked that if it was a replicated schema
 
2204
                                   * it is a superset of the current schema. That is fine to apply the mods
1922
2205
                                   */
1923
2206
                                  *returncode = schema_replace_objectclasses(pb, mods[i],
1924
2207
                                                  returntext, SLAPI_DSE_RETURNTEXT_SIZE);                                 
1925
 
                         }
 
2208
                         
1926
2209
                  } else if (strcasecmp (mods[i]->mod_type, "nsschemacsn") == 0) {
1927
2210
                        if (is_replicated_operation) {
1928
2211
                                /* Update the schema CSN */
3527
3810
                    strlen("directoryOperation"))) {
3528
3811
                flags |= SLAPI_ATTR_FLAG_OPATTR;
3529
3812
            }
 
3813
            if ( !PL_strncmp(ss, "distributedOperation",
 
3814
                    strlen("distributedOperation"))) {
 
3815
                flags |= SLAPI_ATTR_FLAG_OPATTR|SLAPI_ATTR_FLAG_DISTRIBUTED_OPERATION;
 
3816
            }
 
3817
            if ( !PL_strncmp(ss, "dSAOperation",
 
3818
                    strlen("dSAOperation"))) {
 
3819
                flags |= SLAPI_ATTR_FLAG_OPATTR|SLAPI_ATTR_FLAG_DSA_OPERATION;
 
3820
            }
3530
3821
            if ( NULL == ( nextinput = strchr( ss, ' ' ))) {
3531
3822
                nextinput = ss + strlen(ss);
3532
3823
            }
3861
4152
    if(atype->at_usage == LDAP_SCHEMA_DIRECTORY_OPERATION){
3862
4153
        flags |= SLAPI_ATTR_FLAG_OPATTR;
3863
4154
    }
 
4155
    if(atype->at_usage == LDAP_SCHEMA_DISTRIBUTED_OPERATION){
 
4156
        flags |= SLAPI_ATTR_FLAG_OPATTR|SLAPI_ATTR_FLAG_DISTRIBUTED_OPERATION;
 
4157
    }
 
4158
    if(atype->at_usage == LDAP_SCHEMA_DSA_OPERATION){
 
4159
        flags |= SLAPI_ATTR_FLAG_OPATTR|SLAPI_ATTR_FLAG_DSA_OPERATION;
 
4160
    }
3864
4161
    /*
3865
4162
     * Check the superior, and use it fill in any missing oids on this attribute
3866
4163
     */
5856
6153
        return superior;
5857
6154
}
5858
6155
 
5859
 
 
5860
 
 
5861
6156
/* Check if the oc_list1 is a superset of oc_list2.
5862
6157
 * oc_list1 is a superset if it exists objectclass in oc_list1 that
5863
6158
 * do not exist in oc_list2. Or if a OC in oc_list1 required more attributes
5869
6164
 * If oc_list1 or oc_list2 is global_oc, the caller must hold the oc_lock 
5870
6165
 */
5871
6166
static int
5872
 
schema_oc_superset_check(struct objclass *oc_list1, struct objclass *oc_list2, char *message) {
 
6167
schema_oc_superset_check(struct objclass *oc_list1, struct objclass *oc_list2, char *message, int replica_role) {
5873
6168
        struct objclass *oc_1, *oc_2;
5874
 
        char *description;
5875
 
        int rc, i, j;
5876
 
        int found;
 
6169
        const char *description;
 
6170
        int debug_logging = 0;
 
6171
        int rc;
 
6172
        int repl_schema_policy;
5877
6173
 
5878
6174
        if (message == NULL) {
5879
 
                description = "";
 
6175
                description = (const char *) "";
5880
6176
        } else {
5881
 
                description = message;
 
6177
                description = (const char *) message;
5882
6178
        }
5883
6179
        
5884
6180
        /* by default assum oc_list1 == oc_list2 */
5885
6181
        rc = 0;
5886
6182
 
 
6183
        /* Are we doing replication logging */
 
6184
        if(slapi_is_loglevel_set(SLAPI_LOG_REPL)){
 
6185
                debug_logging = 1;
 
6186
        }
 
6187
 
5887
6188
        /* Check if all objectclass in oc_list1
5888
6189
         *   - exists in oc_list2
5889
6190
         *   - required attributes are also required in oc_2
5890
6191
         *   - allowed attributes are also allowed in oc_2
5891
6192
         */
 
6193
        slapi_rwlock_rdlock( schema_policy_lock );
5892
6194
        for (oc_1 = oc_list1; oc_1 != NULL; oc_1 = oc_1->oc_next) {
 
6195
                
5893
6196
 
 
6197
                /* Check if there is a specific policy for that objectclass */
 
6198
                repl_schema_policy = schema_check_policy(replica_role, REPL_SCHEMA_OBJECTCLASS, oc_1->oc_name, oc_1->oc_oid);
 
6199
                if (repl_schema_policy == REPL_SCHEMA_UPDATE_ACCEPT_VALUE) {
 
6200
                        /* We are skipping the superset checking for that objectclass */
 
6201
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Do not check if this OBJECTCLASS is missing on local/remote schema [%s or %s]\n", oc_1->oc_name, oc_1->oc_oid);
 
6202
                        continue;
 
6203
                } else if (repl_schema_policy == REPL_SCHEMA_UPDATE_REJECT_VALUE) {
 
6204
                        /* This objectclass being present, we need to fail as if it was a superset 
 
6205
                         * keep evaluating to have all the objectclass checking
 
6206
                         */
 
6207
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "%s objectclass prevents replication of the schema\n", oc_1->oc_name);
 
6208
                        rc = 1;
 
6209
                        if(debug_logging){
 
6210
                            /* we continue to check all the objectclasses so we log what is wrong */
 
6211
                            continue;
 
6212
                        } else {
 
6213
                            break;
 
6214
                        }
 
6215
                }
 
6216
                
5894
6217
                /* Retrieve the remote objectclass in our local schema */
5895
6218
                oc_2 = oc_find_nolock(oc_1->oc_oid, oc_list2, PR_TRUE);
5896
6219
                if (oc_2 == NULL) {
5897
6220
                        /* try to retrieve it with the name*/
5898
6221
                        oc_2 = oc_find_nolock(oc_1->oc_name, oc_list2, PR_TRUE);
5899
6222
                }
5900
 
                if (oc_2 == NULL) {
 
6223
                if (oc_2) {
 
6224
                        if (schema_oc_compare(oc_1, oc_2, description) > 0) {
 
6225
                                rc = 1;
 
6226
                                if (debug_logging) {
 
6227
                                        if (replica_role == REPL_SCHEMA_AS_CONSUMER) {
 
6228
                                                slapi_log_error(SLAPI_LOG_REPL, "schema", "Local %s schema objectclasses is a superset of"
 
6229
                                                        " the received one.\n", oc_1->oc_name);
 
6230
                                        } else {
 
6231
                                                slapi_log_error(SLAPI_LOG_REPL, "schema", "Remote %s schema objectclasses is a superset of"
 
6232
                                                        " the received one.\n", oc_1->oc_name);
 
6233
                                        }
 
6234
                                        continue;
 
6235
                                } else {
 
6236
                                        break;
 
6237
                                }
 
6238
                        }                 
 
6239
                } else {
5901
6240
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Fail to retrieve in the %s schema [%s or %s]\n", 
5902
6241
                                description,
5903
6242
                                oc_1->oc_name, 
5904
6243
                                oc_1->oc_oid);
5905
 
 
 
6244
                        
5906
6245
                        /* The oc_1 objectclasses is supperset */
5907
6246
                        rc = 1;
5908
 
 
5909
 
                        continue; /* we continue to check all the objectclass */
5910
 
                }
5911
 
 
5912
 
                /* First check the MUST */
5913
 
                if (oc_1->oc_orig_required) {
5914
 
                        for (i = 0; oc_1->oc_orig_required[i] != NULL; i++) {
5915
 
                                /* For each required attribute from the remote schema check that 
5916
 
                                 * it is also required in the local schema
5917
 
                                 */
5918
 
                                found = 0;
5919
 
                                if (oc_2->oc_orig_required) {
5920
 
                                        for (j = 0; oc_2->oc_orig_required[j] != NULL; j++) {
5921
 
                                                if (strcasecmp(oc_2->oc_orig_required[j], oc_1->oc_orig_required[i]) == 0) {
5922
 
                                                        found = 1;
5923
 
                                                        break;
5924
 
                                                }
 
6247
                        if(debug_logging){
 
6248
                            /* we continue to check all the objectclasses so we log what is wrong */
 
6249
                            continue;
 
6250
                        } else {
 
6251
                            break;
 
6252
                        }
 
6253
                }
 
6254
        }
 
6255
        slapi_rwlock_unlock( schema_policy_lock );
 
6256
        
 
6257
        return rc;
 
6258
}
 
6259
/* call must hold oc_lock at least in read */
 
6260
static struct schema_mods_indexes *
 
6261
schema_list_oc2learn(struct objclass *oc_remote_list, struct objclass *oc_local_list, int replica_role) {
 
6262
        struct objclass *oc_remote, *oc_local;
 
6263
        struct schema_mods_indexes *head = NULL, *mods_index;
 
6264
        int index = 0;
 
6265
        int repl_schema_policy;
 
6266
        const char *message;
 
6267
        
 
6268
        if (replica_role == REPL_SCHEMA_AS_SUPPLIER) {
 
6269
                message = (const char *) "remote consumer";
 
6270
        } else {
 
6271
                message = (const char *) "remote supplier";
 
6272
        }
 
6273
 
 
6274
        slapi_rwlock_rdlock( schema_policy_lock );        
 
6275
        for (oc_remote = oc_remote_list; oc_remote != NULL; oc_remote = oc_remote->oc_next, index++) {
 
6276
                
 
6277
                /* If this objectclass is not checked (accept) or rejects schema update */
 
6278
                repl_schema_policy = schema_check_policy(replica_role, REPL_SCHEMA_OBJECTCLASS, oc_remote->oc_name, oc_remote->oc_oid);
 
6279
                if ((repl_schema_policy == REPL_SCHEMA_UPDATE_ACCEPT_VALUE) || (repl_schema_policy == REPL_SCHEMA_UPDATE_REJECT_VALUE)) {
 
6280
                        continue;
 
6281
                }
 
6282
        
 
6283
 
 
6284
                oc_local = oc_find_nolock(oc_remote->oc_oid, oc_local_list, PR_TRUE);
 
6285
                if (oc_local == NULL) {
 
6286
                        /* try to retrieve it with the name*/
 
6287
                        oc_local = oc_find_nolock(oc_remote->oc_name, oc_local_list, PR_TRUE);
 
6288
                }
 
6289
                if ((oc_local == NULL) ||
 
6290
                        (schema_oc_compare(oc_local, oc_remote, message) < 0)) {
 
6291
                        /* This replica does not know this objectclass, It needs to be added */
 
6292
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Add that unknown/extended objectclass %s (%s)\n",
 
6293
                                oc_remote->oc_name,
 
6294
                                oc_remote->oc_oid);
 
6295
 
 
6296
                        if ((mods_index = (struct schema_mods_indexes *) slapi_ch_calloc(1, sizeof (struct schema_mods_indexes))) == NULL) {
 
6297
                                slapi_log_error(SLAPI_LOG_FATAL, "schema", "Fail to Add (no memory) objectclass %s (%s)\n",
 
6298
                                        oc_remote->oc_name,
 
6299
                                        oc_remote->oc_oid);
 
6300
                                continue;
 
6301
                        }
 
6302
                        
 
6303
                        /* insert it in the list */
 
6304
                        mods_index->index     = index;
 
6305
                        mods_index->next      = head;
 
6306
                        mods_index->new_value = NULL;
 
6307
                        head                  = mods_index;
 
6308
                }
 
6309
        }
 
6310
        slapi_rwlock_unlock( schema_policy_lock );
 
6311
        return head;
 
6312
}
 
6313
static struct schema_mods_indexes *
 
6314
schema_list_attr2learn(struct asyntaxinfo *at_list_local, struct asyntaxinfo *at_list_remote, int replica_role)
 
6315
{
 
6316
        struct asyntaxinfo *at_remote, *at_local;
 
6317
        struct schema_mods_indexes *head = NULL, *mods_index;
 
6318
        int index = 0;
 
6319
        int repl_schema_policy;
 
6320
        int debug_logging = 0;
 
6321
        char *message;
 
6322
 
 
6323
        if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
 
6324
                debug_logging = 1;
 
6325
        }
 
6326
        
 
6327
        if (replica_role == REPL_SCHEMA_AS_SUPPLIER) {
 
6328
                message = "remote consumer";
 
6329
        } else {
 
6330
                message = "remote supplier";
 
6331
        }
 
6332
 
 
6333
        slapi_rwlock_rdlock(schema_policy_lock);
 
6334
        for (at_remote = at_list_remote; at_remote != NULL; at_remote = at_remote->asi_next, index++) {
 
6335
                /* If this objectclass is not checked (accept) or rejects schema update */
 
6336
                repl_schema_policy = schema_check_policy(replica_role, REPL_SCHEMA_ATTRIBUTE, at_remote->asi_name, at_remote->asi_oid);;
 
6337
                if ((repl_schema_policy == REPL_SCHEMA_UPDATE_ACCEPT_VALUE) || (repl_schema_policy == REPL_SCHEMA_UPDATE_REJECT_VALUE)) {
 
6338
                        continue;
 
6339
                }
 
6340
                
 
6341
                if (((at_local = attr_syntax_find(at_remote, at_list_local)) == NULL) || 
 
6342
                        (schema_at_compare(at_local, at_remote, message, debug_logging) < 0)) {
 
6343
                        /* This replica does not know this attribute, It needs to be added */
 
6344
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Add that unknown/extended attribute %s (%s)\n",
 
6345
                                at_remote->asi_name,
 
6346
                                at_remote->asi_oid);
 
6347
 
 
6348
                        if ((mods_index = (struct schema_mods_indexes *) slapi_ch_calloc(1, sizeof (struct schema_mods_indexes))) == NULL) {
 
6349
                                slapi_log_error(SLAPI_LOG_FATAL, "schema", "Fail to Add (no memory) attribute %s (%s)\n",
 
6350
                                        at_remote->asi_name,
 
6351
                                        at_remote->asi_oid);
 
6352
                                continue;
 
6353
                        }
 
6354
                        
 
6355
                        /* insert it in the list */
 
6356
                        mods_index->index     = index;
 
6357
                        mods_index->next      = head;
 
6358
                        mods_index->new_value = NULL;
 
6359
                        head                  = mods_index;
 
6360
                        
 
6361
                }                       
 
6362
        }
 
6363
        slapi_rwlock_unlock(schema_policy_lock);
 
6364
        return head;
 
6365
}
 
6366
 
 
6367
/* If oc_1 > oc2  returns 1
 
6368
 * else it returns 0
 
6369
 */
 
6370
static PRBool
 
6371
schema_oc_compare_strict(struct objclass *oc_1, struct objclass *oc_2, const char *description) 
 
6372
{
 
6373
        int found;
 
6374
        int i,j;
 
6375
        PRBool moved_must_to_may;
 
6376
        
 
6377
        /* safety checking */
 
6378
        if (!oc_1) {
 
6379
                return 0;
 
6380
        } else if (!oc_2) {
 
6381
                return 1;
 
6382
        }
 
6383
       
 
6384
 
 
6385
        /* First check the MUST */
 
6386
        if (oc_1->oc_orig_required) {
 
6387
                for (i = 0; oc_1->oc_orig_required[i] != NULL; i++) {
 
6388
                        /* For each required attribute from oc1 schema check that 
 
6389
                         * it is also required in the oc2 schema
 
6390
                         */
 
6391
                        found = 0;
 
6392
                        if (oc_2->oc_orig_required) {
 
6393
                                for (j = 0; oc_2->oc_orig_required[j] != NULL; j++) {
 
6394
                                        if (strcasecmp(oc_2->oc_orig_required[j], oc_1->oc_orig_required[i]) == 0) {
 
6395
                                                found = 1;
 
6396
                                                break;
5925
6397
                                        }
5926
6398
                                }
5927
 
                                if (!found) {
5928
 
                                        /* The required attribute in the remote protocol (remote_oc->oc_orig_required[i])
5929
 
                                         * is not required in the local protocol
5930
 
                                         */
5931
 
                                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Attribute %s is not required in '%s' of the %s schema\n",
5932
 
                                                oc_1->oc_orig_required[i],
5933
 
                                                oc_1->oc_name,
5934
 
                                                description);
5935
 
 
5936
 
                                        /* The oc_1 objectclasses is supperset */
5937
 
                                        rc = 1;
5938
 
                                                
5939
 
                                        continue; /* we continue to check all attributes */
5940
 
                                }
5941
6399
                        }
5942
 
                }
5943
 
 
5944
 
                /* Second check the MAY */
5945
 
                if (oc_1->oc_orig_allowed) {
5946
 
                        for (i = 0; oc_1->oc_orig_allowed[i] != NULL; i++) {
5947
 
                                /* For each required attribute from the remote schema check that 
5948
 
                                 * it is also required in the local schema
 
6400
                        if (!found) {
 
6401
                                /* Before stating that oc1 is a superset of oc2, we need to verify that the 'required'
 
6402
                                 * attribute (from oc1) is missing in 'required' oc2 because it is 
 
6403
                                 * now 'allowed' in oc2
5949
6404
                                 */
5950
 
                                found = 0;
 
6405
                                moved_must_to_may = PR_FALSE;
5951
6406
                                if (oc_2->oc_orig_allowed) {
5952
6407
                                        for (j = 0; oc_2->oc_orig_allowed[j] != NULL; j++) {
5953
 
                                                if (strcasecmp(oc_2->oc_orig_allowed[j], oc_1->oc_orig_allowed[i]) == 0) {
5954
 
                                                        found = 1;
 
6408
                                                if (strcasecmp(oc_2->oc_orig_allowed[j], oc_1->oc_orig_required[i]) == 0) {
 
6409
                                                        moved_must_to_may = PR_TRUE;
5955
6410
                                                        break;
5956
6411
                                                }
5957
6412
                                        }
5958
6413
                                }
5959
 
                                if (!found) {
5960
 
                                        /* The required attribute in the remote protocol (remote_oc->oc_orig_allowed[i])
5961
 
                                         * is not required in the local protocol
 
6414
 
 
6415
                                if (moved_must_to_may) {
 
6416
                                        /* This is a special case where oc1 is actually NOT a superset of oc2 */
 
6417
                                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Attribute %s is no longer 'required' in '%s' of the %s schema but is now 'allowed'\n",
 
6418
                                                oc_1->oc_orig_required[i],
 
6419
                                                oc_1->oc_name,
 
6420
                                                description);
 
6421
                                } else {
 
6422
                                        /* The required attribute in the oc1 
 
6423
                                         * is not required in the oc2
5962
6424
                                         */
5963
 
                                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Attribute %s is not allowed in '%s' of the %s schema\n",
5964
 
                                                oc_1->oc_orig_allowed[i],
 
6425
                                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Attribute %s is not required in '%s' of the %s schema\n",
 
6426
                                                oc_1->oc_orig_required[i],
5965
6427
                                                oc_1->oc_name,
5966
6428
                                                description);
5967
6429
 
5968
6430
                                        /* The oc_1 objectclasses is supperset */
5969
 
                                        rc = 1;
5970
 
                                        
5971
 
                                        continue; /* we continue to check all attributes */
5972
 
                                }
5973
 
                        }
5974
 
                }
5975
 
        }
5976
 
        
5977
 
        return rc;
 
6431
                                        return 1;
 
6432
                                }
 
6433
                        }
 
6434
                }
 
6435
        }
 
6436
 
 
6437
        /* Second check the MAY */
 
6438
        if (oc_1->oc_orig_allowed) {
 
6439
                for (i = 0; oc_1->oc_orig_allowed[i] != NULL; i++) {
 
6440
                        /* For each required attribute from the remote schema check that 
 
6441
                         * it is also required in the local schema
 
6442
                         */
 
6443
                        found = 0;
 
6444
                        if (oc_2->oc_orig_allowed) {
 
6445
                                for (j = 0; oc_2->oc_orig_allowed[j] != NULL; j++) {
 
6446
                                        if (strcasecmp(oc_2->oc_orig_allowed[j], oc_1->oc_orig_allowed[i]) == 0) {
 
6447
                                                found = 1;
 
6448
                                                break;
 
6449
                                        }
 
6450
                                }
 
6451
                        }
 
6452
                        if (!found) {
 
6453
                                /* The allowed attribute in the remote schema (remote_oc->oc_orig_allowed[i])
 
6454
                                 * is not allowed in the local schema
 
6455
                                 */
 
6456
                                slapi_log_error(SLAPI_LOG_REPL, "schema", "Attribute %s is not allowed in '%s' of the %s schema\n",
 
6457
                                        oc_1->oc_orig_allowed[i],
 
6458
                                        oc_1->oc_name,
 
6459
                                        description);
 
6460
 
 
6461
                                /* The oc_1 objectclasses is superset */
 
6462
                                return 1;
 
6463
                        }
 
6464
                }
 
6465
        }
 
6466
 
 
6467
 
 
6468
        return 0;
 
6469
}
 
6470
 
 
6471
 
 
6472
/* Compare two objectclass definitions
 
6473
 * it compares:
 
6474
 
 
6475
 * It returns:
 
6476
 *   1: if oc_1 is a superset of oc_2
 
6477
 *  -1: if oc_2 is a superset of oc_1
 
6478
 *   0: if oc_1 and at_2 are equivalent
 
6479
 */
 
6480
static int
 
6481
schema_oc_compare(struct objclass *oc_1, struct objclass *oc_2, const char *description) 
 
6482
{
 
6483
        if (schema_oc_compare_strict(oc_1, oc_2, description) > 0) {
 
6484
                return 1;
 
6485
        } else if (schema_oc_compare_strict(oc_2, oc_1, description) > 0) {
 
6486
                return -1;
 
6487
        } else {
 
6488
                return 0;
 
6489
        }
 
6490
}
 
6491
 
 
6492
/* Compare two attributes definitions
 
6493
 * it compares:
 
6494
 *  - single/multi value
 
6495
 *  - syntax
 
6496
 *  - matching rules
 
6497
 * It returns:
 
6498
 *   1: if at_1 is a superset of at_2
 
6499
 *  -1: if at_2 is a superset of at_1
 
6500
 *   0: if at_1 and at_2 are equivalent
 
6501
 */
 
6502
static int
 
6503
schema_at_compare(struct asyntaxinfo *at_1, struct asyntaxinfo *at_2, char *message, int debug_logging) 
 
6504
{
 
6505
        char *info = NULL;
 
6506
        
 
6507
        /* safety checking */
 
6508
        if (! at_1) {
 
6509
                if (!at_2) {
 
6510
                        return 0;
 
6511
                } else {
 
6512
                        return -1;
 
6513
                }
 
6514
        } else if (!at_2) {
 
6515
                return 1;
 
6516
        }
 
6517
 
 
6518
        /*
 
6519
         *  Check for single vs. multi value
 
6520
         */
 
6521
        if (!(at_1->asi_flags & SLAPI_ATTR_FLAG_SINGLE) && (at_2->asi_flags & SLAPI_ATTR_FLAG_SINGLE)) {
 
6522
 
 
6523
                /* at_1 is a superset */
 
6524
                if (debug_logging) {
 
6525
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] is not "
 
6526
                                "\"single-valued\" \n", message, at_1->asi_name);
 
6527
                }
 
6528
                return 1;
 
6529
        }
 
6530
        if ((at_1->asi_flags & SLAPI_ATTR_FLAG_SINGLE) && !(at_2->asi_flags & SLAPI_ATTR_FLAG_SINGLE)) {
 
6531
                /* at_2 is a superset */
 
6532
                if (debug_logging) {
 
6533
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] is not "
 
6534
                                "\"single-valued\" \n", message, at_1->asi_name);
 
6535
                }
 
6536
                return -1;
 
6537
        }
 
6538
 
 
6539
        /*
 
6540
         *  Check the syntaxes
 
6541
         */
 
6542
        if (schema_at_superset_check_syntax_oids(at_1->asi_syntax_oid, at_2->asi_syntax_oid)) {
 
6543
                /* at_1 is a superset */
 
6544
                if (debug_logging) {
 
6545
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] syntax "
 
6546
                                "can not be overwritten\n", message, at_1->asi_name);
 
6547
                }
 
6548
                return 1;
 
6549
        }
 
6550
        if (schema_at_superset_check_syntax_oids(at_2->asi_syntax_oid, at_1->asi_syntax_oid)) {
 
6551
                /* at_2 is a superset */
 
6552
                if (debug_logging) {
 
6553
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] syntax "
 
6554
                                "can not be overwritten\n", message, at_2->asi_name);
 
6555
                }
 
6556
                return -1;
 
6557
        }
 
6558
 
 
6559
        /*
 
6560
         *  Check some matching rules - not finished yet...
 
6561
         *
 
6562
         *  For now, skip the matching rule check (rc is never equal to -1)
 
6563
         */
 
6564
        if (schema_at_superset_check_mr(at_1, at_2, info)) {
 
6565
                if (debug_logging) {
 
6566
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] matching "
 
6567
                                "rule can not be overwritten\n", message, at_1->asi_name);
 
6568
                }
 
6569
                return 1;
 
6570
        }
 
6571
        if (schema_at_superset_check_mr(at_2, at_1, info)) {
 
6572
                if (debug_logging) {
 
6573
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "%s schema attribute [%s] matching "
 
6574
                                "rule can not be overwritten\n", message, at_2->asi_name);
 
6575
                }
 
6576
                return -1;
 
6577
        }
 
6578
 
 
6579
        return 0;
 
6580
}
 
6581
 
 
6582
static int
 
6583
schema_at_superset_check(struct asyntaxinfo *at_list1, struct asyntaxinfo *at_list2, char *message, int replica_role)
 
6584
{
 
6585
    struct asyntaxinfo *at_1, *at_2;
 
6586
    int debug_logging = 0;
 
6587
    int repl_schema_policy;
 
6588
    int rc = 0;
 
6589
 
 
6590
    if(at_list1 == NULL || at_list2 == NULL){
 
6591
        return 0;
 
6592
    }
 
6593
 
 
6594
    /* Are we doing replication logging */
 
6595
    if(slapi_is_loglevel_set(SLAPI_LOG_REPL)){
 
6596
        debug_logging = 1;
 
6597
    }
 
6598
 
 
6599
    slapi_rwlock_rdlock( schema_policy_lock );
 
6600
    for (at_1 = at_list1; at_1 != NULL; at_1 = at_1->asi_next) {
 
6601
 
 
6602
        /* Check if there is a specific policy for that objectclass */
 
6603
        repl_schema_policy = schema_check_policy(replica_role, REPL_SCHEMA_ATTRIBUTE, at_1->asi_name, at_1->asi_oid);
 
6604
        if (repl_schema_policy == REPL_SCHEMA_UPDATE_ACCEPT_VALUE) {
 
6605
                /* We are skipping the superset checking for that attribute */
 
6606
                slapi_log_error(SLAPI_LOG_REPL, "schema", "Do not check if this ATTRIBUTE is missing on local/remote schema [%s or %s]\n", at_1->asi_name, at_1->asi_oid);
 
6607
                continue;
 
6608
        } else if (repl_schema_policy == REPL_SCHEMA_UPDATE_REJECT_VALUE) {
 
6609
                /* This attribute being present, we need to fail as if it was a superset 
 
6610
                 * but keep evaluating to have all the attribute checking
 
6611
                 */
 
6612
                slapi_log_error(SLAPI_LOG_REPL, "schema", "%s attribute prevents replication of the schema\n", at_1->asi_name);
 
6613
                rc = 1;
 
6614
                if (debug_logging) {
 
6615
                        /* we continue to check all the objectclasses so we log what is wrong */
 
6616
                        continue;
 
6617
                } else {
 
6618
                        break;
 
6619
                }
 
6620
        }
 
6621
        
 
6622
        /* check if at_1 exists in at_list2 */
 
6623
        if((at_2 = attr_syntax_find(at_1, at_list2))) {
 
6624
                if (schema_at_compare(at_1, at_2, message, debug_logging) > 0) {
 
6625
                        rc = 1;
 
6626
                        if (debug_logging) {
 
6627
                                if (replica_role == REPL_SCHEMA_AS_CONSUMER) {
 
6628
                                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Local %s schema attributetypes is a superset of"
 
6629
                                                " the received one.\n", at_1->asi_name);
 
6630
                                } else {
 
6631
                                        slapi_log_error(SLAPI_LOG_REPL, "schema", "Remote %s schema attributetypes is a superset of"
 
6632
                                                " the received one.\n", at_1->asi_name);
 
6633
                                }
 
6634
                                continue;
 
6635
                        } else {
 
6636
                                break;
 
6637
                        }
 
6638
                }
 
6639
        } else {
 
6640
            rc = 1;
 
6641
            if(debug_logging){
 
6642
                /* we continue to check all attributes so we log what is wrong */
 
6643
                slapi_log_error(SLAPI_LOG_REPL, "schema", "Fail to retrieve in the %s schema [%s or %s]\n",
 
6644
                            message, at_1->asi_name, at_1->asi_oid);
 
6645
                continue;
 
6646
            } else {
 
6647
                break;
 
6648
            }
 
6649
        }
 
6650
    }
 
6651
    slapi_rwlock_unlock( schema_policy_lock );
 
6652
 
 
6653
 
 
6654
    return rc;
 
6655
}
 
6656
 
 
6657
/*
 
6658
 * Return 1 if a1's matching rules are superset(not to be overwritten).  If just one of
 
6659
 * the matching rules should not be overwritten, even if one should, we can not allow it.
 
6660
 */
 
6661
static int
 
6662
schema_at_superset_check_mr(struct asyntaxinfo *a1, struct asyntaxinfo *a2, char *info)
 
6663
{
 
6664
    char *a1_mrtype[3] = { a1->asi_mr_equality, a1->asi_mr_substring, a1->asi_mr_ordering };
 
6665
    char *a2_mrtype[3] = { a2->asi_mr_equality, a2->asi_mr_substring, a2->asi_mr_ordering };
 
6666
    int rc = 0, i;
 
6667
 
 
6668
    /*
 
6669
     * Loop over the three matching rule types
 
6670
     */
 
6671
    for(i = 0; i < 3; i++){
 
6672
        if(a1_mrtype[i]){
 
6673
            if(a2_mrtype[i]){
 
6674
                /*
 
6675
                 *  Future action item - determine matching rule precedence:
 
6676
                 *
 
6677
                    ces
 
6678
                    "caseExactIA5Match", "1.3.6.1.4.1.1466.109.114.1"
 
6679
                    "caseExactMatch", "2.5.13.5"
 
6680
                    "caseExactOrderingMatch", "2.5.13.6"
 
6681
                    "caseExactSubstringsMatch", "2.5.13.7"
 
6682
                    "caseExactIA5SubstringsMatch", "2.16.840.1.113730.3.3.1"
 
6683
 
 
6684
                    cis
 
6685
                    "generalizedTimeMatch", "2.5.13.27"
 
6686
                    "generalizedTimeOrderingMatch", "2.5.13.28"
 
6687
                    "booleanMatch", "2.5.13.13"
 
6688
                    "caseIgnoreIA5Match", "1.3.6.1.4.1.1466.109.114.2"
 
6689
                    "caseIgnoreIA5SubstringsMatch", "1.3.6.1.4.1.1466.109.114.3"
 
6690
                    "caseIgnoreListMatch", "2.5.13.11"
 
6691
                    "caseIgnoreListSubstringsMatch", "2.5.13.12"
 
6692
                    "caseIgnoreMatch", "2.5.13.2" -------------------------------
 
6693
                    "caseIgnoreOrderingMatch", "2.5.13.3" ----------------------->  can have lang options
 
6694
                    "caseIgnoreSubstringsMatch", "2.5.13.4" ---------------------   (as seen in the console)!
 
6695
                    "directoryStringFirstComponentMatch", "2.5.13.31"
 
6696
                    "objectIdentifierMatch", "2.5.13.0"
 
6697
                    "objectIdentifierFirstComponentMatch", "2.5.13.30"
 
6698
 
 
6699
                    bitstring
 
6700
                    "bitStringMatch", "2.5.13.16","2.16.840.1.113730.3.3.1"
 
6701
 
 
6702
                    bin
 
6703
                    "octetStringMatch", "2.5.13.17"
 
6704
                    "octetStringOrderingMatch", "2.5.13.18"
 
6705
 
 
6706
                    DN
 
6707
                    "distinguishedNameMatch", "2.5.13.1"
 
6708
 
 
6709
                    Int
 
6710
                    "integerMatch", "2.5.13.14"
 
6711
                    "integerOrderingMatch", "2.5.13.15"
 
6712
                    "integerFirstComponentMatch", "2.5.13.29"
 
6713
 
 
6714
                    NameAndOptUID
 
6715
                    "uniqueMemberMatch", "2.5.13.23"
 
6716
 
 
6717
                    NumericString
 
6718
                    "numericStringMatch", "2.5.13.8"
 
6719
                    "numericStringOrderingMatch", "2.5.13.9"
 
6720
                    "numericStringSubstringsMatch", "2.5.13.10"
 
6721
 
 
6722
                    Telephone
 
6723
                    "telephoneNumberMatch", "2.5.13.20"
 
6724
                    "telephoneNumberSubstringsMatch", "2.5.13.21"
 
6725
                 */
 
6726
            }
 
6727
        }
 
6728
    }
 
6729
 
 
6730
    return rc;
 
6731
}
 
6732
 
 
6733
/*
 
6734
 * Return 1 if oid1 is a superset(oid1 is not to be overwritten)
 
6735
 */
 
6736
static int
 
6737
schema_at_superset_check_syntax_oids(char *oid1, char *oid2)
 
6738
{
 
6739
    if(oid1 == NULL && oid2 == NULL){
 
6740
        return 0;
 
6741
    } else if (oid2 == NULL){
 
6742
        return 0;
 
6743
    } else if (oid1 == NULL){
 
6744
        return 1;
 
6745
    }
 
6746
 
 
6747
    if(strcmp(oid1, BINARY_SYNTAX_OID) == 0){
 
6748
        if(strcmp(oid2, BINARY_SYNTAX_OID) &&
 
6749
           strcmp(oid2, INTEGER_SYNTAX_OID) &&
 
6750
           strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
 
6751
           strcmp(oid2, IA5STRING_SYNTAX_OID) &&
 
6752
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6753
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6754
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6755
           strcmp(oid2, FACSIMILE_SYNTAX_OID) &&
 
6756
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6757
           strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
 
6758
           strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
 
6759
           strcmp(oid2, TELEXNUMBER_SYNTAX_OID))
 
6760
 
 
6761
        {
 
6762
            return 1;
 
6763
        }
 
6764
    } else if(strcmp(oid1, BITSTRING_SYNTAX_OID) == 0){
 
6765
        if(strcmp(oid2, BINARY_SYNTAX_OID) &&
 
6766
           strcmp(oid2, BITSTRING_SYNTAX_OID) &&
 
6767
           strcmp(oid2, INTEGER_SYNTAX_OID) &&
 
6768
           strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
 
6769
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6770
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6771
           strcmp(oid2, IA5STRING_SYNTAX_OID) &&
 
6772
           strcmp(oid2, FACSIMILE_SYNTAX_OID) &&
 
6773
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6774
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6775
           strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
 
6776
           strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
 
6777
           strcmp(oid2, TELEXNUMBER_SYNTAX_OID))
 
6778
        {
 
6779
            return 1;
 
6780
        }
 
6781
    } else if(strcmp(oid1, BOOLEAN_SYNTAX_OID) == 0){
 
6782
        if(strcmp(oid2, BOOLEAN_SYNTAX_OID) &&
 
6783
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6784
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6785
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6786
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6787
        {
 
6788
            return 1;
 
6789
        }
 
6790
    } else if(strcmp(oid1, COUNTRYSTRING_SYNTAX_OID) ==0){
 
6791
        if(strcmp(oid2, COUNTRYSTRING_SYNTAX_OID) &&
 
6792
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6793
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6794
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6795
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6796
        {
 
6797
            return 1;
 
6798
        }
 
6799
    } else if(strcmp(oid1, DN_SYNTAX_OID) == 0){
 
6800
        if(strcmp(oid2, DN_SYNTAX_OID) &&
 
6801
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6802
           strcmp(oid2, DIRSTRING_SYNTAX_OID) )
 
6803
        {
 
6804
            return 1;
 
6805
        }
 
6806
    } else if(strcmp(oid1, DELIVERYMETHOD_SYNTAX_OID) ==0){
 
6807
        if(strcmp(oid2, DELIVERYMETHOD_SYNTAX_OID) &&
 
6808
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6809
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6810
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6811
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6812
        {
 
6813
            return 1;
 
6814
        }
 
6815
    } else if(strcmp(oid1, DIRSTRING_SYNTAX_OID) == 0){
 
6816
        if(strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6817
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID)){
 
6818
            return 1;
 
6819
        }
 
6820
    } else if(strcmp(oid1, ENHANCEDGUIDE_SYNTAX_OID) == 0){
 
6821
        if(strcmp(oid2, ENHANCEDGUIDE_SYNTAX_OID) &&
 
6822
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6823
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6824
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6825
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6826
        {
 
6827
            return 1;
 
6828
        }
 
6829
    } else if(strcmp(oid1, IA5STRING_SYNTAX_OID) == 0){
 
6830
        if(strcmp(oid2, IA5STRING_SYNTAX_OID) &&
 
6831
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6832
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6833
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID))
 
6834
        {
 
6835
           return 1;
 
6836
        }
 
6837
    } else if(strcmp(oid1, INTEGER_SYNTAX_OID) == 0){
 
6838
        if(strcmp(oid2, INTEGER_SYNTAX_OID) &&
 
6839
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6840
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6841
           strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
 
6842
           strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
 
6843
           strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
 
6844
           strcmp(oid2, TELEXNUMBER_SYNTAX_OID) &&
 
6845
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6846
           strcmp(oid2, IA5STRING_SYNTAX_OID) )
 
6847
        {
 
6848
            return 1;
 
6849
        }
 
6850
    } else if(strcmp(oid1, JPEG_SYNTAX_OID) == 0){
 
6851
        if(strcmp(oid2, JPEG_SYNTAX_OID) &&
 
6852
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6853
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6854
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6855
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6856
        {
 
6857
            return 1;
 
6858
        }
 
6859
    } else if(strcmp(oid1, NAMEANDOPTIONALUID_SYNTAX_OID) == 0){
 
6860
        if(strcmp(oid2, NAMEANDOPTIONALUID_SYNTAX_OID) &&
 
6861
           strcmp(oid2, NAMEANDOPTIONALUID_SYNTAX_OID) &&
 
6862
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6863
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6864
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6865
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6866
        {
 
6867
            return 1;
 
6868
        }
 
6869
    } else if(strcmp(oid1, NUMERICSTRING_SYNTAX_OID) == 0){
 
6870
        if(strcmp(oid2, NUMERICSTRING_SYNTAX_OID) &&
 
6871
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6872
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6873
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6874
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6875
        {
 
6876
            return 1;
 
6877
        }
 
6878
    } else if(strcmp(oid1, OID_SYNTAX_OID) == 0){
 
6879
        if(strcmp(oid2, OID_SYNTAX_OID) &&
 
6880
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6881
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6882
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6883
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6884
        {
 
6885
            return 1;
 
6886
        }
 
6887
    } else if (strcmp(oid1, OCTETSTRING_SYNTAX_OID) == 0){
 
6888
        if(strcmp(oid2, OCTETSTRING_SYNTAX_OID) &&
 
6889
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6890
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6891
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6892
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6893
        {
 
6894
            return 1;
 
6895
        }
 
6896
    } else if(strcmp(oid1, POSTALADDRESS_SYNTAX_OID) ==0){
 
6897
        if(strcmp(oid2, POSTALADDRESS_SYNTAX_OID) &&
 
6898
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6899
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6900
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6901
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6902
        {
 
6903
            return 1;
 
6904
        }
 
6905
    } else if(strcmp(oid1, PRINTABLESTRING_SYNTAX_OID) == 0){
 
6906
        if(strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6907
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6908
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6909
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6910
        {
 
6911
            return 1;
 
6912
        }
 
6913
    } else if(strcmp(oid1, TELEPHONE_SYNTAX_OID) == 0){
 
6914
        if(strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6915
           strcmp(oid2, TELEPHONE_SYNTAX_OID) &&
 
6916
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6917
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6918
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6919
        {
 
6920
            return 1;
 
6921
        }
 
6922
    } else if(strcmp(oid1, TELETEXTERMID_SYNTAX_OID) == 0){
 
6923
        if(strcmp(oid2, TELETEXTERMID_SYNTAX_OID) &&
 
6924
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6925
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6926
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6927
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6928
        {
 
6929
            return 1;
 
6930
        }
 
6931
    } else if(strcmp(oid1, TELEXNUMBER_SYNTAX_OID) == 0){
 
6932
        if(strcmp(oid2, TELEXNUMBER_SYNTAX_OID) &&
 
6933
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6934
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6935
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6936
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6937
        {
 
6938
            return 1;
 
6939
        }
 
6940
    } else if (strcmp(oid1, SPACE_INSENSITIVE_STRING_SYNTAX_OID) == 0){
 
6941
        if(strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6942
           strcmp(oid2, PRINTABLESTRING_SYNTAX_OID) &&
 
6943
           strcmp(oid2, DIRSTRING_SYNTAX_OID) &&
 
6944
           strcmp(oid2, SPACE_INSENSITIVE_STRING_SYNTAX_OID) &&
 
6945
           strcmp(oid2, IA5STRING_SYNTAX_OID))
 
6946
        {
 
6947
            return 1;
 
6948
        }
 
6949
    }
 
6950
 
 
6951
    return 0;
5978
6952
}
5979
6953
 
5980
6954
static void
5988
6962
        }
5989
6963
}
5990
6964
 
5991
 
static
5992
 
struct objclass *schema_berval_to_oclist(struct berval **oc_berval) {
 
6965
static void
 
6966
schema_atlist_free(struct asyntaxinfo *at_list)
 
6967
{
 
6968
    struct asyntaxinfo *at, *at_next;
 
6969
 
 
6970
    for (at = at_list; at != NULL; at = at_next) {
 
6971
        at_next = at->asi_next;
 
6972
        attr_syntax_free(at);
 
6973
    }
 
6974
}
 
6975
 
 
6976
static struct objclass *
 
6977
schema_berval_to_oclist(struct berval **oc_berval)
 
6978
{
5993
6979
        struct objclass *oc, *oc_list, *oc_tail;
5994
6980
        char errorbuf[BUFSIZ];
5995
6981
        int schema_ds4x_compat, rc;
6029
7015
        return oc_list;
6030
7016
}
6031
7017
 
 
7018
static struct asyntaxinfo *
 
7019
schema_berval_to_atlist(struct berval **at_berval)
 
7020
{
 
7021
    struct asyntaxinfo *at, *head = NULL, *at_list = NULL;
 
7022
    char errorbuf[BUFSIZ];
 
7023
    int schema_ds4x_compat, rc = 0, i;
 
7024
 
 
7025
    schema_ds4x_compat = config_get_ds4_compatible_schema();
 
7026
 
 
7027
    if (at_berval != NULL) {
 
7028
        for (i = 0; at_berval[i] != NULL; i++) {
 
7029
            /* parse the objectclass value */
 
7030
            rc = parse_at_str(at_berval[i]->bv_val, &at, errorbuf, sizeof (errorbuf),
 
7031
                    DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_USE_PRIV_SCHEMA, 0, schema_ds4x_compat, 0);
 
7032
            if(rc){
 
7033
                attr_syntax_free(at);
 
7034
                break;
 
7035
            }
 
7036
            if(!head){
 
7037
                head = at_list = at;
 
7038
            } else {
 
7039
                at_list->asi_next = at;
 
7040
                at->asi_prev = at_list;
 
7041
                at_list = at;
 
7042
            }
 
7043
        }
 
7044
    }
 
7045
    if (rc) {
 
7046
        schema_atlist_free(head);
 
7047
    }
 
7048
 
 
7049
    return head;
 
7050
}
 
7051
 
 
7052
 
6032
7053
int
6033
 
schema_objectclasses_superset_check(struct berval **remote_schema, char *type) {
 
7054
schema_objectclasses_superset_check(struct berval **remote_schema, char *type)
 
7055
{
6034
7056
        int  rc;
6035
7057
        struct objclass *remote_oc_list;
6036
7058
 
6053
7075
                 */
6054
7076
 
6055
7077
                if (remote_oc_list) {
6056
 
                        oc_lock_read();
 
7078
                        oc_lock_read();                       
6057
7079
                        if (strcmp(type, OC_SUPPLIER) == 0) {
6058
7080
                                /* Check if the remote_oc_list from a consumer are or not 
6059
7081
                                 * a superset of the objectclasses of the local supplier schema
6060
7082
                                 */
6061
 
                                rc = schema_oc_superset_check(remote_oc_list, g_get_global_oc_nolock(), "local supplier" );
 
7083
                                rc = schema_oc_superset_check(remote_oc_list, g_get_global_oc_nolock(), "remote consumer", REPL_SCHEMA_AS_SUPPLIER);
6062
7084
                        } else {
6063
7085
                                /* Check if the objectclasses of the local consumer schema are or not
6064
7086
                                 * a superset of the remote_oc_list from a supplier
6065
7087
                                 */
6066
 
                                rc = schema_oc_superset_check(g_get_global_oc_nolock(), remote_oc_list, "remote supplier");
 
7088
                                rc = schema_oc_superset_check(g_get_global_oc_nolock(), remote_oc_list, "remote supplier", REPL_SCHEMA_AS_CONSUMER);
6067
7089
                        }
6068
 
                        
 
7090
 
6069
7091
                        oc_unlock();
6070
7092
                }
6071
7093
                
6074
7096
        }
6075
7097
        return rc;
6076
7098
}
 
7099
 
 
7100
int
 
7101
schema_attributetypes_superset_check(struct berval **remote_schema, char *type)
 
7102
{
 
7103
    struct asyntaxinfo *remote_at_list = NULL;
 
7104
    int rc = 0;
 
7105
 
 
7106
    if (remote_schema != NULL) {
 
7107
        /* First build an attribute list from the remote schema */
 
7108
        if ((remote_at_list = schema_berval_to_atlist(remote_schema)) == NULL) {
 
7109
            rc = 1;
 
7110
            return rc;
 
7111
        }
 
7112
 
 
7113
        /*
 
7114
         * Check that for each object from the remote schema
 
7115
         *         - MUST attributes are also MUST in local schema
 
7116
         *         - ALLOWED attributes are also ALLOWED in local schema
 
7117
         */
 
7118
        if (remote_at_list) {
 
7119
            attr_syntax_read_lock();
 
7120
            if (strcmp(type, OC_SUPPLIER) == 0) {
 
7121
                /*
 
7122
                 * Check if the remote_at_list from a consumer are or not
 
7123
                 * a superset of the attributetypes of the local supplier schema
 
7124
                 */
 
7125
                rc = schema_at_superset_check(remote_at_list, attr_syntax_get_global_at(), "local supplier", REPL_SCHEMA_AS_SUPPLIER);
 
7126
            } else {
 
7127
                /*
 
7128
                 * Check if the attributeypes of the local consumer schema are or not
 
7129
                 * a superset of the remote_at_list from a supplier
 
7130
                 */
 
7131
                rc = schema_at_superset_check(attr_syntax_get_global_at(), remote_at_list, "remote supplier", REPL_SCHEMA_AS_CONSUMER);
 
7132
            }
 
7133
            attr_syntax_unlock_read();
 
7134
        }
 
7135
 
 
7136
        /* Free the remote schema list */
 
7137
        schema_atlist_free(remote_at_list);
 
7138
    }
 
7139
    return rc;
 
7140
}
 
7141
 
 
7142
/* Do the internal MOD and update the local "nsSchemaCSN" with a local timestamp
 
7143
 * It could be a good idea to set the 'nsSchemaCSN' with the maximum of local time and
 
7144
 * the CSN received with the remote schema
 
7145
 */
 
7146
static void
 
7147
modify_schema_internal_mod(Slapi_DN *sdn, Slapi_Mods *smods)
 
7148
{
 
7149
        Slapi_PBlock *newpb;
 
7150
        int op_result;
 
7151
        CSN *schema_csn;
 
7152
        
 
7153
        /* allocate internal mod components: pblock*/
 
7154
        newpb = slapi_pblock_new();
 
7155
        
 
7156
        slapi_modify_internal_set_pb_ext (
 
7157
                        newpb,
 
7158
                        sdn,
 
7159
                        slapi_mods_get_ldapmods_byref (smods),
 
7160
                        NULL, /* Controls */
 
7161
                        NULL,
 
7162
                        (void *)plugin_get_default_component_id(),
 
7163
                        0);     
 
7164
 
 
7165
        /* do modify */
 
7166
        slapi_modify_internal_pb (newpb);
 
7167
        slapi_pblock_get (newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
 
7168
        if (op_result == LDAP_SUCCESS) {              
 
7169
                /* Update the schema csn if the operation succeeded */
 
7170
                schema_csn = csn_new();
 
7171
                if (NULL != schema_csn) {
 
7172
                        csn_set_replicaid(schema_csn, 0);
 
7173
                        csn_set_time(schema_csn, current_time());
 
7174
                        g_set_global_schema_csn(schema_csn);
 
7175
                }
 
7176
        }
 
7177
 
 
7178
        slapi_pblock_destroy(newpb);
 
7179
}
 
7180
 
 
7181
/* Prepare slapi_mods for the internal mod 
 
7182
 * Caller must free smods with slapi_mods_done
 
7183
 */
 
7184
static void
 
7185
modify_schema_prepare_mods(Slapi_Mods *smods, char *type, struct schema_mods_indexes *values)
 
7186
{   
 
7187
        struct schema_mods_indexes *object;
 
7188
        struct berval *bv;
 
7189
        struct berval **bvps;
 
7190
        int nb_values, i;
 
7191
            
 
7192
        for (object = values, nb_values = 0; object != NULL; object = object->next, nb_values++);
 
7193
        bvps = (struct berval **) slapi_ch_calloc(1, (nb_values + 1) * sizeof(struct berval *));
 
7194
        
 
7195
        
 
7196
        for (i = 0, object = values; object != NULL; i++, object = object->next) {
 
7197
                bv = (struct berval *) slapi_ch_malloc(sizeof(struct berval));
 
7198
                bv->bv_len = strlen(object->new_value);
 
7199
                bv->bv_val = (void*) object->new_value;
 
7200
                bvps[i] = bv;
 
7201
                slapi_log_error(SLAPI_LOG_REPL, "schema", "MOD[%d] add (%s): %s\n", i, type, object->new_value);
 
7202
        }
 
7203
        bvps[nb_values] = NULL;
 
7204
        slapi_mods_init (smods, 2);
 
7205
        slapi_mods_add_modbvps( smods, LDAP_MOD_ADD, type, bvps );
 
7206
        for (i = 0; bvps[i] != NULL; i++) {
 
7207
                /* bv_val should not be free. It belongs to the incoming MOD */
 
7208
                slapi_ch_free((void **) &bvps[i]);
 
7209
        }
 
7210
        slapi_ch_free((void **) &bvps);
 
7211
        
 
7212
}
 
7213
 
 
7214
/* called by modify_schema_dse/supplier_learn_new_definitions to learn new 
 
7215
 * definitions via internal mod.
 
7216
 * Internal mod is important, because we want those definitions to be updated in 99user.ldif
 
7217
 * and we are not sure that the current operation will succeeds or not.
 
7218
 */
 
7219
static void
 
7220
modify_schema_apply_new_definitions(char *attr_name, struct schema_mods_indexes *list)
 
7221
{
 
7222
        Slapi_Mods smods = {0};
 
7223
        Slapi_DN *sdn = NULL;
 
7224
        
 
7225
        if (list == NULL)
 
7226
                return;
 
7227
        
 
7228
        /* Then the sdn */
 
7229
        sdn = slapi_sdn_new();
 
7230
        if (!sdn) {
 
7231
                slapi_log_error( SLAPI_LOG_FATAL, "schema", "modify_schema_apply_new_definitions Out of memory \n");
 
7232
                goto done;
 
7233
        }
 
7234
        slapi_sdn_set_dn_byval(sdn, SLAPD_SCHEMA_DN);
 
7235
        
 
7236
        /* prepare the mods */
 
7237
        modify_schema_prepare_mods(&smods, attr_name, list);
 
7238
        
 
7239
        /* update the schema with the new attributetypes */
 
7240
        /* No need to lock the schema_dse as the internal mod will do */
 
7241
        modify_schema_internal_mod(sdn, &smods);
 
7242
        
 
7243
        
 
7244
done:
 
7245
        if (sdn) {
 
7246
                slapi_sdn_free(&sdn);
 
7247
        }               
 
7248
        slapi_mods_done (&smods);
 
7249
}
 
7250
 
 
7251
/* 
 
7252
 * This routines retrieves from the remote schema (mods) the
 
7253
 * definitions (attributetypes/objectclasses), that are:
 
7254
 *   - unknown from the local schema
 
7255
 *   - a superset of the local definition
 
7256
 *
 
7257
 * It then builds two lists (to be freed by the caller) with those definitions.
 
7258
 * Those list contains a duplicate of the definition (string).
 
7259
 */
 
7260
static void
 
7261
modify_schema_get_new_definitions(Slapi_PBlock *pb, LDAPMod **mods, struct schema_mods_indexes **at_list, struct schema_mods_indexes **oc_list)
 
7262
{
 
7263
        struct asyntaxinfo *remote_at_list;
 
7264
        struct objclass *remote_oc_list;
 
7265
        int is_replicated_operation = 0;
 
7266
        int replace_allowed = 0;
 
7267
        slapdFrontendConfig_t *slapdFrontendConfig;
 
7268
        int i;
 
7269
        struct schema_mods_indexes *at2learn_list = NULL;
 
7270
        struct schema_mods_indexes *at2learn;
 
7271
        struct schema_mods_indexes *oc2learn_list = NULL;
 
7272
        struct schema_mods_indexes *oc2learn;
 
7273
 
 
7274
 
 
7275
        slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
 
7276
        
 
7277
        /* by default nothing to learn */
 
7278
        *at_list = NULL;
 
7279
        *oc_list = NULL; 
 
7280
        
 
7281
        /* We are only looking for schema received from a supplier */
 
7282
        if (!is_replicated_operation || !mods) {
 
7283
                return ;
 
7284
        }
 
7285
 
 
7286
        /* Check if we are allowed to update the schema (if needed) */
 
7287
        slapdFrontendConfig = getFrontendConfig();
 
7288
        CFG_LOCK_READ(slapdFrontendConfig);
 
7289
        if ((0 == strcasecmp(slapdFrontendConfig->schemareplace, CONFIG_SCHEMAREPLACE_STR_ON)) ||
 
7290
                (0 == strcasecmp(slapdFrontendConfig->schemareplace, CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY))) {
 
7291
                replace_allowed = 1;
 
7292
        }
 
7293
        CFG_UNLOCK_READ(slapdFrontendConfig);
 
7294
        if (!replace_allowed) {
 
7295
                return;
 
7296
        }
 
7297
 
 
7298
        
 
7299
        /* First retrieve unknowns attributetypes because an unknown objectclasses
 
7300
         * may be composed of unknown attributetypes
 
7301
         */
 
7302
        at2learn_list = NULL;
 
7303
        oc2learn_list = NULL;
 
7304
        schema_dse_lock_read();
 
7305
        for (i = 0; mods[i]; i++) {
 
7306
                if (SLAPI_IS_MOD_REPLACE(mods[i]->mod_op) && (mods[i]->mod_bvalues)) {
 
7307
 
 
7308
                        if (strcasecmp(mods[i]->mod_type, "attributetypes") == 0) {
 
7309
                                /* we have some MOD_replace of attributetypes*/
 
7310
 
 
7311
                                /* First build an attribute list from the remote schema */
 
7312
                                if ((remote_at_list = schema_berval_to_atlist(mods[i]->mod_bvalues)) == NULL) {
 
7313
                                        /* If we can not build an attributes list from the mods, just skip
 
7314
                                         * it and look for objectclasses
 
7315
                                         */
 
7316
                                        slapi_log_error(SLAPI_LOG_FATAL, "schema",
 
7317
                                                "Not able to build an attributes list (%s) from the schema received from the supplier\n",
 
7318
                                                mods[i]->mod_type);
 
7319
                                        continue;
 
7320
                                }
 
7321
                                /* Build a list of attributestype to learn from the remote definitions */
 
7322
                                attr_syntax_read_lock();
 
7323
                                at2learn_list = schema_list_attr2learn(attr_syntax_get_global_at(), remote_at_list, REPL_SCHEMA_AS_CONSUMER);
 
7324
                                attr_syntax_unlock_read();
 
7325
                                                                         
 
7326
                                /* For each of them copy the value to set */
 
7327
                                for (at2learn = at2learn_list; at2learn != NULL; at2learn = at2learn->next) {
 
7328
                                        struct berval   *bv;
 
7329
                                        bv = mods[i]->mod_bvalues[at2learn->index]; /* takes the berval from the selected mod */
 
7330
                                        at2learn->new_value = (char *) slapi_ch_malloc(bv->bv_len + 1);
 
7331
                                        memcpy(at2learn->new_value, bv->bv_val, bv->bv_len);
 
7332
                                        at2learn->new_value[bv->bv_len] = '\0';
 
7333
                                        slapi_log_error(SLAPI_LOG_REPL, "schema", "take attributetypes: %s\n", at2learn->new_value);
 
7334
                                }
 
7335
                                                                       
 
7336
                                /* Free the remote schema list */
 
7337
                                schema_atlist_free(remote_at_list);
 
7338
                                
 
7339
                        } else if (strcasecmp(mods[i]->mod_type, "objectclasses") == 0) {
 
7340
                                /* we have some MOD_replace of objectclasses */
 
7341
 
 
7342
                                /* First build an objectclass list from the remote schema */
 
7343
                                if ((remote_oc_list = schema_berval_to_oclist(mods[i]->mod_bvalues)) == NULL) {
 
7344
                                        /* If we can not build an objectclasses list from the mods, just skip
 
7345
                                         * it and look for attributes
 
7346
                                         */
 
7347
                                        slapi_log_error(SLAPI_LOG_FATAL, "schema",
 
7348
                                                "Not able to build an objectclasses list (%s) from the schema received from the supplier\n",
 
7349
                                                mods[i]->mod_type);
 
7350
                                        continue;
 
7351
                                }
 
7352
                                /* Build a list of objectclasses to learn from the remote definitions */
 
7353
                                oc_lock_read();
 
7354
                                oc2learn_list = schema_list_oc2learn(remote_oc_list, g_get_global_oc_nolock(), REPL_SCHEMA_AS_CONSUMER);
 
7355
                                oc_unlock();
 
7356
                                
 
7357
                                /* For each of them copy the value to set */
 
7358
                                for (oc2learn = oc2learn_list; oc2learn != NULL; oc2learn = oc2learn->next) {
 
7359
                                        struct berval   *bv;
 
7360
                                        bv = mods[i]->mod_bvalues[oc2learn->index]; /* takes the berval from the selected mod */
 
7361
                                        oc2learn->new_value = (char *) slapi_ch_malloc(bv->bv_len + 1);
 
7362
                                        memcpy(oc2learn->new_value, bv->bv_val, bv->bv_len);
 
7363
                                        oc2learn->new_value[bv->bv_len] = '\0';
 
7364
                                        slapi_log_error(SLAPI_LOG_REPL, "schema", "take objectclass: %s\n", oc2learn->new_value);
 
7365
                                }
 
7366
                                
 
7367
                                /* Free the remote schema list*/
 
7368
                                schema_oclist_free(remote_oc_list);
 
7369
                        }
 
7370
                }
 
7371
        }
 
7372
        schema_dse_unlock();
 
7373
        
 
7374
        *at_list = at2learn_list;
 
7375
        *oc_list = oc2learn_list;
 
7376
}
 
7377
 
 
7378
/* 
 
7379
 * It evaluate if the schema in the mods, is a superset of
 
7380
 * the local schema.
 
7381
 * Called when we know the mods comes from/to a replicated session
 
7382
 * Caller must not hold schema_dse lock
 
7383
 * 
 
7384
 *   mods: set of mod to apply to the schema
 
7385
 *   replica_role:
 
7386
 *      OC_CONSUMER: means the caller is acting as a consumer (receiving a schema)
 
7387
 *      OC_SUPPLIER: means the caller is acting as a supplier (sending a schema)
 
7388
 * 
 
7389
 * It returns:
 
7390
 *  - PR_TRUE: if replicated schema is a superset of local schema
 
7391
 *  - PR_FALSE: if local schema is a superset of local schema
 
7392
 */
 
7393
static PRBool
 
7394
check_replicated_schema(LDAPMod **mods, char *replica_role, char **attr_name) 
 
7395
{
 
7396
        int i;
 
7397
        PRBool rc = PR_TRUE;
 
7398
        
 
7399
        schema_dse_lock_read();
 
7400
        for (i = 0; mods[i]; i++) {
 
7401
                if ((SLAPI_IS_MOD_REPLACE(mods[i]->mod_op)) && strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
 
7402
                        if (schema_attributetypes_superset_check(mods[i]->mod_bvalues, replica_role)) {
 
7403
                                rc = PR_FALSE;
 
7404
                                *attr_name = mods[i]->mod_type;
 
7405
                                break;
 
7406
                        }
 
7407
                } else if ((SLAPI_IS_MOD_REPLACE(mods[i]->mod_op)) && strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
 
7408
                        if (schema_objectclasses_superset_check(mods[i]->mod_bvalues, replica_role)) {
 
7409
                                rc =  PR_FALSE;
 
7410
                                *attr_name = mods[i]->mod_type;
 
7411
                                break;
 
7412
                        }
 
7413
                        
 
7414
                }
 
7415
                
 
7416
        }
 
7417
        schema_dse_unlock();
 
7418
        
 
7419
        return rc;
 
7420
}
 
7421
 
 
7422
/* Free the list of definitions allocated in modify_schema_get_new_definitions/supplier_get_new_definitions */
 
7423
static void
 
7424
modify_schema_free_new_definitions(struct schema_mods_indexes *def_list)
 
7425
{
 
7426
        struct schema_mods_indexes *def, *head;
 
7427
        
 
7428
        for (head = def_list; head != NULL; ) {
 
7429
                def = head;
 
7430
                head = head->next;
 
7431
                
 
7432
                /* Free the string definition that was copied from the berval */
 
7433
                if (def->new_value) {
 
7434
                        slapi_ch_free((void**) &def->new_value);
 
7435
                }
 
7436
                
 
7437
                /* Then the definition cell */
 
7438
                slapi_ch_free((void **) &def);               
 
7439
        }
 
7440
}
 
7441
 
 
7442
/* This functions is called by a supplier.
 
7443
 * It builds lists of definitions (attributetypes/objectclasses) to learn 
 
7444
 * objectclasses:  received objectclass definitions
 
7445
 * attributetypes: received attribute definitions
 
7446
 * new_oc: list of definitions to learn (list should be freed by the caller)
 
7447
 * new_at: list of definitions to learn (list should be freed by the caller)
 
7448
 */
 
7449
 
 
7450
static void
 
7451
supplier_get_new_definitions(struct berval **objectclasses, struct berval **attributetypes, struct schema_mods_indexes **new_oc, struct schema_mods_indexes **new_at)
 
7452
{
 
7453
        int replace_allowed = 0;
 
7454
        slapdFrontendConfig_t *slapdFrontendConfig;
 
7455
        struct asyntaxinfo *remote_at_list;
 
7456
        struct objclass *remote_oc_list;
 
7457
        struct schema_mods_indexes *at2learn_list = NULL;
 
7458
        struct schema_mods_indexes *at2learn;
 
7459
        struct schema_mods_indexes *oc2learn_list = NULL;
 
7460
        struct schema_mods_indexes *oc2learn;
 
7461
 
 
7462
        *new_oc = NULL;
 
7463
        *new_at = NULL;
 
7464
        
 
7465
        if ((objectclasses == NULL) && (attributetypes == NULL)) {
 
7466
                return;
 
7467
        }
 
7468
        /* Check if we are allowed to update the schema (if needed) */
 
7469
        slapdFrontendConfig = getFrontendConfig();
 
7470
        CFG_LOCK_READ(slapdFrontendConfig);
 
7471
        if ((0 == strcasecmp(slapdFrontendConfig->schemareplace, CONFIG_SCHEMAREPLACE_STR_ON)) ||
 
7472
                (0 == strcasecmp(slapdFrontendConfig->schemareplace, CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY))) {
 
7473
                replace_allowed = 1;
 
7474
        }
 
7475
        CFG_UNLOCK_READ(slapdFrontendConfig);
 
7476
        if (!replace_allowed) {
 
7477
                return;
 
7478
        }
 
7479
        
 
7480
        schema_dse_lock_read();
 
7481
        /* 
 
7482
         * Build the list of objectclasses
 
7483
         */
 
7484
        /* from berval to objclass more convenient to compare */
 
7485
        if ((remote_oc_list = schema_berval_to_oclist(objectclasses)) != NULL) {
 
7486
                /* Build a list of objectclasses to learn from the remote definitions */
 
7487
                oc_lock_read();
 
7488
                oc2learn_list = schema_list_oc2learn(remote_oc_list, g_get_global_oc_nolock(), REPL_SCHEMA_AS_SUPPLIER);
 
7489
                oc_unlock();
 
7490
 
 
7491
                /* For each of them copy the value to set */
 
7492
                for (oc2learn = oc2learn_list; oc2learn != NULL; oc2learn = oc2learn->next) {
 
7493
                        struct berval *bv;
 
7494
                        bv = objectclasses[oc2learn->index]; /* takes the berval from the selected objectclass */
 
7495
                        oc2learn->new_value = (char *) slapi_ch_malloc(bv->bv_len + 1);
 
7496
                        memcpy(oc2learn->new_value, bv->bv_val, bv->bv_len);
 
7497
                        oc2learn->new_value[bv->bv_len] = '\0';
 
7498
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "supplier takes objectclass: %s\n", oc2learn->new_value);
 
7499
                }
 
7500
 
 
7501
                /* Free the remote schema list*/
 
7502
                schema_oclist_free(remote_oc_list);
 
7503
        } else {
 
7504
                /* If we can not build an objectclasses list */
 
7505
                slapi_log_error(SLAPI_LOG_FATAL, "schema",
 
7506
                        "Not able to build an objectclasses list from the consumer schema\n");
 
7507
        }
 
7508
 
 
7509
        
 
7510
        /*
 
7511
         * Build the list of attributetypes
 
7512
         */
 
7513
        /* First build an attribute list from the remote schema */
 
7514
        if ((remote_at_list = schema_berval_to_atlist(attributetypes)) != NULL) {
 
7515
                /* Build a list of attributestype to learn from the remote definitions */
 
7516
                attr_syntax_read_lock();
 
7517
                at2learn_list = schema_list_attr2learn(attr_syntax_get_global_at(), remote_at_list, REPL_SCHEMA_AS_SUPPLIER);
 
7518
                attr_syntax_unlock_read();
 
7519
 
 
7520
                /* For each of them copy the value to set */
 
7521
                for (at2learn = at2learn_list; at2learn != NULL; at2learn = at2learn->next) {
 
7522
                        struct berval *bv;
 
7523
                        bv = attributetypes[at2learn->index]; /* takes the berval from the selected mod */
 
7524
                        at2learn->new_value = (char *) slapi_ch_malloc(bv->bv_len + 1);
 
7525
                        memcpy(at2learn->new_value, bv->bv_val, bv->bv_len);
 
7526
                        at2learn->new_value[bv->bv_len] = '\0';
 
7527
                        slapi_log_error(SLAPI_LOG_REPL, "schema", "supplier takes attributetypes: %s\n", at2learn->new_value);
 
7528
                }
 
7529
 
 
7530
                /* Free the remote schema list */
 
7531
                schema_atlist_free(remote_at_list);
 
7532
        } else {
 
7533
                /* If we can not build an attributes list from the mods, just skip
 
7534
                 * it and look for objectclasses
 
7535
                 */
 
7536
                slapi_log_error(SLAPI_LOG_FATAL, "schema",
 
7537
                        "Not able to build an attributes list from the consumer schema");
 
7538
        }
 
7539
        schema_dse_unlock();
 
7540
        *new_oc = oc2learn_list;
 
7541
        *new_at = at2learn_list;
 
7542
        
 
7543
}
 
7544
 
 
7545
/* This functions is called by a supplier when it detects new definitions (objectclasses/attributetypes)
 
7546
 * or extension of existing definitions in a consumer schema.
 
7547
 * This function, build lists of definitions to "learn" and add those definitions in the schema and 99user.ldif
 
7548
 */
 
7549
void 
 
7550
supplier_learn_new_definitions(struct berval **objectclasses, struct berval **attributetypes)
 
7551
{
 
7552
        struct schema_mods_indexes *oc_list = NULL;
 
7553
        struct schema_mods_indexes *at_list = NULL;
 
7554
        
 
7555
        supplier_get_new_definitions(objectclasses, attributetypes, &oc_list, &at_list);
 
7556
        if (at_list) {
 
7557
                modify_schema_apply_new_definitions("attributetypes", at_list);
 
7558
        }
 
7559
        if (oc_list) {
 
7560
                modify_schema_apply_new_definitions("objectclasses", oc_list);
 
7561
        }
 
7562
        /* No need to hold the lock for these list that are local */
 
7563
        modify_schema_free_new_definitions(at_list);
 
7564
        modify_schema_free_new_definitions(oc_list);
 
7565
}