1/* schema.c - routines to manage schema definitions */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 1998-2011 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16
17#include "portable.h"
18
19#include <stdio.h>
20
21#include <ac/ctype.h>
22#include <ac/string.h>
23#include <ac/socket.h>
24
25#include "slap.h"
26#include "lutil.h"
27
28
29int
30schema_info( Entry **entry, const char **text )
31{
32	AttributeDescription *ad_structuralObjectClass
33		= slap_schema.si_ad_structuralObjectClass;
34	AttributeDescription *ad_objectClass
35		= slap_schema.si_ad_objectClass;
36	AttributeDescription *ad_createTimestamp
37		= slap_schema.si_ad_createTimestamp;
38	AttributeDescription *ad_modifyTimestamp
39		= slap_schema.si_ad_modifyTimestamp;
40
41	Entry		*e;
42	struct berval	vals[5];
43	struct berval	nvals[5];
44
45	e = entry_alloc();
46	if( e == NULL ) {
47		/* Out of memory, do something about it */
48		Debug( LDAP_DEBUG_ANY,
49			"schema_info: entry_alloc failed - out of memory.\n", 0, 0, 0 );
50		*text = "out of memory";
51		return LDAP_OTHER;
52	}
53
54	e->e_attrs = NULL;
55	/* backend-specific schema info should be created by the
56	 * backend itself
57	 */
58	ber_dupbv( &e->e_name, &frontendDB->be_schemadn );
59	ber_dupbv( &e->e_nname, &frontendDB->be_schemandn );
60	e->e_private = NULL;
61
62	BER_BVSTR( &vals[0], "subentry" );
63	if( attr_merge_one( e, ad_structuralObjectClass, vals, NULL ) ) {
64		/* Out of memory, do something about it */
65		entry_free( e );
66		*text = "out of memory";
67		return LDAP_OTHER;
68	}
69
70	BER_BVSTR( &vals[0], "top" );
71	BER_BVSTR( &vals[1], "subentry" );
72	BER_BVSTR( &vals[2], "subschema" );
73	BER_BVSTR( &vals[3], "extensibleObject" );
74	BER_BVZERO( &vals[4] );
75	if ( attr_merge( e, ad_objectClass, vals, NULL ) ) {
76		/* Out of memory, do something about it */
77		entry_free( e );
78		*text = "out of memory";
79		return LDAP_OTHER;
80	}
81
82	{
83		int rc;
84		AttributeDescription *desc = NULL;
85		struct berval rdn = frontendDB->be_schemadn;
86		vals[0].bv_val = ber_bvchr( &rdn, '=' );
87
88		if( vals[0].bv_val == NULL ) {
89			*text = "improperly configured subschema subentry";
90			return LDAP_OTHER;
91		}
92
93		vals[0].bv_val++;
94		vals[0].bv_len = rdn.bv_len - (vals[0].bv_val - rdn.bv_val);
95		rdn.bv_len -= vals[0].bv_len + 1;
96
97		rc = slap_bv2ad( &rdn, &desc, text );
98
99		if( rc != LDAP_SUCCESS ) {
100			entry_free( e );
101			*text = "improperly configured subschema subentry";
102			return LDAP_OTHER;
103		}
104
105		nvals[0].bv_val = ber_bvchr( &frontendDB->be_schemandn, '=' );
106		assert( nvals[0].bv_val != NULL );
107		nvals[0].bv_val++;
108		nvals[0].bv_len = frontendDB->be_schemandn.bv_len -
109			(nvals[0].bv_val - frontendDB->be_schemandn.bv_val);
110
111		if ( attr_merge_one( e, desc, vals, nvals ) ) {
112			/* Out of memory, do something about it */
113			entry_free( e );
114			*text = "out of memory";
115			return LDAP_OTHER;
116		}
117	}
118
119	{
120		char		timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
121
122		/*
123		 * According to RFC 4512:
124
125   Servers SHOULD maintain the 'creatorsName', 'createTimestamp',
126   'modifiersName', and 'modifyTimestamp' attributes for all entries of
127   the DIT.
128
129		 * to be conservative, we declare schema created
130		 * AND modified at server startup time ...
131		 */
132
133		vals[0].bv_val = timebuf;
134		vals[0].bv_len = sizeof( timebuf );
135
136		slap_timestamp( &starttime, vals );
137
138		if( attr_merge_one( e, ad_createTimestamp, vals, NULL ) ) {
139			/* Out of memory, do something about it */
140			entry_free( e );
141			*text = "out of memory";
142			return LDAP_OTHER;
143		}
144		if( attr_merge_one( e, ad_modifyTimestamp, vals, NULL ) ) {
145			/* Out of memory, do something about it */
146			entry_free( e );
147			*text = "out of memory";
148			return LDAP_OTHER;
149		}
150	}
151
152	if ( syn_schema_info( e )
153		|| mr_schema_info( e )
154		|| mru_schema_info( e )
155		|| at_schema_info( e )
156		|| oc_schema_info( e )
157		|| cr_schema_info( e ) )
158	{
159		/* Out of memory, do something about it */
160		entry_free( e );
161		*text = "out of memory";
162		return LDAP_OTHER;
163	}
164
165	*entry = e;
166	return LDAP_SUCCESS;
167}
168