r5037: got rid of all of the TALLOC_DEPRECATED stuff. My apologies for the
[ira/wip.git] / source4 / ldap_server / ldap_parse.c
1 /* 
2    Unix SMB/CIFS implementation.
3    LDAP server
4    Copyright (C) Simo Sorce 2004
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "ldap_parse.h"
23
24 static char char_from_hex(char a, char b) {
25         char m, l;
26
27         if ('0' <= a  && a <= '9') {
28                 m = a - '0';
29         } else if ('A' <= a && a <= 'F') {
30                 m = 10 + (a - 'A');
31         } else if ('a' <= a && a <= 'f') {
32                 m = 10 + (a - 'a');
33         } else {
34                 return a;
35         }
36
37         if ('0' <= b  && b <= '9') {
38                 l = b - '0';
39         } else if ('A' <= b && b <= 'F') {
40                 l = 10 + (b - 'A');
41         } else if ('a' <= b && b <= 'f') {
42                 l = 10 + (b - 'a');
43         } else {
44                 return a;
45         }
46
47         return ((m << 4) + l);
48 }
49
50 static char *parse_slash(char *p, char *end) {
51         switch (*(p + 1)) {
52         case ',':
53         case '=':
54         case '\n':
55         case '+':
56         case '<':
57         case '>':
58         case '#':
59         case ';':
60         case '\\':
61         case '"':
62                 memmove(p, p + 1, end - (p + 1));
63                 return (end - 1);
64         default:
65                 *p = char_from_hex(*(p + 1), *(p + 2));
66                 memmove(p + 1, p + 3, end - (p + 3));
67                 return (end - 2);
68         }
69 }
70
71 #define LDAP_PARSE_DN_INVALID(x) do {\
72         if (x) { \
73                 dn->comp_num = -1; \
74                 return dn; \
75         } \
76 } while(0)
77
78 #if 0
79 static void ldap_parse_attributetypedescription(struct ldap_schema *schema, DATA_BLOB *data)
80 {
81         char *desc;
82
83         desc = talloc_array(schema, char, data->lenght + 1);
84         memcpy(desc, data->data, data->lenght);
85         desc[data->lenght] = '\0';
86
87 }
88
89 static void ldap_parse_objectclassdescription(struct ldap_schema *schema, DATA_BLOB *data)
90 {
91         char *desc;
92
93         desc = talloc_array(schema, char, data->lenght + 1);
94         memcpy(desc, data->data, data->lenght);
95         desc[data->lenght] = '\0';
96
97 }
98
99 static struct ldap_schema *ldap_get_schema(void *mem_ctx, struct ldap_schema *schema, struct ldb_context *ldb)
100 {
101         NTSTATUS status;
102         struct ldap_schema *local_schema;
103         struct ldb_message **res;
104         const char *errstr;
105         const char *schema_dn = "cn=schema";
106         const char *attr_filter = "attributeTypeDescription=*";
107         const char *class_filter = "objectClassDescription=*";
108         const char *attrs = "attributeTypeDescription";
109         const char *classes = "objectClassDescription";
110         enum ldb_scope scope = LDAP_SCOPE_SUBTREE;
111         int count, i, j, k;
112
113         local_schema = schema;
114         if (local_schema == NULL) {
115                 local_schema = talloc(mem_ctx, struct ldap_schema);
116                 ALLOC_CHECK(local_schema);
117         }
118
119         count = ldb_search(ldb, schema_dn, scope, attr_filter, attrs, &res);
120
121         for (i = 0; i < count; i++) {
122                 if (res[i]->num_elements == 0) {
123                         goto attr_done;
124                 }
125                 for (j = 0; j < res[i]->num_elements; j++) {
126                         for (k = 0; res[i]->elements[j].num_values; k++) {
127                                 ldap_parse_attributetypedescription(local_schema, &(res[i]->elements[j].values[k]));
128                         }
129                 }
130 attr_done:
131         }
132
133         count = ldb_search(ldb, schema_dn, scope, class_filter, classes, &res);
134
135         for (i = 0; i < count; i++) {
136                 if (res[i]->num_elements == 0) {
137                         goto class_done;
138                 }
139                 for (j = 0; j < res[i]->num_elements; j++) {
140                         for (k = 0; res[i]->elements[j].num_values; k++) {
141                                 ldap_parse_objectclassdescription(local_schema, &(res[i]->elements[j].values[k]));
142                         }
143                 }
144 class_done:
145         }
146
147         return local_schema;
148 }
149 #endif
150
151 struct ldap_dn *ldap_parse_dn(void *mem_ctx, const char *orig_dn)
152 {
153         struct ldap_dn *dn;
154         struct dn_component *component;
155         struct dn_attribute *attribute;
156         char *p, *start, *separator, *src, *dest, *dn_copy, *dn_end;
157         int i, size, orig_len;
158
159         dn = talloc(mem_ctx, struct ldap_dn);
160         dn->comp_num = 0;
161         dn->components = talloc_array(dn, struct dn_component *, 1);
162         component = talloc(dn, struct dn_component);
163         component->attr_num = 0;
164
165         orig_len = strlen(orig_dn);
166         if (orig_len == 0) {
167                 dn->dn = talloc_strdup(dn, orig_dn);
168                 return dn;
169         }
170
171         dn_copy = p = talloc_strdup(mem_ctx, orig_dn);
172         dn_end = dn_copy + orig_len + 1;
173         do {
174                 component->attributes = talloc_array(component, struct dn_attribute *, 1);
175                 attribute = talloc(component, struct dn_attribute);
176
177                 /* skip "spaces" */
178                 while (*p == ' ' || *p == '\n') {
179                         p++;
180                 }
181
182                 /* start parsing this component */
183                 do {
184                         start = p;
185
186                         /* find out key separator '=' */
187                         while (*p && *p != '=') {
188                                 if (*p == '\\') {
189                                         dn_end = parse_slash(p, dn_end);
190                                 }
191                                 p++;
192                         }
193                         separator = p;
194
195                         /* remove spaces */
196                         while (*(p - 1) == ' ' || *(p - 1) == '\n') {
197                                 p--;
198                         }
199
200                         /* save key name */
201                         LDAP_PARSE_DN_INVALID((p - start) < 1);
202                         attribute->name = talloc_strndup(attribute, start, p - start);
203                         DEBUG(10, ("attribute name: [%s]\n", attribute->name));
204
205                         p = separator + 1;
206
207                         /* skip spaces past the separator */
208                         p = separator + strspn(p, " \n") + 1;
209                         start = p;
210
211                         /* check if the value is enclosed in QUOTATION */
212                         if (*p == '"') {
213                                 start = p + 1;
214                                 while (*p && *p != '"') {
215                                         if (*p == '\\') {
216                                                 dn_end = parse_slash(p, dn_end);
217                                         }
218                                         p++;
219                                 }
220
221                                 /* skip spaces until the separator */
222                                 separator = p + strspn(p, " \n");
223
224                                 if (*separator != ',' && *separator != ';' && *separator != '+') { /* there must be a separator here */
225                                         /* Error Malformed DN */
226                                         DEBUG (0, ("Error: Malformed DN!\n"));
227                                         break;
228                                 }
229                         } else {
230                                 while (*p && !(*p == ',' || *p == ';' || *p == '+')) {
231                                         if (*p == '\\') {
232                                                 dn_end = parse_slash(p, dn_end);
233                                         }
234                                         p++;
235                                 } /* found separator */
236
237                                 separator = p;
238
239                                 /* remove spaces */
240                                 while (*(p - 1) == ' ' || *(p - 1) == '\n') {
241                                         p--;
242                                 }
243                         }
244
245                         /* save the value */
246                         LDAP_PARSE_DN_INVALID((p - start) < 1);
247                         attribute->value = talloc_strndup(attribute, start, p - start);
248                         DEBUG(10, ("attribute value: [%s]\n", attribute->value));
249
250                         attribute->attribute = talloc_asprintf(attribute,"%s=%s", attribute->name, attribute->value);
251                         DEBUG(10, ("attribute: [%s]\n", attribute->attribute));
252
253                         /* save the attribute */
254                         component->attributes[component->attr_num] = attribute;
255                         component->attr_num++;
256
257                         if (*separator == '+') { /* expect other attributes in this component */
258                                 component->attributes = talloc_realloc(component, component->attributes, struct dn_attribute *, component->attr_num + 1);
259
260                                 /* allocate new attribute structure */
261                                 attribute = talloc(component, struct dn_attribute);
262
263                                 /* skip spaces past the separator */
264                                 p = separator + strspn(p, " \n");
265                         }
266
267                 } while (*separator == '+');
268
269                 /* found component bounds */
270                 for (i = 0, size = 0; i < component->attr_num; i++) {
271                         size = size + strlen(component->attributes[i]->attribute) + 1;
272                 }
273
274                 /* rebuild the normlaized component and put it here */
275                 component->component = dest = talloc_size(component, size);
276                 for (i = 0; i < component->attr_num; i++) {
277                         if (i != 0) {
278                                 *dest = '+';
279                                 dest++;
280                         }
281                         src = component->attributes[i]->attribute;
282                         do {
283                                 *(dest++) = *(src++);
284                         } while(*src);
285                         *dest = '\0';
286                 }
287                 DEBUG(10, ("component: [%s]\n", component->component));
288
289                 dn->components[dn->comp_num] = component;
290                 dn->comp_num++;
291
292                 if (*separator == ',' || *separator == ';') {
293                         dn->components = talloc_realloc(dn, dn->components, struct dn_component *, dn->comp_num + 1);
294                         component = talloc(dn, struct dn_component);
295                         component->attr_num = 0;
296                 }
297                 p = separator + 1;
298
299         } while(*separator == ',' || *separator == ';');
300
301         for (i = 0, size = 0; i < dn->comp_num; i++) {
302                 size = size + strlen(dn->components[i]->component) + 1;
303         }
304
305         /* rebuild the normlaized dn and put it here */
306         dn->dn = dest = talloc_size(dn, size);
307         for (i = 0; i < dn->comp_num; i++) {
308                 if (i != 0) {
309                         *dest = ',';
310                         dest++;
311                 }
312                 src = dn->components[i]->component;
313                 do {
314                         *(dest++) = *(src++);
315                 } while(*src);
316                 *dest = '\0';
317         }
318         DEBUG(10, ("dn: [%s]\n", dn->dn));
319
320         talloc_free(dn_copy);
321
322         return dn;
323 }