Make cn=aggregate output less pretty, by more like Win2008.
[kai/samba.git] / source / dsdb / schema / schema_description.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    Print schema info into string format
4    
5    Copyright (C) Andrew Bartlett 2006-2008
6     
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19    
20 */
21 #include "includes.h"
22 #include "dsdb/samdb/samdb.h"
23
24 #define IF_NULL_FAIL_RET(x) do {     \
25                 if (!x) {               \
26                         return NULL;    \
27                 }                       \
28         } while (0) 
29
30
31 char *schema_attribute_description(TALLOC_CTX *mem_ctx, 
32                                           enum dsdb_schema_convert_target target,
33                                           const char *seperator,
34                                           const char *oid, 
35                                           const char *name,
36                                           const char *description,
37                                           const char *equality, 
38                                           const char *substring, 
39                                           const char *syntax,
40                                           bool single_value, bool operational)
41 {
42         char *schema_entry = talloc_asprintf(mem_ctx, 
43                                              "(%s%s%s", seperator, oid, seperator);
44         
45         schema_entry = talloc_asprintf_append(schema_entry, 
46                                               "NAME '%s'%s", name, seperator);
47         IF_NULL_FAIL_RET(schema_entry);
48         
49         if (description) {
50 #if 0           
51                 /* Need a way to escape ' characters from the description */
52                 schema_entry = talloc_asprintf_append(schema_entry, 
53                                                       "DESC '%s'%s", description, seperator);
54                 IF_NULL_FAIL_RET(schema_entry);
55 #endif
56         }
57
58         if (equality) {
59                 schema_entry = talloc_asprintf_append(schema_entry, 
60                                                       "EQUALITY %s%s", equality, seperator);
61                 IF_NULL_FAIL_RET(schema_entry);
62         }
63         if (substring) {
64                 schema_entry = talloc_asprintf_append(schema_entry, 
65                                                       "SUBSTR %s%s", substring, seperator);
66                 IF_NULL_FAIL_RET(schema_entry);
67         }
68         
69         schema_entry = talloc_asprintf_append(schema_entry, 
70                                               "SYNTAX %s%s", syntax, seperator);
71         IF_NULL_FAIL_RET(schema_entry);
72         
73         if (single_value) {
74                 schema_entry = talloc_asprintf_append(schema_entry, 
75                                                       "SINGLE-VALUE%s", seperator);
76                 IF_NULL_FAIL_RET(schema_entry);
77         }
78         
79         if (operational) {
80                 schema_entry = talloc_asprintf_append(schema_entry, 
81                                                       "NO-USER-MODIFICATION%s", seperator);
82                 IF_NULL_FAIL_RET(schema_entry);
83         }
84         
85         schema_entry = talloc_asprintf_append(schema_entry, 
86                                               ")");
87         return schema_entry;
88 }
89
90 char *schema_attribute_to_description(TALLOC_CTX *mem_ctx, const struct dsdb_attribute *attribute) 
91 {
92         char *schema_description;
93         const struct dsdb_syntax *map = find_syntax_map_by_ad_oid(attribute->attributeSyntax_oid);
94         const char *syntax = map ? map->ldap_oid : attribute->attributeSyntax_oid;
95         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
96         if (!tmp_ctx) {
97                 return NULL;
98         }
99
100         
101         schema_description 
102                 = schema_attribute_description(mem_ctx, 
103                                                TARGET_AD_SCHEMA_SUBENTRY,
104                                                " ",
105                                                attribute->attributeID_oid,
106                                                attribute->lDAPDisplayName,
107                                                NULL, NULL, NULL, talloc_asprintf(tmp_ctx, "'%s'", syntax),
108                                                attribute->isSingleValued,
109                                                attribute->systemOnly);
110         talloc_free(tmp_ctx);
111         return schema_description;
112 }
113
114 #define APPEND_ATTRS(attributes)                                \
115         do {                                                            \
116                 int k;                                                  \
117                 for (k=0; attributes && attributes[k]; k++) {           \
118                         const char *attr_name = attributes[k];          \
119                                                                         \
120                         schema_entry = talloc_asprintf_append(schema_entry, \
121                                                               "%s ",    \
122                                                               attr_name); \
123                         IF_NULL_FAIL_RET(schema_entry);                 \
124                         if (attributes[k+1]) {                          \
125                                 IF_NULL_FAIL_RET(schema_entry);         \
126                                 if (target == TARGET_OPENLDAP && ((k+1)%5 == 0)) { \
127                                         schema_entry = talloc_asprintf_append(schema_entry, \
128                                                                               "$%s ", seperator); \
129                                         IF_NULL_FAIL_RET(schema_entry); \
130                                 } else {                                \
131                                         schema_entry = talloc_asprintf_append(schema_entry, \
132                                                                               "$ "); \
133                                 }                                       \
134                         }                                               \
135                 }                                                       \
136         } while (0)
137         
138
139 /* Print a schema class or dITContentRule as a string.  
140  *
141  * To print a scheam class, specify objectClassCategory but not auxillary_classes
142  * To print a dITContentRule, specify auxillary_classes but set objectClassCategory == -1
143  *
144  */
145
146 char *schema_class_description(TALLOC_CTX *mem_ctx, 
147                                enum dsdb_schema_convert_target target,
148                                const char *seperator,
149                                const char *oid, 
150                                const char *name,
151                                const char **auxillary_classes,
152                                const char *description,
153                                const char *subClassOf,
154                                int objectClassCategory,
155                                char **must,
156                                char **may)
157 {
158         char *schema_entry = talloc_asprintf(mem_ctx, 
159                                              "(%s%s%s", seperator, oid, seperator);
160         
161         IF_NULL_FAIL_RET(schema_entry);
162
163         schema_entry = talloc_asprintf_append(schema_entry, 
164                                               "NAME '%s'%s", name, seperator);
165         IF_NULL_FAIL_RET(schema_entry);
166         
167         if (description) {
168                 schema_entry = talloc_asprintf_append(schema_entry, 
169                                                       "DESC '%s'%s", description, seperator);
170                 IF_NULL_FAIL_RET(schema_entry);
171         }
172
173         if (auxillary_classes) {
174                 schema_entry = talloc_asprintf_append(schema_entry, 
175                                                       "AUX ( ");
176                 IF_NULL_FAIL_RET(schema_entry);
177                 
178                 APPEND_ATTRS(auxillary_classes);
179                 
180                 schema_entry = talloc_asprintf_append(schema_entry, 
181                                                       ")%s", seperator);
182                 IF_NULL_FAIL_RET(schema_entry);
183         }
184
185         if (subClassOf && strcasecmp(subClassOf, name) != 0) {
186                 schema_entry = talloc_asprintf_append(schema_entry, 
187                                                       "SUP %s%s", subClassOf, seperator);
188                 IF_NULL_FAIL_RET(schema_entry);
189         }
190         
191         switch (objectClassCategory) {
192         case -1:
193                 break;
194                 /* Dummy case for when used for printing ditContentRules */
195         case 0:
196                 /*
197                  * NOTE: this is an type 88 class
198                  *       e.g. 2.5.6.6 NAME 'person'
199                  *       but w2k3 gives STRUCTURAL here!
200                  */
201                 schema_entry = talloc_asprintf_append(schema_entry, 
202                                                       "STRUCTURAL%s", seperator);
203                 IF_NULL_FAIL_RET(schema_entry);
204                 break;
205         case 1:
206                 schema_entry = talloc_asprintf_append(schema_entry, 
207                                                       "STRUCTURAL%s", seperator);
208                 IF_NULL_FAIL_RET(schema_entry);
209                 break;
210         case 2:
211                 schema_entry = talloc_asprintf_append(schema_entry, 
212                                                       "ABSTRACT%s", seperator);
213                 IF_NULL_FAIL_RET(schema_entry);
214                 break;
215         case 3:
216                 schema_entry = talloc_asprintf_append(schema_entry, 
217                                                       "AUXILIARY%s", seperator);
218                 IF_NULL_FAIL_RET(schema_entry);
219                 break;
220         }
221         
222         if (must) {
223                 schema_entry = talloc_asprintf_append(schema_entry, 
224                                                       "MUST (%s", target == TARGET_AD_SCHEMA_SUBENTRY ? "" : " ");
225                 IF_NULL_FAIL_RET(schema_entry);
226                 
227                 APPEND_ATTRS(must);
228                 
229                 schema_entry = talloc_asprintf_append(schema_entry, 
230                                                       ")%s", seperator);
231                 IF_NULL_FAIL_RET(schema_entry);
232         }
233         
234         if (may) {
235                 schema_entry = talloc_asprintf_append(schema_entry, 
236                                                       "MAY (%s", target == TARGET_AD_SCHEMA_SUBENTRY ? "" : " ");
237                 IF_NULL_FAIL_RET(schema_entry);
238                 
239                 APPEND_ATTRS(may);
240                 
241                 schema_entry = talloc_asprintf_append(schema_entry, 
242                                                       ")%s", seperator);
243                 IF_NULL_FAIL_RET(schema_entry);
244         }
245         
246         schema_entry = talloc_asprintf_append(schema_entry, 
247                                               ")");
248         return schema_entry;
249 }
250
251 char *schema_class_to_description(TALLOC_CTX *mem_ctx, const struct dsdb_class *class) 
252 {
253         char *schema_description;
254         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
255         if (!tmp_ctx) {
256                 return NULL;
257         }
258         
259         schema_description
260                 = schema_class_description(mem_ctx, 
261                                            TARGET_AD_SCHEMA_SUBENTRY,
262                                            " ",
263                                            class->governsID_oid,
264                                            class->lDAPDisplayName,
265                                            NULL,
266                                            NULL, 
267                                            class->subClassOf,
268                                            class->objectClassCategory,
269                                            dsdb_attribute_list(tmp_ctx, 
270                                                                class, DSDB_SCHEMA_ALL_MUST),
271                                            dsdb_attribute_list(tmp_ctx, 
272                                                                class, DSDB_SCHEMA_ALL_MAY));
273         talloc_free(tmp_ctx);
274         return schema_description;
275 }
276 char *schema_class_to_dITContentRule(TALLOC_CTX *mem_ctx, const struct dsdb_class *class,
277                                      const struct dsdb_schema *schema) 
278 {
279         int i;
280         char *schema_description;
281         char **aux_class_list = NULL;
282         char **attrs;
283         char **must_attr_list = NULL;
284         char **may_attr_list = NULL;
285         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
286         const struct dsdb_class *aux_class;
287         if (!tmp_ctx) {
288                 return NULL;
289         }
290
291         aux_class_list = merge_attr_list(tmp_ctx, aux_class_list, class->systemAuxiliaryClass);
292         aux_class_list = merge_attr_list(tmp_ctx, aux_class_list, class->auxiliaryClass);
293
294         for (i=0; aux_class_list && aux_class_list[i]; i++) {
295                 aux_class = dsdb_class_by_lDAPDisplayName(schema, aux_class_list[i]);
296                 
297                 attrs = dsdb_attribute_list(mem_ctx, aux_class, DSDB_SCHEMA_ALL_MUST);
298                 must_attr_list = merge_attr_list(mem_ctx, must_attr_list, attrs);
299
300                 attrs = dsdb_attribute_list(mem_ctx, aux_class, DSDB_SCHEMA_ALL_MAY);
301                 may_attr_list = merge_attr_list(mem_ctx, may_attr_list, attrs);
302         }
303
304         schema_description
305                 = schema_class_description(mem_ctx, 
306                                            TARGET_AD_SCHEMA_SUBENTRY,
307                                            " ",
308                                            class->governsID_oid,
309                                            class->lDAPDisplayName,
310                                            (const char **)aux_class_list,
311                                            NULL, 
312                                            class->subClassOf,
313                                            -1, must_attr_list, may_attr_list);
314         talloc_free(tmp_ctx);
315         return schema_description;
316 }