1 /* -*- show-trailing-whitespace: t; indent-tabs: t -*-
2 * Copyright (c) 2003,2004,2005,2006 David Lichteblau
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include "common.h"
19
20 t_print_binary_mode print_binary_mode = PRINT_UTF8;
21
22 static void
write_backslashed(FILE * s,char * ptr,int n)23 write_backslashed(FILE *s, char *ptr, int n)
24 {
25 int i;
26 for (i = 0; i < n; i++) {
27 char c = ptr[i];
28 if (c == '\n' || c == '\\') fputc('\\', s);
29 fputc(c, s);
30 }
31 if (ferror(s)) syserr();
32 }
33
34 static int
utf8_string_p(unsigned char * str,int n)35 utf8_string_p(unsigned char *str, int n)
36 {
37 int i = 0;
38 while (i < n) {
39 unsigned char c = str[i++];
40 if (c >= 0xfe)
41 return 0;
42 if (c >= 0xfc) {
43 unsigned char d;
44 if ((n - i < 5)
45 || ((d=str[i++]) ^ 0x80) >= 0x40
46 || (str[i++] ^ 0x80) >= 0x40
47 || (str[i++] ^ 0x80) >= 0x40
48 || (str[i++] ^ 0x80) >= 0x40
49 || (str[i++] ^ 0x80) >= 0x40
50 || (c < 0xfd && d < 0x84))
51 return 0;
52 } else if (c >= 0xf8) {
53 unsigned char d;
54 if ((n - i < 4)
55 || ((d=str[i++]) ^ 0x80) >= 0x40
56 || (str[i++] ^ 0x80) >= 0x40
57 || (str[i++] ^ 0x80) >= 0x40
58 || (str[i++] ^ 0x80) >= 0x40
59 || (c < 0xf9 && d < 0x88))
60 return 0;
61 } else if (c >= 0xf0) {
62 unsigned char d;
63 if ((n - i < 3)
64 || ((d=str[i++]) ^ 0x80) >= 0x40
65 || (str[i++] ^ 0x80) >= 0x40
66 || (str[i++] ^ 0x80) >= 0x40
67 || (c < 0xf1 && d < 0x90))
68 return 0;
69 } else if (c >= 0xe0) {
70 unsigned char d, e;
71 unsigned code;
72 if ((n - i < 2)
73 || ((d=str[i++]) ^ 0x80) >= 0x40
74 || ((e=str[i++]) ^ 0x80) >= 0x40
75 || (c < 0xe1 && d < 0xa0))
76 return 0;
77 code = ((int) c & 0x0f) << 12
78 | ((int) d ^ 0x80) << 6
79 | ((int) e ^ 0x80);
80 if ((0xd800 <= code) && (code <= 0xdfff)
81 || code == 0xfffe || code == 0xffff)
82 return 0;
83 } else if (c >= 0x80) {
84 unsigned char d;
85 if ((n - i < 1)
86 || ((d=str[i++]) ^ 0x80) >= 0x40
87 || (c < 0xc2))
88 return 0;
89 } else if (c == 0)
90 return 0;
91 }
92 return 1;
93 }
94
95 static int
readable_string_p(char * str,int n)96 readable_string_p(char *str, int n)
97 {
98 int i;
99 for (i = 0; i < n; i++) {
100 char c = str[i];
101 if (c < 32 && c != '\n' && c != '\t')
102 return 0;
103 }
104 return 1;
105 }
106
107 static int
safe_string_p(char * str,int n)108 safe_string_p(char *str, int n)
109 {
110 unsigned char c;
111 int i;
112
113 if (n == 0) return 1;
114
115 c = str[0];
116 if ((c == ' ') || (c == ':') || (c == '<'))
117 return 0;
118
119 for (i = 0; i < n; i++) {
120 c = str[i];
121 if ((c == '\0') || (c == '\r') || (c == '\n') || (c >= 0x80))
122 return 0;
123 }
124 return 1;
125 }
126
127 static void
print_attrval(FILE * s,char * str,int len,int prefernocolon)128 print_attrval(FILE *s, char *str, int len, int prefernocolon)
129 {
130 int readablep;
131 switch (print_binary_mode) {
132 case PRINT_ASCII:
133 readablep = readable_string_p(str, len);
134 break;
135 case PRINT_UTF8:
136 readablep = utf8_string_p((unsigned char *) str, len);
137 break;
138 case PRINT_JUNK:
139 readablep = 1;
140 break;
141 default:
142 abort();
143 }
144
145 if (!readablep) {
146 fputs(":: ", s);
147 print_base64((unsigned char *) str, len, s);
148 } else if (prefernocolon) {
149 fputc(' ', s);
150 write_backslashed(s, str, len);
151 } else if (!safe_string_p(str, len)) {
152 fputs(":; ", s);
153 write_backslashed(s, str, len);
154 } else {
155 fputs(": ", s);
156 fwrite(str, 1, len, s);
157 }
158 }
159
160 static void
print_attribute(FILE * s,tattribute * attribute)161 print_attribute(FILE *s, tattribute *attribute)
162 {
163 GPtrArray *values = attribute_values(attribute);
164 int j;
165
166 for (j = 0; j < values->len; j++) {
167 GArray *av = g_ptr_array_index(values, j);
168 fputs(attribute_ad(attribute), s);
169 print_attrval(s, av->data, av->len, 0);
170 fputc('\n', s);
171 }
172 if (ferror(s)) syserr();
173 }
174
175 static void
print_entroid_bottom(FILE * s,tentroid * entroid)176 print_entroid_bottom(FILE *s, tentroid *entroid)
177 {
178 int i;
179 LDAPAttributeType *at;
180 for (i = 0; i < entroid->must->len; i++) {
181 at = g_ptr_array_index(entroid->must, i);
182 fprintf(s, "# required attribute not shown: %s\n",
183 attributetype_name(at));
184 }
185 for (i = 0; i < entroid->may->len; i++) {
186 at = g_ptr_array_index(entroid->may, i);
187 fprintf(s, "#%s: \n", attributetype_name(at));
188 }
189 }
190
191 void
print_ldapvi_entry(FILE * s,tentry * entry,char * key,tentroid * entroid)192 print_ldapvi_entry(FILE *s, tentry *entry, char *key, tentroid *entroid)
193 {
194 GPtrArray *attributes = entry_attributes(entry);
195 int i;
196
197 fputc('\n', s);
198 fputs(key ? key : "entry", s);
199 fputc(' ', s);
200 fputs(entry_dn(entry), s);
201 fputc('\n', s);
202 if (ferror(s)) syserr();
203
204 if (entroid)
205 fputs(entroid->comment->str, s);
206 for (i = 0; i < attributes->len; i++) {
207 tattribute *attribute = g_ptr_array_index(attributes, i);
208 char *ad = attribute_ad(attribute);
209 if ( entroid && !entroid_remove_ad(entroid, ad))
210 fprintf(s, "# WARNING: %s not allowed by schema\n",
211 ad);
212 print_attribute(s, attribute);
213 }
214 if (entroid)
215 print_entroid_bottom(s, entroid);
216 }
217
218 static void
print_ldapvi_ldapmod(FILE * s,LDAPMod * mod)219 print_ldapvi_ldapmod(FILE *s, LDAPMod *mod)
220 {
221 struct berval **values = mod->mod_bvalues;
222
223 switch (mod->mod_op & ~LDAP_MOD_BVALUES) {
224 case LDAP_MOD_ADD: fputs("add", s); break;
225 case LDAP_MOD_DELETE: fputs("delete", s); break;
226 case LDAP_MOD_REPLACE: fputs("replace", s); break;
227 default: abort();
228 }
229 print_attrval(s, mod->mod_type, strlen(mod->mod_type), 0);
230 fputc('\n', s);
231 for (; *values; values++) {
232 struct berval *value = *values;
233 print_attrval(s, value->bv_val, value->bv_len, 0);
234 fputc('\n', s);
235 }
236 if (ferror(s)) syserr();
237 }
238
239 void
print_ldapvi_modify(FILE * s,char * dn,LDAPMod ** mods)240 print_ldapvi_modify(FILE *s, char *dn, LDAPMod **mods)
241 {
242 fputs("\nmodify", s);
243 print_attrval(s, dn, strlen(dn), 1);
244 fputc('\n', s);
245
246 for (; *mods; mods++)
247 print_ldapvi_ldapmod(s, *mods);
248 if (ferror(s)) syserr();
249 }
250
251 void
print_ldapvi_rename(FILE * s,char * olddn,char * newdn,int deleteoldrdn)252 print_ldapvi_rename(FILE *s, char *olddn, char *newdn, int deleteoldrdn)
253 {
254 fputs("\nrename", s);
255 print_attrval(s, olddn, strlen(olddn), 1);
256 fputs(deleteoldrdn ? "\nreplace" : "\nadd", s);
257 print_attrval(s, newdn, strlen(newdn), 0);
258 fputc('\n', s);
259 if (ferror(s)) syserr();
260 }
261
262 static GString *
rdns2gstring(char ** ptr)263 rdns2gstring(char **ptr)
264 {
265 GString *result = g_string_new("");
266 if (*ptr)
267 g_string_append(result, *ptr);
268 ptr++;
269 for (; *ptr; ptr++) {
270 g_string_append_c(result, ',');
271 g_string_append(result, *ptr);
272 }
273 return result;
274 }
275
276 /* simple version of _rename without new superior */
277 void
print_ldapvi_modrdn(FILE * s,char * olddn,char * newrdn,int deleteoldrdn)278 print_ldapvi_modrdn(FILE *s, char *olddn, char *newrdn, int deleteoldrdn)
279 {
280 char **newrdns = ldap_explode_dn(olddn, 0);
281 GString *newdn;
282 char *tmp;
283
284 fputs("\nrename", s);
285 print_attrval(s, olddn, strlen(olddn), 1);
286 fputs(deleteoldrdn ? "\nreplace" : "\nadd", s);
287
288 /* fixme, siehe notes */
289 tmp = *newrdns;
290 *newrdns = newrdn;
291 newdn = rdns2gstring(newrdns);
292 print_attrval(s, newdn->str, newdn->len, 0);
293 fputc('\n', s);
294 g_string_free(newdn, 1);
295 *newrdns = tmp;
296
297 if (ferror(s)) syserr();
298 ldap_value_free(newrdns);
299 }
300
301 void
print_ldapvi_add(FILE * s,char * dn,LDAPMod ** mods)302 print_ldapvi_add(FILE *s, char *dn, LDAPMod **mods)
303 {
304 fputs("\nadd", s);
305 print_attrval(s, dn, strlen(dn), 1);
306 fputc('\n', s);
307
308 for (; *mods; mods++) {
309 LDAPMod *mod = *mods;
310 struct berval **values = mod->mod_bvalues;
311 for (; *values; values++) {
312 struct berval *value = *values;
313 fputs(mod->mod_type, s);
314 print_attrval(s, value->bv_val, value->bv_len, 0);
315 fputc('\n', s);
316 }
317 }
318 if (ferror(s)) syserr();
319 }
320
321 void
print_ldapvi_delete(FILE * s,char * dn)322 print_ldapvi_delete(FILE *s, char *dn)
323 {
324 fputs("\ndelete", s);
325 print_attrval(s, dn, strlen(dn), 1);
326 fputc('\n', s);
327 if (ferror(s)) syserr();
328 }
329
330 static void
print_ldif_line(FILE * s,char * ad,char * str,int len)331 print_ldif_line(FILE *s, char *ad, char *str, int len)
332 {
333 if (len == -1)
334 len = strlen(str);
335 fputs(ad, s);
336 if (safe_string_p(str, len)) {
337 fputs(": ", s);
338 fwrite(str, len, 1, s);
339 } else {
340 fputs(":: ", s);
341 print_base64((unsigned char *) str, len, s);
342 }
343 fputs("\n", s);
344 }
345
346 static void
print_ldif_bervals(FILE * s,char * ad,struct berval ** values)347 print_ldif_bervals(FILE *s, char *ad, struct berval **values)
348 {
349 for (; *values; values++) {
350 struct berval *value = *values;
351 print_ldif_line(s, ad, value->bv_val, value->bv_len);
352 }
353 if (ferror(s)) syserr();
354 }
355
356 void
print_ldif_modify(FILE * s,char * dn,LDAPMod ** mods)357 print_ldif_modify(FILE *s, char *dn, LDAPMod **mods)
358 {
359 fputc('\n', s);
360 print_ldif_line(s, "dn", dn, -1);
361 fputs("changetype: modify\n", s);
362
363 for (; *mods; mods++) {
364 LDAPMod *mod = *mods;
365
366 switch (mod->mod_op & ~LDAP_MOD_BVALUES) {
367 case LDAP_MOD_ADD: fputs("add: ", s); break;
368 case LDAP_MOD_DELETE: fputs("delete: ", s); break;
369 case LDAP_MOD_REPLACE: fputs("replace: ", s); break;
370 default: abort();
371 }
372 fputs(mod->mod_type, s);
373 fputc('\n', s);
374
375 print_ldif_bervals(s, mod->mod_type, mod->mod_bvalues);
376 fputs("-\n", s);
377 }
378 if (ferror(s)) syserr();
379 }
380
381 void
print_ldif_add(FILE * s,char * dn,LDAPMod ** mods)382 print_ldif_add(FILE *s, char *dn, LDAPMod **mods)
383 {
384 fputc('\n', s);
385 print_ldif_line(s, "dn", dn, -1);
386 fputs("changetype: add\n", s);
387
388 for (; *mods; mods++) {
389 LDAPMod *mod = *mods;
390 print_ldif_bervals(s, mod->mod_type, mod->mod_bvalues);
391 }
392 if (ferror(s)) syserr();
393 }
394
395 void
print_ldif_rename(FILE * s,char * olddn,char * newdn,int deleteoldrdn)396 print_ldif_rename(FILE *s, char *olddn, char *newdn, int deleteoldrdn)
397 {
398 char **newrdns = ldap_explode_dn(newdn, 0);
399 int isRootDSE = !*newrdns;
400 GString *sup;
401
402 fputc('\n', s);
403 print_ldif_line(s, "dn", olddn, -1);
404 fputs("changetype: modrdn\n", s);
405
406 print_ldif_line(s, "newrdn", isRootDSE ? "" : *newrdns, -1);
407
408 fprintf(s, "deleteoldrdn: %d\n", !!deleteoldrdn);
409
410 if (isRootDSE || !newrdns[1])
411 fputs("newsuperior:\n", s);
412 else {
413 sup = rdns2gstring(newrdns + 1);
414 print_ldif_line(s, "newsuperior", sup->str, sup->len);
415 g_string_free(sup, 1);
416 }
417
418 if (ferror(s)) syserr();
419 ldap_value_free(newrdns);
420 }
421
422 /* simple version of _rename without new superior */
423 void
print_ldif_modrdn(FILE * s,char * olddn,char * newrdn,int deleteoldrdn)424 print_ldif_modrdn(FILE *s, char *olddn, char *newrdn, int deleteoldrdn)
425 {
426 fputc('\n', s);
427 print_ldif_line(s, "dn", olddn, -1);
428 fputs("changetype: modrdn\n", s);
429 print_ldif_line(s, "newrdn", newrdn, -1);
430 fprintf(s, "deleteoldrdn: %d\n", !!deleteoldrdn);
431 if (ferror(s)) syserr();
432 }
433
434 void
print_ldif_delete(FILE * s,char * dn)435 print_ldif_delete(FILE *s, char *dn)
436 {
437 fputc('\n', s);
438 print_ldif_line(s, "dn", dn, -1);
439 fputs("changetype: delete\n", s);
440 if (ferror(s)) syserr();
441 }
442
443 void
print_ldapvi_message(FILE * s,LDAP * ld,LDAPMessage * entry,int key,tentroid * entroid)444 print_ldapvi_message(FILE *s, LDAP *ld, LDAPMessage *entry, int key,
445 tentroid *entroid)
446 {
447 char *dn, *ad;
448 BerElement *ber;
449
450 fprintf(s, "\n%d", key);
451 dn = ldap_get_dn(ld, entry);
452 print_attrval(s, dn, strlen(dn), 1);
453 ldap_memfree(dn);
454 fputc('\n', s);
455 if (entroid)
456 fputs(entroid->comment->str, s);
457
458 for (ad = ldap_first_attribute(ld, entry, &ber);
459 ad;
460 ad = ldap_next_attribute(ld, entry, ber))
461 {
462 struct berval **values = ldap_get_values_len(ld, entry, ad);
463 struct berval **ptr;
464
465 if (!values) continue;
466 if (entroid)
467 entroid_remove_ad(entroid, ad);
468
469 for (ptr = values; *ptr; ptr++) {
470 fputs(ad, s);
471 print_attrval(s, (*ptr)->bv_val, (*ptr)->bv_len, 0);
472 fputc('\n', s);
473 }
474 ldap_memfree(ad);
475 ldap_value_free_len(values);
476 }
477 ber_free(ber, 0);
478
479 if (entroid)
480 print_entroid_bottom(s, entroid);
481 if (ferror(s)) syserr();
482 }
483
484 void
print_ldif_entry(FILE * s,tentry * entry,char * key,tentroid * entroid)485 print_ldif_entry(FILE *s, tentry *entry, char *key, tentroid *entroid)
486 {
487 int i;
488 GPtrArray *attributes = entry_attributes(entry);
489
490 fputc('\n', s);
491 print_ldif_line(s, "dn", entry_dn(entry), -1);
492 if (key)
493 fprintf(s, "ldapvi-key: %s\n", key);
494 if (entroid)
495 fputs(entroid->comment->str, s);
496 for (i = 0; i < attributes->len; i++) {
497 tattribute *attribute = g_ptr_array_index(attributes, i);
498 char *ad = attribute_ad(attribute);
499 GPtrArray *values = attribute_values(attribute);
500 int j;
501
502 if ( entroid && !entroid_remove_ad(entroid, ad))
503 fprintf(s, "# WARNING: %s not allowed by schema\n",
504 ad);
505
506 for (j = 0; j < values->len; j++) {
507 GArray *av = g_ptr_array_index(values, j);
508 print_ldif_line(s, ad, av->data, av->len);
509 }
510 }
511 if (entroid)
512 print_entroid_bottom(s, entroid);
513 }
514
515 void
print_ldif_message(FILE * s,LDAP * ld,LDAPMessage * entry,int key,tentroid * entroid)516 print_ldif_message(FILE *s, LDAP *ld, LDAPMessage *entry, int key,
517 tentroid *entroid)
518 {
519 char *dn, *ad;
520 BerElement *ber;
521
522 fputc('\n', s);
523 if (entroid)
524 fputs(entroid->comment->str, s);
525
526 dn = ldap_get_dn(ld, entry);
527 print_ldif_line(s, "dn", dn, -1);
528 ldap_memfree(dn);
529
530 if (key != -1)
531 fprintf(s, "ldapvi-key: %d\n", key);
532
533 for (ad = ldap_first_attribute(ld, entry, &ber);
534 ad;
535 ad = ldap_next_attribute(ld, entry, ber))
536 {
537 struct berval **values = ldap_get_values_len(ld, entry, ad);
538 if (entroid) entroid_remove_ad(entroid, ad);
539 print_ldif_bervals(s, ad, values);
540 ldap_memfree(ad);
541 ldap_value_free_len(values);
542 }
543 ber_free(ber, 0);
544
545 if (entroid)
546 print_entroid_bottom(s, entroid);
547 if (ferror(s)) syserr();
548 }
549