ca26ffd2068cb96620167637c4c2c6ea8eb9c1db
[ira/wip.git] / source4 / dsdb / schema / schema_query.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    DSDB schema header
4    
5    Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20    
21 */
22
23 #include "includes.h"
24 #include "dsdb/samdb/samdb.h"
25
26 const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
27                                                               uint32_t id)
28 {
29         struct dsdb_attribute *cur;
30
31         /*
32          * 0xFFFFFFFF is used as value when no mapping table is available,
33          * so don't try to match with it
34          */
35         if (id == 0xFFFFFFFF) return NULL;
36
37         /* TODO: add binary search */
38         for (cur = schema->attributes; cur; cur = cur->next) {
39                 if (cur->attributeID_id != id) continue;
40
41                 return cur;
42         }
43
44         return NULL;
45 }
46
47 const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
48                                                                const char *oid)
49 {
50         struct dsdb_attribute *cur;
51
52         if (!oid) return NULL;
53
54         /* TODO: add binary search */
55         for (cur = schema->attributes; cur; cur = cur->next) {
56                 if (strcmp(cur->attributeID_oid, oid) != 0) continue;
57
58                 return cur;
59         }
60
61         return NULL;
62 }
63
64 const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
65                                                                const char *name)
66 {
67         struct dsdb_attribute *cur;
68
69         if (!name) return NULL;
70
71         /* TODO: add binary search */
72         for (cur = schema->attributes; cur; cur = cur->next) {
73                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
74
75                 return cur;
76         }
77
78         return NULL;
79 }
80
81 const struct dsdb_attribute *dsdb_attribute_by_linkID(const struct dsdb_schema *schema,
82                                                       int linkID)
83 {
84         struct dsdb_attribute *cur;
85
86         /* TODO: add binary search */
87         for (cur = schema->attributes; cur; cur = cur->next) {
88                 if (cur->linkID != linkID) continue;
89
90                 return cur;
91         }
92
93         return NULL;
94 }
95
96 const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
97                                                     uint32_t id)
98 {
99         struct dsdb_class *cur;
100
101         /*
102          * 0xFFFFFFFF is used as value when no mapping table is available,
103          * so don't try to match with it
104          */
105         if (id == 0xFFFFFFFF) return NULL;
106
107         /* TODO: add binary search */
108         for (cur = schema->classes; cur; cur = cur->next) {
109                 if (cur->governsID_id != id) continue;
110
111                 return cur;
112         }
113
114         return NULL;
115 }
116
117 const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
118                                                      const char *oid)
119 {
120         struct dsdb_class *cur;
121
122         if (!oid) return NULL;
123
124         /* TODO: add binary search */
125         for (cur = schema->classes; cur; cur = cur->next) {
126                 if (strcmp(cur->governsID_oid, oid) != 0) continue;
127
128                 return cur;
129         }
130
131         return NULL;
132 }
133
134 const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
135                                                        const char *name)
136 {
137         struct dsdb_class *cur;
138
139         if (!name) return NULL;
140
141         /* TODO: add binary search */
142         for (cur = schema->classes; cur; cur = cur->next) {
143                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
144
145                 return cur;
146         }
147
148         return NULL;
149 }
150
151 const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
152                                           const char *cn)
153 {
154         struct dsdb_class *cur;
155
156         if (!cn) return NULL;
157
158         /* TODO: add binary search */
159         for (cur = schema->classes; cur; cur = cur->next) {
160                 if (strcasecmp(cur->cn, cn) != 0) continue;
161
162                 return cur;
163         }
164
165         return NULL;
166 }
167
168 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
169                                        uint32_t id)
170 {
171         const struct dsdb_attribute *a;
172         const struct dsdb_class *c;
173
174         /* TODO: add binary search */
175         a = dsdb_attribute_by_attributeID_id(schema, id);
176         if (a) {
177                 return a->lDAPDisplayName;
178         }
179
180         c = dsdb_class_by_governsID_id(schema, id);
181         if (c) {
182                 return c->lDAPDisplayName;
183         }
184
185         return NULL;
186 }
187
188 /** 
189     Return a list of linked attributes, in lDAPDisplayName format.
190
191     This may be used to determine if a modification would require
192     backlinks to be updated, for example
193 */
194
195 WERROR dsdb_linked_attribute_lDAPDisplayName_list(const struct dsdb_schema *schema, TALLOC_CTX *mem_ctx, const char ***attr_list_ret)
196 {
197         const char **attr_list = NULL;
198         struct dsdb_attribute *cur;
199         int i = 0;
200         for (cur = schema->attributes; cur; cur = cur->next) {
201                 if (cur->linkID == 0) continue;
202                 
203                 attr_list = talloc_realloc(mem_ctx, attr_list, const char *, i+2);
204                 if (!attr_list) {
205                         return WERR_NOMEM;
206                 }
207                 attr_list[i] = cur->lDAPDisplayName;
208                 i++;
209         }
210         attr_list[i] = NULL;
211         *attr_list_ret = attr_list;
212         return WERR_OK;
213 }
214
215 char **merge_attr_list(TALLOC_CTX *mem_ctx, 
216                        char **attrs, const char **new_attrs) 
217 {
218         char **ret_attrs;
219         int i;
220         size_t new_len, orig_len = str_list_length((const char **)attrs);
221         if (!new_attrs) {
222                 return attrs;
223         }
224
225         ret_attrs = talloc_realloc(mem_ctx, 
226                                    attrs, char *, orig_len + str_list_length(new_attrs) + 1);
227         if (ret_attrs) {
228                 for (i=0; i < str_list_length(new_attrs); i++) {
229                         ret_attrs[orig_len + i] = new_attrs[i];
230                 }
231                 new_len = orig_len + str_list_length(new_attrs);
232
233                 ret_attrs[new_len] = NULL;
234         }
235
236         return ret_attrs;
237 }
238
239 /*
240   Return a merged list of the attributes of exactly one class (not
241   considering subclasses, auxillary classes etc)
242 */
243
244 char **dsdb_attribute_list(TALLOC_CTX *mem_ctx, const struct dsdb_class *class, enum dsdb_attr_list_query query)
245 {
246         char **attr_list = NULL;
247         switch (query) {
248         case DSDB_SCHEMA_ALL_MAY:
249                 attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
250                 attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
251                 break;
252                 
253         case DSDB_SCHEMA_ALL_MUST:
254                 attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
255                 attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
256                 break;
257                 
258         case DSDB_SCHEMA_SYS_MAY:
259                 attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
260                 break;
261                 
262         case DSDB_SCHEMA_SYS_MUST:
263                 attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
264                 break;
265                 
266         case DSDB_SCHEMA_MAY:
267                 attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
268                 break;
269                 
270         case DSDB_SCHEMA_MUST:
271                 attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
272                 break;
273                 
274         case DSDB_SCHEMA_ALL:
275                 attr_list = merge_attr_list(mem_ctx, attr_list, class->mayContain);
276                 attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMayContain);
277                 attr_list = merge_attr_list(mem_ctx, attr_list, class->mustContain);
278                 attr_list = merge_attr_list(mem_ctx, attr_list, class->systemMustContain);
279                 break;
280         }
281         return attr_list;
282 }
283
284 static char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx, 
285                                                 const struct dsdb_schema *schema, 
286                                                 const char **class_list,
287                                                 enum dsdb_attr_list_query query)
288 {
289         int i;
290         const struct dsdb_class *class;
291         
292         char **attr_list = NULL;
293         char **this_class_list;
294         char **recursive_list;
295
296         for (i=0; class_list && class_list[i]; i++) {
297                 class = dsdb_class_by_lDAPDisplayName(schema, class_list[i]);
298                 
299                 this_class_list = dsdb_attribute_list(mem_ctx, class, query);
300                 attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)this_class_list);
301
302                 recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, 
303                                                                    class->systemAuxiliaryClass, 
304                                                                    query);
305                 
306                 attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list);
307                 
308                 recursive_list = dsdb_full_attribute_list_internal(mem_ctx, schema, 
309                                                                    class->auxiliaryClass, 
310                                                                    query);
311                 
312                 attr_list = merge_attr_list(mem_ctx, attr_list, (const char **)recursive_list);
313                 
314         }
315         return attr_list;
316 }
317
318 char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx, 
319                                 const struct dsdb_schema *schema, 
320                                 const char **class_list,
321                                 enum dsdb_attr_list_query query)
322 {
323         char **attr_list = dsdb_full_attribute_list_internal(mem_ctx, schema, class_list, query);
324         size_t new_len = str_list_length((const char **)attr_list);
325
326         /* Remove duplicates */
327         if (new_len > 1) {
328                 int i;
329                 qsort(attr_list, new_len,
330                       sizeof(*attr_list),
331                       (comparison_fn_t)strcasecmp);
332                 
333                 for (i=1 ; i < new_len; i++) {
334                         char **val1 = &attr_list[i-1];
335                         char **val2 = &attr_list[i];
336                         if (ldb_attr_cmp(*val1, *val2) == 0) {
337                                 memmove(val1, val2, (new_len - i) * sizeof( *attr_list)); 
338                                 new_len--;
339                                 i--;
340                         }
341                 }
342         }
343         return attr_list;
344 }