/* -*- show-trailing-whitespace: t; indent-tabs: t -*- * Copyright (c) 2003,2004,2005,2006 David Lichteblau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" t_print_binary_mode print_binary_mode = PRINT_UTF8; static void write_backslashed(FILE *s, char *ptr, int n) { int i; for (i = 0; i < n; i++) { char c = ptr[i]; if (c == '\n' || c == '\\') fputc('\\', s); fputc(c, s); } if (ferror(s)) syserr(); } static int utf8_string_p(unsigned char *str, int n) { int i = 0; while (i < n) { unsigned char c = str[i++]; if (c >= 0xfe) return 0; if (c >= 0xfc) { unsigned char d; if ((n - i < 5) || ((d=str[i++]) ^ 0x80) >= 0x40 || (str[i++] ^ 0x80) >= 0x40 || (str[i++] ^ 0x80) >= 0x40 || (str[i++] ^ 0x80) >= 0x40 || (str[i++] ^ 0x80) >= 0x40 || (c < 0xfd && d < 0x84)) return 0; } else if (c >= 0xf8) { unsigned char d; if ((n - i < 4) || ((d=str[i++]) ^ 0x80) >= 0x40 || (str[i++] ^ 0x80) >= 0x40 || (str[i++] ^ 0x80) >= 0x40 || (str[i++] ^ 0x80) >= 0x40 || (c < 0xf9 && d < 0x88)) return 0; } else if (c >= 0xf0) { unsigned char d; if ((n - i < 3) || ((d=str[i++]) ^ 0x80) >= 0x40 || (str[i++] ^ 0x80) >= 0x40 || (str[i++] ^ 0x80) >= 0x40 || (c < 0xf1 && d < 0x90)) return 0; } else if (c >= 0xe0) { unsigned char d, e; unsigned code; if ((n - i < 2) || ((d=str[i++]) ^ 0x80) >= 0x40 || ((e=str[i++]) ^ 0x80) >= 0x40 || (c < 0xe1 && d < 0xa0)) return 0; code = ((int) c & 0x0f) << 12 | ((int) d ^ 0x80) << 6 | ((int) e ^ 0x80); if ((0xd800 <= code) && (code <= 0xdfff) || code == 0xfffe || code == 0xffff) return 0; } else if (c >= 0x80) { unsigned char d; if ((n - i < 1) || ((d=str[i++]) ^ 0x80) >= 0x40 || (c < 0xc2)) return 0; } else if (c == 0) return 0; } return 1; } static int readable_string_p(char *str, int n) { int i; for (i = 0; i < n; i++) { char c = str[i]; if (c < 32 && c != '\n' && c != '\t') return 0; } return 1; } static int safe_string_p(char *str, int n) { unsigned char c; int i; if (n == 0) return 1; c = str[0]; if ((c == ' ') || (c == ':') || (c == '<')) return 0; for (i = 0; i < n; i++) { c = str[i]; if ((c == '\0') || (c == '\r') || (c == '\n') || (c >= 0x80)) return 0; } return 1; } static void print_attrval(FILE *s, char *str, int len, int prefernocolon) { int readablep; switch (print_binary_mode) { case PRINT_ASCII: readablep = readable_string_p(str, len); break; case PRINT_UTF8: readablep = utf8_string_p((unsigned char *) str, len); break; case PRINT_JUNK: readablep = 1; break; default: abort(); } if (!readablep) { fputs(":: ", s); print_base64((unsigned char *) str, len, s); } else if (prefernocolon) { fputc(' ', s); write_backslashed(s, str, len); } else if (!safe_string_p(str, len)) { fputs(":; ", s); write_backslashed(s, str, len); } else { fputs(": ", s); fwrite(str, 1, len, s); } } static void print_attribute(FILE *s, tattribute *attribute) { GPtrArray *values = attribute_values(attribute); int j; for (j = 0; j < values->len; j++) { GArray *av = g_ptr_array_index(values, j); fputs(attribute_ad(attribute), s); print_attrval(s, av->data, av->len, 0); fputc('\n', s); } if (ferror(s)) syserr(); } static void print_entroid_bottom(FILE *s, tentroid *entroid) { int i; LDAPAttributeType *at; for (i = 0; i < entroid->must->len; i++) { at = g_ptr_array_index(entroid->must, i); fprintf(s, "# required attribute not shown: %s\n", attributetype_name(at)); } for (i = 0; i < entroid->may->len; i++) { at = g_ptr_array_index(entroid->may, i); fprintf(s, "#%s: \n", attributetype_name(at)); } } void print_ldapvi_entry(FILE *s, tentry *entry, char *key, tentroid *entroid) { GPtrArray *attributes = entry_attributes(entry); int i; fputc('\n', s); fputs(key ? key : "entry", s); fputc(' ', s); fputs(entry_dn(entry), s); fputc('\n', s); if (ferror(s)) syserr(); if (entroid) fputs(entroid->comment->str, s); for (i = 0; i < attributes->len; i++) { tattribute *attribute = g_ptr_array_index(attributes, i); char *ad = attribute_ad(attribute); if ( entroid && !entroid_remove_ad(entroid, ad)) fprintf(s, "# WARNING: %s not allowed by schema\n", ad); print_attribute(s, attribute); } if (entroid) print_entroid_bottom(s, entroid); } static void print_ldapvi_ldapmod(FILE *s, LDAPMod *mod) { struct berval **values = mod->mod_bvalues; switch (mod->mod_op & ~LDAP_MOD_BVALUES) { case LDAP_MOD_ADD: fputs("add", s); break; case LDAP_MOD_DELETE: fputs("delete", s); break; case LDAP_MOD_REPLACE: fputs("replace", s); break; default: abort(); } print_attrval(s, mod->mod_type, strlen(mod->mod_type), 0); fputc('\n', s); for (; *values; values++) { struct berval *value = *values; print_attrval(s, value->bv_val, value->bv_len, 0); fputc('\n', s); } if (ferror(s)) syserr(); } void print_ldapvi_modify(FILE *s, char *dn, LDAPMod **mods) { fputs("\nmodify", s); print_attrval(s, dn, strlen(dn), 1); fputc('\n', s); for (; *mods; mods++) print_ldapvi_ldapmod(s, *mods); if (ferror(s)) syserr(); } void print_ldapvi_rename(FILE *s, char *olddn, char *newdn, int deleteoldrdn) { fputs("\nrename", s); print_attrval(s, olddn, strlen(olddn), 1); fputs(deleteoldrdn ? "\nreplace" : "\nadd", s); print_attrval(s, newdn, strlen(newdn), 0); fputc('\n', s); if (ferror(s)) syserr(); } static GString * rdns2gstring(char **ptr) { GString *result = g_string_new(""); if (*ptr) g_string_append(result, *ptr); ptr++; for (; *ptr; ptr++) { g_string_append_c(result, ','); g_string_append(result, *ptr); } return result; } /* simple version of _rename without new superior */ void print_ldapvi_modrdn(FILE *s, char *olddn, char *newrdn, int deleteoldrdn) { char **newrdns = ldap_explode_dn(olddn, 0); GString *newdn; char *tmp; fputs("\nrename", s); print_attrval(s, olddn, strlen(olddn), 1); fputs(deleteoldrdn ? "\nreplace" : "\nadd", s); /* fixme, siehe notes */ tmp = *newrdns; *newrdns = newrdn; newdn = rdns2gstring(newrdns); print_attrval(s, newdn->str, newdn->len, 0); fputc('\n', s); g_string_free(newdn, 1); *newrdns = tmp; if (ferror(s)) syserr(); ldap_value_free(newrdns); } void print_ldapvi_add(FILE *s, char *dn, LDAPMod **mods) { fputs("\nadd", s); print_attrval(s, dn, strlen(dn), 1); fputc('\n', s); for (; *mods; mods++) { LDAPMod *mod = *mods; struct berval **values = mod->mod_bvalues; for (; *values; values++) { struct berval *value = *values; fputs(mod->mod_type, s); print_attrval(s, value->bv_val, value->bv_len, 0); fputc('\n', s); } } if (ferror(s)) syserr(); } void print_ldapvi_delete(FILE *s, char *dn) { fputs("\ndelete", s); print_attrval(s, dn, strlen(dn), 1); fputc('\n', s); if (ferror(s)) syserr(); } static void print_ldif_line(FILE *s, char *ad, char *str, int len) { if (len == -1) len = strlen(str); fputs(ad, s); if (safe_string_p(str, len)) { fputs(": ", s); fwrite(str, len, 1, s); } else { fputs(":: ", s); print_base64((unsigned char *) str, len, s); } fputs("\n", s); } static void print_ldif_bervals(FILE *s, char *ad, struct berval **values) { for (; *values; values++) { struct berval *value = *values; print_ldif_line(s, ad, value->bv_val, value->bv_len); } if (ferror(s)) syserr(); } void print_ldif_modify(FILE *s, char *dn, LDAPMod **mods) { fputc('\n', s); print_ldif_line(s, "dn", dn, -1); fputs("changetype: modify\n", s); for (; *mods; mods++) { LDAPMod *mod = *mods; switch (mod->mod_op & ~LDAP_MOD_BVALUES) { case LDAP_MOD_ADD: fputs("add: ", s); break; case LDAP_MOD_DELETE: fputs("delete: ", s); break; case LDAP_MOD_REPLACE: fputs("replace: ", s); break; default: abort(); } fputs(mod->mod_type, s); fputc('\n', s); print_ldif_bervals(s, mod->mod_type, mod->mod_bvalues); fputs("-\n", s); } if (ferror(s)) syserr(); } void print_ldif_add(FILE *s, char *dn, LDAPMod **mods) { fputc('\n', s); print_ldif_line(s, "dn", dn, -1); fputs("changetype: add\n", s); for (; *mods; mods++) { LDAPMod *mod = *mods; print_ldif_bervals(s, mod->mod_type, mod->mod_bvalues); } if (ferror(s)) syserr(); } void print_ldif_rename(FILE *s, char *olddn, char *newdn, int deleteoldrdn) { char **newrdns = ldap_explode_dn(newdn, 0); int isRootDSE = !*newrdns; GString *sup; fputc('\n', s); print_ldif_line(s, "dn", olddn, -1); fputs("changetype: modrdn\n", s); print_ldif_line(s, "newrdn", isRootDSE ? "" : *newrdns, -1); fprintf(s, "deleteoldrdn: %d\n", !!deleteoldrdn); if (isRootDSE || !newrdns[1]) fputs("newsuperior:\n", s); else { sup = rdns2gstring(newrdns + 1); print_ldif_line(s, "newsuperior", sup->str, sup->len); g_string_free(sup, 1); } if (ferror(s)) syserr(); ldap_value_free(newrdns); } /* simple version of _rename without new superior */ void print_ldif_modrdn(FILE *s, char *olddn, char *newrdn, int deleteoldrdn) { fputc('\n', s); print_ldif_line(s, "dn", olddn, -1); fputs("changetype: modrdn\n", s); print_ldif_line(s, "newrdn", newrdn, -1); fprintf(s, "deleteoldrdn: %d\n", !!deleteoldrdn); if (ferror(s)) syserr(); } void print_ldif_delete(FILE *s, char *dn) { fputc('\n', s); print_ldif_line(s, "dn", dn, -1); fputs("changetype: delete\n", s); if (ferror(s)) syserr(); } void print_ldapvi_message(FILE *s, LDAP *ld, LDAPMessage *entry, int key, tentroid *entroid) { char *dn, *ad; BerElement *ber; fprintf(s, "\n%d", key); dn = ldap_get_dn(ld, entry); print_attrval(s, dn, strlen(dn), 1); ldap_memfree(dn); fputc('\n', s); if (entroid) fputs(entroid->comment->str, s); for (ad = ldap_first_attribute(ld, entry, &ber); ad; ad = ldap_next_attribute(ld, entry, ber)) { struct berval **values = ldap_get_values_len(ld, entry, ad); struct berval **ptr; if (!values) continue; if (entroid) entroid_remove_ad(entroid, ad); for (ptr = values; *ptr; ptr++) { fputs(ad, s); print_attrval(s, (*ptr)->bv_val, (*ptr)->bv_len, 0); fputc('\n', s); } ldap_memfree(ad); ldap_value_free_len(values); } ber_free(ber, 0); if (entroid) print_entroid_bottom(s, entroid); if (ferror(s)) syserr(); } void print_ldif_entry(FILE *s, tentry *entry, char *key, tentroid *entroid) { int i; GPtrArray *attributes = entry_attributes(entry); fputc('\n', s); print_ldif_line(s, "dn", entry_dn(entry), -1); if (key) fprintf(s, "ldapvi-key: %s\n", key); if (entroid) fputs(entroid->comment->str, s); for (i = 0; i < attributes->len; i++) { tattribute *attribute = g_ptr_array_index(attributes, i); char *ad = attribute_ad(attribute); GPtrArray *values = attribute_values(attribute); int j; if ( entroid && !entroid_remove_ad(entroid, ad)) fprintf(s, "# WARNING: %s not allowed by schema\n", ad); for (j = 0; j < values->len; j++) { GArray *av = g_ptr_array_index(values, j); print_ldif_line(s, ad, av->data, av->len); } } if (entroid) print_entroid_bottom(s, entroid); } void print_ldif_message(FILE *s, LDAP *ld, LDAPMessage *entry, int key, tentroid *entroid) { char *dn, *ad; BerElement *ber; fputc('\n', s); if (entroid) fputs(entroid->comment->str, s); dn = ldap_get_dn(ld, entry); print_ldif_line(s, "dn", dn, -1); ldap_memfree(dn); if (key != -1) fprintf(s, "ldapvi-key: %d\n", key); for (ad = ldap_first_attribute(ld, entry, &ber); ad; ad = ldap_next_attribute(ld, entry, ber)) { struct berval **values = ldap_get_values_len(ld, entry, ad); if (entroid) entroid_remove_ad(entroid, ad); print_ldif_bervals(s, ad, values); ldap_memfree(ad); ldap_value_free_len(values); } ber_free(ber, 0); if (entroid) print_entroid_bottom(s, entroid); if (ferror(s)) syserr(); }