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